diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp index 8d7731cd55..ce72c81a87 100644 --- a/security/keymint/support/Android.bp +++ b/security/keymint/support/Android.bp @@ -66,6 +66,9 @@ cc_library { static_libs: [ "android.hardware.security.rkp-V3-ndk", ], + whole_static_libs: [ + "libcert_request_validator_cxx", + ], shared_libs: [ "libbase", "libbinder_ndk", 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 1b94c62d66..79189a1cca 100644 --- a/security/keymint/support/include/remote_prov/remote_prov_utils.h +++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h @@ -108,15 +108,6 @@ struct BccEntryData { bytevec pubKey; }; -/** - * Validates the provided CBOR-encoded BCC, returning a vector of BccEntryData - * structs containing the BCC entry contents. If an entry contains no firmware - * digest, the corresponding BccEntryData.firmwareDigest will have length zero - * (there's no way to distinguish between an empty and missing firmware digest, - * which seems fine). - */ -ErrMsgOr> validateBcc(const cppbor::Array* bcc); - struct JsonOutput { static JsonOutput Ok(std::string json) { return {std::move(json), ""}; } static JsonOutput Error(std::string error) { return {"", std::move(error)}; } diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp index ea0fbd8e91..3d8de28658 100644 --- a/security/keymint/support/remote_prov_utils.cpp +++ b/security/keymint/support/remote_prov_utils.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -289,129 +290,16 @@ bytevec getProdEekChain(int32_t supportedEekCurve) { return chain.encode(); } -ErrMsgOr 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 verifyAndParseCoseSign1Cwt(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 && algorithm->asInt()->value() != ES256)) { - return "Unsupported signature algorithm"; - } - - auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(payload); - if (!parsedPayload) return payloadErrMsg + " when parsing key"; - if (!parsedPayload->asMap()) return "CWT must be a map"; - auto serializedKey = validatePayloadAndFetchPubKey(parsedPayload->asMap()); - if (!serializedKey) { - return "CWT validation failed: " + serializedKey.moveMessage(); - } - - bool selfSigned = signingCoseKey.empty(); - bytevec signatureInput = - 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(), - key->getBstrValue(CoseKey::PUBKEY_X)->data())) { - 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(); -} - ErrMsgOr> validateBcc(const cppbor::Array* bcc) { - if (!bcc || bcc->size() == 0) return "Invalid BCC"; - + auto encodedBcc = bcc->encode(); + auto chain = cert_request_validator::DiceChain::verify(encodedBcc); + if (!chain.ok()) return chain.error().message(); + auto keys = chain->cose_public_keys(); + if (!keys.ok()) return keys.error().message(); std::vector result; - - const auto& devicePubKey = bcc->get(0); - if (!devicePubKey->asMap()) return "Invalid device public key at the 1st entry in the BCC"; - - bytevec prevKey; - - for (size_t i = 1; i < bcc->size(); ++i) { - const cppbor::Array* entry = bcc->get(i)->asArray(); - if (!entry || entry->size() != kCoseSign1EntryCount) { - return "Invalid BCC entry " + std::to_string(i) + ": " + prettyPrint(entry); - } - auto payload = verifyAndParseCoseSign1Cwt(entry, std::move(prevKey), bytevec{} /* AAD */); - if (!payload) { - return "Failed to verify entry " + std::to_string(i) + ": " + payload.moveMessage(); - } - - auto& certProtParms = entry->get(kCoseSign1ProtectedParams); - if (!certProtParms || !certProtParms->asBstr()) return "Invalid prot params"; - auto [parsedProtParms, _, errMsg] = cppbor::parse(certProtParms->asBstr()->value()); - if (!parsedProtParms || !parsedProtParms->asMap()) return "Invalid prot params"; - - result.push_back(BccEntryData{*payload}); - - // 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."; - } - } + for (auto& key : *keys) { + result.push_back({std::move(key)}); } - return result; } @@ -685,9 +573,6 @@ ErrMsgOr> verifyProtectedData( 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); @@ -979,9 +864,6 @@ ErrMsgOr parseAndValidateAuthenticatedRequest(const std::vectorsize() == 0U) { - return "The DICE chain is empty. It must contain at least one entry."; - } auto& udsPub = diceContents->back().pubKey;