Skip to content

Commit

Permalink
Merge pull request #404 from Yubico/credprotect
Browse files Browse the repository at this point in the history
Add support for credProtect extension
  • Loading branch information
emlun authored Feb 24, 2025
2 parents ef6b552 + 613d34f commit 349ebec
Show file tree
Hide file tree
Showing 11 changed files with 1,254 additions and 171 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
== Version 2.7.0 (unreleased) ==

* Added overloaded setter `RelyingPartyBuilder.origins(Optional<Set<String>>)`.
* Added support for the CTAP2 `credProtect` extension.
* (Experimental) Added a new suite of interfaces, starting with
`CredentialRepositoryV2`. `RelyingParty` can now be configured with a
`CredentialRepositoryV2` instance instead of a `CredentialRepository`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.yubico.webauthn.data.ByteArray;
import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs;
import com.yubico.webauthn.data.CollectedClientData;
import com.yubico.webauthn.data.Extensions;
import com.yubico.webauthn.data.PublicKeyCredential;
import com.yubico.webauthn.data.PublicKeyCredentialCreationOptions;
import com.yubico.webauthn.data.PublicKeyCredentialParameters;
Expand Down Expand Up @@ -337,7 +338,7 @@ public Step16 nextStep() {
}

@Value
class Step16 implements Step<Step18> {
class Step16 implements Step<Step17> {
private final ByteArray clientDataJsonHash;
private final AttestationObject attestation;

Expand Down Expand Up @@ -368,14 +369,28 @@ public void validate() {
}
}

@Override
public Step17 nextStep() {
return new Step17(clientDataJsonHash, attestation);
}
}

@Value
class Step17 implements Step<Step18> {
private final ByteArray clientDataJsonHash;
private final AttestationObject attestation;

@Override
public void validate() {
Extensions.CredentialProtection.validateExtensionOutput(request, response);
}

@Override
public Step18 nextStep() {
return new Step18(clientDataJsonHash, attestation);
}
}

// Nothing to do for step 17

@Value
class Step18 implements Step<Step19> {
private final ByteArray clientDataJsonHash;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@
import com.yubico.webauthn.data.AuthenticatorResponse;
import com.yubico.webauthn.data.ByteArray;
import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs;
import com.yubico.webauthn.data.Extensions;
import com.yubico.webauthn.data.PublicKeyCredential;
import com.yubico.webauthn.data.PublicKeyCredentialDescriptor;
import com.yubico.webauthn.data.RegistrationExtensionInputs;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
Expand Down Expand Up @@ -367,6 +369,40 @@ public Optional<Boolean> isDiscoverable() {
.flatMap(credProps -> credProps.getRk());
}

/**
* Retrieve the <code>credProtect</code> extension policy that was set for the credential, if
* available.
*
* <p>If accessing this, you most likely also want to set the {@link
* RegistrationExtensionInputs.RegistrationExtensionInputsBuilder#credProtect(Extensions.CredentialProtection.CredentialProtectionInput)
* credProtect} extension input in the {@link
* StartRegistrationOptions.StartRegistrationOptionsBuilder#extensions(RegistrationExtensionInputs)
* extensions} parameter of {@link StartRegistrationOptions}.
*
* <p>This output is signed by the authenticator, and thus its trustworthiness may be evaluated
* using <a
* href="https://developers.yubico.com/java-webauthn-server/#using_attestation">authenticator
* attestation</a>.
*
* @return the <code>credProtect</code> extension policy that was set for the credential, if
* available.
* @see
* StartRegistrationOptions.StartRegistrationOptionsBuilder#extensions(RegistrationExtensionInputs)
* @see
* RegistrationExtensionInputs.RegistrationExtensionInputsBuilder#credProtect(Extensions.CredentialProtection.CredentialProtectionInput)
* @see <a
* href="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#sctn-credProtect-extension">CTAP2
* §12.1. Credential Protection (credProtect)</a>
* @see <a href="https://developers.yubico.com/java-webauthn-server/#using_attestation">Using
* attestation</a>
*/
@JsonIgnore
public Optional<Extensions.CredentialProtection.CredentialProtectionPolicy>
getCredProtectPolicy() {
return getAuthenticatorExtensionOutputs()
.flatMap(AuthenticatorRegistrationExtensionOutputs::getCredProtect);
}

/**
* The <a
* href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#attestation-trust-path">attestation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,15 @@
public final class AuthenticatorRegistrationExtensionOutputs
implements AuthenticatorExtensionOutputs {

private final Extensions.CredentialProtection.CredentialProtectionPolicy credProtect;
private final List<Extensions.Uvm.UvmEntry> uvm;

@JsonCreator
private AuthenticatorRegistrationExtensionOutputs(
@JsonProperty("credProtect")
Extensions.CredentialProtection.CredentialProtectionPolicy credProtect,
@JsonProperty("uvm") List<Extensions.Uvm.UvmEntry> uvm) {
this.credProtect = credProtect;
this.uvm = uvm == null ? null : CollectionUtil.immutableList(uvm);
}

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

Extensions.CredentialProtection.parseAuthenticatorExtensionOutput(cbor)
.ifPresent(b::credProtect);
Extensions.Uvm.parseAuthenticatorExtensionOutput(cbor).ifPresent(b::uvm);

AuthenticatorRegistrationExtensionOutputs result = b.build();
Expand All @@ -122,12 +128,30 @@ static Optional<AuthenticatorRegistrationExtensionOutputs> fromCbor(CBORObject c
@EqualsAndHashCode.Include
public Set<String> getExtensionIds() {
HashSet<String> ids = new HashSet<>();
if (credProtect != null) {
ids.add(Extensions.CredentialProtection.EXTENSION_ID);
}
if (uvm != null) {
ids.add(Extensions.Uvm.EXTENSION_ID);
}
return ids;
}

/**
* @return The <a
* href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#authenticator-extension-output">authenticator
* extension output</a> for the <a
* href="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#sctn-credProtect-extension">Credential
* Protection (credProtect) extension</a>, if any. This indicates the credential protection
* policy that was set for the credential.
* @see <a
* href="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#sctn-credProtect-extension">CTAP2
* §12.1. Credential Protection (credProtect)</a>
*/
public Optional<Extensions.CredentialProtection.CredentialProtectionPolicy> getCredProtect() {
return Optional.ofNullable(credProtect);
}

/**
* @return The <a
* href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#authenticator-extension-output">authenticator
Expand Down
Loading

1 comment on commit 349ebec

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutation test results

Package Coverage Stats Prev Prev
Overall 78 % 🟢 1514 🔺 / 1919 🔺 78 % 1476 / 1884
com.yubico.fido.metadata 68 % 🔹 230 🔹 / 337 🔹 68 % 230 / 337
com.yubico.internal.util 44 % 🔹 128 🔺 / 288 🔹 44 % 127 / 288
com.yubico.webauthn 89 % 🔹 665 🔺 / 745 🔺 89 % 662 / 742
com.yubico.webauthn.attestation 93 % 🔹 15 🔹 / 16 🔹 93 % 15 / 16
com.yubico.webauthn.data 92 % 🟢 451 🔺 / 486 🔺 91 % 417 / 454
com.yubico.webauthn.extension.appid 100 % 🏆 13 🔹 / 13 🔹 100 % 13 / 13
com.yubico.webauthn.extension.uvm 50 % 🔹 12 🔹 / 24 🔹 50 % 12 / 24
com.yubico.webauthn.meta 0 % 🔹 0 🔹 / 10 🔹 0 % 0 / 10

Previous run: ef6b552 - Diff

Detailed reports: workflow run #297

Please sign in to comment.