rkp_factory_extraction_tool now validates DeviceInfo
This way, partners doing testing can see if they are getting bad device
info before they try to upload it to the backend.
This also acts as a check on the factory line, in case a device is
misprovisioned or defective, it can be discoverd earlier in the
manufacturing process (as CSRs tend to be uploaded at the very end).
Test: atest VtsHalRemotelyProvisionedComponentTargetTest
Test: rkp_factory_extraction_tool
Bug: 239838563
Change-Id: I8da97a9740cccb3263d21b07ba9d678513a337c8
diff --git a/provisioner/rkp_factory_extraction_lib.cpp b/provisioner/rkp_factory_extraction_lib.cpp
index 3bf3d7e..831adba 100644
--- a/provisioner/rkp_factory_extraction_lib.cpp
+++ b/provisioner/rkp_factory_extraction_lib.cpp
@@ -19,6 +19,10 @@
#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
#include <android/binder_manager.h>
#include <cppbor.h>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
#include <keymaster/cppcose/cppcose.h>
#include <openssl/base64.h>
#include <remote_prov/remote_prov_utils.h>
@@ -39,6 +43,7 @@
using aidl::android::hardware::security::keymint::RpcHardwareInfo;
using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain;
using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
+using aidl::android::hardware::security::keymint::remote_prov::parseAndValidateDeviceInfo;
using namespace cppbor;
using namespace cppcose;
@@ -89,29 +94,30 @@
return challenge;
}
-CsrResult composeCertificateRequest(const ProtectedData& protectedData,
- const DeviceInfo& verifiedDeviceInfo,
- const std::vector<uint8_t>& challenge,
- const std::vector<uint8_t>& keysToSignMac) {
+CborResult<Array> composeCertificateRequest(const ProtectedData& protectedData,
+ const DeviceInfo& verifiedDeviceInfo,
+ const std::vector<uint8_t>& challenge,
+ const std::vector<uint8_t>& keysToSignMac,
+ IRemotelyProvisionedComponent* provisionable) {
Array macedKeysToSign = Array()
.add(Map().add(1, 5).encode()) // alg: hmac-sha256
.add(Map()) // empty unprotected headers
.add(Null()) // nil for the payload
.add(keysToSignMac); // MAC as returned from the HAL
- auto [parsedVerifiedDeviceInfo, ignore1, errMsg] = parse(verifiedDeviceInfo.deviceInfo);
+ ErrMsgOr<std::unique_ptr<Map>> parsedVerifiedDeviceInfo =
+ parseAndValidateDeviceInfo(verifiedDeviceInfo.deviceInfo, provisionable);
if (!parsedVerifiedDeviceInfo) {
- std::cerr << "Error parsing device info: '" << errMsg << "'" << std::endl;
- return {nullptr, errMsg};
+ return {nullptr, parsedVerifiedDeviceInfo.moveMessage()};
}
- auto [parsedProtectedData, ignore2, errMsg2] = parse(protectedData.protectedData);
+ auto [parsedProtectedData, ignore2, errMsg] = parse(protectedData.protectedData);
if (!parsedProtectedData) {
- std::cerr << "Error parsing protected data: '" << errMsg2 << "'" << std::endl;
+ std::cerr << "Error parsing protected data: '" << errMsg << "'" << std::endl;
return {nullptr, errMsg};
}
- Array deviceInfo = Array().add(std::move(parsedVerifiedDeviceInfo)).add(Map());
+ Array deviceInfo = Array().add(parsedVerifiedDeviceInfo.moveValue()).add(Map());
auto certificateRequest = std::make_unique<Array>();
(*certificateRequest)
@@ -119,10 +125,10 @@
.add(challenge)
.add(std::move(parsedProtectedData))
.add(std::move(macedKeysToSign));
- return {std::move(certificateRequest), std::nullopt};
+ return {std::move(certificateRequest), ""};
}
-CsrResult getCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
+CborResult<Array> getCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
std::vector<uint8_t> keysToSignMac;
std::vector<MacedPublicKey> emptyKeys;
DeviceInfo verifiedDeviceInfo;
@@ -145,5 +151,6 @@
<< "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
exit(-1);
}
- return composeCertificateRequest(protectedData, verifiedDeviceInfo, challenge, keysToSignMac);
+ return composeCertificateRequest(protectedData, verifiedDeviceInfo, challenge, keysToSignMac,
+ irpc);
}
diff --git a/provisioner/rkp_factory_extraction_lib.h b/provisioner/rkp_factory_extraction_lib.h
index fe15402..808ce7c 100644
--- a/provisioner/rkp_factory_extraction_lib.h
+++ b/provisioner/rkp_factory_extraction_lib.h
@@ -21,17 +21,17 @@
#include <cstdint>
#include <memory>
-#include <optional>
#include <string>
+#include <string_view>
#include <vector>
constexpr size_t kChallengeSize = 16;
-// Contains the result of CSR generation, bundling up the result (on success)
-// with an error message (on failure).
-struct CsrResult {
- std::unique_ptr<cppbor::Array> csr;
- std::optional<std::string> errMsg;
+// Contains a the result of an operation that should return cborData on success.
+// Returns an an error message and null cborData on error.
+template <typename T> struct CborResult {
+ std::unique_ptr<T> cborData;
+ std::string errMsg;
};
// Return `buffer` encoded as a base64 string.
@@ -43,5 +43,6 @@
// Get a certificate signing request for the given IRemotelyProvisionedComponent.
// On error, the csr Array is null, and the string field contains a description of
// what went wrong.
-CsrResult getCsr(std::string_view componentName,
- aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent* irpc);
\ No newline at end of file
+CborResult<cppbor::Array>
+getCsr(std::string_view componentName,
+ aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent* irpc);
\ No newline at end of file
diff --git a/provisioner/rkp_factory_extraction_lib_test.cpp b/provisioner/rkp_factory_extraction_lib_test.cpp
index c611097..b27b717 100644
--- a/provisioner/rkp_factory_extraction_lib_test.cpp
+++ b/provisioner/rkp_factory_extraction_lib_test.cpp
@@ -16,6 +16,8 @@
#include "rkp_factory_extraction_lib.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock-more-matchers.h"
#include <aidl/android/hardware/security/keymint/DeviceInfo.h>
#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
#include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
@@ -24,6 +26,7 @@
#include <gtest/gtest.h>
#include <cstdint>
+#include <memory>
#include <ostream>
#include <set>
#include <vector>
@@ -126,7 +129,20 @@
Map cborDeviceInfo;
cborDeviceInfo.add("product", "gShoe");
cborDeviceInfo.add("version", 2);
- const DeviceInfo kVerifiedDeviceInfo = {cborDeviceInfo.encode()};
+ cborDeviceInfo.add("brand", "Fake Brand");
+ cborDeviceInfo.add("manufacturer", "Fake Mfr");
+ cborDeviceInfo.add("model", "Fake Model");
+ cborDeviceInfo.add("device", "Fake Device");
+ cborDeviceInfo.add("vb_state", "orange");
+ cborDeviceInfo.add("bootloader_state", "unlocked");
+ cborDeviceInfo.add("vbmeta_digest", std::vector<uint8_t>{1, 2, 3, 4});
+ cborDeviceInfo.add("system_patch_level", 42);
+ cborDeviceInfo.add("boot_patch_level", 31415);
+ cborDeviceInfo.add("vendor_patch_level", 0);
+ cborDeviceInfo.add("fused", 0);
+ cborDeviceInfo.add("security_level", "tee");
+ cborDeviceInfo.add("os_version", "the best version");
+ const DeviceInfo kVerifiedDeviceInfo = {cborDeviceInfo.canonicalize().encode()};
Array cborProtectedData;
cborProtectedData.add(Bstr()); // protected
@@ -140,7 +156,10 @@
// Set up mock, then call getSCsr
auto mockRpc = SharedRefBase::make<MockIRemotelyProvisionedComponent>();
- EXPECT_CALL(*mockRpc, getHardwareInfo(NotNull())).WillOnce(Return(ByMove(ScopedAStatus::ok())));
+ EXPECT_CALL(*mockRpc, getHardwareInfo(NotNull())).WillRepeatedly([](RpcHardwareInfo* hwInfo) {
+ hwInfo->versionNumber = 2;
+ return ScopedAStatus::ok();
+ });
EXPECT_CALL(*mockRpc,
generateCertificateRequest(false, // testMode
IsEmpty(), // keysToSign
@@ -157,7 +176,7 @@
Return(ByMove(ScopedAStatus::ok())))); //
auto [csr, csrErrMsg] = getCsr("mock component name", mockRpc.get());
- ASSERT_THAT(csr, NotNull()) << csrErrMsg.value_or("");
+ ASSERT_THAT(csr, NotNull()) << csrErrMsg;
ASSERT_THAT(csr->asArray(), Pointee(Property(&Array::size, Eq(4))));
// Verify the input parameters that we received
@@ -172,7 +191,7 @@
// Verified device info must match our mock value
const Map* actualVerifiedDeviceInfo = deviceInfoArray->get(0)->asMap();
- EXPECT_THAT(actualVerifiedDeviceInfo, Pointee(Property(&Map::size, Eq(2))));
+ EXPECT_THAT(actualVerifiedDeviceInfo, Pointee(Property(&Map::size, Eq(cborDeviceInfo.size()))));
EXPECT_THAT(actualVerifiedDeviceInfo->get("product"), Pointee(Eq(Tstr("gShoe"))));
EXPECT_THAT(actualVerifiedDeviceInfo->get("version"), Pointee(Eq(Uint(2))));
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
index ee8d851..502d931 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -81,8 +81,7 @@
auto [request, errMsg] = getCsr(name, rkp_service.get());
if (!request) {
- std::cerr << "Unable to build CSR for '" << fullName << ": "
- << errMsg.value_or("<Unknown Error>") << std::endl;
+ std::cerr << "Unable to build CSR for '" << fullName << ": " << errMsg << std::endl;
exit(-1);
}