Search in sources :

Example 6 with RegistrationExtensionAuthenticatorOutput

use of com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput in project webauthn4j by webauthn4j.

the class TPMAttestationStatementValidator method validate.

@Override
@NonNull
public AttestationType validate(@NonNull CoreRegistrationObject registrationObject) {
    AssertUtil.notNull(registrationObject, "registrationObject must not be null");
    if (!supports(registrationObject)) {
        throw new IllegalArgumentException("Specified format is not supported by " + this.getClass().getName());
    }
    TPMAttestationStatement attestationStatement = (TPMAttestationStatement) registrationObject.getAttestationObject().getAttestationStatement();
    validateAttestationStatementNotNull(attestationStatement);
    if (!attestationStatement.getVer().equals(TPMAttestationStatement.VERSION_2_0)) {
        throw new BadAttestationStatementException("TPM version is not supported.");
    }
    TPMSAttest certInfo = attestationStatement.getCertInfo();
    TPMTPublic pubArea = attestationStatement.getPubArea();
    AuthenticatorData<RegistrationExtensionAuthenticatorOutput> authenticatorData = registrationObject.getAttestationObject().getAuthenticatorData();
    // / Verify that the public key specified by the parameters and unique fields of pubArea is identical to the credentialPublicKey in the attestedCredentialData in authenticatorData.
    validatePublicKeyEquality(pubArea, authenticatorData);
    // / Concatenate authenticatorData and clientDataHash to form attToBeSigned.
    byte[] attToBeSigned = getAttToBeSigned(registrationObject);
    // / Verify that magic is set to TPM_GENERATED_VALUE.
    if (certInfo.getMagic() != TPMGenerated.TPM_GENERATED_VALUE) {
        throw new BadAttestationStatementException("magic must be TPM_GENERATED_VALUE");
    }
    // / Verify that type is set to TPM_ST_ATTEST_CERTIFY.
    if (certInfo.getType() != TPMISTAttest.TPM_ST_ATTEST_CERTIFY) {
        throw new BadAttestationStatementException("type must be TPM_ST_ATTEST_CERTIFY");
    }
    // / Verify that extraData is set to the hash of attToBeSigned using the hash algorithm employed in "alg".
    COSEAlgorithmIdentifier alg = attestationStatement.getAlg();
    MessageDigest messageDigest = getMessageDigest(alg);
    byte[] hash = messageDigest.digest(attToBeSigned);
    // As hash is public data(not secret data) to client side, there is no risk of timing attack and it is OK to use `Arrays.equals` instead of `MessageDigest.isEqual`
    if (!Arrays.equals(certInfo.getExtraData(), hash)) {
        throw new BadAttestationStatementException("extraData must be equals to the hash of attToBeSigned");
    }
    // / Verify that attested contains a TPMS_CERTIFY_INFO structure as specified in [TPMv2-Part2] section 10.12.3,
    // / whose name field contains a valid Name for pubArea, as computed using the algorithm in the nameAlg field of
    // / pubArea using the procedure specified in [TPMv2-Part1] section 16.
    TPMSCertifyInfo certifyInfo = (TPMSCertifyInfo) certInfo.getAttested();
    TPMIAlgHash hashAlg = certifyInfo.getName().getHashAlg();
    String algJcaName;
    algJcaName = getAlgJcaName(hashAlg);
    byte[] pubAreaDigest = MessageDigestUtil.createMessageDigest(algJcaName).digest(pubArea.getBytes());
    // there is no need to prevent timing attack and it is OK to use `Arrays.equals` instead of `MessageDigest.isEqual` here.
    if (!Arrays.equals(pubAreaDigest, certifyInfo.getName().getDigest())) {
        throw new BadAttestationStatementException("hash of `attested` doesn't match with name field of certifyInfo");
    }
    // / If x5c is present, this indicates that the attestation type is not ECDAA. In this case:
    if (attestationStatement.getX5c() != null) {
        validateX5c(attestationStatement, certInfo, authenticatorData);
        // / If successful, return implementation-specific values representing attestation type AttCA and attestation trust path x5c.
        return AttestationType.ATT_CA;
    }
    throw new BadAttestationStatementException("`x5c` or `ecdaaKeyId` must be present.");
}
Also used : RegistrationExtensionAuthenticatorOutput(com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput) Asn1Utf8String(org.apache.kerby.asn1.type.Asn1Utf8String) BadAttestationStatementException(com.webauthn4j.validator.exception.BadAttestationStatementException) NonNull(org.checkerframework.checker.nullness.qual.NonNull)

