summaryrefslogtreecommitdiff
path: root/security/keymint/support/remote_prov_utils.cpp
diff options
context:
space:
mode:
authorMax Bires <jbires@google.com>2022-01-30 17:28:13 -0800
committerMax Bires <jbires@google.com>2022-02-02 02:13:26 +0000
commit81880284af9f8d6f82d8fbd4b82c70307fcb3762 (patch)
treeaa77ddebb3f91c60714a6774fc068a52a9657691 /security/keymint/support/remote_prov_utils.cpp
parentc96879a0ce955c5a8a987aabdd3b7f35424f8fc9 (diff)
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. Test: atest VtsHalRemotelyProvisionedComponentTargetTest Change-Id: I9e7769861529b8095d77ce8fee3c78222579d38c
Diffstat (limited to 'security/keymint/support/remote_prov_utils.cpp')
-rw-r--r--security/keymint/support/remote_prov_utils.cpp43
1 files changed, 34 insertions, 9 deletions
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 0cbee51044..35cb891dac 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -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;