blob: bafe1613bbaa4f5eaec9abcc9d7a6f90004f6856 [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
Seth Mooref1f62152022-09-13 12:00:30 -070017#include <memory>
Shawn Willden274bb552020-09-30 22:39:22 -060018#define LOG_TAG "VtsRemotelyProvisionableComponentTests"
19
Max Bires261a0492021-04-19 18:55:56 -070020#include <AndroidRemotelyProvisionedComponentDevice.h>
Shawn Willden274bb552020-09-30 22:39:22 -060021#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
22#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
23#include <android/binder_manager.h>
Seth Moorefc86bf42021-12-09 14:07:04 -080024#include <binder/IServiceManager.h>
Shawn Willden274bb552020-09-30 22:39:22 -060025#include <cppbor_parse.h>
Shawn Willden274bb552020-09-30 22:39:22 -060026#include <gmock/gmock.h>
Max Bires9704ff62021-04-07 11:12:01 -070027#include <keymaster/cppcose/cppcose.h>
Shawn Willden274bb552020-09-30 22:39:22 -060028#include <keymaster/keymaster_configuration.h>
David Drysdalef0d516d2021-03-22 07:51:43 +000029#include <keymint_support/authorization_set.h>
30#include <openssl/ec.h>
31#include <openssl/ec_key.h>
32#include <openssl/x509.h>
Shawn Willden274bb552020-09-30 22:39:22 -060033#include <remote_prov/remote_prov_utils.h>
Max Bires757ed422022-09-07 16:20:31 -070034#include <optional>
Seth Moorefc86bf42021-12-09 14:07:04 -080035#include <set>
Seth Moore42c11332021-07-02 15:38:17 -070036#include <vector>
Shawn Willden274bb552020-09-30 22:39:22 -060037
David Drysdalef0d516d2021-03-22 07:51:43 +000038#include "KeyMintAidlTestBase.h"
39
Shawn Willden274bb552020-09-30 22:39:22 -060040namespace aidl::android::hardware::security::keymint::test {
41
42using ::std::string;
43using ::std::vector;
44
45namespace {
46
Seth Moorefc86bf42021-12-09 14:07:04 -080047constexpr int32_t VERSION_WITH_UNIQUE_ID_SUPPORT = 2;
48
Shawn Willden274bb552020-09-30 22:39:22 -060049#define INSTANTIATE_REM_PROV_AIDL_TEST(name) \
Seth Moore6305e232021-07-27 14:20:17 -070050 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name); \
Shawn Willden274bb552020-09-30 22:39:22 -060051 INSTANTIATE_TEST_SUITE_P( \
52 PerInstance, name, \
53 testing::ValuesIn(VtsRemotelyProvisionedComponentTests::build_params()), \
54 ::android::PrintInstanceNameToString)
55
Seth Moorefc86bf42021-12-09 14:07:04 -080056using ::android::sp;
Shawn Willden274bb552020-09-30 22:39:22 -060057using bytevec = std::vector<uint8_t>;
58using testing::MatchesRegex;
59using namespace remote_prov;
60using namespace keymaster;
61
62bytevec string_to_bytevec(const char* s) {
63 const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
64 return bytevec(p, p + strlen(s));
65}
66
David Drysdalee99ed862021-03-15 16:43:06 +000067ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
68 auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
69 if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
70 return "COSE Mac0 parse failed";
71 }
72 auto protParams = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
73 auto unprotParams = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
74 auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
75 auto tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
76 if (!protParams || !unprotParams || !payload || !tag) {
77 return "Invalid COSE_Sign1: missing content";
78 }
79 auto corruptMac0 = cppbor::Array();
80 corruptMac0.add(protParams->clone());
81 corruptMac0.add(unprotParams->clone());
82 corruptMac0.add(payload->clone());
83 vector<uint8_t> tagData = tag->value();
84 tagData[0] ^= 0x08;
85 tagData[tagData.size() - 1] ^= 0x80;
86 corruptMac0.add(cppbor::Bstr(tagData));
87
88 return MacedPublicKey{corruptMac0.encode()};
89}
90
David Drysdalecceca9f2021-03-12 15:49:47 +000091ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
92 if (coseSign1->size() != kCoseSign1EntryCount) {
93 return "Invalid COSE_Sign1, wrong entry count";
94 }
95 const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
96 const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
97 const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
98 const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
99 if (!protectedParams || !unprotectedParams || !payload || !signature) {
100 return "Invalid COSE_Sign1: missing content";
101 }
102
103 auto corruptSig = cppbor::Array();
104 corruptSig.add(protectedParams->clone());
105 corruptSig.add(unprotectedParams->clone());
106 corruptSig.add(payload->clone());
107 vector<uint8_t> sigData = signature->value();
108 sigData[0] ^= 0x08;
109 corruptSig.add(cppbor::Bstr(sigData));
110
111 return std::move(corruptSig);
112}
113
Seth Moore19acbe92021-06-23 15:15:52 -0700114ErrMsgOr<bytevec> corrupt_sig_chain(const bytevec& encodedEekChain, int which) {
115 auto [chain, _, parseErr] = cppbor::parse(encodedEekChain);
David Drysdalecceca9f2021-03-12 15:49:47 +0000116 if (!chain || !chain->asArray()) {
117 return "EekChain parse failed";
118 }
119
120 cppbor::Array* eekChain = chain->asArray();
121 if (which >= eekChain->size()) {
122 return "selected sig out of range";
123 }
124 auto corruptChain = cppbor::Array();
125
126 for (int ii = 0; ii < eekChain->size(); ++ii) {
127 if (ii == which) {
128 auto sig = corrupt_sig(eekChain->get(which)->asArray());
129 if (!sig) {
130 return "Failed to build corrupted signature" + sig.moveMessage();
131 }
132 corruptChain.add(sig.moveValue());
133 } else {
134 corruptChain.add(eekChain->get(ii)->clone());
135 }
136 }
Seth Moore19acbe92021-06-23 15:15:52 -0700137 return corruptChain.encode();
David Drysdalecceca9f2021-03-12 15:49:47 +0000138}
139
David Drysdale4d3c2982021-03-31 18:21:40 +0100140string device_suffix(const string& name) {
141 size_t pos = name.find('/');
142 if (pos == string::npos) {
143 return name;
144 }
145 return name.substr(pos + 1);
146}
147
148bool matching_keymint_device(const string& rp_name, std::shared_ptr<IKeyMintDevice>* keyMint) {
149 string rp_suffix = device_suffix(rp_name);
150
151 vector<string> km_names = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
152 for (const string& km_name : km_names) {
153 // If the suffix of the KeyMint instance equals the suffix of the
154 // RemotelyProvisionedComponent instance, assume they match.
155 if (device_suffix(km_name) == rp_suffix && AServiceManager_isDeclared(km_name.c_str())) {
156 ::ndk::SpAIBinder binder(AServiceManager_waitForService(km_name.c_str()));
157 *keyMint = IKeyMintDevice::fromBinder(binder);
158 return true;
159 }
160 }
161 return false;
162}
163
Shawn Willden274bb552020-09-30 22:39:22 -0600164} // namespace
165
166class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
167 public:
168 virtual void SetUp() override {
169 if (AServiceManager_isDeclared(GetParam().c_str())) {
170 ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
171 provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
172 }
173 ASSERT_NE(provisionable_, nullptr);
subrahmanyamanfb213d62022-02-02 23:10:55 +0000174 ASSERT_TRUE(provisionable_->getHardwareInfo(&rpcHardwareInfo).isOk());
Shawn Willden274bb552020-09-30 22:39:22 -0600175 }
176
177 static vector<string> build_params() {
178 auto params = ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
179 return params;
180 }
181
182 protected:
183 std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
subrahmanyamanfb213d62022-02-02 23:10:55 +0000184 RpcHardwareInfo rpcHardwareInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600185};
186
Seth Moorefc86bf42021-12-09 14:07:04 -0800187/**
188 * Verify that every implementation reports a different unique id.
189 */
190TEST(NonParameterizedTests, eachRpcHasAUniqueId) {
191 std::set<std::string> uniqueIds;
192 for (auto hal : ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor)) {
193 ASSERT_TRUE(AServiceManager_isDeclared(hal.c_str()));
194 ::ndk::SpAIBinder binder(AServiceManager_waitForService(hal.c_str()));
195 std::shared_ptr<IRemotelyProvisionedComponent> rpc =
196 IRemotelyProvisionedComponent::fromBinder(binder);
197 ASSERT_NE(rpc, nullptr);
198
199 RpcHardwareInfo hwInfo;
200 ASSERT_TRUE(rpc->getHardwareInfo(&hwInfo).isOk());
201
202 int32_t version;
203 ASSERT_TRUE(rpc->getInterfaceVersion(&version).isOk());
204 if (version >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
205 ASSERT_TRUE(hwInfo.uniqueId);
206 auto [_, wasInserted] = uniqueIds.insert(*hwInfo.uniqueId);
207 EXPECT_TRUE(wasInserted);
208 } else {
209 ASSERT_FALSE(hwInfo.uniqueId);
210 }
211 }
212}
213
214using GetHardwareInfoTests = VtsRemotelyProvisionedComponentTests;
215
216INSTANTIATE_REM_PROV_AIDL_TEST(GetHardwareInfoTests);
217
218/**
219 * Verify that a valid curve is reported by the implementation.
220 */
221TEST_P(GetHardwareInfoTests, supportsValidCurve) {
222 RpcHardwareInfo hwInfo;
223 ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
224
225 const std::set<int> validCurves = {RpcHardwareInfo::CURVE_P256, RpcHardwareInfo::CURVE_25519};
226 ASSERT_EQ(validCurves.count(hwInfo.supportedEekCurve), 1)
227 << "Invalid curve: " << hwInfo.supportedEekCurve;
228}
229
230/**
231 * Verify that the unique id is within the length limits as described in RpcHardwareInfo.aidl.
232 */
233TEST_P(GetHardwareInfoTests, uniqueId) {
234 int32_t version;
235 ASSERT_TRUE(provisionable_->getInterfaceVersion(&version).isOk());
236
237 if (version < VERSION_WITH_UNIQUE_ID_SUPPORT) {
238 return;
239 }
240
241 RpcHardwareInfo hwInfo;
242 ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
243 ASSERT_TRUE(hwInfo.uniqueId);
244 EXPECT_GE(hwInfo.uniqueId->size(), 1);
245 EXPECT_LE(hwInfo.uniqueId->size(), 32);
246}
247
Shawn Willden274bb552020-09-30 22:39:22 -0600248using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
249
250INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
251
252/**
David Drysdalef0d516d2021-03-22 07:51:43 +0000253 * Generate and validate a production-mode key. MAC tag can't be verified, but
254 * the private key blob should be usable in KeyMint operations.
Shawn Willden274bb552020-09-30 22:39:22 -0600255 */
Max Bires126869a2021-02-21 18:32:59 -0800256TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600257 MacedPublicKey macedPubKey;
258 bytevec privateKeyBlob;
259 bool testMode = false;
260 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
261 ASSERT_TRUE(status.isOk());
David Drysdalef0d516d2021-03-22 07:51:43 +0000262 vector<uint8_t> coseKeyData;
263 check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
David Drysdale4d3c2982021-03-31 18:21:40 +0100264}
265
266/**
267 * Generate and validate a production-mode key, then use it as a KeyMint attestation key.
268 */
269TEST_P(GenerateKeyTests, generateAndUseEcdsaP256Key_prodMode) {
270 // See if there is a matching IKeyMintDevice for this IRemotelyProvisionedComponent.
271 std::shared_ptr<IKeyMintDevice> keyMint;
272 if (!matching_keymint_device(GetParam(), &keyMint)) {
273 // No matching IKeyMintDevice.
274 GTEST_SKIP() << "Skipping key use test as no matching KeyMint device found";
275 return;
276 }
277 KeyMintHardwareInfo info;
278 ASSERT_TRUE(keyMint->getHardwareInfo(&info).isOk());
279
280 MacedPublicKey macedPubKey;
281 bytevec privateKeyBlob;
282 bool testMode = false;
283 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
284 ASSERT_TRUE(status.isOk());
285 vector<uint8_t> coseKeyData;
286 check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
287
David Drysdalef0d516d2021-03-22 07:51:43 +0000288 AttestationKey attestKey;
289 attestKey.keyBlob = std::move(privateKeyBlob);
290 attestKey.issuerSubjectName = make_name_from_str("Android Keystore Key");
Shawn Willden274bb552020-09-30 22:39:22 -0600291
David Drysdalef0d516d2021-03-22 07:51:43 +0000292 // Generate an ECDSA key that is attested by the generated P256 keypair.
293 AuthorizationSet keyDesc = AuthorizationSetBuilder()
294 .Authorization(TAG_NO_AUTH_REQUIRED)
David Drysdale915ce252021-10-14 15:17:36 +0100295 .EcdsaSigningKey(EcCurve::P_256)
David Drysdalef0d516d2021-03-22 07:51:43 +0000296 .AttestationChallenge("foo")
297 .AttestationApplicationId("bar")
298 .Digest(Digest::NONE)
299 .SetDefaultValidity();
300 KeyCreationResult creationResult;
301 auto result = keyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
302 ASSERT_TRUE(result.isOk());
303 vector<uint8_t> attested_key_blob = std::move(creationResult.keyBlob);
304 vector<KeyCharacteristics> attested_key_characteristics =
305 std::move(creationResult.keyCharacteristics);
306 vector<Certificate> attested_key_cert_chain = std::move(creationResult.certificateChain);
307 EXPECT_EQ(attested_key_cert_chain.size(), 1);
308
David Drysdale7dff4fc2021-12-10 10:10:52 +0000309 int32_t aidl_version = 0;
310 ASSERT_TRUE(keyMint->getInterfaceVersion(&aidl_version).isOk());
David Drysdalef0d516d2021-03-22 07:51:43 +0000311 AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
312 AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
David Drysdale7dff4fc2021-12-10 10:10:52 +0000313 EXPECT_TRUE(verify_attestation_record(aidl_version, "foo", "bar", sw_enforced, hw_enforced,
David Drysdalef0d516d2021-03-22 07:51:43 +0000314 info.securityLevel,
315 attested_key_cert_chain[0].encodedCertificate));
316
317 // Attestation by itself is not valid (last entry is not self-signed).
318 EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
319
320 // The signature over the attested key should correspond to the P256 public key.
321 X509_Ptr key_cert(parse_cert_blob(attested_key_cert_chain[0].encodedCertificate));
322 ASSERT_TRUE(key_cert.get());
323 EVP_PKEY_Ptr signing_pubkey;
324 p256_pub_key(coseKeyData, &signing_pubkey);
325 ASSERT_TRUE(signing_pubkey.get());
326
327 ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
328 << "Verification of attested certificate failed "
329 << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
Shawn Willden274bb552020-09-30 22:39:22 -0600330}
331
332/**
333 * Generate and validate a test-mode key.
334 */
Max Bires126869a2021-02-21 18:32:59 -0800335TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600336 MacedPublicKey macedPubKey;
337 bytevec privateKeyBlob;
338 bool testMode = true;
339 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
340 ASSERT_TRUE(status.isOk());
341
David Drysdalec8400772021-03-11 12:35:11 +0000342 check_maced_pubkey(macedPubKey, testMode, nullptr);
Shawn Willden274bb552020-09-30 22:39:22 -0600343}
344
345class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
346 protected:
Max Bires89c74882022-03-27 21:06:11 -0700347 CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(64)) {}
David Drysdalecceca9f2021-03-12 15:49:47 +0000348
Seth Moore19acbe92021-06-23 15:15:52 -0700349 void generateTestEekChain(size_t eekLength) {
subrahmanyamanfb213d62022-02-02 23:10:55 +0000350 auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
David Drysdale08696a72022-03-10 10:43:25 +0000351 ASSERT_TRUE(chain) << chain.message();
Seth Moore19acbe92021-06-23 15:15:52 -0700352 if (chain) testEekChain_ = chain.moveValue();
353 testEekLength_ = eekLength;
Shawn Willden274bb552020-09-30 22:39:22 -0600354 }
355
356 void generateKeys(bool testMode, size_t numKeys) {
357 keysToSign_ = std::vector<MacedPublicKey>(numKeys);
358 cborKeysToSign_ = cppbor::Array();
359
360 for (auto& key : keysToSign_) {
361 bytevec privateKeyBlob;
362 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
363 ASSERT_TRUE(status.isOk()) << status.getMessage();
364
David Drysdalec8400772021-03-11 12:35:11 +0000365 vector<uint8_t> payload_value;
366 check_maced_pubkey(key, testMode, &payload_value);
367 cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
Shawn Willden274bb552020-09-30 22:39:22 -0600368 }
369 }
370
subrahmanyamanfb213d62022-02-02 23:10:55 +0000371 ErrMsgOr<bytevec> getSessionKey(ErrMsgOr<std::pair<bytevec, bytevec>>& senderPubkey) {
372 if (rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
373 rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
374 return x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
375 senderPubkey->first, false /* senderIsA */);
376 } else {
377 return ECDH_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
378 senderPubkey->first, false /* senderIsA */);
379 }
380 }
381
David Drysdalef6fc5a62021-03-31 16:14:31 +0100382 void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
Seth Moore42c11332021-07-02 15:38:17 -0700383 const bytevec& keysToSignMac, const ProtectedData& protectedData,
384 std::vector<BccEntryData>* bccOutput = nullptr) {
David Drysdalec8400772021-03-11 12:35:11 +0000385 auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
386 ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
387 ASSERT_TRUE(parsedProtectedData->asArray());
388 ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
389
390 auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
391 ASSERT_TRUE(senderPubkey) << senderPubkey.message();
392 EXPECT_EQ(senderPubkey->second, eekId_);
393
subrahmanyamanfb213d62022-02-02 23:10:55 +0000394 auto sessionKey = getSessionKey(senderPubkey);
David Drysdalec8400772021-03-11 12:35:11 +0000395 ASSERT_TRUE(sessionKey) << sessionKey.message();
396
397 auto protectedDataPayload =
398 decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
399 ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
400
401 auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
402 ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
403 ASSERT_TRUE(parsedPayload->asArray());
subrahmanyamanfb213d62022-02-02 23:10:55 +0000404 // Strongbox may contain additional certificate chain.
405 EXPECT_LE(parsedPayload->asArray()->size(), 3U);
David Drysdalec8400772021-03-11 12:35:11 +0000406
407 auto& signedMac = parsedPayload->asArray()->get(0);
408 auto& bcc = parsedPayload->asArray()->get(1);
409 ASSERT_TRUE(signedMac && signedMac->asArray());
410 ASSERT_TRUE(bcc && bcc->asArray());
411
412 // BCC is [ pubkey, + BccEntry]
413 auto bccContents = validateBcc(bcc->asArray());
414 ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
415 ASSERT_GT(bccContents->size(), 0U);
416
Seth Mooref1f62152022-09-13 12:00:30 -0700417 auto deviceInfoResult =
418 parseAndValidateDeviceInfo(deviceInfo.deviceInfo, provisionable_.get());
419 ASSERT_TRUE(deviceInfoResult) << deviceInfoResult.message();
420 std::unique_ptr<cppbor::Map> deviceInfoMap = deviceInfoResult.moveValue();
David Drysdalec8400772021-03-11 12:35:11 +0000421 auto& signingKey = bccContents->back().pubKey;
Seth Moore798188a2021-06-17 10:58:27 -0700422 auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
David Drysdalef6fc5a62021-03-31 16:14:31 +0100423 cppbor::Array() // SignedMacAad
David Drysdalec8400772021-03-11 12:35:11 +0000424 .add(challenge_)
David Drysdalef6fc5a62021-03-31 16:14:31 +0100425 .add(std::move(deviceInfoMap))
Max Bires8dff0b32021-05-26 13:05:09 -0700426 .add(keysToSignMac)
David Drysdalec8400772021-03-11 12:35:11 +0000427 .encode());
428 ASSERT_TRUE(macKey) << macKey.message();
429
430 auto coseMac0 = cppbor::Array()
431 .add(cppbor::Map() // protected
432 .add(ALGORITHM, HMAC_256)
433 .canonicalize()
434 .encode())
435 .add(cppbor::Map()) // unprotected
436 .add(keysToSign.encode()) // payload (keysToSign)
437 .add(keysToSignMac); // tag
438
439 auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
440 ASSERT_TRUE(macPayload) << macPayload.message();
Seth Moore42c11332021-07-02 15:38:17 -0700441
442 if (bccOutput) {
443 *bccOutput = std::move(*bccContents);
444 }
David Drysdalec8400772021-03-11 12:35:11 +0000445 }
446
Shawn Willden274bb552020-09-30 22:39:22 -0600447 bytevec eekId_;
Seth Moore19acbe92021-06-23 15:15:52 -0700448 size_t testEekLength_;
449 EekChain testEekChain_;
David Drysdalec8400772021-03-11 12:35:11 +0000450 bytevec challenge_;
Shawn Willden274bb552020-09-30 22:39:22 -0600451 std::vector<MacedPublicKey> keysToSign_;
452 cppbor::Array cborKeysToSign_;
453};
454
455/**
456 * Generate an empty certificate request in test mode, and decrypt and verify the structure and
457 * content.
458 */
Max Bires126869a2021-02-21 18:32:59 -0800459TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600460 bool testMode = true;
David Drysdalecceca9f2021-03-12 15:49:47 +0000461 for (size_t eekLength : {2, 3, 7}) {
462 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
Seth Moore19acbe92021-06-23 15:15:52 -0700463 generateTestEekChain(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600464
David Drysdalecceca9f2021-03-12 15:49:47 +0000465 bytevec keysToSignMac;
466 DeviceInfo deviceInfo;
467 ProtectedData protectedData;
468 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700469 testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
David Drysdalecceca9f2021-03-12 15:49:47 +0000470 &protectedData, &keysToSignMac);
471 ASSERT_TRUE(status.isOk()) << status.getMessage();
472
David Drysdalef6fc5a62021-03-31 16:14:31 +0100473 checkProtectedData(deviceInfo, cppbor::Array(), keysToSignMac, protectedData);
David Drysdalecceca9f2021-03-12 15:49:47 +0000474 }
Shawn Willden274bb552020-09-30 22:39:22 -0600475}
476
477/**
Seth Moore42c11332021-07-02 15:38:17 -0700478 * Ensure that test mode outputs a unique BCC root key every time we request a
479 * certificate request. Else, it's possible that the test mode API could be used
480 * to fingerprint devices. Only the GEEK should be allowed to decrypt the same
481 * device public key multiple times.
482 */
483TEST_P(CertificateRequestTest, NewKeyPerCallInTestMode) {
484 constexpr bool testMode = true;
Seth Moore42c11332021-07-02 15:38:17 -0700485
486 bytevec keysToSignMac;
487 DeviceInfo deviceInfo;
488 ProtectedData protectedData;
subrahmanyamanfb213d62022-02-02 23:10:55 +0000489 generateTestEekChain(3);
Seth Moore42c11332021-07-02 15:38:17 -0700490 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700491 testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
492 &protectedData, &keysToSignMac);
Seth Moore42c11332021-07-02 15:38:17 -0700493 ASSERT_TRUE(status.isOk()) << status.getMessage();
494
495 std::vector<BccEntryData> firstBcc;
496 checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
497 &firstBcc);
498
Seth Moore19acbe92021-06-23 15:15:52 -0700499 status = provisionable_->generateCertificateRequest(
500 testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
501 &protectedData, &keysToSignMac);
Seth Moore42c11332021-07-02 15:38:17 -0700502 ASSERT_TRUE(status.isOk()) << status.getMessage();
503
504 std::vector<BccEntryData> secondBcc;
505 checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
506 &secondBcc);
507
508 // Verify that none of the keys in the first BCC are repeated in the second one.
509 for (const auto& i : firstBcc) {
510 for (auto& j : secondBcc) {
511 ASSERT_THAT(i.pubKey, testing::Not(testing::ElementsAreArray(j.pubKey)))
512 << "Found a repeated pubkey in two generateCertificateRequest test mode calls";
513 }
514 }
515}
516
517/**
Seth Moore19acbe92021-06-23 15:15:52 -0700518 * Generate an empty certificate request in prod mode. This test must be run explicitly, and
519 * is not run by default. Not all devices are GMS devices, and therefore they do not all
520 * trust the Google EEK root.
Shawn Willden274bb552020-09-30 22:39:22 -0600521 */
Seth Moore19acbe92021-06-23 15:15:52 -0700522TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600523 bool testMode = false;
David Drysdalecceca9f2021-03-12 15:49:47 +0000524
Seth Moore19acbe92021-06-23 15:15:52 -0700525 bytevec keysToSignMac;
526 DeviceInfo deviceInfo;
527 ProtectedData protectedData;
528 auto status = provisionable_->generateCertificateRequest(
subrahmanyamanfb213d62022-02-02 23:10:55 +0000529 testMode, {} /* keysToSign */, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
530 challenge_, &deviceInfo, &protectedData, &keysToSignMac);
Seth Moore19acbe92021-06-23 15:15:52 -0700531 EXPECT_TRUE(status.isOk());
Shawn Willden274bb552020-09-30 22:39:22 -0600532}
533
534/**
535 * Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
536 */
Max Bires126869a2021-02-21 18:32:59 -0800537TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600538 bool testMode = true;
539 generateKeys(testMode, 4 /* numKeys */);
540
David Drysdalecceca9f2021-03-12 15:49:47 +0000541 for (size_t eekLength : {2, 3, 7}) {
542 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
Seth Moore19acbe92021-06-23 15:15:52 -0700543 generateTestEekChain(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600544
David Drysdalecceca9f2021-03-12 15:49:47 +0000545 bytevec keysToSignMac;
546 DeviceInfo deviceInfo;
547 ProtectedData protectedData;
548 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700549 testMode, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, &protectedData,
David Drysdalecceca9f2021-03-12 15:49:47 +0000550 &keysToSignMac);
551 ASSERT_TRUE(status.isOk()) << status.getMessage();
552
David Drysdalef6fc5a62021-03-31 16:14:31 +0100553 checkProtectedData(deviceInfo, cborKeysToSign_, keysToSignMac, protectedData);
David Drysdalecceca9f2021-03-12 15:49:47 +0000554 }
Shawn Willden274bb552020-09-30 22:39:22 -0600555}
556
557/**
Seth Moore19acbe92021-06-23 15:15:52 -0700558 * Generate a non-empty certificate request in prod mode. This test must be run explicitly, and
559 * is not run by default. Not all devices are GMS devices, and therefore they do not all
560 * trust the Google EEK root.
Shawn Willden274bb552020-09-30 22:39:22 -0600561 */
Seth Moore19acbe92021-06-23 15:15:52 -0700562TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600563 bool testMode = false;
564 generateKeys(testMode, 4 /* numKeys */);
565
Seth Moore19acbe92021-06-23 15:15:52 -0700566 bytevec keysToSignMac;
567 DeviceInfo deviceInfo;
568 ProtectedData protectedData;
569 auto status = provisionable_->generateCertificateRequest(
subrahmanyamanfb213d62022-02-02 23:10:55 +0000570 testMode, keysToSign_, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_,
571 &deviceInfo, &protectedData, &keysToSignMac);
Seth Moore19acbe92021-06-23 15:15:52 -0700572 EXPECT_TRUE(status.isOk());
David Drysdalecceca9f2021-03-12 15:49:47 +0000573}
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 */);
David Drysdale08696a72022-03-10 10:43:25 +0000581 auto result = corrupt_maced_key(keysToSign_[0]);
582 ASSERT_TRUE(result) << result.moveMessage();
583 MacedPublicKey keyWithCorruptMac = result.moveValue();
David Drysdalee99ed862021-03-15 16:43:06 +0000584
585 bytevec keysToSignMac;
586 DeviceInfo deviceInfo;
587 ProtectedData protectedData;
subrahmanyamanfb213d62022-02-02 23:10:55 +0000588 generateTestEekChain(3);
David Drysdalee99ed862021-03-15 16:43:06 +0000589 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700590 testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
591 &protectedData, &keysToSignMac);
David Drysdalee99ed862021-03-15 16:43:06 +0000592 ASSERT_FALSE(status.isOk()) << status.getMessage();
593 EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
594}
595
596/**
597 * Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
598 */
599TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
Seth Moore19acbe92021-06-23 15:15:52 -0700600 bool testMode = false;
David Drysdalee99ed862021-03-15 16:43:06 +0000601 generateKeys(testMode, 1 /* numKeys */);
David Drysdale08696a72022-03-10 10:43:25 +0000602 auto result = corrupt_maced_key(keysToSign_[0]);
603 ASSERT_TRUE(result) << result.moveMessage();
604 MacedPublicKey keyWithCorruptMac = result.moveValue();
David Drysdalee99ed862021-03-15 16:43:06 +0000605
606 bytevec keysToSignMac;
607 DeviceInfo deviceInfo;
608 ProtectedData protectedData;
609 auto status = provisionable_->generateCertificateRequest(
subrahmanyamanfb213d62022-02-02 23:10:55 +0000610 testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
611 challenge_, &deviceInfo, &protectedData, &keysToSignMac);
David Drysdalee99ed862021-03-15 16:43:06 +0000612 ASSERT_FALSE(status.isOk()) << status.getMessage();
Seth Moore19acbe92021-06-23 15:15:52 -0700613 EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
David Drysdalee99ed862021-03-15 16:43:06 +0000614}
615
616/**
David Drysdalecceca9f2021-03-12 15:49:47 +0000617 * Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
618 * Confirm that the request is rejected.
David Drysdalecceca9f2021-03-12 15:49:47 +0000619 */
620TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
621 bool testMode = false;
622 generateKeys(testMode, 4 /* numKeys */);
623
subrahmanyamanfb213d62022-02-02 23:10:55 +0000624 auto prodEekChain = getProdEekChain(rpcHardwareInfo.supportedEekCurve);
Seth Moore19acbe92021-06-23 15:15:52 -0700625 auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
626 ASSERT_NE(parsedChain, nullptr) << parseErr;
627 ASSERT_NE(parsedChain->asArray(), nullptr);
628
629 for (int ii = 0; ii < parsedChain->asArray()->size(); ++ii) {
630 auto chain = corrupt_sig_chain(prodEekChain, ii);
David Drysdalecceca9f2021-03-12 15:49:47 +0000631 ASSERT_TRUE(chain) << chain.message();
David Drysdalecceca9f2021-03-12 15:49:47 +0000632
633 bytevec keysToSignMac;
634 DeviceInfo deviceInfo;
635 ProtectedData protectedData;
Seth Moore19acbe92021-06-23 15:15:52 -0700636 auto status = provisionable_->generateCertificateRequest(testMode, keysToSign_, *chain,
637 challenge_, &deviceInfo,
638 &protectedData, &keysToSignMac);
David Drysdalecceca9f2021-03-12 15:49:47 +0000639 ASSERT_FALSE(status.isOk());
640 ASSERT_EQ(status.getServiceSpecificError(),
641 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
642 }
643}
644
645/**
646 * Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
647 * Confirm that the request is rejected.
David Drysdalecceca9f2021-03-12 15:49:47 +0000648 */
649TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
650 bool testMode = false;
651 generateKeys(testMode, 4 /* numKeys */);
652
653 // Build an EEK chain that omits the first self-signed cert.
654 auto truncatedChain = cppbor::Array();
subrahmanyamanfb213d62022-02-02 23:10:55 +0000655 auto [chain, _, parseErr] = cppbor::parse(getProdEekChain(rpcHardwareInfo.supportedEekCurve));
David Drysdalecceca9f2021-03-12 15:49:47 +0000656 ASSERT_TRUE(chain);
657 auto eekChain = chain->asArray();
658 ASSERT_NE(eekChain, nullptr);
659 for (size_t ii = 1; ii < eekChain->size(); ii++) {
660 truncatedChain.add(eekChain->get(ii)->clone());
661 }
662
Shawn Willden274bb552020-09-30 22:39:22 -0600663 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700664 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600665 ProtectedData protectedData;
David Drysdalecceca9f2021-03-12 15:49:47 +0000666 auto status = provisionable_->generateCertificateRequest(
667 testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
668 &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600669 ASSERT_FALSE(status.isOk());
670 ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
671}
672
673/**
674 * Generate a non-empty certificate request in test mode, with prod keys. Must fail with
675 * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
676 */
Max Bires126869a2021-02-21 18:32:59 -0800677TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600678 generateKeys(false /* testMode */, 2 /* numKeys */);
679
680 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700681 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600682 ProtectedData protectedData;
subrahmanyamanfb213d62022-02-02 23:10:55 +0000683 generateTestEekChain(3);
Max Biresfdbb9042021-03-23 12:43:38 -0700684 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700685 true /* testMode */, keysToSign_, testEekChain_.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;
subrahmanyamanfb213d62022-02-02 23:10:55 +0000702 generateTestEekChain(3);
Shawn Willden274bb552020-09-30 22:39:22 -0600703 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700704 false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
David Drysdalec8400772021-03-11 12:35:11 +0000705 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600706 ASSERT_FALSE(status.isOk());
707 ASSERT_EQ(status.getServiceSpecificError(),
708 BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
709}
710
711INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
712
713} // namespace aidl::android::hardware::security::keymint::test