Merge changes I2f5187bf,Icb79e1e0,I833894d3,I54dcaa61,I47a810f2 am: b39baeaa92 am: 319cf92322 am: ab9655adc7

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1650253

Change-Id: I50251136a8ad421e3526bc44b81b195473f3de6e
This commit is contained in:
David Drysdale
2021-03-31 16:47:35 +00:00
committed by Automerger Merge Worker
11 changed files with 537 additions and 288 deletions

View File

@@ -202,7 +202,7 @@ interface IRemotelyProvisionedComponent {
* 2 : bstr // KID : EEK ID
* 3 : -25, // Algorithm : ECDH-ES + HKDF-256
* -1 : 4, // Curve : X25519
* -2 : bstr // Ed25519 public key
* -2 : bstr // X25519 public key
* }
*
* EekSignatureInput = [
@@ -221,7 +221,7 @@ interface IRemotelyProvisionedComponent {
* in the chain, which implies that it must not attempt to validate the signature.
*
* If testMode is false, the method must validate the chain signatures, and must verify
* that the public key in the root certifictate is in its pre-configured set of
* that the public key in the root certificate is in its pre-configured set of
* authorized EEK root keys. If the public key is not in the database, or if signature
* verification fails, the method must return STATUS_INVALID_EEK.
*

View File

@@ -26,7 +26,7 @@ parcelable MacedPublicKey {
/**
* key is a COSE_Mac0 structure containing the new public key. It's MACed by a key available
* only to the secure environment, as proof that the public key was generated by that
* environment. In CDDL, assuming the contained key is an Ed25519 public key:
* environment. In CDDL, assuming the contained key is a P-256 public key:
*
* MacedPublicKey = [ // COSE_Mac0
* protected: bstr .cbor { 1 : 5}, // Algorithm : HMAC-256
@@ -36,10 +36,11 @@ parcelable MacedPublicKey {
* ]
*
* PublicKey = { // COSE_Key
* 1 : 1, // Key type : octet key pair
* 3 : -8 // Algorithm : EdDSA
* -1 : 6, // Curve : Ed25519
* 1 : 2, // Key type : EC2
* 3 : -8 // Algorithm : ES256
* -1 : 6, // Curve : P256
* -2 : bstr // X coordinate, little-endian
* -3 : bstr // Y coordinate, little-endian
* ? -70000 : nil // Presence indicates this is a test key. If set, K_mac is
* // all zeros.
* },
@@ -51,7 +52,7 @@ parcelable MacedPublicKey {
* payload : bstr .cbor PublicKey
* ]
*
* if a non-Ed25519 public key were contained, the contents of the PublicKey map would change a
* if a non-P256 public key were contained, the contents of the PublicKey map would change a
* little; see RFC 8152 for details.
*/
byte[] macedKey;

View File

@@ -33,7 +33,7 @@ parcelable ProtectedData {
* unprotected: {
* 5 : bstr .size 12 // IV
* },
* ciphertext: bstr, // AES-GCM-128(K, .cbor ProtectedDataPayload)
* ciphertext: bstr, // AES-GCM-256(K, .cbor ProtectedDataPayload)
* recipients : [
* [ // COSE_Recipient
* protected : bstr .cbor {

View File

@@ -46,6 +46,14 @@ using namespace keymaster;
namespace {
// Hard-coded set of acceptable public keys that can act as roots of EEK chains.
inline const vector<bytevec> kAuthorizedEekRoots = {
// TODO(drysdale): replace this random value with real root pubkey(s).
{0x5c, 0xea, 0x4b, 0xd2, 0x31, 0x27, 0x15, 0x5e, 0x62, 0x94, 0x70,
0x53, 0x94, 0x43, 0x0f, 0x9a, 0x89, 0xd5, 0xc5, 0x0f, 0x82, 0x9b,
0xcd, 0x10, 0xe0, 0x79, 0xef, 0xf3, 0xfa, 0x40, 0xeb, 0x0a},
};
constexpr auto STATUS_FAILED = RemotelyProvisionedComponent::STATUS_FAILED;
constexpr auto STATUS_INVALID_EEK = RemotelyProvisionedComponent::STATUS_INVALID_EEK;
constexpr auto STATUS_INVALID_MAC = RemotelyProvisionedComponent::STATUS_INVALID_MAC;
@@ -135,6 +143,13 @@ StatusOr<std::pair<bytevec /* EEK pub */, bytevec /* EEK ID */>> validateAndExtr
"Failed to validate EEK chain: " + cosePubKey.moveMessage());
}
lastPubKey = *std::move(cosePubKey);
// In prod mode the first pubkey should match a well-known Google public key.
if (!testMode && i == 0 &&
std::find(kAuthorizedEekRoots.begin(), kAuthorizedEekRoots.end(), lastPubKey) ==
kAuthorizedEekRoots.end()) {
return Status(STATUS_INVALID_EEK, "Unrecognized root of EEK chain");
}
}
auto eek = CoseKey::parseX25519(lastPubKey, true /* requireKid */);
@@ -417,8 +432,8 @@ RemotelyProvisionedComponent::generateBcc() {
.add(1 /* Issuer */, "Issuer")
.add(2 /* Subject */, "Subject")
.add(-4670552 /* Subject Pub Key */, coseKey)
.add(-4670553 /* Key Usage */,
std::vector<uint8_t>(0x05) /* Big endian order */)
.add(-4670553 /* Key Usage (little-endian order) */,
std::vector<uint8_t>{0x20} /* keyCertSign = 1<<5 */)
.canonicalize()
.encode();
auto coseSign1 = constructCoseSign1(privKey, /* signing key */

View File

@@ -94,11 +94,14 @@ cc_test {
],
static_libs: [
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppcose",
"libgmock_ndk",
"libremote_provisioner",
"libkeymint",
"libkeymint_support",
"libkeymint_remote_prov_support",
"libkeymint_vts_test_utils",
"libremote_provisioner",
],
test_suites: [
"general-tests",

View File

@@ -26,29 +26,6 @@ namespace aidl::android::hardware::security::keymint::test {
namespace {
vector<uint8_t> make_name_from_str(const string& name) {
X509_NAME_Ptr x509_name(X509_NAME_new());
EXPECT_TRUE(x509_name.get() != nullptr);
if (!x509_name) return {};
EXPECT_EQ(1, X509_NAME_add_entry_by_txt(x509_name.get(), //
"CN", //
MBSTRING_ASC,
reinterpret_cast<const uint8_t*>(name.c_str()),
-1, // len
-1, // loc
0 /* set */));
int len = i2d_X509_NAME(x509_name.get(), nullptr /* only return length */);
EXPECT_GT(len, 0);
vector<uint8_t> retval(len);
uint8_t* p = retval.data();
i2d_X509_NAME(x509_name.get(), &p);
return retval;
}
bool IsSelfSigned(const vector<Certificate>& chain) {
if (chain.size() != 1) return false;
return ChainSignaturesAreValid(chain);

View File

@@ -811,30 +811,6 @@ const vector<KeyParameter>& KeyMintAidlTestBase::SecLevelAuthorizations(
return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations;
}
AuthorizationSet KeyMintAidlTestBase::HwEnforcedAuthorizations(
const vector<KeyCharacteristics>& key_characteristics) {
AuthorizationSet authList;
for (auto& entry : key_characteristics) {
if (entry.securityLevel == SecurityLevel::STRONGBOX ||
entry.securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT) {
authList.push_back(AuthorizationSet(entry.authorizations));
}
}
return authList;
}
AuthorizationSet KeyMintAidlTestBase::SwEnforcedAuthorizations(
const vector<KeyCharacteristics>& key_characteristics) {
AuthorizationSet authList;
for (auto& entry : key_characteristics) {
if (entry.securityLevel == SecurityLevel::SOFTWARE ||
entry.securityLevel == SecurityLevel::KEYSTORE) {
authList.push_back(AuthorizationSet(entry.authorizations));
}
}
return authList;
}
ErrorCode KeyMintAidlTestBase::UseAesKey(const vector<uint8_t>& aesKeyBlob) {
auto [result, ciphertext] = ProcessMessage(
aesKeyBlob, KeyPurpose::ENCRYPT, "1234567890123456",
@@ -1046,6 +1022,28 @@ string bin2hex(const vector<uint8_t>& data) {
return retval;
}
AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics) {
AuthorizationSet authList;
for (auto& entry : key_characteristics) {
if (entry.securityLevel == SecurityLevel::STRONGBOX ||
entry.securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT) {
authList.push_back(AuthorizationSet(entry.authorizations));
}
}
return authList;
}
AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics) {
AuthorizationSet authList;
for (auto& entry : key_characteristics) {
if (entry.securityLevel == SecurityLevel::SOFTWARE ||
entry.securityLevel == SecurityLevel::KEYSTORE) {
authList.push_back(AuthorizationSet(entry.authorizations));
}
}
return authList;
}
AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain) {
std::stringstream cert_data;
@@ -1097,6 +1095,29 @@ X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
}
vector<uint8_t> make_name_from_str(const string& name) {
X509_NAME_Ptr x509_name(X509_NAME_new());
EXPECT_TRUE(x509_name.get() != nullptr);
if (!x509_name) return {};
EXPECT_EQ(1, X509_NAME_add_entry_by_txt(x509_name.get(), //
"CN", //
MBSTRING_ASC,
reinterpret_cast<const uint8_t*>(name.c_str()),
-1, // len
-1, // loc
0 /* set */));
int len = i2d_X509_NAME(x509_name.get(), nullptr /* only return length */);
EXPECT_GT(len, 0);
vector<uint8_t> retval(len);
uint8_t* p = retval.data();
i2d_X509_NAME(x509_name.get(), &p);
return retval;
}
} // namespace test
} // namespace aidl::android::hardware::security::keymint

View File

@@ -252,10 +252,6 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
const vector<KeyParameter>& SecLevelAuthorizations(
const vector<KeyCharacteristics>& key_characteristics, SecurityLevel securityLevel);
AuthorizationSet HwEnforcedAuthorizations(
const vector<KeyCharacteristics>& key_characteristics);
AuthorizationSet SwEnforcedAuthorizations(
const vector<KeyCharacteristics>& key_characteristics);
ErrorCode UseAesKey(const vector<uint8_t>& aesKeyBlob);
ErrorCode UseHmacKey(const vector<uint8_t>& hmacKeyBlob);
ErrorCode UseRsaKey(const vector<uint8_t>& rsaKeyBlob);
@@ -280,6 +276,9 @@ bool verify_attestation_record(const string& challenge, //
const vector<uint8_t>& attestation_cert);
string bin2hex(const vector<uint8_t>& data);
X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
vector<uint8_t> make_name_from_str(const string& name);
AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain);
#define INSTANTIATE_KEYMINT_AIDL_TEST(name) \

View File

@@ -17,18 +17,21 @@
#define LOG_TAG "VtsRemotelyProvisionableComponentTests"
#include <RemotelyProvisionedComponent.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
#include <android/binder_manager.h>
#include <cppbor_parse.h>
#include <cppcose/cppcose.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <keymaster/keymaster_configuration.h>
#include <keymint_support/authorization_set.h>
#include <openssl/ec.h>
#include <openssl/ec_key.h>
#include <openssl/x509.h>
#include <remote_prov/remote_prov_utils.h>
#include "KeyMintAidlTestBase.h"
namespace aidl::android::hardware::security::keymint::test {
using ::std::string;
@@ -52,6 +55,190 @@ bytevec string_to_bytevec(const char* s) {
return bytevec(p, p + strlen(s));
}
void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey) {
// Extract x and y affine coordinates from the encoded Cose_Key.
auto [parsedPayload, __, payloadParseErr] = cppbor::parse(coseKeyData);
ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
auto coseKey = parsedPayload->asMap();
const std::unique_ptr<cppbor::Item>& xItem = coseKey->get(cppcose::CoseKey::PUBKEY_X);
ASSERT_NE(xItem->asBstr(), nullptr);
vector<uint8_t> x = xItem->asBstr()->value();
const std::unique_ptr<cppbor::Item>& yItem = coseKey->get(cppcose::CoseKey::PUBKEY_Y);
ASSERT_NE(yItem->asBstr(), nullptr);
vector<uint8_t> y = yItem->asBstr()->value();
// Concatenate: 0x04 (uncompressed form marker) | x | y
vector<uint8_t> pubKeyData{0x04};
pubKeyData.insert(pubKeyData.end(), x.begin(), x.end());
pubKeyData.insert(pubKeyData.end(), y.begin(), y.end());
EC_KEY_Ptr ecKey = EC_KEY_Ptr(EC_KEY_new());
ASSERT_NE(ecKey, nullptr);
EC_GROUP_Ptr group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
ASSERT_NE(group, nullptr);
ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
EC_POINT_Ptr point = EC_POINT_Ptr(EC_POINT_new(group.get()));
ASSERT_NE(point, nullptr);
ASSERT_EQ(EC_POINT_oct2point(group.get(), point.get(), pubKeyData.data(), pubKeyData.size(),
nullptr),
1);
ASSERT_EQ(EC_KEY_set_public_key(ecKey.get(), point.get()), 1);
EVP_PKEY_Ptr pubKey = EVP_PKEY_Ptr(EVP_PKEY_new());
ASSERT_NE(pubKey, nullptr);
EVP_PKEY_assign_EC_KEY(pubKey.get(), ecKey.release());
*signingKey = std::move(pubKey);
}
void check_cose_key(const vector<uint8_t>& data, bool testMode) {
auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
// The following check assumes that canonical CBOR encoding is used for the COSE_Key.
if (testMode) {
EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
MatchesRegex("{\n"
" 1 : 2,\n" // kty: EC2
" 3 : -7,\n" // alg: ES256
" -1 : 1,\n" // EC id: P256
// The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
// sequence of 32 hexadecimal bytes, enclosed in braces and
// separated by commas. In this case, some Ed25519 public key.
" -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
" -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
" -70000 : null,\n" // test marker
"}"));
} else {
EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
MatchesRegex("{\n"
" 1 : 2,\n" // kty: EC2
" 3 : -7,\n" // alg: ES256
" -1 : 1,\n" // EC id: P256
// The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
// sequence of 32 hexadecimal bytes, enclosed in braces and
// separated by commas. In this case, some Ed25519 public key.
" -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
" -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
"}"));
}
}
void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
vector<uint8_t>* payload_value) {
auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
ASSERT_NE(coseMac0->asArray(), nullptr);
ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
ASSERT_NE(protParms, nullptr);
// Header label:value of 'alg': HMAC-256
ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
ASSERT_NE(unprotParms, nullptr);
ASSERT_EQ(unprotParms->size(), 0);
// The payload is a bstr holding an encoded COSE_Key
auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
ASSERT_NE(payload, nullptr);
check_cose_key(payload->value(), testMode);
auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
ASSERT_TRUE(coseMac0Tag);
auto extractedTag = coseMac0Tag->value();
EXPECT_EQ(extractedTag.size(), 32U);
// Compare with tag generated with kTestMacKey. Should only match in test mode
auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
payload->value());
ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
if (testMode) {
EXPECT_EQ(*testTag, extractedTag);
} else {
EXPECT_NE(*testTag, extractedTag);
}
if (payload_value != nullptr) {
*payload_value = payload->value();
}
}
ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
return "COSE Mac0 parse failed";
}
auto protParams = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
auto unprotParams = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
auto tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
if (!protParams || !unprotParams || !payload || !tag) {
return "Invalid COSE_Sign1: missing content";
}
auto corruptMac0 = cppbor::Array();
corruptMac0.add(protParams->clone());
corruptMac0.add(unprotParams->clone());
corruptMac0.add(payload->clone());
vector<uint8_t> tagData = tag->value();
tagData[0] ^= 0x08;
tagData[tagData.size() - 1] ^= 0x80;
corruptMac0.add(cppbor::Bstr(tagData));
return MacedPublicKey{corruptMac0.encode()};
}
ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
if (coseSign1->size() != kCoseSign1EntryCount) {
return "Invalid COSE_Sign1, wrong entry count";
}
const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
if (!protectedParams || !unprotectedParams || !payload || !signature) {
return "Invalid COSE_Sign1: missing content";
}
auto corruptSig = cppbor::Array();
corruptSig.add(protectedParams->clone());
corruptSig.add(unprotectedParams->clone());
corruptSig.add(payload->clone());
vector<uint8_t> sigData = signature->value();
sigData[0] ^= 0x08;
corruptSig.add(cppbor::Bstr(sigData));
return std::move(corruptSig);
}
ErrMsgOr<EekChain> corrupt_sig_chain(const EekChain& eek, int which) {
auto [chain, _, parseErr] = cppbor::parse(eek.chain);
if (!chain || !chain->asArray()) {
return "EekChain parse failed";
}
cppbor::Array* eekChain = chain->asArray();
if (which >= eekChain->size()) {
return "selected sig out of range";
}
auto corruptChain = cppbor::Array();
for (int ii = 0; ii < eekChain->size(); ++ii) {
if (ii == which) {
auto sig = corrupt_sig(eekChain->get(which)->asArray());
if (!sig) {
return "Failed to build corrupted signature" + sig.moveMessage();
}
corruptChain.add(sig.moveValue());
} else {
corruptChain.add(eekChain->get(ii)->clone());
}
}
return EekChain{corruptChain.encode(), eek.last_pubkey, eek.last_privkey};
}
} // namespace
class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
@@ -78,7 +265,8 @@ using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
/**
* Generate and validate a production-mode key. MAC tag can't be verified.
* Generate and validate a production-mode key. MAC tag can't be verified, but
* the private key blob should be usable in KeyMint operations.
*/
TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
MacedPublicKey macedPubKey;
@@ -86,48 +274,59 @@ TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
bool testMode = false;
auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
ASSERT_TRUE(status.isOk());
vector<uint8_t> coseKeyData;
check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
AttestationKey attestKey;
attestKey.keyBlob = std::move(privateKeyBlob);
attestKey.issuerSubjectName = make_name_from_str("Android Keystore Key");
auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
// Also talk to an IKeyMintDevice.
// TODO: if there were multiple instances of IRemotelyProvisionedComponent and IKeyMintDevice,
// what should the correlation between them be?
vector<string> params = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
ASSERT_GT(params.size(), 0U);
ASSERT_TRUE(AServiceManager_isDeclared(params[0].c_str()));
::ndk::SpAIBinder binder(AServiceManager_waitForService(params[0].c_str()));
std::shared_ptr<IKeyMintDevice> keyMint = IKeyMintDevice::fromBinder(binder);
KeyMintHardwareInfo info;
ASSERT_TRUE(keyMint->getHardwareInfo(&info).isOk());
ASSERT_NE(coseMac0->asArray(), nullptr);
ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
// Generate an ECDSA key that is attested by the generated P256 keypair.
AuthorizationSet keyDesc = AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(256)
.AttestationChallenge("foo")
.AttestationApplicationId("bar")
.Digest(Digest::NONE)
.SetDefaultValidity();
KeyCreationResult creationResult;
auto result = keyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
ASSERT_TRUE(result.isOk());
vector<uint8_t> attested_key_blob = std::move(creationResult.keyBlob);
vector<KeyCharacteristics> attested_key_characteristics =
std::move(creationResult.keyCharacteristics);
vector<Certificate> attested_key_cert_chain = std::move(creationResult.certificateChain);
EXPECT_EQ(attested_key_cert_chain.size(), 1);
auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
ASSERT_NE(protParms, nullptr);
ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced,
info.securityLevel,
attested_key_cert_chain[0].encodedCertificate));
auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
ASSERT_NE(unprotParms, nullptr);
ASSERT_EQ(unprotParms->size(), 0);
// Attestation by itself is not valid (last entry is not self-signed).
EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
ASSERT_NE(payload, nullptr);
auto [parsedPayload, __, payloadParseErr] = cppbor::parse(payload->value());
ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
MatchesRegex("{\n"
" 1 : 2,\n"
" 3 : -7,\n"
" -1 : 1,\n"
// The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a sequence of
// 32 hexadecimal bytes, enclosed in braces and separated by commas.
// In this case, some Ed25519 public key.
" -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
" -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
"}"));
// The signature over the attested key should correspond to the P256 public key.
X509_Ptr key_cert(parse_cert_blob(attested_key_cert_chain[0].encodedCertificate));
ASSERT_TRUE(key_cert.get());
EVP_PKEY_Ptr signing_pubkey;
p256_pub_key(coseKeyData, &signing_pubkey);
ASSERT_TRUE(signing_pubkey.get());
auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
ASSERT_TRUE(coseMac0Tag);
auto extractedTag = coseMac0Tag->value();
EXPECT_EQ(extractedTag.size(), 32U);
// Compare with tag generated with kTestMacKey. Shouldn't match.
auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
payload->value());
ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
EXPECT_NE(*testTag, extractedTag);
ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
<< "Verification of attested certificate failed "
<< "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
}
/**
@@ -140,56 +339,20 @@ TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
ASSERT_TRUE(status.isOk());
auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
ASSERT_NE(coseMac0->asArray(), nullptr);
ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
ASSERT_NE(protParms, nullptr);
ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
ASSERT_NE(unprotParms, nullptr);
ASSERT_EQ(unprotParms->size(), 0);
auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
ASSERT_NE(payload, nullptr);
auto [parsedPayload, __, payloadParseErr] = cppbor::parse(payload->value());
ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
MatchesRegex("{\n"
" 1 : 2,\n"
" 3 : -7,\n"
" -1 : 1,\n"
// The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a sequence of
// 32 hexadecimal bytes, enclosed in braces and separated by commas.
// In this case, some Ed25519 public key.
" -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
" -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
" -70000 : null,\n"
"}"));
auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
ASSERT_TRUE(coseMac0);
auto extractedTag = coseMac0Tag->value();
EXPECT_EQ(extractedTag.size(), 32U);
// Compare with tag generated with kTestMacKey. Should match.
auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
payload->value());
ASSERT_TRUE(testTag) << testTag.message();
EXPECT_EQ(*testTag, extractedTag);
check_maced_pubkey(macedPubKey, testMode, nullptr);
}
class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
protected:
CertificateRequestTest() : eekId_(string_to_bytevec("eekid")) {
auto chain = generateEekChain(3, eekId_);
CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
generateEek(3);
}
void generateEek(size_t eekLength) {
auto chain = generateEekChain(eekLength, eekId_);
EXPECT_TRUE(chain) << chain.message();
if (chain) eekChain_ = chain.moveValue();
eekLength_ = eekLength;
}
void generateKeys(bool testMode, size_t numKeys) {
@@ -201,21 +364,71 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
ASSERT_TRUE(status.isOk()) << status.getMessage();
auto [parsedMacedKey, _, parseErr] = cppbor::parse(key.macedKey);
ASSERT_TRUE(parsedMacedKey) << "Failed parsing MACed key: " << parseErr;
ASSERT_TRUE(parsedMacedKey->asArray()) << "COSE_Mac0 not an array?";
ASSERT_EQ(parsedMacedKey->asArray()->size(), kCoseMac0EntryCount);
auto& payload = parsedMacedKey->asArray()->get(kCoseMac0Payload);
ASSERT_TRUE(payload);
ASSERT_TRUE(payload->asBstr());
cborKeysToSign_.add(cppbor::EncodedItem(payload->asBstr()->value()));
vector<uint8_t> payload_value;
check_maced_pubkey(key, testMode, &payload_value);
cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
}
}
void checkProtectedData(bool testMode, const cppbor::Array& keysToSign,
const bytevec& keysToSignMac, const ProtectedData& protectedData) {
auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
ASSERT_TRUE(parsedProtectedData->asArray());
ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
ASSERT_TRUE(senderPubkey) << senderPubkey.message();
EXPECT_EQ(senderPubkey->second, eekId_);
auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
senderPubkey->first, false /* senderIsA */);
ASSERT_TRUE(sessionKey) << sessionKey.message();
auto protectedDataPayload =
decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
ASSERT_TRUE(parsedPayload->asArray());
EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
auto& signedMac = parsedPayload->asArray()->get(0);
auto& bcc = parsedPayload->asArray()->get(1);
ASSERT_TRUE(signedMac && signedMac->asArray());
ASSERT_TRUE(bcc && bcc->asArray());
// BCC is [ pubkey, + BccEntry]
auto bccContents = validateBcc(bcc->asArray());
ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
ASSERT_GT(bccContents->size(), 0U);
auto& signingKey = bccContents->back().pubKey;
auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
cppbor::Array() // DeviceInfo
.add(challenge_)
.add(cppbor::Map())
.encode());
ASSERT_TRUE(macKey) << macKey.message();
auto coseMac0 = cppbor::Array()
.add(cppbor::Map() // protected
.add(ALGORITHM, HMAC_256)
.canonicalize()
.encode())
.add(cppbor::Map()) // unprotected
.add(keysToSign.encode()) // payload (keysToSign)
.add(keysToSignMac); // tag
auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
ASSERT_TRUE(macPayload) << macPayload.message();
}
bytevec eekId_;
size_t eekLength_;
EekChain eekChain_;
bytevec challenge_;
std::vector<MacedPublicKey> keysToSign_;
cppbor::Array cborKeysToSign_;
};
@@ -226,66 +439,20 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
*/
TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
bool testMode = true;
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto challenge = randomBytes(32);
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, eekChain_.chain, challenge, &deviceInfo, &protectedData,
&keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
for (size_t eekLength : {2, 3, 7}) {
SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
generateEek(eekLength);
auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
ASSERT_TRUE(parsedProtectedData->asArray());
ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
ASSERT_TRUE(senderPubkey) << senderPubkey.message();
EXPECT_EQ(senderPubkey->second, eekId_);
auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
senderPubkey->first, false /* senderIsA */);
ASSERT_TRUE(sessionKey) << sessionKey.message();
auto protectedDataPayload =
decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
ASSERT_TRUE(parsedPayload->asArray());
EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
auto& signedMac = parsedPayload->asArray()->get(0);
auto& bcc = parsedPayload->asArray()->get(1);
ASSERT_TRUE(signedMac && signedMac->asArray());
ASSERT_TRUE(bcc && bcc->asArray());
// BCC is [ pubkey, + BccEntry]
auto bccContents = validateBcc(bcc->asArray());
ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
ASSERT_GT(bccContents->size(), 0U);
auto& signingKey = bccContents->back().pubKey;
auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
cppbor::Array() // DeviceInfo
.add(challenge) //
.add(cppbor::Map())
.encode());
ASSERT_TRUE(macKey) << macKey.message();
auto coseMac0 = cppbor::Array()
.add(cppbor::Map() // protected
.add(ALGORITHM, HMAC_256)
.canonicalize()
.encode())
.add(cppbor::Map()) // unprotected
.add(cppbor::Array().encode()) // payload (keysToSign)
.add(std::move(keysToSignMac)); // tag
auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
ASSERT_TRUE(macPayload) << macPayload.message();
checkProtectedData(testMode, cppbor::Array(), keysToSignMac, protectedData);
}
}
/**
@@ -297,15 +464,20 @@ TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
*/
TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
bool testMode = false;
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto challenge = randomBytes(32);
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, eekChain_.chain, challenge, &deviceInfo, &protectedData,
&keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
for (size_t eekLength : {2, 3, 7}) {
SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
generateEek(eekLength);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(),
BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
}
}
/**
@@ -315,65 +487,20 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
bool testMode = true;
generateKeys(testMode, 4 /* numKeys */);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto challenge = randomBytes(32);
auto status = provisionable_->generateCertificateRequest(testMode, keysToSign_, eekChain_.chain,
challenge, &deviceInfo, &protectedData,
&keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
for (size_t eekLength : {2, 3, 7}) {
SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
generateEek(eekLength);
auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
ASSERT_TRUE(parsedProtectedData->asArray());
ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
ASSERT_TRUE(senderPubkey) << senderPubkey.message();
EXPECT_EQ(senderPubkey->second, eekId_);
auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
senderPubkey->first, false /* senderIsA */);
ASSERT_TRUE(sessionKey) << sessionKey.message();
auto protectedDataPayload =
decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
ASSERT_TRUE(parsedPayload->asArray());
EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
auto& signedMac = parsedPayload->asArray()->get(0);
auto& bcc = parsedPayload->asArray()->get(1);
ASSERT_TRUE(signedMac && signedMac->asArray());
ASSERT_TRUE(bcc);
auto bccContents = validateBcc(bcc->asArray());
ASSERT_TRUE(bccContents) << "\n" << prettyPrint(bcc.get());
ASSERT_GT(bccContents->size(), 0U);
auto& signingKey = bccContents->back().pubKey;
auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
cppbor::Array() // DeviceInfo
.add(challenge) //
.add(cppbor::Array())
.encode());
ASSERT_TRUE(macKey) << macKey.message();
auto coseMac0 = cppbor::Array()
.add(cppbor::Map() // protected
.add(ALGORITHM, HMAC_256)
.canonicalize()
.encode())
.add(cppbor::Map()) // unprotected
.add(cborKeysToSign_.encode()) // payload
.add(std::move(keysToSignMac)); // tag
auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
ASSERT_TRUE(macPayload) << macPayload.message();
checkProtectedData(testMode, cborKeysToSign_, keysToSignMac, protectedData);
}
}
/**
@@ -387,13 +514,117 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
bool testMode = false;
generateKeys(testMode, 4 /* numKeys */);
for (size_t eekLength : {2, 3, 7}) {
SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
generateEek(eekLength);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(),
BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
}
}
/**
* Generate a non-empty certificate request in test mode, but with the MAC corrupted on the keypair.
*/
TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
bool testMode = true;
generateKeys(testMode, 1 /* numKeys */);
MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto challenge = randomBytes(32);
auto status = provisionable_->generateCertificateRequest(testMode, keysToSign_, eekChain_.chain,
challenge, &deviceInfo, &protectedData,
&keysToSignMac);
auto status = provisionable_->generateCertificateRequest(
testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
ASSERT_FALSE(status.isOk()) << status.getMessage();
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
/**
* Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
*/
TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
bool testMode = true;
generateKeys(testMode, 1 /* numKeys */);
MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
ASSERT_FALSE(status.isOk()) << status.getMessage();
auto rc = status.getServiceSpecificError();
// TODO(drysdale): drop the INVALID_EEK potential error code when a real GEEK is available.
EXPECT_TRUE(rc == BnRemotelyProvisionedComponent::STATUS_INVALID_EEK ||
rc == BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
/**
* Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
* Confirm that the request is rejected.
*
* TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
* implementation is checking signatures.
*/
TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
bool testMode = false;
generateKeys(testMode, 4 /* numKeys */);
for (size_t ii = 0; ii < eekLength_; ii++) {
auto chain = corrupt_sig_chain(eekChain_, ii);
ASSERT_TRUE(chain) << chain.message();
EekChain corruptEek = chain.moveValue();
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, keysToSign_, corruptEek.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(),
BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
}
}
/**
* Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
* Confirm that the request is rejected.
*
* TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
* implementation is checking signatures.
*/
TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
bool testMode = false;
generateKeys(testMode, 4 /* numKeys */);
// Build an EEK chain that omits the first self-signed cert.
auto truncatedChain = cppbor::Array();
auto [chain, _, parseErr] = cppbor::parse(eekChain_.chain);
ASSERT_TRUE(chain);
auto eekChain = chain->asArray();
ASSERT_NE(eekChain, nullptr);
for (size_t ii = 1; ii < eekChain->size(); ii++) {
truncatedChain.add(eekChain->get(ii)->clone());
}
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
}
@@ -408,9 +639,8 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto challenge = randomBytes(32);
auto status = provisionable_->generateCertificateRequest(
true /* testMode */, keysToSign_, eekChain_.chain, challenge, &deviceInfo,
true /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(),
@@ -428,8 +658,8 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
false /* testMode */, keysToSign_, eekChain_.chain, randomBytes(32) /* challenge */,
&deviceInfo, &protectedData, &keysToSignMac);
false /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(),
BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);

View File

@@ -37,6 +37,7 @@ MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT)
MAKE_OPENSSL_PTR_TYPE(BN_CTX)
MAKE_OPENSSL_PTR_TYPE(EC_GROUP)
MAKE_OPENSSL_PTR_TYPE(EC_KEY)
MAKE_OPENSSL_PTR_TYPE(EC_POINT)
MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
MAKE_OPENSSL_PTR_TYPE(EVP_PKEY_CTX)
MAKE_OPENSSL_PTR_TYPE(RSA)

View File

@@ -54,6 +54,8 @@ ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {
{} /* AAD */);
if (!coseSign1) return coseSign1.moveMessage();
eekChain.add(coseSign1.moveValue());
prev_priv_key = priv_key;
}
bytevec pub_key(X25519_PUBLIC_VALUE_LEN);