blob: 9e52b20675ece226b7ce7521e1c1e240d34c497e [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 Drysdalee99ed862021-03-15 16:43:06 +000058ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
59 auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
60 if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
61 return "COSE Mac0 parse failed";
62 }
63 auto protParams = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
64 auto unprotParams = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
65 auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
66 auto tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
67 if (!protParams || !unprotParams || !payload || !tag) {
68 return "Invalid COSE_Sign1: missing content";
69 }
70 auto corruptMac0 = cppbor::Array();
71 corruptMac0.add(protParams->clone());
72 corruptMac0.add(unprotParams->clone());
73 corruptMac0.add(payload->clone());
74 vector<uint8_t> tagData = tag->value();
75 tagData[0] ^= 0x08;
76 tagData[tagData.size() - 1] ^= 0x80;
77 corruptMac0.add(cppbor::Bstr(tagData));
78
79 return MacedPublicKey{corruptMac0.encode()};
80}
81
David Drysdalecceca9f2021-03-12 15:49:47 +000082ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
83 if (coseSign1->size() != kCoseSign1EntryCount) {
84 return "Invalid COSE_Sign1, wrong entry count";
85 }
86 const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
87 const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
88 const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
89 const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
90 if (!protectedParams || !unprotectedParams || !payload || !signature) {
91 return "Invalid COSE_Sign1: missing content";
92 }
93
94 auto corruptSig = cppbor::Array();
95 corruptSig.add(protectedParams->clone());
96 corruptSig.add(unprotectedParams->clone());
97 corruptSig.add(payload->clone());
98 vector<uint8_t> sigData = signature->value();
99 sigData[0] ^= 0x08;
100 corruptSig.add(cppbor::Bstr(sigData));
101
102 return std::move(corruptSig);
103}
104
105ErrMsgOr<EekChain> corrupt_sig_chain(const EekChain& eek, int which) {
106 auto [chain, _, parseErr] = cppbor::parse(eek.chain);
107 if (!chain || !chain->asArray()) {
108 return "EekChain parse failed";
109 }
110
111 cppbor::Array* eekChain = chain->asArray();
112 if (which >= eekChain->size()) {
113 return "selected sig out of range";
114 }
115 auto corruptChain = cppbor::Array();
116
117 for (int ii = 0; ii < eekChain->size(); ++ii) {
118 if (ii == which) {
119 auto sig = corrupt_sig(eekChain->get(which)->asArray());
120 if (!sig) {
121 return "Failed to build corrupted signature" + sig.moveMessage();
122 }
123 corruptChain.add(sig.moveValue());
124 } else {
125 corruptChain.add(eekChain->get(ii)->clone());
126 }
127 }
128 return EekChain{corruptChain.encode(), eek.last_pubkey, eek.last_privkey};
129}
130
David Drysdale4d3c2982021-03-31 18:21:40 +0100131string device_suffix(const string& name) {
132 size_t pos = name.find('/');
133 if (pos == string::npos) {
134 return name;
135 }
136 return name.substr(pos + 1);
137}
138
139bool matching_keymint_device(const string& rp_name, std::shared_ptr<IKeyMintDevice>* keyMint) {
140 string rp_suffix = device_suffix(rp_name);
141
142 vector<string> km_names = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
143 for (const string& km_name : km_names) {
144 // If the suffix of the KeyMint instance equals the suffix of the
145 // RemotelyProvisionedComponent instance, assume they match.
146 if (device_suffix(km_name) == rp_suffix && AServiceManager_isDeclared(km_name.c_str())) {
147 ::ndk::SpAIBinder binder(AServiceManager_waitForService(km_name.c_str()));
148 *keyMint = IKeyMintDevice::fromBinder(binder);
149 return true;
150 }
151 }
152 return false;
153}
154
Shawn Willden274bb552020-09-30 22:39:22 -0600155} // namespace
156
157class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
158 public:
159 virtual void SetUp() override {
160 if (AServiceManager_isDeclared(GetParam().c_str())) {
161 ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
162 provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
163 }
164 ASSERT_NE(provisionable_, nullptr);
165 }
166
167 static vector<string> build_params() {
168 auto params = ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
169 return params;
170 }
171
172 protected:
173 std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
174};
175
176using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
177
178INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
179
180/**
David Drysdalef0d516d2021-03-22 07:51:43 +0000181 * Generate and validate a production-mode key. MAC tag can't be verified, but
182 * the private key blob should be usable in KeyMint operations.
Shawn Willden274bb552020-09-30 22:39:22 -0600183 */
Max Bires126869a2021-02-21 18:32:59 -0800184TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600185 MacedPublicKey macedPubKey;
186 bytevec privateKeyBlob;
187 bool testMode = false;
188 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
189 ASSERT_TRUE(status.isOk());
David Drysdalef0d516d2021-03-22 07:51:43 +0000190 vector<uint8_t> coseKeyData;
191 check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
David Drysdale4d3c2982021-03-31 18:21:40 +0100192}
193
194/**
195 * Generate and validate a production-mode key, then use it as a KeyMint attestation key.
196 */
197TEST_P(GenerateKeyTests, generateAndUseEcdsaP256Key_prodMode) {
198 // See if there is a matching IKeyMintDevice for this IRemotelyProvisionedComponent.
199 std::shared_ptr<IKeyMintDevice> keyMint;
200 if (!matching_keymint_device(GetParam(), &keyMint)) {
201 // No matching IKeyMintDevice.
202 GTEST_SKIP() << "Skipping key use test as no matching KeyMint device found";
203 return;
204 }
205 KeyMintHardwareInfo info;
206 ASSERT_TRUE(keyMint->getHardwareInfo(&info).isOk());
207
208 MacedPublicKey macedPubKey;
209 bytevec privateKeyBlob;
210 bool testMode = false;
211 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
212 ASSERT_TRUE(status.isOk());
213 vector<uint8_t> coseKeyData;
214 check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
215
David Drysdalef0d516d2021-03-22 07:51:43 +0000216 AttestationKey attestKey;
217 attestKey.keyBlob = std::move(privateKeyBlob);
218 attestKey.issuerSubjectName = make_name_from_str("Android Keystore Key");
Shawn Willden274bb552020-09-30 22:39:22 -0600219
David Drysdalef0d516d2021-03-22 07:51:43 +0000220 // Generate an ECDSA key that is attested by the generated P256 keypair.
221 AuthorizationSet keyDesc = AuthorizationSetBuilder()
222 .Authorization(TAG_NO_AUTH_REQUIRED)
223 .EcdsaSigningKey(256)
224 .AttestationChallenge("foo")
225 .AttestationApplicationId("bar")
226 .Digest(Digest::NONE)
227 .SetDefaultValidity();
228 KeyCreationResult creationResult;
229 auto result = keyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
230 ASSERT_TRUE(result.isOk());
231 vector<uint8_t> attested_key_blob = std::move(creationResult.keyBlob);
232 vector<KeyCharacteristics> attested_key_characteristics =
233 std::move(creationResult.keyCharacteristics);
234 vector<Certificate> attested_key_cert_chain = std::move(creationResult.certificateChain);
235 EXPECT_EQ(attested_key_cert_chain.size(), 1);
236
237 AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
238 AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
239 EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced,
240 info.securityLevel,
241 attested_key_cert_chain[0].encodedCertificate));
242
243 // Attestation by itself is not valid (last entry is not self-signed).
244 EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
245
246 // The signature over the attested key should correspond to the P256 public key.
247 X509_Ptr key_cert(parse_cert_blob(attested_key_cert_chain[0].encodedCertificate));
248 ASSERT_TRUE(key_cert.get());
249 EVP_PKEY_Ptr signing_pubkey;
250 p256_pub_key(coseKeyData, &signing_pubkey);
251 ASSERT_TRUE(signing_pubkey.get());
252
253 ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
254 << "Verification of attested certificate failed "
255 << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
Shawn Willden274bb552020-09-30 22:39:22 -0600256}
257
258/**
259 * Generate and validate a test-mode key.
260 */
Max Bires126869a2021-02-21 18:32:59 -0800261TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600262 MacedPublicKey macedPubKey;
263 bytevec privateKeyBlob;
264 bool testMode = true;
265 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
266 ASSERT_TRUE(status.isOk());
267
David Drysdalec8400772021-03-11 12:35:11 +0000268 check_maced_pubkey(macedPubKey, testMode, nullptr);
Shawn Willden274bb552020-09-30 22:39:22 -0600269}
270
271class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
272 protected:
David Drysdalec8400772021-03-11 12:35:11 +0000273 CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
David Drysdalecceca9f2021-03-12 15:49:47 +0000274 generateEek(3);
275 }
276
277 void generateEek(size_t eekLength) {
278 auto chain = generateEekChain(eekLength, eekId_);
Shawn Willden274bb552020-09-30 22:39:22 -0600279 EXPECT_TRUE(chain) << chain.message();
280 if (chain) eekChain_ = chain.moveValue();
David Drysdalecceca9f2021-03-12 15:49:47 +0000281 eekLength_ = eekLength;
Shawn Willden274bb552020-09-30 22:39:22 -0600282 }
283
284 void generateKeys(bool testMode, size_t numKeys) {
285 keysToSign_ = std::vector<MacedPublicKey>(numKeys);
286 cborKeysToSign_ = cppbor::Array();
287
288 for (auto& key : keysToSign_) {
289 bytevec privateKeyBlob;
290 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
291 ASSERT_TRUE(status.isOk()) << status.getMessage();
292
David Drysdalec8400772021-03-11 12:35:11 +0000293 vector<uint8_t> payload_value;
294 check_maced_pubkey(key, testMode, &payload_value);
295 cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
Shawn Willden274bb552020-09-30 22:39:22 -0600296 }
297 }
298
David Drysdalef6fc5a62021-03-31 16:14:31 +0100299 void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
David Drysdalec8400772021-03-11 12:35:11 +0000300 const bytevec& keysToSignMac, const ProtectedData& protectedData) {
301 auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
302 ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
303 ASSERT_TRUE(parsedProtectedData->asArray());
304 ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
305
306 auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
307 ASSERT_TRUE(senderPubkey) << senderPubkey.message();
308 EXPECT_EQ(senderPubkey->second, eekId_);
309
310 auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
311 senderPubkey->first, false /* senderIsA */);
312 ASSERT_TRUE(sessionKey) << sessionKey.message();
313
314 auto protectedDataPayload =
315 decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
316 ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
317
318 auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
319 ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
320 ASSERT_TRUE(parsedPayload->asArray());
321 EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
322
323 auto& signedMac = parsedPayload->asArray()->get(0);
324 auto& bcc = parsedPayload->asArray()->get(1);
325 ASSERT_TRUE(signedMac && signedMac->asArray());
326 ASSERT_TRUE(bcc && bcc->asArray());
327
328 // BCC is [ pubkey, + BccEntry]
329 auto bccContents = validateBcc(bcc->asArray());
330 ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
331 ASSERT_GT(bccContents->size(), 0U);
332
David Drysdalef6fc5a62021-03-31 16:14:31 +0100333 auto [deviceInfoMap, __2, deviceInfoErrMsg] = cppbor::parse(deviceInfo.deviceInfo);
334 ASSERT_TRUE(deviceInfoMap) << "Failed to parse deviceInfo: " << deviceInfoErrMsg;
335 ASSERT_TRUE(deviceInfoMap->asMap());
336
David Drysdalec8400772021-03-11 12:35:11 +0000337 auto& signingKey = bccContents->back().pubKey;
David Drysdalef6fc5a62021-03-31 16:14:31 +0100338 auto macKey = verifyAndParseCoseSign1(/* ignore_signature = */ false, signedMac->asArray(),
339 signingKey,
340 cppbor::Array() // SignedMacAad
David Drysdalec8400772021-03-11 12:35:11 +0000341 .add(challenge_)
David Drysdalef6fc5a62021-03-31 16:14:31 +0100342 .add(std::move(deviceInfoMap))
David Drysdalec8400772021-03-11 12:35:11 +0000343 .encode());
344 ASSERT_TRUE(macKey) << macKey.message();
345
346 auto coseMac0 = cppbor::Array()
347 .add(cppbor::Map() // protected
348 .add(ALGORITHM, HMAC_256)
349 .canonicalize()
350 .encode())
351 .add(cppbor::Map()) // unprotected
352 .add(keysToSign.encode()) // payload (keysToSign)
353 .add(keysToSignMac); // tag
354
355 auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
356 ASSERT_TRUE(macPayload) << macPayload.message();
357 }
358
Shawn Willden274bb552020-09-30 22:39:22 -0600359 bytevec eekId_;
David Drysdalecceca9f2021-03-12 15:49:47 +0000360 size_t eekLength_;
Shawn Willden274bb552020-09-30 22:39:22 -0600361 EekChain eekChain_;
David Drysdalec8400772021-03-11 12:35:11 +0000362 bytevec challenge_;
Shawn Willden274bb552020-09-30 22:39:22 -0600363 std::vector<MacedPublicKey> keysToSign_;
364 cppbor::Array cborKeysToSign_;
365};
366
367/**
368 * Generate an empty certificate request in test mode, and decrypt and verify the structure and
369 * content.
370 */
Max Bires126869a2021-02-21 18:32:59 -0800371TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600372 bool testMode = true;
David Drysdalecceca9f2021-03-12 15:49:47 +0000373 for (size_t eekLength : {2, 3, 7}) {
374 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
375 generateEek(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600376
David Drysdalecceca9f2021-03-12 15:49:47 +0000377 bytevec keysToSignMac;
378 DeviceInfo deviceInfo;
379 ProtectedData protectedData;
380 auto status = provisionable_->generateCertificateRequest(
381 testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
382 &protectedData, &keysToSignMac);
383 ASSERT_TRUE(status.isOk()) << status.getMessage();
384
David Drysdalef6fc5a62021-03-31 16:14:31 +0100385 checkProtectedData(deviceInfo, cppbor::Array(), keysToSignMac, protectedData);
David Drysdalecceca9f2021-03-12 15:49:47 +0000386 }
Shawn Willden274bb552020-09-30 22:39:22 -0600387}
388
389/**
390 * Generate an empty certificate request in prod mode. Generation will fail because we don't have a
391 * valid GEEK.
392 *
393 * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
394 * able to decrypt.
395 */
Max Bires126869a2021-02-21 18:32:59 -0800396TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600397 bool testMode = false;
David Drysdalecceca9f2021-03-12 15:49:47 +0000398 for (size_t eekLength : {2, 3, 7}) {
399 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
400 generateEek(eekLength);
401
402 bytevec keysToSignMac;
403 DeviceInfo deviceInfo;
404 ProtectedData protectedData;
405 auto status = provisionable_->generateCertificateRequest(
406 testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
407 &protectedData, &keysToSignMac);
408 EXPECT_FALSE(status.isOk());
409 EXPECT_EQ(status.getServiceSpecificError(),
410 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
411 }
Shawn Willden274bb552020-09-30 22:39:22 -0600412}
413
414/**
415 * Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
416 */
Max Bires126869a2021-02-21 18:32:59 -0800417TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600418 bool testMode = true;
419 generateKeys(testMode, 4 /* numKeys */);
420
David Drysdalecceca9f2021-03-12 15:49:47 +0000421 for (size_t eekLength : {2, 3, 7}) {
422 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
423 generateEek(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600424
David Drysdalecceca9f2021-03-12 15:49:47 +0000425 bytevec keysToSignMac;
426 DeviceInfo deviceInfo;
427 ProtectedData protectedData;
428 auto status = provisionable_->generateCertificateRequest(
429 testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
430 &keysToSignMac);
431 ASSERT_TRUE(status.isOk()) << status.getMessage();
432
David Drysdalef6fc5a62021-03-31 16:14:31 +0100433 checkProtectedData(deviceInfo, cborKeysToSign_, keysToSignMac, protectedData);
David Drysdalecceca9f2021-03-12 15:49:47 +0000434 }
Shawn Willden274bb552020-09-30 22:39:22 -0600435}
436
437/**
438 * Generate a non-empty certificate request in prod mode. Must fail because we don't have a valid
439 * GEEK.
440 *
441 * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
442 * able to decrypt.
443 */
Max Bires126869a2021-02-21 18:32:59 -0800444TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600445 bool testMode = false;
446 generateKeys(testMode, 4 /* numKeys */);
447
David Drysdalecceca9f2021-03-12 15:49:47 +0000448 for (size_t eekLength : {2, 3, 7}) {
449 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
450 generateEek(eekLength);
451
452 bytevec keysToSignMac;
453 DeviceInfo deviceInfo;
454 ProtectedData protectedData;
455 auto status = provisionable_->generateCertificateRequest(
456 testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
457 &keysToSignMac);
458 EXPECT_FALSE(status.isOk());
459 EXPECT_EQ(status.getServiceSpecificError(),
460 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
461 }
462}
463
464/**
David Drysdalee99ed862021-03-15 16:43:06 +0000465 * Generate a non-empty certificate request in test mode, but with the MAC corrupted on the keypair.
466 */
467TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
468 bool testMode = true;
469 generateKeys(testMode, 1 /* numKeys */);
470 MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
471
472 bytevec keysToSignMac;
473 DeviceInfo deviceInfo;
474 ProtectedData protectedData;
475 auto status = provisionable_->generateCertificateRequest(
476 testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
477 &keysToSignMac);
478 ASSERT_FALSE(status.isOk()) << status.getMessage();
479 EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
480}
481
482/**
483 * Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
484 */
485TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
486 bool testMode = true;
487 generateKeys(testMode, 1 /* numKeys */);
488 MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
489
490 bytevec keysToSignMac;
491 DeviceInfo deviceInfo;
492 ProtectedData protectedData;
493 auto status = provisionable_->generateCertificateRequest(
494 testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
495 &keysToSignMac);
496 ASSERT_FALSE(status.isOk()) << status.getMessage();
497 auto rc = status.getServiceSpecificError();
498
499 // TODO(drysdale): drop the INVALID_EEK potential error code when a real GEEK is available.
500 EXPECT_TRUE(rc == BnRemotelyProvisionedComponent::STATUS_INVALID_EEK ||
501 rc == BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
502}
503
504/**
David Drysdalecceca9f2021-03-12 15:49:47 +0000505 * Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
506 * Confirm that the request is rejected.
507 *
508 * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
509 * implementation is checking signatures.
510 */
511TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
512 bool testMode = false;
513 generateKeys(testMode, 4 /* numKeys */);
514
515 for (size_t ii = 0; ii < eekLength_; ii++) {
516 auto chain = corrupt_sig_chain(eekChain_, ii);
517 ASSERT_TRUE(chain) << chain.message();
518 EekChain corruptEek = chain.moveValue();
519
520 bytevec keysToSignMac;
521 DeviceInfo deviceInfo;
522 ProtectedData protectedData;
523 auto status = provisionable_->generateCertificateRequest(
524 testMode, keysToSign_, corruptEek.chain, challenge_, &deviceInfo, &protectedData,
525 &keysToSignMac);
526 ASSERT_FALSE(status.isOk());
527 ASSERT_EQ(status.getServiceSpecificError(),
528 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
529 }
530}
531
532/**
533 * Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
534 * Confirm that the request is rejected.
535 *
536 * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
537 * implementation is checking signatures.
538 */
539TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
540 bool testMode = false;
541 generateKeys(testMode, 4 /* numKeys */);
542
543 // Build an EEK chain that omits the first self-signed cert.
544 auto truncatedChain = cppbor::Array();
545 auto [chain, _, parseErr] = cppbor::parse(eekChain_.chain);
546 ASSERT_TRUE(chain);
547 auto eekChain = chain->asArray();
548 ASSERT_NE(eekChain, nullptr);
549 for (size_t ii = 1; ii < eekChain->size(); ii++) {
550 truncatedChain.add(eekChain->get(ii)->clone());
551 }
552
Shawn Willden274bb552020-09-30 22:39:22 -0600553 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700554 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600555 ProtectedData protectedData;
David Drysdalecceca9f2021-03-12 15:49:47 +0000556 auto status = provisionable_->generateCertificateRequest(
557 testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
558 &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600559 ASSERT_FALSE(status.isOk());
560 ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
561}
562
563/**
564 * Generate a non-empty certificate request in test mode, with prod keys. Must fail with
565 * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
566 */
Max Bires126869a2021-02-21 18:32:59 -0800567TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600568 generateKeys(false /* testMode */, 2 /* numKeys */);
569
570 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700571 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600572 ProtectedData protectedData;
Max Biresfdbb9042021-03-23 12:43:38 -0700573 auto status = provisionable_->generateCertificateRequest(
David Drysdalec8400772021-03-11 12:35:11 +0000574 true /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
Max Biresfdbb9042021-03-23 12:43:38 -0700575 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600576 ASSERT_FALSE(status.isOk());
577 ASSERT_EQ(status.getServiceSpecificError(),
578 BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
579}
580
581/**
582 * Generate a non-empty certificate request in prod mode, with test keys. Must fail with
583 * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
584 */
Max Bires126869a2021-02-21 18:32:59 -0800585TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600586 generateKeys(true /* testMode */, 2 /* numKeys */);
587
588 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700589 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600590 ProtectedData protectedData;
591 auto status = provisionable_->generateCertificateRequest(
David Drysdalec8400772021-03-11 12:35:11 +0000592 false /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
593 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600594 ASSERT_FALSE(status.isOk());
595 ASSERT_EQ(status.getServiceSpecificError(),
596 BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
597}
598
599INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
600
601} // namespace aidl::android::hardware::security::keymint::test