Search in sources :

Example 1 with CoreServerProperty

use of com.webauthn4j.server.CoreServerProperty in project webauthn4j by webauthn4j.

the class DCAssertionDataValidator method createCoreAuthenticationObject.

@Override
@NonNull
protected CoreAuthenticationObject createCoreAuthenticationObject(@NonNull CoreAuthenticationData authenticationData, @NonNull CoreAuthenticationParameters authenticationParameters) {
    AssertUtil.notNull(authenticationData, "authenticationData must not be null");
    AssertUtil.notNull(authenticationData, "authenticationParameters must not be null");
    byte[] credentialId = authenticationData.getCredentialId();
    AuthenticatorData<AuthenticationExtensionAuthenticatorOutput> authenticatorData = authenticationData.getAuthenticatorData();
    byte[] authenticatorDataBytes = authenticationData.getAuthenticatorDataBytes();
    byte[] clientDataHash = authenticationData.getClientDataHash();
    CoreServerProperty serverProperty = authenticationParameters.getServerProperty();
    CoreAuthenticator authenticator = authenticationParameters.getAuthenticator();
    DCAppleDevice dcAppleDevice = new DCAppleDeviceImpl(authenticator.getAttestedCredentialData(), authenticator.getAttestationStatement(), authenticator.getCounter(), authenticator.getAuthenticatorExtensions());
    // noinspection ConstantConditions null check is already done in caller
    return new DCAuthenticationObject(credentialId, authenticatorData, authenticatorDataBytes, clientDataHash, serverProperty, dcAppleDevice);
}
Also used : CoreServerProperty(com.webauthn4j.server.CoreServerProperty) DCAppleDevice(com.webauthn4j.appattest.authenticator.DCAppleDevice) AuthenticationExtensionAuthenticatorOutput(com.webauthn4j.data.extension.authenticator.AuthenticationExtensionAuthenticatorOutput) DCAppleDeviceImpl(com.webauthn4j.appattest.authenticator.DCAppleDeviceImpl) CoreAuthenticator(com.webauthn4j.authenticator.CoreAuthenticator) NonNull(org.checkerframework.checker.nullness.qual.NonNull)

Example 2 with CoreServerProperty

use of com.webauthn4j.server.CoreServerProperty in project webauthn4j by webauthn4j.

the class CoreAuthenticationDataValidator method createCoreAuthenticationObject.

@NonNull
protected CoreAuthenticationObject createCoreAuthenticationObject(@NonNull CoreAuthenticationData authenticationData, @NonNull CoreAuthenticationParameters authenticationParameters) {
    byte[] credentialId = authenticationData.getCredentialId();
    AuthenticatorData<AuthenticationExtensionAuthenticatorOutput> authenticatorData = authenticationData.getAuthenticatorData();
    byte[] authenticatorDataBytes = authenticationData.getAuthenticatorDataBytes();
    byte[] clientDataHash = authenticationData.getClientDataHash();
    CoreServerProperty serverProperty = authenticationParameters.getServerProperty();
    CoreAuthenticator authenticator = authenticationParameters.getAuthenticator();
    AssertUtil.notNull(authenticatorData, "authenticatorData must not be null");
    return new CoreAuthenticationObject(credentialId, authenticatorData, authenticatorDataBytes, clientDataHash, serverProperty, authenticator);
}
Also used : CoreServerProperty(com.webauthn4j.server.CoreServerProperty) AuthenticationExtensionAuthenticatorOutput(com.webauthn4j.data.extension.authenticator.AuthenticationExtensionAuthenticatorOutput) CoreAuthenticator(com.webauthn4j.authenticator.CoreAuthenticator) NonNull(org.checkerframework.checker.nullness.qual.NonNull)

Example 3 with CoreServerProperty

use of com.webauthn4j.server.CoreServerProperty in project webauthn4j by webauthn4j.

the class CoreAuthenticationDataValidator method validate.

/**
 * It is up to caller responsibility to inject challenge into clientData and validate it equals to challenge stored in server side
 *
 * @param authenticationData       authentication data
 * @param authenticationParameters authentication parameters
 */
