mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:50:18 +00:00
Include the CWT validation in VTS testing.
This change modifies the VTS tests to validate the structure of the CBOR Web Token (CWT) which contains the public key as one of several fields in the map. It only validates the subset of fields expected to be seen in the VTS tests. The ones related to the actual BCC will not be present in test mode due to the security guarantees of the interface. Additionally, the test will also now check that the first key in the BCC array matches the public key that should be self-signed in the certificate located in the second index of the BCC array. Bug: 219962281 Test: atest VtsHalRemotelyProvisionedComponentTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:81880284af9f8d6f82d8fbd4b82c70307fcb3762) Merged-In: I9e7769861529b8095d77ce8fee3c78222579d38c Change-Id: I9e7769861529b8095d77ce8fee3c78222579d38c
This commit is contained in:
committed by
Subrahmanya Manikanta Venkateswarlu Bhamidipati Kameswara Sri
parent
12b2c93b10
commit
b326f33fbc
@@ -26,6 +26,11 @@
|
||||
|
||||
namespace aidl::android::hardware::security::keymint::remote_prov {
|
||||
|
||||
constexpr uint32_t kBccPayloadIssuer = 1;
|
||||
constexpr uint32_t kBccPayloadSubject = 2;
|
||||
constexpr int32_t kBccPayloadSubjPubKey = -4670552;
|
||||
constexpr int32_t kBccPayloadKeyUsage = -4670553;
|
||||
|
||||
bytevec kTestMacKey(32 /* count */, 0 /* byte value */);
|
||||
|
||||
bytevec randomBytes(size_t numBytes) {
|
||||
@@ -98,6 +103,18 @@ bytevec getProdEekChain() {
|
||||
return prodEek;
|
||||
}
|
||||
|
||||
ErrMsgOr<bytevec> validatePayloadAndFetchPubKey(const cppbor::Map* payload) {
|
||||
const auto& issuer = payload->get(kBccPayloadIssuer);
|
||||
if (!issuer || !issuer->asTstr()) return "Issuer is not present or not a tstr.";
|
||||
const auto& subject = payload->get(kBccPayloadSubject);
|
||||
if (!subject || !subject->asTstr()) return "Subject is not present or not a tstr.";
|
||||
const auto& keyUsage = payload->get(kBccPayloadKeyUsage);
|
||||
if (!keyUsage || !keyUsage->asBstr()) return "Key usage is not present or not a bstr.";
|
||||
const auto& serializedKey = payload->get(kBccPayloadSubjPubKey);
|
||||
if (!serializedKey || !serializedKey->asBstr()) return "Key is not present or not a bstr.";
|
||||
return serializedKey->asBstr()->value();
|
||||
}
|
||||
|
||||
ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
|
||||
const bytevec& signingCoseKey, const bytevec& aad) {
|
||||
if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
|
||||
@@ -126,18 +143,16 @@ ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
|
||||
return "Unsupported signature algorithm";
|
||||
}
|
||||
|
||||
// TODO(jbires): Handle CWTs as the CoseSign1 payload in a less hacky way. Since the CWT payload
|
||||
// is extremely remote provisioning specific, probably just make a separate
|
||||
// function there.
|
||||
auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(payload);
|
||||
if (!parsedPayload) return payloadErrMsg + " when parsing key";
|
||||
if (!parsedPayload->asMap()) return "CWT must be a map";
|
||||
auto serializedKey = parsedPayload->asMap()->get(-4670552)->clone();
|
||||
if (!serializedKey || !serializedKey->asBstr()) return "Could not find key entry";
|
||||
auto serializedKey = validatePayloadAndFetchPubKey(parsedPayload->asMap());
|
||||
if (!serializedKey) {
|
||||
return "CWT validation failed: " + serializedKey.moveMessage();
|
||||
}
|
||||
|
||||
bool selfSigned = signingCoseKey.empty();
|
||||
auto key =
|
||||
CoseKey::parseEd25519(selfSigned ? serializedKey->asBstr()->value() : signingCoseKey);
|
||||
auto key = CoseKey::parseEd25519(selfSigned ? *serializedKey : signingCoseKey);
|
||||
if (!key) return "Bad signing key: " + key.moveMessage();
|
||||
|
||||
bytevec signatureInput =
|
||||
@@ -148,7 +163,7 @@ ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
|
||||
return "Signature verification failed";
|
||||
}
|
||||
|
||||
return serializedKey->asBstr()->value();
|
||||
return serializedKey.moveValue();
|
||||
}
|
||||
|
||||
ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc) {
|
||||
@@ -156,8 +171,11 @@ ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc) {
|
||||
|
||||
std::vector<BccEntryData> result;
|
||||
|
||||
const auto& devicePubKey = bcc->get(0);
|
||||
if (!devicePubKey->asMap()) return "Invalid device public key at the 1st entry in the BCC";
|
||||
|
||||
bytevec prevKey;
|
||||
// TODO(jbires): Actually process the pubKey at the start of the new bcc entry
|
||||
|
||||
for (size_t i = 1; i < bcc->size(); ++i) {
|
||||
const cppbor::Array* entry = bcc->get(i)->asArray();
|
||||
if (!entry || entry->size() != kCoseSign1EntryCount) {
|
||||
@@ -177,6 +195,13 @@ ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc) {
|
||||
|
||||
// This entry's public key is the signing key for the next entry.
|
||||
prevKey = payload.moveValue();
|
||||
if (i == 1) {
|
||||
auto [parsedRootKey, _, errMsg] = cppbor::parse(prevKey);
|
||||
if (!parsedRootKey || !parsedRootKey->asMap()) return "Invalid payload entry in BCC.";
|
||||
if (*parsedRootKey != *devicePubKey) {
|
||||
return "Device public key doesn't match BCC root.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user