diff options
author | Max Bires <jbires@google.com> | 2021-04-07 11:12:01 -0700 |
---|---|---|
committer | Max Bires <jbires@google.com> | 2021-04-17 18:19:28 -0700 |
commit | 9704ff6b85b97ba8ee4ac5056efa1878024d8e2c (patch) | |
tree | b4dd64d3bb61c50b372837e8c5b6c369ecc5ecb7 | |
parent | 6594b5f1b4a65fb22e12c1c42dad235feb6ae69d (diff) |
Porting IRPC functionality.
This is the change that removes the functionality that has been shifted
over to appropriate classes and contexts in system/keymaster.
Test: atest VtsHalRemotelyProvisionedComponentTargetTest
Change-Id: I491f4ef823868322ea6a804d88ca09662c099a44
-rw-r--r-- | identity/aidl/default/Android.bp | 2 | ||||
-rw-r--r-- | identity/aidl/vts/Android.bp | 1 | ||||
-rw-r--r-- | identity/support/Android.bp | 1 | ||||
-rw-r--r-- | security/keymint/aidl/default/Android.bp | 2 | ||||
-rw-r--r-- | security/keymint/aidl/default/RemotelyProvisionedComponent.cpp | 344 | ||||
-rw-r--r-- | security/keymint/aidl/default/RemotelyProvisionedComponent.h | 8 | ||||
-rw-r--r-- | security/keymint/aidl/vts/functional/Android.bp | 12 | ||||
-rw-r--r-- | security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp | 2 | ||||
-rw-r--r-- | security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp | 2 | ||||
-rw-r--r-- | security/keymint/support/Android.bp | 19 | ||||
-rw-r--r-- | security/keymint/support/cppcose.cpp | 467 | ||||
-rw-r--r-- | security/keymint/support/include/cppcose/cppcose.h | 288 | ||||
-rw-r--r-- | security/keymint/support/include/remote_prov/remote_prov_utils.h | 2 |
13 files changed, 39 insertions, 1111 deletions
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp index a124b1e9de..7c68aee26d 100644 --- a/identity/aidl/default/Android.bp +++ b/identity/aidl/default/Android.bp @@ -32,6 +32,7 @@ cc_library_static { static_libs: [ "libbase", "libcppbor_external", + "libcppcose_rkp", "libutils", "libsoft_attestation_cert", "libkeymaster_portable", @@ -92,6 +93,7 @@ cc_binary { static_libs: [ "libbase", "libcppbor_external", + "libcppcose_rkp", "libutils", "libsoft_attestation_cert", "libkeymaster_portable", diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp index 3592d3e93b..61d15d2d54 100644 --- a/identity/aidl/vts/Android.bp +++ b/identity/aidl/vts/Android.bp @@ -35,6 +35,7 @@ cc_test { ], static_libs: [ "libcppbor_external", + "libcppcose_rkp", "libkeymaster_portable", "libpuresoftkeymasterdevice", "android.hardware.keymaster@4.0", diff --git a/identity/support/Android.bp b/identity/support/Android.bp index 774bc40406..db1a945964 100644 --- a/identity/support/Android.bp +++ b/identity/support/Android.bp @@ -35,6 +35,7 @@ cc_library { "android.hardware.keymaster@4.0", "libcrypto", "libbase", + "libcppcose_rkp", "libhidlbase", "libhardware", "libkeymaster_portable", diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp index ebdc9b7790..1187717c63 100644 --- a/security/keymint/aidl/default/Android.bp +++ b/security/keymint/aidl/default/Android.bp @@ -62,7 +62,7 @@ cc_library { "android.hardware.security.keymint-V1-ndk_platform", "libbinder_ndk", "libcppbor_external", - "libcppcose", + "libcppcose_rkp", "libcrypto", "libkeymaster_portable", "libkeymint", diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp b/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp index 5b027292fe..6007663b58 100644 --- a/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp +++ b/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp @@ -23,7 +23,7 @@ #include <cppbor_parse.h> #include <KeyMintUtils.h> -#include <cppcose/cppcose.h> +#include <keymaster/cppcose/cppcose.h> #include <keymaster/keymaster_configuration.h> #include <remote_prov/remote_prov_utils.h> @@ -46,18 +46,8 @@ 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; -constexpr uint32_t kAffinePointLength = 32; + struct AStatusDeleter { void operator()(AStatus* p) { AStatus_delete(p); } }; @@ -125,167 +115,10 @@ class StatusOr { std::optional<T> value_; }; -StatusOr<std::pair<bytevec /* EEK pub */, bytevec /* EEK ID */>> validateAndExtractEekPubAndId( - bool testMode, const bytevec& endpointEncryptionCertChain) { - auto [item, newPos, errMsg] = cppbor::parse(endpointEncryptionCertChain); - - if (!item || !item->asArray()) { - return Status("Error parsing EEK chain" + errMsg); - } - - const cppbor::Array* certArr = item->asArray(); - bytevec lastPubKey; - for (int i = 0; i < certArr->size(); ++i) { - auto cosePubKey = verifyAndParseCoseSign1(testMode, certArr->get(i)->asArray(), - std::move(lastPubKey), bytevec{} /* AAD */); - if (!cosePubKey) { - return Status(STATUS_INVALID_EEK, - "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 */); - if (!eek) return Status(STATUS_INVALID_EEK, "Failed to get EEK: " + eek.moveMessage()); - - return std::make_pair(eek->getBstrValue(CoseKey::PUBKEY_X).value(), - eek->getBstrValue(CoseKey::KEY_ID).value()); -} - -StatusOr<bytevec /* pubkeys */> validateAndExtractPubkeys(bool testMode, - const vector<MacedPublicKey>& keysToSign, - const bytevec& macKey) { - auto pubKeysToMac = cppbor::Array(); - for (auto& keyToSign : keysToSign) { - auto [macedKeyItem, _, coseMacErrMsg] = cppbor::parse(keyToSign.macedKey); - if (!macedKeyItem || !macedKeyItem->asArray() || - macedKeyItem->asArray()->size() != kCoseMac0EntryCount) { - return Status("Invalid COSE_Mac0 structure"); - } - - auto protectedParms = macedKeyItem->asArray()->get(kCoseMac0ProtectedParams)->asBstr(); - auto unprotectedParms = macedKeyItem->asArray()->get(kCoseMac0UnprotectedParams)->asMap(); - auto payload = macedKeyItem->asArray()->get(kCoseMac0Payload)->asBstr(); - auto tag = macedKeyItem->asArray()->get(kCoseMac0Tag)->asBstr(); - if (!protectedParms || !unprotectedParms || !payload || !tag) { - return Status("Invalid COSE_Mac0 contents"); - } - - auto [protectedMap, __, errMsg] = cppbor::parse(protectedParms); - if (!protectedMap || !protectedMap->asMap()) { - return Status("Invalid Mac0 protected: " + errMsg); - } - auto& algo = protectedMap->asMap()->get(ALGORITHM); - if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) { - return Status("Unsupported Mac0 algorithm"); - } - - auto pubKey = CoseKey::parse(payload->value(), EC2, ES256, P256); - if (!pubKey) return Status(pubKey.moveMessage()); - - bool testKey = static_cast<bool>(pubKey->getMap().get(CoseKey::TEST_KEY)); - if (testMode && !testKey) { - return Status(BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST, - "Production key in test request"); - } else if (!testMode && testKey) { - return Status(BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST, - "Test key in production request"); - } - - auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value()); - if (!macTag) return Status(STATUS_INVALID_MAC, macTag.moveMessage()); - if (macTag->size() != tag->value().size() || - CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) { - return Status(STATUS_INVALID_MAC, "MAC tag mismatch"); - } - - pubKeysToMac.add(pubKey->moveMap()); - } - - return pubKeysToMac.encode(); -} - -StatusOr<std::pair<bytevec, bytevec>> buildCosePublicKeyFromKmCert( - const keymaster_blob_t* km_cert) { - if (km_cert == nullptr) { - return Status(STATUS_FAILED, "km_cert is a nullptr"); - } - const uint8_t* temp = km_cert->data; - X509* cert = d2i_X509(NULL, &temp, km_cert->data_length); - if (cert == nullptr) { - return Status(STATUS_FAILED, "d2i_X509 returned null when attempting to get the cert."); - } - EVP_PKEY* pubKey = X509_get_pubkey(cert); - if (pubKey == nullptr) { - return Status(STATUS_FAILED, "Boringssl failed to get the public key from the cert"); - } - EC_KEY* ecKey = EVP_PKEY_get0_EC_KEY(pubKey); - if (ecKey == nullptr) { - return Status(STATUS_FAILED, - "The key in the certificate returned from GenerateKey is not " - "an EC key."); - } - const EC_POINT* jacobian_coords = EC_KEY_get0_public_key(ecKey); - BIGNUM x; - BIGNUM y; - BN_CTX* ctx = BN_CTX_new(); - if (ctx == nullptr) { - return Status(STATUS_FAILED, "Memory allocation failure for BN_CTX"); - } - if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ecKey), jacobian_coords, &x, &y, - ctx)) { - return Status(STATUS_FAILED, "Failed to get affine coordinates"); - } - bytevec x_bytestring(kAffinePointLength); - bytevec y_bytestring(kAffinePointLength); - if (BN_bn2binpad(&x, x_bytestring.data(), kAffinePointLength) != kAffinePointLength) { - return Status(STATUS_FAILED, "Wrote incorrect number of bytes for x coordinate"); - } - if (BN_bn2binpad(&y, y_bytestring.data(), kAffinePointLength) != kAffinePointLength) { - return Status(STATUS_FAILED, "Wrote incorrect number of bytes for y coordinate"); - } - BN_CTX_free(ctx); - return std::make_pair(x_bytestring, y_bytestring); -} - -cppbor::Array buildCertReqRecipients(const bytevec& pubkey, const bytevec& kid) { - return cppbor::Array() // Array of recipients - .add(cppbor::Array() // Recipient - .add(cppbor::Map() // Protected - .add(ALGORITHM, ECDH_ES_HKDF_256) - .canonicalize() - .encode()) - .add(cppbor::Map() // Unprotected - .add(COSE_KEY, cppbor::Map() - .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR) - .add(CoseKey::CURVE, cppcose::X25519) - .add(CoseKey::PUBKEY_X, pubkey) - .canonicalize()) - .add(KEY_ID, kid) - .canonicalize()) - .add(cppbor::Null())); // No ciphertext -} - -static keymaster_key_param_t kKeyMintEcdsaP256Params[] = { - Authorization(TAG_PURPOSE, KM_PURPOSE_ATTEST_KEY), - Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC), Authorization(TAG_KEY_SIZE, 256), - Authorization(TAG_DIGEST, KM_DIGEST_SHA_2_256), - Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256), Authorization(TAG_NO_AUTH_REQUIRED), - // The certificate generated by KM will be discarded, these values don't matter. - Authorization(TAG_CERTIFICATE_NOT_BEFORE, 0), Authorization(TAG_CERTIFICATE_NOT_AFTER, 0)}; - } // namespace RemotelyProvisionedComponent::RemotelyProvisionedComponent( std::shared_ptr<keymint::AndroidKeyMintDevice> keymint) { - std::tie(devicePrivKey_, bcc_) = generateBcc(); impl_ = keymint->getKeymasterImpl(); } @@ -294,43 +127,15 @@ RemotelyProvisionedComponent::~RemotelyProvisionedComponent() {} ScopedAStatus RemotelyProvisionedComponent::generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey, bytevec* privateKeyHandle) { - // TODO(jbires): The following should move from ->GenerateKey to ->GenerateRKPKey and everything - // after the GenerateKey call should basically be moved into that new function call - // as well once the issue with libcppbor in system/keymaster is sorted out - GenerateKeyRequest request(impl_->message_version()); - request.key_description.Reinitialize(kKeyMintEcdsaP256Params, - array_length(kKeyMintEcdsaP256Params)); - GenerateKeyResponse response(impl_->message_version()); - impl_->GenerateKey(request, &response); + GenerateRkpKeyRequest request(impl_->message_version()); + request.test_mode = testMode; + GenerateRkpKeyResponse response(impl_->message_version()); + impl_->GenerateRkpKey(request, &response); if (response.error != KM_ERROR_OK) { - return km_utils::kmError2ScopedAStatus(response.error); - } - - if (response.certificate_chain.entry_count != 1) { - // Error: Need the single non-signed certificate with the public key in it. - return Status(STATUS_FAILED, - "Expected to receive a single certificate from GenerateKey. Instead got: " + - std::to_string(response.certificate_chain.entry_count)); - } - auto affineCoords = buildCosePublicKeyFromKmCert(response.certificate_chain.begin()); - if (!affineCoords.isOk()) return affineCoords.moveError(); - cppbor::Map cosePublicKeyMap = cppbor::Map() - .add(CoseKey::KEY_TYPE, EC2) - .add(CoseKey::ALGORITHM, ES256) - .add(CoseKey::CURVE, cppcose::P256) - .add(CoseKey::PUBKEY_X, affineCoords->first) - .add(CoseKey::PUBKEY_Y, affineCoords->second); - if (testMode) { - cosePublicKeyMap.add(CoseKey::TEST_KEY, cppbor::Null()); + return Status(-static_cast<int32_t>(response.error), "Failure in key generation."); } - bytevec cosePublicKey = cosePublicKeyMap.canonicalize().encode(); - - auto macedKey = constructCoseMac0(testMode ? remote_prov::kTestMacKey : macKey_, - {} /* externalAad */, cosePublicKey); - if (!macedKey) return Status(macedKey.moveMessage()); - - macedPublicKey->macedKey = macedKey->encode(); + macedPublicKey->macedKey = km_utils::kmBlob2vector(response.maced_public_key); *privateKeyHandle = km_utils::kmBlob2vector(response.key_blob); return ScopedAStatus::ok(); } @@ -339,126 +144,25 @@ ScopedAStatus RemotelyProvisionedComponent::generateCertificateRequest( bool testMode, const vector<MacedPublicKey>& keysToSign, const bytevec& endpointEncCertChain, const bytevec& challenge, DeviceInfo* deviceInfo, ProtectedData* protectedData, bytevec* keysToSignMac) { - auto pubKeysToSign = validateAndExtractPubkeys(testMode, keysToSign, - testMode ? remote_prov::kTestMacKey : macKey_); - if (!pubKeysToSign.isOk()) return pubKeysToSign.moveError(); + GenerateCsrRequest request(impl_->message_version()); + request.test_mode = testMode; + request.num_keys = keysToSign.size(); + request.keys_to_sign_array = new KeymasterBlob[keysToSign.size()]; + for (int i = 0; i < keysToSign.size(); i++) { + request.SetKeyToSign(i, keysToSign[i].macedKey.data(), keysToSign[i].macedKey.size()); + } + request.SetEndpointEncCertChain(endpointEncCertChain.data(), endpointEncCertChain.size()); + request.SetChallenge(challenge.data(), challenge.size()); + GenerateCsrResponse response(impl_->message_version()); + impl_->GenerateCsr(request, &response); - bytevec ephemeralMacKey = remote_prov::randomBytes(SHA256_DIGEST_LENGTH); - - auto pubKeysToSignMac = generateCoseMac0Mac(ephemeralMacKey, bytevec{}, *pubKeysToSign); - if (!pubKeysToSignMac) return Status(pubKeysToSignMac.moveMessage()); - *keysToSignMac = *std::move(pubKeysToSignMac); - - bytevec devicePrivKey; - cppbor::Array bcc; - if (testMode) { - std::tie(devicePrivKey, bcc) = generateBcc(); - } else { - devicePrivKey = devicePrivKey_; - bcc = bcc_.clone(); + if (response.error != KM_ERROR_OK) { + return Status(-static_cast<int32_t>(response.error), "Failure in CSR Generation."); } - - std::unique_ptr<cppbor::Map> deviceInfoMap = createDeviceInfo(); - deviceInfo->deviceInfo = deviceInfoMap->encode(); - auto signedMac = constructCoseSign1(devicePrivKey /* Signing key */, // - ephemeralMacKey /* Payload */, - cppbor::Array() /* AAD */ - .add(challenge) - .add(std::move(deviceInfoMap)) - .encode()); - if (!signedMac) return Status(signedMac.moveMessage()); - - bytevec ephemeralPrivKey(X25519_PRIVATE_KEY_LEN); - bytevec ephemeralPubKey(X25519_PUBLIC_VALUE_LEN); - X25519_keypair(ephemeralPubKey.data(), ephemeralPrivKey.data()); - - auto eek = validateAndExtractEekPubAndId(testMode, endpointEncCertChain); - if (!eek.isOk()) return eek.moveError(); - - auto sessionKey = x25519_HKDF_DeriveKey(ephemeralPubKey, ephemeralPrivKey, eek->first, - true /* senderIsA */); - if (!sessionKey) return Status(sessionKey.moveMessage()); - - auto coseEncrypted = - constructCoseEncrypt(*sessionKey, remote_prov::randomBytes(kAesGcmNonceLength), - cppbor::Array() // payload - .add(signedMac.moveValue()) - .add(std::move(bcc)) - .encode(), - {}, // aad - buildCertReqRecipients(ephemeralPubKey, eek->second)); - - if (!coseEncrypted) return Status(coseEncrypted.moveMessage()); - protectedData->protectedData = coseEncrypted->encode(); - + deviceInfo->deviceInfo = km_utils::kmBlob2vector(response.device_info_blob); + protectedData->protectedData = km_utils::kmBlob2vector(response.protected_data_blob); + *keysToSignMac = km_utils::kmBlob2vector(response.keys_to_sign_mac); return ScopedAStatus::ok(); } -bytevec RemotelyProvisionedComponent::deriveBytesFromHbk(const string& context, - size_t numBytes) const { - bytevec fakeHbk(32, 0); - bytevec result(numBytes); - - // TODO(swillden): Figure out if HKDF can fail. It doesn't seem like it should be able to, - // but the function does return an error code. - HKDF(result.data(), numBytes, // - EVP_sha256(), // - fakeHbk.data(), fakeHbk.size(), // - nullptr /* salt */, 0 /* salt len */, // - reinterpret_cast<const uint8_t*>(context.data()), context.size()); - - return result; -} - -std::unique_ptr<cppbor::Map> RemotelyProvisionedComponent::createDeviceInfo() const { - auto result = std::make_unique<cppbor::Map>(cppbor::Map()); - - // The following placeholders show how the DeviceInfo map would be populated. - // result->add(cppbor::Tstr("brand"), cppbor::Tstr("Google")); - // result->add(cppbor::Tstr("manufacturer"), cppbor::Tstr("Google")); - // result->add(cppbor::Tstr("product"), cppbor::Tstr("Fake")); - // result->add(cppbor::Tstr("model"), cppbor::Tstr("Imaginary")); - // result->add(cppbor::Tstr("board"), cppbor::Tstr("Chess")); - // result->add(cppbor::Tstr("vb_state"), cppbor::Tstr("orange")); - // result->add(cppbor::Tstr("bootloader_state"), cppbor::Tstr("unlocked")); - // result->add(cppbor::Tstr("os_version"), cppbor::Tstr("SC")); - // result->add(cppbor::Tstr("system_patch_level"), cppbor::Uint(20210331)); - // result->add(cppbor::Tstr("boot_patch_level"), cppbor::Uint(20210331)); - // result->add(cppbor::Tstr("vendor_patch_level"), cppbor::Uint(20210331)); - - result->canonicalize(); - return result; -} - -std::pair<bytevec /* privKey */, cppbor::Array /* BCC */> -RemotelyProvisionedComponent::generateBcc() { - bytevec privKey(ED25519_PRIVATE_KEY_LEN); - bytevec pubKey(ED25519_PUBLIC_KEY_LEN); - - ED25519_keypair(pubKey.data(), privKey.data()); - - auto coseKey = cppbor::Map() - .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR) - .add(CoseKey::ALGORITHM, EDDSA) - .add(CoseKey::CURVE, ED25519) - .add(CoseKey::KEY_OPS, VERIFY) - .add(CoseKey::PUBKEY_X, pubKey) - .canonicalize() - .encode(); - auto sign1Payload = cppbor::Map() - .add(1 /* Issuer */, "Issuer") - .add(2 /* Subject */, "Subject") - .add(-4670552 /* Subject Pub Key */, coseKey) - .add(-4670553 /* Key Usage (little-endian order) */, - std::vector<uint8_t>{0x20} /* keyCertSign = 1<<5 */) - .canonicalize() - .encode(); - auto coseSign1 = constructCoseSign1(privKey, /* signing key */ - cppbor::Map(), /* extra protected */ - sign1Payload, {} /* AAD */); - assert(coseSign1); - - return {privKey, cppbor::Array().add(coseKey).add(coseSign1.moveValue())}; -} - } // namespace aidl::android::hardware::security::keymint diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.h b/security/keymint/aidl/default/RemotelyProvisionedComponent.h index 8185e26e1f..4b012bceb8 100644 --- a/security/keymint/aidl/default/RemotelyProvisionedComponent.h +++ b/security/keymint/aidl/default/RemotelyProvisionedComponent.h @@ -43,14 +43,6 @@ class RemotelyProvisionedComponent : public BnRemotelyProvisionedComponent { std::vector<uint8_t>* keysToSignMac) override; private: - // TODO(swillden): Move these into an appropriate Context class. - std::vector<uint8_t> deriveBytesFromHbk(const std::string& context, size_t numBytes) const; - std::unique_ptr<cppbor::Map> createDeviceInfo() const; - std::pair<std::vector<uint8_t>, cppbor::Array> generateBcc(); - - std::vector<uint8_t> macKey_ = deriveBytesFromHbk("Key to MAC public keys", 32); - std::vector<uint8_t> devicePrivKey_; - cppbor::Array bcc_; std::shared_ptr<::keymaster::AndroidKeymaster> impl_; }; diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp index 6c7309eb7a..d969dfe03a 100644 --- a/security/keymint/aidl/vts/functional/Android.bp +++ b/security/keymint/aidl/vts/functional/Android.bp @@ -43,7 +43,7 @@ cc_test { "android.hardware.security.keymint-V1-ndk_platform", "android.hardware.security.secureclock-V1-ndk_platform", "libcppbor_external", - "libcppcose", + "libcppcose_rkp", "libkeymint_remote_prov_support", "libkeymint_vts_test_utils", ], @@ -75,7 +75,7 @@ cc_test_library { "android.hardware.security.keymint-V1-ndk_platform", "android.hardware.security.secureclock-V1-ndk_platform", "libcppbor_external", - "libcppcose", + "libcppcose_rkp", "libgmock_ndk", "libkeymint_remote_prov_support", ], @@ -92,20 +92,20 @@ cc_test { ], shared_libs: [ "libbinder_ndk", - "libcppbor_external", "libcrypto", - "libkeymaster_portable", - "libpuresoftkeymasterdevice", ], static_libs: [ "android.hardware.security.keymint-V1-ndk_platform", "android.hardware.security.secureclock-V1-ndk_platform", - "libcppcose", + "libcppbor_external", + "libcppcose_rkp", "libgmock_ndk", + "libkeymaster_portable", "libkeymint", "libkeymint_support", "libkeymint_remote_prov_support", "libkeymint_vts_test_utils", + "libpuresoftkeymasterdevice", "libremote_provisioner", ], test_suites: [ diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp index 3da048449b..0dcc961932 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -23,12 +23,12 @@ #include <android-base/logging.h> #include <android/binder_manager.h> #include <cppbor_parse.h> -#include <cppcose/cppcose.h> #include <cutils/properties.h> #include <gmock/gmock.h> #include <openssl/mem.h> #include <remote_prov/remote_prov_utils.h> +#include <keymaster/cppcose/cppcose.h> #include <keymint_support/attestation_record.h> #include <keymint_support/key_param_output.h> #include <keymint_support/keymint_utils.h> diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp index 9e52b20675..64430159ac 100644 --- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp +++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp @@ -21,8 +21,8 @@ #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 <keymaster/cppcose/cppcose.h> #include <keymaster/keymaster_configuration.h> #include <keymint_support/authorization_set.h> #include <openssl/ec.h> diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp index 4c4258b822..718133aa41 100644 --- a/security/keymint/support/Android.bp +++ b/security/keymint/support/Android.bp @@ -57,25 +57,8 @@ cc_library { "include", ], shared_libs: [ - "libcppcose", "libcppbor_external", + "libcppcose_rkp", "libcrypto", ], } - -cc_library { - name: "libcppcose", - vendor_available: true, - host_supported: true, - srcs: [ - "cppcose.cpp", - ], - export_include_dirs: [ - "include", - ], - shared_libs: [ - "libcppbor_external", - "libcrypto", - "liblog", - ], -} diff --git a/security/keymint/support/cppcose.cpp b/security/keymint/support/cppcose.cpp deleted file mode 100644 index bafb2b6bc9..0000000000 --- a/security/keymint/support/cppcose.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <cppcose/cppcose.h> - -#include <stdio.h> -#include <iostream> - -#include <cppbor.h> -#include <cppbor_parse.h> - -#include <openssl/err.h> - -namespace cppcose { - -namespace { - -ErrMsgOr<bssl::UniquePtr<EVP_CIPHER_CTX>> aesGcmInitAndProcessAad(const bytevec& key, - const bytevec& nonce, - const bytevec& aad, - bool encrypt) { - if (key.size() != kAesGcmKeySize) return "Invalid key size"; - - bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new()); - if (!ctx) return "Failed to allocate cipher context"; - - if (!EVP_CipherInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, key.data(), - nonce.data(), encrypt ? 1 : 0)) { - return "Failed to initialize cipher"; - } - - int outlen; - if (!aad.empty() && !EVP_CipherUpdate(ctx.get(), nullptr /* out; null means AAD */, &outlen, - aad.data(), aad.size())) { - return "Failed to process AAD"; - } - - return std::move(ctx); -} - -} // namespace - -ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad, - const bytevec& payload) { - auto macStructure = cppbor::Array() - .add("MAC0") - .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode()) - .add(externalAad) - .add(payload) - .encode(); - - bytevec macTag(SHA256_DIGEST_LENGTH); - uint8_t* out = macTag.data(); - unsigned int outLen; - out = HMAC(EVP_sha256(), // - macKey.data(), macKey.size(), // - macStructure.data(), macStructure.size(), // - out, &outLen); - - assert(out != nullptr && outLen == macTag.size()); - if (out == nullptr || outLen != macTag.size()) { - return "Error computing public key MAC"; - } - - return macTag; -} - -ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad, - const bytevec& payload) { - auto tag = generateCoseMac0Mac(macKey, externalAad, payload); - if (!tag) return tag.moveMessage(); - - return cppbor::Array() - .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode()) - .add(cppbor::Map() /* unprotected */) - .add(payload) - .add(tag.moveValue()); -} - -ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem) { - auto mac = macItem ? macItem->asArray() : nullptr; - if (!mac || mac->size() != kCoseMac0EntryCount) { - return "Invalid COSE_Mac0"; - } - - auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr(); - auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asMap(); - auto payload = mac->get(kCoseMac0Payload)->asBstr(); - auto tag = mac->get(kCoseMac0Tag)->asBstr(); - if (!protectedParms || !unprotectedParms || !payload || !tag) { - return "Invalid COSE_Mac0 contents"; - } - - return payload->value(); -} - -ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem, - const bytevec& macKey) { - auto mac = macItem ? macItem->asArray() : nullptr; - if (!mac || mac->size() != kCoseMac0EntryCount) { - return "Invalid COSE_Mac0"; - } - - auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr(); - auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asMap(); - auto payload = mac->get(kCoseMac0Payload)->asBstr(); - auto tag = mac->get(kCoseMac0Tag)->asBstr(); - if (!protectedParms || !unprotectedParms || !payload || !tag) { - return "Invalid COSE_Mac0 contents"; - } - - auto [protectedMap, _, errMsg] = cppbor::parse(protectedParms); - if (!protectedMap || !protectedMap->asMap()) { - return "Invalid Mac0 protected: " + errMsg; - } - auto& algo = protectedMap->asMap()->get(ALGORITHM); - if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) { - return "Unsupported Mac0 algorithm"; - } - - auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value()); - if (!macTag) return macTag.moveMessage(); - - if (macTag->size() != tag->value().size() || - CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) { - return "MAC tag mismatch"; - } - - return payload->value(); -} - -ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams, - const bytevec& payload, const bytevec& aad) { - bytevec signatureInput = cppbor::Array() - .add("Signature1") // - .add(protectedParams) - .add(aad) - .add(payload) - .encode(); - - if (key.size() != ED25519_PRIVATE_KEY_LEN) return "Invalid signing key"; - bytevec signature(ED25519_SIGNATURE_LEN); - if (!ED25519_sign(signature.data(), signatureInput.data(), signatureInput.size(), key.data())) { - return "Signing failed"; - } - - return signature; -} - -ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map protectedParams, - const bytevec& payload, const bytevec& aad) { - bytevec protParms = protectedParams.add(ALGORITHM, EDDSA).canonicalize().encode(); - auto signature = createCoseSign1Signature(key, protParms, payload, aad); - if (!signature) return signature.moveMessage(); - - return cppbor::Array() - .add(protParms) - .add(cppbor::Map() /* unprotected parameters */) - .add(payload) - .add(*signature); -} - -ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload, - const bytevec& aad) { - return constructCoseSign1(key, {} /* protectedParams */, payload, aad); -} - -ErrMsgOr<bytevec> verifyAndParseCoseSign1(bool ignoreSignature, const cppbor::Array* coseSign1, - const bytevec& signingCoseKey, const bytevec& aad) { - if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) { - return "Invalid COSE_Sign1"; - } - - 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"; - } - - auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams); - if (!parsedProtParams) { - return errMsg + " when parsing protected params."; - } - if (!parsedProtParams->asMap()) { - return "Protected params must be a map"; - } - - auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM); - if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) { - return "Unsupported signature algorithm"; - } - - if (!ignoreSignature) { - bool selfSigned = signingCoseKey.empty(); - auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey); - if (!key) return "Bad signing key: " + key.moveMessage(); - - bytevec signatureInput = cppbor::Array() - .add("Signature1") - .add(*protectedParams) - .add(aad) - .add(*payload) - .encode(); - - if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(), - key->getBstrValue(CoseKey::PUBKEY_X)->data())) { - return "Signature verification failed"; - } - } - - return payload->value(); -} - -ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce, - const bytevec& protectedParams, - const bytevec& plaintextPayload, const bytevec& aad) { - auto ciphertext = aesGcmEncrypt(key, nonce, - cppbor::Array() // Enc strucure as AAD - .add("Encrypt") // Context - .add(protectedParams) // Protected - .add(aad) // External AAD - .encode(), - plaintextPayload); - - if (!ciphertext) return ciphertext.moveMessage(); - return ciphertext.moveValue(); -} - -ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce, - const bytevec& plaintextPayload, const bytevec& aad, - cppbor::Array recipients) { - auto encryptProtectedHeader = cppbor::Map() // - .add(ALGORITHM, AES_GCM_256) - .canonicalize() - .encode(); - - auto ciphertext = - createCoseEncryptCiphertext(key, nonce, encryptProtectedHeader, plaintextPayload, aad); - if (!ciphertext) return ciphertext.moveMessage(); - - return cppbor::Array() - .add(encryptProtectedHeader) // Protected - .add(cppbor::Map().add(IV, nonce).canonicalize()) // Unprotected - .add(*ciphertext) // Payload - .add(std::move(recipients)); -} - -ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt( - const cppbor::Item* coseEncrypt) { - if (!coseEncrypt || !coseEncrypt->asArray() || - coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) { - return "Invalid COSE_Encrypt"; - } - - auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients); - if (!recipients || !recipients->asArray() || recipients->asArray()->size() != 1) { - return "Invalid recipients list"; - } - - auto& recipient = recipients->asArray()->get(0); - if (!recipient || !recipient->asArray() || recipient->asArray()->size() != 3) { - return "Invalid COSE_recipient"; - } - - auto& ciphertext = recipient->asArray()->get(2); - if (!ciphertext->asSimple() || !ciphertext->asSimple()->asNull()) { - return "Unexpected value in recipients ciphertext field " + - cppbor::prettyPrint(ciphertext.get()); - } - - auto& protParms = recipient->asArray()->get(0); - if (!protParms || !protParms->asBstr()) return "Invalid protected params"; - auto [parsedProtParms, _, errMsg] = cppbor::parse(protParms->asBstr()); - if (!parsedProtParms) return "Failed to parse protected params: " + errMsg; - if (!parsedProtParms->asMap()) return "Invalid protected params"; - - auto& algorithm = parsedProtParms->asMap()->get(ALGORITHM); - if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != ECDH_ES_HKDF_256) { - return "Invalid algorithm"; - } - - auto& unprotParms = recipient->asArray()->get(1); - if (!unprotParms || !unprotParms->asMap()) return "Invalid unprotected params"; - - auto& senderCoseKey = unprotParms->asMap()->get(COSE_KEY); - if (!senderCoseKey || !senderCoseKey->asMap()) return "Invalid sender COSE_Key"; - - auto& keyType = senderCoseKey->asMap()->get(CoseKey::KEY_TYPE); - if (!keyType || !keyType->asInt() || keyType->asInt()->value() != OCTET_KEY_PAIR) { - return "Invalid key type"; - } - - auto& curve = senderCoseKey->asMap()->get(CoseKey::CURVE); - if (!curve || !curve->asInt() || curve->asInt()->value() != X25519) { - return "Unsupported curve"; - } - - auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X); - if (!pubkey || !pubkey->asBstr() || - pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) { - return "Invalid X25519 public key"; - } - - auto& key_id = unprotParms->asMap()->get(KEY_ID); - if (key_id && key_id->asBstr()) { - return std::make_pair(pubkey->asBstr()->value(), key_id->asBstr()->value()); - } - - // If no key ID, just return an empty vector. - return std::make_pair(pubkey->asBstr()->value(), bytevec{}); -} - -ErrMsgOr<bytevec> decryptCoseEncrypt(const bytevec& key, const cppbor::Item* coseEncrypt, - const bytevec& external_aad) { - if (!coseEncrypt || !coseEncrypt->asArray() || - coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) { - return "Invalid COSE_Encrypt"; - } - - auto& protParms = coseEncrypt->asArray()->get(kCoseEncryptProtectedParams); - auto& unprotParms = coseEncrypt->asArray()->get(kCoseEncryptUnprotectedParams); - auto& ciphertext = coseEncrypt->asArray()->get(kCoseEncryptPayload); - auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients); - - if (!protParms || !protParms->asBstr() || !unprotParms || !ciphertext || !recipients) { - return "Invalid COSE_Encrypt"; - } - - auto [parsedProtParams, _, errMsg] = cppbor::parse(protParms->asBstr()->value()); - if (!parsedProtParams) { - return errMsg + " when parsing protected params."; - } - if (!parsedProtParams->asMap()) { - return "Protected params must be a map"; - } - - auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM); - if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != AES_GCM_256) { - return "Unsupported encryption algorithm"; - } - - if (!unprotParms->asMap() || unprotParms->asMap()->size() != 1) { - return "Invalid unprotected params"; - } - - auto& nonce = unprotParms->asMap()->get(IV); - if (!nonce || !nonce->asBstr() || nonce->asBstr()->value().size() != kAesGcmNonceLength) { - return "Invalid nonce"; - } - - if (!ciphertext->asBstr()) return "Invalid ciphertext"; - - auto aad = cppbor::Array() // Enc strucure as AAD - .add("Encrypt") // Context - .add(protParms->asBstr()->value()) // Protected - .add(external_aad) // External AAD - .encode(); - - return aesGcmDecrypt(key, nonce->asBstr()->value(), aad, ciphertext->asBstr()->value()); -} - -ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA, - const bytevec& pubKeyB, bool senderIsA) { - bytevec rawSharedKey(X25519_SHARED_KEY_LEN); - if (!::X25519(rawSharedKey.data(), privKeyA.data(), pubKeyB.data())) { - return "ECDH operation failed"; - } - - bytevec kdfContext = cppbor::Array() - .add(AES_GCM_256) - .add(cppbor::Array() // Sender Info - .add(cppbor::Bstr("client")) - .add(bytevec{} /* nonce */) - .add(senderIsA ? pubKeyA : pubKeyB)) - .add(cppbor::Array() // Recipient Info - .add(cppbor::Bstr("server")) - .add(bytevec{} /* nonce */) - .add(senderIsA ? pubKeyB : pubKeyA)) - .add(cppbor::Array() // SuppPubInfo - .add(128) // output key length - .add(bytevec{})) // protected - .encode(); - - bytevec retval(SHA256_DIGEST_LENGTH); - bytevec salt{}; - if (!HKDF(retval.data(), retval.size(), // - EVP_sha256(), // - rawSharedKey.data(), rawSharedKey.size(), // - salt.data(), salt.size(), // - kdfContext.data(), kdfContext.size())) { - return "ECDH HKDF failed"; - } - - return retval; -} - -ErrMsgOr<bytevec> aesGcmEncrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad, - const bytevec& plaintext) { - auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, true /* encrypt */); - if (!ctx) return ctx.moveMessage(); - - bytevec ciphertext(plaintext.size() + kAesGcmTagSize); - int outlen; - if (!EVP_CipherUpdate(ctx->get(), ciphertext.data(), &outlen, plaintext.data(), - plaintext.size())) { - return "Failed to encrypt plaintext"; - } - assert(plaintext.size() == outlen); - - if (!EVP_CipherFinal_ex(ctx->get(), ciphertext.data() + outlen, &outlen)) { - return "Failed to finalize encryption"; - } - assert(outlen == 0); - - if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagSize, - ciphertext.data() + plaintext.size())) { - return "Failed to retrieve tag"; - } - - return ciphertext; -} - -ErrMsgOr<bytevec> aesGcmDecrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad, - const bytevec& ciphertextWithTag) { - auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, false /* encrypt */); - if (!ctx) return ctx.moveMessage(); - - if (ciphertextWithTag.size() < kAesGcmTagSize) return "Missing tag"; - - bytevec plaintext(ciphertextWithTag.size() - kAesGcmTagSize); - int outlen; - if (!EVP_CipherUpdate(ctx->get(), plaintext.data(), &outlen, ciphertextWithTag.data(), - ciphertextWithTag.size() - kAesGcmTagSize)) { - return "Failed to decrypt plaintext"; - } - assert(plaintext.size() == outlen); - - bytevec tag(ciphertextWithTag.end() - kAesGcmTagSize, ciphertextWithTag.end()); - if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagSize, tag.data())) { - return "Failed to set tag: " + std::to_string(ERR_peek_last_error()); - } - - if (!EVP_CipherFinal_ex(ctx->get(), nullptr, &outlen)) { - return "Failed to finalize encryption"; - } - assert(outlen == 0); - - return plaintext; -} - -} // namespace cppcose diff --git a/security/keymint/support/include/cppcose/cppcose.h b/security/keymint/support/include/cppcose/cppcose.h deleted file mode 100644 index a936bfdb5a..0000000000 --- a/security/keymint/support/include/cppcose/cppcose.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <memory> -#include <optional> -#include <string> -#include <vector> - -#include <cppbor.h> -#include <cppbor_parse.h> - -#include <openssl/cipher.h> -#include <openssl/curve25519.h> -#include <openssl/digest.h> -#include <openssl/hkdf.h> -#include <openssl/hmac.h> -#include <openssl/mem.h> -#include <openssl/sha.h> - -namespace cppcose { - -using bytevec = std::vector<uint8_t>; - -constexpr int kCoseSign1EntryCount = 4; -constexpr int kCoseSign1ProtectedParams = 0; -constexpr int kCoseSign1UnprotectedParams = 1; -constexpr int kCoseSign1Payload = 2; -constexpr int kCoseSign1Signature = 3; - -constexpr int kCoseMac0EntryCount = 4; -constexpr int kCoseMac0ProtectedParams = 0; -constexpr int kCoseMac0UnprotectedParams = 1; -constexpr int kCoseMac0Payload = 2; -constexpr int kCoseMac0Tag = 3; - -constexpr int kCoseEncryptEntryCount = 4; -constexpr int kCoseEncryptProtectedParams = 0; -constexpr int kCoseEncryptUnprotectedParams = 1; -constexpr int kCoseEncryptPayload = 2; -constexpr int kCoseEncryptRecipients = 3; - -enum Label : int { - ALGORITHM = 1, - KEY_ID = 4, - IV = 5, - COSE_KEY = -1, -}; - -enum CoseKeyAlgorithm : int { - AES_GCM_256 = 3, - HMAC_256 = 5, - ES256 = -7, // ECDSA with SHA-256 - EDDSA = -8, - ECDH_ES_HKDF_256 = -25, -}; - -enum CoseKeyCurve : int { P256 = 1, X25519 = 4, ED25519 = 6 }; -enum CoseKeyType : int { OCTET_KEY_PAIR = 1, EC2 = 2, SYMMETRIC_KEY = 4 }; -enum CoseKeyOps : int { SIGN = 1, VERIFY = 2, ENCRYPT = 3, DECRYPT = 4 }; - -constexpr int kAesGcmNonceLength = 12; -constexpr int kAesGcmTagSize = 16; -constexpr int kAesGcmKeySize = 32; - -template <typename T> -class ErrMsgOr { - public: - ErrMsgOr(std::string errMsg) : errMsg_(std::move(errMsg)) {} - ErrMsgOr(const char* errMsg) : errMsg_(errMsg) {} - ErrMsgOr(T val) : value_(std::move(val)) {} - - operator bool() const { return value_.has_value(); } - - T* operator->() & { - assert(value_); - return &value_.value(); - } - T& operator*() & { - assert(value_); - return value_.value(); - }; - T&& operator*() && { - assert(value_); - return std::move(value_).value(); - }; - - const std::string& message() { return errMsg_; } - std::string moveMessage() { return std::move(errMsg_); } - - T moveValue() { - assert(value_); - return std::move(value_).value(); - } - - private: - std::string errMsg_; - std::optional<T> value_; -}; - -class CoseKey { - public: - CoseKey() {} - CoseKey(const CoseKey&) = delete; - CoseKey(CoseKey&&) = default; - - enum Label : int { - KEY_TYPE = 1, - KEY_ID = 2, - ALGORITHM = 3, - KEY_OPS = 4, - CURVE = -1, - PUBKEY_X = -2, - PUBKEY_Y = -3, - PRIVATE_KEY = -4, - TEST_KEY = -70000 // Application-defined - }; - - static ErrMsgOr<CoseKey> parse(const bytevec& coseKey) { - auto [parsedKey, _, errMsg] = cppbor::parse(coseKey); - if (!parsedKey) return errMsg + " when parsing key"; - if (!parsedKey->asMap()) return "CoseKey must be a map"; - return CoseKey(static_cast<cppbor::Map*>(parsedKey.release())); - } - - static ErrMsgOr<CoseKey> parse(const bytevec& coseKey, CoseKeyType expectedKeyType, - CoseKeyAlgorithm expectedAlgorithm, CoseKeyCurve expectedCurve) { - auto key = parse(coseKey); - if (!key) return key; - - if (!key->checkIntValue(CoseKey::KEY_TYPE, expectedKeyType) || - !key->checkIntValue(CoseKey::ALGORITHM, expectedAlgorithm) || - !key->checkIntValue(CoseKey::CURVE, expectedCurve)) { - return "Unexpected key type:"; - } - - return key; - } - - static ErrMsgOr<CoseKey> parseEd25519(const bytevec& coseKey) { - auto key = parse(coseKey, OCTET_KEY_PAIR, EDDSA, ED25519); - if (!key) return key; - - auto& pubkey = key->getMap().get(PUBKEY_X); - if (!pubkey || !pubkey->asBstr() || - pubkey->asBstr()->value().size() != ED25519_PUBLIC_KEY_LEN) { - return "Invalid Ed25519 public key"; - } - - return key; - } - - static ErrMsgOr<CoseKey> parseX25519(const bytevec& coseKey, bool requireKid) { - auto key = parse(coseKey, OCTET_KEY_PAIR, ECDH_ES_HKDF_256, X25519); - if (!key) return key; - - auto& pubkey = key->getMap().get(PUBKEY_X); - if (!pubkey || !pubkey->asBstr() || - pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) { - return "Invalid X25519 public key"; - } - - auto& kid = key->getMap().get(KEY_ID); - if (requireKid && (!kid || !kid->asBstr())) { - return "Missing KID"; - } - - return key; - } - - static ErrMsgOr<CoseKey> parseP256(const bytevec& coseKey) { - auto key = parse(coseKey, EC2, ES256, P256); - if (!key) return key; - - auto& pubkey_x = key->getMap().get(PUBKEY_X); - auto& pubkey_y = key->getMap().get(PUBKEY_Y); - if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() || - pubkey_x->asBstr()->value().size() != 32 || pubkey_y->asBstr()->value().size() != 32) { - return "Invalid P256 public key"; - } - - return key; - } - - std::optional<int> getIntValue(Label label) { - const auto& value = key_->get(label); - if (!value || !value->asInt()) return {}; - return value->asInt()->value(); - } - - std::optional<bytevec> getBstrValue(Label label) { - const auto& value = key_->get(label); - if (!value || !value->asBstr()) return {}; - return value->asBstr()->value(); - } - - const cppbor::Map& getMap() const { return *key_; } - cppbor::Map&& moveMap() { return std::move(*key_); } - - bool checkIntValue(Label label, int expectedValue) { - const auto& value = key_->get(label); - return value && value->asInt() && value->asInt()->value() == expectedValue; - } - - void add(Label label, int value) { key_->add(label, value); } - void add(Label label, bytevec value) { key_->add(label, std::move(value)); } - - bytevec encode() { return key_->canonicalize().encode(); } - - private: - CoseKey(cppbor::Map* parsedKey) : key_(parsedKey) {} - - // This is the full parsed key structure. - std::unique_ptr<cppbor::Map> key_; -}; - -ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad, - const bytevec& payload); -ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad, - const bytevec& payload); -ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem); -ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem, - const bytevec& macKey); - -ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams, - const bytevec& payload, const bytevec& aad); -ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload, - const bytevec& aad); -ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields, - const bytevec& payload, const bytevec& aad); -/** - * Verify and parse a COSE_Sign1 message, returning the payload. - * - * @param ignoreSignature indicates whether signature verification should be skipped. If true, no - * verification of the signature will be done. - * - * @param coseSign1 is the COSE_Sign1 to verify and parse. - * - * @param signingCoseKey is a CBOR-encoded COSE_Key to use to verify the signature. The bytevec may - * be empty, in which case the function assumes that coseSign1's payload is the COSE_Key to - * use, i.e. that coseSign1 is a self-signed "certificate". - */ -ErrMsgOr<bytevec /* payload */> verifyAndParseCoseSign1(bool ignoreSignature, - const cppbor::Array* coseSign1, - const bytevec& signingCoseKey, - const bytevec& aad); - -ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce, - const bytevec& protectedParams, const bytevec& aad); -ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce, - const bytevec& plaintextPayload, const bytevec& aad, - cppbor::Array recipients); -ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt( - const cppbor::Item* encryptItem); -inline ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> -getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item>& encryptItem) { - return getSenderPubKeyFromCoseEncrypt(encryptItem.get()); -} - -ErrMsgOr<bytevec /* plaintextPayload */> decryptCoseEncrypt(const bytevec& key, - const cppbor::Item* encryptItem, - const bytevec& aad); - -ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey, - const bytevec& recipientPubKey, bool senderIsA); - -ErrMsgOr<bytevec /* ciphertextWithTag */> aesGcmEncrypt(const bytevec& key, const bytevec& nonce, - const bytevec& aad, - const bytevec& plaintext); -ErrMsgOr<bytevec /* plaintext */> aesGcmDecrypt(const bytevec& key, const bytevec& nonce, - const bytevec& aad, - const bytevec& ciphertextWithTag); - -} // namespace cppcose diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h index 5e205a27a9..e4261f31bc 100644 --- a/security/keymint/support/include/remote_prov/remote_prov_utils.h +++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h @@ -18,7 +18,7 @@ #include <vector> -#include <cppcose/cppcose.h> +#include <keymaster/cppcose/cppcose.h> namespace aidl::android::hardware::security::keymint::remote_prov { |