// as null check is done by BeanAssertUtil#validate
@SuppressWarnings("ConstantConditions")
public void validate(@NonNull CoreAuthenticationData authenticationData, @NonNull CoreAuthenticationParameters authenticationParameters) {
    BeanAssertUtil.validate(authenticationData);
    AssertUtil.notNull(authenticationParameters, "authenticationParameters must not be null");
    // spec| Step1
    // spec| Let options be a new PublicKeyCredentialRequestOptions 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.get() 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, or otherwise guide the user experience as might be determinable
    // spec| from the context available in the rejected promise. For information on different error contexts and the circumstances leading to them,
    // spec| see § 6.3.3 The authenticatorGetAssertion 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 AuthenticatorAssertionResponse, 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().
    // (This step is only applicable to WebAuthn)
    // spec| Step5
    // spec| If options.allowCredentials is not empty, verify that credential.id identifies one of the public key credentials listed in options.allowCredentials.
    byte[] credentialId = authenticationData.getCredentialId();
    List<byte[]> allowCredentials = authenticationParameters.getAllowCredentials();
    validateCredentialId(credentialId, allowCredentials);
    // spec| Step6
    // spec| Identify the user being authenticated and verify that this user is the owner of the public key credential source credentialSource identified by credential.id:
    // spec| - If the user was identified before the authentication ceremony was initiated,
    // spec|   verify that the identified user is the owner of credentialSource. If credential.response.userHandle is present,
    // spec|   let userHandle be its value. Verify that userHandle also maps to the same user.
    // spec| - If the user was not identified before the authentication ceremony was initiated,
    // spec|   verify that response.userHandle is present, and that the user identified by this value is the owner of credentialSource.
    // (This step is out of WebAuthn4J scope. It's caller's responsibility.)
    // spec| Step7
    // spec| Using credential’s id attribute (or the corresponding rawId, if base64url encoding is inappropriate for your use case),
    // spec| look up the corresponding credential public key and let credentialPublicKey be that credential public key.
    // (This step is out of WebAuthn4J scope. It's caller's responsibility.)
    // spec| Step8
    // spec| Let cData, aData and sig denote the value of credential’s response's clientDataJSON, authenticatorData,
    // spec| and signature respectively.
    // (This step is only applicable to WebAuthn)
    // spec| Step9
    // spec| Let JSONtext be the result of running UTF-8 decode on the value of cData.
    // (This step is done on caller.)
    // spec| Step10
    // spec| Let C, the client data claimed as used for the signature, be the result of running an implementation-specific JSON parser on JSONtext.
    // (This step is only applicable to WebAuthn)
    AuthenticatorData<AuthenticationExtensionAuthenticatorOutput> authenticatorData = authenticationData.getAuthenticatorData();
    CoreServerProperty serverProperty = authenticationParameters.getServerProperty();
    BeanAssertUtil.validate(authenticatorData);
    validateAuthenticatorData(authenticatorData);
    CoreAuthenticator authenticator = authenticationParameters.getAuthenticator();
    CoreAuthenticationObject authenticationObject = createCoreAuthenticationObject(authenticationData, authenticationParameters);
    // spec| Step11
    // spec| Verify that the value of C.type is the string webauthn.get.
    // (This step is only applicable to WebAuthn)
    // spec| Step12
    // spec| Verify that the value of C.challenge matches the challenge that was sent to the authenticator in
    // spec| the PublicKeyCredentialRequestOptions passed to the get() call.
    // (This step is only applicable to WebAuthn)
    // spec| Step13
    // spec| Verify that the value of C.origin matches the Relying Party's origin.
    // (This step is only applicable to WebAuthn)
    // Verify cross origin, which is not defined in the spec
    // (This step is only applicable to WebAuthn)
    // spec| Step14
    // spec| Verify that the value of C.tokenBinding.status matches the state of Token Binding for the TLS connection over
    // spec| which the attestation was obtained. If Token Binding was used on that TLS connection,
    // spec| also verify that C.tokenBinding.id matches the base64url encoding of the Token Binding ID for the connection.
    // (This step is only applicable to WebAuthn)
    // spec| Step15
    // 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| Verify that the User Present bit of the flags in authData is set.
    if (authenticationParameters.isUserPresenceRequired() && !authenticatorData.isFlagUP()) {
        throw new UserNotPresentException("Validator is configured to check user present, but UP flag in authenticatorData is not set.");
    }
    // spec| If user verification is required for this assertion, verify that the User Verified bit of the flags in authData is set.
    if (authenticationParameters.isUserVerificationRequired() && !authenticatorData.isFlagUV()) {
        throw new UserNotVerifiedException("Validator is configured to check user verified, but UV flag in authenticatorData is not set.");
    }
    // spec| Step18
    // spec| Verify that the values of the client extension outputs in clientExtensionResults and the authenticator
    // spec| extension outputs in the extensions in authData are as expected, considering the client extension input
    // spec| values that were given as the extensions option in the get() call. In particular, any extension identifier
    // spec| values in the clientExtensionResults and the extensions in authData MUST be also be present as extension
    // spec| identifier values in the extensions member of options, i.e., no extensions are present that were not requested.
    // spec| In the general case, the meaning of "are as expected" is specific to the Relying Party and which extensions are in use.
    AuthenticationExtensionsAuthenticatorOutputs<AuthenticationExtensionAuthenticatorOutput> authenticationExtensionsAuthenticatorOutputs = authenticatorData.getExtensions();
    // (This clientExtensionResults verification is only applicable to WebAuthn)
    authenticatorExtensionValidator.validate(authenticationExtensionsAuthenticatorOutputs);
    // spec| Step19
    // spec| Let hash be the result of computing a hash over the cData using SHA-256.
    // spec| Step20
    // spec| Using the credential public key, validate that sig is a valid signature over
    // spec| the binary concatenation of the authenticatorData and the hash of the collectedClientData.
    assertionSignatureValidator.validate(authenticationData, authenticator.getAttestedCredentialData().getCOSEKey());
    // spec| Step21
    // spec| Let storedSignCount be the stored signature counter value associated with credential.id.
    // spec| If authData.signCount is nonzero or storedSignCount is nonzero, then run the following sub-step:
    long presentedSignCount = authenticatorData.getSignCount();
    long storedSignCount = authenticator.getCounter();
    if (presentedSignCount > 0 || storedSignCount > 0) {
        // spec| greater than storedSignCount:
        if (presentedSignCount > storedSignCount) {
            // spec| Update storedSignCount to be the value of authData.signCount.
            // (caller need to update the signature counter value based on the value set in the Authenticator instance)
            authenticator.setCounter(presentedSignCount);
        } else // spec| less than or equal to storedSignCount:
        // spec| This is a signal that the authenticator may be cloned, i.e. at least two copies of the credential private key may exist and are being used in parallel.
        // spec| Relying Parties should incorporate this information into their risk scoring.
        // spec| Whether the Relying Party updates storedSignCount in this case, or not, or fails the authentication ceremony or not, is Relying Party-specific.
        {
            coreMaliciousCounterValueHandler.maliciousCounterValueDetected(authenticationObject);
        }
    }
    for (CustomCoreAuthenticationValidator customAuthenticationValidator : customAuthenticationValidators) {
        customAuthenticationValidator.validate(authenticationObject);
    }
// spec| Step18
// spec| If all the above steps are successful, continue with the authentication ceremony as appropriate. Otherwise, fail the authentication ceremony.
}
Also used : CoreServerProperty(com.webauthn4j.server.CoreServerProperty) UserNotVerifiedException(com.webauthn4j.validator.exception.UserNotVerifiedException) AuthenticationExtensionAuthenticatorOutput(com.webauthn4j.data.extension.authenticator.AuthenticationExtensionAuthenticatorOutput) CoreAuthenticator(com.webauthn4j.authenticator.CoreAuthenticator) UserNotPresentException(com.webauthn4j.validator.exception.UserNotPresentException)