Example 7 with RegistrationExtensionAuthenticatorOutput

use of com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput in project webauthn4j by webauthn4j.

the class RegistrationDataValidator method validate.

// as null check is done by BeanAssertUtil#validate
@SuppressWarnings("ConstantConditions")
public void validate(@NonNull RegistrationData registrationData, @NonNull RegistrationParameters registrationParameters) {
    // spec| Step1
    // spec| Let options be a new PublicKeyCredentialCreationOptions structure configured to the Relying Party's needs for the ceremony.
    // (This step is done on client slide and out of WebAuthn4J responsibility.)
    // spec| Step2
    // spec| Call navigator.credentials.create() and pass options as the publicKey option. Let credential be the result of the successfully resolved promise.
    // spec| If the promise is rejected, abort the ceremony with a user-visible error,
    // spec| or otherwise guide the user experience as might be determinable from the context available in the rejected promise.
    // spec| For example if the promise is rejected with an error code equivalent to "InvalidStateError",
    // spec| the user might be instructed to use a different authenticator.
    // spec| For information on different error contexts and the circumstances leading to them, see § 6.3.2 The authenticatorMakeCredential Operation.
    // (This step is done on client slide and out of WebAuthn4J responsibility.)
    // spec| Step3
    // spec| Let response be credential.response. If response is not an instance of AuthenticatorAttestationResponse, abort the ceremony with a user-visible error.
    // (This step is done on client slide and out of WebAuthn4J responsibility.)
    // spec| Step4
    // spec| Let clientExtensionResults be the result of calling credential.getClientExtensionResults().
    // spec| Step5
    // spec| Let JSONtext be the result of running UTF-8 decode on the value of response.clientDataJSON.
    // (This step is done on caller.)
    BeanAssertUtil.validate(registrationData);
    AssertUtil.notNull(registrationParameters, "registrationParameters must not be null");
    byte[] clientDataBytes = registrationData.getCollectedClientDataBytes();
    byte[] attestationObjectBytes = registrationData.getAttestationObjectBytes();
    // spec| Step6
    // spec| Let C, the client data claimed as collected during the credential creation,
    // spec| be the result of running an implementation-specific JSON parser on JSONtext.
    CollectedClientData collectedClientData = registrationData.getCollectedClientData();
    AttestationObject attestationObject = registrationData.getAttestationObject();
    Set<AuthenticatorTransport> transports = registrationData.getTransports();
    AuthenticationExtensionsClientOutputs<RegistrationExtensionClientOutput> clientExtensions = registrationData.getClientExtensions();
    validateAuthenticatorDataField(attestationObject.getAuthenticatorData());
    ServerProperty serverProperty = registrationParameters.getServerProperty();
    RegistrationObject registrationObject = new RegistrationObject(attestationObject, attestationObjectBytes, collectedClientData, clientDataBytes, clientExtensions, transports, serverProperty);
    AuthenticatorData<RegistrationExtensionAuthenticatorOutput> authenticatorData = attestationObject.getAuthenticatorData();
    // spec| Verify that the value of C.type is webauthn.create.
    if (!Objects.equals(collectedClientData.getType(), ClientDataType.WEBAUTHN_CREATE)) {
        throw new InconsistentClientDataTypeException("ClientData.type must be 'create' on registration, but it isn't.");
    }
    // spec| Step8
    // spec| Verify that the value of C.challenge equals the base64url encoding of options.challenge.
    challengeValidator.validate(collectedClientData, serverProperty);
    // spec| Step9
    // spec| Verify that the value of C.origin matches the Relying Party's origin.
    originValidator.validate(registrationObject);
    // spec| Step10
    // spec| Verify that the value of C.tokenBinding.status matches the state of Token Binding for the TLS connection over
    // spec| which the assertion was obtained. If Token Binding was used on that TLS connection, also verify that
    // spec| C.tokenBinding.id matches the base64url encoding of the Token Binding ID for the connection.
    tokenBindingValidator.validate(collectedClientData.getTokenBinding(), serverProperty.getTokenBindingId());
    // spec| Step11
    // spec| Let hash be the result of computing a hash over response.clientDataJSON using SHA-256.
    // spec| Step12
    // spec| Perform CBOR decoding on the attestationObject field of the AuthenticatorAttestationResponse structure to
    // spec| obtain the attestation statement format fmt, the authenticator data authData, and the attestation statement attStmt.
    // (This step is done on caller.)
    // spec| Step13
    // spec| Verify that the rpIdHash in authData is the SHA-256 hash of the RP ID expected by the Relying Party.
    rpIdHashValidator.validate(authenticatorData.getRpIdHash(), serverProperty);
    // spec| Step14, 15
    // spec| Verify that the User Present bit of the flags in authData is set.
    // spec| If user verification is required for this registration, verify that the User Verified bit of the flags in authData is set.
    validateUVUPFlags(authenticatorData, registrationParameters.isUserVerificationRequired(), registrationParameters.isUserPresenceRequired());
    // spec| Step16
    // spec| Verify that the "alg" parameter in the credential public key in authData matches the alg attribute of one of the items in options.pubKeyCredParams.
    COSEAlgorithmIdentifier alg = authenticatorData.getAttestedCredentialData().getCOSEKey().getAlgorithm();
    List<PublicKeyCredentialParameters> pubKeyCredParams = registrationParameters.getPubKeyCredParams();
    validateAlg(alg, pubKeyCredParams);
    // spec| Step17
    // spec| Verify that the values of the client extension outputs in clientExtensionResults and the authenticator extension outputs in the extensions in authData are as expected,
    // spec| considering the client extension input values that were given in options.extensions and any specific policy of the Relying Party regarding unsolicited extensions,
    // spec| i.e., those that were not specified as part of options.extensions.
    // spec| In the general case, the meaning of "are as expected" is specific to the Relying Party and which extensions are in use.
    AuthenticationExtensionsAuthenticatorOutputs<RegistrationExtensionAuthenticatorOutput> authenticationExtensionsAuthenticatorOutputs = authenticatorData.getExtensions();
    clientExtensionValidator.validate(clientExtensions);
    authenticatorExtensionValidator.validate(authenticationExtensionsAuthenticatorOutputs);
    // spec| Step18-21
    attestationValidator.validate(registrationObject);
    // validate with custom logic
    for (CustomRegistrationValidator customRegistrationValidator : customRegistrationValidators) {
        customRegistrationValidator.validate(registrationObject);
    }
}
Also used : ServerProperty(com.webauthn4j.server.ServerProperty) RegistrationExtensionAuthenticatorOutput(com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput) RegistrationExtensionClientOutput(com.webauthn4j.data.extension.client.RegistrationExtensionClientOutput) CollectedClientData(com.webauthn4j.data.client.CollectedClientData) PublicKeyCredentialParameters(com.webauthn4j.data.PublicKeyCredentialParameters) COSEAlgorithmIdentifier(com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier) AttestationObject(com.webauthn4j.data.attestation.AttestationObject) AuthenticatorTransport(com.webauthn4j.data.AuthenticatorTransport)

