Search in sources :

Example 1 with Fido2RegistrationData

use of io.jans.fido2.model.entry.Fido2RegistrationData in project jans by JanssenProject.

the class AppleAssertionFormatProcessor method process.

@Override
public void process(String base64AuthenticatorData, String signature, String clientDataJson, Fido2RegistrationData registration, Fido2AuthenticationData authenticationEntity) {
    AuthData authData = authenticatorDataParser.parseAssertionData(base64AuthenticatorData);
    commonVerifiers.verifyRpIdHash(authData, registration.getDomain());
    log.info("User verification option {}", authenticationEntity.getUserVerificationOption());
    userVerificationVerifier.verifyUserVerificationOption(authenticationEntity.getUserVerificationOption(), authData);
    byte[] clientDataHash = DigestUtils.getSha256Digest().digest(base64Service.urlDecode(clientDataJson));
    try {
        int counter = authenticatorDataParser.parseCounter(authData.getCounters());
        commonVerifiers.verifyCounter(registration.getCounter(), counter);
        registration.setCounter(counter);
        JsonNode uncompressedECPointNode = dataMapperService.cborReadTree(base64Service.urlDecode(registration.getUncompressedECPoint()));
        PublicKey publicKey = coseService.createUncompressedPointFromCOSEPublicKey(uncompressedECPointNode);
        log.info("Uncompressed ECpoint node {}", uncompressedECPointNode.toString());
        log.info("EC Public key hex {}", Hex.encodeHexString(publicKey.getEncoded()));
        log.info("Signature algorithm: " + registration.getSignatureAlgorithm());
        // Note : The signature counter is not implemented and therefore it is always
        // zero. Secure Enclave is used to prevent the credential private key from
        // leaking instead of a software safeguard.
        log.info("Key type / Algorithm : " + authData.getKeyType());
        // authData.getKeyType());
        authenticatorDataVerifier.verifyAssertionSignature(authData, clientDataHash, signature, publicKey, -7);
    } catch (Fido2CompromisedDevice ex) {
        throw ex;
    } catch (Exception ex) {
        throw new Fido2RuntimeException("Failed to check packet assertion", ex);
    }
}
Also used : AuthData(io.jans.fido2.model.auth.AuthData) Fido2CompromisedDevice(io.jans.fido2.exception.Fido2CompromisedDevice) PublicKey(java.security.PublicKey) JsonNode(com.fasterxml.jackson.databind.JsonNode) Fido2RuntimeException(io.jans.fido2.exception.Fido2RuntimeException) Fido2RuntimeException(io.jans.fido2.exception.Fido2RuntimeException)

Example 2 with Fido2RegistrationData

use of io.jans.fido2.model.entry.Fido2RegistrationData in project jans by JanssenProject.

the class PackedAssertionFormatProcessor method process.

@Override
public void process(String base64AuthenticatorData, String signature, String clientDataJson, Fido2RegistrationData registration, Fido2AuthenticationData authenticationEntity) {
    AuthData authData = authenticatorDataParser.parseAssertionData(base64AuthenticatorData);
    commonVerifiers.verifyRpIdHash(authData, registration.getDomain());
    log.debug("User verification option {}", authenticationEntity.getUserVerificationOption());
    userVerificationVerifier.verifyUserVerificationOption(authenticationEntity.getUserVerificationOption(), authData);
    byte[] clientDataHash = DigestUtils.getSha256Digest().digest(base64Service.urlDecode(clientDataJson));
    try {
        int counter = authenticatorDataParser.parseCounter(authData.getCounters());
        commonVerifiers.verifyCounter(registration.getCounter(), counter);
        registration.setCounter(counter);
        JsonNode uncompressedECPointNode = dataMapperService.cborReadTree(base64Service.urlDecode(registration.getUncompressedECPoint()));
        PublicKey publicKey = coseService.createUncompressedPointFromCOSEPublicKey(uncompressedECPointNode);
        log.debug("Uncompressed ECpoint node {}", uncompressedECPointNode.toString());
        log.debug("EC Public key hex {}", Hex.encodeHexString(publicKey.getEncoded()));
        // apple algorithm = -7
        // windows hello algorithm is -257
        log.debug("registration.getSignatureAlgorithm(): " + registration.getSignatureAlgorithm());
        log.debug("Platform authenticator: " + String.valueOf(registration.getAttenstationRequest().contains(AuthenticatorAttachment.PLATFORM.getAttachment()) ? -7 : registration.getSignatureAlgorithm()));
        authenticatorDataVerifier.verifyAssertionSignature(authData, clientDataHash, signature, publicKey, registration.getAttenstationRequest().contains(AuthenticatorAttachment.PLATFORM.getAttachment()) ? -7 : registration.getSignatureAlgorithm());
    } catch (Fido2CompromisedDevice ex) {
        throw ex;
    } catch (Exception ex) {
        throw new Fido2RuntimeException("Failed to check packet assertion", ex);
    }
}
Also used : AuthData(io.jans.fido2.model.auth.AuthData) Fido2CompromisedDevice(io.jans.fido2.exception.Fido2CompromisedDevice) PublicKey(java.security.PublicKey) JsonNode(com.fasterxml.jackson.databind.JsonNode) Fido2RuntimeException(io.jans.fido2.exception.Fido2RuntimeException) Fido2RuntimeException(io.jans.fido2.exception.Fido2RuntimeException)

