1 /*
2 * Copyright 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "VtsIdentityTestUtils.h"
18
19 #include <aidl/Gtest.h>
20 #include <map>
21
22 #include "VtsAttestationParserSupport.h"
23
24 namespace android::hardware::identity::test_utils {
25
26 using std::endl;
27 using std::map;
28 using std::optional;
29 using std::string;
30 using std::vector;
31
32 using ::android::sp;
33 using ::android::String16;
34 using ::android::binder::Status;
35
setupWritableCredential(sp<IWritableIdentityCredential> & writableCredential,sp<IIdentityCredentialStore> & credentialStore)36 bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
37 sp<IIdentityCredentialStore>& credentialStore) {
38 if (credentialStore == nullptr) {
39 return false;
40 }
41
42 string docType = "org.iso.18013-5.2019.mdl";
43 bool testCredential = true;
44 Status result = credentialStore->createCredential(docType, testCredential, &writableCredential);
45
46 if (result.isOk() && writableCredential != nullptr) {
47 return true;
48 } else {
49 return false;
50 }
51 }
52
generateReaderCertificate(string serialDecimal)53 optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal) {
54 vector<uint8_t> privKey;
55 return generateReaderCertificate(serialDecimal, &privKey);
56 }
57
generateReaderCertificate(string serialDecimal,vector<uint8_t> * outReaderPrivateKey)58 optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal,
59 vector<uint8_t>* outReaderPrivateKey) {
60 optional<vector<uint8_t>> readerKeyPKCS8 = support::createEcKeyPair();
61 if (!readerKeyPKCS8) {
62 return {};
63 }
64
65 optional<vector<uint8_t>> readerPublicKey =
66 support::ecKeyPairGetPublicKey(readerKeyPKCS8.value());
67 optional<vector<uint8_t>> readerKey = support::ecKeyPairGetPrivateKey(readerKeyPKCS8.value());
68 if (!readerPublicKey || !readerKey) {
69 return {};
70 }
71
72 if (outReaderPrivateKey == nullptr) {
73 return {};
74 }
75
76 *outReaderPrivateKey = readerKey.value();
77
78 string issuer = "Android Open Source Project";
79 string subject = "Android IdentityCredential VTS Test";
80 time_t validityNotBefore = time(nullptr);
81 time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
82
83 return support::ecPublicKeyGenerateCertificate(readerPublicKey.value(), readerKey.value(),
84 serialDecimal, issuer, subject,
85 validityNotBefore, validityNotAfter);
86 }
87
addAccessControlProfiles(sp<IWritableIdentityCredential> & writableCredential,const vector<TestProfile> & testProfiles)88 optional<vector<SecureAccessControlProfile>> addAccessControlProfiles(
89 sp<IWritableIdentityCredential>& writableCredential,
90 const vector<TestProfile>& testProfiles) {
91 Status result;
92
93 vector<SecureAccessControlProfile> secureProfiles;
94
95 for (const auto& testProfile : testProfiles) {
96 SecureAccessControlProfile profile;
97 Certificate cert;
98 cert.encodedCertificate = testProfile.readerCertificate;
99 int64_t secureUserId = testProfile.userAuthenticationRequired ? 66 : 0;
100 result = writableCredential->addAccessControlProfile(
101 testProfile.id, cert, testProfile.userAuthenticationRequired,
102 testProfile.timeoutMillis, secureUserId, &profile);
103
104 // Don't use assert so all errors can be outputed. Then return
105 // instead of exit even on errors so caller can decide.
106 EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
107 << "test profile id = " << testProfile.id << endl;
108 EXPECT_EQ(testProfile.id, profile.id);
109 EXPECT_EQ(testProfile.readerCertificate, profile.readerCertificate.encodedCertificate);
110 EXPECT_EQ(testProfile.userAuthenticationRequired, profile.userAuthenticationRequired);
111 EXPECT_EQ(testProfile.timeoutMillis, profile.timeoutMillis);
112 EXPECT_EQ(support::kAesGcmTagSize + support::kAesGcmIvSize, profile.mac.size());
113
114 if (!result.isOk() || testProfile.id != profile.id ||
115 testProfile.readerCertificate != profile.readerCertificate.encodedCertificate ||
116 testProfile.userAuthenticationRequired != profile.userAuthenticationRequired ||
117 testProfile.timeoutMillis != profile.timeoutMillis ||
118 support::kAesGcmTagSize + support::kAesGcmIvSize != profile.mac.size()) {
119 return {};
120 }
121
122 secureProfiles.push_back(profile);
123 }
124
125 return secureProfiles;
126 }
127
128 // Most test expects this function to pass. So we will print out additional
129 // value if failed so more debug data can be provided.
addEntry(sp<IWritableIdentityCredential> & writableCredential,const TestEntryData & entry,int dataChunkSize,map<const TestEntryData *,vector<vector<uint8_t>>> & encryptedBlobs,bool expectSuccess)130 bool addEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry,
131 int dataChunkSize, map<const TestEntryData*, vector<vector<uint8_t>>>& encryptedBlobs,
132 bool expectSuccess) {
133 Status result;
134 vector<vector<uint8_t>> chunks = support::chunkVector(entry.valueCbor, dataChunkSize);
135
136 result = writableCredential->beginAddEntry(entry.profileIds, entry.nameSpace, entry.name,
137 entry.valueCbor.size());
138
139 if (expectSuccess) {
140 EXPECT_TRUE(result.isOk())
141 << result.exceptionCode() << "; " << result.exceptionMessage() << endl
142 << "entry name = " << entry.name << ", name space=" << entry.nameSpace << endl;
143 }
144
145 if (!result.isOk()) {
146 return false;
147 }
148
149 vector<vector<uint8_t>> encryptedChunks;
150 for (const auto& chunk : chunks) {
151 vector<uint8_t> encryptedContent;
152 result = writableCredential->addEntryValue(chunk, &encryptedContent);
153 if (expectSuccess) {
154 EXPECT_TRUE(result.isOk())
155 << result.exceptionCode() << "; " << result.exceptionMessage() << endl
156 << "entry name = " << entry.name << ", name space = " << entry.nameSpace
157 << endl;
158
159 EXPECT_GT(encryptedContent.size(), 0u) << "entry name = " << entry.name
160 << ", name space = " << entry.nameSpace << endl;
161 }
162
163 if (!result.isOk() || encryptedContent.size() <= 0u) {
164 return false;
165 }
166
167 encryptedChunks.push_back(encryptedContent);
168 }
169
170 encryptedBlobs[&entry] = encryptedChunks;
171 return true;
172 }
173
setImageData(vector<uint8_t> & image)174 void setImageData(vector<uint8_t>& image) {
175 image.resize(256 * 1024 - 10);
176 for (size_t n = 0; n < image.size(); n++) {
177 image[n] = (uint8_t)n;
178 }
179 }
180
validateAttestationCertificate(const vector<Certificate> & inputCertificates,const vector<uint8_t> & expectedChallenge,const vector<uint8_t> & expectedAppId,const HardwareInformation & hwInfo)181 bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
182 const vector<uint8_t>& expectedChallenge,
183 const vector<uint8_t>& expectedAppId,
184 const HardwareInformation& hwInfo) {
185 AttestationCertificateParser certParser_(inputCertificates);
186 bool ret = certParser_.parse();
187 EXPECT_TRUE(ret);
188 if (!ret) {
189 return false;
190 }
191
192 // As per the IC HAL, the version of the Identity
193 // Credential HAL is 1.0 - and this is encoded as major*10 + minor. This field is used by
194 // Keymaster which is known to report integers less than or equal to 4 (for KM up to 4.0)
195 // and integers greater or equal than 41 (for KM starting with 4.1).
196 //
197 // Since we won't get to version 4.0 of the IC HAL for a while, let's also check that a KM
198 // version isn't errornously returned.
199 EXPECT_LE(10, certParser_.getKeymasterVersion());
200 EXPECT_GT(40, certParser_.getKeymasterVersion());
201 EXPECT_LE(3, certParser_.getAttestationVersion());
202
203 // Verify the app id matches to whatever we set it to be.
204 optional<vector<uint8_t>> appId =
205 certParser_.getSwEnforcedBlob(::keymaster::TAG_ATTESTATION_APPLICATION_ID);
206 if (appId) {
207 EXPECT_EQ(expectedAppId.size(), appId.value().size());
208 EXPECT_EQ(0, memcmp(expectedAppId.data(), appId.value().data(), expectedAppId.size()));
209 } else {
210 // app id not found
211 EXPECT_EQ(0, expectedAppId.size());
212 }
213
214 EXPECT_TRUE(certParser_.getHwEnforcedBool(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
215 EXPECT_FALSE(certParser_.getHwEnforcedBool(::keymaster::TAG_INCLUDE_UNIQUE_ID));
216
217 // Verify the challenge always matches in size and data of what is passed
218 // in.
219 vector<uint8_t> attChallenge = certParser_.getAttestationChallenge();
220 EXPECT_EQ(expectedChallenge.size(), attChallenge.size());
221 EXPECT_EQ(0, memcmp(expectedChallenge.data(), attChallenge.data(), expectedChallenge.size()));
222
223 // Ensure the attestation conveys that it's implemented in secure hardware (with carve-out
224 // for the reference implementation which cannot be implemented in secure hardware).
225 if (hwInfo.credentialStoreName == "Identity Credential Reference Implementation" &&
226 hwInfo.credentialStoreAuthorName == "Google") {
227 EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getKeymasterSecurityLevel());
228 EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getAttestationSecurityLevel());
229
230 } else {
231 // Actual devices should use TrustedEnvironment or StrongBox.
232 EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getKeymasterSecurityLevel());
233 EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getAttestationSecurityLevel());
234 }
235 return true;
236 }
237
buildRequestNamespaces(const vector<TestEntryData> entries)238 vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries) {
239 vector<RequestNamespace> ret;
240 RequestNamespace curNs;
241 for (const TestEntryData& testEntry : entries) {
242 if (testEntry.nameSpace != curNs.namespaceName) {
243 if (curNs.namespaceName.size() > 0) {
244 ret.push_back(curNs);
245 }
246 curNs.namespaceName = testEntry.nameSpace;
247 curNs.items.clear();
248 }
249
250 RequestDataItem item;
251 item.name = testEntry.name;
252 item.size = testEntry.valueCbor.size();
253 item.accessControlProfileIds = testEntry.profileIds;
254 curNs.items.push_back(item);
255 }
256 if (curNs.namespaceName.size() > 0) {
257 ret.push_back(curNs);
258 }
259 return ret;
260 }
261
262 } // namespace android::hardware::identity::test_utils
263