Search in sources :

Example 6 with BadAttestationStatementException

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

the class TPMAttestationStatementValidator method validateX5c.

private void validateX5c(TPMAttestationStatement attestationStatement, TPMSAttest certInfo, AuthenticatorData<RegistrationExtensionAuthenticatorOutput> authenticatorData) {
    // noinspection ConstantConditions as null check is already done in validateTPMAttestationStatementNull
    X509Certificate aikCert = attestationStatement.getX5c().getEndEntityAttestationCertificate().getCertificate();
    // / Verify the sig is a valid signature over certInfo using the attestation public key in aikCert with the algorithm specified in alg.
    String jcaName = getJcaName(attestationStatement.getAlg());
    Signature certInfoSignature = SignatureUtil.createSignature(jcaName);
    try {
        certInfoSignature.initVerify(aikCert.getPublicKey());
        certInfoSignature.update(certInfo.getBytes());
        if (!certInfoSignature.verify(attestationStatement.getSig())) {
            throw new BadAttestationStatementException("hash of certInfo doesn't match with sig.");
        }
    } catch (SignatureException | InvalidKeyException e) {
        throw new BadAttestationStatementException("Failed to validate the signature.", e);
    }
    // / Verify that aikCert meets the requirements in §8.3.1 TPM Attestation Statement Certificate Requirements.
    validateAikCert(aikCert);
    // / If aikCert contains an extension with OID 1 3 6 1 4 1 45724 1 1 4 (id-fido-gen-ce-aaguid) verify that the value of this extension matches the aaguid in authenticatorData.
    byte[] aaguidBytes = aikCert.getExtensionValue(ID_FIDO_GEN_CE_AAGUID);
    // noinspection ConstantConditions as null check is already done in caller
    if (aaguidBytes != null && !Objects.equals(new AAGUID(aaguidBytes), authenticatorData.getAttestedCredentialData().getAaguid())) {
        throw new BadAttestationStatementException("AAGUID in aikCert doesn't match with that in authenticatorData");
    }
}
Also used : BadAttestationStatementException(com.webauthn4j.validator.exception.BadAttestationStatementException) AAGUID(com.webauthn4j.data.attestation.authenticator.AAGUID) Asn1Utf8String(org.apache.kerby.asn1.type.Asn1Utf8String) X509Certificate(java.security.cert.X509Certificate)

Example 7 with BadAttestationStatementException

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

the class FIDOU2FAttestationStatementValidator method validateAttestationStatement.

void validateAttestationStatement(@NonNull FIDOU2FAttestationStatement attestationStatement) {
    if (attestationStatement.getX5c().size() != 1) {
        throw new BadAttestationStatementException("FIDO-U2F attestation statement must have only one certificate.");
    }
    PublicKey publicKey = attestationStatement.getX5c().getEndEntityAttestationCertificate().getCertificate().getPublicKey();
    validatePublicKey(publicKey);
}
Also used : BadAttestationStatementException(com.webauthn4j.validator.exception.BadAttestationStatementException) ECPublicKey(java.security.interfaces.ECPublicKey)

Example 8 with BadAttestationStatementException

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

the class AndroidKeyAttestationStatementValidator method validate.