Example 3 with Fido2RegistrationData

use of io.jans.fido2.model.entry.Fido2RegistrationData in project jans by JanssenProject.

the class AppleAttestationProcessor method process.

// @Override
public void process(JsonNode attStmt, AuthData authData, Fido2RegistrationData credential, byte[] clientDataHash, CredAndCounterData credIdAndCounters) {
    log.info("AttStmt: " + attStmt.asText());
    // Check attStmt and it contains “x5c” then its a FULL attestation.
    if (attStmt.hasNonNull("x5c")) {
        // 1. Verify |x5c| is a valid certificate chain starting from the |credCert|
        // (the first certificate in x5c) to
        // the Apple WebAuthn root certificate.
        Iterator<JsonNode> i = attStmt.get("x5c").elements();
        List<X509Certificate> certificates = new ArrayList<X509Certificate>();
        while (i.hasNext()) {
            String c = i.next().asText();
            X509Certificate cert = certificateService.getCertificate(c);
            certificates.add(cert);
        }
        // the first certificate in x5c
        X509Certificate credCert = certificates.get(0);
        List<X509Certificate> trustAnchorCertificates = new ArrayList<X509Certificate>();
        trustAnchorCertificates.addAll(certificateService.getCertificates(APPLE_WEBAUTHN_ROOT_CA));
        try {
            log.debug("APPLE_WEBAUTHN_ROOT_CA root certificate" + trustAnchorCertificates.size());
            X509Certificate verifiedCert = certificateVerifier.verifyAttestationCertificates(certificates, trustAnchorCertificates);
            log.info("Step 1 completed  ");
        } catch (Fido2MissingAttestationCertException ex) {
            X509Certificate certificate = certificates.get(0);
            String issuerDN = certificate.getIssuerDN().getName();
            log.warn("Failed to find attestation validation signature public certificate with DN: '{}'", issuerDN);
        }
        // 2. Concatenate |authenticatorData| and |clientDataHash| to form
        // |nonceToHash|.
        byte[] authDataInBytes = authData.getAuthDataDecoded();
        // byte[] nonceToHash = new byte[authDataInBytes.length +
        // clientDataHash.length];
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            baos.write(authDataInBytes);
            baos.write(clientDataHash);
        } catch (IOException e) {
            throw new AttestationException("Concatenate |authenticatorData| and |clientDataHash| to form |nonceToHash|." + e.getMessage());
        }
        byte[] nonceToHash = baos.toByteArray();
        log.info("Step 2 completed");
        // 3. Perform SHA-256 hash of |nonceToHash| to produce |nonce|.
        byte[] nonce = DigestUtils.getSha256Digest().digest(nonceToHash);
        log.info("Step 3 completed");
        // 4. Verify |nonce| matches the value of the extension with OID (
        // 1.2.840.113635.100.8.2 ) in |credCert|.
        byte[] attestationChallenge = getExtension(credCert);
        if (!Arrays.equals(nonce, attestationChallenge)) {
            throw new AttestationException("Certificate 1.2.840.113635.100.8.2 extension does not match nonce");
        } else
            log.info("Step 4 completed");
        // 5. Verify credential public key matches the Subject Public Key of
        // |credCert|.
        PublicKey publicKeyAuthData = coseService.getPublicKeyFromUncompressedECPoint(authData.getCosePublicKey());
        PublicKey publicKeyCredCert = credCert.getPublicKey();
        if (!publicKeyAuthData.equals(publicKeyCredCert)) {
            throw new AttestationException("The public key in the first certificate in x5c doesn't matches the credentialPublicKey in the attestedCredentialData in authenticatorData.");
        } else {
            log.info("Step 5 completed");
        }
        // this is Gluu implementation specific where setUncompressedEcPoint is saved in
        // LDAP registrationData and read during assertion
        credIdAndCounters.setAttestationType(getAttestationFormat().getFmt());
        credIdAndCounters.setCredId(base64Service.urlEncodeToString(authData.getCredId()));
        credIdAndCounters.setUncompressedEcPoint(base64Service.urlEncodeToString(authData.getCosePublicKey()));
        // log.info("attStmt.get(\"alg\")"+attStmt.get("alg"));
        // commonVerifiers.verifyAlgorithm(attStmt.get("alg"), authData.getKeyType());
        int alg = -7;
        credIdAndCounters.setSignatureAlgorithm(alg);
    }
}
Also used : Fido2MissingAttestationCertException(io.jans.fido2.exception.Fido2MissingAttestationCertException) AttestationException(io.jans.fido2.exception.AttestationException) PublicKey(java.security.PublicKey) ArrayList(java.util.ArrayList) JsonNode(com.fasterxml.jackson.databind.JsonNode) Asn1OctetString(org.apache.kerby.asn1.type.Asn1OctetString) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) X509Certificate(java.security.cert.X509Certificate)