Example 8 with RegistrationExtensionAuthenticatorOutput

use of com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput in project webauthn4j by webauthn4j.

the class AuthenticatorImplTest method getter_setter_test.

@Test
void getter_setter_test() {
    AttestedCredentialData attestedCredentialData = TestDataUtil.createAttestedCredentialData();
    AttestationStatement attestationStatement = TestAttestationStatementUtil.createFIDOU2FAttestationStatement();
    AuthenticatorImpl authenticator = new AuthenticatorImpl(TestDataUtil.createAttestedCredentialData(), TestAttestationStatementUtil.createBasicPackedAttestationStatement(), 0);
    AuthenticationExtensionsAuthenticatorOutputs<RegistrationExtensionAuthenticatorOutput> authenticatorExtensions = new AuthenticationExtensionsAuthenticatorOutputs<>();
    AuthenticationExtensionsClientOutputs<RegistrationExtensionClientOutput> clientExtensions = new AuthenticationExtensionsClientOutputs<>();
    Set<AuthenticatorTransport> transports = Collections.singleton(AuthenticatorTransport.USB);
    authenticator.setAttestedCredentialData(attestedCredentialData);
    authenticator.setAttestationStatement(attestationStatement);
    authenticator.setTransports(transports);
    authenticator.setCounter(1);
    authenticator.setAuthenticatorExtensions(authenticatorExtensions);
    authenticator.setClientExtensions(clientExtensions);
    assertAll(() -> assertThat(authenticator.getAttestedCredentialData()).isEqualTo(attestedCredentialData), () -> assertThat(authenticator.getAttestationStatement()).isEqualTo(attestationStatement), () -> assertThat(authenticator.getTransports()).isEqualTo(transports), () -> assertThat(authenticator.getCounter()).isEqualTo(1), () -> assertThat(authenticator.getAuthenticatorExtensions()).isEqualTo(authenticatorExtensions), () -> assertThat(authenticator.getClientExtensions()).isEqualTo(clientExtensions));
}
Also used : AttestedCredentialData(com.webauthn4j.data.attestation.authenticator.AttestedCredentialData) AuthenticationExtensionsAuthenticatorOutputs(com.webauthn4j.data.extension.authenticator.AuthenticationExtensionsAuthenticatorOutputs) RegistrationExtensionAuthenticatorOutput(com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput) AuthenticationExtensionsClientOutputs(com.webauthn4j.data.extension.client.AuthenticationExtensionsClientOutputs) AttestationStatement(com.webauthn4j.data.attestation.statement.AttestationStatement) RegistrationExtensionClientOutput(com.webauthn4j.data.extension.client.RegistrationExtensionClientOutput) AuthenticatorTransport(com.webauthn4j.data.AuthenticatorTransport) Test(org.junit.jupiter.api.Test)

