diff options
-rw-r--r-- | net/net.gyp | 6 | ||||
-rw-r--r-- | net/quic/crypto/channel_id.h | 4 | ||||
-rw-r--r-- | net/quic/crypto/channel_id_openssl.cc | 11 | ||||
-rw-r--r-- | net/quic/crypto/channel_id_test.cc | 5 | ||||
-rw-r--r-- | net/quic/crypto/crypto_handshake.cc | 4 | ||||
-rw-r--r-- | net/quic/crypto/crypto_handshake.h | 2 | ||||
-rw-r--r-- | net/quic/quic_crypto_server_stream_test.cc | 7 | ||||
-rw-r--r-- | net/quic/test_tools/crypto_test_utils.cc | 7 | ||||
-rw-r--r-- | net/quic/test_tools/crypto_test_utils.h | 6 | ||||
-rw-r--r-- | net/quic/test_tools/crypto_test_utils_nss.cc | 103 | ||||
-rw-r--r-- | net/quic/test_tools/crypto_test_utils_openssl.cc | 7 |
11 files changed, 122 insertions, 40 deletions
diff --git a/net/net.gyp b/net/net.gyp index c82af14..5a0bc49 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -2732,6 +2732,12 @@ 'tools/quic/test_tools/run_all_unittests.cc', ], 'conditions': [ + [ 'use_glib == 1', { + 'dependencies': [ + '../build/linux/system.gyp:ssl', + ], + }, + ], [ 'use_openssl==1', { # When building for OpenSSL, we need to exclude NSS specific tests. 'sources!': [ diff --git a/net/quic/crypto/channel_id.h b/net/quic/crypto/channel_id.h index 6151f0f..2d0c29d 100644 --- a/net/quic/crypto/channel_id.h +++ b/net/quic/crypto/channel_id.h @@ -25,6 +25,10 @@ class NET_EXPORT_PRIVATE ChannelIDSigner { base::StringPiece signed_data, std::string* out_key, std::string* out_signature) = 0; + + // GetKeyForHostname returns the ChannelID key that |ChannelIDSigner| will use + // for the given hostname. + virtual std::string GetKeyForHostname(const std::string& hostname) = 0; }; // ChannelIDVerifier verifies ChannelID signatures. diff --git a/net/quic/crypto/channel_id_openssl.cc b/net/quic/crypto/channel_id_openssl.cc index d27bbb4..241acae 100644 --- a/net/quic/crypto/channel_id_openssl.cc +++ b/net/quic/crypto/channel_id_openssl.cc @@ -47,12 +47,13 @@ bool ChannelIDVerifier::VerifyRaw(StringPiece key, sig.s = s.get(); const uint8* key_bytes = reinterpret_cast<const uint8*>(key.data()); - const uint8* proof_bytes = reinterpret_cast<const uint8*>(signature.data()); + const uint8* signature_bytes = + reinterpret_cast<const uint8*>(signature.data()); - if (BN_bin2bn(key_bytes + 0, 32, x.get()) == NULL || - BN_bin2bn(key_bytes + 32, 32, y.get()) == NULL || - BN_bin2bn(proof_bytes + 0, 32, sig.r) == NULL || - BN_bin2bn(proof_bytes + 32, 32, sig.s) == NULL) { + if (BN_bin2bn(key_bytes + 0, 32, x.get()) == NULL || + BN_bin2bn(key_bytes + 32, 32, y.get()) == NULL || + BN_bin2bn(signature_bytes + 0, 32, sig.r) == NULL || + BN_bin2bn(signature_bytes + 32, 32, sig.s) == NULL) { return false; } diff --git a/net/quic/crypto/channel_id_test.cc b/net/quic/crypto/channel_id_test.cc index 41851be..d29bfce 100644 --- a/net/quic/crypto/channel_id_test.cc +++ b/net/quic/crypto/channel_id_test.cc @@ -267,8 +267,7 @@ TEST(ChannelIDTest, VerifyKnownAnswerTest) { } } -// TODO(rtenneti): Enable testing of ChannelID. -TEST(ChannelIDTest, DISABLED_SignAndVerify) { +TEST(ChannelIDTest, SignAndVerify) { scoped_ptr<ChannelIDSigner> signer( CryptoTestUtils::ChannelIDSignerForTesting()); @@ -277,7 +276,7 @@ TEST(ChannelIDTest, DISABLED_SignAndVerify) { string key, signature; ASSERT_TRUE(signer->Sign(hostname, signed_data, &key, &signature)); - EXPECT_EQ(key, CryptoTestUtils::ChannelIDKeyForHostname(hostname)); + EXPECT_EQ(key, signer->GetKeyForHostname(hostname)); EXPECT_TRUE(ChannelIDVerifier::Verify(key, signed_data, signature)); diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc index bd5a4a5..be296be 100644 --- a/net/quic/crypto/crypto_handshake.cc +++ b/net/quic/crypto/crypto_handshake.cc @@ -844,6 +844,10 @@ void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier* verifier) { proof_verifier_.reset(verifier); } +ChannelIDSigner* QuicCryptoClientConfig::channel_id_signer() const { + return channel_id_signer_.get(); +} + void QuicCryptoClientConfig::SetChannelIDSigner(ChannelIDSigner* signer) { channel_id_signer_.reset(signer); } diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h index 1727a08..919f777 100644 --- a/net/quic/crypto/crypto_handshake.h +++ b/net/quic/crypto/crypto_handshake.h @@ -356,6 +356,8 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // the server. void SetProofVerifier(ProofVerifier* verifier); + ChannelIDSigner* channel_id_signer() const; + // SetChannelIDSigner sets a ChannelIDSigner that will be called when the // server supports channel IDs to sign a message proving possession of the // given ChannelID. This object takes ownership of |signer|. diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc index cb26ac95..fb829db 100644 --- a/net/quic/quic_crypto_server_stream_test.cc +++ b/net/quic/quic_crypto_server_stream_test.cc @@ -249,8 +249,7 @@ TEST_F(QuicCryptoServerStreamTest, WithoutCertificates) { EXPECT_TRUE(stream_.handshake_confirmed()); } -// TODO(rtenneti): Enable testing of ChannelID. -TEST_F(QuicCryptoServerStreamTest, DISABLED_ChannelID) { +TEST_F(QuicCryptoServerStreamTest, ChannelID) { if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; @@ -258,11 +257,11 @@ TEST_F(QuicCryptoServerStreamTest, DISABLED_ChannelID) { client_options_.channel_id_enabled = true; // TODO(rtenneti): Enable testing of ProofVerifier. + // CompleteCryptoHandshake verifies + // stream_.crypto_negotiated_params().channel_id is correct. EXPECT_EQ(2, CompleteCryptoHandshake()); EXPECT_TRUE(stream_.encryption_established()); EXPECT_TRUE(stream_.handshake_confirmed()); - EXPECT_EQ(CryptoTestUtils::ChannelIDKeyForHostname("test.example.com"), - stream_.crypto_negotiated_params().channel_id); } } // namespace diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc index d469bfa..113bdde 100644 --- a/net/quic/test_tools/crypto_test_utils.cc +++ b/net/quic/test_tools/crypto_test_utils.cc @@ -4,6 +4,7 @@ #include "net/quic/test_tools/crypto_test_utils.h" +#include "net/quic/crypto/channel_id.h" #include "net/quic/crypto/common_cert_set.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/crypto_server_config.h" @@ -191,6 +192,12 @@ int CryptoTestUtils::HandshakeWithFakeClient( CompareClientAndServerKeys(&client, server); + if (options.channel_id_enabled) { + EXPECT_EQ(crypto_config.channel_id_signer()->GetKeyForHostname( + "test.example.com"), + server->crypto_negotiated_params().channel_id); + } + return client.num_sent_client_hellos(); } diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h index 3946c44..7b0c952 100644 --- a/net/quic/test_tools/crypto_test_utils.h +++ b/net/quic/test_tools/crypto_test_utils.h @@ -46,7 +46,7 @@ class CryptoTestUtils { // If channel_id_enabled is true then the client will attempt to send a // ChannelID. The key will be the same as is returned by - // |ChannelIDKeyForHostname|. + // ChannelIDSigner's |GetKeyForHostname|. bool channel_id_enabled; }; @@ -120,10 +120,6 @@ class CryptoTestUtils { // deterministically based on the hostname given in the Sign call. static ChannelIDSigner* ChannelIDSignerForTesting(); - // ChannelIDKeyForHostname returns the ChannelID key that - // |ChannelIDSignerForTesting| will use for the given hostname. - static std::string ChannelIDKeyForHostname(const std::string& hostname); - private: static void CompareClientAndServerKeys(QuicCryptoClientStream* client, QuicCryptoServerStream* server); diff --git a/net/quic/test_tools/crypto_test_utils_nss.cc b/net/quic/test_tools/crypto_test_utils_nss.cc index d6be917..88c8767 100644 --- a/net/quic/test_tools/crypto_test_utils_nss.cc +++ b/net/quic/test_tools/crypto_test_utils_nss.cc @@ -4,6 +4,13 @@ #include "net/quic/test_tools/crypto_test_utils.h" +#include <keyhi.h> +#include <pk11pub.h> +#include <sechash.h> + +#include "base/stl_util.h" +#include "base/strings/string_util.h" +#include "crypto/ec_private_key.h" #include "net/quic/crypto/channel_id.h" using base::StringPiece; @@ -18,7 +25,9 @@ namespace test { // implement real ChannelIDSigner. class TestChannelIDSigner : public ChannelIDSigner { public: - virtual ~TestChannelIDSigner() { } + virtual ~TestChannelIDSigner() { + STLDeleteValues(&hostname_to_key_); + } // ChannelIDSigner implementation. @@ -26,32 +35,97 @@ class TestChannelIDSigner : public ChannelIDSigner { StringPiece signed_data, string* out_key, string* out_signature) OVERRIDE { - string key(HostnameToKey(hostname)); + crypto::ECPrivateKey* ecdsa_keypair = HostnameToKey(hostname); + if (!ecdsa_keypair) { + return false; + } - *out_key = SerializeKey(key); + *out_key = SerializeKey(ecdsa_keypair->public_key()); if (out_key->empty()) { return false; } - *out_signature = signed_data.as_string(); + unsigned char hash_buf[SHA256_LENGTH]; + SECItem hash_item = { siBuffer, hash_buf, sizeof(hash_buf) }; + HASHContext* sha256 = HASH_Create(HASH_AlgSHA256); + if (!sha256) { + return false; + } + HASH_Begin(sha256); + HASH_Update(sha256, + reinterpret_cast<const unsigned char*>( + ChannelIDVerifier::kContextStr), + strlen(ChannelIDVerifier::kContextStr) + 1); + HASH_Update(sha256, + reinterpret_cast<const unsigned char*>( + ChannelIDVerifier::kClientToServerStr), + strlen(ChannelIDVerifier::kClientToServerStr) + 1); + HASH_Update(sha256, + reinterpret_cast<const unsigned char*>(signed_data.data()), + signed_data.size()); + HASH_End(sha256, hash_buf, &hash_item.len, sizeof(hash_buf)); + HASH_Destroy(sha256); + + // The signature consists of a pair of 32-byte numbers. + static const unsigned int kSignatureLength = 32 * 2; + string signature; + SECItem sig_item = { + siBuffer, + reinterpret_cast<unsigned char*>( + WriteInto(&signature, kSignatureLength + 1)), + kSignatureLength + }; + + if (PK11_Sign(ecdsa_keypair->key(), &sig_item, &hash_item) != SECSuccess) { + return false; + } + *out_signature = signature; return true; } - static string KeyForHostname(const string& hostname) { - string key(HostnameToKey(hostname)); - return SerializeKey(key); + virtual string GetKeyForHostname(const string& hostname) OVERRIDE { + crypto::ECPrivateKey* ecdsa_keypair = HostnameToKey(hostname); + if (!ecdsa_keypair) { + return ""; + } + return SerializeKey(ecdsa_keypair->public_key()); } private: - static string HostnameToKey(const string& hostname) { - string ret = hostname; - return ret; + typedef std::map<string, crypto::ECPrivateKey*> HostnameToKeyMap; + + crypto::ECPrivateKey* HostnameToKey(const string& hostname) { + HostnameToKeyMap::const_iterator it = hostname_to_key_.find(hostname); + if (it != hostname_to_key_.end()) { + return it->second; + } + + crypto::ECPrivateKey* keypair = crypto::ECPrivateKey::Create(); + if (!keypair) { + return NULL; + } + hostname_to_key_[hostname] = keypair; + return keypair; } - static string SerializeKey(string& key) { - return string(key); + static string SerializeKey(const SECKEYPublicKey* public_key) { + // public_key->u.ec.publicValue is an ANSI X9.62 public key which, for + // a P-256 key, is 0x04 (meaning uncompressed) followed by the x and y field + // elements as 32-byte, big-endian numbers. + static const unsigned int kExpectedKeyLength = 65; + + const unsigned char* const data = public_key->u.ec.publicValue.data; + const unsigned int len = public_key->u.ec.publicValue.len; + if (len != kExpectedKeyLength || data[0] != 0x04) { + return ""; + } + + string key(reinterpret_cast<const char*>(data + 1), kExpectedKeyLength - 1); + return key; } + + HostnameToKeyMap hostname_to_key_; }; // static @@ -59,11 +133,6 @@ ChannelIDSigner* CryptoTestUtils::ChannelIDSignerForTesting() { return new TestChannelIDSigner(); } -// static -string CryptoTestUtils::ChannelIDKeyForHostname(const string& hostname) { - return TestChannelIDSigner::KeyForHostname(hostname); -} - } // namespace test } // namespace net diff --git a/net/quic/test_tools/crypto_test_utils_openssl.cc b/net/quic/test_tools/crypto_test_utils_openssl.cc index 24d0bc7..842118d 100644 --- a/net/quic/test_tools/crypto_test_utils_openssl.cc +++ b/net/quic/test_tools/crypto_test_utils_openssl.cc @@ -94,7 +94,7 @@ class TestChannelIDSigner : public ChannelIDSigner { return true; } - static string KeyForHostname(const string& hostname) { + virtual string GetKeyForHostname(const string& hostname) OVERRIDE { crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> ecdsa_key( HostnameToKey(hostname)); return SerializeKey(ecdsa_key.get()); @@ -168,11 +168,6 @@ ChannelIDSigner* CryptoTestUtils::ChannelIDSignerForTesting() { return new TestChannelIDSigner(); } -// static -string CryptoTestUtils::ChannelIDKeyForHostname(const string& hostname) { - return TestChannelIDSigner::KeyForHostname(hostname); -} - } // namespace test } // namespace net |