1 /*
2 * Copyright (c) 2019, 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 #include <iterator>
18 #include <memory>
19 #include <set>
20 #include <string>
21 #include <tuple>
22 #include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h"
23
24 #include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
25 #include <android-base/macros.h>
26 #include <android-base/properties.h>
27 #include <cppbor.h>
28 #include <hwtrust/hwtrust.h>
29 #include <json/json.h>
30 #include <keymaster/km_openssl/ec_key.h>
31 #include <keymaster/km_openssl/ecdsa_operation.h>
32 #include <keymaster/km_openssl/openssl_err.h>
33 #include <keymaster/km_openssl/openssl_utils.h>
34 #include <openssl/base64.h>
35 #include <openssl/evp.h>
36 #include <openssl/rand.h>
37 #include <openssl/x509.h>
38 #include <remote_prov/remote_prov_utils.h>
39
40 namespace aidl::android::hardware::security::keymint::remote_prov {
41
42 constexpr uint32_t kBccPayloadIssuer = 1;
43 constexpr uint32_t kBccPayloadSubject = 2;
44 constexpr int32_t kBccPayloadSubjPubKey = -4670552;
45 constexpr int32_t kBccPayloadKeyUsage = -4670553;
46 constexpr int kP256AffinePointSize = 32;
47 constexpr uint32_t kNumTeeDeviceInfoEntries = 14;
48
49 using EC_KEY_Ptr = bssl::UniquePtr<EC_KEY>;
50 using EVP_PKEY_Ptr = bssl::UniquePtr<EVP_PKEY>;
51 using EVP_PKEY_CTX_Ptr = bssl::UniquePtr<EVP_PKEY_CTX>;
52 using X509_Ptr = bssl::UniquePtr<X509>;
53 using CRYPTO_BUFFER_Ptr = bssl::UniquePtr<CRYPTO_BUFFER>;
54
ecKeyGetPrivateKey(const EC_KEY * ecKey)55 ErrMsgOr<bytevec> ecKeyGetPrivateKey(const EC_KEY* ecKey) {
56 // Extract private key.
57 const BIGNUM* bignum = EC_KEY_get0_private_key(ecKey);
58 if (bignum == nullptr) {
59 return "Error getting bignum from private key";
60 }
61 // Pad with zeros in case the length is lesser than 32.
62 bytevec privKey(32, 0);
63 BN_bn2binpad(bignum, privKey.data(), privKey.size());
64 return privKey;
65 }
66
ecKeyGetPublicKey(const EC_KEY * ecKey)67 ErrMsgOr<bytevec> ecKeyGetPublicKey(const EC_KEY* ecKey) {
68 // Extract public key.
69 auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
70 if (group.get() == nullptr) {
71 return "Error creating EC group by curve name";
72 }
73 const EC_POINT* point = EC_KEY_get0_public_key(ecKey);
74 if (point == nullptr) return "Error getting ecpoint from public key";
75
76 int size =
77 EC_POINT_point2oct(group.get(), point, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
78 if (size == 0) {
79 return "Error generating public key encoding";
80 }
81
82 bytevec publicKey;
83 publicKey.resize(size);
84 EC_POINT_point2oct(group.get(), point, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(),
85 publicKey.size(), nullptr);
86 return publicKey;
87 }
88
getAffineCoordinates(const bytevec & pubKey)89 ErrMsgOr<std::tuple<bytevec, bytevec>> getAffineCoordinates(const bytevec& pubKey) {
90 auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
91 if (group.get() == nullptr) {
92 return "Error creating EC group by curve name";
93 }
94 auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
95 if (EC_POINT_oct2point(group.get(), point.get(), pubKey.data(), pubKey.size(), nullptr) != 1) {
96 return "Error decoding publicKey";
97 }
98 BIGNUM_Ptr x(BN_new());
99 BIGNUM_Ptr y(BN_new());
100 BN_CTX_Ptr ctx(BN_CTX_new());
101 if (!ctx.get()) return "Failed to create BN_CTX instance";
102
103 if (!EC_POINT_get_affine_coordinates_GFp(group.get(), point.get(), x.get(), y.get(),
104 ctx.get())) {
105 return "Failed to get affine coordinates from ECPoint";
106 }
107 bytevec pubX(kP256AffinePointSize);
108 bytevec pubY(kP256AffinePointSize);
109 if (BN_bn2binpad(x.get(), pubX.data(), kP256AffinePointSize) != kP256AffinePointSize) {
110 return "Error in converting absolute value of x coordinate to big-endian";
111 }
112 if (BN_bn2binpad(y.get(), pubY.data(), kP256AffinePointSize) != kP256AffinePointSize) {
113 return "Error in converting absolute value of y coordinate to big-endian";
114 }
115 return std::make_tuple(std::move(pubX), std::move(pubY));
116 }
117
getRawPublicKey(const EVP_PKEY_Ptr & pubKey)118 ErrMsgOr<bytevec> getRawPublicKey(const EVP_PKEY_Ptr& pubKey) {
119 if (pubKey.get() == nullptr) {
120 return "pkey is null.";
121 }
122 int keyType = EVP_PKEY_base_id(pubKey.get());
123 switch (keyType) {
124 case EVP_PKEY_EC: {
125 auto ecKey = EC_KEY_Ptr(EVP_PKEY_get1_EC_KEY(pubKey.get()));
126 if (ecKey.get() == nullptr) {
127 return "Failed to get ec key";
128 }
129 return ecKeyGetPublicKey(ecKey.get());
130 }
131 case EVP_PKEY_ED25519: {
132 bytevec rawPubKey;
133 size_t rawKeySize = 0;
134 if (!EVP_PKEY_get_raw_public_key(pubKey.get(), NULL, &rawKeySize)) {
135 return "Failed to get raw public key.";
136 }
137 rawPubKey.resize(rawKeySize);
138 if (!EVP_PKEY_get_raw_public_key(pubKey.get(), rawPubKey.data(), &rawKeySize)) {
139 return "Failed to get raw public key.";
140 }
141 return rawPubKey;
142 }
143 default:
144 return "Unknown key type.";
145 }
146 }
147
generateEc256KeyPair()148 ErrMsgOr<std::tuple<bytevec, bytevec>> generateEc256KeyPair() {
149 auto ec_key = EC_KEY_Ptr(EC_KEY_new());
150 if (ec_key.get() == nullptr) {
151 return "Failed to allocate ec key";
152 }
153
154 auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
155 if (group.get() == nullptr) {
156 return "Error creating EC group by curve name";
157 }
158
159 if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
160 EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
161 return "Error generating key";
162 }
163
164 auto privKey = ecKeyGetPrivateKey(ec_key.get());
165 if (!privKey) return privKey.moveMessage();
166
167 auto pubKey = ecKeyGetPublicKey(ec_key.get());
168 if (!pubKey) return pubKey.moveMessage();
169
170 return std::make_tuple(pubKey.moveValue(), privKey.moveValue());
171 }
172
generateX25519KeyPair()173 ErrMsgOr<std::tuple<bytevec, bytevec>> generateX25519KeyPair() {
174 /* Generate X25519 key pair */
175 bytevec pubKey(X25519_PUBLIC_VALUE_LEN);
176 bytevec privKey(X25519_PRIVATE_KEY_LEN);
177 X25519_keypair(pubKey.data(), privKey.data());
178 return std::make_tuple(std::move(pubKey), std::move(privKey));
179 }
180
generateED25519KeyPair()181 ErrMsgOr<std::tuple<bytevec, bytevec>> generateED25519KeyPair() {
182 /* Generate ED25519 key pair */
183 bytevec pubKey(ED25519_PUBLIC_KEY_LEN);
184 bytevec privKey(ED25519_PRIVATE_KEY_LEN);
185 ED25519_keypair(pubKey.data(), privKey.data());
186 return std::make_tuple(std::move(pubKey), std::move(privKey));
187 }
188
generateKeyPair(int32_t supportedEekCurve,bool isEek)189 ErrMsgOr<std::tuple<bytevec, bytevec>> generateKeyPair(int32_t supportedEekCurve, bool isEek) {
190 switch (supportedEekCurve) {
191 case RpcHardwareInfo::CURVE_25519:
192 if (isEek) {
193 return generateX25519KeyPair();
194 }
195 return generateED25519KeyPair();
196 case RpcHardwareInfo::CURVE_P256:
197 return generateEc256KeyPair();
198 default:
199 return "Unknown EEK Curve.";
200 }
201 }
202
constructCoseKey(int32_t supportedEekCurve,const bytevec & eekId,const bytevec & pubKey)203 ErrMsgOr<bytevec> constructCoseKey(int32_t supportedEekCurve, const bytevec& eekId,
204 const bytevec& pubKey) {
205 CoseKeyType keyType;
206 CoseKeyAlgorithm algorithm;
207 CoseKeyCurve curve;
208 bytevec pubX;
209 bytevec pubY;
210 switch (supportedEekCurve) {
211 case RpcHardwareInfo::CURVE_25519:
212 keyType = OCTET_KEY_PAIR;
213 algorithm = (eekId.empty()) ? EDDSA : ECDH_ES_HKDF_256;
214 curve = (eekId.empty()) ? ED25519 : cppcose::X25519;
215 pubX = pubKey;
216 break;
217 case RpcHardwareInfo::CURVE_P256: {
218 keyType = EC2;
219 algorithm = (eekId.empty()) ? ES256 : ECDH_ES_HKDF_256;
220 curve = P256;
221 auto affineCoordinates = getAffineCoordinates(pubKey);
222 if (!affineCoordinates) return affineCoordinates.moveMessage();
223 std::tie(pubX, pubY) = affineCoordinates.moveValue();
224 } break;
225 default:
226 return "Unknown EEK Curve.";
227 }
228 cppbor::Map coseKey = cppbor::Map()
229 .add(CoseKey::KEY_TYPE, keyType)
230 .add(CoseKey::ALGORITHM, algorithm)
231 .add(CoseKey::CURVE, curve)
232 .add(CoseKey::PUBKEY_X, pubX);
233
234 if (!pubY.empty()) coseKey.add(CoseKey::PUBKEY_Y, pubY);
235 if (!eekId.empty()) coseKey.add(CoseKey::KEY_ID, eekId);
236
237 return coseKey.canonicalize().encode();
238 }
239
240 bytevec kTestMacKey(32 /* count */, 0 /* byte value */);
241
randomBytes(size_t numBytes)242 bytevec randomBytes(size_t numBytes) {
243 bytevec retval(numBytes);
244 RAND_bytes(retval.data(), numBytes);
245 return retval;
246 }
247
constructCoseSign1(int32_t supportedEekCurve,const bytevec & key,const bytevec & payload,const bytevec & aad)248 ErrMsgOr<cppbor::Array> constructCoseSign1(int32_t supportedEekCurve, const bytevec& key,
249 const bytevec& payload, const bytevec& aad) {
250 if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
251 return constructECDSACoseSign1(key, {} /* protectedParams */, payload, aad);
252 } else {
253 return cppcose::constructCoseSign1(key, payload, aad);
254 }
255 }
256
generateEekChain(int32_t supportedEekCurve,size_t length,const bytevec & eekId)257 ErrMsgOr<EekChain> generateEekChain(int32_t supportedEekCurve, size_t length,
258 const bytevec& eekId) {
259 if (length < 2) {
260 return "EEK chain must contain at least 2 certs.";
261 }
262
263 auto eekChain = cppbor::Array();
264
265 bytevec prev_priv_key;
266 for (size_t i = 0; i < length - 1; ++i) {
267 auto keyPair = generateKeyPair(supportedEekCurve, false);
268 if (!keyPair) return keyPair.moveMessage();
269 auto [pub_key, priv_key] = keyPair.moveValue();
270
271 // The first signing key is self-signed.
272 if (prev_priv_key.empty()) prev_priv_key = priv_key;
273
274 auto coseKey = constructCoseKey(supportedEekCurve, {}, pub_key);
275 if (!coseKey) return coseKey.moveMessage();
276
277 auto coseSign1 =
278 constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), {} /* AAD */);
279 if (!coseSign1) return coseSign1.moveMessage();
280 eekChain.add(coseSign1.moveValue());
281
282 prev_priv_key = priv_key;
283 }
284 auto keyPair = generateKeyPair(supportedEekCurve, true);
285 if (!keyPair) return keyPair.moveMessage();
286 auto [pub_key, priv_key] = keyPair.moveValue();
287
288 auto coseKey = constructCoseKey(supportedEekCurve, eekId, pub_key);
289 if (!coseKey) return coseKey.moveMessage();
290
291 auto coseSign1 =
292 constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), {} /* AAD */);
293 if (!coseSign1) return coseSign1.moveMessage();
294 eekChain.add(coseSign1.moveValue());
295
296 if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
297 // convert ec public key to x and y co-ordinates.
298 auto affineCoordinates = getAffineCoordinates(pub_key);
299 if (!affineCoordinates) return affineCoordinates.moveMessage();
300 auto [pubX, pubY] = affineCoordinates.moveValue();
301 pub_key.clear();
302 pub_key.insert(pub_key.begin(), pubX.begin(), pubX.end());
303 pub_key.insert(pub_key.end(), pubY.begin(), pubY.end());
304 }
305
306 return EekChain{eekChain.encode(), pub_key, priv_key};
307 }
308
getProdEekChain(int32_t supportedEekCurve)309 bytevec getProdEekChain(int32_t supportedEekCurve) {
310 cppbor::Array chain;
311 if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
312 chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsa256RootCert),
313 std::end(kCoseEncodedEcdsa256RootCert))));
314 chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsa256GeekCert),
315 std::end(kCoseEncodedEcdsa256GeekCert))));
316 } else {
317 chain.add(cppbor::EncodedItem(
318 bytevec(std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert))));
319 chain.add(cppbor::EncodedItem(
320 bytevec(std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert))));
321 }
322 return chain.encode();
323 }
324
validateBcc(const cppbor::Array * bcc,hwtrust::DiceChain::Kind kind)325 ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc,
326 hwtrust::DiceChain::Kind kind) {
327 auto encodedBcc = bcc->encode();
328 auto chain = hwtrust::DiceChain::Verify(encodedBcc, kind);
329 if (!chain.ok()) return chain.error().message();
330 auto keys = chain->CosePublicKeys();
331 if (!keys.ok()) return keys.error().message();
332 std::vector<BccEntryData> result;
333 for (auto& key : *keys) {
334 result.push_back({std::move(key)});
335 }
336 return result;
337 }
338
jsonEncodeCsrWithBuild(const std::string instance_name,const cppbor::Array & csr)339 JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name, const cppbor::Array& csr) {
340 const std::string kFingerprintProp = "ro.build.fingerprint";
341 const std::string kSerialNoProp = "ro.serialno";
342
343 if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) {
344 return JsonOutput::Error("Unable to read build fingerprint");
345 }
346
347 bytevec csrCbor = csr.encode();
348 size_t base64Length;
349 int rc = EVP_EncodedLength(&base64Length, csrCbor.size());
350 if (!rc) {
351 return JsonOutput::Error("Error getting base64 length. Size overflow?");
352 }
353
354 std::vector<char> base64(base64Length);
355 rc = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(base64.data()), csrCbor.data(), csrCbor.size());
356 ++rc; // Account for NUL, which BoringSSL does not for some reason.
357 if (rc != base64Length) {
358 return JsonOutput::Error("Error writing base64. Expected " + std::to_string(base64Length) +
359 " bytes to be written, but " + std::to_string(rc) +
360 " bytes were actually written.");
361 }
362
363 Json::Value json(Json::objectValue);
364 json["name"] = instance_name;
365 json["build_fingerprint"] = ::android::base::GetProperty(kFingerprintProp, /*default=*/"");
366 json["serialno"] = ::android::base::GetProperty(kSerialNoProp, /*default=*/"");
367 json["csr"] = base64.data(); // Boring writes a NUL-terminated c-string
368
369 Json::StreamWriterBuilder factory;
370 factory["indentation"] = ""; // disable pretty formatting
371 return JsonOutput::Ok(Json::writeString(factory, json));
372 }
373
checkMapEntry(bool isFactory,const cppbor::Map & devInfo,cppbor::MajorType majorType,const std::string & entryName)374 std::string checkMapEntry(bool isFactory, const cppbor::Map& devInfo, cppbor::MajorType majorType,
375 const std::string& entryName) {
376 const std::unique_ptr<cppbor::Item>& val = devInfo.get(entryName);
377 if (!val) {
378 return entryName + " is missing.\n";
379 }
380 if (val->type() != majorType) {
381 return entryName + " has the wrong type.\n";
382 }
383 if (isFactory) {
384 return "";
385 }
386 switch (majorType) {
387 case cppbor::TSTR:
388 if (val->asTstr()->value().size() <= 0) {
389 return entryName + " is present but the value is empty.\n";
390 }
391 break;
392 case cppbor::BSTR:
393 if (val->asBstr()->value().size() <= 0) {
394 return entryName + " is present but the value is empty.\n";
395 }
396 break;
397 default:
398 break;
399 }
400 return "";
401 }
402
checkMapEntry(bool isFactory,const cppbor::Map & devInfo,cppbor::MajorType majorType,const std::string & entryName,const cppbor::Array & allowList)403 std::string checkMapEntry(bool isFactory, const cppbor::Map& devInfo, cppbor::MajorType majorType,
404 const std::string& entryName, const cppbor::Array& allowList) {
405 std::string error = checkMapEntry(isFactory, devInfo, majorType, entryName);
406 if (!error.empty()) {
407 return error;
408 }
409
410 if (isFactory) {
411 return "";
412 }
413
414 const std::unique_ptr<cppbor::Item>& val = devInfo.get(entryName);
415 for (auto i = allowList.begin(); i != allowList.end(); ++i) {
416 if (**i == *val) {
417 return "";
418 }
419 }
420 return entryName + " has an invalid value.\n";
421 }
422
isTeeDeviceInfo(const cppbor::Map & devInfo)423 bool isTeeDeviceInfo(const cppbor::Map& devInfo) {
424 return devInfo.get("security_level") && devInfo.get("security_level")->asTstr() &&
425 devInfo.get("security_level")->asTstr()->value() == "tee";
426 }
427
parseAndValidateDeviceInfo(const std::vector<uint8_t> & deviceInfoBytes,IRemotelyProvisionedComponent * provisionable,bool isFactory)428 ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateDeviceInfo(
429 const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable,
430 bool isFactory) {
431 const cppbor::Array kValidVbStates = {"green", "yellow", "orange"};
432 const cppbor::Array kValidBootloaderStates = {"locked", "unlocked"};
433 const cppbor::Array kValidSecurityLevels = {"tee", "strongbox"};
434 const cppbor::Array kValidAttIdStates = {"locked", "open"};
435 const cppbor::Array kValidFused = {0, 1};
436 constexpr std::array<std::string_view, kNumTeeDeviceInfoEntries> kDeviceInfoKeys = {
437 "brand",
438 "manufacturer",
439 "product",
440 "model",
441 "device",
442 "vb_state",
443 "bootloader_state",
444 "vbmeta_digest",
445 "os_version",
446 "system_patch_level",
447 "boot_patch_level",
448 "vendor_patch_level",
449 "security_level",
450 "fused"};
451
452 struct AttestationIdEntry {
453 const char* id;
454 bool alwaysValidate;
455 };
456 constexpr AttestationIdEntry kAttestationIdEntrySet[] = {{"brand", false},
457 {"manufacturer", true},
458 {"product", false},
459 {"model", false},
460 {"device", false}};
461
462 auto [parsedVerifiedDeviceInfo, ignore1, errMsg] = cppbor::parse(deviceInfoBytes);
463 if (!parsedVerifiedDeviceInfo) {
464 return errMsg;
465 }
466
467 std::unique_ptr<cppbor::Map> parsed(parsedVerifiedDeviceInfo.release()->asMap());
468 if (!parsed) {
469 return "DeviceInfo must be a CBOR map.";
470 }
471
472 if (parsed->clone()->asMap()->canonicalize().encode() != deviceInfoBytes) {
473 return "DeviceInfo ordering is non-canonical.";
474 }
475
476 RpcHardwareInfo info;
477 provisionable->getHardwareInfo(&info);
478 if (info.versionNumber < 3) {
479 const std::unique_ptr<cppbor::Item>& version = parsed->get("version");
480 if (!version) {
481 return "Device info is missing version";
482 }
483 if (!version->asUint()) {
484 return "version must be an unsigned integer";
485 }
486 if (version->asUint()->value() != info.versionNumber) {
487 return "DeviceInfo version (" + std::to_string(version->asUint()->value()) +
488 ") does not match the remotely provisioned component version (" +
489 std::to_string(info.versionNumber) + ").";
490 }
491 }
492
493 std::string error;
494 std::string tmp;
495 std::set<std::string_view> previousKeys;
496 switch (info.versionNumber) {
497 case 3:
498 if (isTeeDeviceInfo(*parsed) && parsed->size() != kNumTeeDeviceInfoEntries) {
499 error += fmt::format(
500 "Err: Incorrect number of device info entries. Expected {} but got "
501 "{}\n",
502 kNumTeeDeviceInfoEntries, parsed->size());
503 }
504 // TEE IRPC instances require all entries to be present in DeviceInfo. Non-TEE instances
505 // may omit `os_version`
506 if (!isTeeDeviceInfo(*parsed) && (parsed->size() != kNumTeeDeviceInfoEntries &&
507 parsed->size() != kNumTeeDeviceInfoEntries - 1)) {
508 error += fmt::format(
509 "Err: Incorrect number of device info entries. Expected {} or {} but got "
510 "{}\n",
511 kNumTeeDeviceInfoEntries - 1, kNumTeeDeviceInfoEntries, parsed->size());
512 }
513 for (auto& [key, _] : *parsed) {
514 const std::string& keyValue = key->asTstr()->value();
515 if (!previousKeys.insert(keyValue).second) {
516 error += "Err: Duplicate device info entry: <" + keyValue + ">,\n";
517 }
518 if (std::find(kDeviceInfoKeys.begin(), kDeviceInfoKeys.end(), keyValue) ==
519 kDeviceInfoKeys.end()) {
520 error += "Err: Unrecognized key entry: <" + key->asTstr()->value() + ">,\n";
521 }
522 }
523 FALLTHROUGH_INTENDED;
524 case 2:
525 for (const auto& entry : kAttestationIdEntrySet) {
526 tmp = checkMapEntry(isFactory && !entry.alwaysValidate, *parsed, cppbor::TSTR,
527 entry.id);
528 }
529 if (!tmp.empty()) {
530 error += tmp +
531 "Attestation IDs are missing or malprovisioned. If this test is being\n"
532 "run against an early proto or EVT build, this error is probably WAI\n"
533 "and indicates that Device IDs were not provisioned in the factory. If\n"
534 "this error is returned on a DVT or later build revision, then\n"
535 "something is likely wrong with the factory provisioning process.";
536 }
537 // TODO: Refactor the KeyMint code that validates these fields and include it here.
538 error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "vb_state", kValidVbStates);
539 error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "bootloader_state",
540 kValidBootloaderStates);
541 error += checkMapEntry(isFactory, *parsed, cppbor::BSTR, "vbmeta_digest");
542 error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "system_patch_level");
543 error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "boot_patch_level");
544 error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "vendor_patch_level");
545 error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "fused", kValidFused);
546 error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "security_level",
547 kValidSecurityLevels);
548 if (isTeeDeviceInfo(*parsed)) {
549 error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "os_version");
550 }
551 break;
552 case 1:
553 error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "security_level",
554 kValidSecurityLevels);
555 error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "att_id_state",
556 kValidAttIdStates);
557 break;
558 default:
559 return "Unrecognized version: " + std::to_string(info.versionNumber);
560 }
561
562 if (!error.empty()) {
563 return error;
564 }
565
566 return std::move(parsed);
567 }
568
parseAndValidateFactoryDeviceInfo(const std::vector<uint8_t> & deviceInfoBytes,IRemotelyProvisionedComponent * provisionable)569 ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateFactoryDeviceInfo(
570 const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable) {
571 return parseAndValidateDeviceInfo(deviceInfoBytes, provisionable, /*isFactory=*/true);
572 }
573
parseAndValidateProductionDeviceInfo(const std::vector<uint8_t> & deviceInfoBytes,IRemotelyProvisionedComponent * provisionable)574 ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateProductionDeviceInfo(
575 const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable) {
576 return parseAndValidateDeviceInfo(deviceInfoBytes, provisionable, /*isFactory=*/false);
577 }
578
getSessionKey(ErrMsgOr<std::pair<bytevec,bytevec>> & senderPubkey,const EekChain & eekChain,int32_t supportedEekCurve)579 ErrMsgOr<bytevec> getSessionKey(ErrMsgOr<std::pair<bytevec, bytevec>>& senderPubkey,
580 const EekChain& eekChain, int32_t supportedEekCurve) {
581 if (supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
582 supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
583 return x25519_HKDF_DeriveKey(eekChain.last_pubkey, eekChain.last_privkey,
584 senderPubkey->first, false /* senderIsA */);
585 } else {
586 return ECDH_HKDF_DeriveKey(eekChain.last_pubkey, eekChain.last_privkey, senderPubkey->first,
587 false /* senderIsA */);
588 }
589 }
590
verifyProtectedData(const DeviceInfo & deviceInfo,const cppbor::Array & keysToSign,const std::vector<uint8_t> & keysToSignMac,const ProtectedData & protectedData,const EekChain & eekChain,const std::vector<uint8_t> & eekId,int32_t supportedEekCurve,IRemotelyProvisionedComponent * provisionable,const std::vector<uint8_t> & challenge,bool isFactory)591 ErrMsgOr<std::vector<BccEntryData>> verifyProtectedData(
592 const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
593 const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
594 const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
595 IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge,
596 bool isFactory) {
597 auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
598 if (!parsedProtectedData) {
599 return protDataErrMsg;
600 }
601 if (!parsedProtectedData->asArray()) {
602 return "Protected data is not a CBOR array.";
603 }
604 if (parsedProtectedData->asArray()->size() != kCoseEncryptEntryCount) {
605 return "The protected data COSE_encrypt structure must have " +
606 std::to_string(kCoseEncryptEntryCount) + " entries, but it only has " +
607 std::to_string(parsedProtectedData->asArray()->size());
608 }
609
610 auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
611 if (!senderPubkey) {
612 return senderPubkey.message();
613 }
614 if (senderPubkey->second != eekId) {
615 return "The COSE_encrypt recipient does not match the expected EEK identifier";
616 }
617
618 auto sessionKey = getSessionKey(senderPubkey, eekChain, supportedEekCurve);
619 if (!sessionKey) {
620 return sessionKey.message();
621 }
622
623 auto protectedDataPayload =
624 decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
625 if (!protectedDataPayload) {
626 return protectedDataPayload.message();
627 }
628
629 auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
630 if (!parsedPayload) {
631 return "Failed to parse payload: " + payloadErrMsg;
632 }
633 if (!parsedPayload->asArray()) {
634 return "The protected data payload must be an Array.";
635 }
636 if (parsedPayload->asArray()->size() != 3U && parsedPayload->asArray()->size() != 2U) {
637 return "The protected data payload must contain SignedMAC and BCC. It may optionally "
638 "contain AdditionalDKSignatures. However, the parsed payload has " +
639 std::to_string(parsedPayload->asArray()->size()) + " entries.";
640 }
641
642 auto& signedMac = parsedPayload->asArray()->get(0);
643 auto& bcc = parsedPayload->asArray()->get(1);
644 if (!signedMac->asArray()) {
645 return "The SignedMAC in the protected data payload is not an Array.";
646 }
647 if (!bcc->asArray()) {
648 return "The BCC in the protected data payload is not an Array.";
649 }
650
651 // BCC is [ pubkey, + BccEntry]
652 auto bccContents = validateBcc(bcc->asArray(), hwtrust::DiceChain::Kind::kVsr13);
653 if (!bccContents) {
654 return bccContents.message() + "\n" + prettyPrint(bcc.get());
655 }
656
657 auto deviceInfoResult =
658 parseAndValidateDeviceInfo(deviceInfo.deviceInfo, provisionable, isFactory);
659 if (!deviceInfoResult) {
660 return deviceInfoResult.message();
661 }
662 std::unique_ptr<cppbor::Map> deviceInfoMap = deviceInfoResult.moveValue();
663 auto& signingKey = bccContents->back().pubKey;
664 auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
665 cppbor::Array() // SignedMacAad
666 .add(challenge)
667 .add(std::move(deviceInfoMap))
668 .add(keysToSignMac)
669 .encode());
670 if (!macKey) {
671 return macKey.message();
672 }
673
674 auto coseMac0 = cppbor::Array()
675 .add(cppbor::Map() // protected
676 .add(ALGORITHM, HMAC_256)
677 .canonicalize()
678 .encode())
679 .add(cppbor::Map()) // unprotected
680 .add(keysToSign.encode()) // payload (keysToSign)
681 .add(keysToSignMac); // tag
682
683 auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
684 if (!macPayload) {
685 return macPayload.message();
686 }
687
688 return *bccContents;
689 }
690
verifyFactoryProtectedData(const DeviceInfo & deviceInfo,const cppbor::Array & keysToSign,const std::vector<uint8_t> & keysToSignMac,const ProtectedData & protectedData,const EekChain & eekChain,const std::vector<uint8_t> & eekId,int32_t supportedEekCurve,IRemotelyProvisionedComponent * provisionable,const std::vector<uint8_t> & challenge)691 ErrMsgOr<std::vector<BccEntryData>> verifyFactoryProtectedData(
692 const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
693 const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
694 const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
695 IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
696 return verifyProtectedData(deviceInfo, keysToSign, keysToSignMac, protectedData, eekChain,
697 eekId, supportedEekCurve, provisionable, challenge,
698 /*isFactory=*/true);
699 }
700
verifyProductionProtectedData(const DeviceInfo & deviceInfo,const cppbor::Array & keysToSign,const std::vector<uint8_t> & keysToSignMac,const ProtectedData & protectedData,const EekChain & eekChain,const std::vector<uint8_t> & eekId,int32_t supportedEekCurve,IRemotelyProvisionedComponent * provisionable,const std::vector<uint8_t> & challenge)701 ErrMsgOr<std::vector<BccEntryData>> verifyProductionProtectedData(
702 const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
703 const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
704 const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
705 IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
706 return verifyProtectedData(deviceInfo, keysToSign, keysToSignMac, protectedData, eekChain,
707 eekId, supportedEekCurve, provisionable, challenge,
708 /*isFactory=*/false);
709 }
710
parseX509Cert(const std::vector<uint8_t> & cert)711 ErrMsgOr<X509_Ptr> parseX509Cert(const std::vector<uint8_t>& cert) {
712 CRYPTO_BUFFER_Ptr certBuf(CRYPTO_BUFFER_new(cert.data(), cert.size(), nullptr));
713 if (!certBuf.get()) {
714 return "Failed to create crypto buffer.";
715 }
716 X509_Ptr result(X509_parse_from_buffer(certBuf.get()));
717 if (!result.get()) {
718 return "Failed to parse certificate.";
719 }
720 return result;
721 }
722
getX509IssuerName(const X509_Ptr & cert)723 std::string getX509IssuerName(const X509_Ptr& cert) {
724 char* name = X509_NAME_oneline(X509_get_issuer_name(cert.get()), nullptr, 0);
725 std::string result(name);
726 OPENSSL_free(name);
727 return result;
728 }
729
getX509SubjectName(const X509_Ptr & cert)730 std::string getX509SubjectName(const X509_Ptr& cert) {
731 char* name = X509_NAME_oneline(X509_get_subject_name(cert.get()), nullptr, 0);
732 std::string result(name);
733 OPENSSL_free(name);
734 return result;
735 }
736
737 // Validates the certificate chain and returns the leaf public key.
validateCertChain(const cppbor::Array & chain)738 ErrMsgOr<bytevec> validateCertChain(const cppbor::Array& chain) {
739 bytevec rawPubKey;
740 for (size_t i = 0; i < chain.size(); ++i) {
741 // Root must be self-signed.
742 size_t signingCertIndex = (i > 0) ? i - 1 : i;
743 auto& keyCertItem = chain[i];
744 auto& signingCertItem = chain[signingCertIndex];
745 if (!keyCertItem || !keyCertItem->asBstr()) {
746 return "Key certificate must be a Bstr.";
747 }
748 if (!signingCertItem || !signingCertItem->asBstr()) {
749 return "Signing certificate must be a Bstr.";
750 }
751
752 auto keyCert = parseX509Cert(keyCertItem->asBstr()->value());
753 if (!keyCert) {
754 return keyCert.message();
755 }
756 auto signingCert = parseX509Cert(signingCertItem->asBstr()->value());
757 if (!signingCert) {
758 return signingCert.message();
759 }
760
761 EVP_PKEY_Ptr pubKey(X509_get_pubkey(keyCert->get()));
762 if (!pubKey.get()) {
763 return "Failed to get public key.";
764 }
765 EVP_PKEY_Ptr signingPubKey(X509_get_pubkey(signingCert->get()));
766 if (!signingPubKey.get()) {
767 return "Failed to get signing public key.";
768 }
769
770 if (!X509_verify(keyCert->get(), signingPubKey.get())) {
771 return "Verification of certificate " + std::to_string(i) +
772 " faile. OpenSSL error string: " + ERR_error_string(ERR_get_error(), NULL);
773 }
774
775 auto certIssuer = getX509IssuerName(*keyCert);
776 auto signerSubj = getX509SubjectName(*signingCert);
777 if (certIssuer != signerSubj) {
778 return "Certificate " + std::to_string(i) + " has wrong issuer. Signer subject is " +
779 signerSubj + " Issuer subject is " + certIssuer;
780 }
781 if (i == chain.size() - 1) {
782 auto key = getRawPublicKey(pubKey);
783 if (!key) key.moveMessage();
784 rawPubKey = key.moveValue();
785 }
786 }
787 return rawPubKey;
788 }
789
validateUdsCerts(const cppbor::Map & udsCerts,const bytevec & udsCoseKeyBytes)790 std::string validateUdsCerts(const cppbor::Map& udsCerts, const bytevec& udsCoseKeyBytes) {
791 for (const auto& [signerName, udsCertChain] : udsCerts) {
792 if (!signerName || !signerName->asTstr()) {
793 return "Signer Name must be a Tstr.";
794 }
795 if (!udsCertChain || !udsCertChain->asArray()) {
796 return "UDS certificate chain must be an Array.";
797 }
798 if (udsCertChain->asArray()->size() < 2) {
799 return "UDS certificate chain must have at least two entries: root and leaf.";
800 }
801
802 auto leafPubKey = validateCertChain(*udsCertChain->asArray());
803 if (!leafPubKey) {
804 return leafPubKey.message();
805 }
806 auto coseKey = CoseKey::parse(udsCoseKeyBytes);
807 if (!coseKey) return coseKey.moveMessage();
808
809 auto curve = coseKey->getIntValue(CoseKey::CURVE);
810 if (!curve) {
811 return "CoseKey must contain curve.";
812 }
813 bytevec udsPub;
814 if (curve == CoseKeyCurve::P256 || curve == CoseKeyCurve::P384) {
815 auto pubKey = coseKey->getEcPublicKey();
816 if (!pubKey) return pubKey.moveMessage();
817 // convert public key to uncompressed form by prepending 0x04 at begin.
818 pubKey->insert(pubKey->begin(), 0x04);
819 udsPub = pubKey.moveValue();
820 } else if (curve == CoseKeyCurve::ED25519) {
821 auto& pubkey = coseKey->getMap().get(cppcose::CoseKey::PUBKEY_X);
822 if (!pubkey || !pubkey->asBstr()) {
823 return "Invalid public key.";
824 }
825 udsPub = pubkey->asBstr()->value();
826 } else {
827 return "Unknown curve.";
828 }
829 if (*leafPubKey != udsPub) {
830 return "Leaf public key in UDS certificate chain doesn't match UDS public key.";
831 }
832 }
833 return "";
834 }
835
parseAndValidateCsrPayload(const cppbor::Array & keysToSign,const std::vector<uint8_t> & csrPayload,IRemotelyProvisionedComponent * provisionable,bool isFactory)836 ErrMsgOr<std::unique_ptr<cppbor::Array>> parseAndValidateCsrPayload(
837 const cppbor::Array& keysToSign, const std::vector<uint8_t>& csrPayload,
838 IRemotelyProvisionedComponent* provisionable, bool isFactory) {
839 auto [parsedCsrPayload, _, errMsg] = cppbor::parse(csrPayload);
840 if (!parsedCsrPayload) {
841 return errMsg;
842 }
843
844 std::unique_ptr<cppbor::Array> parsed(parsedCsrPayload.release()->asArray());
845 if (!parsed) {
846 return "CSR payload is not a CBOR array.";
847 }
848
849 if (parsed->size() != 4U) {
850 return "CSR payload must contain version, certificate type, device info, keys. "
851 "However, the parsed CSR payload has " +
852 std::to_string(parsed->size()) + " entries.";
853 }
854
855 auto signedVersion = parsed->get(0)->asUint();
856 auto signedCertificateType = parsed->get(1)->asTstr();
857 auto signedDeviceInfo = parsed->get(2)->asMap();
858 auto signedKeys = parsed->get(3)->asArray();
859
860 if (!signedVersion || signedVersion->value() != 3U) {
861 return "CSR payload version must be an unsigned integer and must be equal to 3.";
862 }
863 if (!signedCertificateType) {
864 // Certificate type is allowed to be extendend by vendor, i.e. we can't
865 // enforce its value.
866 return "Certificate type must be a Tstr.";
867 }
868 if (!signedDeviceInfo) {
869 return "Device info must be an Map.";
870 }
871 if (!signedKeys) {
872 return "Keys must be an Array.";
873 }
874
875 auto result = parseAndValidateDeviceInfo(signedDeviceInfo->encode(), provisionable, isFactory);
876 if (!result) {
877 return result.message();
878 }
879
880 if (signedKeys->encode() != keysToSign.encode()) {
881 return "Signed keys do not match.";
882 }
883
884 return std::move(parsed);
885 }
886
parseAndValidateAuthenticatedRequestSignedPayload(const std::vector<uint8_t> & signedPayload,const std::vector<uint8_t> & challenge)887 ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequestSignedPayload(
888 const std::vector<uint8_t>& signedPayload, const std::vector<uint8_t>& challenge) {
889 auto [parsedSignedPayload, _, errMsg] = cppbor::parse(signedPayload);
890 if (!parsedSignedPayload) {
891 return errMsg;
892 }
893 if (!parsedSignedPayload->asArray()) {
894 return "SignedData payload is not a CBOR array.";
895 }
896 if (parsedSignedPayload->asArray()->size() != 2U) {
897 return "SignedData payload must contain the challenge and request. However, the parsed "
898 "SignedData payload has " +
899 std::to_string(parsedSignedPayload->asArray()->size()) + " entries.";
900 }
901
902 auto signedChallenge = parsedSignedPayload->asArray()->get(0)->asBstr();
903 auto signedRequest = parsedSignedPayload->asArray()->get(1)->asBstr();
904
905 if (!signedChallenge) {
906 return "Challenge must be a Bstr.";
907 }
908
909 if (challenge.size() > 64) {
910 return "Challenge size must be between 0 and 64 bytes inclusive. "
911 "However, challenge is " +
912 std::to_string(challenge.size()) + " bytes long.";
913 }
914
915 auto challengeBstr = cppbor::Bstr(challenge);
916 if (*signedChallenge != challengeBstr) {
917 return "Signed challenge does not match."
918 "\n Actual: " +
919 cppbor::prettyPrint(signedChallenge->asBstr(), 64 /* maxBStrSize */) +
920 "\nExpected: " + cppbor::prettyPrint(&challengeBstr, 64 /* maxBStrSize */);
921 }
922
923 if (!signedRequest) {
924 return "Request must be a Bstr.";
925 }
926
927 return signedRequest->value();
928 }
929
parseAndValidateAuthenticatedRequest(const std::vector<uint8_t> & request,const std::vector<uint8_t> & challenge)930 ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequest(const std::vector<uint8_t>& request,
931 const std::vector<uint8_t>& challenge) {
932 auto [parsedRequest, _, csrErrMsg] = cppbor::parse(request);
933 if (!parsedRequest) {
934 return csrErrMsg;
935 }
936 if (!parsedRequest->asArray()) {
937 return "AuthenticatedRequest is not a CBOR array.";
938 }
939 if (parsedRequest->asArray()->size() != 4U) {
940 return "AuthenticatedRequest must contain version, UDS certificates, DICE chain, and "
941 "signed data. However, the parsed AuthenticatedRequest has " +
942 std::to_string(parsedRequest->asArray()->size()) + " entries.";
943 }
944
945 auto version = parsedRequest->asArray()->get(0)->asUint();
946 auto udsCerts = parsedRequest->asArray()->get(1)->asMap();
947 auto diceCertChain = parsedRequest->asArray()->get(2)->asArray();
948 auto signedData = parsedRequest->asArray()->get(3)->asArray();
949
950 if (!version || version->value() != 1U) {
951 return "AuthenticatedRequest version must be an unsigned integer and must be equal to 1.";
952 }
953 if (!udsCerts) {
954 return "AuthenticatedRequest UdsCerts must be an Map.";
955 }
956 if (!diceCertChain) {
957 return "AuthenticatedRequest DiceCertChain must be an Array.";
958 }
959 if (!signedData) {
960 return "AuthenticatedRequest SignedData must be an Array.";
961 }
962
963 // DICE chain is [ pubkey, + DiceChainEntry ].
964 auto diceContents = validateBcc(diceCertChain, hwtrust::DiceChain::Kind::kVsr14);
965 if (!diceContents) {
966 return diceContents.message() + "\n" + prettyPrint(diceCertChain);
967 }
968
969 auto& udsPub = diceContents->back().pubKey;
970
971 auto error = validateUdsCerts(*udsCerts, udsPub);
972 if (!error.empty()) {
973 return error;
974 }
975
976 auto signedPayload = verifyAndParseCoseSign1(signedData, udsPub, {} /* aad */);
977 if (!signedPayload) {
978 return signedPayload.message();
979 }
980
981 auto payload = parseAndValidateAuthenticatedRequestSignedPayload(*signedPayload, challenge);
982 if (!payload) {
983 return payload.message();
984 }
985
986 return payload;
987 }
988
verifyCsr(const cppbor::Array & keysToSign,const std::vector<uint8_t> & csr,IRemotelyProvisionedComponent * provisionable,const std::vector<uint8_t> & challenge,bool isFactory)989 ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyCsr(const cppbor::Array& keysToSign,
990 const std::vector<uint8_t>& csr,
991 IRemotelyProvisionedComponent* provisionable,
992 const std::vector<uint8_t>& challenge,
993 bool isFactory) {
994 RpcHardwareInfo info;
995 provisionable->getHardwareInfo(&info);
996 if (info.versionNumber != 3) {
997 return "Remotely provisioned component version (" + std::to_string(info.versionNumber) +
998 ") does not match expected version (3).";
999 }
1000
1001 auto csrPayload = parseAndValidateAuthenticatedRequest(csr, challenge);
1002 if (!csrPayload) {
1003 return csrPayload.message();
1004 }
1005
1006 return parseAndValidateCsrPayload(keysToSign, *csrPayload, provisionable, isFactory);
1007 }
1008
verifyFactoryCsr(const cppbor::Array & keysToSign,const std::vector<uint8_t> & csr,IRemotelyProvisionedComponent * provisionable,const std::vector<uint8_t> & challenge)1009 ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
1010 const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
1011 IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
1012 return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/true);
1013 }
1014
verifyProductionCsr(const cppbor::Array & keysToSign,const std::vector<uint8_t> & csr,IRemotelyProvisionedComponent * provisionable,const std::vector<uint8_t> & challenge)1015 ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
1016 const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
1017 IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
1018 return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/false);
1019 }
1020
1021 } // namespace aidl::android::hardware::security::keymint::remote_prov
1022