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.Set; 29 import org.bouncycastle.asn1.ASN1Sequence; 30 import org.junit.Test; 31 import org.junit.runner.RunWith; 32 import org.junit.runners.JUnit4; 33 34 /** Test for {@link ParsedAttestationRecord}. */ 35 @RunWith(JUnit4.class) 36 public class ParsedAttestationRecordTest { 37 38 // Certificate generated by TestDPC with RSA Algorithm and StrongBox Security Level 39 private static final String CERT = 40 "-----BEGIN CERTIFICATE-----\n" 41 + "MIIGCDCCBHCgAwIBAgIBATANBgkqhkiG9w0BAQsFADApMRkwFwYDVQQFExAyZGM1OGIyZDFhMjQx" 42 + "MzI2MQwwCgYDVQQMDANURUUwIBcNNzAwMTAxMDAwMDAwWhgPMjEwNjAyMDcwNjI4MTVaMB8xHTAb" 43 + "BgNVBAMMFEFuZHJvaWQgS2V5c3RvcmUgS2V5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC" 44 + "AQEApNVcnyN40MANMbbo2nMGNq2NNysDSjfLm0W3i6wPKf0ffCYkhWM4dCmQKKf50uAZTBeTit4c" 45 + "NwXeZn3qellMlOsIN3Qc384rfN/8cikrRvUAgibz0Jy7STykjwa7x6tKwqITxbO8HqAhKo8/BQXU" 46 + "xzrOdIg5ciy+UM7Vgh7a7ogen0KL2iGgrsalb1ti7Vlzb6vIJ4WzIC3TGD2sCkoPahghwqFDZZCo" 47 + "/FzaLoNY0jAUX2mL+kf8aUaoxz7xA9FTvgara+1pLBR1s4c8xPS2HdZipcVXWfey0wujv1VAKs4+" 48 + "tXjKlHkYBHBBceEjxUtEmrapSQEdpHPv7Xh9Uanq4QIDAQABo4ICwTCCAr0wDgYDVR0PAQH/BAQD" 49 + "AgeAMIICqQYKKwYBBAHWeQIBEQSCApkwggKVAgEDCgEBAgEECgEBBANhYmMEADCCAc2/hT0IAgYB" 50 + "ZOYGEYe/hUWCAbsEggG3MIIBszGCAYswDAQHYW5kcm9pZAIBHTAZBBRjb20uYW5kcm9pZC5rZXlj" 51 + "aGFpbgIBHTAZBBRjb20uYW5kcm9pZC5zZXR0aW5ncwIBHTAZBBRjb20ucXRpLmRpYWdzZXJ2aWNl" 52 + "cwIBHTAaBBVjb20uYW5kcm9pZC5keW5zeXN0ZW0CAR0wHQQYY29tLmFuZHJvaWQuaW5wdXRkZXZp" 53 + "Y2VzAgEdMB8EGmNvbS5hbmRyb2lkLmxvY2FsdHJhbnNwb3J0AgEdMB8EGmNvbS5hbmRyb2lkLmxv" 54 + "Y2F0aW9uLmZ1c2VkAgEdMB8EGmNvbS5hbmRyb2lkLnNlcnZlci50ZWxlY29tAgEdMCAEG2NvbS5h" 55 + "bmRyb2lkLndhbGxwYXBlcmJhY2t1cAIBHTAhBBxjb20uZ29vZ2xlLlNTUmVzdGFydERldGVjdG9y" 56 + "AgEdMCIEHWNvbS5nb29nbGUuYW5kcm9pZC5oaWRkZW5tZW51AgEBMCMEHmNvbS5hbmRyb2lkLnBy" 57 + "b3ZpZGVycy5zZXR0aW5ncwIBHTEiBCAwGqPLCBE0UBxF8UIqvGbCQiT9Xe1f3I8X5pcXb9hmqjCB" 58 + "rqEIMQYCAQICAQOiAwIBAaMEAgIIAKUFMQMCAQSmCDEGAgEDAgEFv4FIBQIDAQABv4N3AgUAv4U+" 59 + "AwIBAL+FQEwwSgQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQAKAQIEIHKNsSdP" 60 + "HxzxVx3kOAsEilVKxKOA529TVQg1KQhKk3gBv4VBAwIBAL+FQgUCAwMUs7+FTgUCAwMUs7+FTwUC" 61 + "AwMUszANBgkqhkiG9w0BAQsFAAOCAYEAJMIuzdNUdfrE6sIdmsnMn/scSG2odbphj8FkX9JGdF2S" 62 + "OT599HuDY9qhvkru2Dza4sLKK3f4ViBhuR9lpfeprKvstxbtBO7jkLYfVn0ZRzHRHVEyiW5IVKh+" 63 + "qOXVJ9S1lMShOTlsaYJytLKIlcrRAZBEXZiNbzTuVh1CH6X9Ni1dog14snm+lcOeORdL9fht2CHa" 64 + "u/caRnpWiZbjoAoJp0O89uBrRkXPpln51+3jPY6AFny30grNAvKguauDcPPhNV1yR+ylSsQi2gm3" 65 + "Rs4pgtlxFLMfZLgT0cbkl+9zk/QUqlpBP8ftUBsOI0ARr8xhFN3cvq9kXGLtJ9hEP9PRaflAFREk" 66 + "DK3IBIbVcAFZBFoAQOdE9zy0+F5bQrznPGaZg4Dzhcx33qMDUTgHtWoy+k3ePGQMEtmoTTLgQywW" 67 + "OIkXEoFqqGi9GKJXUT1KYi5NsigaYqu7FoN4Qsvs61pMUEfZSPP2AFwkA8uNFbmb9uxcxaGHCA8i" 68 + "3i9VM6yOLIrP\n" 69 + "-----END CERTIFICATE-----"; 70 71 private static final int EXPECTED_ATTESTATION_VERSION = 3; 72 private static final SecurityLevel EXPECTED_ATTESTATION_SECURITY_LEVEL = 73 SecurityLevel.TRUSTED_ENVIRONMENT; 74 private static final int EXPECTED_KEYMASTER_VERSION = 4; 75 private static final SecurityLevel EXPECTED_KEYMASTER_SECURITY_LEVEL = 76 SecurityLevel.TRUSTED_ENVIRONMENT; 77 private static final byte[] EXPECTED_ATTESTATION_CHALLENGE = "abc".getBytes(UTF_8); 78 private static final byte[] EXPECTED_UNIQUE_ID = "".getBytes(UTF_8); 79 getAttestationRecord(String certStr)80 private static X509Certificate getAttestationRecord(String certStr) throws CertificateException { 81 CertificateFactory factory = CertificateFactory.getInstance("X509"); 82 X509Certificate cert = 83 (X509Certificate) 84 factory.generateCertificate(new ByteArrayInputStream(certStr.getBytes(UTF_8))); 85 cert.checkValidity(); 86 return cert; 87 } 88 89 @Test testParseAttestationRecord()90 public void testParseAttestationRecord() throws CertificateException, IOException { 91 X509Certificate x509Certificate = getAttestationRecord(CERT); 92 ParsedAttestationRecord attestationRecord = 93 ParsedAttestationRecord.createParsedAttestationRecord(x509Certificate); 94 95 assertThat(attestationRecord.attestationVersion).isEqualTo(EXPECTED_ATTESTATION_VERSION); 96 assertThat(attestationRecord.attestationSecurityLevel) 97 .isEqualTo(EXPECTED_ATTESTATION_SECURITY_LEVEL); 98 assertThat(attestationRecord.keymasterVersion).isEqualTo(EXPECTED_KEYMASTER_VERSION); 99 assertThat(attestationRecord.keymasterSecurityLevel) 100 .isEqualTo(EXPECTED_KEYMASTER_SECURITY_LEVEL); 101 assertThat(attestationRecord.attestationChallenge).isEqualTo(EXPECTED_ATTESTATION_CHALLENGE); 102 assertThat(attestationRecord.uniqueId).isEqualTo(EXPECTED_UNIQUE_ID); 103 assertThat(attestationRecord.softwareEnforced).isNotNull(); 104 assertThat(attestationRecord.teeEnforced).isNotNull(); 105 } 106 107 @Test testCreateAndParseAttestationRecord()108 public void testCreateAndParseAttestationRecord() { 109 AuthorizationList.Builder teeEnforcedBuilder = AuthorizationList.builder(); 110 teeEnforcedBuilder.userAuthType = Set.of(UserAuthType.FINGERPRINT); 111 teeEnforcedBuilder.attestationIdBrand = "free food".getBytes(UTF_8); 112 ParsedAttestationRecord expected = 113 ParsedAttestationRecord.create( 114 /* attestationVersion= */ 2, 115 /* attestationSecurityLevel= */ SecurityLevel.TRUSTED_ENVIRONMENT, 116 /* keymasterVersion= */ 4, 117 /* keymasterSecurityLevel= */ SecurityLevel.SOFTWARE, 118 /* attestationChallenge= */ "abc".getBytes(UTF_8), 119 /* uniqueId= */ "foodplease".getBytes(UTF_8), 120 /* softwareEnforced= */ AuthorizationList.builder().build(), 121 /* teeEnforced= */ AuthorizationList.builder() 122 .setUserAuthType(Set.of(UserAuthType.FINGERPRINT)) 123 .setAttestationIdBrand("free food".getBytes(UTF_8)).build()); 124 ASN1Sequence seq = expected.toAsn1Sequence(); 125 ParsedAttestationRecord actual = ParsedAttestationRecord.create(seq); 126 assertThat(actual.attestationVersion).isEqualTo(expected.attestationVersion); 127 assertThat(actual.attestationSecurityLevel).isEqualTo(expected.attestationSecurityLevel); 128 assertThat(actual.keymasterVersion).isEqualTo(expected.keymasterVersion); 129 assertThat(actual.keymasterSecurityLevel).isEqualTo(expected.keymasterSecurityLevel); 130 assertThat(actual.attestationChallenge).isEqualTo(expected.attestationChallenge); 131 assertThat(actual.uniqueId).isEqualTo(expected.uniqueId); 132 assertThat(actual.teeEnforced.userAuthType).isEqualTo(expected.teeEnforced.userAuthType); 133 assertThat(actual.teeEnforced.attestationIdBrand) 134 .isEqualTo(expected.teeEnforced.attestationIdBrand); 135 } 136 } 137