Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df05e411 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Support for P256 curve in RKP for Strongbox Test: Run Rkp Vts tests."...

Merge "Support for P256 curve in RKP for Strongbox Test: Run Rkp Vts tests." am: 55419fd9 am: 3b6c35b9

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

Change-Id: I517ed2fda53174956f477e54b84235e98d913140
parents 77a0eb6d 3b6c35b9
Loading
Loading
Loading
Loading
+29 −14
Original line number Original line Diff line number Diff line
@@ -185,6 +185,7 @@ class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::
            provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
            provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
        }
        }
        ASSERT_NE(provisionable_, nullptr);
        ASSERT_NE(provisionable_, nullptr);
        ASSERT_TRUE(provisionable_->getHardwareInfo(&rpcHardwareInfo).isOk());
    }
    }


    static vector<string> build_params() {
    static vector<string> build_params() {
@@ -194,6 +195,7 @@ class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::


  protected:
  protected:
    std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
    std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
    RpcHardwareInfo rpcHardwareInfo;
};
};


/**
/**
@@ -357,11 +359,10 @@ TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
  protected:
  protected:
    CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
    CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
        generateTestEekChain(3);
    }
    }


    void generateTestEekChain(size_t eekLength) {
    void generateTestEekChain(size_t eekLength) {
        auto chain = generateEekChain(eekLength, eekId_);
        auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
        EXPECT_TRUE(chain) << chain.message();
        EXPECT_TRUE(chain) << chain.message();
        if (chain) testEekChain_ = chain.moveValue();
        if (chain) testEekChain_ = chain.moveValue();
        testEekLength_ = eekLength;
        testEekLength_ = eekLength;
@@ -382,6 +383,17 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
        }
        }
    }
    }


    ErrMsgOr<bytevec> getSessionKey(ErrMsgOr<std::pair<bytevec, bytevec>>& senderPubkey) {
        if (rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
            rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
            return x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
                                         senderPubkey->first, false /* senderIsA */);
        } else {
            return ECDH_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
                                       senderPubkey->first, false /* senderIsA */);
        }
    }

    void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
    void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
                            const bytevec& keysToSignMac, const ProtectedData& protectedData,
                            const bytevec& keysToSignMac, const ProtectedData& protectedData,
                            std::vector<BccEntryData>* bccOutput = nullptr) {
                            std::vector<BccEntryData>* bccOutput = nullptr) {
@@ -394,9 +406,7 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
        ASSERT_TRUE(senderPubkey) << senderPubkey.message();
        ASSERT_TRUE(senderPubkey) << senderPubkey.message();
        EXPECT_EQ(senderPubkey->second, eekId_);
        EXPECT_EQ(senderPubkey->second, eekId_);


        auto sessionKey =
        auto sessionKey = getSessionKey(senderPubkey);
                x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
                                      senderPubkey->first, false /* senderIsA */);
        ASSERT_TRUE(sessionKey) << sessionKey.message();
        ASSERT_TRUE(sessionKey) << sessionKey.message();


        auto protectedDataPayload =
        auto protectedDataPayload =
@@ -406,7 +416,8 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
        auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
        auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
        ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
        ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
        ASSERT_TRUE(parsedPayload->asArray());
        ASSERT_TRUE(parsedPayload->asArray());
        EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
        // Strongbox may contain additional certificate chain.
        EXPECT_LE(parsedPayload->asArray()->size(), 3U);


        auto& signedMac = parsedPayload->asArray()->get(0);
        auto& signedMac = parsedPayload->asArray()->get(0);
        auto& bcc = parsedPayload->asArray()->get(1);
        auto& bcc = parsedPayload->asArray()->get(1);