Example 9 with RegistrationExtensionAuthenticatorOutput

use of com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput in project webauthn4j by webauthn4j.

the class AttestationObjectConverterTest method convert_deserialization_test.

@Test
void convert_deserialization_test() {
    // noinspection SpellCheckingInspection
    String testData = "v2hhdXRoRGF0YVi6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBAAAAAQAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv2ExYTJhMvZhMyZhNPZhNfZiLTEBYi0yWCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGItM1ggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABhMQL_Z2F0dFN0bXS_Y3g1Y4FZAsswggLHMIIBr6ADAgECAhAg92PAQYOxBTfb6FBqIlDyMA0GCSqGSIb3DQEBCwUAMEoxEjAQBgNVBAoMCVNoYXJwTGFiLjE0MDIGA1UEAwwrc3ByaW5nLXNlY3VyaXR5LXdlYmF1dGhuIDJ0aWVyIHRlc3Qgcm9vdCBDQTAgFw0xODA1MjAwNzA5NTVaGA8yMTE4MDQyNjA3MDk1NVowfTELMAkGA1UEBhMCSlAxEjAQBgNVBAoMCVNoYXJwTGFiLjEgMB4GA1UECwwXQXR0ZXN0YXRpb24gQ2VydGlmaWNhdGUxODA2BgNVBAMML3dlYmF1dGhuNGogdGVzdCAydGllciBhdXRoZW50aWNhdG9yIGF0dGVzdGF0aW9uMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYOdbrImOAgjZN3Xb8unfHHhJDINdIykolt-ypGxcrop4KwbujX2zvoRGZvdoQ9mu-rwjAZt4H3SMsSxPvB8z8KM_MD0wDAYDVR0TAQH_BAIwADAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFNDrzrNaaa7sdMR9uzsvO8OohdjhMA0GCSqGSIb3DQEBCwUAA4IBAQCtHcryqNSHDyszLtIByc5AzPam37vl0AVchb0qOxLFbmdUu4Nhzk-87YdA_VZuvVLInsIGaCwkP3rdqGAFY1HllglMnmWIoG2sKjmT3vpJydlDODaha9F_fVG7cq2i5Zx2KMTeUtuTkNdZDjocUUHXYVShgNnggoUWkVeLBG1ckzK1tAkbUwyChWMv4PDmIUBNv6DwkYI9oBSCSAJHpUzyxzMvCRbAFAICwPl3g-SQEUeiNlnzJuGXHnHxu-DB6JD2b0hPeYD6XxWPuI0Pq1G_6hGQmsNv3SF2ye2y_HOKnw3L-fzRHl5ksOdVZbpy9xXzTdIBUpvTmFuwcBo4HwRMY3NpZ1ggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD_Y2ZtdGhmaWRvLXUyZv8";
    AttestationObject attestationObject = target.convert(testData);
    AuthenticatorData<RegistrationExtensionAuthenticatorOutput> authenticatorData = attestationObject.getAuthenticatorData();
    String format = attestationObject.getFormat();
    AttestationStatement attestationStatement = attestationObject.getAttestationStatement();
    assertAll(() -> assertThat(authenticatorData).isNotNull(), () -> assertThat(format).isEqualTo("fido-u2f"), () -> assertThat(attestationStatement).isInstanceOf(FIDOU2FAttestationStatement.class));
}
Also used : AttestationObject(com.webauthn4j.data.attestation.AttestationObject) RegistrationExtensionAuthenticatorOutput(com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput) Test(org.junit.jupiter.api.Test)

