blob: a177317297b5a9dc7b52a2a123972f0b1c4015dd [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>
23#include <cppbor_parse.h>
Shawn Willden274bb552020-09-30 22:39:22 -060024#include <gmock/gmock.h>
Max Bires9704ff62021-04-07 11:12:01 -070025#include <keymaster/cppcose/cppcose.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))
Max Bires8dff0b32021-05-26 13:05:09 -0700343 .add(keysToSignMac)
David Drysdalec8400772021-03-11 12:35:11 +0000344 .encode());
345 ASSERT_TRUE(macKey) << macKey.message();
346
347 auto coseMac0 = cppbor::Array()
348 .add(cppbor::Map() // protected
349 .add(ALGORITHM, HMAC_256)
350 .canonicalize()
351 .encode())
352 .add(cppbor::Map()) // unprotected
353 .add(keysToSign.encode()) // payload (keysToSign)
354 .add(keysToSignMac); // tag
355
356 auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
357 ASSERT_TRUE(macPayload) << macPayload.message();
358 }
359
Shawn Willden274bb552020-09-30 22:39:22 -0600360 bytevec eekId_;
David Drysdalecceca9f2021-03-12 15:49:47 +0000361 size_t eekLength_;
Shawn Willden274bb552020-09-30 22:39:22 -0600362 EekChain eekChain_;
David Drysdalec8400772021-03-11 12:35:11 +0000363 bytevec challenge_;
Shawn Willden274bb552020-09-30 22:39:22 -0600364 std::vector<MacedPublicKey> keysToSign_;
365 cppbor::Array cborKeysToSign_;
366};
367
368/**
369 * Generate an empty certificate request in test mode, and decrypt and verify the structure and
370 * content.
371 */
Max Bires126869a2021-02-21 18:32:59 -0800372TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600373 bool testMode = true;
David Drysdalecceca9f2021-03-12 15:49:47 +0000374 for (size_t eekLength : {2, 3, 7}) {
375 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
376 generateEek(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600377
David Drysdalecceca9f2021-03-12 15:49:47 +0000378 bytevec keysToSignMac;
379 DeviceInfo deviceInfo;
380 ProtectedData protectedData;
381 auto status = provisionable_->generateCertificateRequest(
382 testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
383 &protectedData, &keysToSignMac);
384 ASSERT_TRUE(status.isOk()) << status.getMessage();
385
David Drysdalef6fc5a62021-03-31 16:14:31 +0100386 checkProtectedData(deviceInfo, cppbor::Array(), keysToSignMac, protectedData);
David Drysdalecceca9f2021-03-12 15:49:47 +0000387 }
Shawn Willden274bb552020-09-30 22:39:22 -0600388}
389
390/**
391 * Generate an empty certificate request in prod mode. Generation will fail because we don't have a
392 * valid GEEK.
393 *
394 * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
395 * able to decrypt.
396 */
Max Bires126869a2021-02-21 18:32:59 -0800397TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600398 bool testMode = false;
David Drysdalecceca9f2021-03-12 15:49:47 +0000399 for (size_t eekLength : {2, 3, 7}) {
400 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
401 generateEek(eekLength);
402
403 bytevec keysToSignMac;
404 DeviceInfo deviceInfo;
405 ProtectedData protectedData;
406 auto status = provisionable_->generateCertificateRequest(
407 testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
408 &protectedData, &keysToSignMac);
409 EXPECT_FALSE(status.isOk());
410 EXPECT_EQ(status.getServiceSpecificError(),
411 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
412 }
Shawn Willden274bb552020-09-30 22:39:22 -0600413}
414
415/**
416 * Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
417 */
Max Bires126869a2021-02-21 18:32:59 -0800418TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600419 bool testMode = true;
420 generateKeys(testMode, 4 /* numKeys */);
421
David Drysdalecceca9f2021-03-12 15:49:47 +0000422 for (size_t eekLength : {2, 3, 7}) {
423 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
424 generateEek(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600425
David Drysdalecceca9f2021-03-12 15:49:47 +0000426 bytevec keysToSignMac;
427 DeviceInfo deviceInfo;
428 ProtectedData protectedData;
429 auto status = provisionable_->generateCertificateRequest(
430 testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
431 &keysToSignMac);
432 ASSERT_TRUE(status.isOk()) << status.getMessage();
433
David Drysdalef6fc5a62021-03-31 16:14:31 +0100434 checkProtectedData(deviceInfo, cborKeysToSign_, keysToSignMac, protectedData);
David Drysdalecceca9f2021-03-12 15:49:47 +0000435 }
Shawn Willden274bb552020-09-30 22:39:22 -0600436}
437
438/**
439 * Generate a non-empty certificate request in prod mode. Must fail because we don't have a valid
440 * GEEK.
441 *
442 * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
443 * able to decrypt.
444 */
Max Bires126869a2021-02-21 18:32:59 -0800445TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600446 bool testMode = false;
447 generateKeys(testMode, 4 /* numKeys */);
448
David Drysdalecceca9f2021-03-12 15:49:47 +0000449 for (size_t eekLength : {2, 3, 7}) {
450 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
451 generateEek(eekLength);
452
453 bytevec keysToSignMac;
454 DeviceInfo deviceInfo;
455 ProtectedData protectedData;
456 auto status = provisionable_->generateCertificateRequest(
457 testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
458 &keysToSignMac);
459 EXPECT_FALSE(status.isOk());
460 EXPECT_EQ(status.getServiceSpecificError(),
461 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
462 }
463}
464
465/**
David Drysdalee99ed862021-03-15 16:43:06 +0000466 * Generate a non-empty certificate request in test mode, but with the MAC corrupted on the keypair.
467 */
468TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
469 bool testMode = true;
470 generateKeys(testMode, 1 /* numKeys */);
471 MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
472
473 bytevec keysToSignMac;
474 DeviceInfo deviceInfo;
475 ProtectedData protectedData;
476 auto status = provisionable_->generateCertificateRequest(
477 testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
478 &keysToSignMac);
479 ASSERT_FALSE(status.isOk()) << status.getMessage();
480 EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
481}
482
483/**
484 * Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
485 */
486TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
487 bool testMode = true;
488 generateKeys(testMode, 1 /* numKeys */);
489 MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
490
491 bytevec keysToSignMac;
492 DeviceInfo deviceInfo;
493 ProtectedData protectedData;
494 auto status = provisionable_->generateCertificateRequest(
495 testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
496 &keysToSignMac);
497 ASSERT_FALSE(status.isOk()) << status.getMessage();
498 auto rc = status.getServiceSpecificError();
499
500 // TODO(drysdale): drop the INVALID_EEK potential error code when a real GEEK is available.
501 EXPECT_TRUE(rc == BnRemotelyProvisionedComponent::STATUS_INVALID_EEK ||
502 rc == BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
503}
504
505/**
David Drysdalecceca9f2021-03-12 15:49:47 +0000506 * Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
507 * Confirm that the request is rejected.
508 *
509 * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
510 * implementation is checking signatures.
511 */
512TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
513 bool testMode = false;
514 generateKeys(testMode, 4 /* numKeys */);
515
516 for (size_t ii = 0; ii < eekLength_; ii++) {
517 auto chain = corrupt_sig_chain(eekChain_, ii);
518 ASSERT_TRUE(chain) << chain.message();
519 EekChain corruptEek = chain.moveValue();
520
521 bytevec keysToSignMac;
522 DeviceInfo deviceInfo;
523 ProtectedData protectedData;
524 auto status = provisionable_->generateCertificateRequest(
525 testMode, keysToSign_, corruptEek.chain, challenge_, &deviceInfo, &protectedData,
526 &keysToSignMac);
527 ASSERT_FALSE(status.isOk());
528 ASSERT_EQ(status.getServiceSpecificError(),
529 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
530 }
531}
532
533/**
534 * Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
535 * Confirm that the request is rejected.
536 *
537 * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
538 * implementation is checking signatures.
539 */
540TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
541 bool testMode = false;
542 generateKeys(testMode, 4 /* numKeys */);
543
544 // Build an EEK chain that omits the first self-signed cert.
545 auto truncatedChain = cppbor::Array();
546 auto [chain, _, parseErr] = cppbor::parse(eekChain_.chain);
547 ASSERT_TRUE(chain);
548 auto eekChain = chain->asArray();
549 ASSERT_NE(eekChain, nullptr);
550 for (size_t ii = 1; ii < eekChain->size(); ii++) {
551 truncatedChain.add(eekChain->get(ii)->clone());
552 }
553
Shawn Willden274bb552020-09-30 22:39:22 -0600554 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700555 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600556 ProtectedData protectedData;
David Drysdalecceca9f2021-03-12 15:49:47 +0000557 auto status = provisionable_->generateCertificateRequest(
558 testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
559 &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600560 ASSERT_FALSE(status.isOk());
561 ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
562}
563
564/**
565 * Generate a non-empty certificate request in test mode, with prod keys. Must fail with
566 * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
567 */
Max Bires126869a2021-02-21 18:32:59 -0800568TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600569 generateKeys(false /* testMode */, 2 /* numKeys */);
570
571 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700572 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600573 ProtectedData protectedData;
Max Biresfdbb9042021-03-23 12:43:38 -0700574 auto status = provisionable_->generateCertificateRequest(
David Drysdalec8400772021-03-11 12:35:11 +0000575 true /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
Max Biresfdbb9042021-03-23 12:43:38 -0700576 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600577 ASSERT_FALSE(status.isOk());
578 ASSERT_EQ(status.getServiceSpecificError(),
579 BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
580}
581
582/**
583 * Generate a non-empty certificate request in prod mode, with test keys. Must fail with
584 * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
585 */
Max Bires126869a2021-02-21 18:32:59 -0800586TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600587 generateKeys(true /* testMode */, 2 /* numKeys */);
588
589 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700590 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600591 ProtectedData protectedData;
592 auto status = provisionable_->generateCertificateRequest(
David Drysdalec8400772021-03-11 12:35:11 +0000593 false /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
594 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600595 ASSERT_FALSE(status.isOk());
596 ASSERT_EQ(status.getServiceSpecificError(),
597 BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
598}
599
600INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
601
602} // namespace aidl::android::hardware::security::keymint::test