Example 4 with Fido2RegistrationData

use of io.jans.fido2.model.entry.Fido2RegistrationData in project jans by JanssenProject.

the class AssertionVerifier method verifyAuthenticatorAssertionResponse.

public void verifyAuthenticatorAssertionResponse(JsonNode response, Fido2RegistrationData registration, Fido2AuthenticationData authenticationEntity) {
    if (!(response.hasNonNull("authenticatorData") && response.hasNonNull("clientDataJSON") && response.hasNonNull("signature"))) {
        throw new Fido2RuntimeException("Authenticator data is invalid");
    }
    String base64AuthenticatorData = response.get("authenticatorData").asText();
    String clientDataJson = response.get("clientDataJSON").asText();
    String signature = response.get("signature").asText();
    log.debug("Authenticator data {}", base64AuthenticatorData);
    AssertionFormatProcessor assertionProcessor = assertionProcessorFactory.getCommandProcessor(registration.getAttestationType());
    assertionProcessor.process(base64AuthenticatorData, signature, clientDataJson, registration, authenticationEntity);
}
Also used : AssertionFormatProcessor(io.jans.fido2.service.processors.AssertionFormatProcessor) Fido2RuntimeException(io.jans.fido2.exception.Fido2RuntimeException)

Example 5 with Fido2RegistrationData

use of io.jans.fido2.model.entry.Fido2RegistrationData in project jans by JanssenProject.

the class TPMProcessor method process.