Example 10 with RegistrationExtensionAuthenticatorOutput

use of com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput in project webauthn4j by webauthn4j.

the class AuthenticatorDataConverterTest method serialize_deserialize_test.

@Test
void serialize_deserialize_test() {
    // Given
    byte[] rpIdHash = new byte[32];
    // noinspection UnnecessaryLocalVariable
    byte flags = BIT_ED;
    AuthenticationExtensionsAuthenticatorOutputs.BuilderForRegistration builder = new AuthenticationExtensionsAuthenticatorOutputs.BuilderForRegistration();
    builder.setUvm(new UvmEntries());
    AuthenticatorData<RegistrationExtensionAuthenticatorOutput> authenticatorData = new AuthenticatorData<>(rpIdHash, flags, 0, builder.build());
    // When
    byte[] serialized = new AuthenticatorDataConverter(objectConverter).convert(authenticatorData);
    AuthenticatorData<RegistrationExtensionAuthenticatorOutput> result = new AuthenticatorDataConverter(objectConverter).convert(serialized);
    // Then
    assertThat(result.getRpIdHash()).isNotNull();
    assertThat(result.getRpIdHash()).hasSize(32);
    assertThat(result.getFlags()).isEqualTo(BIT_ED);
    assertThat(result.getSignCount()).isZero();
    assertThat(result.getAttestedCredentialData()).isNull();
    assertThat(result.getExtensions().getKeys()).contains(UserVerificationMethodExtensionAuthenticatorOutput.ID);
}
Also used : AuthenticationExtensionsAuthenticatorOutputs(com.webauthn4j.data.extension.authenticator.AuthenticationExtensionsAuthenticatorOutputs) AuthenticatorData(com.webauthn4j.data.attestation.authenticator.AuthenticatorData) RegistrationExtensionAuthenticatorOutput(com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput) UvmEntries(com.webauthn4j.data.extension.UvmEntries) Test(org.junit.jupiter.api.Test)

Aggregations

RegistrationExtensionAuthenticatorOutput (com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput)12 AttestationObject (com.webauthn4j.data.attestation.AttestationObject)7 Test (org.junit.jupiter.api.Test)6 AuthenticatorTransport (com.webauthn4j.data.AuthenticatorTransport)3 PublicKeyCredentialParameters (com.webauthn4j.data.PublicKeyCredentialParameters)3 AttestedCredentialData (com.webauthn4j.data.attestation.authenticator.AttestedCredentialData)3 AuthenticatorData (com.webauthn4j.data.attestation.authenticator.AuthenticatorData)3 AttestationStatement (com.webauthn4j.data.attestation.statement.AttestationStatement)3 RegistrationExtensionClientOutput (com.webauthn4j.data.extension.client.RegistrationExtensionClientOutput)3 COSEKey (com.webauthn4j.data.attestation.authenticator.COSEKey)2 AttestationCertificatePath (com.webauthn4j.data.attestation.statement.AttestationCertificatePath)2 COSEAlgorithmIdentifier (com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier)2 CollectedClientData (com.webauthn4j.data.client.CollectedClientData)2 AuthenticationExtensionsAuthenticatorOutputs (com.webauthn4j.data.extension.authenticator.AuthenticationExtensionsAuthenticatorOutputs)2 AuthenticationExtensionsClientOutputs (com.webauthn4j.data.extension.client.AuthenticationExtensionsClientOutputs)2 ServerProperty (com.webauthn4j.server.ServerProperty)2 BadAttestationStatementException (com.webauthn4j.validator.exception.BadAttestationStatementException)2 NonNull (org.checkerframework.checker.nullness.qual.NonNull)2 DCAssertion (com.webauthn4j.appattest.data.DCAssertion)1 DCAssertionData (com.webauthn4j.appattest.data.DCAssertionData)1