Search code examples
sslssl-certificatex509certificatex509devicecheck

Not able to verify the validity of X509Certificate using Apples App attest root certificate


All I am able to do is validate the generated X509Certificate using its method checkValidity(), but as per the steps mentioned in https://developer.apple.com/documentation/devicecheck/validating_apps_that_connect_to_your_server, we have to validate the X509Certificate using Apple App attest root certificate which is

-----BEGIN CERTIFICATE-----
MIICITCCAaegAwIBAgIQC/O+DvHN0uD7jG5yH2IXmDAKBggqhkjOPQQDAzBSMSYw
JAYDVQQDDB1BcHBsZSBBcHAgQXR0ZXN0YXRpb24gUm9vdCBDQTETMBEGA1UECgwK
QXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTAeFw0yMDAzMTgxODMyNTNa
Fw00NTAzMTUwMDAwMDBaMFIxJjAkBgNVBAMMHUFwcGxlIEFwcCBBdHRlc3RhdGlv
biBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9y
bmlhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAERTHhmLW07ATaFQIEVwTtT4dyctdh
NbJhFs/Ii2FdCgAHGbpphY3+d8qjuDngIN3WVhQUBHAoMeQ/cLiP1sOUtgjqK9au
Yen1mMEvRq9Sk3Jm5X8U62H+xTD3FE9TgS41o0IwQDAPBgNVHRMBAf8EBTADAQH/
MB0GA1UdDgQWBBSskRBTM72+aEH/pwyp5frq5eWKoTAOBgNVHQ8BAf8EBAMCAQYw
CgYIKoZIzj0EAwMDaAAwZQIwQgFGnByvsiVbpTKwSga0kP0e8EeDS4+sQmTvb7vn
53O5+FRXgeLhpJ06ysC5PrOyAjEAp5U4xDgEgllF7En3VcE3iexZZtKeYnpqtijV
oyFraWVIyd/dganmrduC1bmTBGwD
-----END CERTIFICATE-----

You can have a look at my code:

String decodedCredCert = "
    -----BEGIN CERTIFICATE----MIIC4jCCAmmgAwIBAgIGAX66NktmMAoGCCqGSM49BAMCME8xIzAhBgNVBAMMGkFwcGxlIEFwcCBBdHRlc3RhdGlvbiBDQSAxMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIyMDIwMTExMzM0N1oXDTIyMDIwNDExMzM0N1owgZExSTBHBgNVBAMMQGMwYTY1ZmRjYjE1MDJjNTNmNzUyMzM4NzZlM2ViZTE3NGVlMzYyODkwZDVmZGE3N2RmZTJhMmE2NWQwOTQ1MGYxGjAYBgNVBAsMEUFBQSBDZXJ0aWZpY2F0aW9uMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExooI0SVHKxhLJu+1zDz1VmCQU7SDdoYTBP5FPsl3sn2sYc1De9tzkKCbb/txsvZXDU6cn+HH5Lt3w4+s+wkkmqOB7TCB6jAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIE8DB6BgkqhkiG92NkCAUEbTBrpAMCAQq/iTADAgEBv4kxAwIBAL+JMgMCAQG/iTMDAgEBv4k0IgQgV0EyREI2MzdKVy5jb20uZ2wubWljaGFlbEtvcnMucWGlBgQEc2tzIL+JNgMCAQW/iTcDAgEAv4k5AwIBAL+JOgMCAQAwGQYJKoZIhvdjZAgHBAwwCr+KeAYEBDE1LjIwMwYJKoZIhvdjZAgCBCYwJKEiBCCDM1heaSkW2MvNzjxqor1xYX1U/tdYlXz9a1CiCT/VBjAKBggqhkjOPQQDAgNnADBkAjA4Ek+QKVFVunbBBBbjQ4qfni7vhXVABvbV/ru8CjsSc/fkuKsR4mKmmWjNoFq2vnACMAv5YFRC6rt1fv9vD1duDxv608DOGZtC95H7LOI65RHn0IYiq1iMLfBF 
    MPUPwJACRw==
    -----END CERTIFICATE----- ";
                        X509Certificate cert1 = getParentCertificate(decodedCredCert);
                        System.out.println(cert1);
                        cert1.checkValidity();

where my


Solution

  • This app attest step is to verify the certificate chain. You will get 2 certificates in attestation request i.e. under x5c[0], x5c[1]. These are leaf and intermediate certificates.

    To verify the certificate chain, x5c[0] certificate should be signed by x5c[1] and x5c[1] certificate should be signed by Apple App attest root certificate.

    Sample code for this

        CertificateFactory cf = CertificateFactory.getInstance(AppConstants.X_509);
        byte[] credCertByte = Base64.getDecoder().decode(x5c[0]);
        X509Certificate credCert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(credCertByte));
    
        byte[] caCertByte = Base64.getDecoder().decode(x5c[1]);
        X509Certificate caCert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(caCertByte));
        X509Certificate appleAppAttestationRootCaCert = (X509Certificate) cf
                .generateCertificate(APPLE_APP_ATTEST_CERT);
    
        credCert.verify(caCert.getPublicKey());
        caCert.verify(appleAppAttestationRootCaCert.getPublicKey());
    

    This is the code for NodeJS/Typescript:

    import fs from 'fs';
    import crypto from 'crypto'
    
        const appleAppAttestationRootCaCert = fs.readFileSync(__dirname + '/../assets/AppleRootCA-G3.pem').toString();
    
        const credCert = new crypto.X509Certificate(Buffer.from(x5c[0], 'base64'))
        const caCert = new crypto.X509Certificate(Buffer.from(x5c[1], 'base64'))
        const appleCert = new crypto.X509Certificate(appleAppAttestationRootCaCert)
    
        const valid = credCert.verify(caCert.publicKey)
        console.log("Valid:", valid)
        caCert.verify(appleCert.publicKey);
        console.log("Valid with Apple Key:", valid)