blob: 6c16ff4b2ceecec007321235de585117c6e96882 [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 Drysdalecceca9f2021-03-12 15:49:47 +0000131ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
132 if (coseSign1->size() != kCoseSign1EntryCount) {
133 return "Invalid COSE_Sign1, wrong entry count";
134 }
135 const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
136 const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
137 const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
138 const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
139 if (!protectedParams || !unprotectedParams || !payload || !signature) {
140 return "Invalid COSE_Sign1: missing content";
141 }
142
143 auto corruptSig = cppbor::Array();
144 corruptSig.add(protectedParams->clone());
145 corruptSig.add(unprotectedParams->clone());
146 corruptSig.add(payload->clone());
147 vector<uint8_t> sigData = signature->value();
148 sigData[0] ^= 0x08;
149 corruptSig.add(cppbor::Bstr(sigData));
150
151 return std::move(corruptSig);
152}
153
154ErrMsgOr<EekChain> corrupt_sig_chain(const EekChain& eek, int which) {
155 auto [chain, _, parseErr] = cppbor::parse(eek.chain);
156 if (!chain || !chain->asArray()) {
157 return "EekChain parse failed";
158 }
159
160 cppbor::Array* eekChain = chain->asArray();
161 if (which >= eekChain->size()) {
162 return "selected sig out of range";
163 }
164 auto corruptChain = cppbor::Array();
165
166 for (int ii = 0; ii < eekChain->size(); ++ii) {
167 if (ii == which) {
168 auto sig = corrupt_sig(eekChain->get(which)->asArray());
169 if (!sig) {
170 return "Failed to build corrupted signature" + sig.moveMessage();
171 }
172 corruptChain.add(sig.moveValue());
173 } else {
174 corruptChain.add(eekChain->get(ii)->clone());
175 }
176 }
177 return EekChain{corruptChain.encode(), eek.last_pubkey, eek.last_privkey};
178}
179
Shawn Willden274bb552020-09-30 22:39:22 -0600180} // namespace
181
182class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
183 public:
184 virtual void SetUp() override {
185 if (AServiceManager_isDeclared(GetParam().c_str())) {
186 ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
187 provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
188 }
189 ASSERT_NE(provisionable_, nullptr);
190 }
191
192 static vector<string> build_params() {
193 auto params = ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
194 return params;
195 }
196
197 protected:
198 std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
199};
200
201using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
202
203INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
204
205/**
206 * Generate and validate a production-mode key. MAC tag can't be verified.
207 */
Max Bires126869a2021-02-21 18:32:59 -0800208TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600209 MacedPublicKey macedPubKey;
210 bytevec privateKeyBlob;
211 bool testMode = false;
212 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
213 ASSERT_TRUE(status.isOk());
214
David Drysdalec8400772021-03-11 12:35:11 +0000215 check_maced_pubkey(macedPubKey, testMode, nullptr);
Shawn Willden274bb552020-09-30 22:39:22 -0600216}
217
218/**
219 * Generate and validate a test-mode key.
220 */
Max Bires126869a2021-02-21 18:32:59 -0800221TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600222 MacedPublicKey macedPubKey;
223 bytevec privateKeyBlob;
224 bool testMode = true;
225 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
226 ASSERT_TRUE(status.isOk());
227
David Drysdalec8400772021-03-11 12:35:11 +0000228 check_maced_pubkey(macedPubKey, testMode, nullptr);
Shawn Willden274bb552020-09-30 22:39:22 -0600229}
230
231class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
232 protected:
David Drysdalec8400772021-03-11 12:35:11 +0000233 CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
David Drysdalecceca9f2021-03-12 15:49:47 +0000234 generateEek(3);
235 }
236
237 void generateEek(size_t eekLength) {
238 auto chain = generateEekChain(eekLength, eekId_);
Shawn Willden274bb552020-09-30 22:39:22 -0600239 EXPECT_TRUE(chain) << chain.message();
240 if (chain) eekChain_ = chain.moveValue();
David Drysdalecceca9f2021-03-12 15:49:47 +0000241 eekLength_ = eekLength;
Shawn Willden274bb552020-09-30 22:39:22 -0600242 }
243
244 void generateKeys(bool testMode, size_t numKeys) {
245 keysToSign_ = std::vector<MacedPublicKey>(numKeys);
246 cborKeysToSign_ = cppbor::Array();
247
248 for (auto& key : keysToSign_) {
249 bytevec privateKeyBlob;
250 auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
251 ASSERT_TRUE(status.isOk()) << status.getMessage();
252
David Drysdalec8400772021-03-11 12:35:11 +0000253 vector<uint8_t> payload_value;
254 check_maced_pubkey(key, testMode, &payload_value);
255 cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
Shawn Willden274bb552020-09-30 22:39:22 -0600256 }
257 }
258
David Drysdalec8400772021-03-11 12:35:11 +0000259 void checkProtectedData(bool testMode, const cppbor::Array& keysToSign,
260 const bytevec& keysToSignMac, const ProtectedData& protectedData) {
261 auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
262 ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
263 ASSERT_TRUE(parsedProtectedData->asArray());
264 ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
265
266 auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
267 ASSERT_TRUE(senderPubkey) << senderPubkey.message();
268 EXPECT_EQ(senderPubkey->second, eekId_);
269
270 auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
271 senderPubkey->first, false /* senderIsA */);
272 ASSERT_TRUE(sessionKey) << sessionKey.message();
273
274 auto protectedDataPayload =
275 decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
276 ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
277
278 auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
279 ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
280 ASSERT_TRUE(parsedPayload->asArray());
281 EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
282
283 auto& signedMac = parsedPayload->asArray()->get(0);
284 auto& bcc = parsedPayload->asArray()->get(1);
285 ASSERT_TRUE(signedMac && signedMac->asArray());
286 ASSERT_TRUE(bcc && bcc->asArray());
287
288 // BCC is [ pubkey, + BccEntry]
289 auto bccContents = validateBcc(bcc->asArray());
290 ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
291 ASSERT_GT(bccContents->size(), 0U);
292
293 auto& signingKey = bccContents->back().pubKey;
294 auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
295 cppbor::Array() // DeviceInfo
296 .add(challenge_)
297 .add(cppbor::Map())
298 .encode());
299 ASSERT_TRUE(macKey) << macKey.message();
300
301 auto coseMac0 = cppbor::Array()
302 .add(cppbor::Map() // protected
303 .add(ALGORITHM, HMAC_256)
304 .canonicalize()
305 .encode())
306 .add(cppbor::Map()) // unprotected
307 .add(keysToSign.encode()) // payload (keysToSign)
308 .add(keysToSignMac); // tag
309
310 auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
311 ASSERT_TRUE(macPayload) << macPayload.message();
312 }
313
Shawn Willden274bb552020-09-30 22:39:22 -0600314 bytevec eekId_;
David Drysdalecceca9f2021-03-12 15:49:47 +0000315 size_t eekLength_;
Shawn Willden274bb552020-09-30 22:39:22 -0600316 EekChain eekChain_;
David Drysdalec8400772021-03-11 12:35:11 +0000317 bytevec challenge_;
Shawn Willden274bb552020-09-30 22:39:22 -0600318 std::vector<MacedPublicKey> keysToSign_;
319 cppbor::Array cborKeysToSign_;
320};
321
322/**
323 * Generate an empty certificate request in test mode, and decrypt and verify the structure and
324 * content.
325 */
Max Bires126869a2021-02-21 18:32:59 -0800326TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600327 bool testMode = true;
David Drysdalecceca9f2021-03-12 15:49:47 +0000328 for (size_t eekLength : {2, 3, 7}) {
329 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
330 generateEek(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600331
David Drysdalecceca9f2021-03-12 15:49:47 +0000332 bytevec keysToSignMac;
333 DeviceInfo deviceInfo;
334 ProtectedData protectedData;
335 auto status = provisionable_->generateCertificateRequest(
336 testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
337 &protectedData, &keysToSignMac);
338 ASSERT_TRUE(status.isOk()) << status.getMessage();
339
340 checkProtectedData(testMode, cppbor::Array(), keysToSignMac, protectedData);
341 }
Shawn Willden274bb552020-09-30 22:39:22 -0600342}
343
344/**
345 * Generate an empty certificate request in prod mode. Generation will fail because we don't have a
346 * valid GEEK.
347 *
348 * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
349 * able to decrypt.
350 */
Max Bires126869a2021-02-21 18:32:59 -0800351TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600352 bool testMode = false;
David Drysdalecceca9f2021-03-12 15:49:47 +0000353 for (size_t eekLength : {2, 3, 7}) {
354 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
355 generateEek(eekLength);
356
357 bytevec keysToSignMac;
358 DeviceInfo deviceInfo;
359 ProtectedData protectedData;
360 auto status = provisionable_->generateCertificateRequest(
361 testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
362 &protectedData, &keysToSignMac);
363 EXPECT_FALSE(status.isOk());
364 EXPECT_EQ(status.getServiceSpecificError(),
365 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
366 }
Shawn Willden274bb552020-09-30 22:39:22 -0600367}
368
369/**
370 * Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
371 */
Max Bires126869a2021-02-21 18:32:59 -0800372TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600373 bool testMode = true;
374 generateKeys(testMode, 4 /* numKeys */);
375
David Drysdalecceca9f2021-03-12 15:49:47 +0000376 for (size_t eekLength : {2, 3, 7}) {
377 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
378 generateEek(eekLength);
Shawn Willden274bb552020-09-30 22:39:22 -0600379
David Drysdalecceca9f2021-03-12 15:49:47 +0000380 bytevec keysToSignMac;
381 DeviceInfo deviceInfo;
382 ProtectedData protectedData;
383 auto status = provisionable_->generateCertificateRequest(
384 testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
385 &keysToSignMac);
386 ASSERT_TRUE(status.isOk()) << status.getMessage();
387
388 checkProtectedData(testMode, cborKeysToSign_, keysToSignMac, protectedData);
389 }
Shawn Willden274bb552020-09-30 22:39:22 -0600390}
391
392/**
393 * Generate a non-empty certificate request in prod mode. Must fail because we don't have a valid
394 * GEEK.
395 *
396 * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
397 * able to decrypt.
398 */
Max Bires126869a2021-02-21 18:32:59 -0800399TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
Shawn Willden274bb552020-09-30 22:39:22 -0600400 bool testMode = false;
401 generateKeys(testMode, 4 /* numKeys */);
402
David Drysdalecceca9f2021-03-12 15:49:47 +0000403 for (size_t eekLength : {2, 3, 7}) {
404 SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
405 generateEek(eekLength);
406
407 bytevec keysToSignMac;
408 DeviceInfo deviceInfo;
409 ProtectedData protectedData;
410 auto status = provisionable_->generateCertificateRequest(
411 testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
412 &keysToSignMac);
413 EXPECT_FALSE(status.isOk());
414 EXPECT_EQ(status.getServiceSpecificError(),
415 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
416 }
417}
418
419/**
420 * Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
421 * Confirm that the request is rejected.
422 *
423 * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
424 * implementation is checking signatures.
425 */
426TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
427 bool testMode = false;
428 generateKeys(testMode, 4 /* numKeys */);
429
430 for (size_t ii = 0; ii < eekLength_; ii++) {
431 auto chain = corrupt_sig_chain(eekChain_, ii);
432 ASSERT_TRUE(chain) << chain.message();
433 EekChain corruptEek = chain.moveValue();
434
435 bytevec keysToSignMac;
436 DeviceInfo deviceInfo;
437 ProtectedData protectedData;
438 auto status = provisionable_->generateCertificateRequest(
439 testMode, keysToSign_, corruptEek.chain, challenge_, &deviceInfo, &protectedData,
440 &keysToSignMac);
441 ASSERT_FALSE(status.isOk());
442 ASSERT_EQ(status.getServiceSpecificError(),
443 BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
444 }
445}
446
447/**
448 * Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
449 * Confirm that the request is rejected.
450 *
451 * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
452 * implementation is checking signatures.
453 */
454TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
455 bool testMode = false;
456 generateKeys(testMode, 4 /* numKeys */);
457
458 // Build an EEK chain that omits the first self-signed cert.
459 auto truncatedChain = cppbor::Array();
460 auto [chain, _, parseErr] = cppbor::parse(eekChain_.chain);
461 ASSERT_TRUE(chain);
462 auto eekChain = chain->asArray();
463 ASSERT_NE(eekChain, nullptr);
464 for (size_t ii = 1; ii < eekChain->size(); ii++) {
465 truncatedChain.add(eekChain->get(ii)->clone());
466 }
467
Shawn Willden274bb552020-09-30 22:39:22 -0600468 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700469 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600470 ProtectedData protectedData;
David Drysdalecceca9f2021-03-12 15:49:47 +0000471 auto status = provisionable_->generateCertificateRequest(
472 testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
473 &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600474 ASSERT_FALSE(status.isOk());
475 ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
476}
477
478/**
479 * Generate a non-empty certificate request in test mode, with prod keys. Must fail with
480 * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
481 */
Max Bires126869a2021-02-21 18:32:59 -0800482TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600483 generateKeys(false /* testMode */, 2 /* numKeys */);
484
485 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700486 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600487 ProtectedData protectedData;
Max Biresfdbb9042021-03-23 12:43:38 -0700488 auto status = provisionable_->generateCertificateRequest(
David Drysdalec8400772021-03-11 12:35:11 +0000489 true /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
Max Biresfdbb9042021-03-23 12:43:38 -0700490 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600491 ASSERT_FALSE(status.isOk());
492 ASSERT_EQ(status.getServiceSpecificError(),
493 BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
494}
495
496/**
497 * Generate a non-empty certificate request in prod mode, with test keys. Must fail with
498 * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
499 */
Max Bires126869a2021-02-21 18:32:59 -0800500TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
Shawn Willden274bb552020-09-30 22:39:22 -0600501 generateKeys(true /* testMode */, 2 /* numKeys */);
502
503 bytevec keysToSignMac;
Max Biresfdbb9042021-03-23 12:43:38 -0700504 DeviceInfo deviceInfo;
Shawn Willden274bb552020-09-30 22:39:22 -0600505 ProtectedData protectedData;
506 auto status = provisionable_->generateCertificateRequest(
David Drysdalec8400772021-03-11 12:35:11 +0000507 false /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
508 &protectedData, &keysToSignMac);
Shawn Willden274bb552020-09-30 22:39:22 -0600509 ASSERT_FALSE(status.isOk());
510 ASSERT_EQ(status.getServiceSpecificError(),
511 BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
512}
513
514INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
515
516} // namespace aidl::android::hardware::security::keymint::test