Reland "[DBSC] Make it easier to test binding keys on Linux and Mac"
This is a reland of commit 964303340b500b4c1d2e10fa00c3a91f9a786149
Orignal CL wasn't the cause for the test failures:
https://crbug.com/1464248#c3
Original change's description:
> [DBSC] Make it easier to test binding keys on Linux and Mac
>
> //crypto currently has an UnexportableKeyProvider support on Windows
> only. Since most of the future developers work on Linux and Mac, it will
> be helpful to be able to test the feature on these platforms.
>
> To facilite local development, this CL adds a mock software-backed
> implementation of an UnexportableKeyProvider behind a feature flag. This
> feature flag is expected to never be shipped to end users.
>
> The flag is checked on the UnexportableKeyService level, so only
> DBSC-related code will switch to an insecure implementation.
>
> Bug: b/290640296
> Change-Id: Iccd1d0c1733d3f5472380023377bd81df4e3f933
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4675882
> Reviewed-by: Adam Langley <agl@chromium.org>
> Reviewed-by: Kristian Monsen <kristianm@chromium.org>
> Commit-Queue: Alex Ilin <alexilin@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1168616}
Bug: b/290640296, 1464248
Change-Id: Ie749b8a48c2435d389bb13e5a9b69ccd7dbb7755
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4681330
Reviewed-by: Adam Langley <agl@chromium.org>
Commit-Queue: Adam Langley <agl@chromium.org>
Reviewed-by: Kristian Monsen <kristianm@chromium.org>
Auto-Submit: Alex Ilin <alexilin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1171456}
diff --git a/crypto/BUILD.gn b/crypto/BUILD.gn
index 4444bb74..fb6b03d 100644
--- a/crypto/BUILD.gn
+++ b/crypto/BUILD.gn
@@ -56,6 +56,7 @@
"unexportable_key.h",
"unexportable_key_metrics.cc",
"unexportable_key_metrics.h",
+ "unexportable_key_software_unsecure.cc",
]
deps = [
diff --git a/crypto/scoped_mock_unexportable_key_provider.cc b/crypto/scoped_mock_unexportable_key_provider.cc
index 381e968..d0e3cf2 100644
--- a/crypto/scoped_mock_unexportable_key_provider.cc
+++ b/crypto/scoped_mock_unexportable_key_provider.cc
@@ -4,114 +4,15 @@
#include <vector>
-#include "base/check.h"
#include "crypto/scoped_mock_unexportable_key_provider.h"
-#include "crypto/sha2.h"
-#include "crypto/signature_verifier.h"
#include "crypto/unexportable_key.h"
-#include "third_party/boringssl/src/include/openssl/bytestring.h"
-#include "third_party/boringssl/src/include/openssl/ec.h"
-#include "third_party/boringssl/src/include/openssl/ec_key.h"
-#include "third_party/boringssl/src/include/openssl/ecdsa.h"
-#include "third_party/boringssl/src/include/openssl/evp.h"
-#include "third_party/boringssl/src/include/openssl/obj.h"
namespace crypto {
namespace {
-std::vector<uint8_t> CBBToVector(const CBB* cbb) {
- return std::vector<uint8_t>(CBB_data(cbb), CBB_data(cbb) + CBB_len(cbb));
-}
-
-class SoftwareECDSA : public UnexportableSigningKey {
- public:
- explicit SoftwareECDSA(bssl::UniquePtr<EC_KEY> key) : key_(std::move(key)) {}
- ~SoftwareECDSA() override = default;
-
- SignatureVerifier::SignatureAlgorithm Algorithm() const override {
- return SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
- }
-
- std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
- bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
- CHECK(EVP_PKEY_set1_EC_KEY(pkey.get(), key_.get()));
-
- bssl::ScopedCBB cbb;
- CHECK(CBB_init(cbb.get(), /*initial_capacity=*/128) &&
- EVP_marshal_public_key(cbb.get(), pkey.get()));
- return CBBToVector(cbb.get());
- }
-
- std::vector<uint8_t> GetWrappedKey() const override {
- bssl::ScopedCBB cbb;
- CHECK(
- CBB_init(cbb.get(), /*initial_capacity=*/128) &&
- EC_KEY_marshal_private_key(cbb.get(), key_.get(),
- EC_PKEY_NO_PARAMETERS | EC_PKEY_NO_PUBKEY));
- return CBBToVector(cbb.get());
- }
-
- absl::optional<std::vector<uint8_t>> SignSlowly(
- base::span<const uint8_t> data) override {
- std::vector<uint8_t> ret(ECDSA_size(key_.get()));
- std::array<uint8_t, kSHA256Length> digest = SHA256Hash(data);
- unsigned int ret_size;
- CHECK(ECDSA_sign(0, digest.data(), digest.size(), ret.data(), &ret_size,
- key_.get()));
- ret.resize(ret_size);
- return ret;
- }
-
- private:
- bssl::UniquePtr<EC_KEY> key_;
-};
-
-class SoftwareProvider : public UnexportableKeyProvider {
- public:
- ~SoftwareProvider() override = default;
-
- absl::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
- base::span<const SignatureVerifier::SignatureAlgorithm>
- acceptable_algorithms) override {
- for (auto algo : acceptable_algorithms) {
- if (algo == SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256) {
- return algo;
- }
- }
-
- return absl::nullopt;
- }
-
- std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly(
- base::span<const SignatureVerifier::SignatureAlgorithm>
- acceptable_algorithms) override {
- if (!SelectAlgorithm(acceptable_algorithms)) {
- return nullptr;
- }
-
- bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
- CHECK(EC_KEY_generate_key(key.get()));
-
- return std::make_unique<SoftwareECDSA>(std::move(key));
- }
-
- std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly(
- base::span<const uint8_t> wrapped_key) override {
- bssl::UniquePtr<EC_GROUP> p256(
- EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
- CBS cbs;
- CBS_init(&cbs, wrapped_key.data(), wrapped_key.size());
- bssl::UniquePtr<EC_KEY> key(EC_KEY_parse_private_key(&cbs, p256.get()));
- if (!key || CBS_len(&cbs) != 0) {
- return nullptr;
- }
- return std::make_unique<SoftwareECDSA>(std::move(key));
- }
-};
-
std::unique_ptr<UnexportableKeyProvider> GetUnexportableKeyProviderMock() {
- return std::make_unique<SoftwareProvider>();
+ return GetSoftwareUnsecureUnexportableKeyProvider();
}
std::unique_ptr<UnexportableKeyProvider> GetUnexportableKeyProviderNull() {
diff --git a/crypto/unexportable_key.cc b/crypto/unexportable_key.cc
index 4eb6378..5615125 100644
--- a/crypto/unexportable_key.cc
+++ b/crypto/unexportable_key.cc
@@ -26,6 +26,10 @@
GetVirtualUnexportableKeyProviderWin();
#endif
+// Implemented in unexportable_key_software_unsecure.cc.
+std::unique_ptr<UnexportableKeyProvider>
+GetUnexportableKeyProviderSoftwareUnsecure();
+
std::unique_ptr<UnexportableKeyProvider> GetUnexportableKeyProvider() {
if (g_mock_provider) {
return g_mock_provider();
diff --git a/crypto/unexportable_key.h b/crypto/unexportable_key.h
index 61c25be..63acf4b6 100644
--- a/crypto/unexportable_key.h
+++ b/crypto/unexportable_key.h
@@ -191,6 +191,14 @@
CRYPTO_EXPORT std::unique_ptr<VirtualUnexportableKeyProvider>
GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY();
+// `GetSoftwareUnsecureUnexportableKeyProvider()` returns a mock software
+// implementation of `UnexportableKeyProvider` that can be used on platforms
+// that do not have a native secure implementation.
+// This should be used for development purposes only since these keys are not
+// backed by hardware and are not stored securely.
+CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider>
+GetSoftwareUnsecureUnexportableKeyProvider();
+
namespace internal {
CRYPTO_EXPORT void SetUnexportableKeyProviderForTesting(
diff --git a/crypto/unexportable_key_software_unsecure.cc b/crypto/unexportable_key_software_unsecure.cc
new file mode 100644
index 0000000..64ca3f0
--- /dev/null
+++ b/crypto/unexportable_key_software_unsecure.cc
@@ -0,0 +1,118 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/unexportable_key.h"
+
+#include "base/check.h"
+#include "crypto/sha2.h"
+#include "crypto/signature_verifier.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ec_key.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/obj.h"
+
+namespace crypto {
+
+namespace {
+
+std::vector<uint8_t> CBBToVector(const CBB* cbb) {
+ return std::vector<uint8_t>(CBB_data(cbb), CBB_data(cbb) + CBB_len(cbb));
+}
+
+class SoftwareECDSA : public UnexportableSigningKey {
+ public:
+ explicit SoftwareECDSA(bssl::UniquePtr<EC_KEY> key) : key_(std::move(key)) {}
+ ~SoftwareECDSA() override = default;
+
+ SignatureVerifier::SignatureAlgorithm Algorithm() const override {
+ return SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
+ }
+
+ std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
+ bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
+ CHECK(EVP_PKEY_set1_EC_KEY(pkey.get(), key_.get()));
+
+ bssl::ScopedCBB cbb;
+ CHECK(CBB_init(cbb.get(), /*initial_capacity=*/128) &&
+ EVP_marshal_public_key(cbb.get(), pkey.get()));
+ return CBBToVector(cbb.get());
+ }
+
+ std::vector<uint8_t> GetWrappedKey() const override {
+ bssl::ScopedCBB cbb;
+ CHECK(
+ CBB_init(cbb.get(), /*initial_capacity=*/128) &&
+ EC_KEY_marshal_private_key(cbb.get(), key_.get(),
+ EC_PKEY_NO_PARAMETERS | EC_PKEY_NO_PUBKEY));
+ return CBBToVector(cbb.get());
+ }
+
+ absl::optional<std::vector<uint8_t>> SignSlowly(
+ base::span<const uint8_t> data) override {
+ std::vector<uint8_t> ret(ECDSA_size(key_.get()));
+ std::array<uint8_t, kSHA256Length> digest = SHA256Hash(data);
+ unsigned int ret_size;
+ CHECK(ECDSA_sign(0, digest.data(), digest.size(), ret.data(), &ret_size,
+ key_.get()));
+ ret.resize(ret_size);
+ return ret;
+ }
+
+ private:
+ bssl::UniquePtr<EC_KEY> key_;
+};
+
+class SoftwareProvider : public UnexportableKeyProvider {
+ public:
+ ~SoftwareProvider() override = default;
+
+ absl::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
+ base::span<const SignatureVerifier::SignatureAlgorithm>
+ acceptable_algorithms) override {
+ for (auto algo : acceptable_algorithms) {
+ if (algo == SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256) {
+ return algo;
+ }
+ }
+
+ return absl::nullopt;
+ }
+
+ std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly(
+ base::span<const SignatureVerifier::SignatureAlgorithm>
+ acceptable_algorithms) override {
+ if (!SelectAlgorithm(acceptable_algorithms)) {
+ return nullptr;
+ }
+
+ bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+ CHECK(EC_KEY_generate_key(key.get()));
+
+ return std::make_unique<SoftwareECDSA>(std::move(key));
+ }
+
+ std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly(
+ base::span<const uint8_t> wrapped_key) override {
+ bssl::UniquePtr<EC_GROUP> p256(
+ EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ CBS cbs;
+ CBS_init(&cbs, wrapped_key.data(), wrapped_key.size());
+ bssl::UniquePtr<EC_KEY> key(EC_KEY_parse_private_key(&cbs, p256.get()));
+ if (!key || CBS_len(&cbs) != 0) {
+ return nullptr;
+ }
+ return std::make_unique<SoftwareECDSA>(std::move(key));
+ }
+};
+
+} // namespace
+
+std::unique_ptr<UnexportableKeyProvider>
+GetSoftwareUnsecureUnexportableKeyProvider() {
+ return std::make_unique<SoftwareProvider>();
+}
+
+} // namespace crypto