@@ -566,6 +577,7 @@ TEST_P(CertificateRequestTest, NewKeyPerCallInTestMode) {
    bytevec keysToSignMac;
    bytevec keysToSignMac;
    DeviceInfo deviceInfo;
    DeviceInfo deviceInfo;
    ProtectedData protectedData;
    ProtectedData protectedData;
    generateTestEekChain(3);
    auto status = provisionable_->generateCertificateRequest(
    auto status = provisionable_->generateCertificateRequest(
            testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
            testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
            &protectedData, &keysToSignMac);
            &protectedData, &keysToSignMac);
@@ -605,8 +617,8 @@ TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
    DeviceInfo deviceInfo;
    DeviceInfo deviceInfo;
    ProtectedData protectedData;
    ProtectedData protectedData;
    auto status = provisionable_->generateCertificateRequest(
    auto status = provisionable_->generateCertificateRequest(
            testMode, {} /* keysToSign */, getProdEekChain(), challenge_, &deviceInfo,
            testMode, {} /* keysToSign */, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
            &protectedData, &keysToSignMac);
            challenge_, &deviceInfo, &protectedData, &keysToSignMac);
    EXPECT_TRUE(status.isOk());
    EXPECT_TRUE(status.isOk());
}
}


@@ -646,8 +658,8 @@ TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
    DeviceInfo deviceInfo;
    DeviceInfo deviceInfo;
    ProtectedData protectedData;
    ProtectedData protectedData;
    auto status = provisionable_->generateCertificateRequest(
    auto status = provisionable_->generateCertificateRequest(
            testMode, keysToSign_, getProdEekChain(), challenge_, &deviceInfo, &protectedData,
            testMode, keysToSign_, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_,
            &keysToSignMac);
            &deviceInfo, &protectedData, &keysToSignMac);
    EXPECT_TRUE(status.isOk());
    EXPECT_TRUE(status.isOk());
}
}


@@ -662,6 +674,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
    bytevec keysToSignMac;
    bytevec keysToSignMac;
    DeviceInfo deviceInfo;
    DeviceInfo deviceInfo;
    ProtectedData protectedData;
    ProtectedData protectedData;
    generateTestEekChain(3);
    auto status = provisionable_->generateCertificateRequest(
    auto status = provisionable_->generateCertificateRequest(
            testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
            testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
            &protectedData, &keysToSignMac);
            &protectedData, &keysToSignMac);
@@ -681,8 +694,8 @@ TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
    DeviceInfo deviceInfo;
    DeviceInfo deviceInfo;
    ProtectedData protectedData;
    ProtectedData protectedData;
    auto status = provisionable_->generateCertificateRequest(
    auto status = provisionable_->generateCertificateRequest(
            testMode, {keyWithCorruptMac}, getProdEekChain(), challenge_, &deviceInfo,
            testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
            &protectedData, &keysToSignMac);
            challenge_, &deviceInfo, &protectedData, &keysToSignMac);
    ASSERT_FALSE(status.isOk()) << status.getMessage();
    ASSERT_FALSE(status.isOk()) << status.getMessage();
    EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
    EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
}
@@ -695,7 +708,7 @@ TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
    bool testMode = false;
    bool testMode = false;
    generateKeys(testMode, 4 /* numKeys */);
    generateKeys(testMode, 4 /* numKeys */);


    auto prodEekChain = getProdEekChain();
    auto prodEekChain = getProdEekChain(rpcHardwareInfo.supportedEekCurve);
    auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
    auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
    ASSERT_NE(parsedChain, nullptr) << parseErr;
    ASSERT_NE(parsedChain, nullptr) << parseErr;
    ASSERT_NE(parsedChain->asArray(), nullptr);
    ASSERT_NE(parsedChain->asArray(), nullptr);
