Merge "Sync audio_policy_engine_configuration.xsd with the SDK"
diff --git a/radio/aidl/OWNERS b/radio/aidl/OWNERS
new file mode 100644
index 0000000..7b01aad
--- /dev/null
+++ b/radio/aidl/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 20868
+include ../1.0/vts/OWNERS
+
diff --git a/radio/aidl/vts/OWNERS b/radio/aidl/vts/OWNERS
deleted file mode 100644
index e75c6c8..0000000
--- a/radio/aidl/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 20868
-include ../../1.0/vts/OWNERS
-
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 2e282e0..e1f65fe 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <memory>
+#include <string>
#define LOG_TAG "VtsRemotelyProvisionableComponentTests"
#include <AndroidRemotelyProvisionedComponentDevice.h>
@@ -58,26 +60,6 @@
using namespace remote_prov;
using namespace keymaster;
-std::set<std::string> getAllowedVbStates() {
- return {"green", "yellow", "orange"};
-}
-
-std::set<std::string> getAllowedBootloaderStates() {
- return {"locked", "unlocked"};
-}
-
-std::set<std::string> getAllowedSecurityLevels() {
- return {"tee", "strongbox"};
-}
-
-std::set<std::string> getAllowedAttIdStates() {
- return {"locked", "open"};
-}
-
-std::set<std::string> getAttestationIdEntrySet() {
- return {"brand", "manufacturer", "product", "model", "device"};
-}
-
bytevec string_to_bytevec(const char* s) {
const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
return bytevec(p, p + strlen(s));
@@ -387,177 +369,6 @@
}
}
- 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,
- const bytevec& keysToSignMac, const ProtectedData& protectedData,
- std::vector<BccEntryData>* bccOutput = nullptr) {
- 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 = getSessionKey(senderPubkey);
- 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());
- // Strongbox may contain additional certificate chain.
- EXPECT_LE(parsedPayload->asArray()->size(), 3U);
-
- 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 [deviceInfoMap, __2, deviceInfoErrMsg] = cppbor::parse(deviceInfo.deviceInfo);
- ASSERT_TRUE(deviceInfoMap) << "Failed to parse deviceInfo: " << deviceInfoErrMsg;
- ASSERT_TRUE(deviceInfoMap->asMap());
- checkDeviceInfo(*deviceInfoMap->asMap(), deviceInfo.deviceInfo);
- auto& signingKey = bccContents->back().pubKey;
- deviceInfoMap->asMap()->canonicalize();
- auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
- cppbor::Array() // SignedMacAad
- .add(challenge_)
- .add(std::move(deviceInfoMap))
- .add(keysToSignMac)
- .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();
-
- if (bccOutput) {
- *bccOutput = std::move(*bccContents);
- }
- }
-
- std::optional<std::string> assertAttribute(const cppbor::Map& devInfo,
- cppbor::MajorType majorType, std::string entryName) {
- const auto& val = devInfo.get(entryName);
- if (!val) return entryName + " is missing.\n";
- if (val->type() != majorType) return entryName + " has the wrong type.\n";
- switch (majorType) {
- case cppbor::TSTR:
- if (val->asTstr()->value().size() <= 0) {
- return entryName + " is present but the value is empty.\n";
- }
- break;
- case cppbor::BSTR:
- if (val->asBstr()->value().size() <= 0) {
- return entryName + " is present but the value is empty.\n";
- }
- break;
- default:
- break;
- }
- return {};
- }
-
- void checkType(const cppbor::Map& devInfo, cppbor::MajorType majorType, std::string entryName) {
- if (auto error = assertAttribute(devInfo, majorType, entryName)) {
- FAIL() << *error;
- }
- }
-
- void checkDeviceInfo(const cppbor::Map& deviceInfo, bytevec deviceInfoBytes) {
- EXPECT_EQ(deviceInfo.clone()->asMap()->canonicalize().encode(), deviceInfoBytes)
- << "DeviceInfo ordering is non-canonical.";
- const auto& version = deviceInfo.get("version");
- ASSERT_TRUE(version);
- ASSERT_TRUE(version->asUint());
- RpcHardwareInfo info;
- provisionable_->getHardwareInfo(&info);
- ASSERT_EQ(version->asUint()->value(), info.versionNumber);
- std::set<std::string> allowList;
- std::string problemEntries;
- switch (version->asUint()->value()) {
- // These fields became mandated in version 2.
- case 2:
- for (auto attId : getAttestationIdEntrySet()) {
- if (auto errMsg = assertAttribute(deviceInfo, cppbor::TSTR, attId)) {
- problemEntries += *errMsg;
- }
- }
- EXPECT_EQ("", problemEntries)
- << problemEntries
- << "Attestation IDs are missing or malprovisioned. If this test is being "
- "run against an early proto or EVT build, this error is probably WAI "
- "and indicates that Device IDs were not provisioned in the factory. If "
- "this error is returned on a DVT or later build revision, then "
- "something is likely wrong with the factory provisioning process.";
- // TODO: Refactor the KeyMint code that validates these fields and include it here.
- checkType(deviceInfo, cppbor::TSTR, "vb_state");
- allowList = getAllowedVbStates();
- EXPECT_NE(allowList.find(deviceInfo.get("vb_state")->asTstr()->value()),
- allowList.end());
- checkType(deviceInfo, cppbor::TSTR, "bootloader_state");
- allowList = getAllowedBootloaderStates();
- EXPECT_NE(allowList.find(deviceInfo.get("bootloader_state")->asTstr()->value()),
- allowList.end());
- checkType(deviceInfo, cppbor::BSTR, "vbmeta_digest");
- checkType(deviceInfo, cppbor::UINT, "system_patch_level");
- checkType(deviceInfo, cppbor::UINT, "boot_patch_level");
- checkType(deviceInfo, cppbor::UINT, "vendor_patch_level");
- checkType(deviceInfo, cppbor::UINT, "fused");
- EXPECT_LT(deviceInfo.get("fused")->asUint()->value(), 2); // Must be 0 or 1.
- checkType(deviceInfo, cppbor::TSTR, "security_level");
- allowList = getAllowedSecurityLevels();
- EXPECT_NE(allowList.find(deviceInfo.get("security_level")->asTstr()->value()),
- allowList.end());
- if (deviceInfo.get("security_level")->asTstr()->value() == "tee") {
- checkType(deviceInfo, cppbor::TSTR, "os_version");
- }
- break;
- case 1:
- checkType(deviceInfo, cppbor::TSTR, "security_level");
- allowList = getAllowedSecurityLevels();
- EXPECT_NE(allowList.find(deviceInfo.get("security_level")->asTstr()->value()),
- allowList.end());
- if (version->asUint()->value() == 1) {
- checkType(deviceInfo, cppbor::TSTR, "att_id_state");
- allowList = getAllowedAttIdStates();
- EXPECT_NE(allowList.find(deviceInfo.get("att_id_state")->asTstr()->value()),
- allowList.end());
- }
- break;
- default:
- FAIL() << "Unrecognized version: " << version->asUint()->value();
- }
- }
-
bytevec eekId_;
size_t testEekLength_;
EekChain testEekChain_;
@@ -584,7 +395,10 @@
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
- checkProtectedData(deviceInfo, cppbor::Array(), keysToSignMac, protectedData);
+ auto result = verifyProductionProtectedData(
+ deviceInfo, cppbor::Array(), keysToSignMac, protectedData, testEekChain_, eekId_,
+ rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+ ASSERT_TRUE(result) << result.message();
}
}
@@ -606,22 +420,24 @@
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
- std::vector<BccEntryData> firstBcc;
- checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
- &firstBcc);
+ auto firstBcc = verifyProductionProtectedData(
+ deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
+ eekId_, rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+ ASSERT_TRUE(firstBcc) << firstBcc.message();
status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
- std::vector<BccEntryData> secondBcc;
- checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
- &secondBcc);
+ auto secondBcc = verifyProductionProtectedData(
+ deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
+ eekId_, rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+ ASSERT_TRUE(secondBcc) << secondBcc.message();
// Verify that none of the keys in the first BCC are repeated in the second one.
- for (const auto& i : firstBcc) {
- for (auto& j : secondBcc) {
+ for (const auto& i : *firstBcc) {
+ for (auto& j : *secondBcc) {
ASSERT_THAT(i.pubKey, testing::Not(testing::ElementsAreArray(j.pubKey)))
<< "Found a repeated pubkey in two generateCertificateRequest test mode calls";
}
@@ -664,7 +480,10 @@
&keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
- checkProtectedData(deviceInfo, cborKeysToSign_, keysToSignMac, protectedData);
+ auto result = verifyProductionProtectedData(
+ deviceInfo, cborKeysToSign_, keysToSignMac, protectedData, testEekChain_, eekId_,
+ rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+ ASSERT_TRUE(result) << result.message();
}
}
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index bf2ab02..3f48320 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -65,6 +65,7 @@
],
shared_libs: [
"libbase",
+ "libbinder_ndk",
"libcppbor_external",
"libcppcose_rkp",
"libcrypto",
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 f3b8608..9ea20ac 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -16,7 +16,9 @@
#pragma once
+#include <memory>
#include <vector>
+#include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h"
#include <keymaster/cppcose/cppcose.h>
@@ -139,4 +141,40 @@
JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name,
const cppbor::Array& csr);
+/**
+ * Parses a DeviceInfo structure from the given CBOR data. The parsed data is then validated to
+ * ensure it contains the minimum required data at the time of manufacturing. This is only a
+ * partial validation, as some fields may not be provisioned yet at the time this information
+ * is parsed in the manufacturing process.
+ */
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateFactoryDeviceInfo(
+ const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable);
+
+/**
+ * Parses a DeviceInfo structure from the given CBOR data. The parsed data is then validated to
+ * ensure it is formatted correctly and that it contains the required values for Remote Key
+ * Provisioning. This is a full validation, and assumes the device is provisioned as if it is
+ * suitable for the end user.
+ */
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateProductionDeviceInfo(
+ const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable);
+
+/**
+ * Verify the protected data as if the device is still early in the factory process and may not
+ * have all device identifiers provisioned yet.
+ */
+ErrMsgOr<std::vector<BccEntryData>> verifyFactoryProtectedData(
+ const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+ const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+/**
+ * Verify the protected data as if the device is a final production sample.
+ */
+ErrMsgOr<std::vector<BccEntryData>> verifyProductionProtectedData(
+ const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+ const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+
} // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 0dbea5b..0651496 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -15,7 +15,11 @@
*/
#include <iterator>
+#include <memory>
+#include <set>
+#include <string>
#include <tuple>
+#include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h"
#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
#include <android-base/properties.h>
@@ -441,4 +445,293 @@
return JsonOutput::Ok(Json::writeString(factory, json));
}
-} // namespace aidl::android::hardware::security::keymint::remote_prov
+std::string checkMapEntry(bool isFactory, const cppbor::Map& devInfo, cppbor::MajorType majorType,
+ const std::string& entryName) {
+ const std::unique_ptr<cppbor::Item>& val = devInfo.get(entryName);
+ if (!val) {
+ return entryName + " is missing.\n";
+ }
+ if (val->type() != majorType) {
+ return entryName + " has the wrong type.\n";
+ }
+ if (isFactory) {
+ return "";
+ }
+ switch (majorType) {
+ case cppbor::TSTR:
+ if (val->asTstr()->value().size() <= 0) {
+ return entryName + " is present but the value is empty.\n";
+ }
+ break;
+ case cppbor::BSTR:
+ if (val->asBstr()->value().size() <= 0) {
+ return entryName + " is present but the value is empty.\n";
+ }
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+std::string checkMapEntry(bool isFactory, const cppbor::Map& devInfo, cppbor::MajorType majorType,
+ const std::string& entryName, const cppbor::Array& allowList) {
+ std::string error = checkMapEntry(isFactory, devInfo, majorType, entryName);
+ if (!error.empty()) {
+ return error;
+ }
+
+ if (isFactory) {
+ return "";
+ }
+
+ const std::unique_ptr<cppbor::Item>& val = devInfo.get(entryName);
+ for (auto i = allowList.begin(); i != allowList.end(); ++i) {
+ if (**i == *val) {
+ return "";
+ }
+ }
+ return entryName + " has an invalid value.\n";
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateDeviceInfo(
+ const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable,
+ bool isFactory) {
+ const cppbor::Array kValidVbStates = {"green", "yellow", "orange"};
+ const cppbor::Array kValidBootloaderStates = {"locked", "unlocked"};
+ const cppbor::Array kValidSecurityLevels = {"tee", "strongbox"};
+ const cppbor::Array kValidAttIdStates = {"locked", "open"};
+ const cppbor::Array kValidFused = {0, 1};
+
+ struct AttestationIdEntry {
+ const char* id;
+ bool alwaysValidate;
+ };
+ constexpr AttestationIdEntry kAttestationIdEntrySet[] = {{"brand", false},
+ {"manufacturer", true},
+ {"product", false},
+ {"model", false},
+ {"device", false}};
+
+ auto [parsedVerifiedDeviceInfo, ignore1, errMsg] = cppbor::parse(deviceInfoBytes);
+ if (!parsedVerifiedDeviceInfo) {
+ return errMsg;
+ }
+
+ std::unique_ptr<cppbor::Map> parsed(parsedVerifiedDeviceInfo->asMap());
+ if (!parsed) {
+ return "DeviceInfo must be a CBOR map.";
+ }
+ parsedVerifiedDeviceInfo.release();
+
+ if (parsed->clone()->asMap()->canonicalize().encode() != deviceInfoBytes) {
+ return "DeviceInfo ordering is non-canonical.";
+ }
+ const std::unique_ptr<cppbor::Item>& version = parsed->get("version");
+ if (!version) {
+ return "Device info is missing version";
+ }
+ if (!version->asUint()) {
+ return "version must be an unsigned integer";
+ }
+ RpcHardwareInfo info;
+ provisionable->getHardwareInfo(&info);
+ if (version->asUint()->value() != info.versionNumber) {
+ return "DeviceInfo version (" + std::to_string(version->asUint()->value()) +
+ ") does not match the remotely provisioned component version (" +
+ std::to_string(info.versionNumber) + ").";
+ }
+ std::string error;
+ switch (version->asUint()->value()) {
+ case 2:
+ for (const auto& entry : kAttestationIdEntrySet) {
+ error += checkMapEntry(isFactory && !entry.alwaysValidate, *parsed, cppbor::TSTR,
+ entry.id);
+ }
+ if (!error.empty()) {
+ return error +
+ "Attestation IDs are missing or malprovisioned. If this test is being\n"
+ "run against an early proto or EVT build, this error is probably WAI\n"
+ "and indicates that Device IDs were not provisioned in the factory. If\n"
+ "this error is returned on a DVT or later build revision, then\n"
+ "something is likely wrong with the factory provisioning process.";
+ }
+ // TODO: Refactor the KeyMint code that validates these fields and include it here.
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "vb_state", kValidVbStates);
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "bootloader_state",
+ kValidBootloaderStates);
+ error += checkMapEntry(isFactory, *parsed, cppbor::BSTR, "vbmeta_digest");
+ error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "system_patch_level");
+ error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "boot_patch_level");
+ error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "vendor_patch_level");
+ error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "fused", kValidFused);
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "security_level",
+ kValidSecurityLevels);
+ if (parsed->get("security_level") && parsed->get("security_level")->asTstr() &&
+ parsed->get("security_level")->asTstr()->value() == "tee") {
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "os_version");
+ }
+ break;
+ case 1:
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "security_level",
+ kValidSecurityLevels);
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "att_id_state",
+ kValidAttIdStates);
+ break;
+ default:
+ return "Unrecognized version: " + std::to_string(version->asUint()->value());
+ }
+
+ if (!error.empty()) {
+ return error;
+ }
+
+ return std::move(parsed);
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateFactoryDeviceInfo(
+ const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable) {
+ return parseAndValidateDeviceInfo(deviceInfoBytes, provisionable, /*isFactory=*/true);
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateProductionDeviceInfo(
+ const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable) {
+ return parseAndValidateDeviceInfo(deviceInfoBytes, provisionable, /*isFactory=*/false);
+}
+
+ErrMsgOr<bytevec> getSessionKey(ErrMsgOr<std::pair<bytevec, bytevec>>& senderPubkey,
+ const EekChain& eekChain, int32_t supportedEekCurve) {
+ if (supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
+ supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
+ return x25519_HKDF_DeriveKey(eekChain.last_pubkey, eekChain.last_privkey,
+ senderPubkey->first, false /* senderIsA */);
+ } else {
+ return ECDH_HKDF_DeriveKey(eekChain.last_pubkey, eekChain.last_privkey, senderPubkey->first,
+ false /* senderIsA */);
+ }
+}
+
+ErrMsgOr<std::vector<BccEntryData>> verifyProtectedData(
+ const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+ const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge,
+ bool isFactory) {
+ auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
+ if (!parsedProtectedData) {
+ return protDataErrMsg;
+ }
+ if (!parsedProtectedData->asArray()) {
+ return "Protected data is not a CBOR array.";
+ }
+ if (parsedProtectedData->asArray()->size() != kCoseEncryptEntryCount) {
+ return "The protected data COSE_encrypt structure must have " +
+ std::to_string(kCoseEncryptEntryCount) + " entries, but it only has " +
+ std::to_string(parsedProtectedData->asArray()->size());
+ }
+
+ auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
+ if (!senderPubkey) {
+ return senderPubkey.message();
+ }
+ if (senderPubkey->second != eekId) {
+ return "The COSE_encrypt recipient does not match the expected EEK identifier";
+ }
+
+ auto sessionKey = getSessionKey(senderPubkey, eekChain, supportedEekCurve);
+ if (!sessionKey) {
+ return sessionKey.message();
+ }
+
+ auto protectedDataPayload =
+ decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
+ if (!protectedDataPayload) {
+ return protectedDataPayload.message();
+ }
+
+ auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
+ if (!parsedPayload) {
+ return "Failed to parse payload: " + payloadErrMsg;
+ }
+ if (!parsedPayload->asArray()) {
+ return "The protected data payload must be an Array.";
+ }
+ if (parsedPayload->asArray()->size() != 3U && parsedPayload->asArray()->size() != 2U) {
+ return "The protected data payload must contain SignedMAC and BCC. It may optionally "
+ "contain AdditionalDKSignatures. However, the parsed payload has " +
+ std::to_string(parsedPayload->asArray()->size()) + " entries.";
+ }
+
+ auto& signedMac = parsedPayload->asArray()->get(0);
+ auto& bcc = parsedPayload->asArray()->get(1);
+ if (!signedMac->asArray()) {
+ return "The SignedMAC in the protected data payload is not an Array.";
+ }
+ if (!bcc->asArray()) {
+ return "The BCC in the protected data payload is not an Array.";
+ }
+
+ // BCC is [ pubkey, + BccEntry]
+ auto bccContents = validateBcc(bcc->asArray());
+ if (!bccContents) {
+ return bccContents.message() + "\n" + prettyPrint(bcc.get());
+ }
+ if (bccContents->size() == 0U) {
+ return "The BCC is empty. It must contain at least one entry.";
+ }
+
+ auto deviceInfoResult =
+ parseAndValidateDeviceInfo(deviceInfo.deviceInfo, provisionable, isFactory);
+ if (!deviceInfoResult) {
+ return deviceInfoResult.message();
+ }
+ std::unique_ptr<cppbor::Map> deviceInfoMap = deviceInfoResult.moveValue();
+ auto& signingKey = bccContents->back().pubKey;
+ auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
+ cppbor::Array() // SignedMacAad
+ .add(challenge)
+ .add(std::move(deviceInfoMap))
+ .add(keysToSignMac)
+ .encode());
+ if (!macKey) {
+ return 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);
+ if (!macPayload) {
+ return macPayload.message();
+ }
+
+ return *bccContents;
+}
+
+ErrMsgOr<std::vector<BccEntryData>> verifyFactoryProtectedData(
+ const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+ const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+ return verifyProtectedData(deviceInfo, keysToSign, keysToSignMac, protectedData, eekChain,
+ eekId, supportedEekCurve, provisionable, challenge,
+ /*isFactory=*/true);
+}
+
+ErrMsgOr<std::vector<BccEntryData>> verifyProductionProtectedData(
+ const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+ const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+ return verifyProtectedData(deviceInfo, keysToSign, keysToSignMac, protectedData, eekChain,
+ eekId, supportedEekCurve, provisionable, challenge,
+ /*isFactory=*/false);
+}
+
+} // namespace aidl::android::hardware::security::keymint::remote_prov
\ No newline at end of file