[Trust Tokens] Add V3 crypto classes
In preparation for implementing the V3 spec changes, we add the necessary signing and key generation classes for the new request signing algorithm In order to support this change we modify the ECPrivateKey::ExportRawPublicKey function to correctly include the leading byte as specified in RFC 5480 Section 2.2. Bug: 1202232 Change-Id: I92c2517a36ff7a66ed803a75a86963a4c2c5006d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2845411 Reviewed-by: Filip Gorski <fgorski@chromium.org> Reviewed-by: David Van Cleve <davidvc@chromium.org> Reviewed-by: Alice Gong <alicego@google.com> Reviewed-by: David Benjamin <davidben@chromium.org> Commit-Queue: Alice Gong <alicego@google.com> Cr-Commit-Position: refs/heads/master@{#889082}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
2a343978ce
commit
63ecbf0d09
chrome/browser/enterprise/connectors/device_trust
components/gcm_driver/crypto
crypto
services/network/trust_tokens
@ -175,6 +175,10 @@ std::string DeviceTrustKeyPair::ExportPEMPublicKey() {
|
||||
std::string raw_public_key;
|
||||
if (!key_pair_->ExportRawPublicKey(&raw_public_key))
|
||||
return std::string();
|
||||
// This is intentionally using a non-standard format for the uncompressed
|
||||
// point length, so we trim the leading 0x04 byte. See
|
||||
// https://crbug.com/1212786
|
||||
raw_public_key.erase(0, 1);
|
||||
std::string public_key;
|
||||
if (!CreatePEMKey(raw_public_key, KeyType::PUBLIC_KEY, public_key))
|
||||
return std::string();
|
||||
|
@ -21,9 +21,6 @@ namespace gcm {
|
||||
|
||||
namespace {
|
||||
|
||||
// The first byte in an uncompressed P-256 point per SEC1 2.3.3.
|
||||
const char kUncompressedPointForm = 0x04;
|
||||
|
||||
// A P-256 field element consists of 32 bytes.
|
||||
const size_t kFieldBytes = 32;
|
||||
|
||||
@ -38,17 +35,14 @@ bool GetRawPublicKey(const crypto::ECPrivateKey& key, std::string* public_key) {
|
||||
std::string candidate_public_key;
|
||||
|
||||
// ECPrivateKey::ExportRawPublicKey() returns the EC point in the uncompressed
|
||||
// point format, but does not include the leading byte of value 0x04 that
|
||||
// indicates usage of uncompressed points, per SEC1 2.3.3.
|
||||
// point format.
|
||||
if (!key.ExportRawPublicKey(&candidate_public_key) ||
|
||||
candidate_public_key.size() != 2 * kFieldBytes) {
|
||||
candidate_public_key.size() != kUncompressedPointBytes) {
|
||||
DLOG(ERROR) << "Unable to export the public key.";
|
||||
return false;
|
||||
}
|
||||
// Concatenate the leading 0x04 byte and the two uncompressed points.
|
||||
public_key->erase();
|
||||
public_key->reserve(kUncompressedPointBytes);
|
||||
public_key->push_back(kUncompressedPointForm);
|
||||
public_key->append(candidate_public_key);
|
||||
return true;
|
||||
}
|
||||
@ -79,11 +73,10 @@ bool ComputeSharedP256Secret(crypto::ECPrivateKey& key,
|
||||
bssl::UniquePtr<EC_POINT> point(
|
||||
EC_POINT_new(EC_KEY_get0_group(ec_private_key)));
|
||||
|
||||
if (!point ||
|
||||
!EC_POINT_oct2point(
|
||||
EC_KEY_get0_group(ec_private_key), point.get(),
|
||||
reinterpret_cast<const uint8_t*>(peer_public_key.data()),
|
||||
peer_public_key.size(), nullptr)) {
|
||||
if (!point || !EC_POINT_oct2point(
|
||||
EC_KEY_get0_group(ec_private_key), point.get(),
|
||||
reinterpret_cast<const uint8_t*>(peer_public_key.data()),
|
||||
peer_public_key.size(), nullptr)) {
|
||||
DLOG(ERROR) << "Can't convert peer public value to curve point.";
|
||||
return false;
|
||||
}
|
||||
|
@ -151,22 +151,16 @@ bool ECPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) const {
|
||||
bool ECPrivateKey::ExportRawPublicKey(std::string* output) const {
|
||||
OpenSSLErrStackTracer err_tracer(FROM_HERE);
|
||||
|
||||
// Export the x and y field elements as 32-byte, big-endian numbers. (This is
|
||||
// the same as X9.62 uncompressed form without the leading 0x04 byte.)
|
||||
std::array<uint8_t, 65> buf;
|
||||
EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key_.get());
|
||||
bssl::UniquePtr<BIGNUM> x(BN_new());
|
||||
bssl::UniquePtr<BIGNUM> y(BN_new());
|
||||
uint8_t buf[64];
|
||||
if (!x || !y ||
|
||||
!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key),
|
||||
EC_KEY_get0_public_key(ec_key),
|
||||
x.get(), y.get(), nullptr) ||
|
||||
!BN_bn2bin_padded(buf, 32, x.get()) ||
|
||||
!BN_bn2bin_padded(buf + 32, 32, y.get())) {
|
||||
if (!EC_POINT_point2oct(EC_KEY_get0_group(ec_key),
|
||||
EC_KEY_get0_public_key(ec_key),
|
||||
POINT_CONVERSION_UNCOMPRESSED, buf.data(), buf.size(),
|
||||
/*ctx=*/nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
output->assign(reinterpret_cast<const char*>(buf), sizeof(buf));
|
||||
output->assign(buf.begin(), buf.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,8 @@ class CRYPTO_EXPORT ECPrivateKey {
|
||||
// Exports the public key to an X.509 SubjectPublicKeyInfo block.
|
||||
bool ExportPublicKey(std::vector<uint8_t>* output) const;
|
||||
|
||||
// Exports the public key as an EC point in the uncompressed point format.
|
||||
// Exports the public key as an EC point in X9.62 uncompressed form. Note this
|
||||
// includes the leading 0x04 byte.
|
||||
bool ExportRawPublicKey(std::string* output) const;
|
||||
|
||||
private:
|
||||
|
@ -97,12 +97,12 @@ TEST(ECPrivateKeyUnitTest, CreateFromPrivateKeyInfo) {
|
||||
0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1,
|
||||
};
|
||||
static const uint8_t kRawPublicKey[] = {
|
||||
0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e,
|
||||
0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d,
|
||||
0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01,
|
||||
0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e,
|
||||
0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d,
|
||||
0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1,
|
||||
0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f,
|
||||
0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e,
|
||||
0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a,
|
||||
0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3,
|
||||
0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5,
|
||||
0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1,
|
||||
};
|
||||
|
||||
std::unique_ptr<crypto::ECPrivateKey> key =
|
||||
@ -242,12 +242,12 @@ TEST(ECPrivateKeyUnitTest, LoadOpenSSLKeyTest) {
|
||||
0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d,
|
||||
};
|
||||
static const uint8_t kOpenSSLRawPublicKey[] = {
|
||||
0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, 0x67, 0xe7,
|
||||
0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34, 0xf6,
|
||||
0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6, 0x50,
|
||||
0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56, 0xfb,
|
||||
0x33, 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27, 0xc5,
|
||||
0xaa, 0x44, 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d,
|
||||
0x04, 0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, 0x67,
|
||||
0xe7, 0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34,
|
||||
0xf6, 0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6,
|
||||
0x50, 0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56,
|
||||
0xfb, 0x33, 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27,
|
||||
0xc5, 0xaa, 0x44, 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d,
|
||||
};
|
||||
|
||||
std::unique_ptr<crypto::ECPrivateKey> keypair_openssl(
|
||||
|
@ -20,6 +20,10 @@ source_set("trust_tokens") {
|
||||
"boringssl_trust_token_issuance_cryptographer.h",
|
||||
"boringssl_trust_token_redemption_cryptographer.cc",
|
||||
"boringssl_trust_token_redemption_cryptographer.h",
|
||||
"ecdsa_p256_key_pair_generator.cc",
|
||||
"ecdsa_p256_key_pair_generator.h",
|
||||
"ecdsa_sha256_trust_token_request_signer.cc",
|
||||
"ecdsa_sha256_trust_token_request_signer.h",
|
||||
"ed25519_key_pair_generator.cc",
|
||||
"ed25519_key_pair_generator.h",
|
||||
"ed25519_trust_token_request_signer.cc",
|
||||
@ -132,8 +136,8 @@ source_set("tests") {
|
||||
|
||||
sources = [
|
||||
"boringssl_trust_token_issuance_cryptographer_unittest.cc",
|
||||
"ecdsa_p256_key_pair_generator_unittest.cc",
|
||||
"ed25519_key_pair_generator_unittest.cc",
|
||||
"ed25519_trust_token_request_signer_unittest.cc",
|
||||
"expiry_inspecting_record_expiry_delegate_unittest.cc",
|
||||
"has_trust_tokens_answerer_unittest.cc",
|
||||
"local_trust_token_operation_delegate_impl_unittest.cc",
|
||||
@ -153,6 +157,7 @@ source_set("tests") {
|
||||
"trust_token_request_helper_factory_unittest.cc",
|
||||
"trust_token_request_issuance_helper_unittest.cc",
|
||||
"trust_token_request_redemption_helper_unittest.cc",
|
||||
"trust_token_request_signer_unittest.cc",
|
||||
"trust_token_request_signing_helper_unittest.cc",
|
||||
"trust_token_store_unittest.cc",
|
||||
"types_unittest.cc",
|
||||
|
@ -0,0 +1,28 @@
|
||||
// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "services/network/trust_tokens/ecdsa_p256_key_pair_generator.h"
|
||||
|
||||
#include "crypto/ec_private_key.h"
|
||||
|
||||
namespace network {
|
||||
|
||||
bool EcdsaP256KeyPairGenerator::Generate(std::string* signing_key_out,
|
||||
std::string* verification_key_out) {
|
||||
std::unique_ptr<crypto::ECPrivateKey> key_pair =
|
||||
crypto::ECPrivateKey::Create();
|
||||
std::vector<uint8_t> private_key;
|
||||
std::string public_key;
|
||||
if (!key_pair->ExportPrivateKey(&private_key)) {
|
||||
return false;
|
||||
}
|
||||
if (!key_pair->ExportRawPublicKey(verification_key_out)) {
|
||||
return false;
|
||||
}
|
||||
signing_key_out->assign(private_key.begin(), private_key.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace network
|
@ -0,0 +1,29 @@
|
||||
// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SERVICES_NETWORK_TRUST_TOKENS_ECDSA_P256_KEY_PAIR_GENERATOR_H_
|
||||
#define SERVICES_NETWORK_TRUST_TOKENS_ECDSA_P256_KEY_PAIR_GENERATOR_H_
|
||||
|
||||
#include "services/network/trust_tokens/trust_token_request_redemption_helper.h"
|
||||
|
||||
namespace network {
|
||||
|
||||
// EcdsaP256KeyPairGenerator generates an ECDSA key pair based on the NIST
|
||||
// P-256 curve. The |verification_key_out| is encoded as an EC point in the
|
||||
// uncompressed point format and the |signing_key_out| is encoded as a PKCS #8
|
||||
// PrivateKeyInfo block.
|
||||
class EcdsaP256KeyPairGenerator
|
||||
: public TrustTokenRequestRedemptionHelper::KeyPairGenerator {
|
||||
public:
|
||||
EcdsaP256KeyPairGenerator() = default;
|
||||
~EcdsaP256KeyPairGenerator() override = default;
|
||||
|
||||
// TrustTokenRequestRedemptionHelper::KeyPairGenerator implementation:
|
||||
bool Generate(std::string* signing_key_out,
|
||||
std::string* verification_key_out) override;
|
||||
};
|
||||
|
||||
} // namespace network
|
||||
|
||||
#endif // SERVICES_NETWORK_TRUST_TOKENS_ECDSA_P256_KEY_PAIR_GENERATOR_H_
|
@ -0,0 +1,31 @@
|
||||
// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "services/network/trust_tokens/ecdsa_p256_key_pair_generator.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace network {
|
||||
|
||||
TEST(EcdsaP256KeyPairGenerator, Roundtrip) {
|
||||
auto message = base::as_bytes(base::make_span(
|
||||
"Four score and seven years ago our fathers brought forth on this "
|
||||
"continent, a new nation, conceived in Liberty, and dedicated to the "
|
||||
"proposition that all men are created equal."));
|
||||
|
||||
std::string signing, verification;
|
||||
ASSERT_TRUE(EcdsaP256KeyPairGenerator().Generate(&signing, &verification));
|
||||
|
||||
EcdsaSha256TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(base::as_bytes(base::make_span(signing)), message);
|
||||
ASSERT_TRUE(signature);
|
||||
|
||||
EXPECT_TRUE(signer.Verify(message, *signature,
|
||||
base::as_bytes(base::make_span(verification))));
|
||||
}
|
||||
|
||||
} // namespace network
|
@ -0,0 +1,90 @@
|
||||
// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.h"
|
||||
|
||||
#include "crypto/ec_private_key.h"
|
||||
#include "crypto/ec_signature_creator.h"
|
||||
#include "crypto/signature_verifier.h"
|
||||
#include "third_party/boringssl/src/include/openssl/bytestring.h"
|
||||
#include "third_party/boringssl/src/include/openssl/digest.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/mem.h"
|
||||
|
||||
namespace network {
|
||||
|
||||
EcdsaSha256TrustTokenRequestSigner::EcdsaSha256TrustTokenRequestSigner() =
|
||||
default;
|
||||
EcdsaSha256TrustTokenRequestSigner::~EcdsaSha256TrustTokenRequestSigner() =
|
||||
default;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> EcdsaSha256TrustTokenRequestSigner::Sign(
|
||||
base::span<const uint8_t> key,
|
||||
base::span<const uint8_t> data) {
|
||||
std::unique_ptr<crypto::ECPrivateKey> private_key =
|
||||
crypto::ECPrivateKey::CreateFromPrivateKeyInfo(key);
|
||||
if (!private_key)
|
||||
return absl::nullopt;
|
||||
|
||||
EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(private_key->key());
|
||||
if (!ec_key)
|
||||
return absl::nullopt;
|
||||
|
||||
if (EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) !=
|
||||
NID_X9_62_prime256v1)
|
||||
return absl::nullopt;
|
||||
|
||||
std::unique_ptr<crypto::ECSignatureCreator> sig_creator =
|
||||
crypto::ECSignatureCreator::Create(private_key.get());
|
||||
|
||||
std::vector<uint8_t> signature;
|
||||
|
||||
if (!sig_creator->Sign(data.data(), data.size(), &signature))
|
||||
return absl::nullopt;
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
bool EcdsaSha256TrustTokenRequestSigner::Verify(
|
||||
base::span<const uint8_t> data,
|
||||
base::span<const uint8_t> signature,
|
||||
base::span<const uint8_t> verification_key) {
|
||||
// Require the public key be in uncompressed form. EC_POINT_oct2point
|
||||
// also accepts compressed form.
|
||||
if (verification_key.empty() ||
|
||||
verification_key[0] != POINT_CONVERSION_UNCOMPRESSED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
|
||||
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(EC_KEY_get0_group(key.get())));
|
||||
if (!EC_POINT_oct2point(EC_KEY_get0_group(key.get()), pub_key.get(),
|
||||
verification_key.data(), verification_key.size(),
|
||||
nullptr) ||
|
||||
!EC_KEY_set_public_key(key.get(), pub_key.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<EVP_PKEY> public_key(EVP_PKEY_new());
|
||||
if (!EVP_PKEY_set1_EC_KEY(public_key.get(), key.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bssl::ScopedEVP_MD_CTX ctx;
|
||||
EVP_PKEY_CTX* pctx;
|
||||
if (!EVP_DigestVerifyInit(ctx.get(), &pctx, EVP_sha256(), nullptr,
|
||||
public_key.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return EVP_DigestVerify(ctx.get(), signature.data(), signature.size(),
|
||||
data.data(), data.size());
|
||||
}
|
||||
|
||||
std::string EcdsaSha256TrustTokenRequestSigner::GetAlgorithmIdentifier() {
|
||||
return "EcdsaSha256TrustTokenRequestSigner";
|
||||
}
|
||||
|
||||
} // namespace network
|
@ -0,0 +1,36 @@
|
||||
// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SERVICES_NETWORK_TRUST_TOKENS_ECDSA_SHA256_TRUST_TOKEN_REQUEST_SIGNER_H_
|
||||
#define SERVICES_NETWORK_TRUST_TOKENS_ECDSA_SHA256_TRUST_TOKEN_REQUEST_SIGNER_H_
|
||||
|
||||
#include "services/network/trust_tokens/trust_token_request_signing_helper.h"
|
||||
|
||||
namespace network {
|
||||
|
||||
// EcdsaSha256TrustTokenRequestSigner provides a wrapper around BoringSSL's
|
||||
// ECDSA signing and verification routines capable of satisfying the Trust
|
||||
// Tokens signing request helper's Signer delegate interface. The signature is a
|
||||
// DER encoded ECDSA-Sig-Value from RFC 3279.
|
||||
class EcdsaSha256TrustTokenRequestSigner
|
||||
: public TrustTokenRequestSigningHelper::Signer {
|
||||
public:
|
||||
EcdsaSha256TrustTokenRequestSigner();
|
||||
~EcdsaSha256TrustTokenRequestSigner() override;
|
||||
|
||||
// TrustTokenRequestSigningHelper::Signer implementation:
|
||||
absl::optional<std::vector<uint8_t>> Sign(
|
||||
base::span<const uint8_t> key,
|
||||
base::span<const uint8_t> data) override;
|
||||
|
||||
bool Verify(base::span<const uint8_t> data,
|
||||
base::span<const uint8_t> signature,
|
||||
base::span<const uint8_t> verification_key) override;
|
||||
|
||||
std::string GetAlgorithmIdentifier() override;
|
||||
};
|
||||
|
||||
} // namespace network
|
||||
|
||||
#endif // SERVICES_NETWORK_TRUST_TOKENS_ECDSA_SHA256_TRUST_TOKEN_REQUEST_SIGNER_H_
|
@ -1,216 +0,0 @@
|
||||
// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "services/network/trust_tokens/ed25519_trust_token_request_signer.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/boringssl/src/include/openssl/curve25519.h"
|
||||
|
||||
namespace network {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Keys {
|
||||
std::array<uint8_t, ED25519_PRIVATE_KEY_LEN> signing;
|
||||
std::array<uint8_t, ED25519_PUBLIC_KEY_LEN> verification;
|
||||
};
|
||||
|
||||
// The fixed constant 32 comes from curve25519.h and is not defined in a macro.
|
||||
Keys KeysFromSeed(base::span<const uint8_t, 32> seed) {
|
||||
Keys ret;
|
||||
|
||||
// Cannot fail.
|
||||
ED25519_keypair_from_seed(ret.verification.data(), ret.signing.data(),
|
||||
seed.data());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char kLongishMessage[] =
|
||||
"Four score and seven years ago our fathers brought forth on this "
|
||||
"continent, a new nation, conceived in Liberty, and dedicated to the "
|
||||
"proposition that all men are created equal.";
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, Roundtrip) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(keys.signing, message);
|
||||
ASSERT_TRUE(signature);
|
||||
|
||||
EXPECT_TRUE(signer.Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, EmptyMessage) {
|
||||
auto message = base::span<const uint8_t>();
|
||||
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(keys.signing, message);
|
||||
ASSERT_TRUE(signature);
|
||||
|
||||
EXPECT_TRUE(signer.Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, ShortMessage) {
|
||||
auto message = base::as_bytes(base::make_span("Hello"));
|
||||
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(keys.signing, message);
|
||||
ASSERT_TRUE(signature);
|
||||
|
||||
EXPECT_TRUE(signer.Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, LongerMessage) {
|
||||
std::vector<uint8_t> message(1000000);
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(keys.signing, message);
|
||||
ASSERT_TRUE(signature);
|
||||
|
||||
EXPECT_TRUE(signer.Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, VerificationFromDifferentSigner) {
|
||||
// Test that Verify works without prior initialization and signing, as its
|
||||
// contract promises.
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(keys.signing, message);
|
||||
|
||||
Ed25519TrustTokenRequestSigner verifier;
|
||||
EXPECT_TRUE(verifier.Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, SigningKeyTooShort) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(base::make_span(keys.signing).subspan(1), message);
|
||||
EXPECT_FALSE(signature);
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, SigningKeyTooLong) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
std::vector<uint8_t> overlong_signing_key(ED25519_PRIVATE_KEY_LEN + 1);
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(overlong_signing_key, message);
|
||||
EXPECT_FALSE(signature);
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, VerificationKeyTooShort) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(keys.signing, message);
|
||||
|
||||
EXPECT_FALSE(signer.Verify(message, *signature,
|
||||
base::make_span(keys.verification).subspan(1)));
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, VerificationKeyTooLong) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(keys.signing, message);
|
||||
|
||||
std::vector<uint8_t> overlong_verification_key(ED25519_PUBLIC_KEY_LEN + 1);
|
||||
|
||||
EXPECT_FALSE(signer.Verify(message, *signature, overlong_verification_key));
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, SignatureTooShort) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(keys.signing, message);
|
||||
signature->pop_back();
|
||||
|
||||
EXPECT_FALSE(signer.Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, SignatureTooLong) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(keys.signing, message);
|
||||
signature->push_back(0);
|
||||
|
||||
EXPECT_FALSE(
|
||||
signer.Verify(message, base::make_span(*signature), keys.verification));
|
||||
}
|
||||
|
||||
TEST(Ed25519TrustTokenRequestSigner, SignatureWrong) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
Keys keys = KeysFromSeed(seed);
|
||||
|
||||
Ed25519TrustTokenRequestSigner signer;
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer.Sign(keys.signing, message);
|
||||
|
||||
// Corrupt the signature.
|
||||
signature->front() += 1;
|
||||
|
||||
EXPECT_FALSE(signer.Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
} // namespace network
|
@ -0,0 +1,282 @@
|
||||
// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "crypto/ec_private_key.h"
|
||||
#include "services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.h"
|
||||
#include "services/network/trust_tokens/ed25519_trust_token_request_signer.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/boringssl/src/include/openssl/curve25519.h"
|
||||
|
||||
namespace network {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Keys {
|
||||
std::vector<uint8_t> signing;
|
||||
std::vector<uint8_t> verification;
|
||||
};
|
||||
|
||||
const char kLongishMessage[] =
|
||||
"Four score and seven years ago our fathers brought forth on this "
|
||||
"continent, a new nation, conceived in Liberty, and dedicated to the "
|
||||
"proposition that all men are created equal.";
|
||||
|
||||
enum class RequestSigner {
|
||||
kEd25519 = 0,
|
||||
kEcdsaSha256 = 1,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class TrustTokenRequestSigner : public ::testing::TestWithParam<RequestSigner> {
|
||||
protected:
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> CreateSigner() {
|
||||
switch (GetParam()) {
|
||||
case RequestSigner::kEd25519:
|
||||
return std::make_unique<Ed25519TrustTokenRequestSigner>();
|
||||
|
||||
case RequestSigner::kEcdsaSha256:
|
||||
return std::make_unique<EcdsaSha256TrustTokenRequestSigner>();
|
||||
}
|
||||
}
|
||||
|
||||
// The fixed constant 32 comes from curve25519.h and is not defined in a
|
||||
// macro.
|
||||
Keys GetTestKeys() {
|
||||
Keys ret;
|
||||
switch (GetParam()) {
|
||||
case RequestSigner::kEd25519: {
|
||||
ret.signing.resize(ED25519_PRIVATE_KEY_LEN);
|
||||
ret.verification.resize(ED25519_PUBLIC_KEY_LEN);
|
||||
// Cannot fail.
|
||||
std::array<uint8_t, 32> seed{1, 2, 3, 4, 5};
|
||||
ED25519_keypair_from_seed(ret.verification.data(), ret.signing.data(),
|
||||
seed.data());
|
||||
break;
|
||||
}
|
||||
case RequestSigner::kEcdsaSha256:
|
||||
const std::vector<uint8_t> private_key = {
|
||||
0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a,
|
||||
0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
|
||||
0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01,
|
||||
0x01, 0x04, 0x20, 0x7f, 0x4c, 0x85, 0x5d, 0xcb, 0xd5, 0x3e, 0x9e,
|
||||
0xed, 0x0a, 0x34, 0xc9, 0xbf, 0xbc, 0xfb, 0x0e, 0xcd, 0xd8, 0xa0,
|
||||
0x89, 0x7e, 0x1d, 0xaf, 0x1c, 0x1e, 0x9f, 0x8c, 0x9f, 0xac, 0x21,
|
||||
0xee, 0xa5, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x62, 0x22, 0x44,
|
||||
0x4b, 0x41, 0x0e, 0x16, 0xcc, 0x6e, 0xbb, 0x72, 0xb9, 0xe5, 0x70,
|
||||
0xba, 0x13, 0xd0, 0xd2, 0x1f, 0x8f, 0x2a, 0x10, 0x57, 0x32, 0x77,
|
||||
0xb8, 0xd0, 0x62, 0x7e, 0x4d, 0x18, 0x6d, 0xc2, 0x87, 0x25, 0x17,
|
||||
0x45, 0x11, 0x82, 0xf2, 0x93, 0xed, 0xd5, 0x60, 0x7f, 0xae, 0x67,
|
||||
0x87, 0x39, 0x15, 0x90, 0x16, 0x91, 0x3c, 0xf9, 0x11, 0x76, 0x09,
|
||||
0xfa, 0x51, 0x90, 0xa4, 0x2f, 0x9a};
|
||||
std::unique_ptr<crypto::ECPrivateKey> key =
|
||||
crypto::ECPrivateKey::CreateFromPrivateKeyInfo(private_key);
|
||||
std::vector<uint8_t> ec_private_key;
|
||||
key->ExportPrivateKey(&ec_private_key);
|
||||
ret.signing.swap(ec_private_key);
|
||||
|
||||
std::string public_key;
|
||||
key->ExportRawPublicKey(&public_key);
|
||||
ret.verification =
|
||||
std::vector<uint8_t>(public_key.begin(), public_key.end());
|
||||
std::string raw_public_key;
|
||||
key->ExportRawPublicKey(&raw_public_key);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}; // namespace network
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, Roundtrip) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(keys.signing, message);
|
||||
ASSERT_TRUE(signature);
|
||||
|
||||
EXPECT_TRUE(signer->Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, EmptyMessage) {
|
||||
auto message = base::span<const uint8_t>();
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(keys.signing, message);
|
||||
ASSERT_TRUE(signature);
|
||||
|
||||
EXPECT_TRUE(signer->Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, ShortMessage) {
|
||||
auto message = base::as_bytes(base::make_span("Hello"));
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(keys.signing, message);
|
||||
ASSERT_TRUE(signature);
|
||||
|
||||
EXPECT_TRUE(signer->Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, LongerMessage) {
|
||||
std::vector<uint8_t> message(1000000);
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(keys.signing, message);
|
||||
ASSERT_TRUE(signature);
|
||||
|
||||
EXPECT_TRUE(signer->Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, VerificationFromDifferentSigner) {
|
||||
// Test that Verify works without prior initialization and signing, as its
|
||||
// contract promises.
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(keys.signing, message);
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> verifier =
|
||||
CreateSigner();
|
||||
EXPECT_TRUE(verifier->Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, SigningKeyTooShort) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(base::make_span(keys.signing).subspan(1), message);
|
||||
EXPECT_FALSE(signature);
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, SigningKeyTooLong) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
std::vector<uint8_t> overlong_signing_key(keys.signing.size() + 1);
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(overlong_signing_key, message);
|
||||
EXPECT_FALSE(signature);
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, VerificationKeyTooShort) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(keys.signing, message);
|
||||
|
||||
EXPECT_FALSE(signer->Verify(message, *signature,
|
||||
base::make_span(keys.verification).subspan(1)));
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, VerificationKeyTooLong) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(keys.signing, message);
|
||||
|
||||
std::vector<uint8_t> overlong_verification_key(keys.verification.size() + 1);
|
||||
|
||||
EXPECT_FALSE(signer->Verify(message, *signature, overlong_verification_key));
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, SignatureTooShort) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(keys.signing, message);
|
||||
signature->pop_back();
|
||||
|
||||
EXPECT_FALSE(signer->Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, SignatureTooLong) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(keys.signing, message);
|
||||
signature->push_back(0);
|
||||
|
||||
EXPECT_FALSE(
|
||||
signer->Verify(message, base::make_span(*signature), keys.verification));
|
||||
}
|
||||
|
||||
TEST_P(TrustTokenRequestSigner, SignatureWrong) {
|
||||
auto message = base::as_bytes(base::make_span(kLongishMessage));
|
||||
|
||||
Keys keys = GetTestKeys();
|
||||
|
||||
std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer =
|
||||
CreateSigner();
|
||||
|
||||
absl::optional<std::vector<uint8_t>> signature =
|
||||
signer->Sign(keys.signing, message);
|
||||
|
||||
// Corrupt the signature.
|
||||
signature->front() += 1;
|
||||
|
||||
EXPECT_FALSE(signer->Verify(message, *signature, keys.verification));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Algorithm,
|
||||
TrustTokenRequestSigner,
|
||||
::testing::Values(RequestSigner::kEd25519, RequestSigner::kEcdsaSha256),
|
||||
[](const testing::TestParamInfo<TrustTokenRequestSigner::ParamType>& info) {
|
||||
return info.param == RequestSigner::kEd25519 ? "ED25519" : "ECDSA_SHA256";
|
||||
});
|
||||
|
||||
} // namespace network
|
Reference in New Issue
Block a user