Merge "Add prng_seeder utility"
diff --git a/fsverity/Android.bp b/fsverity/Android.bp
index 040c99b..ce3b499 100644
--- a/fsverity/Android.bp
+++ b/fsverity/Android.bp
@@ -32,14 +32,6 @@
proto: {
canonical_path_from_root: false,
},
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: true,
- },
- },
}
python_binary_host {
diff --git a/fsverity/TEST_MAPPING b/fsverity/TEST_MAPPING
new file mode 100644
index 0000000..b327cb8
--- /dev/null
+++ b/fsverity/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "ComposHostTestCases"
+ }
+ ]
+}
diff --git a/fsverity/fsverity_manifest_generator.py b/fsverity/fsverity_manifest_generator.py
index 0b01a55..79be591 100644
--- a/fsverity/fsverity_manifest_generator.py
+++ b/fsverity/fsverity_manifest_generator.py
@@ -58,7 +58,6 @@
for f in sorted(args.inputs):
# f is a full path for now; make it relative so it starts with {mount_point}/
digest = digests.digests[os.path.relpath(f, args.base_dir)]
- print(f"{os.path.relpath(f, args.base_dir)}")
digest.digest = _digest(args.fsverity_path, f)
digest.hash_alg = HASH_ALGORITHM
diff --git a/identity/Android.bp b/identity/Android.bp
index 512e3ad..4e4b79a 100644
--- a/identity/Android.bp
+++ b/identity/Android.bp
@@ -26,6 +26,7 @@
name: "credstore",
defaults: [
"identity_defaults",
+ "identity_use_latest_hal_aidl_cpp_static",
"keymint_use_latest_hal_aidl_ndk_shared",
"keymint_use_latest_hal_aidl_cpp_static",
],
@@ -58,7 +59,6 @@
"libutilscallstack",
],
static_libs: [
- "android.hardware.identity-V4-cpp",
"android.hardware.keymaster-V3-cpp",
"libcppbor_external",
],
diff --git a/identity/util/src/java/com/android/security/identity/internal/Iso18013.java b/identity/util/src/java/com/android/security/identity/internal/Iso18013.java
index 2561fcc..b47009b 100644
--- a/identity/util/src/java/com/android/security/identity/internal/Iso18013.java
+++ b/identity/util/src/java/com/android/security/identity/internal/Iso18013.java
@@ -146,36 +146,9 @@
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
baos.write(new byte[]{41});
- ECPoint w = ((ECPublicKey) ephemeralKeyPair.getPublic()).getW();
- // Each coordinate may be encoded in 33*, 32, or fewer bytes.
- //
- // * : it can be 33 bytes because toByteArray() guarantees "The array will contain the
- // minimum number of bytes required to represent this BigInteger, including at
- // least one sign bit, which is (ceil((this.bitLength() + 1)/8))" which means that
- // the MSB is always 0x00. This is taken care of by calling calling
- // stripLeadingZeroes().
- //
- // We need the encoding to be exactly 32 bytes since according to RFC 5480 section 2.2
- // and SEC 1: Elliptic Curve Cryptography section 2.3.3 the encoding is 0x04 | X | Y
- // where X and Y are encoded in exactly 32 byte, big endian integer values each.
- //
- byte[] xBytes = stripLeadingZeroes(w.getAffineX().toByteArray());
- if (xBytes.length > 32) {
- throw new RuntimeException("xBytes is " + xBytes.length + " which is unexpected");
- }
- for (int n = 0; n < 32 - xBytes.length; n++) {
- baos.write(0x00);
- }
- baos.write(xBytes);
- byte[] yBytes = stripLeadingZeroes(w.getAffineY().toByteArray());
- if (yBytes.length > 32) {
- throw new RuntimeException("yBytes is " + yBytes.length + " which is unexpected");
- }
- for (int n = 0; n < 32 - yBytes.length; n++) {
- baos.write(0x00);
- }
- baos.write(yBytes);
+ ECPoint w = ((ECPublicKey) ephemeralKeyPair.getPublic()).getW();
+ baos.write(Util.convertP256PublicKeyToDERFormat(w));
baos.write(new byte[]{42, 44});
} catch (IOException e) {
@@ -303,18 +276,4 @@
throw new IllegalStateException("Error performing key agreement", e);
}
}
-
- private static byte[] stripLeadingZeroes(byte[] value) {
- int n = 0;
- while (n < value.length && value[n] == 0) {
- n++;
- }
- int newLen = value.length - n;
- byte[] ret = new byte[newLen];
- int m = 0;
- while (n < value.length) {
- ret[m++] = value[n++];
- }
- return ret;
- }
}
diff --git a/identity/util/src/java/com/android/security/identity/internal/Util.java b/identity/util/src/java/com/android/security/identity/internal/Util.java
index 94d7d15..ee12cd0 100644
--- a/identity/util/src/java/com/android/security/identity/internal/Util.java
+++ b/identity/util/src/java/com/android/security/identity/internal/Util.java
@@ -1130,6 +1130,48 @@
Log.e(TAG, name + ": dumping " + data.length + " bytes\n" + fmt.toString());
}
+ // Convert EC P256 public key to DER format binary format
+ public static byte[] convertP256PublicKeyToDERFormat(ECPoint w) {
+ byte[] ret = new byte[64];
+
+ // Each coordinate may be encoded in 33*, 32, or fewer bytes.
+ //
+ // * : it can be 33 bytes because toByteArray() guarantees "The array will contain the
+ // minimum number of bytes required to represent this BigInteger, including at
+ // least one sign bit, which is (ceil((this.bitLength() + 1)/8))" which means that
+ // the MSB is always 0x00. This is taken care of by calling calling
+ // stripLeadingZeroes().
+ //
+ // We need the encoding to be exactly 32 bytes since according to RFC 5480 section 2.2
+ // and SEC 1: Elliptic Curve Cryptography section 2.3.3 the encoding is 0x04 | X | Y
+ // where X and Y are encoded in exactly 32 byte, big endian integer values each.
+ //
+ byte[] xBytes = stripLeadingZeroes(w.getAffineX().toByteArray());
+ if (xBytes.length > 32) {
+ throw new RuntimeException("xBytes is " + xBytes.length + " which is unexpected");
+ }
+ int numLeadingZeroBytes = 32 - xBytes.length;
+ for (int n = 0; n < numLeadingZeroBytes; n++) {
+ ret[n] = 0x00;
+ }
+ for (int n = 0; n < xBytes.length; n++) {
+ ret[numLeadingZeroBytes + n] = xBytes[n];
+ }
+
+ byte[] yBytes = stripLeadingZeroes(w.getAffineY().toByteArray());
+ if (yBytes.length > 32) {
+ throw new RuntimeException("yBytes is " + yBytes.length + " which is unexpected");
+ }
+ numLeadingZeroBytes = 32 - yBytes.length;
+ for (int n = 0; n < numLeadingZeroBytes; n++) {
+ ret[32 + n] = 0x00;
+ }
+ for (int n = 0; n < yBytes.length; n++) {
+ ret[32 + numLeadingZeroBytes + n] = yBytes[n];
+ }
+
+ return ret;
+ }
// This returns a SessionTranscript which satisfy the requirement
// that the uncompressed X and Y coordinates of the public key for the
@@ -1142,36 +1184,9 @@
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
baos.write(new byte[]{42});
- ECPoint w = ((ECPublicKey) ephemeralKeyPair.getPublic()).getW();
- // Each coordinate may be encoded in 33*, 32, or fewer bytes.
- //
- // * : it can be 33 bytes because toByteArray() guarantees "The array will contain the
- // minimum number of bytes required to represent this BigInteger, including at
- // least one sign bit, which is (ceil((this.bitLength() + 1)/8))" which means that
- // the MSB is always 0x00. This is taken care of by calling calling
- // stripLeadingZeroes().
- //
- // We need the encoding to be exactly 32 bytes since according to RFC 5480 section 2.2
- // and SEC 1: Elliptic Curve Cryptography section 2.3.3 the encoding is 0x04 | X | Y
- // where X and Y are encoded in exactly 32 byte, big endian integer values each.
- //
- byte[] xBytes = stripLeadingZeroes(w.getAffineX().toByteArray());
- if (xBytes.length > 32) {
- throw new RuntimeException("xBytes is " + xBytes.length + " which is unexpected");
- }
- for (int n = 0; n < 32 - xBytes.length; n++) {
- baos.write(0x00);
- }
- baos.write(xBytes);
- byte[] yBytes = stripLeadingZeroes(w.getAffineY().toByteArray());
- if (yBytes.length > 32) {
- throw new RuntimeException("yBytes is " + yBytes.length + " which is unexpected");
- }
- for (int n = 0; n < 32 - yBytes.length; n++) {
- baos.write(0x00);
- }
- baos.write(yBytes);
+ ECPoint w = ((ECPublicKey) ephemeralKeyPair.getPublic()).getW();
+ baos.write(convertP256PublicKeyToDERFormat(w));
baos.write(new byte[]{43, 44});
} catch (IOException e) {
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 43419b7..0e5afd9 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -27,6 +27,7 @@
srcs: ["src/lib.rs"],
defaults: [
"keymint_use_latest_hal_aidl_rust",
+ "keystore2_use_latest_aidl_rust",
],
rustlibs: [
@@ -39,7 +40,6 @@
"android.security.maintenance-rust",
"android.security.metrics-rust",
"android.security.remoteprovisioning-rust",
- "android.system.keystore2-V2-rust",
"libanyhow",
"libbinder_rs",
"libkeystore2_aaid-rust",
@@ -79,9 +79,11 @@
name: "libkeystore2_test_utils",
crate_name: "keystore2_test_utils",
srcs: ["test_utils/lib.rs"],
- defaults: ["keymint_use_latest_hal_aidl_rust"],
+ defaults: [
+ "keymint_use_latest_hal_aidl_rust",
+ "keystore2_use_latest_aidl_rust",
+ ],
rustlibs: [
- "android.system.keystore2-V2-rust",
"libbinder_rs",
"libkeystore2_selinux",
"liblog_rust",
@@ -89,8 +91,8 @@
"librand",
"libserde",
"libserde_cbor",
- "libthiserror",
- "libanyhow",
+ "libthiserror",
+ "libanyhow",
],
}
@@ -110,13 +112,15 @@
rust_test {
name: "keystore2_test_utils_test",
srcs: ["test_utils/lib.rs"],
- defaults: ["keymint_use_latest_hal_aidl_rust"],
+ defaults: [
+ "keymint_use_latest_hal_aidl_rust",
+ "keystore2_use_latest_aidl_rust",
+ ],
test_suites: ["general-tests"],
require_root: true,
auto_gen_config: true,
compile_multilib: "first",
rustlibs: [
- "android.system.keystore2-V2-rust",
"libbinder_rs",
"libkeystore2_selinux",
"liblog_rust",
@@ -124,8 +128,8 @@
"librand",
"libserde",
"libserde_cbor",
- "libthiserror",
- "libanyhow",
+ "libthiserror",
+ "libanyhow",
],
}
diff --git a/keystore2/legacykeystore/lib.rs b/keystore2/legacykeystore/lib.rs
index 95f917a..ed5bd4f 100644
--- a/keystore2/legacykeystore/lib.rs
+++ b/keystore2/legacykeystore/lib.rs
@@ -393,7 +393,7 @@
let uid = Self::get_effective_uid(uid).context("In list.")?;
let mut result = self.list_legacy(uid).context("In list.")?;
result.append(&mut db.list(uid).context("In list: Trying to get list of entries.")?);
- result = result.into_iter().filter(|s| s.starts_with(prefix)).collect();
+ result.retain(|s| s.starts_with(prefix));
result.sort_unstable();
result.dedup();
Ok(result)
diff --git a/keystore2/rustfmt.toml b/keystore2/rustfmt.toml
new file mode 100644
index 0000000..4335d66
--- /dev/null
+++ b/keystore2/rustfmt.toml
@@ -0,0 +1,5 @@
+# Android Format Style
+
+edition = "2021"
+use_small_heuristics = "Max"
+newline_style = "Unix"
\ No newline at end of file
diff --git a/keystore2/tests/legacy_blobs/Android.bp b/keystore2/tests/legacy_blobs/Android.bp
index f25b5d5..92f2cc3 100644
--- a/keystore2/tests/legacy_blobs/Android.bp
+++ b/keystore2/tests/legacy_blobs/Android.bp
@@ -33,7 +33,6 @@
rustlibs: [
"libkeystore2_with_test_utils",
"libkeystore2_crypto_rust",
- "android.system.keystore2-V2-rust",
"android.security.maintenance-rust",
"android.security.authorization-rust",
"librustutils",
@@ -48,6 +47,7 @@
],
defaults: [
"keymint_use_latest_hal_aidl_rust",
+ "keystore2_use_latest_aidl_rust",
],
require_root: true,
}
diff --git a/provisioner/rkp_factory_extraction_lib.cpp b/provisioner/rkp_factory_extraction_lib.cpp
index 3bf3d7e..77d032b 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>
@@ -37,8 +41,12 @@
using aidl::android::hardware::security::keymint::MacedPublicKey;
using aidl::android::hardware::security::keymint::ProtectedData;
using aidl::android::hardware::security::keymint::RpcHardwareInfo;
+using aidl::android::hardware::security::keymint::remote_prov::EekChain;
+using aidl::android::hardware::security::keymint::remote_prov::generateEekChain;
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::parseAndValidateFactoryDeviceInfo;
+using aidl::android::hardware::security::keymint::remote_prov::verifyFactoryProtectedData;
using namespace cppbor;
using namespace cppcose;
@@ -89,29 +97,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 =
+ parseAndValidateFactoryDeviceInfo(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 +128,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 +154,42 @@
<< "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
exit(-1);
}
- return composeCertificateRequest(protectedData, verifiedDeviceInfo, challenge, keysToSignMac);
+ return composeCertificateRequest(protectedData, verifiedDeviceInfo, challenge, keysToSignMac,
+ irpc);
}
+
+void selfTestGetCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
+ std::vector<uint8_t> keysToSignMac;
+ std::vector<MacedPublicKey> emptyKeys;
+ DeviceInfo verifiedDeviceInfo;
+ ProtectedData protectedData;
+ RpcHardwareInfo hwInfo;
+ ::ndk::ScopedAStatus status = irpc->getHardwareInfo(&hwInfo);
+ if (!status.isOk()) {
+ std::cerr << "Failed to get hardware info for '" << componentName
+ << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
+ exit(-1);
+ }
+
+ const std::vector<uint8_t> eekId = {0, 1, 2, 3, 4, 5, 6, 7};
+ ErrMsgOr<EekChain> eekChain = generateEekChain(hwInfo.supportedEekCurve, /*length=*/3, eekId);
+ if (!eekChain) {
+ std::cerr << "Error generating test EEK certificate chain: " << eekChain.message();
+ exit(-1);
+ }
+ const std::vector<uint8_t> challenge = generateChallenge();
+ status = irpc->generateCertificateRequest(
+ /*test_mode=*/true, emptyKeys, eekChain->chain, challenge, &verifiedDeviceInfo,
+ &protectedData, &keysToSignMac);
+ if (!status.isOk()) {
+ std::cerr << "Error generating test cert chain for '" << componentName
+ << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
+ exit(-1);
+ }
+
+ auto result = verifyFactoryProtectedData(verifiedDeviceInfo, /*keysToSign=*/{}, keysToSignMac,
+ protectedData, *eekChain, eekId,
+ hwInfo.supportedEekCurve, irpc, challenge);
+
+ std::cout << "Self test successful." << std::endl;
+}
\ No newline at end of file
diff --git a/provisioner/rkp_factory_extraction_lib.h b/provisioner/rkp_factory_extraction_lib.h
index fe15402..a803582 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,11 @@
// 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);
+
+// Generates a test certificate chain and validates it, exiting the process on error.
+void selfTestGetCsr(
+ 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..0fe7d74 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -34,7 +34,11 @@
using namespace cppbor;
using namespace cppcose;
-DEFINE_string(output_format, "csr", "How to format the output. Defaults to 'csr'.");
+DEFINE_string(output_format, "build+csr", "How to format the output. Defaults to 'build+csr'.");
+DEFINE_bool(self_test, false,
+ "If true, the tool does not output CSR data, but instead performs a self-test, "
+ "validating a test payload for correctness. This may be used to verify a device on the "
+ "factory line before attempting to upload the output to the device info service.");
namespace {
@@ -79,14 +83,17 @@
exit(-1);
}
- 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;
- exit(-1);
- }
+ if (FLAGS_self_test) {
+ selfTestGetCsr(name, rkp_service.get());
+ } else {
+ auto [request, errMsg] = getCsr(name, rkp_service.get());
+ if (!request) {
+ std::cerr << "Unable to build CSR for '" << fullName << ": " << errMsg << std::endl;
+ exit(-1);
+ }
- writeOutput(std::string(name), *request);
+ writeOutput(std::string(name), *request);
+ }
}
} // namespace