@@ -726,7 +739,7 @@ TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {


    // Build an EEK chain that omits the first self-signed cert.
    // Build an EEK chain that omits the first self-signed cert.
    auto truncatedChain = cppbor::Array();
    auto truncatedChain = cppbor::Array();
    auto [chain, _, parseErr] = cppbor::parse(getProdEekChain());
    auto [chain, _, parseErr] = cppbor::parse(getProdEekChain(rpcHardwareInfo.supportedEekCurve));
    ASSERT_TRUE(chain);
    ASSERT_TRUE(chain);
    auto eekChain = chain->asArray();
    auto eekChain = chain->asArray();
    ASSERT_NE(eekChain, nullptr);
    ASSERT_NE(eekChain, nullptr);
@@ -754,6 +767,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
    bytevec keysToSignMac;
    bytevec keysToSignMac;
    DeviceInfo deviceInfo;
    DeviceInfo deviceInfo;
    ProtectedData protectedData;
    ProtectedData protectedData;
    generateTestEekChain(3);
    auto status = provisionable_->generateCertificateRequest(
    auto status = provisionable_->generateCertificateRequest(
            true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
            true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
            &protectedData, &keysToSignMac);
            &protectedData, &keysToSignMac);
@@ -772,6 +786,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
    bytevec keysToSignMac;
    bytevec keysToSignMac;
    DeviceInfo deviceInfo;
    DeviceInfo deviceInfo;
    ProtectedData protectedData;
    ProtectedData protectedData;
    generateTestEekChain(3);
    auto status = provisionable_->generateCertificateRequest(
    auto status = provisionable_->generateCertificateRequest(
            false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
            false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
            &protectedData, &keysToSignMac);
            &protectedData, &keysToSignMac);
+7 −0
Original line number Original line Diff line number Diff line
@@ -60,11 +60,15 @@ cc_library {
    export_include_dirs: [
    export_include_dirs: [
        "include",
        "include",
    ],
    ],
    defaults: [
        "keymint_use_latest_hal_aidl_ndk_shared",
    ],
    shared_libs: [
    shared_libs: [
        "libbase",
        "libbase",
        "libcppbor_external",
        "libcppbor_external",
        "libcppcose_rkp",
        "libcppcose_rkp",
        "libcrypto",
        "libcrypto",
        "libkeymaster_portable",
        "libjsoncpp",
        "libjsoncpp",
    ],
    ],
}
}
@@ -76,6 +80,9 @@ cc_test {
        "libgmock",
        "libgmock",
        "libgtest_main",
        "libgtest_main",
    ],
    ],
    defaults: [
        "keymint_use_latest_hal_aidl_ndk_shared",
    ],
    shared_libs: [
    shared_libs: [
        "libbase",
        "libbase",
        "libcppbor_external",
        "libcppbor_external",
+32 −4
Original line number Original line Diff line number Diff line
@@ -52,6 +52,34 @@ inline constexpr uint8_t kCoseEncodedGeekCert[] = {
        0x31, 0xbf, 0x6b, 0xe8, 0x1e, 0x35, 0xe2, 0xf0, 0x2d, 0xce, 0x6c, 0x2f, 0x4f, 0xf2,
        0x31, 0xbf, 0x6b, 0xe8, 0x1e, 0x35, 0xe2, 0xf0, 0x2d, 0xce, 0x6c, 0x2f, 0x4f, 0xf2,
        0xf5, 0x4f, 0xa5, 0xd4, 0x83, 0xad, 0x96, 0xa2, 0xf1, 0x87, 0x58, 0x04};
        0xf5, 0x4f, 0xa5, 0xd4, 0x83, 0xad, 0x96, 0xa2, 0xf1, 0x87, 0x58, 0x04};


// The Google ECDSA P256 root key for the Endpoint Encryption Key chain, encoded as COSE_Sign1
inline constexpr uint8_t kCoseEncodedEcdsa256RootCert[] = {
    0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21,
    0x58, 0x20, 0xf7, 0x14, 0x8a, 0xdb, 0x97, 0xf4, 0xcc, 0x53, 0xef, 0xd2, 0x64, 0x11, 0xc4, 0xe3,
    0x75, 0x1f, 0x66, 0x1f, 0xa4, 0x71, 0x0c, 0x6c, 0xcf, 0xfa, 0x09, 0x46, 0x80, 0x74, 0x87, 0x54,
    0xf2, 0xad, 0x22, 0x58, 0x20, 0x5e, 0x7f, 0x5b, 0xf6, 0xec, 0xe4, 0xf6, 0x19, 0xcc, 0xff, 0x13,
    0x37, 0xfd, 0x0f, 0xa1, 0xc8, 0x93, 0xdb, 0x18, 0x06, 0x76, 0xc4, 0x5d, 0xe6, 0xd7, 0x6a, 0x77,
    0x86, 0xc3, 0x2d, 0xaf, 0x8f, 0x58, 0x40, 0x2f, 0x97, 0x8e, 0x42, 0xfb, 0xbe, 0x07, 0x2d, 0x95,
    0x47, 0x85, 0x47, 0x93, 0x40, 0xb0, 0x1f, 0xd4, 0x9b, 0x47, 0xa4, 0xc4, 0x44, 0xa9, 0xf2, 0xa1,
    0x07, 0x87, 0x10, 0xc7, 0x9f, 0xcb, 0x11, 0xf4, 0xbf, 0x9f, 0xe8, 0x3b, 0xe0, 0xe7, 0x34, 0x4c,
    0x15, 0xfc, 0x7b, 0xc3, 0x7e, 0x33, 0x05, 0xf4, 0xd1, 0x34, 0x3c, 0xed, 0x02, 0x04, 0x60, 0x7a,
    0x15, 0xe0, 0x79, 0xd3, 0x8a, 0xff, 0x24};

// The Google ECDSA P256 Endpoint Encryption Key certificate, encoded as COSE_Sign1
inline constexpr uint8_t kCoseEncodedEcdsa256GeekCert[] = {
    0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x58, 0x71, 0xa6, 0x01, 0x02, 0x02, 0x58, 0x20, 0x35, 0x73,
    0xb7, 0x3f, 0xa0, 0x8a, 0x80, 0x89, 0xb1, 0x26, 0x67, 0xe9, 0xcb, 0x7c, 0x75, 0xa1, 0xaf, 0x02,
    0x61, 0xfc, 0x6e, 0x65, 0x03, 0x91, 0x3b, 0xd3, 0x4b, 0x7d, 0x14, 0x94, 0x3e, 0x46, 0x03, 0x38,
    0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0xe0, 0x41, 0xcf, 0x2f, 0x0f, 0x34, 0x0f, 0x1c, 0x33, 0x2c,
    0x41, 0xb0, 0xcf, 0xd7, 0x0c, 0x30, 0x55, 0x35, 0xd2, 0x1e, 0x6a, 0x47, 0x13, 0x4b, 0x2e, 0xd1,
    0x48, 0x96, 0x7e, 0x24, 0x9c, 0x68, 0x22, 0x58, 0x20, 0x1f, 0xce, 0x45, 0xc5, 0xfb, 0x61, 0xba,
    0x81, 0x21, 0xf9, 0xe5, 0x05, 0x9b, 0x9b, 0x39, 0x0e, 0x76, 0x86, 0x86, 0x47, 0xb8, 0x1e, 0x2f,
    0x45, 0xf1, 0xce, 0xaf, 0xda, 0x3f, 0x80, 0x68, 0xdb, 0x58, 0x40, 0x8c, 0xb3, 0xba, 0x7e, 0x20,
    0x3e, 0x32, 0xb0, 0x68, 0xdf, 0x60, 0xd1, 0x1d, 0x7d, 0xf0, 0xac, 0x38, 0x8e, 0x51, 0xbc, 0xff,
    0x6c, 0xe1, 0x67, 0x3b, 0x4a, 0x79, 0xbc, 0x56, 0x78, 0xb3, 0x99, 0xd8, 0x7c, 0x8a, 0x07, 0xd8,
    0xda, 0xb5, 0xb5, 0x7f, 0x71, 0xf4, 0xd8, 0x6b, 0xdf, 0x33, 0x27, 0x34, 0x7b, 0x65, 0xd1, 0x2a,
    0xeb, 0x86, 0x99, 0x98, 0xab, 0x3a, 0xb4, 0x80, 0xaa, 0xbd, 0x50};

/**
/**
 * Generates random bytes.
 * Generates random bytes.
 */
 */
@@ -64,15 +92,15 @@ struct EekChain {
};
};


