1 /* Copyright 2019, The Android Open Source Project, Inc. 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package com.google.android.attestation; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static java.nio.charset.StandardCharsets.UTF_8; 20 21 import com.google.android.attestation.AuthorizationList.UserAuthType; 22 import com.google.android.attestation.ParsedAttestationRecord.SecurityLevel; 23 import java.io.ByteArrayInputStream; 24 import java.io.IOException; 25 import java.security.cert.CertificateException; 26 import java.security.cert.CertificateFactory; 27 import java.security.cert.X509Certificate; 28 import java.util.Arrays; 29 30 import com.google.common.collect.ImmutableSet; 31 import org.bouncycastle.asn1.ASN1Sequence; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 import org.junit.runners.JUnit4; 35 36 /** Test for {@link ParsedAttestationRecord}. */ 37 @RunWith(JUnit4.class) 38 public class ParsedAttestationRecordTest { 39 40 // Certificate generated by TestDPC with RSA Algorithm and StrongBox Security Level 41 private static final String CERT = 42 "-----BEGIN CERTIFICATE-----\n" 43 + "MIIGCDCCBHCgAwIBAgIBATANBgkqhkiG9w0BAQsFADApMRkwFwYDVQQFExAyZGM1OGIyZDFhMjQx" 44 + "MzI2MQwwCgYDVQQMDANURUUwIBcNNzAwMTAxMDAwMDAwWhgPMjEwNjAyMDcwNjI4MTVaMB8xHTAb" 45 + "BgNVBAMMFEFuZHJvaWQgS2V5c3RvcmUgS2V5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC" 46 + "AQEApNVcnyN40MANMbbo2nMGNq2NNysDSjfLm0W3i6wPKf0ffCYkhWM4dCmQKKf50uAZTBeTit4c" 47 + "NwXeZn3qellMlOsIN3Qc384rfN/8cikrRvUAgibz0Jy7STykjwa7x6tKwqITxbO8HqAhKo8/BQXU" 48 + "xzrOdIg5ciy+UM7Vgh7a7ogen0KL2iGgrsalb1ti7Vlzb6vIJ4WzIC3TGD2sCkoPahghwqFDZZCo" 49 + "/FzaLoNY0jAUX2mL+kf8aUaoxz7xA9FTvgara+1pLBR1s4c8xPS2HdZipcVXWfey0wujv1VAKs4+" 50 + "tXjKlHkYBHBBceEjxUtEmrapSQEdpHPv7Xh9Uanq4QIDAQABo4ICwTCCAr0wDgYDVR0PAQH/BAQD" 51 + "AgeAMIICqQYKKwYBBAHWeQIBEQSCApkwggKVAgEDCgEBAgEECgEBBANhYmMEADCCAc2/hT0IAgYB" 52 + "ZOYGEYe/hUWCAbsEggG3MIIBszGCAYswDAQHYW5kcm9pZAIBHTAZBBRjb20uYW5kcm9pZC5rZXlj" 53 + "aGFpbgIBHTAZBBRjb20uYW5kcm9pZC5zZXR0aW5ncwIBHTAZBBRjb20ucXRpLmRpYWdzZXJ2aWNl" 54 + "cwIBHTAaBBVjb20uYW5kcm9pZC5keW5zeXN0ZW0CAR0wHQQYY29tLmFuZHJvaWQuaW5wdXRkZXZp" 55 + "Y2VzAgEdMB8EGmNvbS5hbmRyb2lkLmxvY2FsdHJhbnNwb3J0AgEdMB8EGmNvbS5hbmRyb2lkLmxv" 56 + "Y2F0aW9uLmZ1c2VkAgEdMB8EGmNvbS5hbmRyb2lkLnNlcnZlci50ZWxlY29tAgEdMCAEG2NvbS5h" 57 + "bmRyb2lkLndhbGxwYXBlcmJhY2t1cAIBHTAhBBxjb20uZ29vZ2xlLlNTUmVzdGFydERldGVjdG9y" 58 + "AgEdMCIEHWNvbS5nb29nbGUuYW5kcm9pZC5oaWRkZW5tZW51AgEBMCMEHmNvbS5hbmRyb2lkLnBy" 59 + "b3ZpZGVycy5zZXR0aW5ncwIBHTEiBCAwGqPLCBE0UBxF8UIqvGbCQiT9Xe1f3I8X5pcXb9hmqjCB" 60 + "rqEIMQYCAQICAQOiAwIBAaMEAgIIAKUFMQMCAQSmCDEGAgEDAgEFv4FIBQIDAQABv4N3AgUAv4U+" 61 + "AwIBAL+FQEwwSgQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQAKAQIEIHKNsSdP" 62 + "HxzxVx3kOAsEilVKxKOA529TVQg1KQhKk3gBv4VBAwIBAL+FQgUCAwMUs7+FTgUCAwMUs7+FTwUC" 63 + "AwMUszANBgkqhkiG9w0BAQsFAAOCAYEAJMIuzdNUdfrE6sIdmsnMn/scSG2odbphj8FkX9JGdF2S" 64 + "OT599HuDY9qhvkru2Dza4sLKK3f4ViBhuR9lpfeprKvstxbtBO7jkLYfVn0ZRzHRHVEyiW5IVKh+" 65 + "qOXVJ9S1lMShOTlsaYJytLKIlcrRAZBEXZiNbzTuVh1CH6X9Ni1dog14snm+lcOeORdL9fht2CHa" 66 + "u/caRnpWiZbjoAoJp0O89uBrRkXPpln51+3jPY6AFny30grNAvKguauDcPPhNV1yR+ylSsQi2gm3" 67 + "Rs4pgtlxFLMfZLgT0cbkl+9zk/QUqlpBP8ftUBsOI0ARr8xhFN3cvq9kXGLtJ9hEP9PRaflAFREk" 68 + "DK3IBIbVcAFZBFoAQOdE9zy0+F5bQrznPGaZg4Dzhcx33qMDUTgHtWoy+k3ePGQMEtmoTTLgQywW" 69 + "OIkXEoFqqGi9GKJXUT1KYi5NsigaYqu7FoN4Qsvs61pMUEfZSPP2AFwkA8uNFbmb9uxcxaGHCA8i" 70 + "3i9VM6yOLIrP\n" 71 + "-----END CERTIFICATE-----"; 72 private static final String CERT2 = 73 "-----BEGIN CERTIFICATE-----\n" 74 + "MIIEFDCCAnygAwIBAgIVAKZFQPAXr5VWrosuqx4C8tai2XbHMA0GCSqGSIb3DQEB\n" 75 + "CwUAMBgxFjAUBgNVBAMMDVVua25vd25Jc3N1ZXIwHhcNMjMwMjE1MTU0MzIwWhcN\n" 76 + "MjMwMjE1MTU0ODIwWjAdMRswGQYDVQQDDBJBbmRyb2lkQXR0ZXN0ZWRLZXkwggGi\n" 77 + "MA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDJAVfP/7F1bUbDqxMnOVXpSjt5\n" 78 + "NJwYemBJkN7l7TTbAhTfMW91006Si/snd79Y6bsJklVoiEN9LGL7tQrJEf5lSSLX\n" 79 + "ZeppjsbLqKnogFHhDJy2vaSiypV2wZdX+kO0qqIKjRvgSqHuTz3gemI1rWilrG3C\n" 80 + "vd3iHGlkw/4X5PpHQKz99/20p85HP6f/jydMHewFDRQCbkbo2pJ5WrJsyPe9me3o\n" 81 + "QE0O3lgij7jJ/UBHyb9iH0w13yi+1yZ/jgyojL4QNUeWZnxW656zfHCB8weePD+l\n" 82 + "tX4AAztZTziJQwk3zVClw4xIPTeztQV6ddRQgjSjGvWanpXqhJx8mq11gWaVJoCl\n" 83 + "q/I0KOguVsKq42M25uhF7/iAQjC+6lOUUfi2+aPwyTUfGHc5Bw/rTSw2LzvZDnUW\n" 84 + "8/yw4OUTyDravVcQLeoBES4+O5cVL0yTKDY0THG+ymgsFNgFS7PXUnAbXczYzvg8\n" 85 + "ldXKOXxnF5nWgg55n2iSQ6mqtHDEUsjcxjmuFcMCAwEAAaNQME4wTAYKKwYBBAHW\n" 86 + "eQIBEQQ+MDwCAQEKAQECAQIKAQEEEkEgcmFuZG9tIGNoYWxsZW5nZQQAMAAwFr+F\n" 87 + "SQgEBlNFUklBTL+FSgYEBElNRUkwDQYJKoZIhvcNAQELBQADggGBAHSms4IBjkc8\n" 88 + "1ZLHu5l70Ih2RrNU4XAc2E/oJX8OsBte9ZRwDT3TdcfLeg0rSneS+aB4xN1BGfmL\n" 89 + "DPZ1epRzMY4RagVhzBEauHpTaM2imRT9RN5TxbFvuMC4ELICYr5qHfqeALIlMET3\n" 90 + "TbCAo3njpNh5ids6qdlmpZRoYBQNMKfWJn8SUtCmVMk87FA7RZZCqCiRk+PBnciT\n" 91 + "O3LLbwT4aBlMinQ84gBfVXRqOvGAeGOgojDqGyK3tDMjIS7itpGb23vGogxHiHjA\n" 92 + "i8hiQhsHA+C89duCdeGyWZGmxwln7QRsosFI7G4ZOufXPLZt/DauNAC2Mb2OPcDw\n" 93 + "4tSKQvzQiL9UG4X3Cck0JnATxjT5sLttshJl98V6jQHcWSnjg8+oa3B8WgcePX8E\n" 94 + "QgcLhYaEGo9WDYJQvHfuUE5AquTxdTRbeiDbV7W+FAOQ5zi/wiGit86gF26120OQ\n" 95 + "KzQHP94/ORuAT/lkv3Fp3HytF4n3scur1nI0WqrfKpbUuPkmndCIbg==\n" 96 + "-----END CERTIFICATE-----\n"; 97 98 private static final int EXPECTED_ATTESTATION_VERSION = 3; 99 private static final SecurityLevel EXPECTED_ATTESTATION_SECURITY_LEVEL = 100 SecurityLevel.TRUSTED_ENVIRONMENT; 101 private static final int EXPECTED_KEYMASTER_VERSION = 4; 102 private static final SecurityLevel EXPECTED_KEYMASTER_SECURITY_LEVEL = 103 SecurityLevel.TRUSTED_ENVIRONMENT; 104 private static final byte[] EXPECTED_ATTESTATION_CHALLENGE = "abc".getBytes(UTF_8); 105 private static final byte[] EXPECTED_UNIQUE_ID = "".getBytes(UTF_8); 106 getAttestationRecord(String certStr)107 private static X509Certificate getAttestationRecord(String certStr) throws CertificateException { 108 CertificateFactory factory = CertificateFactory.getInstance("X509"); 109 X509Certificate cert = 110 (X509Certificate) 111 factory.generateCertificate(new ByteArrayInputStream(certStr.getBytes(UTF_8))); 112 return cert; 113 } 114 115 @Test testParseAttestationRecord()116 public void testParseAttestationRecord() throws CertificateException, IOException { 117 X509Certificate x509Certificate = getAttestationRecord(CERT); 118 X509Certificate x509Certificate2 = getAttestationRecord(CERT2); 119 ParsedAttestationRecord attestationRecord = 120 ParsedAttestationRecord.createParsedAttestationRecord(Arrays.asList(x509Certificate2, x509Certificate)); 121 122 assertThat(attestationRecord.attestationVersion).isEqualTo(EXPECTED_ATTESTATION_VERSION); 123 assertThat(attestationRecord.attestationSecurityLevel) 124 .isEqualTo(EXPECTED_ATTESTATION_SECURITY_LEVEL); 125 assertThat(attestationRecord.keymasterVersion).isEqualTo(EXPECTED_KEYMASTER_VERSION); 126 assertThat(attestationRecord.keymasterSecurityLevel) 127 .isEqualTo(EXPECTED_KEYMASTER_SECURITY_LEVEL); 128 assertThat(attestationRecord.attestationChallenge).isEqualTo(EXPECTED_ATTESTATION_CHALLENGE); 129 assertThat(attestationRecord.uniqueId).isEqualTo(EXPECTED_UNIQUE_ID); 130 assertThat(attestationRecord.softwareEnforced).isNotNull(); 131 assertThat(attestationRecord.teeEnforced).isNotNull(); 132 } 133 134 @Test testCreateAndParseAttestationRecord()135 public void testCreateAndParseAttestationRecord() { 136 AuthorizationList.Builder teeEnforcedBuilder = AuthorizationList.builder(); 137 teeEnforcedBuilder.userAuthType = ImmutableSet.of(UserAuthType.FINGERPRINT); 138 teeEnforcedBuilder.attestationIdBrand = "free food".getBytes(UTF_8); 139 ParsedAttestationRecord expected = 140 ParsedAttestationRecord.create( 141 /* attestationVersion= */ 2, 142 /* attestationSecurityLevel= */ SecurityLevel.TRUSTED_ENVIRONMENT, 143 /* keymasterVersion= */ 4, 144 /* keymasterSecurityLevel= */ SecurityLevel.SOFTWARE, 145 /* attestationChallenge= */ "abc".getBytes(UTF_8), 146 /* uniqueId= */ "foodplease".getBytes(UTF_8), 147 /* softwareEnforced= */ AuthorizationList.builder().build(), 148 /* teeEnforced= */ AuthorizationList.builder() 149 .setUserAuthType(ImmutableSet.of(UserAuthType.FINGERPRINT)) 150 .setAttestationIdBrand("free food".getBytes(UTF_8)).build()); 151 ASN1Sequence seq = expected.toAsn1Sequence(); 152 ParsedAttestationRecord actual = ParsedAttestationRecord.create(seq); 153 assertThat(actual.attestationVersion).isEqualTo(expected.attestationVersion); 154 assertThat(actual.attestationSecurityLevel).isEqualTo(expected.attestationSecurityLevel); 155 assertThat(actual.keymasterVersion).isEqualTo(expected.keymasterVersion); 156 assertThat(actual.keymasterSecurityLevel).isEqualTo(expected.keymasterSecurityLevel); 157 assertThat(actual.attestationChallenge).isEqualTo(expected.attestationChallenge); 158 assertThat(actual.uniqueId).isEqualTo(expected.uniqueId); 159 assertThat(actual.teeEnforced.userAuthType).isEqualTo(expected.teeEnforced.userAuthType); 160 assertThat(actual.teeEnforced.attestationIdBrand) 161 .isEqualTo(expected.teeEnforced.attestationIdBrand); 162 } 163 } 164