• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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