/**
/**
 * Generates an X25518 EEK with the specified eekId and an Ed25519 chain of the
 * Based on the supportedEekCurve, Generates an X25519/ECDH with the specified eekId
 * specified length. All keys are generated randomly.
 * and an Ed25519/ECDSA chain of the specified length. All keys are generated randomly.
 */
 */
ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId);
ErrMsgOr<EekChain> generateEekChain(int32_t supportedEekCurve, size_t length, const bytevec& eekId);


/**
/**
 * Returns the CBOR-encoded, production Google Endpoint Encryption Key chain.
 * Returns the CBOR-encoded, production Google Endpoint Encryption Key chain.
 */
 */
bytevec getProdEekChain();
bytevec getProdEekChain(int32_t supportedEekCurve);


struct BccEntryData {
struct BccEntryData {
    bytevec pubKey;
    bytevec pubKey;
+247 −46
Original line number Original line Diff line number Diff line
@@ -17,10 +17,16 @@
#include <iterator>
#include <iterator>
#include <tuple>
#include <tuple>


#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
#include <android-base/properties.h>
#include <android-base/properties.h>
#include <cppbor.h>
#include <cppbor.h>
#include <json/json.h>
#include <json/json.h>
#include <keymaster/km_openssl/ec_key.h>
#include <keymaster/km_openssl/ecdsa_operation.h>
#include <keymaster/km_openssl/openssl_err.h>
#include <keymaster/km_openssl/openssl_utils.h>
#include <openssl/base64.h>
#include <openssl/base64.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/rand.h>
#include <remote_prov/remote_prov_utils.h>
#include <remote_prov/remote_prov_utils.h>


@@ -30,6 +36,166 @@ constexpr uint32_t kBccPayloadIssuer = 1;
constexpr uint32_t kBccPayloadSubject = 2;
constexpr uint32_t kBccPayloadSubject = 2;
constexpr int32_t kBccPayloadSubjPubKey = -4670552;
constexpr int32_t kBccPayloadSubjPubKey = -4670552;
constexpr int32_t kBccPayloadKeyUsage = -4670553;
constexpr int32_t kBccPayloadKeyUsage = -4670553;
constexpr int kP256AffinePointSize = 32;

using EC_KEY_Ptr = bssl::UniquePtr<EC_KEY>;
using EVP_PKEY_Ptr = bssl::UniquePtr<EVP_PKEY>;
using EVP_PKEY_CTX_Ptr = bssl::UniquePtr<EVP_PKEY_CTX>;

ErrMsgOr<bytevec> ecKeyGetPrivateKey(const EC_KEY* ecKey) {
    // Extract private key.
    const BIGNUM* bignum = EC_KEY_get0_private_key(ecKey);
    if (bignum == nullptr) {
        return "Error getting bignum from private key";
    }
    // Pad with zeros in case the length is lesser than 32.
    bytevec privKey(32, 0);
    BN_bn2binpad(bignum, privKey.data(), privKey.size());
    return privKey;
}

ErrMsgOr<bytevec> ecKeyGetPublicKey(const EC_KEY* ecKey) {
    // Extract public key.
    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
    if (group.get() == nullptr) {
        return "Error creating EC group by curve name";
    }
    const EC_POINT* point = EC_KEY_get0_public_key(ecKey);
    if (point == nullptr) return "Error getting ecpoint from public key";

    int size =
        EC_POINT_point2oct(group.get(), point, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
    if (size == 0) {
        return "Error generating public key encoding";
    }

    bytevec publicKey;
    publicKey.resize(size);
    EC_POINT_point2oct(group.get(), point, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(),
                       publicKey.size(), nullptr);
    return publicKey;
}

ErrMsgOr<std::tuple<bytevec, bytevec>> getAffineCoordinates(const bytevec& pubKey) {
    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
    if (group.get() == nullptr) {
        return "Error creating EC group by curve name";
    }
    auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
    if (EC_POINT_oct2point(group.get(), point.get(), pubKey.data(), pubKey.size(), nullptr) != 1) {
        return "Error decoding publicKey";
    }
    BIGNUM_Ptr x(BN_new());
    BIGNUM_Ptr y(BN_new());
    BN_CTX_Ptr ctx(BN_CTX_new());
    if (!ctx.get()) return "Failed to create BN_CTX instance";

    if (!EC_POINT_get_affine_coordinates_GFp(group.get(), point.get(), x.get(), y.get(),
                                             ctx.get())) {
        return "Failed to get affine coordinates from ECPoint";
    }
    bytevec pubX(kP256AffinePointSize);
    bytevec pubY(kP256AffinePointSize);
    if (BN_bn2binpad(x.get(), pubX.data(), kP256AffinePointSize) != kP256AffinePointSize) {
        return "Error in converting absolute value of x coordinate to big-endian";
    }
    if (BN_bn2binpad(y.get(), pubY.data(), kP256AffinePointSize) != kP256AffinePointSize) {
        return "Error in converting absolute value of y coordinate to big-endian";
    }
    return std::make_tuple(std::move(pubX), std::move(pubY));
}

ErrMsgOr<std::tuple<bytevec, bytevec>> generateEc256KeyPair() {
    auto ec_key = EC_KEY_Ptr(EC_KEY_new());
    if (ec_key.get() == nullptr) {
        return "Failed to allocate ec key";
    }

    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
    if (group.get() == nullptr) {
        return "Error creating EC group by curve name";
    }

    if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
        EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
        return "Error generating key";
    }

    auto privKey = ecKeyGetPrivateKey(ec_key.get());
    if (!privKey) return privKey.moveMessage();

    auto pubKey = ecKeyGetPublicKey(ec_key.get());
    if (!pubKey) return pubKey.moveMessage();

    return std::make_tuple(pubKey.moveValue(), privKey.moveValue());
}

ErrMsgOr<std::tuple<bytevec, bytevec>> generateX25519KeyPair() {
    /* Generate X25519 key pair */
    bytevec pubKey(X25519_PUBLIC_VALUE_LEN);
    bytevec privKey(X25519_PRIVATE_KEY_LEN);
    X25519_keypair(pubKey.data(), privKey.data());
    return std::make_tuple(std::move(pubKey), std::move(privKey));
}

ErrMsgOr<std::tuple<bytevec, bytevec>> generateED25519KeyPair() {
    /* Generate ED25519 key pair */
    bytevec pubKey(ED25519_PUBLIC_KEY_LEN);
    bytevec privKey(ED25519_PRIVATE_KEY_LEN);
    ED25519_keypair(pubKey.data(), privKey.data());
    return std::make_tuple(std::move(pubKey), std::move(privKey));
}

ErrMsgOr<std::tuple<bytevec, bytevec>> generateKeyPair(int32_t supportedEekCurve, bool isEek) {
    switch (supportedEekCurve) {
    case RpcHardwareInfo::CURVE_25519:
        if (isEek) {
            return generateX25519KeyPair();
        }
        return generateED25519KeyPair();
    case RpcHardwareInfo::CURVE_P256:
        return generateEc256KeyPair();
    default:
        return "Unknown EEK Curve.";
    }
}

ErrMsgOr<bytevec> constructCoseKey(int32_t supportedEekCurve, const bytevec& eekId,
                                   const bytevec& pubKey) {
    CoseKeyType keyType;
    CoseKeyAlgorithm algorithm;
    CoseKeyCurve curve;
    bytevec pubX;
    bytevec pubY;
    switch (supportedEekCurve) {
    case RpcHardwareInfo::CURVE_25519:
        keyType = OCTET_KEY_PAIR;
        algorithm = (eekId.empty()) ? EDDSA : ECDH_ES_HKDF_256;
        curve = (eekId.empty()) ? ED25519 : cppcose::X25519;
        pubX = pubKey;
        break;
    case RpcHardwareInfo::CURVE_P256: {
        keyType = EC2;
        algorithm = (eekId.empty()) ? ES256 : ECDH_ES_HKDF_256;
        curve = P256;
        auto affineCoordinates = getAffineCoordinates(pubKey);
        if (!affineCoordinates) return affineCoordinates.moveMessage();
        std::tie(pubX, pubY) = affineCoordinates.moveValue();
    } break;
    default:
        return "Unknown EEK Curve.";
    }
    cppbor::Map coseKey = cppbor::Map()
                              .add(CoseKey::KEY_TYPE, keyType)
                              .add(CoseKey::ALGORITHM, algorithm)
                              .add(CoseKey::CURVE, curve)
                              .add(CoseKey::PUBKEY_X, pubX);

    if (!pubY.empty()) coseKey.add(CoseKey::PUBKEY_Y, pubY);
    if (!eekId.empty()) coseKey.add(CoseKey::KEY_ID, eekId);

    return coseKey.canonicalize().encode();
}


bytevec kTestMacKey(32 /* count */, 0 /* byte value */);
bytevec kTestMacKey(32 /* count */, 0 /* byte value */);


@@ -39,7 +205,17 @@ bytevec randomBytes(size_t numBytes) {
    return retval;
    return retval;
}
}


ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {
ErrMsgOr<cppbor::Array> constructCoseSign1(int32_t supportedEekCurve, const bytevec& key,
                                           const bytevec& payload, const bytevec& aad) {
    if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
        return constructECDSACoseSign1(key, {} /* protectedParams */, payload, aad);
    } else {
        return cppcose::constructCoseSign1(key, payload, aad);
    }
}

ErrMsgOr<EekChain> generateEekChain(int32_t supportedEekCurve, size_t length,
                                    const bytevec& eekId) {
    if (length < 2) {
    if (length < 2) {
        return "EEK chain must contain at least 2 certs.";
        return "EEK chain must contain at least 2 certs.";
    }
    }
@@ -48,59 +224,62 @@ ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {


    bytevec prev_priv_key;
    bytevec prev_priv_key;
    for (size_t i = 0; i < length - 1; ++i) {
    for (size_t i = 0; i < length - 1; ++i) {
        bytevec pub_key(ED25519_PUBLIC_KEY_LEN);
        auto keyPair = generateKeyPair(supportedEekCurve, false);
        bytevec priv_key(ED25519_PRIVATE_KEY_LEN);
        if (!keyPair) keyPair.moveMessage();

        auto [pub_key, priv_key] = keyPair.moveValue();
        ED25519_keypair(pub_key.data(), priv_key.data());


        // The first signing key is self-signed.
        // The first signing key is self-signed.
        if (prev_priv_key.empty()) prev_priv_key = priv_key;
        if (prev_priv_key.empty()) prev_priv_key = priv_key;


        auto coseSign1 = constructCoseSign1(prev_priv_key,
        auto coseKey = constructCoseKey(supportedEekCurve, {}, pub_key);
                                            cppbor::Map() /* payload CoseKey */
        if (!coseKey) return coseKey.moveMessage();
                                                    .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)

                                                    .add(CoseKey::ALGORITHM, EDDSA)
        auto coseSign1 =
                                                    .add(CoseKey::CURVE, ED25519)
            constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), {} /* AAD */);
                                                    .add(CoseKey::PUBKEY_X, pub_key)
                                                    .canonicalize()
                                                    .encode(),
                                            {} /* AAD */);
        if (!coseSign1) return coseSign1.moveMessage();
        if (!coseSign1) return coseSign1.moveMessage();
        eekChain.add(coseSign1.moveValue());
        eekChain.add(coseSign1.moveValue());


        prev_priv_key = priv_key;
        prev_priv_key = priv_key;
    }
    }
    auto keyPair = generateKeyPair(supportedEekCurve, true);
    if (!keyPair) keyPair.moveMessage();
    auto [pub_key, priv_key] = keyPair.moveValue();


    bytevec pub_key(X25519_PUBLIC_VALUE_LEN);
    auto coseKey = constructCoseKey(supportedEekCurve, eekId, pub_key);
    bytevec priv_key(X25519_PRIVATE_KEY_LEN);
    if (!coseKey) return coseKey.moveMessage();
    X25519_keypair(pub_key.data(), priv_key.data());


    auto coseSign1 =
    auto coseSign1 = constructCoseSign1(prev_priv_key,
        constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), {} /* AAD */);
                                        cppbor::Map() /* payload CoseKey */
                                                .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
                                                .add(CoseKey::KEY_ID, eekId)
                                                .add(CoseKey::ALGORITHM, ECDH_ES_HKDF_256)
                                                .add(CoseKey::CURVE, cppcose::X25519)
                                                .add(CoseKey::PUBKEY_X, pub_key)
                                                .canonicalize()
                                                .encode(),
                                        {} /* AAD */);
    if (!coseSign1) return coseSign1.moveMessage();
    if (!coseSign1) return coseSign1.moveMessage();
    eekChain.add(coseSign1.moveValue());
    eekChain.add(coseSign1.moveValue());


    return EekChain{eekChain.encode(), pub_key, priv_key};
    if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
        // convert ec public key to x and y co-ordinates.
        auto affineCoordinates = getAffineCoordinates(pub_key);
        if (!affineCoordinates) return affineCoordinates.moveMessage();
        auto [pubX, pubY] = affineCoordinates.moveValue();
        pub_key.clear();
        pub_key.insert(pub_key.begin(), pubX.begin(), pubX.end());
        pub_key.insert(pub_key.end(), pubY.begin(), pubY.end());
    }
    }


