Search in sources :

Example 11 with BadAttestationStatementException

use of com.webauthn4j.validator.exception.BadAttestationStatementException in project webauthn4j by webauthn4j.

the class AbstractStatementValidator method getJcaName.

protected String getJcaName(@NonNull COSEAlgorithmIdentifier alg) {
    String jcaName;
    try {
        SignatureAlgorithm signatureAlgorithm = alg.toSignatureAlgorithm();
        jcaName = signatureAlgorithm.getJcaName();
    } catch (IllegalArgumentException e) {
        throw new BadAttestationStatementException("alg is not signature algorithm", e);
    }
    return jcaName;
}
Also used : BadAttestationStatementException(com.webauthn4j.validator.exception.BadAttestationStatementException) SignatureAlgorithm(com.webauthn4j.data.SignatureAlgorithm)

Example 12 with BadAttestationStatementException

use of com.webauthn4j.validator.exception.BadAttestationStatementException in project webauthn4j by webauthn4j.

the class KeyDescriptionValidator method getIntegerFromAsn1.

@Nullable
private BigInteger getIntegerFromAsn1(Asn1ParseResult asn1Value) throws IOException {
    if (asn1Value == null) {
        return null;
    }
    if (!asn1Value.isPrimitive()) {
        throw new BadAttestationStatementException(String.format("ASN1Integer is expected. Found %s instead.", asn1Value.getClass().getName()));
    }
    Asn1Integer value = new Asn1Integer();
    value.decode(asn1Value);
    return value.getValue();
}
Also used : BadAttestationStatementException(com.webauthn4j.validator.exception.BadAttestationStatementException) Asn1Integer(org.apache.kerby.asn1.type.Asn1Integer) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Example 13 with BadAttestationStatementException

use of com.webauthn4j.validator.exception.BadAttestationStatementException in project webauthn4j by webauthn4j.

the class AndroidSafetyNetAttestationStatementValidator method validateNonce.

private void validateNonce(@Nullable String nonce, @NonNull byte[] authenticatorData, @NonNull byte[] clientDataHash) {
    if (nonce == null) {
        throw new BadAttestationStatementException("Nonce in the Android safetynet response is null.");
    }
    ByteBuffer buffer = ByteBuffer.allocate(authenticatorData.length + clientDataHash.length);
    byte[] data = buffer.put(authenticatorData).put(clientDataHash).array();
    byte[] hash = MessageDigestUtil.createSHA256().digest(data);
    // there is no need to prevent timing attack and it is OK to use `Arrays.equals` instead of `MessageDigest.isEqual` here.
    if (!Arrays.equals(hash, Base64Util.decode(nonce))) {
        throw new BadAttestationStatementException("Nonce in the Android safetynet response doesn't match.");
    }
}
Also used : BadAttestationStatementException(com.webauthn4j.validator.exception.BadAttestationStatementException) ByteBuffer(java.nio.ByteBuffer)

Example 14 with BadAttestationStatementException

use of com.webauthn4j.validator.exception.BadAttestationStatementException in project webauthn4j by webauthn4j.

the class AndroidSafetyNetAttestationStatementValidator method validate.

@SuppressWarnings("ConstantConditions")
@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());
    }
    AndroidSafetyNetAttestationStatement attestationStatement = (AndroidSafetyNetAttestationStatement) registrationObject.getAttestationObject().getAttestationStatement();
    validateAttestationStatementNotNull(attestationStatement);
    if (attestationStatement.getX5c().isEmpty()) {
        throw new BadAttestationStatementException("No attestation certificate is found in android safetynet attestation statement.");
    }
    // / Given the verification procedure inputs attStmt, authenticatorData and clientDataHash,
    // the verification procedure is as follows:
    // / Verify that attStmt is valid CBOR conforming to the syntax defined above and perform CBOR decoding on it
    // to extract the contained fields.
    // / Verify that response is a valid SafetyNet response of version ver.
    versionValidator.validate(attestationStatement.getVer());
    // / Verify that the nonce in the response is identical to the Base64url encoding of the SHA-256 hash of the concatenation of authenticatorData and clientDataHash.
    Response response = attestationStatement.getResponse().getPayload();
    String nonce = response.getNonce();
    byte[] authenticatorData = registrationObject.getAuthenticatorDataBytes();
    validateNonce(nonce, authenticatorData, registrationObject.getClientDataHash());
    // / Let attestationCert be the attestation certificate.
    // / Verify that attestationCert is issued to the hostname "attest.android.com" (see SafetyNet online documentation).
    AttestationCertificate attestationCertificate = attestationStatement.getX5c().getEndEntityAttestationCertificate();
    if (!Objects.equals(attestationCertificate.getSubjectCommonName(), "attest.android.com")) {
        throw new BadAttestationStatementException("The attestation certificate is not issued to 'attest.android.com'.");
    }
    // / Verify that the ctsProfileMatch attribute in the payload of response is true.
    if (!Objects.equals(response.getCtsProfileMatch(), true)) {
        throw new BadAttestationStatementException("The profile of the device doesn't match the profile of a device that has passed Android Compatibility Test Suite.");
    }
    if (response.getTimestampMs() == null) {
        throw new BadAttestationStatementException("timestampMs is null.");
    }
    // Verify the timestampMs doesn't violate backwardThreshold
    if (Instant.ofEpochMilli(response.getTimestampMs()).isBefore(registrationObject.getTimestamp().minus(Duration.ofSeconds(backwardThreshold)))) {
        throw new BadAttestationStatementException("timestampMs violates backwardThreshold.");
    }
    // Verify the timestampMs doesn't violate forwardThreshold
    if (Instant.ofEpochMilli(response.getTimestampMs()).isAfter(registrationObject.getTimestamp().plus(Duration.ofSeconds(forwardThreshold)))) {
        throw new BadAttestationStatementException("timestampMs violates forwardThreshold.");
    }
    if (!attestationStatement.getResponse().isValidSignature()) {
        throw new BadAttestationStatementException("Android safetynet response in the attestation statement doesn't have a valid signature.");
    }
    // / If successful, return implementation-specific values representing attestation type Basic and attestation trust path attestationCert.
    return AttestationType.BASIC;
}
Also used : Response(com.webauthn4j.data.attestation.statement.Response) AndroidSafetyNetAttestationStatement(com.webauthn4j.data.attestation.statement.AndroidSafetyNetAttestationStatement) BadAttestationStatementException(com.webauthn4j.validator.exception.BadAttestationStatementException) AttestationCertificate(com.webauthn4j.data.attestation.statement.AttestationCertificate) NonNull(org.checkerframework.checker.nullness.qual.NonNull)

