blob: 14702fa9bf07c04dd19a8acfd3a7fc80191fa7b4 [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>
20#include <aidl/Gtest.h>
21#include <aidl/Vintf.h>
22#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
23#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
24#include <android/binder_manager.h>
25#include <cppbor_parse.h>
26#include <cppcose/cppcose.h>
27#include <gmock/gmock.h>
28#include <gtest/gtest.h>
29#include <keymaster/keymaster_configuration.h>
30#include <remote_prov/remote_prov_utils.h>
31
32namespace aidl::android::hardware::security::keymint::test {
33
34using ::std::string;
35using ::std::vector;
36
37namespace {
38
39#define INSTANTIATE_REM_PROV_AIDL_TEST(name) \
40 INSTANTIATE_TEST_SUITE_P( \
41 PerInstance, name, \
42 testing::ValuesIn(VtsRemotelyProvisionedComponentTests::build_params()), \
43 ::android::PrintInstanceNameToString)
44
45using bytevec = std::vector<uint8_t>;
46using testing::MatchesRegex;
47using namespace remote_prov;
48using namespace keymaster;
49
50bytevec string_to_bytevec(const char* s) {
51 const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
52 return bytevec(p, p + strlen(s));
53}
54
David Drysdalec8400772021-03-11 12:35:11 +000055void check_cose_key(const vector<uint8_t>& data, bool testMode) {
56 auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
57 ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
58
59 // The following check assumes that canonical CBOR encoding is used for the COSE_Key.
60 if (testMode) {
61 EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
62 MatchesRegex("{\n"
63 " 1 : 2,\n" // kty: EC2
64 " 3 : -7,\n" // alg: ES256
65 " -1 : 1,\n" // EC id: P256
66 // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
67 // sequence of 32 hexadecimal bytes, enclosed in braces and
68 // separated by commas. In this case, some Ed25519 public key.
69 " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
70 " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
71 " -70000 : null,\n" // test marker
72 "}"));
73 } else {
74 EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
75 MatchesRegex("{\n"
76 " 1 : 2,\n" // kty: EC2
77 " 3 : -7,\n" // alg: ES256
78 " -1 : 1,\n" // EC id: P256
79 // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
80 // sequence of 32 hexadecimal bytes, enclosed in braces and
81 // separated by commas. In this case, some Ed25519 public key.
82 " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
83 " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
84 "}"));
85 }
86}
87
88void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
89 vector<uint8_t>* payload_value) {
90 auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
91 ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
92
93 ASSERT_NE(coseMac0->asArray(), nullptr);
94 ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
95
96 auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
97 ASSERT_NE(protParms, nullptr);
98
99 // Header label:value of 'alg': HMAC-256
100 ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
101
102 auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
103 ASSERT_NE(unprotParms, nullptr);
104 ASSERT_EQ(unprotParms->size(), 0);
105
106 // The payload is a bstr holding an encoded COSE_Key
107 auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
108 ASSERT_NE(payload, nullptr);
109 check_cose_key(payload->value(), testMode);
110
111 auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
112 ASSERT_TRUE(coseMac0Tag);
113 auto extractedTag = coseMac0Tag->value();
114 EXPECT_EQ(extractedTag.size(), 32U);
115
116 // Compare with tag generated with kTestMacKey. Should only match in test mode
117 auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
118 payload->value());
119 ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
120
121 if (testMode) {
122 EXPECT_EQ(*testTag, extractedTag);
123 } else {
124 EXPECT_NE(*testTag, extractedTag);
125 }
126 if (payload_value != nullptr) {
127 *payload_value = payload->value();
128 }
129}
130
David Drysdalee99ed862021-03-15 16:43:06 +0000131ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
132 auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
133 if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
134 return "COSE Mac0 parse failed";
135 }
136 auto protParams = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
137 auto unprotParams = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
138 auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
139 auto tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
140 if (!protParams || !unprotParams || !payload || !tag) {
141 return "Invalid COSE_Sign1: missing content";
142 }
143 auto corruptMac0 = cppbor::Array();
144 corruptMac0.add(protParams->clone());
145 corruptMac0.add(unprotParams->clone());
146 corruptMac0.add(payload->clone());
147 vector<uint8_t> tagData = tag->value();
148 tagData[0] ^= 0x08;
149 tagData[tagData.size() - 1] ^= 0x80;
150 corruptMac0.add(cppbor::Bstr(tagData));
151
152 return MacedPublicKey{corruptMac0.encode()};
153}
154
David Drysdalecceca9f2021-03-12 15:49:47 +0000155ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
156 if (coseSign1->size() != kCoseSign1EntryCount) {
157 return "Invalid COSE_Sign1, wrong entry count";
158 }
159 const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
160 const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
161 const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
162 const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
163 if (!protectedParams || !unprotectedParams || !payload || !signature) {
164 return "Invalid COSE_Sign1: missing content";
165 }
166
167 auto corruptSig = cppbor::Array();
168 corruptSig.add(protectedParams->clone());
169 corruptSig.add(unprotectedParams->clone());
170 corruptSig.add(payload->clone());
171 vector<uint8_t> sigData = signature->value();
172 sigData[0] ^= 0x08;
173 corruptSig.add(cppbor::Bstr(sigData));
174
175 return std::move(corruptSig);
176}
177
178ErrMsgOr<EekChain> corrupt_sig_chain(const EekChain& eek, int which) {
179 auto [chain, _, parseErr] = cppbor::parse(eek.chain);
180 if (!chain || !chain->asArray()) {
181 return "EekChain parse failed";
182 }
183
184 cppbor::Array* eekChain = chain->asArray();
185 if (which >= eekChain->size()) {
186 return "selected sig out of range";
187 }
188 auto corruptChain = cppbor::Array();
189
190 for (int ii = 0; ii < eekChain->size(); ++ii) {
191 if (ii == which) {
192 auto sig = corrupt_sig(eekChain->get(which)->asArray());
193 if (!sig) {
194 return "Failed to build corrupted signature" + sig.moveMessage();
195 }
196 corruptChain.add(sig.moveValue());
197 } else {
198 corruptChain.add(eekChain->get(ii)->clone());
199 }
200 }
201 return EekChain{corruptChain.encode(), eek.last_pubkey, eek.last_privkey};
202}
203
Shawn Willden274bb552020-09-30 22:39:22 -0600204} // namespace
205
206class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
207 public:
208 virtual void SetUp() override {
209 if (AServiceManager_isDeclared(GetParam().c_str())) {
210 ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
211 provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
212 }
213 ASSERT_NE(provisionable_, nullptr);
214 }
215
216 static vector<string> build_params() {
217 auto params = ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
218 return params;
219 }
220
221 protected:
222 std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
223};
224
225using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
226
227INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
228
229/**
230 * Generate and validate a production-mode key. MAC tag can't be verified.
231 */
Max Bires126869a2021-02-21 18:32:59 -0800232TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600233 MacedPublicKey macedPubKey;
234 bytevec privateKeyBlob;
235 bool testMode = false;
236 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
237 ASSERT_TRUE(status.isOk());
238
David Drysdalec8400772021-03-11 12:35:11 +0000239 check_maced_pubkey(macedPubKey, testMode, nullptr);
Shawn Willden274bb552020-09-30 22:39:22 -0600240}
241
242/**
243 * Generate and validate a test-mode key.
244 */
Max Bires126869a2021-02-21 18:32:59 -0800245TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600246 MacedPublicKey macedPubKey;
247 bytevec privateKeyBlob;
248 bool testMode = true;
249 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
250 ASSERT_TRUE(status.isOk());
251
David Drysdalec8400772021-03-11 12:35:11 +0000252 check_maced_pubkey(macedPubKey, testMode, nullptr);
Shawn Willden274bb552020-09-30 22:39:22 -0600253}
254
255class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
256 protected:
David Drysdalec8400772021-03-11 12:35:11 +0000257 CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
David Drysdalecceca9f2021-03-12 15:49:47 +0000258 generateEek(3);
259 }
260
261 void generateEek(size_t eekLength) {
262 auto chain = generateEekChain(eekLength, eekId_);
Shawn Willden274bb552020-09-30 22:39:22 -0600263 EXPECT_TRUE(chain) << chain.message();
264 if (chain) eekChain_ = chain.moveValue();
David Drysdalecceca9f2021-03-12 15:49:47 +0000265 eekLength_ = eekLength;
Shawn Willden274bb552020-09-30 22:39:22 -0600266 }
267
268 void generateKeys(bool testMode, size_t numKeys) {
269 keysToSign_ = std::vector<MacedPublicKey>(numKeys);
270 cborKeysToSign_ = cppbor::Array();
271
272 for (auto& key : keysToSign_) {
273 bytevec privateKeyBlob;
274 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
275 ASSERT_TRUE(status.isOk()) << status.getMessage();
276
David Drysdalec8400772021-03-11 12:35:11 +0000277 vector<uint8_t> payload_value;
278 check_maced_pubkey(key, testMode, &payload_value);
279 cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
Shawn Willden274bb552020-09-30 22:39:22 -0600280 }
281 }
282
David Drysdalec8400772021-03-11 12:35:11 +0000283 void checkProtectedData(bool testMode, const cppbor::Array& keysToSign,
284 const bytevec& keysToSignMac, const ProtectedData& protectedData) {
285 auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
286 ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
287 ASSERT_TRUE(parsedProtectedData->asArray());
288 ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
289
290 auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
291 ASSERT_TRUE(senderPubkey) << senderPubkey.message();
292 EXPECT_EQ(senderPubkey->second, eekId_);
293
294 auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
295 senderPubkey->first, false /* senderIsA */);
296 ASSERT_TRUE(sessionKey) << sessionKey.message();
297
298 auto protectedDataPayload =
299 decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
300 ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
301
302 auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
303 ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
304 ASSERT_TRUE(parsedPayload->asArray());
305 EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
306
307 auto& signedMac = parsedPayload->asArray()->get(0);
308 auto& bcc = parsedPayload->asArray()->get(1);
309 ASSERT_TRUE(signedMac && signedMac->asArray());
310 ASSERT_TRUE(bcc && bcc->asArray());
311
312 // BCC is [ pubkey, + BccEntry]
313 auto bccContents = validateBcc(bcc->asArray());
314 ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
315 ASSERT_GT(bccContents->size(), 0U);
316
317 auto& signingKey = bccContents->back().pubKey;
318 auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
319 cppbor::Array() // DeviceInfo
320 .add(challenge_)
321 .add(cppbor::Map())
322 .encode());
323 ASSERT_TRUE(macKey) << macKey.message();
324
325 auto coseMac0 = cppbor::Array()
326 .add(cppbor::Map() // protected
327 .add(ALGORITHM, HMAC_256)
328 .canonicalize()
329 .encode())
330 .add(cppbor::Map()) // unprotected
331 .add(keysToSign.encode()) // payload (keysToSign)
332 .add(keysToSignMac); // tag
333
334 auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
335 ASSERT_TRUE(macPayload) << macPayload.message();
336 }
337
Shawn Willden274bb552020-09-30 22:39:22 -0600338 bytevec eekId_;
David Drysdalecceca9f2021-03-12 15:49:47 +0000339 size_t eekLength_;
Shawn Willden274bb552020-09-30 22:39:22 -0600340 EekChain eekChain_;
David Drysdalec8400772021-03-11 12:35:11 +0000341 bytevec challenge_;
Shawn Willden274bb552020-09-30 22:39:22 -0600342 std::vector<MacedPublicKey> keysToSign_;
343 cppbor::Array cborKeysToSign_;
344};
345
346/**
347 * Generate an empty certificate request in test mode, and decrypt and verify the structure and
348 * content.
349 */
Max Bires126869a2021-02-21 18:32:59 -0800350TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600351 bool testMode = true;
David Drysdalecceca9f2021-03-12 15:49:47 +0000352 for (size_t eekLength : {2, 3, 7}) {
353 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
354 generateEek(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600355
David Drysdalecceca9f2021-03-12 15:49:47 +0000356 bytevec keysToSignMac;
357 DeviceInfo deviceInfo;
358 ProtectedData protectedData;
359 auto status = provisionable_->generateCertificateRequest(
360 testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
361 &protectedData, &keysToSignMac);
362 ASSERT_TRUE(status.isOk()) << status.getMessage();
363
364 checkProtectedData(testMode, cppbor::Array(), keysToSignMac, protectedData);
365 }
Shawn Willden274bb552020-09-30 22:39:22 -0600366}
367
368/**
369 * Generate an empty certificate request in prod mode. Generation will fail because we don't have a
370 * valid GEEK.
371 *
372 * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
373 * able to decrypt.
374 */
Max Bires126869a2021-02-21 18:32:59 -0800375TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600376 bool testMode = false;
David Drysdalecceca9f2021-03-12 15:49:47 +0000377 for (size_t eekLength : {2, 3, 7}) {
378 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
379 generateEek(eekLength);
380
381 bytevec keysToSignMac;
382 DeviceInfo deviceInfo;
383 ProtectedData protectedData;
384 auto status = provisionable_->generateCertificateRequest(
385 testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
386 &protectedData, &keysToSignMac);
387 EXPECT_FALSE(status.isOk());
388 EXPECT_EQ(status.getServiceSpecificError(),
389 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
390 }
Shawn Willden274bb552020-09-30 22:39:22 -0600391}
392
393/**
394 * Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
395 */
Max Bires126869a2021-02-21 18:32:59 -0800396TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600397 bool testMode = true;
398 generateKeys(testMode, 4 /* numKeys */);
399
David Drysdalecceca9f2021-03-12 15:49:47 +0000400 for (size_t eekLength : {2, 3, 7}) {
401 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
402 generateEek(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600403
David Drysdalecceca9f2021-03-12 15:49:47 +0000404 bytevec keysToSignMac;
405 DeviceInfo deviceInfo;
406 ProtectedData protectedData;
407 auto status = provisionable_->generateCertificateRequest(
408 testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
409 &keysToSignMac);
410 ASSERT_TRUE(status.isOk()) << status.getMessage();
411
412 checkProtectedData(testMode, cborKeysToSign_, keysToSignMac, protectedData);
413 }
Shawn Willden274bb552020-09-30 22:39:22 -0600414}
415
416/**
417 * Generate a non-empty certificate request in prod mode. Must fail because we don't have a valid
418 * GEEK.
419 *
420 * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
421 * able to decrypt.
422 */
Max Bires126869a2021-02-21 18:32:59 -0800423TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600424 bool testMode = false;
425 generateKeys(testMode, 4 /* numKeys */);
426
David Drysdalecceca9f2021-03-12 15:49:47 +0000427 for (size_t eekLength : {2, 3, 7}) {
428 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
429 generateEek(eekLength);
430
431 bytevec keysToSignMac;
432 DeviceInfo deviceInfo;
433 ProtectedData protectedData;
434 auto status = provisionable_->generateCertificateRequest(
435 testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
436 &keysToSignMac);
437 EXPECT_FALSE(status.isOk());
438 EXPECT_EQ(status.getServiceSpecificError(),
439 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
440 }
441}
442
443/**
David Drysdalee99ed862021-03-15 16:43:06 +0000444 * Generate a non-empty certificate request in test mode, but with the MAC corrupted on the keypair.
445 */
446TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
447 bool testMode = true;
448 generateKeys(testMode, 1 /* numKeys */);
449 MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
450
451 bytevec keysToSignMac;
452 DeviceInfo deviceInfo;
453 ProtectedData protectedData;
454 auto status = provisionable_->generateCertificateRequest(
455 testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
456 &keysToSignMac);
457 ASSERT_FALSE(status.isOk()) << status.getMessage();
458 EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
459}
460
461/**
462 * Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
463 */
464TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
465 bool testMode = true;
466 generateKeys(testMode, 1 /* numKeys */);
467 MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
468
469 bytevec keysToSignMac;
470 DeviceInfo deviceInfo;
471 ProtectedData protectedData;
472 auto status = provisionable_->generateCertificateRequest(
473 testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
474 &keysToSignMac);
475 ASSERT_FALSE(status.isOk()) << status.getMessage();
476 auto rc = status.getServiceSpecificError();
477
478 // TODO(drysdale): drop the INVALID_EEK potential error code when a real GEEK is available.
479 EXPECT_TRUE(rc == BnRemotelyProvisionedComponent::STATUS_INVALID_EEK ||
480 rc == BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
481}
482
483/**
David Drysdalecceca9f2021-03-12 15:49:47 +0000484 * Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
485 * Confirm that the request is rejected.
486 *
487 * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
488 * implementation is checking signatures.
489 */
490TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
491 bool testMode = false;
492 generateKeys(testMode, 4 /* numKeys */);
493
494 for (size_t ii = 0; ii < eekLength_; ii++) {
495 auto chain = corrupt_sig_chain(eekChain_, ii);
496 ASSERT_TRUE(chain) << chain.message();
497 EekChain corruptEek = chain.moveValue();
498
499 bytevec keysToSignMac;
500 DeviceInfo deviceInfo;
501 ProtectedData protectedData;
502 auto status = provisionable_->generateCertificateRequest(
503 testMode, keysToSign_, corruptEek.chain, challenge_, &deviceInfo, &protectedData,
504 &keysToSignMac);
505 ASSERT_FALSE(status.isOk());
506 ASSERT_EQ(status.getServiceSpecificError(),
507 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
508 }
509}
510
511/**
512 * Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
513 * Confirm that the request is rejected.
514 *
515 * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
516 * implementation is checking signatures.
517 */
518TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
519 bool testMode = false;
520 generateKeys(testMode, 4 /* numKeys */);
521
522 // Build an EEK chain that omits the first self-signed cert.
523 auto truncatedChain = cppbor::Array();
524 auto [chain, _, parseErr] = cppbor::parse(eekChain_.chain);
525 ASSERT_TRUE(chain);
526 auto eekChain = chain->asArray();
527 ASSERT_NE(eekChain, nullptr);
528 for (size_t ii = 1; ii < eekChain->size(); ii++) {
529 truncatedChain.add(eekChain->get(ii)->clone());
530 }
531
Shawn Willden274bb552020-09-30 22:39:22 -0600532 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700533 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600534 ProtectedData protectedData;
David Drysdalecceca9f2021-03-12 15:49:47 +0000535 auto status = provisionable_->generateCertificateRequest(
536 testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
537 &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600538 ASSERT_FALSE(status.isOk());
539 ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
540}
541
542/**
543 * Generate a non-empty certificate request in test mode, with prod keys. Must fail with
544 * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
545 */
Max Bires126869a2021-02-21 18:32:59 -0800546TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600547 generateKeys(false /* testMode */, 2 /* numKeys */);
548
549 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700550 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600551 ProtectedData protectedData;
Max Biresfdbb9042021-03-23 12:43:38 -0700552 auto status = provisionable_->generateCertificateRequest(
David Drysdalec8400772021-03-11 12:35:11 +0000553 true /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
Max Biresfdbb9042021-03-23 12:43:38 -0700554 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600555 ASSERT_FALSE(status.isOk());
556 ASSERT_EQ(status.getServiceSpecificError(),
557 BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
558}
559
560/**
561 * Generate a non-empty certificate request in prod mode, with test keys. Must fail with
562 * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
563 */
Max Bires126869a2021-02-21 18:32:59 -0800564TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600565 generateKeys(true /* testMode */, 2 /* numKeys */);
566
567 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700568 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600569 ProtectedData protectedData;
570 auto status = provisionable_->generateCertificateRequest(
David Drysdalec8400772021-03-11 12:35:11 +0000571 false /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
572 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600573 ASSERT_FALSE(status.isOk());
574 ASSERT_EQ(status.getServiceSpecificError(),
575 BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
576}
577
578INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
579
580} // namespace aidl::android::hardware::security::keymint::test