bytevec getProdEekChain() {
    return EekChain{eekChain.encode(), pub_key, priv_key};
    bytevec prodEek;
}
    prodEek.reserve(1 + sizeof(kCoseEncodedRootCert) + sizeof(kCoseEncodedGeekCert));

    // In CBOR encoding, 0x82 indicates an array of two items
    prodEek.push_back(0x82);
    prodEek.insert(prodEek.end(), std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert));
    prodEek.insert(prodEek.end(), std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert));


    return prodEek;
bytevec getProdEekChain(int32_t supportedEekCurve) {
    cppbor::Array chain;
    if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
        chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsa256RootCert),
                                              std::end(kCoseEncodedEcdsa256RootCert))));
        chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsa256GeekCert),
                                              std::end(kCoseEncodedEcdsa256GeekCert))));
    } else {
        chain.add(cppbor::EncodedItem(
            bytevec(std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert))));
        chain.add(cppbor::EncodedItem(
            bytevec(std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert))));
    }
    return chain.encode();
}
}


ErrMsgOr<bytevec> validatePayloadAndFetchPubKey(const cppbor::Map* payload) {
ErrMsgOr<bytevec> validatePayloadAndFetchPubKey(const cppbor::Map* payload) {
@@ -139,7 +318,8 @@ ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
    }
    }


    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
    if (!algorithm || !algorithm->asInt() ||
        (algorithm->asInt()->value() != EDDSA && algorithm->asInt()->value() != ES256)) {
        return "Unsupported signature algorithm";
        return "Unsupported signature algorithm";
    }
    }