@Override
@NonNull
public AttestationType validate(@NonNull CoreRegistrationObject registrationObject) {
    AssertUtil.notNull(registrationObject, "registrationObject must not be null");
    if (!supports(registrationObject)) {
        throw new IllegalArgumentException(String.format("Specified format '%s' is not supported by %s.", registrationObject.getAttestationObject().getFormat(), this.getClass().getName()));
    }
    AndroidKeyAttestationStatement attestationStatement = (AndroidKeyAttestationStatement) registrationObject.getAttestationObject().getAttestationStatement();
    validateAttestationStatementNotNull(attestationStatement);
    if (attestationStatement.getX5c().isEmpty()) {
        throw new BadAttestationStatementException("No attestation certificate is found in android key attestation statement.");
    }
    // / 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 sig is a valid signature over the concatenation of authenticatorData and clientDataHash using the public key in the first certificate in x5c with the algorithm specified in alg.
    validateSignature(registrationObject);
    // / Verify that the public key in the first certificate in x5c matches the credentialPublicKey in the attestedCredentialData in authenticatorData.
    PublicKey publicKeyInEndEntityCert = attestationStatement.getX5c().getEndEntityAttestationCertificate().getCertificate().getPublicKey();
    AuthenticatorData<RegistrationExtensionAuthenticatorOutput> authenticatorData = registrationObject.getAttestationObject().getAuthenticatorData();
    // noinspection ConstantConditions as null check is already done in caller
    PublicKey publicKeyInCredentialData = authenticatorData.getAttestedCredentialData().getCOSEKey().getPublicKey();
    if (!publicKeyInEndEntityCert.equals(publicKeyInCredentialData)) {
        throw new PublicKeyMismatchException("The public key in the first certificate in x5c doesn't matches the credentialPublicKey in the attestedCredentialData in authenticatorData.");
    }
    byte[] clientDataHash = registrationObject.getClientDataHash();
    keyDescriptionValidator.validate(attestationStatement.getX5c().getEndEntityAttestationCertificate().getCertificate(), clientDataHash, teeEnforcedOnly);
    return AttestationType.BASIC;
}
Also used : AndroidKeyAttestationStatement(com.webauthn4j.data.attestation.statement.AndroidKeyAttestationStatement) BadAttestationStatementException(com.webauthn4j.validator.exception.BadAttestationStatementException) PublicKey(java.security.PublicKey) RegistrationExtensionAuthenticatorOutput(com.webauthn4j.data.extension.authenticator.RegistrationExtensionAuthenticatorOutput) PublicKeyMismatchException(com.webauthn4j.validator.exception.PublicKeyMismatchException) NonNull(org.checkerframework.checker.nullness.qual.NonNull)

Example 9 with BadAttestationStatementException

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

the class PackedAttestationStatementValidator method validateX5c.

@SuppressWarnings("SameReturnValue")
@NonNull
private AttestationType validateX5c(@NonNull CoreRegistrationObject registrationObject, @NonNull PackedAttestationStatement attestationStatement, @NonNull byte[] sig, @NonNull COSEAlgorithmIdentifier alg, @NonNull byte[] attrToBeSigned) {
    if (attestationStatement.getX5c() == null || attestationStatement.getX5c().isEmpty()) {
        throw new BadAttestationStatementException("No attestation certificate is found in packed attestation statement.");
    }
    // using the attestation public key in x5c with the algorithm specified in alg.
    if (!verifySignature(attestationStatement.getX5c().getEndEntityAttestationCertificate().getCertificate().getPublicKey(), alg, sig, attrToBeSigned)) {
        throw new BadSignatureException("`sig` in attestation statement is not valid signature over the concatenation of authenticatorData and clientDataHash.");
    }
    // Verify that x5c meets the requirements in §8.2.1 Packed attestation statement certificate requirements.
    attestationStatement.getX5c().getEndEntityAttestationCertificate().validate();
    // If x5c contains an extension with OID 1.3.6.1.4.1.45724.1.1.4 (id-fido-gen-ce-aaguid) verify that
    // the value of this extension matches the aaguid in authenticatorData.
    X509Certificate attestationCertificate = attestationStatement.getX5c().getEndEntityAttestationCertificate().getCertificate();
    AAGUID aaguidInCertificate = extractAAGUIDFromAttestationCertificate(attestationCertificate);
    // noinspection ConstantConditions as null check is already done in caller
    AAGUID aaguid = registrationObject.getAttestationObject().getAuthenticatorData().getAttestedCredentialData().getAaguid();
    if (aaguidInCertificate != AAGUID.NULL && !Objects.equals(aaguidInCertificate, aaguid)) {
        throw new BadAttestationStatementException("AAGUID in attestation certificate doesn't match the AAGUID in authenticatorData.");
    }
    // If successful, return attestation type BASIC and attestation trust path x5c.
    return AttestationType.BASIC;
}
Also used : BadSignatureException(com.webauthn4j.validator.exception.BadSignatureException) BadAttestationStatementException(com.webauthn4j.validator.exception.BadAttestationStatementException) AAGUID(com.webauthn4j.data.attestation.authenticator.AAGUID) X509Certificate(java.security.cert.X509Certificate) NonNull(org.checkerframework.checker.nullness.qual.NonNull)

Example 10 with BadAttestationStatementException

use of com.webauthn4j.validator.exception.BadAttestationStatementException 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)

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