@Override
public void process(JsonNode attStmt, AuthData authData, Fido2RegistrationData credential, byte[] clientDataHash, CredAndCounterData credIdAndCounters) {
    JsonNode cborPublicKey;
    try {
        cborPublicKey = dataMapperService.cborReadTree(authData.getCosePublicKey());
    } catch (IOException e) {
        throw new Fido2RuntimeException("Problem with TPM attestation");
    }
    byte[] hashedBuffer = getHashedBuffer(cborPublicKey.get("3").asInt(), authData.getAttestationBuffer(), clientDataHash);
    byte[] keyBufferFromAuthData = base64Service.decode(cborPublicKey.get("-1").asText());
    Iterator<JsonNode> i = attStmt.get("x5c").elements();
    String pubArea = attStmt.get("pubArea").asText();
    String certInfo = attStmt.get("certInfo").asText();
    if (i.hasNext()) {
        ArrayList<String> aikCertificatePath = new ArrayList<String>();
        aikCertificatePath.add(i.next().asText());
        ArrayList<String> certificatePath = new ArrayList<String>();
        while (i.hasNext()) {
            certificatePath.add(i.next().asText());
        }
        List<X509Certificate> certificates = certificateService.getCertificates(certificatePath);
        List<X509Certificate> aikCertificates = certificateService.getCertificates(aikCertificatePath);
        List<X509Certificate> trustAnchorCertificates = attestationCertificateService.getAttestationRootCertificates(authData, aikCertificates);
        X509Certificate verifiedCert = certificateVerifier.verifyAttestationCertificates(certificates, trustAnchorCertificates);
        X509Certificate aikCertificate = aikCertificates.get(0);
        verifyTPMCertificateExtenstion(aikCertificate, authData);
        verifyAIKCertificate(aikCertificate, verifiedCert);
        String signature = commonVerifiers.verifyBase64String(attStmt.get("sig"));
        byte[] certInfoBuffer = base64Service.decode(certInfo);
        byte[] signatureBytes = base64Service.decode(signature.getBytes());
        signatureVerifier.verifySignature(signatureBytes, certInfoBuffer, aikCertificate, authData.getKeyType());
        byte[] pubAreaBuffer = base64Service.decode(pubArea);
        TPMT_PUBLIC tpmtPublic = TPMT_PUBLIC.fromTpm(pubAreaBuffer);
        TPMS_ATTEST tpmsAttest = TPMS_ATTEST.fromTpm(certInfoBuffer);
        verifyMagicInTpms(tpmsAttest);
        verifyTPMSCertificateName(tpmtPublic, tpmsAttest, pubAreaBuffer);
        verifyTPMSExtraData(hashedBuffer, tpmsAttest.extraData);
        verifyThatKeysAreSame(tpmtPublic, keyBufferFromAuthData);
    } else {
        throw new Fido2RuntimeException("Problem with TPM attestation. Unsupported");
    }
}
Also used : TPMT_PUBLIC(tss.tpm.TPMT_PUBLIC) TPMS_ATTEST(tss.tpm.TPMS_ATTEST) ArrayList(java.util.ArrayList) JsonNode(com.fasterxml.jackson.databind.JsonNode) IOException(java.io.IOException) Fido2RuntimeException(io.jans.fido2.exception.Fido2RuntimeException) X509Certificate(java.security.cert.X509Certificate)

Aggregations

JsonNode (com.fasterxml.jackson.databind.JsonNode)12 Fido2RuntimeException (io.jans.fido2.exception.Fido2RuntimeException)12 Fido2RegistrationData (io.jans.fido2.model.entry.Fido2RegistrationData)6 PublicKey (java.security.PublicKey)6 Fido2RegistrationEntry (io.jans.fido2.model.entry.Fido2RegistrationEntry)5 X509Certificate (java.security.cert.X509Certificate)5 AuthData (io.jans.fido2.model.auth.AuthData)4 IOException (java.io.IOException)4 ArrayList (java.util.ArrayList)4 Date (java.util.Date)4 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)3 Fido2CompromisedDevice (io.jans.fido2.exception.Fido2CompromisedDevice)3 Fido2MissingAttestationCertException (io.jans.fido2.exception.Fido2MissingAttestationCertException)2 CredAndCounterData (io.jans.fido2.model.auth.CredAndCounterData)2 PublicKeyCredentialDescriptor (io.jans.fido2.model.auth.PublicKeyCredentialDescriptor)2 GregorianCalendar (java.util.GregorianCalendar)2 X509TrustManager (javax.net.ssl.X509TrustManager)2 ArrayNode (com.fasterxml.jackson.databind.node.ArrayNode)1 User (io.jans.as.common.model.common.User)1 DeviceRegistration (io.jans.entry.DeviceRegistration)1