Example 4 with CoreServerProperty

use of com.webauthn4j.server.CoreServerProperty in project webauthn4j by webauthn4j.

the class CoreRegistrationDataValidator method validate.

/**
 * It is up to caller responsibility to inject challenge into clientData and validate it equals to challenge stored in server side
 *
 * @param registrationData       registration data
 * @param registrationParameters registration parameters
 */
// as null check is done by BeanAssertUtil#validate
@SuppressWarnings("ConstantConditions")
public void validate(@NonNull CoreRegistrationData registrationData, @NonNull CoreRegistrationParameters 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().
    // (This step is only applicable to WebAuthn)
    // spec| Step5
    // spec| Let JSONtext be the result of running UTF-8 decode on the value of response.clientDataJSON.
    // (This step is only applicable to WebAuthn)
    BeanAssertUtil.validate(registrationData);
    AssertUtil.notNull(registrationParameters, "registrationParameters must not be null");
    // 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.
    // (This step is only applicable to WebAuthn)
    AttestationObject attestationObject = registrationData.getAttestationObject();
    validateAuthenticatorDataField(attestationObject.getAuthenticatorData());
    CoreServerProperty serverProperty = registrationParameters.getServerProperty();
    CoreRegistrationObject registrationObject = createCoreRegistrationObject(registrationData, registrationParameters);
    AuthenticatorData<RegistrationExtensionAuthenticatorOutput> authenticatorData = attestationObject.getAuthenticatorData();
    COSEKey coseKey = authenticatorData.getAttestedCredentialData().getCOSEKey();
    validateCOSEKey(coseKey);
    // spec| Step7
    // spec| Verify that the value of C.type is webauthn.create.
    // (This step is only applicable to WebAuthn)
    // spec| Step8
    // spec| Verify that the value of C.challenge equals the base64url encoding of options.challenge.
    // (This step is only applicable to WebAuthn)
    // spec| Step9
    // spec| Verify that the value of C.origin matches the Relying Party's origin.
    // (This step is only applicable to WebAuthn)
    // 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.
    // (This step is only applicable to WebAuthn)
    // 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();
    authenticatorExtensionValidator.validate(authenticationExtensionsAuthenticatorOutputs);
    // spec| Step18-21
    attestationValidator.validate(registrationObject);
    // validate with custom logic
    for (CustomCoreRegistrationValidator customRegistrationValidator : customRegistrationValidators) {
        customRegistrationValidator.validate(registrationObject);
    }
}
Also used : CoreServerProperty(com.webauthn4j.server.CoreServerProperty) COSEKey(com.webauthn4j.data.attestation.authenticator.COSEKey) PublicKeyCredentialParameters(com.webauthn4j.data.PublicKeyCredentialParameters) COSEAlgorithmIdentifier(com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier) AttestationObject(com.webauthn4j.data.attestation.AttestationObject) RegistrationExtensionAuthenticatorOutput(com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput)

