blob: 57bc27a3f66d227d76acc07635fc0cd63c8dc05b [file] [log] [blame]
Shawn Willden274bb552020-09-30 22:39:22 -06001/*
2 * Copyright (C) 2020 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#define LOG_TAG "VtsRemotelyProvisionableComponentTests"
18
19#include <RemotelyProvisionedComponent.h>
Shawn Willden274bb552020-09-30 22:39:22 -060020#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
21#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
22#include <android/binder_manager.h>
23#include <cppbor_parse.h>
24#include <cppcose/cppcose.h>
25#include <gmock/gmock.h>
Shawn Willden274bb552020-09-30 22:39:22 -060026#include <keymaster/keymaster_configuration.h>
David Drysdalef0d516d2021-03-22 07:51:43 +000027#include <keymint_support/authorization_set.h>
28#include <openssl/ec.h>
29#include <openssl/ec_key.h>
30#include <openssl/x509.h>
Shawn Willden274bb552020-09-30 22:39:22 -060031#include <remote_prov/remote_prov_utils.h>
32
David Drysdalef0d516d2021-03-22 07:51:43 +000033#include "KeyMintAidlTestBase.h"
34
Shawn Willden274bb552020-09-30 22:39:22 -060035namespace aidl::android::hardware::security::keymint::test {
36
37using ::std::string;
38using ::std::vector;
39
40namespace {
41
42#define INSTANTIATE_REM_PROV_AIDL_TEST(name) \
43 INSTANTIATE_TEST_SUITE_P( \
44 PerInstance, name, \
45 testing::ValuesIn(VtsRemotelyProvisionedComponentTests::build_params()), \
46 ::android::PrintInstanceNameToString)
47
48using bytevec = std::vector<uint8_t>;
49using testing::MatchesRegex;
50using namespace remote_prov;
51using namespace keymaster;
52
53bytevec string_to_bytevec(const char* s) {
54 const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
55 return bytevec(p, p + strlen(s));
56}
57
David Drysdalef0d516d2021-03-22 07:51:43 +000058void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey) {
59 // Extract x and y affine coordinates from the encoded Cose_Key.
60 auto [parsedPayload, __, payloadParseErr] = cppbor::parse(coseKeyData);
61 ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
62 auto coseKey = parsedPayload->asMap();
63 const std::unique_ptr<cppbor::Item>& xItem = coseKey->get(cppcose::CoseKey::PUBKEY_X);
64 ASSERT_NE(xItem->asBstr(), nullptr);
65 vector<uint8_t> x = xItem->asBstr()->value();
66 const std::unique_ptr<cppbor::Item>& yItem = coseKey->get(cppcose::CoseKey::PUBKEY_Y);
67 ASSERT_NE(yItem->asBstr(), nullptr);
68 vector<uint8_t> y = yItem->asBstr()->value();
69
70 // Concatenate: 0x04 (uncompressed form marker) | x | y
71 vector<uint8_t> pubKeyData{0x04};
72 pubKeyData.insert(pubKeyData.end(), x.begin(), x.end());
73 pubKeyData.insert(pubKeyData.end(), y.begin(), y.end());
74
75 EC_KEY_Ptr ecKey = EC_KEY_Ptr(EC_KEY_new());
76 ASSERT_NE(ecKey, nullptr);
77 EC_GROUP_Ptr group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
78 ASSERT_NE(group, nullptr);
79 ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
80 EC_POINT_Ptr point = EC_POINT_Ptr(EC_POINT_new(group.get()));
81 ASSERT_NE(point, nullptr);
82 ASSERT_EQ(EC_POINT_oct2point(group.get(), point.get(), pubKeyData.data(), pubKeyData.size(),
83 nullptr),
84 1);
85 ASSERT_EQ(EC_KEY_set_public_key(ecKey.get(), point.get()), 1);
86
87 EVP_PKEY_Ptr pubKey = EVP_PKEY_Ptr(EVP_PKEY_new());
88 ASSERT_NE(pubKey, nullptr);
89 EVP_PKEY_assign_EC_KEY(pubKey.get(), ecKey.release());
90 *signingKey = std::move(pubKey);
91}
92
David Drysdalec8400772021-03-11 12:35:11 +000093void check_cose_key(const vector<uint8_t>& data, bool testMode) {
94 auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
95 ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
96
97 // The following check assumes that canonical CBOR encoding is used for the COSE_Key.
98 if (testMode) {
99 EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
100 MatchesRegex("{\n"
101 " 1 : 2,\n" // kty: EC2
102 " 3 : -7,\n" // alg: ES256
103 " -1 : 1,\n" // EC id: P256
104 // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
105 // sequence of 32 hexadecimal bytes, enclosed in braces and
106 // separated by commas. In this case, some Ed25519 public key.
107 " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
108 " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
109 " -70000 : null,\n" // test marker
110 "}"));
111 } else {
112 EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
113 MatchesRegex("{\n"
114 " 1 : 2,\n" // kty: EC2
115 " 3 : -7,\n" // alg: ES256
116 " -1 : 1,\n" // EC id: P256
117 // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
118 // sequence of 32 hexadecimal bytes, enclosed in braces and
119 // separated by commas. In this case, some Ed25519 public key.
120 " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
121 " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
122 "}"));
123 }
124}
125
126void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
127 vector<uint8_t>* payload_value) {
128 auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
129 ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
130
131 ASSERT_NE(coseMac0->asArray(), nullptr);
132 ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
133
134 auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
135 ASSERT_NE(protParms, nullptr);
136
137 // Header label:value of 'alg': HMAC-256
138 ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
139
140 auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
141 ASSERT_NE(unprotParms, nullptr);
142 ASSERT_EQ(unprotParms->size(), 0);
143
144 // The payload is a bstr holding an encoded COSE_Key
145 auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
146 ASSERT_NE(payload, nullptr);
147 check_cose_key(payload->value(), testMode);
148
149 auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
150 ASSERT_TRUE(coseMac0Tag);
151 auto extractedTag = coseMac0Tag->value();
152 EXPECT_EQ(extractedTag.size(), 32U);
153
154 // Compare with tag generated with kTestMacKey. Should only match in test mode
155 auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
156 payload->value());
157 ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
158
159 if (testMode) {
160 EXPECT_EQ(*testTag, extractedTag);
161 } else {
162 EXPECT_NE(*testTag, extractedTag);
163 }
164 if (payload_value != nullptr) {
165 *payload_value = payload->value();
166 }
167}
168
David Drysdalee99ed862021-03-15 16:43:06 +0000169ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
170 auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
171 if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
172 return "COSE Mac0 parse failed";
173 }
174 auto protParams = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
175 auto unprotParams = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
176 auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
177 auto tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
178 if (!protParams || !unprotParams || !payload || !tag) {
179 return "Invalid COSE_Sign1: missing content";
180 }
181 auto corruptMac0 = cppbor::Array();
182 corruptMac0.add(protParams->clone());
183 corruptMac0.add(unprotParams->clone());
184 corruptMac0.add(payload->clone());
185 vector<uint8_t> tagData = tag->value();
186 tagData[0] ^= 0x08;
187 tagData[tagData.size() - 1] ^= 0x80;
188 corruptMac0.add(cppbor::Bstr(tagData));
189
190 return MacedPublicKey{corruptMac0.encode()};
191}
192
David Drysdalecceca9f2021-03-12 15:49:47 +0000193ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
194 if (coseSign1->size() != kCoseSign1EntryCount) {
195 return "Invalid COSE_Sign1, wrong entry count";
196 }
197 const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
198 const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
199 const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
200 const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
201 if (!protectedParams || !unprotectedParams || !payload || !signature) {
202 return "Invalid COSE_Sign1: missing content";
203 }
204
205 auto corruptSig = cppbor::Array();
206 corruptSig.add(protectedParams->clone());
207 corruptSig.add(unprotectedParams->clone());
208 corruptSig.add(payload->clone());
209 vector<uint8_t> sigData = signature->value();
210 sigData[0] ^= 0x08;
211 corruptSig.add(cppbor::Bstr(sigData));
212
213 return std::move(corruptSig);
214}
215
216ErrMsgOr<EekChain> corrupt_sig_chain(const EekChain& eek, int which) {
217 auto [chain, _, parseErr] = cppbor::parse(eek.chain);
218 if (!chain || !chain->asArray()) {
219 return "EekChain parse failed";
220 }
221
222 cppbor::Array* eekChain = chain->asArray();
223 if (which >= eekChain->size()) {
224 return "selected sig out of range";
225 }
226 auto corruptChain = cppbor::Array();
227
228 for (int ii = 0; ii < eekChain->size(); ++ii) {
229 if (ii == which) {
230 auto sig = corrupt_sig(eekChain->get(which)->asArray());
231 if (!sig) {
232 return "Failed to build corrupted signature" + sig.moveMessage();
233 }
234 corruptChain.add(sig.moveValue());
235 } else {
236 corruptChain.add(eekChain->get(ii)->clone());
237 }
238 }
239 return EekChain{corruptChain.encode(), eek.last_pubkey, eek.last_privkey};
240}
241
David Drysdale4d3c2982021-03-31 18:21:40 +0100242string device_suffix(const string& name) {
243 size_t pos = name.find('/');
244 if (pos == string::npos) {
245 return name;
246 }
247 return name.substr(pos + 1);
248}
249
250bool matching_keymint_device(const string& rp_name, std::shared_ptr<IKeyMintDevice>* keyMint) {
251 string rp_suffix = device_suffix(rp_name);
252
253 vector<string> km_names = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
254 for (const string& km_name : km_names) {
255 // If the suffix of the KeyMint instance equals the suffix of the
256 // RemotelyProvisionedComponent instance, assume they match.
257 if (device_suffix(km_name) == rp_suffix && AServiceManager_isDeclared(km_name.c_str())) {
258 ::ndk::SpAIBinder binder(AServiceManager_waitForService(km_name.c_str()));
259 *keyMint = IKeyMintDevice::fromBinder(binder);
260 return true;
261 }
262 }
263 return false;
264}
265
Shawn Willden274bb552020-09-30 22:39:22 -0600266} // namespace
267
268class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
269 public:
270 virtual void SetUp() override {
271 if (AServiceManager_isDeclared(GetParam().c_str())) {
272 ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
273 provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
274 }
275 ASSERT_NE(provisionable_, nullptr);
276 }
277
278 static vector<string> build_params() {
279 auto params = ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
280 return params;
281 }
282
283 protected:
284 std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
285};
286
287using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
288
289INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
290
291/**
David Drysdalef0d516d2021-03-22 07:51:43 +0000292 * Generate and validate a production-mode key. MAC tag can't be verified, but
293 * the private key blob should be usable in KeyMint operations.
Shawn Willden274bb552020-09-30 22:39:22 -0600294 */
Max Bires126869a2021-02-21 18:32:59 -0800295TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600296 MacedPublicKey macedPubKey;
297 bytevec privateKeyBlob;
298 bool testMode = false;
299 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
300 ASSERT_TRUE(status.isOk());
David Drysdalef0d516d2021-03-22 07:51:43 +0000301 vector<uint8_t> coseKeyData;
302 check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
David Drysdale4d3c2982021-03-31 18:21:40 +0100303}
304
305/**
306 * Generate and validate a production-mode key, then use it as a KeyMint attestation key.
307 */
308TEST_P(GenerateKeyTests, generateAndUseEcdsaP256Key_prodMode) {
309 // See if there is a matching IKeyMintDevice for this IRemotelyProvisionedComponent.
310 std::shared_ptr<IKeyMintDevice> keyMint;
311 if (!matching_keymint_device(GetParam(), &keyMint)) {
312 // No matching IKeyMintDevice.
313 GTEST_SKIP() << "Skipping key use test as no matching KeyMint device found";
314 return;
315 }
316 KeyMintHardwareInfo info;
317 ASSERT_TRUE(keyMint->getHardwareInfo(&info).isOk());
318
319 MacedPublicKey macedPubKey;
320 bytevec privateKeyBlob;
321 bool testMode = false;
322 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
323 ASSERT_TRUE(status.isOk());
324 vector<uint8_t> coseKeyData;
325 check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
326
David Drysdalef0d516d2021-03-22 07:51:43 +0000327 AttestationKey attestKey;
328 attestKey.keyBlob = std::move(privateKeyBlob);
329 attestKey.issuerSubjectName = make_name_from_str("Android Keystore Key");
Shawn Willden274bb552020-09-30 22:39:22 -0600330
David Drysdalef0d516d2021-03-22 07:51:43 +0000331 // Generate an ECDSA key that is attested by the generated P256 keypair.
332 AuthorizationSet keyDesc = AuthorizationSetBuilder()
333 .Authorization(TAG_NO_AUTH_REQUIRED)
334 .EcdsaSigningKey(256)
335 .AttestationChallenge("foo")
336 .AttestationApplicationId("bar")
337 .Digest(Digest::NONE)
338 .SetDefaultValidity();
339 KeyCreationResult creationResult;
340 auto result = keyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
341 ASSERT_TRUE(result.isOk());
342 vector<uint8_t> attested_key_blob = std::move(creationResult.keyBlob);
343 vector<KeyCharacteristics> attested_key_characteristics =
344 std::move(creationResult.keyCharacteristics);
345 vector<Certificate> attested_key_cert_chain = std::move(creationResult.certificateChain);
346 EXPECT_EQ(attested_key_cert_chain.size(), 1);
347
348 AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
349 AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
350 EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced,
351 info.securityLevel,
352 attested_key_cert_chain[0].encodedCertificate));
353
354 // Attestation by itself is not valid (last entry is not self-signed).
355 EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
356
357 // The signature over the attested key should correspond to the P256 public key.
358 X509_Ptr key_cert(parse_cert_blob(attested_key_cert_chain[0].encodedCertificate));
359 ASSERT_TRUE(key_cert.get());
360 EVP_PKEY_Ptr signing_pubkey;
361 p256_pub_key(coseKeyData, &signing_pubkey);
362 ASSERT_TRUE(signing_pubkey.get());
363
364 ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
365 << "Verification of attested certificate failed "
366 << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
Shawn Willden274bb552020-09-30 22:39:22 -0600367}
368
369/**
370 * Generate and validate a test-mode key.
371 */
Max Bires126869a2021-02-21 18:32:59 -0800372TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600373 MacedPublicKey macedPubKey;
374 bytevec privateKeyBlob;
375 bool testMode = true;
376 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
377 ASSERT_TRUE(status.isOk());
378
David Drysdalec8400772021-03-11 12:35:11 +0000379 check_maced_pubkey(macedPubKey, testMode, nullptr);
Shawn Willden274bb552020-09-30 22:39:22 -0600380}
381
382class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
383 protected:
David Drysdalec8400772021-03-11 12:35:11 +0000384 CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
David Drysdalecceca9f2021-03-12 15:49:47 +0000385 generateEek(3);
386 }
387
388 void generateEek(size_t eekLength) {
389 auto chain = generateEekChain(eekLength, eekId_);
Shawn Willden274bb552020-09-30 22:39:22 -0600390 EXPECT_TRUE(chain) << chain.message();
391 if (chain) eekChain_ = chain.moveValue();
David Drysdalecceca9f2021-03-12 15:49:47 +0000392 eekLength_ = eekLength;
Shawn Willden274bb552020-09-30 22:39:22 -0600393 }
394
395 void generateKeys(bool testMode, size_t numKeys) {
396 keysToSign_ = std::vector<MacedPublicKey>(numKeys);
397 cborKeysToSign_ = cppbor::Array();
398
399 for (auto& key : keysToSign_) {
400 bytevec privateKeyBlob;
401 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
402 ASSERT_TRUE(status.isOk()) << status.getMessage();
403
David Drysdalec8400772021-03-11 12:35:11 +0000404 vector<uint8_t> payload_value;
405 check_maced_pubkey(key, testMode, &payload_value);
406 cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
Shawn Willden274bb552020-09-30 22:39:22 -0600407 }
408 }
409
David Drysdalef6fc5a62021-03-31 16:14:31 +0100410 void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
David Drysdalec8400772021-03-11 12:35:11 +0000411 const bytevec& keysToSignMac, const ProtectedData& protectedData) {
412 auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
413 ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
414 ASSERT_TRUE(parsedProtectedData->asArray());
415 ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
416
417 auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
418 ASSERT_TRUE(senderPubkey) << senderPubkey.message();
419 EXPECT_EQ(senderPubkey->second, eekId_);
420
421 auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
422 senderPubkey->first, false /* senderIsA */);
423 ASSERT_TRUE(sessionKey) << sessionKey.message();
424
425 auto protectedDataPayload =
426 decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
427 ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
428
429 auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
430 ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
431 ASSERT_TRUE(parsedPayload->asArray());
432 EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
433
434 auto& signedMac = parsedPayload->asArray()->get(0);
435 auto& bcc = parsedPayload->asArray()->get(1);
436 ASSERT_TRUE(signedMac && signedMac->asArray());
437 ASSERT_TRUE(bcc && bcc->asArray());
438
439 // BCC is [ pubkey, + BccEntry]
440 auto bccContents = validateBcc(bcc->asArray());
441 ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
442 ASSERT_GT(bccContents->size(), 0U);
443
David Drysdalef6fc5a62021-03-31 16:14:31 +0100444 auto [deviceInfoMap, __2, deviceInfoErrMsg] = cppbor::parse(deviceInfo.deviceInfo);
445 ASSERT_TRUE(deviceInfoMap) << "Failed to parse deviceInfo: " << deviceInfoErrMsg;
446 ASSERT_TRUE(deviceInfoMap->asMap());
447
David Drysdalec8400772021-03-11 12:35:11 +0000448 auto& signingKey = bccContents->back().pubKey;
David Drysdalef6fc5a62021-03-31 16:14:31 +0100449 auto macKey = verifyAndParseCoseSign1(/* ignore_signature = */ false, signedMac->asArray(),
450 signingKey,
451 cppbor::Array() // SignedMacAad
David Drysdalec8400772021-03-11 12:35:11 +0000452 .add(challenge_)
David Drysdalef6fc5a62021-03-31 16:14:31 +0100453 .add(std::move(deviceInfoMap))
David Drysdalec8400772021-03-11 12:35:11 +0000454 .encode());
455 ASSERT_TRUE(macKey) << macKey.message();
456
457 auto coseMac0 = cppbor::Array()
458 .add(cppbor::Map() // protected
459 .add(ALGORITHM, HMAC_256)
460 .canonicalize()
461 .encode())
462 .add(cppbor::Map()) // unprotected
463 .add(keysToSign.encode()) // payload (keysToSign)
464 .add(keysToSignMac); // tag
465
466 auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
467 ASSERT_TRUE(macPayload) << macPayload.message();
468 }
469
Shawn Willden274bb552020-09-30 22:39:22 -0600470 bytevec eekId_;
David Drysdalecceca9f2021-03-12 15:49:47 +0000471 size_t eekLength_;
Shawn Willden274bb552020-09-30 22:39:22 -0600472 EekChain eekChain_;
David Drysdalec8400772021-03-11 12:35:11 +0000473 bytevec challenge_;
Shawn Willden274bb552020-09-30 22:39:22 -0600474 std::vector<MacedPublicKey> keysToSign_;
475 cppbor::Array cborKeysToSign_;
476};
477
478/**
479 * Generate an empty certificate request in test mode, and decrypt and verify the structure and
480 * content.
481 */
Max Bires126869a2021-02-21 18:32:59 -0800482TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600483 bool testMode = true;
David Drysdalecceca9f2021-03-12 15:49:47 +0000484 for (size_t eekLength : {2, 3, 7}) {
485 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
486 generateEek(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600487
David Drysdalecceca9f2021-03-12 15:49:47 +0000488 bytevec keysToSignMac;
489 DeviceInfo deviceInfo;
490 ProtectedData protectedData;
491 auto status = provisionable_->generateCertificateRequest(
492 testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
493 &protectedData, &keysToSignMac);
494 ASSERT_TRUE(status.isOk()) << status.getMessage();
495
David Drysdalef6fc5a62021-03-31 16:14:31 +0100496 checkProtectedData(deviceInfo, cppbor::Array(), keysToSignMac, protectedData);
David Drysdalecceca9f2021-03-12 15:49:47 +0000497 }
Shawn Willden274bb552020-09-30 22:39:22 -0600498}
499
500/**
501 * Generate an empty certificate request in prod mode. Generation will fail because we don't have a
502 * valid GEEK.
503 *
504 * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
505 * able to decrypt.
506 */
Max Bires126869a2021-02-21 18:32:59 -0800507TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600508 bool testMode = false;
David Drysdalecceca9f2021-03-12 15:49:47 +0000509 for (size_t eekLength : {2, 3, 7}) {
510 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
511 generateEek(eekLength);
512
513 bytevec keysToSignMac;
514 DeviceInfo deviceInfo;
515 ProtectedData protectedData;
516 auto status = provisionable_->generateCertificateRequest(
517 testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
518 &protectedData, &keysToSignMac);
519 EXPECT_FALSE(status.isOk());
520 EXPECT_EQ(status.getServiceSpecificError(),
521 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
522 }
Shawn Willden274bb552020-09-30 22:39:22 -0600523}
524
525/**
526 * Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
527 */
Max Bires126869a2021-02-21 18:32:59 -0800528TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600529 bool testMode = true;
530 generateKeys(testMode, 4 /* numKeys */);
531
David Drysdalecceca9f2021-03-12 15:49:47 +0000532 for (size_t eekLength : {2, 3, 7}) {
533 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
534 generateEek(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600535
David Drysdalecceca9f2021-03-12 15:49:47 +0000536 bytevec keysToSignMac;
537 DeviceInfo deviceInfo;
538 ProtectedData protectedData;
539 auto status = provisionable_->generateCertificateRequest(
540 testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
541 &keysToSignMac);
542 ASSERT_TRUE(status.isOk()) << status.getMessage();
543
David Drysdalef6fc5a62021-03-31 16:14:31 +0100544 checkProtectedData(deviceInfo, cborKeysToSign_, keysToSignMac, protectedData);
David Drysdalecceca9f2021-03-12 15:49:47 +0000545 }
Shawn Willden274bb552020-09-30 22:39:22 -0600546}
547
548/**
549 * Generate a non-empty certificate request in prod mode. Must fail because we don't have a valid
550 * GEEK.
551 *
552 * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
553 * able to decrypt.
554 */
Max Bires126869a2021-02-21 18:32:59 -0800555TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600556 bool testMode = false;
557 generateKeys(testMode, 4 /* numKeys */);
558
David Drysdalecceca9f2021-03-12 15:49:47 +0000559 for (size_t eekLength : {2, 3, 7}) {
560 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
561 generateEek(eekLength);
562
563 bytevec keysToSignMac;
564 DeviceInfo deviceInfo;
565 ProtectedData protectedData;
566 auto status = provisionable_->generateCertificateRequest(
567 testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
568 &keysToSignMac);
569 EXPECT_FALSE(status.isOk());
570 EXPECT_EQ(status.getServiceSpecificError(),
571 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
572 }
573}
574
575/**
David Drysdalee99ed862021-03-15 16:43:06 +0000576 * Generate a non-empty certificate request in test mode, but with the MAC corrupted on the keypair.
577 */
578TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
579 bool testMode = true;
580 generateKeys(testMode, 1 /* numKeys */);
581 MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
582
583 bytevec keysToSignMac;
584 DeviceInfo deviceInfo;
585 ProtectedData protectedData;
586 auto status = provisionable_->generateCertificateRequest(
587 testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
588 &keysToSignMac);
589 ASSERT_FALSE(status.isOk()) << status.getMessage();
590 EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
591}
592
593/**
594 * Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
595 */
596TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
597 bool testMode = true;
598 generateKeys(testMode, 1 /* numKeys */);
599 MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
600
601 bytevec keysToSignMac;
602 DeviceInfo deviceInfo;
603 ProtectedData protectedData;
604 auto status = provisionable_->generateCertificateRequest(
605 testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
606 &keysToSignMac);
607 ASSERT_FALSE(status.isOk()) << status.getMessage();
608 auto rc = status.getServiceSpecificError();
609
610 // TODO(drysdale): drop the INVALID_EEK potential error code when a real GEEK is available.
611 EXPECT_TRUE(rc == BnRemotelyProvisionedComponent::STATUS_INVALID_EEK ||
612 rc == BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
613}
614
615/**
David Drysdalecceca9f2021-03-12 15:49:47 +0000616 * Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
617 * Confirm that the request is rejected.
618 *
619 * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
620 * implementation is checking signatures.
621 */
622TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
623 bool testMode = false;
624 generateKeys(testMode, 4 /* numKeys */);
625
626 for (size_t ii = 0; ii < eekLength_; ii++) {
627 auto chain = corrupt_sig_chain(eekChain_, ii);
628 ASSERT_TRUE(chain) << chain.message();
629 EekChain corruptEek = chain.moveValue();
630
631 bytevec keysToSignMac;
632 DeviceInfo deviceInfo;
633 ProtectedData protectedData;
634 auto status = provisionable_->generateCertificateRequest(
635 testMode, keysToSign_, corruptEek.chain, challenge_, &deviceInfo, &protectedData,
636 &keysToSignMac);
637 ASSERT_FALSE(status.isOk());
638 ASSERT_EQ(status.getServiceSpecificError(),
639 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
640 }
641}
642
643/**
644 * Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
645 * Confirm that the request is rejected.
646 *
647 * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
648 * implementation is checking signatures.
649 */
650TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
651 bool testMode = false;
652 generateKeys(testMode, 4 /* numKeys */);
653
654 // Build an EEK chain that omits the first self-signed cert.
655 auto truncatedChain = cppbor::Array();
656 auto [chain, _, parseErr] = cppbor::parse(eekChain_.chain);
657 ASSERT_TRUE(chain);
658 auto eekChain = chain->asArray();
659 ASSERT_NE(eekChain, nullptr);
660 for (size_t ii = 1; ii < eekChain->size(); ii++) {
661 truncatedChain.add(eekChain->get(ii)->clone());
662 }
663
Shawn Willden274bb552020-09-30 22:39:22 -0600664 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700665 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600666 ProtectedData protectedData;
David Drysdalecceca9f2021-03-12 15:49:47 +0000667 auto status = provisionable_->generateCertificateRequest(
668 testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
669 &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600670 ASSERT_FALSE(status.isOk());
671 ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
672}
673
674/**
675 * Generate a non-empty certificate request in test mode, with prod keys. Must fail with
676 * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
677 */
Max Bires126869a2021-02-21 18:32:59 -0800678TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600679 generateKeys(false /* testMode */, 2 /* numKeys */);
680
681 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700682 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600683 ProtectedData protectedData;
Max Biresfdbb9042021-03-23 12:43:38 -0700684 auto status = provisionable_->generateCertificateRequest(
David Drysdalec8400772021-03-11 12:35:11 +0000685 true /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
Max Biresfdbb9042021-03-23 12:43:38 -0700686 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600687 ASSERT_FALSE(status.isOk());
688 ASSERT_EQ(status.getServiceSpecificError(),
689 BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
690}
691
692/**
693 * Generate a non-empty certificate request in prod mode, with test keys. Must fail with
694 * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
695 */
Max Bires126869a2021-02-21 18:32:59 -0800696TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600697 generateKeys(true /* testMode */, 2 /* numKeys */);
698
699 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700700 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600701 ProtectedData protectedData;
702 auto status = provisionable_->generateCertificateRequest(
David Drysdalec8400772021-03-11 12:35:11 +0000703 false /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
704 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600705 ASSERT_FALSE(status.isOk());
706 ASSERT_EQ(status.getServiceSpecificError(),
707 BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
708}
709
710INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
711
712} // namespace aidl::android::hardware::security::keymint::test