blob: f154d03c7c736991cf8caff1ba60309d6bb4d257 [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
Max Bires261a0492021-04-19 18:55:56 -070019#include <AndroidRemotelyProvisionedComponentDevice.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>
Seth Moorefc86bf42021-12-09 14:07:04 -080023#include <binder/IServiceManager.h>
Shawn Willden274bb552020-09-30 22:39:22 -060024#include <cppbor_parse.h>
Shawn Willden274bb552020-09-30 22:39:22 -060025#include <gmock/gmock.h>
Max Bires9704ff62021-04-07 11:12:01 -070026#include <keymaster/cppcose/cppcose.h>
Shawn Willden274bb552020-09-30 22:39:22 -060027#include <keymaster/keymaster_configuration.h>
David Drysdalef0d516d2021-03-22 07:51:43 +000028#include <keymint_support/authorization_set.h>
29#include <openssl/ec.h>
30#include <openssl/ec_key.h>
31#include <openssl/x509.h>
Shawn Willden274bb552020-09-30 22:39:22 -060032#include <remote_prov/remote_prov_utils.h>
Seth Moorefc86bf42021-12-09 14:07:04 -080033#include <set>
Seth Moore42c11332021-07-02 15:38:17 -070034#include <vector>
Shawn Willden274bb552020-09-30 22:39:22 -060035
David Drysdalef0d516d2021-03-22 07:51:43 +000036#include "KeyMintAidlTestBase.h"
37
Shawn Willden274bb552020-09-30 22:39:22 -060038namespace aidl::android::hardware::security::keymint::test {
39
40using ::std::string;
41using ::std::vector;
42
43namespace {
44
Seth Moorefc86bf42021-12-09 14:07:04 -080045constexpr int32_t VERSION_WITH_UNIQUE_ID_SUPPORT = 2;
46
Shawn Willden274bb552020-09-30 22:39:22 -060047#define INSTANTIATE_REM_PROV_AIDL_TEST(name) \
Seth Moore6305e232021-07-27 14:20:17 -070048 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name); \
Shawn Willden274bb552020-09-30 22:39:22 -060049 INSTANTIATE_TEST_SUITE_P( \
50 PerInstance, name, \
51 testing::ValuesIn(VtsRemotelyProvisionedComponentTests::build_params()), \
52 ::android::PrintInstanceNameToString)
53
Seth Moorefc86bf42021-12-09 14:07:04 -080054using ::android::sp;
Shawn Willden274bb552020-09-30 22:39:22 -060055using bytevec = std::vector<uint8_t>;
56using testing::MatchesRegex;
57using namespace remote_prov;
58using namespace keymaster;
59
60bytevec string_to_bytevec(const char* s) {
61 const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
62 return bytevec(p, p + strlen(s));
63}
64
David Drysdalee99ed862021-03-15 16:43:06 +000065ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
66 auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
67 if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
68 return "COSE Mac0 parse failed";
69 }
70 auto protParams = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
71 auto unprotParams = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
72 auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
73 auto tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
74 if (!protParams || !unprotParams || !payload || !tag) {
75 return "Invalid COSE_Sign1: missing content";
76 }
77 auto corruptMac0 = cppbor::Array();
78 corruptMac0.add(protParams->clone());
79 corruptMac0.add(unprotParams->clone());
80 corruptMac0.add(payload->clone());
81 vector<uint8_t> tagData = tag->value();
82 tagData[0] ^= 0x08;
83 tagData[tagData.size() - 1] ^= 0x80;
84 corruptMac0.add(cppbor::Bstr(tagData));
85
86 return MacedPublicKey{corruptMac0.encode()};
87}
88
David Drysdalecceca9f2021-03-12 15:49:47 +000089ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
90 if (coseSign1->size() != kCoseSign1EntryCount) {
91 return "Invalid COSE_Sign1, wrong entry count";
92 }
93 const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
94 const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
95 const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
96 const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
97 if (!protectedParams || !unprotectedParams || !payload || !signature) {
98 return "Invalid COSE_Sign1: missing content";
99 }
100
101 auto corruptSig = cppbor::Array();
102 corruptSig.add(protectedParams->clone());
103 corruptSig.add(unprotectedParams->clone());
104 corruptSig.add(payload->clone());
105 vector<uint8_t> sigData = signature->value();
106 sigData[0] ^= 0x08;
107 corruptSig.add(cppbor::Bstr(sigData));
108
109 return std::move(corruptSig);
110}
111
Seth Moore19acbe92021-06-23 15:15:52 -0700112ErrMsgOr<bytevec> corrupt_sig_chain(const bytevec& encodedEekChain, int which) {
113 auto [chain, _, parseErr] = cppbor::parse(encodedEekChain);
David Drysdalecceca9f2021-03-12 15:49:47 +0000114 if (!chain || !chain->asArray()) {
115 return "EekChain parse failed";
116 }
117
118 cppbor::Array* eekChain = chain->asArray();
119 if (which >= eekChain->size()) {
120 return "selected sig out of range";
121 }
122 auto corruptChain = cppbor::Array();
123
124 for (int ii = 0; ii < eekChain->size(); ++ii) {
125 if (ii == which) {
126 auto sig = corrupt_sig(eekChain->get(which)->asArray());
127 if (!sig) {
128 return "Failed to build corrupted signature" + sig.moveMessage();
129 }
130 corruptChain.add(sig.moveValue());
131 } else {
132 corruptChain.add(eekChain->get(ii)->clone());
133 }
134 }
Seth Moore19acbe92021-06-23 15:15:52 -0700135 return corruptChain.encode();
David Drysdalecceca9f2021-03-12 15:49:47 +0000136}
137
David Drysdale4d3c2982021-03-31 18:21:40 +0100138string device_suffix(const string& name) {
139 size_t pos = name.find('/');
140 if (pos == string::npos) {
141 return name;
142 }
143 return name.substr(pos + 1);
144}
145
146bool matching_keymint_device(const string& rp_name, std::shared_ptr<IKeyMintDevice>* keyMint) {
147 string rp_suffix = device_suffix(rp_name);
148
149 vector<string> km_names = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
150 for (const string& km_name : km_names) {
151 // If the suffix of the KeyMint instance equals the suffix of the
152 // RemotelyProvisionedComponent instance, assume they match.
153 if (device_suffix(km_name) == rp_suffix && AServiceManager_isDeclared(km_name.c_str())) {
154 ::ndk::SpAIBinder binder(AServiceManager_waitForService(km_name.c_str()));
155 *keyMint = IKeyMintDevice::fromBinder(binder);
156 return true;
157 }
158 }
159 return false;
160}
161
Shawn Willden274bb552020-09-30 22:39:22 -0600162} // namespace
163
164class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
165 public:
166 virtual void SetUp() override {
167 if (AServiceManager_isDeclared(GetParam().c_str())) {
168 ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
169 provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
170 }
171 ASSERT_NE(provisionable_, nullptr);
subrahmanyamanfb213d62022-02-02 23:10:55 +0000172 ASSERT_TRUE(provisionable_->getHardwareInfo(&rpcHardwareInfo).isOk());
Shawn Willden274bb552020-09-30 22:39:22 -0600173 }
174
175 static vector<string> build_params() {
176 auto params = ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
177 return params;
178 }
179
180 protected:
181 std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
subrahmanyamanfb213d62022-02-02 23:10:55 +0000182 RpcHardwareInfo rpcHardwareInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600183};
184
Seth Moorefc86bf42021-12-09 14:07:04 -0800185/**
186 * Verify that every implementation reports a different unique id.
187 */
188TEST(NonParameterizedTests, eachRpcHasAUniqueId) {
189 std::set<std::string> uniqueIds;
190 for (auto hal : ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor)) {
191 ASSERT_TRUE(AServiceManager_isDeclared(hal.c_str()));
192 ::ndk::SpAIBinder binder(AServiceManager_waitForService(hal.c_str()));
193 std::shared_ptr<IRemotelyProvisionedComponent> rpc =
194 IRemotelyProvisionedComponent::fromBinder(binder);
195 ASSERT_NE(rpc, nullptr);
196
197 RpcHardwareInfo hwInfo;
198 ASSERT_TRUE(rpc->getHardwareInfo(&hwInfo).isOk());
199
200 int32_t version;
201 ASSERT_TRUE(rpc->getInterfaceVersion(&version).isOk());
202 if (version >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
203 ASSERT_TRUE(hwInfo.uniqueId);
204 auto [_, wasInserted] = uniqueIds.insert(*hwInfo.uniqueId);
205 EXPECT_TRUE(wasInserted);
206 } else {
207 ASSERT_FALSE(hwInfo.uniqueId);
208 }
209 }
210}
211
212using GetHardwareInfoTests = VtsRemotelyProvisionedComponentTests;
213
214INSTANTIATE_REM_PROV_AIDL_TEST(GetHardwareInfoTests);
215
216/**
217 * Verify that a valid curve is reported by the implementation.
218 */
219TEST_P(GetHardwareInfoTests, supportsValidCurve) {
220 RpcHardwareInfo hwInfo;
221 ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
222
223 const std::set<int> validCurves = {RpcHardwareInfo::CURVE_P256, RpcHardwareInfo::CURVE_25519};
224 ASSERT_EQ(validCurves.count(hwInfo.supportedEekCurve), 1)
225 << "Invalid curve: " << hwInfo.supportedEekCurve;
226}
227
228/**
229 * Verify that the unique id is within the length limits as described in RpcHardwareInfo.aidl.
230 */
231TEST_P(GetHardwareInfoTests, uniqueId) {
232 int32_t version;
233 ASSERT_TRUE(provisionable_->getInterfaceVersion(&version).isOk());
234
235 if (version < VERSION_WITH_UNIQUE_ID_SUPPORT) {
236 return;
237 }
238
239 RpcHardwareInfo hwInfo;
240 ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
241 ASSERT_TRUE(hwInfo.uniqueId);
242 EXPECT_GE(hwInfo.uniqueId->size(), 1);
243 EXPECT_LE(hwInfo.uniqueId->size(), 32);
244}
245
Shawn Willden274bb552020-09-30 22:39:22 -0600246using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
247
248INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
249
250/**
David Drysdalef0d516d2021-03-22 07:51:43 +0000251 * Generate and validate a production-mode key. MAC tag can't be verified, but
252 * the private key blob should be usable in KeyMint operations.
Shawn Willden274bb552020-09-30 22:39:22 -0600253 */
Max Bires126869a2021-02-21 18:32:59 -0800254TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600255 MacedPublicKey macedPubKey;
256 bytevec privateKeyBlob;
257 bool testMode = false;
258 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
259 ASSERT_TRUE(status.isOk());
David Drysdalef0d516d2021-03-22 07:51:43 +0000260 vector<uint8_t> coseKeyData;
261 check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
David Drysdale4d3c2982021-03-31 18:21:40 +0100262}
263
264/**
265 * Generate and validate a production-mode key, then use it as a KeyMint attestation key.
266 */
267TEST_P(GenerateKeyTests, generateAndUseEcdsaP256Key_prodMode) {
268 // See if there is a matching IKeyMintDevice for this IRemotelyProvisionedComponent.
269 std::shared_ptr<IKeyMintDevice> keyMint;
270 if (!matching_keymint_device(GetParam(), &keyMint)) {
271 // No matching IKeyMintDevice.
272 GTEST_SKIP() << "Skipping key use test as no matching KeyMint device found";
273 return;
274 }
275 KeyMintHardwareInfo info;
276 ASSERT_TRUE(keyMint->getHardwareInfo(&info).isOk());
277
278 MacedPublicKey macedPubKey;
279 bytevec privateKeyBlob;
280 bool testMode = false;
281 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
282 ASSERT_TRUE(status.isOk());
283 vector<uint8_t> coseKeyData;
284 check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
285
David Drysdalef0d516d2021-03-22 07:51:43 +0000286 AttestationKey attestKey;
287 attestKey.keyBlob = std::move(privateKeyBlob);
288 attestKey.issuerSubjectName = make_name_from_str("Android Keystore Key");
Shawn Willden274bb552020-09-30 22:39:22 -0600289
David Drysdalef0d516d2021-03-22 07:51:43 +0000290 // Generate an ECDSA key that is attested by the generated P256 keypair.
291 AuthorizationSet keyDesc = AuthorizationSetBuilder()
292 .Authorization(TAG_NO_AUTH_REQUIRED)
David Drysdale915ce252021-10-14 15:17:36 +0100293 .EcdsaSigningKey(EcCurve::P_256)
David Drysdalef0d516d2021-03-22 07:51:43 +0000294 .AttestationChallenge("foo")
295 .AttestationApplicationId("bar")
296 .Digest(Digest::NONE)
297 .SetDefaultValidity();
298 KeyCreationResult creationResult;
299 auto result = keyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
300 ASSERT_TRUE(result.isOk());
301 vector<uint8_t> attested_key_blob = std::move(creationResult.keyBlob);
302 vector<KeyCharacteristics> attested_key_characteristics =
303 std::move(creationResult.keyCharacteristics);
304 vector<Certificate> attested_key_cert_chain = std::move(creationResult.certificateChain);
305 EXPECT_EQ(attested_key_cert_chain.size(), 1);
306
David Drysdale7dff4fc2021-12-10 10:10:52 +0000307 int32_t aidl_version = 0;
308 ASSERT_TRUE(keyMint->getInterfaceVersion(&aidl_version).isOk());
David Drysdalef0d516d2021-03-22 07:51:43 +0000309 AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
310 AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
David Drysdale7dff4fc2021-12-10 10:10:52 +0000311 EXPECT_TRUE(verify_attestation_record(aidl_version, "foo", "bar", sw_enforced, hw_enforced,
David Drysdalef0d516d2021-03-22 07:51:43 +0000312 info.securityLevel,
313 attested_key_cert_chain[0].encodedCertificate));
314
315 // Attestation by itself is not valid (last entry is not self-signed).
316 EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
317
318 // The signature over the attested key should correspond to the P256 public key.
319 X509_Ptr key_cert(parse_cert_blob(attested_key_cert_chain[0].encodedCertificate));
320 ASSERT_TRUE(key_cert.get());
321 EVP_PKEY_Ptr signing_pubkey;
322 p256_pub_key(coseKeyData, &signing_pubkey);
323 ASSERT_TRUE(signing_pubkey.get());
324
325 ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
326 << "Verification of attested certificate failed "
327 << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
Shawn Willden274bb552020-09-30 22:39:22 -0600328}
329
330/**
331 * Generate and validate a test-mode key.
332 */
Max Bires126869a2021-02-21 18:32:59 -0800333TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600334 MacedPublicKey macedPubKey;
335 bytevec privateKeyBlob;
336 bool testMode = true;
337 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
338 ASSERT_TRUE(status.isOk());
339
David Drysdalec8400772021-03-11 12:35:11 +0000340 check_maced_pubkey(macedPubKey, testMode, nullptr);
Shawn Willden274bb552020-09-30 22:39:22 -0600341}
342
343class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
344 protected:
David Drysdalec8400772021-03-11 12:35:11 +0000345 CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
David Drysdalecceca9f2021-03-12 15:49:47 +0000346 }
347
Seth Moore19acbe92021-06-23 15:15:52 -0700348 void generateTestEekChain(size_t eekLength) {
subrahmanyamanfb213d62022-02-02 23:10:55 +0000349 auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
Shawn Willden274bb552020-09-30 22:39:22 -0600350 EXPECT_TRUE(chain) << chain.message();
Seth Moore19acbe92021-06-23 15:15:52 -0700351 if (chain) testEekChain_ = chain.moveValue();
352 testEekLength_ = eekLength;
Shawn Willden274bb552020-09-30 22:39:22 -0600353 }
354
355 void generateKeys(bool testMode, size_t numKeys) {
356 keysToSign_ = std::vector<MacedPublicKey>(numKeys);
357 cborKeysToSign_ = cppbor::Array();
358
359 for (auto& key : keysToSign_) {
360 bytevec privateKeyBlob;
361 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
362 ASSERT_TRUE(status.isOk()) << status.getMessage();
363
David Drysdalec8400772021-03-11 12:35:11 +0000364 vector<uint8_t> payload_value;
365 check_maced_pubkey(key, testMode, &payload_value);
366 cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
Shawn Willden274bb552020-09-30 22:39:22 -0600367 }
368 }
369
subrahmanyamanfb213d62022-02-02 23:10:55 +0000370 ErrMsgOr<bytevec> getSessionKey(ErrMsgOr<std::pair<bytevec, bytevec>>& senderPubkey) {
371 if (rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
372 rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
373 return x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
374 senderPubkey->first, false /* senderIsA */);
375 } else {
376 return ECDH_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
377 senderPubkey->first, false /* senderIsA */);
378 }
379 }
380
David Drysdalef6fc5a62021-03-31 16:14:31 +0100381 void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
Seth Moore42c11332021-07-02 15:38:17 -0700382 const bytevec& keysToSignMac, const ProtectedData& protectedData,
383 std::vector<BccEntryData>* bccOutput = nullptr) {
David Drysdalec8400772021-03-11 12:35:11 +0000384 auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
385 ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
386 ASSERT_TRUE(parsedProtectedData->asArray());
387 ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
388
389 auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
390 ASSERT_TRUE(senderPubkey) << senderPubkey.message();
391 EXPECT_EQ(senderPubkey->second, eekId_);
392
subrahmanyamanfb213d62022-02-02 23:10:55 +0000393 auto sessionKey = getSessionKey(senderPubkey);
David Drysdalec8400772021-03-11 12:35:11 +0000394 ASSERT_TRUE(sessionKey) << sessionKey.message();
395
396 auto protectedDataPayload =
397 decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
398 ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
399
400 auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
401 ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
402 ASSERT_TRUE(parsedPayload->asArray());
subrahmanyamanfb213d62022-02-02 23:10:55 +0000403 // Strongbox may contain additional certificate chain.
404 EXPECT_LE(parsedPayload->asArray()->size(), 3U);
David Drysdalec8400772021-03-11 12:35:11 +0000405
406 auto& signedMac = parsedPayload->asArray()->get(0);
407 auto& bcc = parsedPayload->asArray()->get(1);
408 ASSERT_TRUE(signedMac && signedMac->asArray());
409 ASSERT_TRUE(bcc && bcc->asArray());
410
411 // BCC is [ pubkey, + BccEntry]
412 auto bccContents = validateBcc(bcc->asArray());
413 ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
414 ASSERT_GT(bccContents->size(), 0U);
415
David Drysdalef6fc5a62021-03-31 16:14:31 +0100416 auto [deviceInfoMap, __2, deviceInfoErrMsg] = cppbor::parse(deviceInfo.deviceInfo);
417 ASSERT_TRUE(deviceInfoMap) << "Failed to parse deviceInfo: " << deviceInfoErrMsg;
418 ASSERT_TRUE(deviceInfoMap->asMap());
419
David Drysdalec8400772021-03-11 12:35:11 +0000420 auto& signingKey = bccContents->back().pubKey;
Seth Moore798188a2021-06-17 10:58:27 -0700421 auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
David Drysdalef6fc5a62021-03-31 16:14:31 +0100422 cppbor::Array() // SignedMacAad
David Drysdalec8400772021-03-11 12:35:11 +0000423 .add(challenge_)
David Drysdalef6fc5a62021-03-31 16:14:31 +0100424 .add(std::move(deviceInfoMap))
Max Bires8dff0b32021-05-26 13:05:09 -0700425 .add(keysToSignMac)
David Drysdalec8400772021-03-11 12:35:11 +0000426 .encode());
427 ASSERT_TRUE(macKey) << macKey.message();
428
429 auto coseMac0 = cppbor::Array()
430 .add(cppbor::Map() // protected
431 .add(ALGORITHM, HMAC_256)
432 .canonicalize()
433 .encode())
434 .add(cppbor::Map()) // unprotected
435 .add(keysToSign.encode()) // payload (keysToSign)
436 .add(keysToSignMac); // tag
437
438 auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
439 ASSERT_TRUE(macPayload) << macPayload.message();
Seth Moore42c11332021-07-02 15:38:17 -0700440
441 if (bccOutput) {
442 *bccOutput = std::move(*bccContents);
443 }
David Drysdalec8400772021-03-11 12:35:11 +0000444 }
445
Shawn Willden274bb552020-09-30 22:39:22 -0600446 bytevec eekId_;
Seth Moore19acbe92021-06-23 15:15:52 -0700447 size_t testEekLength_;
448 EekChain testEekChain_;
David Drysdalec8400772021-03-11 12:35:11 +0000449 bytevec challenge_;
Shawn Willden274bb552020-09-30 22:39:22 -0600450 std::vector<MacedPublicKey> keysToSign_;
451 cppbor::Array cborKeysToSign_;
452};
453
454/**
455 * Generate an empty certificate request in test mode, and decrypt and verify the structure and
456 * content.
457 */
Max Bires126869a2021-02-21 18:32:59 -0800458TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600459 bool testMode = true;
David Drysdalecceca9f2021-03-12 15:49:47 +0000460 for (size_t eekLength : {2, 3, 7}) {
461 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
Seth Moore19acbe92021-06-23 15:15:52 -0700462 generateTestEekChain(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600463
David Drysdalecceca9f2021-03-12 15:49:47 +0000464 bytevec keysToSignMac;
465 DeviceInfo deviceInfo;
466 ProtectedData protectedData;
467 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700468 testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
David Drysdalecceca9f2021-03-12 15:49:47 +0000469 &protectedData, &keysToSignMac);
470 ASSERT_TRUE(status.isOk()) << status.getMessage();
471
David Drysdalef6fc5a62021-03-31 16:14:31 +0100472 checkProtectedData(deviceInfo, cppbor::Array(), keysToSignMac, protectedData);
David Drysdalecceca9f2021-03-12 15:49:47 +0000473 }
Shawn Willden274bb552020-09-30 22:39:22 -0600474}
475
476/**
Seth Moore42c11332021-07-02 15:38:17 -0700477 * Ensure that test mode outputs a unique BCC root key every time we request a
478 * certificate request. Else, it's possible that the test mode API could be used
479 * to fingerprint devices. Only the GEEK should be allowed to decrypt the same
480 * device public key multiple times.
481 */
482TEST_P(CertificateRequestTest, NewKeyPerCallInTestMode) {
483 constexpr bool testMode = true;
Seth Moore42c11332021-07-02 15:38:17 -0700484
485 bytevec keysToSignMac;
486 DeviceInfo deviceInfo;
487 ProtectedData protectedData;
subrahmanyamanfb213d62022-02-02 23:10:55 +0000488 generateTestEekChain(3);
Seth Moore42c11332021-07-02 15:38:17 -0700489 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700490 testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
491 &protectedData, &keysToSignMac);
Seth Moore42c11332021-07-02 15:38:17 -0700492 ASSERT_TRUE(status.isOk()) << status.getMessage();
493
494 std::vector<BccEntryData> firstBcc;
495 checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
496 &firstBcc);
497
Seth Moore19acbe92021-06-23 15:15:52 -0700498 status = provisionable_->generateCertificateRequest(
499 testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
500 &protectedData, &keysToSignMac);
Seth Moore42c11332021-07-02 15:38:17 -0700501 ASSERT_TRUE(status.isOk()) << status.getMessage();
502
503 std::vector<BccEntryData> secondBcc;
504 checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
505 &secondBcc);
506
507 // Verify that none of the keys in the first BCC are repeated in the second one.
508 for (const auto& i : firstBcc) {
509 for (auto& j : secondBcc) {
510 ASSERT_THAT(i.pubKey, testing::Not(testing::ElementsAreArray(j.pubKey)))
511 << "Found a repeated pubkey in two generateCertificateRequest test mode calls";
512 }
513 }
514}
515
516/**
Seth Moore19acbe92021-06-23 15:15:52 -0700517 * Generate an empty certificate request in prod mode. This test must be run explicitly, and
518 * is not run by default. Not all devices are GMS devices, and therefore they do not all
519 * trust the Google EEK root.
Shawn Willden274bb552020-09-30 22:39:22 -0600520 */
Seth Moore19acbe92021-06-23 15:15:52 -0700521TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600522 bool testMode = false;
David Drysdalecceca9f2021-03-12 15:49:47 +0000523
Seth Moore19acbe92021-06-23 15:15:52 -0700524 bytevec keysToSignMac;
525 DeviceInfo deviceInfo;
526 ProtectedData protectedData;
527 auto status = provisionable_->generateCertificateRequest(
subrahmanyamanfb213d62022-02-02 23:10:55 +0000528 testMode, {} /* keysToSign */, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
529 challenge_, &deviceInfo, &protectedData, &keysToSignMac);
Seth Moore19acbe92021-06-23 15:15:52 -0700530 EXPECT_TRUE(status.isOk());
Shawn Willden274bb552020-09-30 22:39:22 -0600531}
532
533/**
534 * Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
535 */
Max Bires126869a2021-02-21 18:32:59 -0800536TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600537 bool testMode = true;
538 generateKeys(testMode, 4 /* numKeys */);
539
David Drysdalecceca9f2021-03-12 15:49:47 +0000540 for (size_t eekLength : {2, 3, 7}) {
541 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
Seth Moore19acbe92021-06-23 15:15:52 -0700542 generateTestEekChain(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600543
David Drysdalecceca9f2021-03-12 15:49:47 +0000544 bytevec keysToSignMac;
545 DeviceInfo deviceInfo;
546 ProtectedData protectedData;
547 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700548 testMode, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, &protectedData,
David Drysdalecceca9f2021-03-12 15:49:47 +0000549 &keysToSignMac);
550 ASSERT_TRUE(status.isOk()) << status.getMessage();
551
David Drysdalef6fc5a62021-03-31 16:14:31 +0100552 checkProtectedData(deviceInfo, cborKeysToSign_, keysToSignMac, protectedData);
David Drysdalecceca9f2021-03-12 15:49:47 +0000553 }
Shawn Willden274bb552020-09-30 22:39:22 -0600554}
555
556/**
Seth Moore19acbe92021-06-23 15:15:52 -0700557 * Generate a non-empty certificate request in prod mode. This test must be run explicitly, and
558 * is not run by default. Not all devices are GMS devices, and therefore they do not all
559 * trust the Google EEK root.
Shawn Willden274bb552020-09-30 22:39:22 -0600560 */
Seth Moore19acbe92021-06-23 15:15:52 -0700561TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600562 bool testMode = false;
563 generateKeys(testMode, 4 /* numKeys */);
564
Seth Moore19acbe92021-06-23 15:15:52 -0700565 bytevec keysToSignMac;
566 DeviceInfo deviceInfo;
567 ProtectedData protectedData;
568 auto status = provisionable_->generateCertificateRequest(
subrahmanyamanfb213d62022-02-02 23:10:55 +0000569 testMode, keysToSign_, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_,
570 &deviceInfo, &protectedData, &keysToSignMac);
Seth Moore19acbe92021-06-23 15:15:52 -0700571 EXPECT_TRUE(status.isOk());
David Drysdalecceca9f2021-03-12 15:49:47 +0000572}
573
574/**
David Drysdalee99ed862021-03-15 16:43:06 +0000575 * Generate a non-empty certificate request in test mode, but with the MAC corrupted on the keypair.
576 */
577TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
578 bool testMode = true;
579 generateKeys(testMode, 1 /* numKeys */);
580 MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
581
582 bytevec keysToSignMac;
583 DeviceInfo deviceInfo;
584 ProtectedData protectedData;
subrahmanyamanfb213d62022-02-02 23:10:55 +0000585 generateTestEekChain(3);
David Drysdalee99ed862021-03-15 16:43:06 +0000586 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700587 testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
588 &protectedData, &keysToSignMac);
David Drysdalee99ed862021-03-15 16:43:06 +0000589 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) {
Seth Moore19acbe92021-06-23 15:15:52 -0700597 bool testMode = false;
David Drysdalee99ed862021-03-15 16:43:06 +0000598 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(
subrahmanyamanfb213d62022-02-02 23:10:55 +0000605 testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
606 challenge_, &deviceInfo, &protectedData, &keysToSignMac);
David Drysdalee99ed862021-03-15 16:43:06 +0000607 ASSERT_FALSE(status.isOk()) << status.getMessage();
Seth Moore19acbe92021-06-23 15:15:52 -0700608 EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
David Drysdalee99ed862021-03-15 16:43:06 +0000609}
610
611/**
David Drysdalecceca9f2021-03-12 15:49:47 +0000612 * Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
613 * Confirm that the request is rejected.
David Drysdalecceca9f2021-03-12 15:49:47 +0000614 */
615TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
616 bool testMode = false;
617 generateKeys(testMode, 4 /* numKeys */);
618
subrahmanyamanfb213d62022-02-02 23:10:55 +0000619 auto prodEekChain = getProdEekChain(rpcHardwareInfo.supportedEekCurve);
Seth Moore19acbe92021-06-23 15:15:52 -0700620 auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
621 ASSERT_NE(parsedChain, nullptr) << parseErr;
622 ASSERT_NE(parsedChain->asArray(), nullptr);
623
624 for (int ii = 0; ii < parsedChain->asArray()->size(); ++ii) {
625 auto chain = corrupt_sig_chain(prodEekChain, ii);
David Drysdalecceca9f2021-03-12 15:49:47 +0000626 ASSERT_TRUE(chain) << chain.message();
David Drysdalecceca9f2021-03-12 15:49:47 +0000627
628 bytevec keysToSignMac;
629 DeviceInfo deviceInfo;
630 ProtectedData protectedData;
Seth Moore19acbe92021-06-23 15:15:52 -0700631 auto status = provisionable_->generateCertificateRequest(testMode, keysToSign_, *chain,
632 challenge_, &deviceInfo,
633 &protectedData, &keysToSignMac);
David Drysdalecceca9f2021-03-12 15:49:47 +0000634 ASSERT_FALSE(status.isOk());
635 ASSERT_EQ(status.getServiceSpecificError(),
636 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
637 }
638}
639
640/**
641 * Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
642 * Confirm that the request is rejected.
David Drysdalecceca9f2021-03-12 15:49:47 +0000643 */
644TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
645 bool testMode = false;
646 generateKeys(testMode, 4 /* numKeys */);
647
648 // Build an EEK chain that omits the first self-signed cert.
649 auto truncatedChain = cppbor::Array();
subrahmanyamanfb213d62022-02-02 23:10:55 +0000650 auto [chain, _, parseErr] = cppbor::parse(getProdEekChain(rpcHardwareInfo.supportedEekCurve));
David Drysdalecceca9f2021-03-12 15:49:47 +0000651 ASSERT_TRUE(chain);
652 auto eekChain = chain->asArray();
653 ASSERT_NE(eekChain, nullptr);
654 for (size_t ii = 1; ii < eekChain->size(); ii++) {
655 truncatedChain.add(eekChain->get(ii)->clone());
656 }
657
Shawn Willden274bb552020-09-30 22:39:22 -0600658 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700659 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600660 ProtectedData protectedData;
David Drysdalecceca9f2021-03-12 15:49:47 +0000661 auto status = provisionable_->generateCertificateRequest(
662 testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
663 &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600664 ASSERT_FALSE(status.isOk());
665 ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
666}
667
668/**
669 * Generate a non-empty certificate request in test mode, with prod keys. Must fail with
670 * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
671 */
Max Bires126869a2021-02-21 18:32:59 -0800672TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600673 generateKeys(false /* testMode */, 2 /* numKeys */);
674
675 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700676 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600677 ProtectedData protectedData;
subrahmanyamanfb213d62022-02-02 23:10:55 +0000678 generateTestEekChain(3);
Max Biresfdbb9042021-03-23 12:43:38 -0700679 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700680 true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
Max Biresfdbb9042021-03-23 12:43:38 -0700681 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600682 ASSERT_FALSE(status.isOk());
683 ASSERT_EQ(status.getServiceSpecificError(),
684 BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
685}
686
687/**
688 * Generate a non-empty certificate request in prod mode, with test keys. Must fail with
689 * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
690 */
Max Bires126869a2021-02-21 18:32:59 -0800691TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600692 generateKeys(true /* testMode */, 2 /* numKeys */);
693
694 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700695 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600696 ProtectedData protectedData;
subrahmanyamanfb213d62022-02-02 23:10:55 +0000697 generateTestEekChain(3);
Shawn Willden274bb552020-09-30 22:39:22 -0600698 auto status = provisionable_->generateCertificateRequest(
Seth Moore19acbe92021-06-23 15:15:52 -0700699 false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
David Drysdalec8400772021-03-11 12:35:11 +0000700 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600701 ASSERT_FALSE(status.isOk());
702 ASSERT_EQ(status.getServiceSpecificError(),
703 BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
704}
705
706INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
707
708} // namespace aidl::android::hardware::security::keymint::test