Example 5 with CoreServerProperty

use of com.webauthn4j.server.CoreServerProperty in project webauthn4j by webauthn4j.

the class CoreAuthenticationParametersTest method constructor_without_allowCredentials_userPresenceRequired_test.

@Deprecated
@Test
void constructor_without_allowCredentials_userPresenceRequired_test() {
    // Server properties
    String rpId = "example.com";
    Challenge challenge = new DefaultChallenge();
    CoreServerProperty serverProperty = new CoreServerProperty(rpId, challenge);
    Authenticator authenticator = mock(Authenticator.class);
    CoreAuthenticationParameters instance = new CoreAuthenticationParameters(serverProperty, authenticator, false);
    assertThat(instance.getServerProperty()).isEqualTo(serverProperty);
    assertThat(instance.getAuthenticator()).isEqualTo(authenticator);
    assertThat(instance.getAllowCredentials()).isNull();
    assertThat(instance.isUserVerificationRequired()).isFalse();
}
Also used : DefaultChallenge(com.webauthn4j.data.client.challenge.DefaultChallenge) CoreServerProperty(com.webauthn4j.server.CoreServerProperty) Authenticator(com.webauthn4j.authenticator.Authenticator) Challenge(com.webauthn4j.data.client.challenge.Challenge) DefaultChallenge(com.webauthn4j.data.client.challenge.DefaultChallenge) Test(org.junit.jupiter.api.Test)

Aggregations

CoreServerProperty (com.webauthn4j.server.CoreServerProperty)8 Challenge (com.webauthn4j.data.client.challenge.Challenge)4 DefaultChallenge (com.webauthn4j.data.client.challenge.DefaultChallenge)4 Test (org.junit.jupiter.api.Test)4 CoreAuthenticator (com.webauthn4j.authenticator.CoreAuthenticator)3 AuthenticationExtensionAuthenticatorOutput (com.webauthn4j.data.extension.authenticator.AuthenticationExtensionAuthenticatorOutput)3 Authenticator (com.webauthn4j.authenticator.Authenticator)2 NonNull (org.checkerframework.checker.nullness.qual.NonNull)2 DCAppleDevice (com.webauthn4j.appattest.authenticator.DCAppleDevice)1 DCAppleDeviceImpl (com.webauthn4j.appattest.authenticator.DCAppleDeviceImpl)1 PublicKeyCredentialParameters (com.webauthn4j.data.PublicKeyCredentialParameters)1 AttestationObject (com.webauthn4j.data.attestation.AttestationObject)1 COSEKey (com.webauthn4j.data.attestation.authenticator.COSEKey)1 COSEAlgorithmIdentifier (com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier)1 RegistrationExtensionAuthenticatorOutput (com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput)1 UserNotPresentException (com.webauthn4j.validator.exception.UserNotPresentException)1 UserNotVerifiedException (com.webauthn4j.validator.exception.UserNotVerifiedException)1