Skip to content

Commit 349ebec

Browse files
authored
Merge pull request #404 from Yubico/credprotect
Add support for credProtect extension
2 parents ef6b552 + 613d34f commit 349ebec

11 files changed

+1254
-171
lines changed

NEWS

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
== Version 2.7.0 (unreleased) ==
22

33
* Added overloaded setter `RelyingPartyBuilder.origins(Optional<Set<String>>)`.
4+
* Added support for the CTAP2 `credProtect` extension.
45
* (Experimental) Added a new suite of interfaces, starting with
56
`CredentialRepositoryV2`. `RelyingParty` can now be configured with a
67
`CredentialRepositoryV2` instance instead of a `CredentialRepository`

webauthn-server-core/src/main/java/com/yubico/webauthn/FinishRegistrationSteps.java

+18-3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.yubico.webauthn.data.ByteArray;
4040
import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs;
4141
import com.yubico.webauthn.data.CollectedClientData;
42+
import com.yubico.webauthn.data.Extensions;
4243
import com.yubico.webauthn.data.PublicKeyCredential;
4344
import com.yubico.webauthn.data.PublicKeyCredentialCreationOptions;
4445
import com.yubico.webauthn.data.PublicKeyCredentialParameters;
@@ -337,7 +338,7 @@ public Step16 nextStep() {
337338
}
338339

339340
@Value
340-
class Step16 implements Step<Step18> {
341+
class Step16 implements Step<Step17> {
341342
private final ByteArray clientDataJsonHash;
342343
private final AttestationObject attestation;
343344

@@ -368,14 +369,28 @@ public void validate() {
368369
}
369370
}
370371

372+
@Override
373+
public Step17 nextStep() {
374+
return new Step17(clientDataJsonHash, attestation);
375+
}
376+
}
377+
378+
@Value
379+
class Step17 implements Step<Step18> {
380+
private final ByteArray clientDataJsonHash;
381+
private final AttestationObject attestation;
382+
383+
@Override
384+
public void validate() {
385+
Extensions.CredentialProtection.validateExtensionOutput(request, response);
386+
}
387+
371388
@Override
372389
public Step18 nextStep() {
373390
return new Step18(clientDataJsonHash, attestation);
374391
}
375392
}
376393

