| Index: net/base/keygen_handler_unittest.cc
|
| diff --git a/net/base/keygen_handler_unittest.cc b/net/base/keygen_handler_unittest.cc
|
| index c1b5fe44e0064b97989fd441052af9a7cefd3d15..b045ababacd60548b4dc775d7cdc1fc7d7299c4e 100644
|
| --- a/net/base/keygen_handler_unittest.cc
|
| +++ b/net/base/keygen_handler_unittest.cc
|
| @@ -4,6 +4,10 @@
|
|
|
| #include "net/base/keygen_handler.h"
|
|
|
| +#include <openssl/bytestring.h>
|
| +#include <openssl/evp.h>
|
| +#include <stdint.h>
|
| +
|
| #include <string>
|
| #include <utility>
|
|
|
| @@ -11,10 +15,12 @@
|
| #include "base/bind.h"
|
| #include "base/location.h"
|
| #include "base/logging.h"
|
| +#include "base/strings/string_piece.h"
|
| #include "base/synchronization/waitable_event.h"
|
| #include "base/threading/thread_restrictions.h"
|
| #include "base/threading/worker_pool.h"
|
| #include "build/build_config.h"
|
| +#include "crypto/scoped_openssl_types.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| #if defined(USE_NSS_CERTS)
|
| @@ -48,14 +54,16 @@ class StubCryptoModuleDelegate : public crypto::NSSCryptoModuleDelegate {
|
| };
|
| #endif
|
|
|
| +const char kChallenge[] = "some challenge";
|
| +
|
| class KeygenHandlerTest : public ::testing::Test {
|
| public:
|
| KeygenHandlerTest() {}
|
| ~KeygenHandlerTest() override {}
|
|
|
| scoped_ptr<KeygenHandler> CreateKeygenHandler() {
|
| - scoped_ptr<KeygenHandler> handler(new KeygenHandler(
|
| - 768, "some challenge", GURL("http://www.example.com")));
|
| + scoped_ptr<KeygenHandler> handler(
|
| + new KeygenHandler(768, kChallenge, GURL("http://www.example.com")));
|
| #if defined(USE_NSS_CERTS)
|
| handler->set_crypto_module_delegate(
|
| scoped_ptr<crypto::NSSCryptoModuleDelegate>(
|
| @@ -71,40 +79,89 @@ class KeygenHandlerTest : public ::testing::Test {
|
| #endif
|
| };
|
|
|
| +base::StringPiece StringPieceFromCBS(const CBS& cbs) {
|
| + return base::StringPiece(reinterpret_cast<const char*>(CBS_data(&cbs)),
|
| + CBS_len(&cbs));
|
| +}
|
| +
|
| // Assert that |result| is a valid output for KeygenHandler given challenge
|
| // string of |challenge|.
|
| void AssertValidSignedPublicKeyAndChallenge(const std::string& result,
|
| const std::string& challenge) {
|
| - ASSERT_GT(result.length(), 0U);
|
| -
|
| // Verify it's valid base64:
|
| std::string spkac;
|
| ASSERT_TRUE(base::Base64Decode(result, &spkac));
|
| - // In lieu of actually parsing and validating the DER data,
|
| - // just check that it exists and has a reasonable length.
|
| - // (It's almost always 590 bytes, but the DER encoding of the random key
|
| - // and signature could sometimes be a few bytes different.)
|
| - ASSERT_GE(spkac.length(), 200U);
|
| - ASSERT_LE(spkac.length(), 300U);
|
| -
|
| - // NOTE:
|
| - // The value of |result| can be validated by prefixing 'SPKAC=' to it
|
| - // and piping it through
|
| - // openssl spkac -verify
|
| - // whose output should look like:
|
| - // Netscape SPKI:
|
| - // Public Key Algorithm: rsaEncryption
|
| - // RSA Public Key: (2048 bit)
|
| - // Modulus (2048 bit):
|
| - // 00:b6:cc:14:c9:43:b5:2d:51:65:7e:11:8b:80:9e: .....
|
| - // Exponent: 65537 (0x10001)
|
| - // Challenge String: some challenge
|
| - // Signature Algorithm: md5WithRSAEncryption
|
| - // 92:f3:cc:ff:0b:d3:d0:4a:3a:4c:ba:ff:d6:38:7f:a5:4b:b5: .....
|
| - // Signature OK
|
| +
|
| + // Parse the following structure:
|
| //
|
| - // The value of |spkac| can be ASN.1-parsed with:
|
| - // openssl asn1parse -inform DER
|
| + // PublicKeyAndChallenge ::= SEQUENCE {
|
| + // spki SubjectPublicKeyInfo,
|
| + // challenge IA5STRING
|
| + // }
|
| + // SignedPublicKeyAndChallenge ::= SEQUENCE {
|
| + // publicKeyAndChallenge PublicKeyAndChallenge,
|
| + // signatureAlgorithm AlgorithmIdentifier,
|
| + // signature BIT STRING
|
| + // }
|
| +
|
| + CBS cbs;
|
| + CBS_init(&cbs, reinterpret_cast<const uint8_t*>(spkac.data()), spkac.size());
|
| +
|
| + // The input should consist of a SEQUENCE.
|
| + CBS child;
|
| + ASSERT_TRUE(CBS_get_asn1(&cbs, &child, CBS_ASN1_SEQUENCE));
|
| + ASSERT_EQ(0u, CBS_len(&cbs));
|
| +
|
| + // Extract the raw PublicKeyAndChallenge.
|
| + CBS public_key_and_challenge_raw;
|
| + ASSERT_TRUE(CBS_get_asn1_element(&child, &public_key_and_challenge_raw,
|
| + CBS_ASN1_SEQUENCE));
|
| +
|
| + // Parse out the PublicKeyAndChallenge.
|
| + CBS copy = public_key_and_challenge_raw;
|
| + CBS public_key_and_challenge;
|
| + ASSERT_TRUE(
|
| + CBS_get_asn1(©, &public_key_and_challenge, CBS_ASN1_SEQUENCE));
|
| + ASSERT_EQ(0u, CBS_len(©));
|
| + crypto::ScopedEVP_PKEY key(EVP_parse_public_key(&public_key_and_challenge));
|
| + ASSERT_TRUE(key);
|
| + CBS challenge_spkac;
|
| + ASSERT_TRUE(CBS_get_asn1(&public_key_and_challenge, &challenge_spkac,
|
| + CBS_ASN1_IA5STRING));
|
| + ASSERT_EQ(0u, CBS_len(&public_key_and_challenge));
|
| +
|
| + // The challenge must match.
|
| + ASSERT_EQ(challenge, StringPieceFromCBS(challenge_spkac));
|
| +
|
| + // The next element must be the AlgorithmIdentifier for MD5 with RSA.
|
| + static const uint8_t kMd5WithRsaEncryption[] = {
|
| + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
| + 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00,
|
| + };
|
| + CBS algorithm;
|
| + ASSERT_TRUE(CBS_get_bytes(&child, &algorithm, sizeof(kMd5WithRsaEncryption)));
|
| + ASSERT_EQ(
|
| + base::StringPiece(reinterpret_cast<const char*>(kMd5WithRsaEncryption),
|
| + sizeof(kMd5WithRsaEncryption)),
|
| + StringPieceFromCBS(algorithm));
|
| +
|
| + // Finally, parse the signature.
|
| + CBS signature;
|
| + ASSERT_TRUE(CBS_get_asn1(&child, &signature, CBS_ASN1_BITSTRING));
|
| + ASSERT_EQ(0u, CBS_len(&child));
|
| + uint8_t pad;
|
| + ASSERT_TRUE(CBS_get_u8(&signature, &pad));
|
| + ASSERT_EQ(0u, pad);
|
| +
|
| + // Check the signature.
|
| + crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
|
| + ASSERT_TRUE(
|
| + EVP_DigestVerifyInit(ctx.get(), nullptr, EVP_md5(), nullptr, key.get()));
|
| + ASSERT_TRUE(EVP_DigestVerifyUpdate(ctx.get(),
|
| + CBS_data(&public_key_and_challenge_raw),
|
| + CBS_len(&public_key_and_challenge_raw)));
|
| + ASSERT_TRUE(EVP_DigestVerifyFinal(ctx.get(), CBS_data(&signature),
|
| + CBS_len(&signature)));
|
| }
|
|
|
| TEST_F(KeygenHandlerTest, SmokeTest) {
|
| @@ -112,7 +169,7 @@ TEST_F(KeygenHandlerTest, SmokeTest) {
|
| handler->set_stores_key(false); // Don't leave the key-pair behind
|
| std::string result = handler->GenKeyAndSignChallenge();
|
| VLOG(1) << "KeygenHandler produced: " << result;
|
| - AssertValidSignedPublicKeyAndChallenge(result, "some challenge");
|
| + AssertValidSignedPublicKeyAndChallenge(result, kChallenge);
|
| }
|
|
|
| void ConcurrencyTestCallback(const std::string& challenge,
|
|
|