@@ -152,16 +332,37 @@ ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
    }
    }


    bool selfSigned = signingCoseKey.empty();
    bool selfSigned = signingCoseKey.empty();
    auto key = CoseKey::parseEd25519(selfSigned ? *serializedKey : signingCoseKey);
    if (!key) return "Bad signing key: " + key.moveMessage();

    bytevec signatureInput =
    bytevec signatureInput =
        cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
        cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();


    if (algorithm->asInt()->value() == EDDSA) {
        auto key = CoseKey::parseEd25519(selfSigned ? *serializedKey : signingCoseKey);

        if (!key) return "Bad signing key: " + key.moveMessage();

        if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
        if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
                            key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
                            key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
            return "Signature verification failed";
            return "Signature verification failed";
        }
        }
    } else {  // P256
        auto key = CoseKey::parseP256(selfSigned ? *serializedKey : signingCoseKey);
        if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() ||
            key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) {
            return "Bad signing key: " + key.moveMessage();
        }
        auto publicKey = key->getEcPublicKey();
        if (!publicKey) return publicKey.moveMessage();

        auto ecdsaDerSignature = ecdsaCoseSignatureToDer(signature->value());
        if (!ecdsaDerSignature) return ecdsaDerSignature.moveMessage();

        // convert public key to uncompressed form.
        publicKey->insert(publicKey->begin(), 0x04);

        if (!verifyEcdsaDigest(publicKey.moveValue(), sha256(signatureInput), *ecdsaDerSignature)) {
            return "Signature verification failed";
        }
    }


    return serializedKey.moveValue();
    return serializedKey.moveValue();
}
}
+158 −7

File changed.

Preview size limit exceeded, changes collapsed.