Add a utility to JSON-format a CSR with build info

We need both the build fingerprint as well as the CSR when uploading
data to the APFE provisioning server. Add a utility function to format
the output as a JSON blob so that it may be easily collected in the
factory in a serialized data format, then later uploaded.

Test: libkeymint_remote_prov_support_test
Test: VtsAidlKeyMintTargetTest
Test: VtsHalRemotelyProvisionedComponentTargetTest
Bug: 191301285
Change-Id: I751c5461876d83251869539f1a395ba13cb5cf84
This commit is contained in:
Seth Moore
2021-06-25 14:20:15 -07:00
parent ba83133139
commit 23f624599f
5 changed files with 101 additions and 38 deletions

View File

@@ -23,16 +23,11 @@ package {
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_test {
name: "VtsAidlKeyMintTargetTest",
cc_defaults {
name: "keymint_vts_defaults",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"AttestKeyTest.cpp",
"DeviceUniqueAttestationTest.cpp",
"KeyMintTest.cpp",
"VtsHalTargetTestDefaults",
],
shared_libs: [
"libbinder_ndk",
@@ -43,9 +38,24 @@ cc_test {
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
"libcppcose_rkp",
"libjsoncpp",
"libkeymint",
"libkeymint_remote_prov_support",
"libkeymint_support",
],
}
cc_test {
name: "VtsAidlKeyMintTargetTest",
defaults: [
"keymint_vts_defaults",
],
srcs: [
"AttestKeyTest.cpp",
"DeviceUniqueAttestationTest.cpp",
"KeyMintTest.cpp",
],
static_libs: [
"libkeymint_vts_test_utils",
],
test_suites: [
@@ -57,8 +67,7 @@ cc_test {
cc_test_library {
name: "libkeymint_vts_test_utils",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
"keymint_vts_defaults",
],
srcs: [
"KeyMintAidlTestBase.cpp",
@@ -66,45 +75,22 @@ cc_test_library {
export_include_dirs: [
".",
],
shared_libs: [
"libbinder_ndk",
"libcrypto",
],
static_libs: [
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
"libcppcose_rkp",
"libgmock_ndk",
"libkeymint",
"libkeymint_remote_prov_support",
"libkeymint_support",
],
}
cc_test {
name: "VtsHalRemotelyProvisionedComponentTargetTest",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
"keymint_vts_defaults",
],
srcs: [
"VtsRemotelyProvisionedComponentTests.cpp",
],
shared_libs: [
"libbinder_ndk",
"libcrypto",
],
static_libs: [
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
"libcppcose_rkp",
"libgmock_ndk",
"libkeymaster_portable",
"libkeymint",
"libkeymint_support",
"libkeymint_remote_prov_support",
"libkeymint_vts_test_utils",
"libpuresoftkeymasterdevice",
],

View File

@@ -57,9 +57,11 @@ cc_library {
"include",
],
shared_libs: [
"libbase",
"libcppbor_external",
"libcppcose_rkp",
"libcrypto",
"libjsoncpp",
],
}
@@ -71,9 +73,11 @@ cc_test {
"libgtest_main",
],
shared_libs: [
"libbase",
"libcppbor_external",
"libcppcose_rkp",
"libcrypto",
"libjsoncpp",
"libkeymaster_portable",
"libkeymint_remote_prov_support",
],

View File

@@ -87,4 +87,26 @@ struct BccEntryData {
*/
ErrMsgOr<std::vector<BccEntryData>> 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)}; }
std::string output;
std::string error; // if non-empty, this describes what went wrong
};
/**
* Take a given certificate request and output a JSON blob containing both the
* build fingerprint and certificate request. This data may be serialized, then
* later uploaded to the remote provisioning service. The input csr is not
* validated, only encoded.
*
* Output format:
* {
* "build_fingerprint": <string>
* "csr": <base64 CBOR CSR>
* }
*/
JsonOutput jsonEncodeCsrWithBuild(const cppbor::Array& csr);
} // namespace aidl::android::hardware::security::keymint::remote_prov

View File

@@ -14,13 +14,15 @@
* limitations under the License.
*/
#include <iterator>
#include <tuple>
#include <remote_prov/remote_prov_utils.h>
#include <openssl/rand.h>
#include <android-base/properties.h>
#include <cppbor.h>
#include <json/json.h>
#include <openssl/base64.h>
#include <openssl/rand.h>
#include <remote_prov/remote_prov_utils.h>
namespace aidl::android::hardware::security::keymint::remote_prov {
@@ -180,4 +182,36 @@ ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc) {
return result;
}
JsonOutput jsonEncodeCsrWithBuild(const cppbor::Array& csr) {
const std::string kFingerprintProp = "ro.build.fingerprint";
if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) {
return JsonOutput::Error("Unable to read build fingerprint");
}
bytevec csrCbor = csr.encode();
size_t base64Length;
int rc = EVP_EncodedLength(&base64Length, csrCbor.size());
if (!rc) {
return JsonOutput::Error("Error getting base64 length. Size overflow?");
}
std::vector<char> base64(base64Length);
rc = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(base64.data()), csrCbor.data(), csrCbor.size());
++rc; // Account for NUL, which BoringSSL does not for some reason.
if (rc != base64Length) {
return JsonOutput::Error("Error writing base64. Expected " + std::to_string(base64Length) +
" bytes to be written, but " + std::to_string(rc) +
" bytes were actually written.");
}
Json::Value json(Json::objectValue);
json["build_fingerprint"] = ::android::base::GetProperty(kFingerprintProp, /*default=*/"");
json["csr"] = base64.data(); // Boring writes a NUL-terminated c-string
Json::StreamWriterBuilder factory;
factory["indentation"] = ""; // disable pretty formatting
return JsonOutput::Ok(Json::writeString(factory, json));
}
} // namespace aidl::android::hardware::security::keymint::remote_prov

View File

@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <android-base/properties.h>
#include <cppbor_parse.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -23,6 +24,7 @@
#include <openssl/curve25519.h>
#include <remote_prov/remote_prov_utils.h>
#include <cstdint>
#include "cppbor.h"
#include "keymaster/cppcose/cppcose.h"
namespace aidl::android::hardware::security::keymint::remote_prov {
@@ -80,5 +82,20 @@ TEST(RemoteProvUtilsTest, GetProdEekChain) {
EXPECT_THAT(eekPub, ElementsAreArray(geek->getBstrValue(CoseKey::PUBKEY_X).value_or(empty)));
}
TEST(RemoteProvUtilsTest, JsonEncodeCsr) {
cppbor::Array array;
array.add(1);
auto [json, error] = jsonEncodeCsrWithBuild(array);
ASSERT_TRUE(error.empty()) << error;
std::string expected = R"({"build_fingerprint":")" +
::android::base::GetProperty("ro.build.fingerprint", /*default=*/"") +
R"(","csr":"gQE="})";
ASSERT_EQ(json, expected);
}
} // namespace
} // namespace aidl::android::hardware::security::keymint::remote_prov