Example 15 with BadAttestationStatementException

use of com.webauthn4j.validator.exception.BadAttestationStatementException in project webauthn4j by webauthn4j.

the class AppleAnonymousAttestationStatementValidator method validateNonce.

private void validateNonce(@NonNull CoreRegistrationObject registrationObject) {
    AppleAnonymousAttestationStatement attestationStatement = (AppleAnonymousAttestationStatement) registrationObject.getAttestationObject().getAttestationStatement();
    byte[] nonce = getNonce(registrationObject);
    byte[] extensionValue = attestationStatement.getX5c().getEndEntityAttestationCertificate().getCertificate().getExtensionValue("1.2.840.113635.100.8.2");
    byte[] extracted;
    try {
        Asn1OctetString extensionEnvelope = new Asn1OctetString();
        extensionEnvelope.decode(extensionValue);
        extensionEnvelope.getValue();
        byte[] extensionEnvelopeValue = extensionEnvelope.getValue();
        Asn1Container container = (Asn1Container) Asn1Parser.parse(ByteBuffer.wrap(extensionEnvelopeValue));
        Asn1ParseResult firstElement = container.getChildren().get(0);
        Asn1OctetString octetString = new Asn1OctetString();
        octetString.decode(firstElement);
        extracted = octetString.getValue();
    } catch (IOException | RuntimeException e) {
        throw new BadAttestationStatementException("Failed to extract nonce from Apple anonymous attestation statement.", e);
    }
    // there is no need to prevent timing attack and it is OK to use `Arrays.equals` instead of `MessageDigest.isEqual` here.
    if (!Arrays.equals(extracted, nonce)) {
        throw new BadAttestationStatementException("nonce doesn't match.");
    }
}
Also used : Asn1ParseResult(org.apache.kerby.asn1.parse.Asn1ParseResult) Asn1Container(org.apache.kerby.asn1.parse.Asn1Container) BadAttestationStatementException(com.webauthn4j.validator.exception.BadAttestationStatementException) IOException(java.io.IOException) Asn1OctetString(org.apache.kerby.asn1.type.Asn1OctetString) AppleAnonymousAttestationStatement(com.webauthn4j.data.attestation.statement.AppleAnonymousAttestationStatement)

Aggregations

BadAttestationStatementException (com.webauthn4j.validator.exception.BadAttestationStatementException)17 X509Certificate (java.security.cert.X509Certificate)4 NonNull (org.checkerframework.checker.nullness.qual.NonNull)4 AAGUID (com.webauthn4j.data.attestation.authenticator.AAGUID)3 IOException (java.io.IOException)3 RegistrationExtensionAuthenticatorOutput (com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput)2 ECPublicKey (java.security.interfaces.ECPublicKey)2 Asn1Container (org.apache.kerby.asn1.parse.Asn1Container)2 Asn1OctetString (org.apache.kerby.asn1.type.Asn1OctetString)2 Asn1Utf8String (org.apache.kerby.asn1.type.Asn1Utf8String)2 DCAttestationData (com.webauthn4j.appattest.data.DCAttestationData)1 AppleAppAttestAttestationStatement (com.webauthn4j.appattest.data.attestation.statement.AppleAppAttestAttestationStatement)1 DCRegistrationObject (com.webauthn4j.appattest.validator.DCRegistrationObject)1 ObjectConverter (com.webauthn4j.converter.util.ObjectConverter)1 AuthenticatorAttestationType (com.webauthn4j.data.AuthenticatorAttestationType)1 SignatureAlgorithm (com.webauthn4j.data.SignatureAlgorithm)1 AndroidKeyAttestationStatement (com.webauthn4j.data.attestation.statement.AndroidKeyAttestationStatement)1 AndroidSafetyNetAttestationStatement (com.webauthn4j.data.attestation.statement.AndroidSafetyNetAttestationStatement)1 AppleAnonymousAttestationStatement (com.webauthn4j.data.attestation.statement.AppleAnonymousAttestationStatement)1 AttestationCertificate (com.webauthn4j.data.attestation.statement.AttestationCertificate)1