blob: aaebcbe3c9f92b306c077d188c357ceb4a55b3e2 [file] [log] [blame]
Selene Huang92b61d62020-03-04 02:24:16 -08001/*
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
Selene Huangcab019a2020-03-11 04:37:48 -070022#include "VtsAttestationParserSupport.h"
23
Selene Huang92b61d62020-03-04 02:24:16 -080024namespace android::hardware::identity::test_utils {
25
26using std::endl;
27using std::map;
28using std::optional;
29using std::string;
30using std::vector;
31
32using ::android::sp;
33using ::android::String16;
34using ::android::binder::Status;
35
Selene Huangcab019a2020-03-11 04:37:48 -070036bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
Selene Huang92b61d62020-03-04 02:24:16 -080037 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
Selene Huangcab019a2020-03-11 04:37:48 -070053optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal) {
Selene Huang92b61d62020-03-04 02:24:16 -080054 vector<uint8_t> privKey;
Selene Huangcab019a2020-03-11 04:37:48 -070055 return generateReaderCertificate(serialDecimal, &privKey);
Selene Huang92b61d62020-03-04 02:24:16 -080056}
57
Selene Huangcab019a2020-03-11 04:37:48 -070058optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal,
59 vector<uint8_t>* outReaderPrivateKey) {
Selene Huang92b61d62020-03-04 02:24:16 -080060 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
Selene Huangcab019a2020-03-11 04:37:48 -070072 if (outReaderPrivateKey == nullptr) {
73 return {};
74 }
75
76 *outReaderPrivateKey = readerKey.value();
Selene Huang92b61d62020-03-04 02:24:16 -080077
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
Selene Huangcab019a2020-03-11 04:37:48 -070088optional<vector<SecureAccessControlProfile>> addAccessControlProfiles(
Selene Huang92b61d62020-03-04 02:24:16 -080089 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 result = writableCredential->addAccessControlProfile(
100 testProfile.id, cert, testProfile.userAuthenticationRequired,
101 testProfile.timeoutMillis, 0, &profile);
102
103 // Don't use assert so all errors can be outputed. Then return
104 // instead of exit even on errors so caller can decide.
105 EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
106 << "test profile id = " << testProfile.id << endl;
107 EXPECT_EQ(testProfile.id, profile.id);
108 EXPECT_EQ(testProfile.readerCertificate, profile.readerCertificate.encodedCertificate);
109 EXPECT_EQ(testProfile.userAuthenticationRequired, profile.userAuthenticationRequired);
110 EXPECT_EQ(testProfile.timeoutMillis, profile.timeoutMillis);
111 EXPECT_EQ(support::kAesGcmTagSize + support::kAesGcmIvSize, profile.mac.size());
112
113 if (!result.isOk() || testProfile.id != profile.id ||
114 testProfile.readerCertificate != profile.readerCertificate.encodedCertificate ||
115 testProfile.userAuthenticationRequired != profile.userAuthenticationRequired ||
116 testProfile.timeoutMillis != profile.timeoutMillis ||
117 support::kAesGcmTagSize + support::kAesGcmIvSize != profile.mac.size()) {
118 return {};
119 }
120
121 secureProfiles.push_back(profile);
122 }
123
124 return secureProfiles;
125}
126
127// Most test expects this function to pass. So we will print out additional
128// value if failed so more debug data can be provided.
Selene Huangcab019a2020-03-11 04:37:48 -0700129bool addEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry,
Selene Huang92b61d62020-03-04 02:24:16 -0800130 int dataChunkSize, map<const TestEntryData*, vector<vector<uint8_t>>>& encryptedBlobs,
131 bool expectSuccess) {
132 Status result;
133 vector<vector<uint8_t>> chunks = support::chunkVector(entry.valueCbor, dataChunkSize);
134
135 result = writableCredential->beginAddEntry(entry.profileIds, entry.nameSpace, entry.name,
136 entry.valueCbor.size());
137
138 if (expectSuccess) {
139 EXPECT_TRUE(result.isOk())
140 << result.exceptionCode() << "; " << result.exceptionMessage() << endl
141 << "entry name = " << entry.name << ", name space=" << entry.nameSpace << endl;
142 }
143
144 if (!result.isOk()) {
145 return false;
146 }
147
148 vector<vector<uint8_t>> encryptedChunks;
149 for (const auto& chunk : chunks) {
150 vector<uint8_t> encryptedContent;
151 result = writableCredential->addEntryValue(chunk, &encryptedContent);
152 if (expectSuccess) {
153 EXPECT_TRUE(result.isOk())
154 << result.exceptionCode() << "; " << result.exceptionMessage() << endl
155 << "entry name = " << entry.name << ", name space = " << entry.nameSpace
156 << endl;
157
158 EXPECT_GT(encryptedContent.size(), 0u) << "entry name = " << entry.name
159 << ", name space = " << entry.nameSpace << endl;
160 }
161
162 if (!result.isOk() || encryptedContent.size() <= 0u) {
163 return false;
164 }
165
166 encryptedChunks.push_back(encryptedContent);
167 }
168
169 encryptedBlobs[&entry] = encryptedChunks;
170 return true;
171}
172
Selene Huangcab019a2020-03-11 04:37:48 -0700173void setImageData(vector<uint8_t>& image) {
Selene Huang92b61d62020-03-04 02:24:16 -0800174 image.resize(256 * 1024 - 10);
175 for (size_t n = 0; n < image.size(); n++) {
176 image[n] = (uint8_t)n;
177 }
178}
179
Selene Huangcab019a2020-03-11 04:37:48 -0700180bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
181 const vector<uint8_t>& expectedChallenge,
182 const vector<uint8_t>& expectedAppId,
183 const HardwareInformation& hwInfo) {
184 AttestationCertificateParser certParser_(inputCertificates);
185 bool ret = certParser_.parse();
186 EXPECT_TRUE(ret);
187 if (!ret) {
188 return false;
189 }
190
191 // As per the IC HAL, the version of the Identity
192 // Credential HAL is 1.0 - and this is encoded as major*10 + minor. This field is used by
193 // Keymaster which is known to report integers less than or equal to 4 (for KM up to 4.0)
194 // and integers greater or equal than 41 (for KM starting with 4.1).
195 //
196 // Since we won't get to version 4.0 of the IC HAL for a while, let's also check that a KM
197 // version isn't errornously returned.
198 EXPECT_LE(10, certParser_.getKeymasterVersion());
199 EXPECT_GT(40, certParser_.getKeymasterVersion());
200 EXPECT_LE(3, certParser_.getAttestationVersion());
201
202 // Verify the app id matches to whatever we set it to be.
203 optional<vector<uint8_t>> appId =
204 certParser_.getSwEnforcedBlob(::keymaster::TAG_ATTESTATION_APPLICATION_ID);
205 if (appId) {
206 EXPECT_EQ(expectedAppId.size(), appId.value().size());
207 EXPECT_EQ(0, memcmp(expectedAppId.data(), appId.value().data(), expectedAppId.size()));
208 } else {
209 // app id not found
210 EXPECT_EQ(0, expectedAppId.size());
211 }
212
213 EXPECT_TRUE(certParser_.getHwEnforcedBool(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
214 EXPECT_FALSE(certParser_.getHwEnforcedBool(::keymaster::TAG_INCLUDE_UNIQUE_ID));
215
216 // Verify the challenge always matches in size and data of what is passed
217 // in.
218 vector<uint8_t> attChallenge = certParser_.getAttestationChallenge();
219 EXPECT_EQ(expectedChallenge.size(), attChallenge.size());
220 EXPECT_EQ(0, memcmp(expectedChallenge.data(), attChallenge.data(), expectedChallenge.size()));
221
222 // Ensure the attestation conveys that it's implemented in secure hardware (with carve-out
223 // for the reference implementation which cannot be implemented in secure hardware).
224 if (hwInfo.credentialStoreName == "Identity Credential Reference Implementation" &&
225 hwInfo.credentialStoreAuthorName == "Google") {
226 EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getKeymasterSecurityLevel());
227 EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getAttestationSecurityLevel());
228
229 } else {
230 // Actual devices should use TrustedEnvironment or StrongBox.
231 EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getKeymasterSecurityLevel());
232 EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getAttestationSecurityLevel());
233 }
234 return true;
235}
236
David Zeuthen28edb102020-04-28 18:54:55 -0400237vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries) {
238 vector<RequestNamespace> ret;
239 RequestNamespace curNs;
240 for (const TestEntryData& testEntry : entries) {
241 if (testEntry.nameSpace != curNs.namespaceName) {
242 if (curNs.namespaceName.size() > 0) {
243 ret.push_back(curNs);
244 }
245 curNs.namespaceName = testEntry.nameSpace;
246 curNs.items.clear();
247 }
248
249 RequestDataItem item;
250 item.name = testEntry.name;
251 item.size = testEntry.valueCbor.size();
252 item.accessControlProfileIds = testEntry.profileIds;
253 curNs.items.push_back(item);
254 }
255 if (curNs.namespaceName.size() > 0) {
256 ret.push_back(curNs);
257 }
258 return ret;
259}
260
Selene Huang92b61d62020-03-04 02:24:16 -0800261} // namespace android::hardware::identity::test_utils