377-
// Nothing to do for step 17
378-
379394
@Value
380395
class Step18 implements Step<Step19> {
381396
private final ByteArray clientDataJsonHash;

webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java

+36
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
import com.yubico.webauthn.data.AuthenticatorResponse;
4040
import com.yubico.webauthn.data.ByteArray;
4141
import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs;
42+
import com.yubico.webauthn.data.Extensions;
4243
import com.yubico.webauthn.data.PublicKeyCredential;
4344
import com.yubico.webauthn.data.PublicKeyCredentialDescriptor;
45+
import com.yubico.webauthn.data.RegistrationExtensionInputs;
4446
import java.io.IOException;
4547
import java.security.NoSuchAlgorithmException;
4648
import java.security.PublicKey;
@@ -367,6 +369,40 @@ public Optional<Boolean> isDiscoverable() {
367369
.flatMap(credProps -> credProps.getRk());
368370
}
369371

372+
/**
373+
* Retrieve the <code>credProtect</code> extension policy that was set for the credential, if
374+
* available.
375+
*
376+
* <p>If accessing this, you most likely also want to set the {@link
377+
* RegistrationExtensionInputs.RegistrationExtensionInputsBuilder#credProtect(Extensions.CredentialProtection.CredentialProtectionInput)
378+
* credProtect} extension input in the {@link
379+
* StartRegistrationOptions.StartRegistrationOptionsBuilder#extensions(RegistrationExtensionInputs)
380+
* extensions} parameter of {@link StartRegistrationOptions}.
381+
*
382+
* <p>This output is signed by the authenticator, and thus its trustworthiness may be evaluated
383+
* using <a
384+
* href="https://developers.yubico.com/java-webauthn-server/#using_attestation">authenticator
385+
* attestation</a>.
386+
*
387+
* @return the <code>credProtect</code> extension policy that was set for the credential, if
388+
* available.
389+
* @see
390+
* StartRegistrationOptions.StartRegistrationOptionsBuilder#extensions(RegistrationExtensionInputs)
391+
* @see
392+
* RegistrationExtensionInputs.RegistrationExtensionInputsBuilder#credProtect(Extensions.CredentialProtection.CredentialProtectionInput)
393+
* @see <a
394+
* href="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#sctn-credProtect-extension">CTAP2
395+
* §12.1. Credential Protection (credProtect)</a>
396+
* @see <a href="https://developers.yubico.com/java-webauthn-server/#using_attestation">Using
397+
* attestation</a>
398+
*/
399+
@JsonIgnore
400+
public Optional<Extensions.CredentialProtection.CredentialProtectionPolicy>
401+
getCredProtectPolicy() {
402+
return getAuthenticatorExtensionOutputs()
403+
.flatMap(AuthenticatorRegistrationExtensionOutputs::getCredProtect);
404+
}
405+
370406
/**
371407
* The <a
372408
* href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#attestation-trust-path">attestation

webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorRegistrationExtensionOutputs.java

+24
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,15 @@
6161
public final class AuthenticatorRegistrationExtensionOutputs
6262
implements AuthenticatorExtensionOutputs {
6363

64+
private final Extensions.CredentialProtection.CredentialProtectionPolicy credProtect;
6465
private final List<Extensions.Uvm.UvmEntry> uvm;
6566

6667
@JsonCreator
6768
private AuthenticatorRegistrationExtensionOutputs(
69+
@JsonProperty("credProtect")
70+
Extensions.CredentialProtection.CredentialProtectionPolicy credProtect,
6871
@JsonProperty("uvm") List<Extensions.Uvm.UvmEntry> uvm) {
72+
this.credProtect = credProtect;
6973
this.uvm = uvm == null ? null : CollectionUtil.immutableList(uvm);
7074
}
7175

@@ -107,6 +111,8 @@ public static Optional<AuthenticatorRegistrationExtensionOutputs> fromAuthentica
107111
static Optional<AuthenticatorRegistrationExtensionOutputs> fromCbor(CBORObject cbor) {
108112
AuthenticatorRegistrationExtensionOutputsBuilder b = builder();
109113

114+
Extensions.CredentialProtection.parseAuthenticatorExtensionOutput(cbor)
115+
.ifPresent(b::credProtect);
110116
Extensions.Uvm.parseAuthenticatorExtensionOutput(cbor).ifPresent(b::uvm);
111117

112118
AuthenticatorRegistrationExtensionOutputs result = b.build();
@@ -122,12 +128,30 @@ static Optional<AuthenticatorRegistrationExtensionOutputs> fromCbor(CBORObject c
122128
@EqualsAndHashCode.Include
123129
public Set<String> getExtensionIds() {
124130
HashSet<String> ids = new HashSet<>();
131+
if (credProtect != null) {
132+
ids.add(Extensions.CredentialProtection.EXTENSION_ID);
133+
}
125134
if (uvm != null) {
126135
ids.add(Extensions.Uvm.EXTENSION_ID);
127136
}
128137
return ids;
129138
}
130139

140+
/**
141+
* @return The <a
142+
* href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#authenticator-extension-output">authenticator
143+
* extension output</a> for the <a
144+
* href="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#sctn-credProtect-extension">Credential
145+
* Protection (credProtect) extension</a>, if any. This indicates the credential protection
146+
* policy that was set for the credential.
147+
* @see <a
148+
* href="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#sctn-credProtect-extension">CTAP2
149+
* §12.1. Credential Protection (credProtect)</a>
150+
*/
151+
public Optional<Extensions.CredentialProtection.CredentialProtectionPolicy> getCredProtect() {
152+
return Optional.ofNullable(credProtect);
153+
}
154+
131155
/**
132156
* @return The <a
133157
* href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#authenticator-extension-output">authenticator

0 commit comments

Comments
 (0)