diff options
author | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-22 12:53:51 +0000 |
---|---|---|
committer | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-22 12:53:51 +0000 |
commit | 90ba4fad974648c03c0ca3860b0ddd2b2b06e4a9 (patch) | |
tree | ceffe8e1be1860001ebee450d7e0e7c57316eb47 /net | |
parent | 801847c51282ac3fab316eb7ca482c38b60226a5 (diff) | |
download | chromium_src-90ba4fad974648c03c0ca3860b0ddd2b2b06e4a9.zip chromium_src-90ba4fad974648c03c0ca3860b0ddd2b2b06e4a9.tar.gz chromium_src-90ba4fad974648c03c0ca3860b0ddd2b2b06e4a9.tar.bz2 |
Land Recent QUIC changes.
Use example.com as test hostname.
Merge internal change: 46048925
Only updating the time of last packet once we've done our best to verify packet validity.
Merge internal change: 46044184
Improve logging behavior in quic_connection.h.
Merge internal change: 46033559
Moving the public flags to the beginning of the header in preparation for variable length guids.
Merge internal change: 45980153
QUIC: change the GCM tag size to 12 bytes.
Merge internal change: 45973625
QUIC: add some crypto tests.
The client code tries to be correct, which can hamper some tests that wish to
send invalid requests.
This CL contains some utilities for constructing arbitrary handshake messages
and some tests that exercise the server crypto code.
Merge internal change: 45972782
Not allowing retransmissions to affect client timeouts. Fixes a serious
bug where if client vanishes and we have unacked packets, the connection
could live on forever.
Merge internal change: 45935953
Address wtc's comments on cl/44272981.
Merge internal change: 45917323
QUIC: don't CHECK when QUIC is enabled without any certificates loaded.
Without certificates we don't have any key material for the source-address
token nor server config and so QUIC isn't setup at server load time. However,
if QUIC is enabled anyway then it'll crash.
This change removes the CHECK and has every crypto handshake fail instead.
(I have tests for the recent SNI change pending, into which a test for this
will fall nicely, hopefully this afternoon. But I'm prioritising this change
for now rather than waiting for the test CL to land.)
Merge internal change: 45914344
Merging cleanup changes from chromium
Merge internal change: 45797529
QUIC: pad client hello messages and require padding on the server.
This reduces any amplification factor that an attacker might get from us. I've
picked a minimum size of 512 bytes out of thin air.
Satyam has a change pending that bumps the version to 2 so I've omitted that here.
Merge internal change: 45779287
QUIC: small fixes
* Don't send invalid SNIs as a client.
* Don't require an SNI as a server.
* Don't ignore client hello processing errors.
Merge internal change: 45774287
QUIC - set QUIC max stream per connections based on SNI.
Merge internal change: 45656436
- Enabled EndToEnd's Timeout unittest.
- Ported IsValidSNI and NormalizeHostname from internal code.
R=rch@chromium.org
Review URL: https://chromiumcodereview.appspot.com/15385004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@201501 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
50 files changed, 1184 insertions, 435 deletions
diff --git a/net/net.gyp b/net/net.gyp index 24dbbb1..39dfede 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -706,12 +706,12 @@ 'quic/congestion_control/tcp_cubic_sender.h', 'quic/congestion_control/tcp_receiver.cc', 'quic/congestion_control/tcp_receiver.h', - 'quic/crypto/aes_128_gcm_decrypter.h', - 'quic/crypto/aes_128_gcm_decrypter_nss.cc', - 'quic/crypto/aes_128_gcm_decrypter_openssl.cc', - 'quic/crypto/aes_128_gcm_encrypter.h', - 'quic/crypto/aes_128_gcm_encrypter_nss.cc', - 'quic/crypto/aes_128_gcm_encrypter_openssl.cc', + 'quic/crypto/aes_128_gcm_12_decrypter.h', + 'quic/crypto/aes_128_gcm_12_decrypter_nss.cc', + 'quic/crypto/aes_128_gcm_12_decrypter_openssl.cc', + 'quic/crypto/aes_128_gcm_12_encrypter.h', + 'quic/crypto/aes_128_gcm_12_encrypter_nss.cc', + 'quic/crypto/aes_128_gcm_12_encrypter_openssl.cc', 'quic/crypto/cert_compressor.cc', 'quic/crypto/cert_compressor.h', 'quic/crypto/common_cert_set.cc', @@ -1173,8 +1173,8 @@ 'cert/x509_util_nss.h', 'ocsp/nss_ocsp.cc', 'ocsp/nss_ocsp.h', - 'quic/crypto/aes_128_gcm_decrypter_nss.cc', - 'quic/crypto/aes_128_gcm_encrypter_nss.cc', + 'quic/crypto/aes_128_gcm_12_decrypter_nss.cc', + 'quic/crypto/aes_128_gcm_12_encrypter_nss.cc', 'quic/crypto/p256_key_exchange_nss.cc', 'socket/nss_ssl_util.cc', 'socket/nss_ssl_util.h', @@ -1205,8 +1205,8 @@ 'cert/x509_certificate_openssl.cc', 'cert/x509_util_openssl.cc', 'cert/x509_util_openssl.h', - 'quic/crypto/aes_128_gcm_decrypter_openssl.cc', - 'quic/crypto/aes_128_gcm_encrypter_openssl.cc', + 'quic/crypto/aes_128_gcm_12_decrypter_openssl.cc', + 'quic/crypto/aes_128_gcm_12_encrypter_openssl.cc', 'quic/crypto/p256_key_exchange_openssl.cc', 'quic/crypto/scoped_evp_cipher_ctx.h', 'socket/ssl_client_socket_openssl.cc', @@ -1638,12 +1638,14 @@ 'quic/congestion_control/quic_max_sized_map_test.cc', 'quic/congestion_control/tcp_cubic_sender_test.cc', 'quic/congestion_control/tcp_receiver_test.cc', - 'quic/crypto/aes_128_gcm_decrypter_test.cc', - 'quic/crypto/aes_128_gcm_encrypter_test.cc', + 'quic/crypto/aes_128_gcm_12_decrypter_test.cc', + 'quic/crypto/aes_128_gcm_12_encrypter_test.cc', 'quic/crypto/cert_compressor_test.cc', 'quic/crypto/common_cert_set_test.cc', 'quic/crypto/crypto_framer_test.cc', 'quic/crypto/crypto_handshake_test.cc', + 'quic/crypto/crypto_server_test.cc', + 'quic/crypto/crypto_utils_test.cc', 'quic/crypto/curve25519_key_exchange_test.cc', 'quic/crypto/null_decrypter_test.cc', 'quic/crypto/null_encrypter_test.cc', diff --git a/net/quic/crypto/aes_128_gcm_decrypter.h b/net/quic/crypto/aes_128_gcm_12_decrypter.h index cf7e412..0a066659 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter.h +++ b/net/quic/crypto/aes_128_gcm_12_decrypter.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_QUIC_CRYPTO_AES_128_GCM_DECRYPTER_H_ -#define NET_QUIC_CRYPTO_AES_128_GCM_DECRYPTER_H_ +#ifndef NET_QUIC_CRYPTO_AES_128_GCM_12_DECRYPTER_H_ +#define NET_QUIC_CRYPTO_AES_128_GCM_12_DECRYPTER_H_ #include <string> @@ -13,19 +13,24 @@ namespace net { namespace test { -class Aes128GcmDecrypterPeer; +class Aes128Gcm12DecrypterPeer; } // namespace test -// An Aes128GcmDecrypter is a QuicDecrypter that implements the -// AEAD_AES_128_GCM algorithm specified in RFC 5116. Create an instance by +// An Aes128Gcm12Decrypter is a QuicDecrypter that implements the +// AEAD_AES_128_GCM_12 algorithm specified in RFC 5282. Create an instance by // calling QuicDecrypter::Create(kAESG). // -// It uses an authentication tag of 16 bytes (128 bits). The fixed prefix +// It uses an authentication tag of 12 bytes (96 bits). The fixed prefix // of the nonce is four bytes. -class NET_EXPORT_PRIVATE Aes128GcmDecrypter : public QuicDecrypter { +class NET_EXPORT_PRIVATE Aes128Gcm12Decrypter : public QuicDecrypter { public: - Aes128GcmDecrypter(); - virtual ~Aes128GcmDecrypter() {} + enum { + // Authentication tags are truncated to 96 bits. + kAuthTagSize = 12, + }; + + Aes128Gcm12Decrypter(); + virtual ~Aes128Gcm12Decrypter() {} // Returns true if the underlying crypto library supports AES GCM. static bool IsSupported(); @@ -54,4 +59,4 @@ class NET_EXPORT_PRIVATE Aes128GcmDecrypter : public QuicDecrypter { } // namespace net -#endif // NET_QUIC_CRYPTO_AES_128_GCM_DECRYPTER_H_ +#endif // NET_QUIC_CRYPTO_AES_128_GCM_12_DECRYPTER_H_ diff --git a/net/quic/crypto/aes_128_gcm_decrypter_nss.cc b/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc index 424cdef..c2a9788 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter_nss.cc +++ b/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/quic/crypto/aes_128_gcm_decrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_decrypter.h" #include <nss.h> #include <pk11pub.h> @@ -106,7 +106,6 @@ base::LazyInstance<GcmSupportChecker>::Leaky g_gcm_support_checker = const size_t kKeySize = 16; const size_t kNoncePrefixSize = 4; -const size_t kAuthTagSize = 16; // Calls PK11_Decrypt if it's available. Otherwise, emulates CKM_AES_GCM using // CKM_AES_CTR and the GaloisHash class. @@ -140,7 +139,8 @@ SECStatus My_Decrypt(PK11SymKey* key, const CK_GCM_PARAMS* gcm_params = reinterpret_cast<CK_GCM_PARAMS*>(param->data); - DCHECK_EQ(gcm_params->ulTagBits, kAuthTagSize * 8); + DCHECK_EQ(gcm_params->ulTagBits, + static_cast<CK_ULONG>(Aes128Gcm12Decrypter::kAuthTagSize * 8)); if (gcm_params->ulIvLen != 12u) { DLOG(INFO) << "ulIvLen is not equal to 12"; PORT_SetError(SEC_ERROR_INPUT_LEN); @@ -205,7 +205,7 @@ SECStatus My_Decrypt(PK11SymKey* key, return SECFailure; } - if (enc_len < kAuthTagSize) { + if (enc_len < Aes128Gcm12Decrypter::kAuthTagSize) { PORT_SetError(SEC_ERROR_INPUT_LEN); return SECFailure; } @@ -214,15 +214,16 @@ SECStatus My_Decrypt(PK11SymKey* key, // NSS 3.14.1 or later (NSS bug // https://bugzilla.mozilla.org/show_bug.cgi?id=808218). if (PK11_CipherOp(ctx.get(), out, &output_len, max_len, - const_cast<unsigned char*>(enc), - enc_len - kAuthTagSize) != SECSuccess) { + const_cast<unsigned char*>(enc), + enc_len - Aes128Gcm12Decrypter::kAuthTagSize) != SECSuccess) { DLOG(INFO) << "PK11_CipherOp failed"; return SECFailure; } PK11_Finalize(ctx.get()); - if (static_cast<unsigned int>(output_len) != enc_len - kAuthTagSize) { + if (static_cast<unsigned int>(output_len) != + enc_len - Aes128Gcm12Decrypter::kAuthTagSize) { DLOG(INFO) << "Wrong output length"; PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; @@ -231,13 +232,14 @@ SECStatus My_Decrypt(PK11SymKey* key, crypto::GaloisHash ghash(ghash_key); ghash.UpdateAdditional(gcm_params->pAAD, gcm_params->ulAADLen); ghash.UpdateCiphertext(enc, output_len); - unsigned char auth_tag[kAuthTagSize]; - ghash.Finish(auth_tag, kAuthTagSize); - for (unsigned int i = 0; i < kAuthTagSize; i++) { + unsigned char auth_tag[Aes128Gcm12Decrypter::kAuthTagSize]; + ghash.Finish(auth_tag, Aes128Gcm12Decrypter::kAuthTagSize); + for (unsigned int i = 0; i < Aes128Gcm12Decrypter::kAuthTagSize; i++) { auth_tag[i] ^= tag_mask[i]; } - if (NSS_SecureMemcmp(auth_tag, enc + output_len, kAuthTagSize) != 0) { + if (NSS_SecureMemcmp(auth_tag, enc + output_len, + Aes128Gcm12Decrypter::kAuthTagSize) != 0) { PORT_SetError(SEC_ERROR_BAD_DATA); return SECFailure; } @@ -248,19 +250,19 @@ SECStatus My_Decrypt(PK11SymKey* key, } // namespace -Aes128GcmDecrypter::Aes128GcmDecrypter() { +Aes128Gcm12Decrypter::Aes128Gcm12Decrypter() { ignore_result(g_gcm_support_checker.Get()); } // static -bool Aes128GcmDecrypter::IsSupported() { +bool Aes128Gcm12Decrypter::IsSupported() { // NSS 3.15 supports CKM_AES_GCM directly. // NSS 3.14 supports CKM_AES_CTR, which can be used to emulate CKM_AES_GCM. // Versions earlier than NSS 3.14 are not supported. return NSS_VersionCheck("3.14") != PR_FALSE; } -bool Aes128GcmDecrypter::SetKey(StringPiece key) { +bool Aes128Gcm12Decrypter::SetKey(StringPiece key) { DCHECK_EQ(key.size(), sizeof(key_)); if (key.size() != sizeof(key_)) { return false; @@ -269,7 +271,7 @@ bool Aes128GcmDecrypter::SetKey(StringPiece key) { return true; } -bool Aes128GcmDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { +bool Aes128Gcm12Decrypter::SetNoncePrefix(StringPiece nonce_prefix) { DCHECK_EQ(nonce_prefix.size(), kNoncePrefixSize); if (nonce_prefix.size() != kNoncePrefixSize) { return false; @@ -278,11 +280,11 @@ bool Aes128GcmDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { return true; } -bool Aes128GcmDecrypter::Decrypt(StringPiece nonce, - StringPiece associated_data, - StringPiece ciphertext, - unsigned char* output, - size_t* output_length) { +bool Aes128Gcm12Decrypter::Decrypt(StringPiece nonce, + StringPiece associated_data, + StringPiece ciphertext, + unsigned char* output, + size_t* output_length) { if (ciphertext.length() < kAuthTagSize || nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) { return false; @@ -346,7 +348,7 @@ bool Aes128GcmDecrypter::Decrypt(StringPiece nonce, return true; } -QuicData* Aes128GcmDecrypter::DecryptPacket( +QuicData* Aes128Gcm12Decrypter::DecryptPacket( QuicPacketSequenceNumber sequence_number, StringPiece associated_data, StringPiece ciphertext) { @@ -368,11 +370,11 @@ QuicData* Aes128GcmDecrypter::DecryptPacket( return new QuicData(plaintext.release(), plaintext_size, true); } -StringPiece Aes128GcmDecrypter::GetKey() const { +StringPiece Aes128Gcm12Decrypter::GetKey() const { return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); } -StringPiece Aes128GcmDecrypter::GetNoncePrefix() const { +StringPiece Aes128Gcm12Decrypter::GetNoncePrefix() const { return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); } diff --git a/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_12_decrypter_openssl.cc index 0800cb5..cf0f5c5 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc +++ b/net/quic/crypto/aes_128_gcm_12_decrypter_openssl.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/quic/crypto/aes_128_gcm_decrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_decrypter.h" #include <openssl/evp.h> @@ -17,16 +17,15 @@ namespace { const size_t kKeySize = 16; const size_t kNoncePrefixSize = 4; -const size_t kAuthTagSize = 16; } // namespace -Aes128GcmDecrypter::Aes128GcmDecrypter() {} +Aes128Gcm12Decrypter::Aes128Gcm12Decrypter() {} // static -bool Aes128GcmDecrypter::IsSupported() { return true; } +bool Aes128Gcm12Decrypter::IsSupported() { return true; } -bool Aes128GcmDecrypter::SetKey(StringPiece key) { +bool Aes128Gcm12Decrypter::SetKey(StringPiece key) { DCHECK_EQ(key.size(), sizeof(key_)); if (key.size() != sizeof(key_)) { return false; @@ -35,7 +34,7 @@ bool Aes128GcmDecrypter::SetKey(StringPiece key) { return true; } -bool Aes128GcmDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { +bool Aes128Gcm12Decrypter::SetNoncePrefix(StringPiece nonce_prefix) { DCHECK_EQ(nonce_prefix.size(), kNoncePrefixSize); if (nonce_prefix.size() != kNoncePrefixSize) { return false; @@ -44,11 +43,11 @@ bool Aes128GcmDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { return true; } -bool Aes128GcmDecrypter::Decrypt(StringPiece nonce, - StringPiece associated_data, - StringPiece ciphertext, - unsigned char* output, - size_t* output_length) { +bool Aes128Gcm12Decrypter::Decrypt(StringPiece nonce, + StringPiece associated_data, + StringPiece ciphertext, + unsigned char* output, + size_t* output_length) { if (ciphertext.length() < kAuthTagSize || nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) { return false; @@ -114,7 +113,7 @@ bool Aes128GcmDecrypter::Decrypt(StringPiece nonce, return true; } -QuicData* Aes128GcmDecrypter::DecryptPacket( +QuicData* Aes128Gcm12Decrypter::DecryptPacket( QuicPacketSequenceNumber sequence_number, StringPiece associated_data, StringPiece ciphertext) { @@ -136,11 +135,11 @@ QuicData* Aes128GcmDecrypter::DecryptPacket( return new QuicData(plaintext.release(), plaintext_size, true); } -StringPiece Aes128GcmDecrypter::GetKey() const { +StringPiece Aes128Gcm12Decrypter::GetKey() const { return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); } -StringPiece Aes128GcmDecrypter::GetNoncePrefix() const { +StringPiece Aes128Gcm12Decrypter::GetNoncePrefix() const { return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); } diff --git a/net/quic/crypto/aes_128_gcm_decrypter_test.cc b/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc index 156dfb8..cea6a6e5 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter_test.cc +++ b/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/quic/crypto/aes_128_gcm_decrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_decrypter.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -293,7 +293,7 @@ namespace test { // DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing // in an nonce and also to allocate the buffer needed for the plaintext. -QuicData* DecryptWithNonce(Aes128GcmDecrypter* decrypter, +QuicData* DecryptWithNonce(Aes128Gcm12Decrypter* decrypter, StringPiece nonce, StringPiece associated_data, StringPiece ciphertext) { @@ -308,8 +308,8 @@ QuicData* DecryptWithNonce(Aes128GcmDecrypter* decrypter, return new QuicData(plaintext.release(), plaintext_size, true); } -TEST(Aes128GcmDecrypterTest, Decrypt) { - if (!Aes128GcmDecrypter::IsSupported()) { +TEST(Aes128Gcm12DecrypterTest, Decrypt) { + if (!Aes128Gcm12Decrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -354,7 +354,13 @@ TEST(Aes128GcmDecrypterTest, Decrypt) { EXPECT_EQ(test_info.pt_len, pt_len * 8); } - Aes128GcmDecrypter decrypter; + // The test vectors have 16 byte authenticators but this code only uses + // the first 12. + ASSERT_LE(static_cast<size_t>(Aes128Gcm12Decrypter::kAuthTagSize), + tag_len); + tag_len = Aes128Gcm12Decrypter::kAuthTagSize; + + Aes128Gcm12Decrypter decrypter; ASSERT_TRUE(decrypter.SetKey(StringPiece(key, key_len))); string ciphertext(ct, ct_len); ciphertext.append(tag, tag_len); diff --git a/net/quic/crypto/aes_128_gcm_encrypter.h b/net/quic/crypto/aes_128_gcm_12_encrypter.h index 3aee81e..b8380c7 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter.h +++ b/net/quic/crypto/aes_128_gcm_12_encrypter.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_QUIC_CRYPTO_AES_128_GCM_ENCRYPTER_H_ -#define NET_QUIC_CRYPTO_AES_128_GCM_ENCRYPTER_H_ +#ifndef NET_QUIC_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_ +#define NET_QUIC_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_ #include <string> @@ -13,19 +13,24 @@ namespace net { namespace test { -class Aes128GcmEncrypterPeer; +class Aes128Gcm12EncrypterPeer; } // namespace test -// An Aes128GcmEncrypter is a QuicEncrypter that implements the -// AEAD_AES_128_GCM algorithm specified in RFC 5116. Create an instance by +// An Aes128Gcm12Encrypter is a QuicEncrypter that implements the +// AEAD_AES_128_GCM_12 algorithm specified in RFC 5282. Create an instance by // calling QuicEncrypter::Create(kAESG). // -// It uses an authentication tag of 16 bytes (128 bits). The fixed prefix +// It uses an authentication tag of 12 bytes (96 bits). The fixed prefix // of the nonce is four bytes. -class NET_EXPORT_PRIVATE Aes128GcmEncrypter : public QuicEncrypter { +class NET_EXPORT_PRIVATE Aes128Gcm12Encrypter : public QuicEncrypter { public: - Aes128GcmEncrypter(); - virtual ~Aes128GcmEncrypter() {} + enum { + // Authentication tags are truncated to 96 bits. + kAuthTagSize = 12, + }; + + Aes128Gcm12Encrypter(); + virtual ~Aes128Gcm12Encrypter() {} // Returns true if the underlying crypto library supports AES GCM. static bool IsSupported(); @@ -57,4 +62,4 @@ class NET_EXPORT_PRIVATE Aes128GcmEncrypter : public QuicEncrypter { } // namespace net -#endif // NET_QUIC_CRYPTO_AES_128_GCM_ENCRYPTER_H_ +#endif // NET_QUIC_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_ diff --git a/net/quic/crypto/aes_128_gcm_encrypter_nss.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc index 55b1b6f..9084b7c 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter_nss.cc +++ b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include <nss.h> #include <pk11pub.h> @@ -106,7 +106,6 @@ base::LazyInstance<GcmSupportChecker>::Leaky g_gcm_support_checker = const size_t kKeySize = 16; const size_t kNoncePrefixSize = 4; -const size_t kAuthTagSize = 16; // Calls PK11_Encrypt if it's available. Otherwise, emulates CKM_AES_GCM using // CKM_AES_CTR and the GaloisHash class. @@ -137,7 +136,7 @@ SECStatus My_Encrypt(PK11SymKey* key, DCHECK_EQ(mechanism, static_cast<CK_MECHANISM_TYPE>(CKM_AES_GCM)); DCHECK_EQ(param->len, sizeof(CK_GCM_PARAMS)); - if (max_len < kAuthTagSize) { + if (max_len < static_cast<unsigned int>(Aes128Gcm12Encrypter::kAuthTagSize)) { DLOG(INFO) << "max_len is less than kAuthTagSize"; PORT_SetError(SEC_ERROR_OUTPUT_LEN); return SECFailure; @@ -146,7 +145,8 @@ SECStatus My_Encrypt(PK11SymKey* key, const CK_GCM_PARAMS* gcm_params = reinterpret_cast<CK_GCM_PARAMS*>(param->data); - DCHECK_EQ(gcm_params->ulTagBits, kAuthTagSize * 8); + DCHECK_EQ(gcm_params->ulTagBits, + static_cast<CK_ULONG>(Aes128Gcm12Encrypter::kAuthTagSize * 8)); if (gcm_params->ulIvLen != 12u) { DLOG(INFO) << "ulIvLen is not equal to 12"; PORT_SetError(SEC_ERROR_INPUT_LEN); @@ -228,7 +228,8 @@ SECStatus My_Encrypt(PK11SymKey* key, return SECFailure; } - if ((max_len - kAuthTagSize) < static_cast<unsigned int>(output_len)) { + if ((max_len - Aes128Gcm12Encrypter::kAuthTagSize) < + static_cast<unsigned int>(output_len)) { DLOG(INFO) << "(max_len - kAuthTagSize) is less than output_len"; PORT_SetError(SEC_ERROR_OUTPUT_LEN); return SECFailure; @@ -237,30 +238,30 @@ SECStatus My_Encrypt(PK11SymKey* key, crypto::GaloisHash ghash(ghash_key); ghash.UpdateAdditional(gcm_params->pAAD, gcm_params->ulAADLen); ghash.UpdateCiphertext(out, output_len); - ghash.Finish(out + output_len, kAuthTagSize); - for (unsigned int i = 0; i < kAuthTagSize; i++) { + ghash.Finish(out + output_len, Aes128Gcm12Encrypter::kAuthTagSize); + for (unsigned int i = 0; i < Aes128Gcm12Encrypter::kAuthTagSize; i++) { out[output_len + i] ^= tag_mask[i]; } - *out_len = output_len + kAuthTagSize; + *out_len = output_len + Aes128Gcm12Encrypter::kAuthTagSize; return SECSuccess; } } // namespace -Aes128GcmEncrypter::Aes128GcmEncrypter() { +Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() { ignore_result(g_gcm_support_checker.Get()); } // static -bool Aes128GcmEncrypter::IsSupported() { +bool Aes128Gcm12Encrypter::IsSupported() { // NSS 3.15 supports CKM_AES_GCM directly. // NSS 3.14 supports CKM_AES_CTR, which can be used to emulate CKM_AES_GCM. // Versions earlier than NSS 3.14 are not supported. return NSS_VersionCheck("3.14") != PR_FALSE; } -bool Aes128GcmEncrypter::SetKey(StringPiece key) { +bool Aes128Gcm12Encrypter::SetKey(StringPiece key) { DCHECK_EQ(key.size(), sizeof(key_)); if (key.size() != sizeof(key_)) { return false; @@ -269,7 +270,7 @@ bool Aes128GcmEncrypter::SetKey(StringPiece key) { return true; } -bool Aes128GcmEncrypter::SetNoncePrefix(StringPiece nonce_prefix) { +bool Aes128Gcm12Encrypter::SetNoncePrefix(StringPiece nonce_prefix) { DCHECK_EQ(nonce_prefix.size(), kNoncePrefixSize); if (nonce_prefix.size() != kNoncePrefixSize) { return false; @@ -278,10 +279,10 @@ bool Aes128GcmEncrypter::SetNoncePrefix(StringPiece nonce_prefix) { return true; } -bool Aes128GcmEncrypter::Encrypt(StringPiece nonce, - StringPiece associated_data, - StringPiece plaintext, - unsigned char* output) { +bool Aes128Gcm12Encrypter::Encrypt(StringPiece nonce, + StringPiece associated_data, + StringPiece plaintext, + unsigned char* output) { if (nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) { return false; } @@ -338,7 +339,7 @@ bool Aes128GcmEncrypter::Encrypt(StringPiece nonce, return true; } -QuicData* Aes128GcmEncrypter::EncryptPacket( +QuicData* Aes128Gcm12Encrypter::EncryptPacket( QuicPacketSequenceNumber sequence_number, StringPiece associated_data, StringPiece plaintext) { @@ -357,29 +358,29 @@ QuicData* Aes128GcmEncrypter::EncryptPacket( return new QuicData(ciphertext.release(), ciphertext_size, true); } -size_t Aes128GcmEncrypter::GetKeySize() const { +size_t Aes128Gcm12Encrypter::GetKeySize() const { return kKeySize; } -size_t Aes128GcmEncrypter::GetNoncePrefixSize() const { +size_t Aes128Gcm12Encrypter::GetNoncePrefixSize() const { return kNoncePrefixSize; } -size_t Aes128GcmEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { +size_t Aes128Gcm12Encrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { return ciphertext_size - kAuthTagSize; } // An AEAD_AES_128_GCM ciphertext is exactly 16 bytes longer than its // corresponding plaintext. -size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const { +size_t Aes128Gcm12Encrypter::GetCiphertextSize(size_t plaintext_size) const { return plaintext_size + kAuthTagSize; } -StringPiece Aes128GcmEncrypter::GetKey() const { +StringPiece Aes128Gcm12Encrypter::GetKey() const { return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); } -StringPiece Aes128GcmEncrypter::GetNoncePrefix() const { +StringPiece Aes128Gcm12Encrypter::GetNoncePrefix() const { return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); } diff --git a/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc index b00dec8..7481184 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc +++ b/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include <openssl/evp.h> #include <string.h> @@ -18,17 +18,16 @@ namespace { const size_t kKeySize = 16; const size_t kNoncePrefixSize = 4; -const size_t kAuthTagSize = 16; } // namespace -Aes128GcmEncrypter::Aes128GcmEncrypter() { +Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() { } // static -bool Aes128GcmEncrypter::IsSupported() { return true; } +bool Aes128Gcm12Encrypter::IsSupported() { return true; } -bool Aes128GcmEncrypter::SetKey(StringPiece key) { +bool Aes128Gcm12Encrypter::SetKey(StringPiece key) { DCHECK_EQ(key.size(), sizeof(key_)); if (key.size() != sizeof(key_)) { return false; @@ -37,7 +36,7 @@ bool Aes128GcmEncrypter::SetKey(StringPiece key) { return true; } -bool Aes128GcmEncrypter::SetNoncePrefix(StringPiece nonce_prefix) { +bool Aes128Gcm12Encrypter::SetNoncePrefix(StringPiece nonce_prefix) { DCHECK_EQ(nonce_prefix.size(), kNoncePrefixSize); if (nonce_prefix.size() != kNoncePrefixSize) { return false; @@ -46,10 +45,10 @@ bool Aes128GcmEncrypter::SetNoncePrefix(StringPiece nonce_prefix) { return true; } -bool Aes128GcmEncrypter::Encrypt(StringPiece nonce, - StringPiece associated_data, - StringPiece plaintext, - unsigned char* output) { +bool Aes128Gcm12Encrypter::Encrypt(StringPiece nonce, + StringPiece associated_data, + StringPiece plaintext, + unsigned char* output) { // |output_len| is passed to an OpenSSL function to receive the output // length. int output_len; @@ -111,7 +110,7 @@ bool Aes128GcmEncrypter::Encrypt(StringPiece nonce, return true; } -QuicData* Aes128GcmEncrypter::EncryptPacket( +QuicData* Aes128Gcm12Encrypter::EncryptPacket( QuicPacketSequenceNumber sequence_number, StringPiece associated_data, StringPiece plaintext) { @@ -131,27 +130,27 @@ QuicData* Aes128GcmEncrypter::EncryptPacket( return new QuicData(ciphertext.release(), ciphertext_size, true); } -size_t Aes128GcmEncrypter::GetKeySize() const { return kKeySize; } +size_t Aes128Gcm12Encrypter::GetKeySize() const { return kKeySize; } -size_t Aes128GcmEncrypter::GetNoncePrefixSize() const { +size_t Aes128Gcm12Encrypter::GetNoncePrefixSize() const { return kNoncePrefixSize; } -size_t Aes128GcmEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { +size_t Aes128Gcm12Encrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { return ciphertext_size - kAuthTagSize; } -// An AEAD_AES_128_GCM ciphertext is exactly 16 bytes longer than its +// An AEAD_AES_128_GCM_12 ciphertext is exactly 12 bytes longer than its // corresponding plaintext. -size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const { +size_t Aes128Gcm12Encrypter::GetCiphertextSize(size_t plaintext_size) const { return plaintext_size + kAuthTagSize; } -StringPiece Aes128GcmEncrypter::GetKey() const { +StringPiece Aes128Gcm12Encrypter::GetKey() const { return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); } -StringPiece Aes128GcmEncrypter::GetNoncePrefix() const { +StringPiece Aes128Gcm12Encrypter::GetNoncePrefix() const { return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); } diff --git a/net/quic/crypto/aes_128_gcm_encrypter_test.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc index 7e07ba9..0c9928b 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter_test.cc +++ b/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -245,7 +245,7 @@ namespace test { // EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing // in an nonce and also to allocate the buffer needed for the ciphertext. -QuicData* EncryptWithNonce(Aes128GcmEncrypter* encrypter, +QuicData* EncryptWithNonce(Aes128Gcm12Encrypter* encrypter, StringPiece nonce, StringPiece associated_data, StringPiece plaintext) { @@ -260,8 +260,8 @@ QuicData* EncryptWithNonce(Aes128GcmEncrypter* encrypter, return new QuicData(ciphertext.release(), ciphertext_size, true); } -TEST(Aes128GcmEncrypterTest, Encrypt) { - if (!Aes128GcmEncrypter::IsSupported()) { +TEST(Aes128Gcm12EncrypterTest, Encrypt) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -304,7 +304,7 @@ TEST(Aes128GcmEncrypterTest, Encrypt) { EXPECT_EQ(test_info.pt_len, ct_len * 8); EXPECT_EQ(test_info.tag_len, tag_len * 8); - Aes128GcmEncrypter encrypter; + Aes128Gcm12Encrypter encrypter; ASSERT_TRUE(encrypter.SetKey(StringPiece(key, key_len))); scoped_ptr<QuicData> encrypted(EncryptWithNonce( &encrypter, StringPiece(iv, iv_len), @@ -313,6 +313,13 @@ TEST(Aes128GcmEncrypterTest, Encrypt) { // handle this case. StringPiece(aad_len ? aad : NULL, aad_len), StringPiece(pt, pt_len))); ASSERT_TRUE(encrypted.get()); + + // The test vectors have 16 byte authenticators but this code only uses + // the first 12. + ASSERT_LE(static_cast<size_t>(Aes128Gcm12Encrypter::kAuthTagSize), + tag_len); + tag_len = Aes128Gcm12Encrypter::kAuthTagSize; + ASSERT_EQ(ct_len + tag_len, encrypted->length()); test::CompareCharArraysWithHexError("ciphertext", encrypted->data(), ct_len, ct, ct_len); @@ -323,18 +330,18 @@ TEST(Aes128GcmEncrypterTest, Encrypt) { } } -TEST(Aes128GcmEncrypterTest, GetMaxPlaintextSize) { - Aes128GcmEncrypter encrypter; - EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1016)); - EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(116)); - EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(26)); +TEST(Aes128Gcm12EncrypterTest, GetMaxPlaintextSize) { + Aes128Gcm12Encrypter encrypter; + EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012)); + EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112)); + EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22)); } -TEST(Aes128GcmEncrypterTest, GetCiphertextSize) { - Aes128GcmEncrypter encrypter; - EXPECT_EQ(1016u, encrypter.GetCiphertextSize(1000)); - EXPECT_EQ(116u, encrypter.GetCiphertextSize(100)); - EXPECT_EQ(26u, encrypter.GetCiphertextSize(10)); +TEST(Aes128Gcm12EncrypterTest, GetCiphertextSize) { + Aes128Gcm12Encrypter encrypter; + EXPECT_EQ(1012u, encrypter.GetCiphertextSize(1000)); + EXPECT_EQ(112u, encrypter.GetCiphertextSize(100)); + EXPECT_EQ(22u, encrypter.GetCiphertextSize(10)); } } // namespace test diff --git a/net/quic/crypto/crypto_framer.cc b/net/quic/crypto/crypto_framer.cc index 4b3ce64..6307d82 100644 --- a/net/quic/crypto/crypto_framer.cc +++ b/net/quic/crypto/crypto_framer.cc @@ -160,26 +160,36 @@ bool CryptoFramer::ProcessInput(StringPiece input) { // static QuicData* CryptoFramer::ConstructHandshakeMessage( const CryptoHandshakeMessage& message) { - if (message.tag_value_map().size() > kMaxEntries) { - return NULL; + size_t num_entries = message.tag_value_map().size(); + size_t pad_length = 0; + bool need_pad_tag = false; + bool need_pad_value = false; + + size_t len = message.size(); + if (len < message.minimum_size()) { + need_pad_tag = true; + need_pad_value = true; + num_entries++; + + size_t delta = message.minimum_size() - len; + const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize; + if (delta > overhead) { + pad_length = delta - overhead; + } + len += overhead + pad_length; } - size_t len = kQuicTagSize; // message tag - len += sizeof(uint16); // number of map entries - len += sizeof(uint16); // padding. - QuicTagValueMap::const_iterator it = message.tag_value_map().begin(); - while (it != message.tag_value_map().end()) { - len += kQuicTagSize; // tag - len += kCryptoEndOffsetSize; // end offset - len += it->second.length(); // value - ++it; + + if (num_entries > kMaxEntries) { + return NULL; } + QuicDataWriter writer(len); if (!writer.WriteUInt32(message.tag())) { DCHECK(false) << "Failed to write message tag."; return NULL; } - if (!writer.WriteUInt16(message.tag_value_map().size())) { + if (!writer.WriteUInt16(num_entries)) { DCHECK(false) << "Failed to write size."; return NULL; } @@ -190,8 +200,23 @@ QuicData* CryptoFramer::ConstructHandshakeMessage( uint32 end_offset = 0; // Tags and offsets - for (it = message.tag_value_map().begin(); + for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin(); it != message.tag_value_map().end(); ++it) { + if (it->first == kPAD && need_pad_tag) { + // Existing PAD tags are only checked when padding needs to be added + // because parts of the code may need to reserialize received messages + // and those messages may, legitimately include padding. + DCHECK(false) << "Message needed padding but already contained a PAD tag"; + return NULL; + } + + if (it->first > kPAD && need_pad_tag) { + need_pad_tag = false; + if (!WritePadTag(&writer, pad_length, &end_offset)) { + return NULL; + } + } + if (!writer.WriteUInt32(it->first)) { DCHECK(false) << "Failed to write tag."; return NULL; @@ -203,14 +228,36 @@ QuicData* CryptoFramer::ConstructHandshakeMessage( } } + if (need_pad_tag) { + if (!WritePadTag(&writer, pad_length, &end_offset)) { + return NULL; + } + } + // Values - for (it = message.tag_value_map().begin(); + for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin(); it != message.tag_value_map().end(); ++it) { + if (it->first > kPAD && need_pad_value) { + need_pad_value = false; + if (!writer.WriteRepeatedByte('-', pad_length)) { + DCHECK(false) << "Failed to write padding."; + return NULL; + } + } + if (!writer.WriteBytes(it->second.data(), it->second.length())) { DCHECK(false) << "Failed to write value."; return NULL; } } + + if (need_pad_value) { + if (!writer.WriteRepeatedByte('-', pad_length)) { + DCHECK(false) << "Failed to write padding."; + return NULL; + } + } + return new QuicData(writer.take(), len, true); } @@ -221,4 +268,20 @@ void CryptoFramer::Clear() { state_ = STATE_READING_TAG; } +// static +bool CryptoFramer::WritePadTag(QuicDataWriter* writer, + size_t pad_length, + uint32* end_offset) { + if (!writer->WriteUInt32(kPAD)) { + DCHECK(false) << "Failed to write tag."; + return false; + } + *end_offset += pad_length; + if (!writer->WriteUInt32(*end_offset)) { + DCHECK(false) << "Failed to write end offset."; + return false; + } + return true; +} + } // namespace net diff --git a/net/quic/crypto/crypto_framer.h b/net/quic/crypto/crypto_framer.h index 75cc405..ad1768d 100644 --- a/net/quic/crypto/crypto_framer.h +++ b/net/quic/crypto/crypto_framer.h @@ -20,8 +20,9 @@ namespace net { class CryptoFramer; -class QuicDataReader; class QuicData; +class QuicDataReader; +class QuicDataWriter; class NET_EXPORT_PRIVATE CryptoFramerVisitorInterface { public: @@ -75,6 +76,10 @@ class NET_EXPORT_PRIVATE CryptoFramer { // Clears per-message state. Does not clear the visitor. void Clear(); + static bool WritePadTag(QuicDataWriter* writer, + size_t pad_length, + uint32* end_offset); + void set_error(QuicErrorCode error) { error_ = error; } // Represents the current state of the parsing state machine. diff --git a/net/quic/crypto/crypto_framer_test.cc b/net/quic/crypto/crypto_framer_test.cc index ca4b92e..f33c6c7 100644 --- a/net/quic/crypto/crypto_framer_test.cc +++ b/net/quic/crypto/crypto_framer_test.cc @@ -171,6 +171,84 @@ TEST(CryptoFramerTest, ConstructHandshakeMessageTooManyEntries) { EXPECT_TRUE(data.get() == NULL); } +TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSize) { + CryptoHandshakeMessage message; + message.set_tag(0xFFAA7733); + message.SetStringPiece(0x01020304, "test"); + message.set_minimum_size(64); + + unsigned char packet[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x02, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 'P', 'A', 'D', 0, + // end offset 1 + 0x24, 0x00, 0x00, 0x00, + // tag 2 + 0x04, 0x03, 0x02, 0x01, + // end offset 2 + 0x28, 0x00, 0x00, 0x00, + // 36 bytes of padding. + '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', + // value 2 + 't', 'e', 's', 't', + }; + + CryptoFramer framer; + scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message)); + ASSERT_TRUE(data.get() != NULL); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + arraysize(packet)); +} + +TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSizePadLast) { + CryptoHandshakeMessage message; + message.set_tag(0xFFAA7733); + message.SetStringPiece(1, ""); + message.set_minimum_size(64); + + unsigned char packet[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x02, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x01, 0x00, 0x00, 0x00, + // end offset 1 + 0x00, 0x00, 0x00, 0x00, + // tag 2 + 'P', 'A', 'D', 0, + // end offset 2 + 0x28, 0x00, 0x00, 0x00, + // 40 bytes of padding. + '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', '-', '-', + }; + + CryptoFramer framer; + scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message)); + ASSERT_TRUE(data.get() != NULL); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + arraysize(packet)); +} + TEST(CryptoFramerTest, ProcessInput) { test::TestCryptoVisitor visitor; CryptoFramer framer; diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc index 3585eb5..db66f4b 100644 --- a/net/quic/crypto/crypto_handshake.cc +++ b/net/quic/crypto/crypto_handshake.cc @@ -8,6 +8,7 @@ #include "base/memory/scoped_ptr.h" #include "base/stl_util.h" +#include "base/stringprintf.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "crypto/secure_hash.h" @@ -27,18 +28,22 @@ #include "net/quic/quic_utils.h" using base::StringPiece; +using base::StringPrintf; using std::map; using std::string; using std::vector; namespace net { -CryptoHandshakeMessage::CryptoHandshakeMessage() : tag_(0) {} +CryptoHandshakeMessage::CryptoHandshakeMessage() + : tag_(0), + minimum_size_(0) {} CryptoHandshakeMessage::CryptoHandshakeMessage( const CryptoHandshakeMessage& other) : tag_(other.tag_), - tag_value_map_(other.tag_value_map_) { + tag_value_map_(other.tag_value_map_), + minimum_size_(other.minimum_size_) { // Don't copy serialized_. scoped_ptr doesn't have a copy constructor. // The new object can reconstruct serialized_ lazily. } @@ -52,12 +57,14 @@ CryptoHandshakeMessage& CryptoHandshakeMessage::operator=( // Don't copy serialized_. scoped_ptr doesn't have an assignment operator. // However, invalidate serialized_. serialized_.reset(); + minimum_size_ = other.minimum_size_; return *this; } void CryptoHandshakeMessage::Clear() { tag_ = 0; tag_value_map_.clear(); + minimum_size_ = 0; serialized_.reset(); } @@ -196,6 +203,29 @@ QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag, return GetPOD(tag, out, sizeof(uint64)); } +size_t CryptoHandshakeMessage::size() const { + size_t ret = sizeof(QuicTag) + + sizeof(uint16) /* number of entries */ + + sizeof(uint16) /* padding */; + ret += (sizeof(QuicTag) + sizeof(uint32) /* end offset */) * + tag_value_map_.size(); + for (QuicTagValueMap::const_iterator i = tag_value_map_.begin(); + i != tag_value_map_.end(); ++i) { + ret += i->second.size(); + } + + return ret; +} + +void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) { + serialized_.reset(); + minimum_size_ = min_bytes; +} + +size_t CryptoHandshakeMessage::minimum_size() const { + return minimum_size_; +} + string CryptoHandshakeMessage::DebugString() const { return DebugStringInternal(0); } @@ -269,6 +299,11 @@ string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const { } } break; + case kPAD: + ret += StringPrintf("(%d bytes of padding)", + static_cast<int>(it->second.size())); + done = true; + break; } if (!done) { @@ -433,12 +468,11 @@ void QuicCryptoClientConfig::FillInchoateClientHello( QuicCryptoNegotiatedParameters* out_params, CryptoHandshakeMessage* out) const { out->set_tag(kCHLO); + out->set_minimum_size(kClientHelloMinimumSize); - // Server name indication. - // If server_hostname is not an IP address literal, it is a DNS hostname. - IPAddressNumber ip; - if (!server_hostname.empty() && - !ParseIPLiteralToNumber(server_hostname, &ip)) { + // Server name indication. We only send SNI if it's a valid domain name, as + // per the spec. + if (CryptoUtils::IsValidSNI(server_hostname)) { out->SetStringPiece(kSNI, server_hostname); } out->SetValue(kVERS, version); diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h index 0774905..96a78a2 100644 --- a/net/quic/crypto/crypto_handshake.h +++ b/net/quic/crypto/crypto_handshake.h @@ -96,6 +96,21 @@ class NET_EXPORT_PRIVATE CryptoHandshakeMessage { QuicErrorCode GetUint32(QuicTag tag, uint32* out) const; QuicErrorCode GetUint64(QuicTag tag, uint64* out) const; + // size returns 4 (message tag) + 2 (uint16, number of entries) + + // (4 (tag) + 4 (end offset))*tag_value_map_.size() + ∑ value sizes. + size_t size() const; + + // set_minimum_size sets the minimum number of bytes that the message should + // consume. The CryptoFramer will add a PAD tag as needed when serializing in + // order to ensure this. Setting a value of 0 disables padding. + // + // Padding is useful in order to ensure that messages are a minimum size. A + // QUIC server can require a minimum size in order to reduce the + // amplification factor of any mirror DoS attack. + void set_minimum_size(size_t min_bytes); + + size_t minimum_size() const; + // DebugString returns a multi-line, string representation of the message // suitable for including in debug output. std::string DebugString() const; @@ -115,6 +130,8 @@ class NET_EXPORT_PRIVATE CryptoHandshakeMessage { QuicTag tag_; QuicTagValueMap tag_value_map_; + size_t minimum_size_; + // The serialized form of the handshake message. This member is constructed // lasily. mutable scoped_ptr<QuicData> serialized_; @@ -142,6 +159,8 @@ struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters { CrypterPair initial_crypters; CrypterPair forward_secure_crypters; std::string server_config_id; + // Normalized SNI: converted to lower case and trailing '.' removed. + std::string sni; std::string client_nonce; std::string server_nonce; // hkdf_input_suffix contains the HKDF input following the label: the GUID, diff --git a/net/quic/crypto/crypto_handshake_test.cc b/net/quic/crypto/crypto_handshake_test.cc index e2e45f3..b637db5 100644 --- a/net/quic/crypto/crypto_handshake_test.cc +++ b/net/quic/crypto/crypto_handshake_test.cc @@ -4,7 +4,7 @@ #include "net/quic/crypto/crypto_handshake.h" -#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/crypto_server_config.h" #include "net/quic/crypto/quic_random.h" #include "net/quic/quic_time.h" @@ -49,7 +49,7 @@ TEST(QuicCryptoServerConfigTest, ServerConfig) { } TEST(QuicCryptoServerConfigTest, SourceAddressTokens) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index c32884a..52f0dde 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h @@ -39,7 +39,7 @@ const QuicTag kC255 = TAG('C', '2', '5', '5'); // ECDH, Curve25519 // AEAD algorithms const QuicTag kNULL = TAG('N', 'U', 'L', 'L'); // null algorithm -const QuicTag kAESG = TAG('A', 'E', 'S', 'G'); // AES128 + GCM +const QuicTag kAESG = TAG('A', 'E', 'S', 'G'); // AES128 + GCM-12 // Congestion control feedback types const QuicTag kQBIC = TAG('Q', 'B', 'I', 'C'); // TCP cubic @@ -72,6 +72,9 @@ const QuicTag kCCS = TAG('C', 'C', 'S', 0); // Common certificate set const QuicTag kCCRT = TAG('C', 'C', 'R', 'T'); // Cached certificate const QuicTag kEXPY = TAG('E', 'X', 'P', 'Y'); // Expiry +// Universal tags +const QuicTag kPAD = TAG('P', 'A', 'D', '\0'); // Padding + // These tags have a special form so that they appear either at the beginning // or the end of a handshake message. Since handshake messages are sorted by // tag value, the tags with 0 at the end will sort first and those with 255 at @@ -105,6 +108,12 @@ const size_t kOrbitSize = 8; // Number of bytes in an orbit value. // any cross-protocol attacks on the signature. const char kProofSignatureLabel[] = "QUIC server config signature"; +// kClientHelloMinimumSize is the minimum size of a client hello. Client hellos +// will have PAD tags added in order to ensure this minimum is met and client +// hellos smaller than this will be an error. This minimum size reduces the +// amplification factor of any mirror DoS attack. +const size_t kClientHelloMinimumSize = 512; + } // namespace net #endif // NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_ diff --git a/net/quic/crypto/crypto_server_config.cc b/net/quic/crypto/crypto_server_config.cc index d7eca6a..d766c20 100644 --- a/net/quic/crypto/crypto_server_config.cc +++ b/net/quic/crypto/crypto_server_config.cc @@ -4,11 +4,13 @@ #include "net/quic/crypto/crypto_server_config.h" +#include <stdlib.h> + #include "base/stl_util.h" #include "crypto/hkdf.h" #include "crypto/secure_hash.h" -#include "net/quic/crypto/aes_128_gcm_decrypter.h" -#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_decrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/cert_compressor.h" #include "net/quic/crypto/crypto_framer.h" #include "net/quic/crypto/crypto_server_config_protobuf.h" @@ -51,8 +53,8 @@ QuicCryptoServerConfig::QuicCryptoServerConfig( // TODO(agl): switch to an encrypter with a larger nonce space (i.e. // Salsa20+Poly1305). : strike_register_lock_(), - source_address_token_encrypter_(new Aes128GcmEncrypter), - source_address_token_decrypter_(new Aes128GcmDecrypter), + source_address_token_encrypter_(new Aes128Gcm12Encrypter), + source_address_token_decrypter_(new Aes128Gcm12Decrypter), strike_register_max_entries_(1 << 10), strike_register_window_secs_(600), source_address_token_future_secs_(3600), @@ -295,7 +297,10 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( string* error_details) const { DCHECK(error_details); - CHECK(!configs_.empty()); + if (configs_.empty()) { + *error_details = "No configurations loaded"; + return QUIC_CRYPTO_INTERNAL_ERROR; + } // FIXME(agl): we should use the client's SCID, not just the active config. map<ServerConfigID, Config*>::const_iterator it = @@ -306,6 +311,11 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( } const Config* const config(it->second); + if (client_hello.size() < kClientHelloMinimumSize) { + *error_details = "Client hello too small"; + return QUIC_CRYPTO_INVALID_VALUE_LENGTH; + } + const QuicWallTime now = clock->WallNow(); bool valid_source_address_token = false; StringPiece srct; @@ -351,7 +361,11 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( out->Clear(); StringPiece sni; - client_hello.GetStringPiece(kSNI, &sni); + if (client_hello.GetStringPiece(kSNI, &sni) && + !CryptoUtils::IsValidSNI(sni)) { + *error_details = "Invalid SNI name"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } StringPiece scid; if (!client_hello.GetStringPiece(kSCID, &scid) || @@ -458,6 +472,12 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( } params->server_config_id = scid.as_string(); + if (!sni.empty()) { + scoped_ptr<char[]> sni_tmp(new char[sni.length() + 1]); + memcpy(sni_tmp.get(), sni.data(), sni.length()); + sni_tmp[sni.length()] = 0; + params->sni = CryptoUtils::NormalizeHostname(sni_tmp.get()); + } string hkdf_suffix; const QuicData& client_hello_serialized = client_hello.GetSerialized(); diff --git a/net/quic/crypto/crypto_server_test.cc b/net/quic/crypto/crypto_server_test.cc new file mode 100644 index 0000000..7ab0efe --- /dev/null +++ b/net/quic/crypto/crypto_server_test.cc @@ -0,0 +1,148 @@ +// Copyright (c) 2013 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 "net/quic/crypto/crypto_server_config.h" +#include "net/quic/crypto/quic_random.h" +#include "net/quic/test_tools/crypto_test_utils.h" +#include "net/quic/test_tools/mock_clock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using std::string; + +namespace net { +namespace test { + +class CryptoServerTest : public ::testing::Test { + public: + CryptoServerTest() + : rand_(QuicRandom::GetInstance()), + config_(QuicCryptoServerConfig::TESTING), + addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_) ? + ip_ : IPAddressNumber(), 1) { + } + + virtual void SetUp() { + scoped_ptr<CryptoHandshakeMessage> msg( + config_.AddDefaultConfig(rand_, &clock_, 0)); + } + + void ShouldSucceed(const CryptoHandshakeMessage& message) { + string error_details; + QuicErrorCode error = config_.ProcessClientHello( + message, 1 /* GUID */, addr_, &clock_, + rand_, ¶ms_, &out_, &error_details); + + ASSERT_EQ(error, QUIC_NO_ERROR) + << "Message failed with error " << error_details << ": " + << message.DebugString(); + } + + void ShouldFailMentioning(const char* error_substr, + const CryptoHandshakeMessage& message) { + string error_details; + QuicErrorCode error = config_.ProcessClientHello( + message, 1 /* GUID */, addr_, &clock_, + rand_, ¶ms_, &out_, &error_details); + + ASSERT_NE(error, QUIC_NO_ERROR) + << "Message didn't fail: " << message.DebugString(); + + EXPECT_TRUE(error_details.find(error_substr) != string::npos) + << error_substr << " not in " << error_details; + } + + CryptoHandshakeMessage InchoateClientHello(const char* message_tag, ...) { + va_list ap; + va_start(ap, message_tag); + + CryptoHandshakeMessage message = + CryptoTestUtils::BuildMessage(message_tag, ap); + va_end(ap); + + message.SetStringPiece(kPAD, string(kClientHelloMinimumSize, '-')); + return message; + } + + private: + QuicRandom* const rand_; + MockClock clock_; + QuicCryptoServerConfig config_; + QuicCryptoNegotiatedParameters params_; + CryptoHandshakeMessage out_; + IPAddressNumber ip_; + IPEndPoint addr_; +}; + +TEST_F(CryptoServerTest, BadSNI) { + static const char* kBadSNIs[] = { + "", + "foo", + "#00", + "#ff00", + "127.0.0.1", + "ffee::1", + }; + + for (size_t i = 0; i < arraysize(kBadSNIs); i++) { + ShouldFailMentioning("SNI", InchoateClientHello( + "CHLO", + "SNI", kBadSNIs[i], + NULL)); + } +} + +TEST_F(CryptoServerTest, TooSmall) { + ShouldFailMentioning("too small", CryptoTestUtils::Message( + "CHLO", + NULL)); +} + +TEST_F(CryptoServerTest, BadSourceAddressToken) { + // Invalid source-address tokens should be ignored. + static const char* kBadSourceAddressTokens[] = { + "", + "foo", + "#0000", + "#0000000000000000000000000000000000000000", + }; + + for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) { + ShouldSucceed(InchoateClientHello( + "CHLO", + "STK", kBadSourceAddressTokens[i], + NULL)); + } +} + +TEST_F(CryptoServerTest, BadClientNonce) { + // Invalid nonces should be ignored. + static const char* kBadNonces[] = { + "", + "#0000", + "#0000000000000000000000000000000000000000", + }; + + for (size_t i = 0; i < arraysize(kBadNonces); i++) { + ShouldSucceed(InchoateClientHello( + "CHLO", + "NONC", kBadNonces[i], + NULL)); + } +} + +class CryptoServerTestNoConfig : public CryptoServerTest { + public: + virtual void SetUp() { + // Deliberately don't add a config so that we can test this situation. + } +}; + +TEST_F(CryptoServerTestNoConfig, DontCrash) { + ShouldFailMentioning("No config", InchoateClientHello( + "CHLO", + NULL)); +} + +} // namespace test +} // namespace net diff --git a/net/quic/crypto/crypto_utils.cc b/net/quic/crypto/crypto_utils.cc index a95ac42..a5bed6a 100644 --- a/net/quic/crypto/crypto_utils.cc +++ b/net/quic/crypto/crypto_utils.cc @@ -5,6 +5,8 @@ #include "net/quic/crypto/crypto_utils.h" #include "crypto/hkdf.h" +#include "googleurl/src/url_canon.h" +#include "net/base/net_util.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/crypto_protocol.h" #include "net/quic/crypto/quic_decrypter.h" @@ -17,6 +19,7 @@ using std::string; namespace net { +// static void CryptoUtils::GenerateNonce(QuicWallTime now, QuicRandom* random_generator, StringPiece orbit, @@ -41,6 +44,39 @@ void CryptoUtils::GenerateNonce(QuicWallTime now, kNonceSize - bytes_written); } +// static +bool CryptoUtils::IsValidSNI(StringPiece sni) { + // TODO(rtenneti): Support RFC2396 hostname. + // NOTE: Microsoft does NOT enforce this spec, so if we throw away hostnames + // based on the above spec, we may be losing some hostnames that windows + // would consider valid. By far the most common hostname character NOT + // accepted by the above spec is '_'. + url_canon::CanonHostInfo host_info; + string canonicalized_host(CanonicalizeHost(sni.as_string(), &host_info)); + return !host_info.IsIPAddress() && + IsCanonicalizedHostCompliant(canonicalized_host, "") && + sni.find_last_of('.') != string::npos; +} + +// static +string CryptoUtils::NormalizeHostname(const char* hostname) { + url_canon::CanonHostInfo host_info; + string host(CanonicalizeHost(hostname, &host_info)); + + // Walk backwards over the string, skipping any trailing dots. + size_t host_end = host.length(); + while (host_end != 0 && host[host_end - 1] == '.') { + host_end--; + } + + // Erase the trailing dots. + if (host_end != host.length()) { + host.erase(host_end, host.length() - host_end); + } + return host; +} + +// static void CryptoUtils::DeriveKeys(StringPiece premaster_secret, QuicTag aead, StringPiece client_nonce, diff --git a/net/quic/crypto/crypto_utils.h b/net/quic/crypto/crypto_utils.h index e516718..6dfce2a 100644 --- a/net/quic/crypto/crypto_utils.h +++ b/net/quic/crypto/crypto_utils.h @@ -13,6 +13,7 @@ #include "net/base/net_export.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/quic_protocol.h" #include "net/quic/quic_time.h" namespace net { @@ -37,6 +38,17 @@ class NET_EXPORT_PRIVATE CryptoUtils { base::StringPiece orbit, std::string* nonce); + // Returns true if the sni is valid, false otherwise. + // (1) disallow IP addresses; + // (2) check that the hostname contains valid characters only; and + // (3) contains at least one dot. + static bool IsValidSNI(base::StringPiece sni); + + // Convert hostname to lowercase and remove the trailing '.'. + // Returns |hostname|. NormalizeHostname() doesn't support IP address + // literals. IsValidSNI() should be called before calling NormalizeHostname(). + static std::string NormalizeHostname(const char* hostname); + // DeriveKeys populates |out->encrypter| and |out->decrypter| given the // contents of |premaster_secret|, |client_nonce|, |server_nonce| and // |hkdf_input|. |aead| determines which cipher will be used. |perspective| diff --git a/net/quic/crypto/crypto_utils_test.cc b/net/quic/crypto/crypto_utils_test.cc new file mode 100644 index 0000000..17eb192 --- /dev/null +++ b/net/quic/crypto/crypto_utils_test.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2013 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 "net/quic/crypto/crypto_utils.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { +namespace test { +namespace { + +TEST(CryptoUtilsTest, IsValidSNI) { + // IP as SNI. + EXPECT_FALSE(CryptoUtils::IsValidSNI("192.168.0.1")); + // SNI without any dot. + EXPECT_FALSE(CryptoUtils::IsValidSNI("somedomain")); + // Invalid RFC2396 hostname + // TODO(rtenneti): Support RFC2396 hostname. + // EXPECT_FALSE(CryptoUtils::IsValidSNI("some_domain.com")); + // An empty string must be invalid otherwise the QUIC client will try sending + // it. + EXPECT_FALSE(CryptoUtils::IsValidSNI("")); + + // Valid SNI + EXPECT_TRUE(CryptoUtils::IsValidSNI("test.google.com")); +} + +TEST(CryptoUtilsTest, NormalizeHostname) { + struct { + const char *input, *expected; + } tests[] = { + { "www.google.com", "www.google.com", }, + { "WWW.GOOGLE.COM", "www.google.com", }, + { "www.google.com.", "www.google.com", }, + { "www.google.COM.", "www.google.com", }, + { "www.google.com..", "www.google.com", }, + { "www.google.com........", "www.google.com", }, + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + EXPECT_EQ(std::string(tests[i].expected), + CryptoUtils::NormalizeHostname(tests[i].input)); + } +} + +} // namespace +} // namespace test +} // namespace net diff --git a/net/quic/crypto/quic_decrypter.cc b/net/quic/crypto/quic_decrypter.cc index 2eafdc3..fb19d4c 100644 --- a/net/quic/crypto/quic_decrypter.cc +++ b/net/quic/crypto/quic_decrypter.cc @@ -4,7 +4,7 @@ #include "net/quic/crypto/quic_decrypter.h" -#include "net/quic/crypto/aes_128_gcm_decrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_decrypter.h" #include "net/quic/crypto/null_decrypter.h" namespace net { @@ -13,7 +13,7 @@ namespace net { QuicDecrypter* QuicDecrypter::Create(QuicTag algorithm) { switch (algorithm) { case kAESG: - return new Aes128GcmDecrypter(); + return new Aes128Gcm12Decrypter(); case kNULL: return new NullDecrypter(); default: diff --git a/net/quic/crypto/quic_encrypter.cc b/net/quic/crypto/quic_encrypter.cc index 2e2b83d..489da8e 100644 --- a/net/quic/crypto/quic_encrypter.cc +++ b/net/quic/crypto/quic_encrypter.cc @@ -4,7 +4,7 @@ #include "net/quic/crypto/quic_encrypter.h" -#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/null_encrypter.h" namespace net { @@ -13,7 +13,7 @@ namespace net { QuicEncrypter* QuicEncrypter::Create(QuicTag algorithm) { switch (algorithm) { case kAESG: - return new Aes128GcmEncrypter(); + return new Aes128Gcm12Encrypter(); case kNULL: return new NullEncrypter(); default: diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc index 591da0a..4f90b3e 100644 --- a/net/quic/quic_client_session_test.cc +++ b/net/quic/quic_client_session_test.cc @@ -8,7 +8,7 @@ #include "net/base/capturing_net_log.h" #include "net/base/test_completion_callback.h" -#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/crypto_protocol.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" @@ -56,7 +56,7 @@ class QuicClientSessionTest : public ::testing::Test { }; TEST_F(QuicClientSessionTest, CryptoConnect) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -65,7 +65,7 @@ TEST_F(QuicClientSessionTest, CryptoConnect) { } TEST_F(QuicClientSessionTest, MaxNumConnections) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -86,7 +86,7 @@ TEST_F(QuicClientSessionTest, MaxNumConnections) { } TEST_F(QuicClientSessionTest, GoAwayReceived) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 51319ff..e75bc1a7 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -148,11 +148,6 @@ void QuicConnection::OnError(QuicFramer* framer) { } void QuicConnection::OnPacket() { - // TODO(satyamshekhar): Validate packet before updating the time - // since it affects the timeout of the connection. - time_of_last_received_packet_ = clock_->Now(); - DVLOG(1) << "time of last received packet: " - << time_of_last_received_packet_.ToDebuggingValue(); } void QuicConnection::OnPublicResetPacket( @@ -164,15 +159,9 @@ void QuicConnection::OnPublicResetPacket( } bool QuicConnection::OnProtocolVersionMismatch(QuicTag received_version) { - if (address_migrating_) { - SendConnectionCloseWithDetails( - QUIC_ERROR_MIGRATING_ADDRESS, - "Address migration is not yet a supported feature"); - } - // TODO(satyamshekhar): Implement no server state in this mode. if (!is_server_) { - LOG(DFATAL) << "Framer called OnProtocolVersionMismatch for server. " + LOG(DFATAL) << ENDPOINT << "Framer called OnProtocolVersionMismatch. " << "Closing connection."; CloseConnection(QUIC_INTERNAL_ERROR, false); return false; @@ -221,14 +210,9 @@ bool QuicConnection::OnProtocolVersionMismatch(QuicTag received_version) { // Handles version negotiation for client connection. void QuicConnection::OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) { - if (address_migrating_) { - SendConnectionCloseWithDetails( - QUIC_ERROR_MIGRATING_ADDRESS, - "Address migration is not yet a supported feature"); - } if (is_server_) { - LOG(DFATAL) << "Framer parsed VersionNegotiationPacket for server." - << "Closing connection."; + LOG(DFATAL) << ENDPOINT << "Framer parsed VersionNegotiationPacket." + << " Closing connection."; CloseConnection(QUIC_INTERNAL_ERROR, false); return; } @@ -244,8 +228,8 @@ void QuicConnection::OnVersionNegotiationPacket( if (std::find(packet.versions.begin(), packet.versions.end(), quic_version_) != packet.versions.end()) { - DLOG(WARNING) << "The server already supports our version. It should have " - << "accepted our connection."; + DLOG(WARNING) << ENDPOINT << "The server already supports our version. " + << "It should have accepted our connection."; // Just drop the connection. CloseConnection(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, false); return; @@ -268,10 +252,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { debug_visitor_->OnPacketHeader(header); } - if (address_migrating_) { - SendConnectionCloseWithDetails( - QUIC_ERROR_MIGRATING_ADDRESS, - "Address migration is not yet a supported feature"); + if (!ProcessValidatedPacket()) { return false; } @@ -326,7 +307,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { DCHECK_EQ(NEGOTIATED_VERSION, version_negotiation_state_); --stats_.packets_dropped; - DVLOG(1) << "Received packet header: " << header; + DVLOG(1) << ENDPOINT << "Received packet header: " << header; last_header_ = header; return true; } @@ -353,7 +334,7 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { if (debug_visitor_) { debug_visitor_->OnAckFrame(incoming_ack); } - DVLOG(1) << "OnAckFrame: " << incoming_ack; + DVLOG(1) << ENDPOINT << "OnAckFrame: " << incoming_ack; if (last_header_.packet_sequence_number <= largest_seen_packet_with_ack_) { DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring"; @@ -506,7 +487,7 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( RetransmittableFrames* unacked = it->second; if (!IsAwaitingPacket(incoming_ack.received_info, sequence_number)) { // Packet was acked, so remove it from our unacked packet list. - DVLOG(1) << "Got an ack for " << sequence_number; + DVLOG(1) << ENDPOINT <<"Got an ack for packet " << sequence_number; acked_packets.insert(sequence_number); delete unacked; UnackedPacketMap::iterator it_tmp = it; @@ -517,7 +498,7 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( // This is a packet which we planned on retransmitting and has not been // seen at the time of this ack being sent out. See if it's our new // lowest unacked packet. - DVLOG(1) << "still missing " << sequence_number; + DVLOG(1) << ENDPOINT << "still missing packet " << sequence_number; ++it; // The peer got packets after this sequence number. This is an explicit // nack. @@ -528,7 +509,8 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( kNumberOfNacksBeforeRetransmission && retransmitted_packets < kMaxRetransmissionsPerAck) { ++retransmitted_packets; - DVLOG(1) << "Trying to retransmit packet " << sequence_number + DVLOG(1) << ENDPOINT << "Trying to retransmit packet " + << sequence_number << " as it has been nacked 3 or more times."; // TODO(satyamshekhar): save in a vector and retransmit after the // loop. @@ -562,7 +544,7 @@ void QuicConnection::UpdatePacketInformationSentByPeer( DontWaitForPacketsBefore(incoming_ack.sent_info.least_unacked); if (missed_packets || incoming_ack.sent_info.least_unacked > outgoing_ack_.received_info.largest_observed + 1) { - DVLOG(1) << "Updating entropy hashed since we missed packets"; + DVLOG(1) << ENDPOINT << "Updating entropy hashed since we missed packets"; // There were some missing packets that we won't ever get now. Recalculate // the received entropy hash. entropy_manager_.RecalculateReceivedEntropyHash( @@ -596,7 +578,7 @@ bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) { if (debug_visitor_) { debug_visitor_->OnRstStreamFrame(frame); } - DLOG(INFO) << "Stream reset with error " + DLOG(INFO) << ENDPOINT << "Stream reset with error " << QuicUtils::StreamErrorToString(frame.error_code); visitor_->OnRstStream(frame); return connected_; @@ -778,6 +760,19 @@ bool QuicConnection::OnCanWrite() { return !write_blocked_; } +bool QuicConnection::ProcessValidatedPacket() { + if (address_migrating_) { + SendConnectionCloseWithDetails( + QUIC_ERROR_MIGRATING_ADDRESS, + "Address migration is not yet a supported feature"); + return false; + } + time_of_last_received_packet_ = clock_->Now(); + DVLOG(1) << ENDPOINT << "time of last received packet: " + << time_of_last_received_packet_.ToDebuggingValue(); + return true; +} + bool QuicConnection::WriteQueuedPackets() { DCHECK(!write_blocked_); @@ -821,7 +816,8 @@ void QuicConnection::RecordPacketReceived(const QuicPacketHeader& header) { header.packet_sequence_number) { // We've gotten one of the out of order packets - remove it from our // "missing packets" list. - DVLOG(1) << "Removing " << sequence_number << " from missing list"; + DVLOG(1) << ENDPOINT << "Removing " << sequence_number + << " from missing list"; outgoing_ack_.received_info.missing_packets.erase(sequence_number); } if (header.packet_sequence_number > @@ -840,7 +836,7 @@ bool QuicConnection::MaybeRetransmitPacketForRTO( ContainsKey(retransmission_map_, sequence_number)); if (!ContainsKey(unacked_packets_, sequence_number)) { - DVLOG(2) << "alarm fired for " << sequence_number + DVLOG(2) << ENDPOINT << "alarm fired for " << sequence_number << " but it has been acked or already retransmitted with" << " different sequence number."; // So no extra delay is added for this packet. @@ -903,8 +899,8 @@ void QuicConnection::RetransmitPacket( // Remove info with old sequence number. unacked_packets_.erase(unacked_it); retransmission_map_.erase(retransmission_it); - DVLOG(1) << "Retransmitting unacked packet " << sequence_number << " as " - << serialized_packet.sequence_number; + DVLOG(1) << ENDPOINT << "Retransmitting unacked packet " << sequence_number + << " as " << serialized_packet.sequence_number; DCHECK(unacked_packets_.empty() || unacked_packets_.rbegin()->first < serialized_packet.sequence_number); unacked_packets_.insert(make_pair(serialized_packet.sequence_number, @@ -950,7 +946,7 @@ void QuicConnection::MaybeSetupRetransmission( QuicPacketSequenceNumber sequence_number) { RetransmissionMap::iterator it = retransmission_map_.find(sequence_number); if (it == retransmission_map_.end()) { - DVLOG(1) << "Will not retransmit packet " << sequence_number; + DVLOG(1) << ENDPOINT << "Will not retransmit packet " << sequence_number; return; } @@ -1000,7 +996,12 @@ bool QuicConnection::WritePacket(EncryptionLevel level, << " : " << (packet->is_fec_packet() ? "FEC " : (retransmittable == HAS_RETRANSMITTABLE_DATA ? "data bearing " : " ack only ")) - << " Packet length:" << packet->length(); + << ", encryption level: " + << QuicUtils::EncryptionLevelToString(level) + << ", length:" << packet->length(); + // TODO(rtenneti): Get StringToHexASCIIDump of packet. + DVLOG(2) << ENDPOINT << "packet(" << sequence_number << "): " << std::endl + << packet->AsStringPiece(); DCHECK(encrypted->length() <= kMaxPacketSize) << "Packet " << sequence_number << " will not be read; too large: " @@ -1024,8 +1025,11 @@ bool QuicConnection::WritePacket(EncryptionLevel level, CloseConnection(QUIC_PACKET_WRITE_ERROR, false); return false; } - time_of_last_sent_packet_ = now; - DVLOG(1) << "time of last sent packet: " << now.ToDebuggingValue(); + if (!retransmission) { + time_of_last_sent_packet_ = now; + } + DVLOG(1) << ENDPOINT << "time of last sent packet: " + << now.ToDebuggingValue(); // Set the retransmit alarm only when we have sent the packet to the client // and not when it goes to the pending queue, otherwise we will end up adding @@ -1117,7 +1121,7 @@ void QuicConnection::UpdateOutgoingAck() { void QuicConnection::SendAck() { helper_->ClearAckAlarm(); UpdateOutgoingAck(); - DVLOG(1) << "Sending ack: " << outgoing_ack_; + DVLOG(1) << ENDPOINT << "Sending ack: " << outgoing_ack_; // TODO(rch): delay this until the CreateFeedbackFrame // method is invoked. This requires changes SetShouldSendAck @@ -1125,7 +1129,8 @@ void QuicConnection::SendAck() { bool send_feedback = false; if (congestion_manager_.GenerateCongestionFeedback( &outgoing_congestion_feedback_)) { - DVLOG(1) << "Sending feedback " << outgoing_congestion_feedback_; + DVLOG(1) << ENDPOINT << "Sending feedback " + << outgoing_congestion_feedback_; send_feedback = true; } @@ -1338,7 +1343,8 @@ bool QuicConnection::CheckForTimeout() { time_of_last_sent_packet_); QuicTime::Delta delta = now.Subtract(time_of_last_packet); - DVLOG(1) << "last packet " << time_of_last_packet.ToDebuggingValue() + DVLOG(1) << ENDPOINT << "last packet " + << time_of_last_packet.ToDebuggingValue() << " now:" << now.ToDebuggingValue() << " delta:" << delta.ToMicroseconds(); if (delta >= timeout_) { diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index dab64ee..f3096ad 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -257,6 +257,11 @@ class NET_EXPORT_PRIVATE QuicConnection // queued writes to happen. Returns false if the socket has become blocked. virtual bool OnCanWrite() OVERRIDE; + // Do any work which logically would be done in OnPacket but can not be + // safely done until the packet is validated. Returns true if the packet + // can be handled, false otherwise. + bool ProcessValidatedPacket(); + QuicTag version() const { return quic_version_; } // From QuicFramerVisitorInterface diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index b761aaf..cf28e46 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -73,7 +73,7 @@ class TestReceiveAlgorithm : public ReceiveAlgorithmInterface { DISALLOW_COPY_AND_ASSIGN(TestReceiveAlgorithm); }; -// TaggingEncrypter appends 16 bytes of |tag| to the end of each message. +// TaggingEncrypter appends kTagSize bytes of |tag| to the end of each message. class TaggingEncrypter : public QuicEncrypter { public: explicit TaggingEncrypter(uint8 tag) @@ -128,14 +128,14 @@ class TaggingEncrypter : public QuicEncrypter { private: enum { - kTagSize = 16, + kTagSize = 12, }; const uint8 tag_; }; -// TaggingDecrypter ensures that the final 16 bytes of the message all have the -// same value and then removes them. +// TaggingDecrypter ensures that the final kTagSize bytes of the message all +// have the same value and then removes them. class TaggingDecrypter : public QuicDecrypter { public: virtual ~TaggingDecrypter() {} @@ -183,7 +183,7 @@ class TaggingDecrypter : public QuicDecrypter { private: enum { - kTagSize = 16, + kTagSize = 12, }; bool CheckTag(StringPiece ciphertext) { @@ -1343,8 +1343,8 @@ TEST_F(QuicConnectionTest, RetransmitWithSameEncryptionLevel) { kDefaultRetransmissionTime); use_tagging_decrypter(); - // A TaggingEncrypter puts 16 copies of the given byte (0x01 here) at the end - // of the packet. We can test this to check which encrypter was used. + // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at + // the end of the packet. We can test this to check which encrypter was used. connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01)); SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); EXPECT_EQ(0x01010101u, final_bytes_of_last_packet()); diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc index 90b9122..160aaf9 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc @@ -5,7 +5,7 @@ #include "net/quic/quic_crypto_client_stream.h" #include "base/memory/scoped_ptr.h" -#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" #include "net/quic/quic_protocol.h" @@ -19,7 +19,7 @@ namespace net { namespace test { namespace { -const char kServerHostname[] = "localhost"; +const char kServerHostname[] = "example.com"; class TestQuicVisitor : public NoOpFramerVisitor { public: @@ -52,15 +52,16 @@ class QuicCryptoClientStreamTest : public ::testing::Test { : addr_(), connection_(new PacketSavingConnection(1, addr_, true)), session_(connection_, QuicConfig(), true), - stream_(kServerHostname, &session_, &crypto_config_) { - session_.SetCryptoStream(&stream_); + stream_(new QuicCryptoClientStream(kServerHostname, &session_, + &crypto_config_)) { + session_.SetCryptoStream(stream_.get()); session_.config()->SetDefaults(); crypto_config_.SetDefaults(); } void CompleteCryptoHandshake() { - EXPECT_TRUE(stream_.CryptoConnect()); - CryptoTestUtils::HandshakeWithFakeServer(connection_, &stream_); + EXPECT_TRUE(stream_->CryptoConnect()); + CryptoTestUtils::HandshakeWithFakeServer(connection_, stream_.get()); } void ConstructHandshakeMessage() { @@ -71,35 +72,35 @@ class QuicCryptoClientStreamTest : public ::testing::Test { IPEndPoint addr_; PacketSavingConnection* connection_; TestSession session_; - QuicCryptoClientStream stream_; + scoped_ptr<QuicCryptoClientStream> stream_; CryptoHandshakeMessage message_; scoped_ptr<QuicData> message_data_; QuicCryptoClientConfig crypto_config_; }; TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } - EXPECT_FALSE(stream_.encryption_established()); - EXPECT_FALSE(stream_.handshake_confirmed()); + EXPECT_FALSE(stream_->encryption_established()); + EXPECT_FALSE(stream_->handshake_confirmed()); } TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } CompleteCryptoHandshake(); - EXPECT_TRUE(stream_.encryption_established()); - EXPECT_TRUE(stream_.handshake_confirmed()); + EXPECT_TRUE(stream_->encryption_established()); + EXPECT_TRUE(stream_->handshake_confirmed()); } TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -110,27 +111,27 @@ TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)); message_.set_tag(kCHLO); ConstructHandshakeMessage(); - stream_.ProcessData(message_data_->data(), message_data_->length()); + stream_->ProcessData(message_data_->data(), message_data_->length()); } TEST_F(QuicCryptoClientStreamTest, BadMessageType) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } - EXPECT_TRUE(stream_.CryptoConnect()); + EXPECT_TRUE(stream_->CryptoConnect()); message_.set_tag(kCHLO); ConstructHandshakeMessage(); EXPECT_CALL(*connection_, SendConnectionCloseWithDetails( QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "Expected REJ")); - stream_.ProcessData(message_data_->data(), message_data_->length()); + stream_->ProcessData(message_data_->data(), message_data_->length()); } TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -146,11 +147,26 @@ TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) { EXPECT_EQ(0, config->keepalive_timeout().ToSeconds()); const QuicCryptoNegotiatedParameters& crypto_params( - stream_.crypto_negotiated_params()); + stream_->crypto_negotiated_params()); EXPECT_EQ(kAESG, crypto_params.aead); EXPECT_EQ(kC255, crypto_params.key_exchange); } +TEST_F(QuicCryptoClientStreamTest, InvalidHostname) { + if (!Aes128Gcm12Encrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + + stream_.reset(new QuicCryptoClientStream("invalid", &session_, + &crypto_config_)); + session_.SetCryptoStream(stream_.get()); + + CompleteCryptoHandshake(); + EXPECT_TRUE(stream_->encryption_established()); + EXPECT_TRUE(stream_->handshake_confirmed()); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc index c87c6d5..6aef276 100644 --- a/net/quic/quic_crypto_server_stream.cc +++ b/net/quic/quic_crypto_server_stream.cc @@ -44,7 +44,6 @@ void QuicCryptoServerStream::OnHandshakeMessage( session()->connection()->clock(), session()->connection()->random_generator(), &crypto_negotiated_params_, &reply, &error_details); - if (error != QUIC_NO_ERROR) { CloseConnectionWithDetails(error, error_details); return; diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc index 686bca7..2db0881 100644 --- a/net/quic/quic_crypto_server_stream_test.cc +++ b/net/quic/quic_crypto_server_stream_test.cc @@ -8,7 +8,7 @@ #include <vector> #include "base/memory/scoped_ptr.h" -#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/crypto_framer.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/crypto_protocol.h" @@ -103,7 +103,7 @@ class QuicCryptoServerStreamTest : public ::testing::Test { }; TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -113,7 +113,7 @@ TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) { } TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -132,7 +132,7 @@ TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { } TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -186,7 +186,7 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { // This causes the client's nonce to be different and thus stops the // strike-register from rejecting the repeated nonce. - client_conn->random_generator()->Reseed(NULL, 0); + reinterpret_cast<MockRandom*>(client_conn->random_generator())->ChangeValue(); client_session.reset(new TestSession(client_conn, client_config, false)); server_session.reset(new TestSession(server_conn, config_, true)); client.reset(new QuicCryptoClientStream( @@ -205,7 +205,7 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { } TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -219,7 +219,7 @@ TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) { } TEST_F(QuicCryptoServerStreamTest, BadMessageType) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -232,7 +232,7 @@ TEST_F(QuicCryptoServerStreamTest, BadMessageType) { } TEST_F(QuicCryptoServerStreamTest, WithoutCertificates) { - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } diff --git a/net/quic/quic_data_writer.cc b/net/quic/quic_data_writer.cc index 4182d9a..e52cd03 100644 --- a/net/quic/quic_data_writer.cc +++ b/net/quic/quic_data_writer.cc @@ -98,6 +98,18 @@ bool QuicDataWriter::WriteBytes(const void* data, size_t data_len) { return true; } +bool QuicDataWriter::WriteRepeatedByte(uint8 byte, size_t count) { + char* dest = BeginWrite(count); + if (!dest) { + return false; + } + + memset(dest, byte, count); + + length_ += count; + return true; +} + void QuicDataWriter::WritePadding() { DCHECK_LE(length_, capacity_); if (length_ > capacity_) { diff --git a/net/quic/quic_data_writer.h b/net/quic/quic_data_writer.h index 5ecd628..f3408d1 100644 --- a/net/quic/quic_data_writer.h +++ b/net/quic/quic_data_writer.h @@ -46,6 +46,7 @@ class NET_EXPORT_PRIVATE QuicDataWriter { bool WriteUInt128(uint128 value); bool WriteStringPiece16(base::StringPiece val); bool WriteBytes(const void* data, size_t data_len); + bool WriteRepeatedByte(uint8 byte, size_t count); // Fills the remaining buffer with null characters. void WritePadding(); diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index 0e56382..e900e2c 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -105,6 +105,8 @@ size_t QuicFramer::GetMinGoAwayFrameSize() { // static // TODO(satyamshekhar): 16 - Crypto hash for integrity. Not a static value. Use // QuicEncrypter::GetMaxPlaintextSize. +// 16 is a conservative estimate in the case of AEAD_AES_128_GCM_12, which uses +// 12-byte tags. size_t QuicFramer::GetMaxUnackedPackets(bool include_version) { return (kMaxPacketSize - GetPacketHeaderSize(include_version) - GetMinAckFrameSize() - 16) / kSequenceNumberSize; @@ -115,7 +117,7 @@ bool QuicFramer::IsSupportedVersion(QuicTag version) { } size_t QuicFramer::GetVersionNegotiationPacketSize(size_t number_versions) { - return kQuicGuidSize + kPublicFlagsSize + + return kPublicFlagsSize + kQuicGuidSize + number_versions * kQuicVersionSize; } @@ -274,12 +276,12 @@ QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket( size_t len = GetPublicResetPacketSize(); QuicDataWriter writer(len); - if (!writer.WriteUInt64(packet.public_header.guid)) { + uint8 flags = static_cast<uint8>(PACKET_PUBLIC_FLAGS_RST); + if (!writer.WriteUInt8(flags)) { return NULL; } - uint8 flags = static_cast<uint8>(PACKET_PUBLIC_FLAGS_RST); - if (!writer.WriteUInt8(flags)) { + if (!writer.WriteUInt64(packet.public_header.guid)) { return NULL; } @@ -302,12 +304,12 @@ QuicEncryptedPacket* QuicFramer::ConstructVersionNegotiationPacket( size_t len = GetVersionNegotiationPacketSize(supported_versions.size()); QuicDataWriter writer(len); - if (!writer.WriteUInt64(header.guid)) { + uint8 flags = static_cast<uint8>(PACKET_PUBLIC_FLAGS_VERSION); + if (!writer.WriteUInt8(flags)) { return NULL; } - uint8 flags = static_cast<uint8>(PACKET_PUBLIC_FLAGS_VERSION); - if (!writer.WriteUInt8(flags)) { + if (!writer.WriteUInt64(header.guid)) { return NULL; } @@ -463,10 +465,6 @@ bool QuicFramer::ProcessRevivedPacket(QuicPacketHeader* header, bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header, QuicDataWriter* writer) { - if (!writer->WriteUInt64(header.public_header.guid)) { - return false; - } - uint8 flags = 0; if (header.public_header.reset_flag) { flags |= PACKET_PUBLIC_FLAGS_RST; @@ -478,6 +476,10 @@ bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header, return false; } + if (!writer->WriteUInt64(header.public_header.guid)) { + return false; + } + if (header.public_header.version_flag) { DCHECK(!is_server_); writer->WriteUInt32(quic_version_); @@ -538,11 +540,6 @@ QuicPacketSequenceNumber QuicFramer::CalculatePacketSequenceNumberFromWire( } bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) { - if (!reader_->ReadUInt64(&public_header->guid)) { - set_detailed_error("Unable to read GUID."); - return false; - } - uint8 public_flags; if (!reader_->ReadBytes(&public_flags, 1)) { set_detailed_error("Unable to read public flags."); @@ -563,6 +560,11 @@ bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) { return false; } + if (!reader_->ReadUInt64(&public_header->guid)) { + set_detailed_error("Unable to read GUID."); + return false; + } + if (public_header->version_flag && is_server_) { QuicTag version; if (!reader_->ReadUInt32(&version)) { @@ -579,7 +581,13 @@ bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) { // static bool QuicFramer::ReadGuidFromPacket(const QuicEncryptedPacket& packet, QuicGuid* guid) { + // TODO(ianswett): In the next CL, the flags will be used for guid length. QuicDataReader reader(packet.data(), packet.length()); + uint8 public_flags; + if (!reader.ReadBytes(&public_flags, 1)) { + return false; + } + return reader.ReadUInt64(guid); } @@ -1115,9 +1123,9 @@ QuicEncryptedPacket* QuicFramer::EncryptPacket( size_t QuicFramer::GetMaxPlaintextSize(size_t ciphertext_size) { // In order to keep the code simple, we don't have the current encryption - // level to hand. At the moment, all AEADs have a tag-length of 16 bytes so - // that doesn't matter but we take the minimum plaintext length just to be - // safe. + // level to hand. At the moment, the NullEncrypter has a tag length of 16 + // bytes and AES-GCM has a tag length of 12. We take the minimum plaintext + // length just to be safe. size_t min_plaintext_size = ciphertext_size; for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; i++) { diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index 701e2bb..d75d9a6 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -36,16 +36,16 @@ namespace test { const QuicPacketSequenceNumber kEpoch = GG_UINT64_C(1) << 48; const QuicPacketSequenceNumber kMask = kEpoch - 1; -// Index into the guid offset in the header. -const size_t kGuidOffset = 0; // Index into the flags offset in the header. -const size_t kPublicFlagsOffset = kQuicGuidSize; +const size_t kPublicFlagsOffset = 0; +// Index into the guid offset in the header. +const size_t kGuidOffset = kPublicFlagsSize; // Index into the version string in the header. (if present). -const size_t kVersionOffset = kPublicFlagsOffset + kPublicFlagsSize; +const size_t kVersionOffset = kGuidOffset + kQuicGuidSize; // Index into the sequence number offset in the header. size_t GetSequenceNumberOffset(bool include_version) { - return kPublicFlagsOffset + kPublicFlagsSize + + return kGuidOffset + kQuicGuidSize + (include_version ? kQuicVersionSize : 0); } @@ -60,8 +60,7 @@ size_t GetFecGroupOffset(bool include_version) { } // Index into the nonce proof of the public reset packet. -const size_t kPublicResetPacketNonceProofOffset = - kPublicFlagsOffset + kPublicFlagsSize; +const size_t kPublicResetPacketNonceProofOffset = kGuidOffset + kQuicGuidSize; // Index into the rejected sequence number of the public reset packet. const size_t kPublicResetPacketRejectedSequenceNumberOffset = kPublicResetPacketNonceProofOffset + kPublicResetNonceSize; @@ -486,11 +485,11 @@ TEST_F(QuicFramerTest, EmptyPacket) { TEST_F(QuicFramerTest, LargePacket) { unsigned char packet[kMaxPacketSize + 1] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -516,11 +515,11 @@ TEST_F(QuicFramerTest, LargePacket) { TEST_F(QuicFramerTest, PacketHeader) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -549,10 +548,10 @@ TEST_F(QuicFramerTest, PacketHeader) { // Now test framing boundaries for (size_t i = 0; i < GetPacketHeaderSize(!kIncludeVersion); ++i) { string expected_error; - if (i < kPublicFlagsOffset) { - expected_error = "Unable to read GUID."; - } else if (i < GetSequenceNumberOffset(!kIncludeVersion)) { + if (i < kGuidOffset) { expected_error = "Unable to read public flags."; + } else if (i < GetSequenceNumberOffset(!kIncludeVersion)) { + expected_error = "Unable to read GUID."; } else if (i < GetPrivateFlagsOffset(!kIncludeVersion)) { expected_error = "Unable to read sequence number."; } else if (i < GetFecGroupOffset(!kIncludeVersion)) { @@ -566,13 +565,13 @@ TEST_F(QuicFramerTest, PacketHeader) { TEST_F(QuicFramerTest, PacketHeaderWithVersionFlag) { unsigned char packet[] = { + // public flags (version) + 0x01, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags (version) - 0x01, // version tag - 'Q', '0', '0', '2', + 'Q', '0', '0', '3', // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -602,10 +601,10 @@ TEST_F(QuicFramerTest, PacketHeaderWithVersionFlag) { // Now test framing boundaries for (size_t i = 0; i < GetPacketHeaderSize(kIncludeVersion); ++i) { string expected_error; - if (i < kPublicFlagsOffset) { - expected_error = "Unable to read GUID."; - } else if (i < kVersionOffset) { + if (i < kGuidOffset) { expected_error = "Unable to read public flags."; + } else if (i < kVersionOffset) { + expected_error = "Unable to read GUID."; } else if (i < GetSequenceNumberOffset(kIncludeVersion)) { expected_error = "Unable to read protocol version."; } else if (i < GetPrivateFlagsOffset(kIncludeVersion)) { @@ -622,11 +621,11 @@ TEST_F(QuicFramerTest, PacketHeaderWithVersionFlag) { TEST_F(QuicFramerTest, InvalidPublicFlag) { unsigned char packet[] = { + // public flags + 0x07, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x07, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -661,11 +660,11 @@ TEST_F(QuicFramerTest, InvalidPublicFlag) { TEST_F(QuicFramerTest, InvalidPrivateFlag) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -700,11 +699,11 @@ TEST_F(QuicFramerTest, InvalidPrivateFlag) { TEST_F(QuicFramerTest, PaddingFrame) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -742,11 +741,11 @@ TEST_F(QuicFramerTest, PaddingFrame) { TEST_F(QuicFramerTest, StreamFrame) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -811,13 +810,13 @@ TEST_F(QuicFramerTest, StreamFrame) { TEST_F(QuicFramerTest, StreamFrameWithVersion) { unsigned char packet[] = { + // public flags (version) + 0x01, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags (version) - 0x01, // version tag - 'Q', '0', '0', '2', + 'Q', '0', '0', '3', // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -886,11 +885,11 @@ TEST_F(QuicFramerTest, RejectPacket) { visitor_.accept_packet_ = false; unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -988,11 +987,11 @@ TEST_F(QuicFramerTest, RevivedStreamFrame) { TEST_F(QuicFramerTest, StreamFrameInFecGroup) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x12, 0x34, @@ -1042,11 +1041,11 @@ TEST_F(QuicFramerTest, StreamFrameInFecGroup) { TEST_F(QuicFramerTest, AckFrame) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1136,11 +1135,11 @@ TEST_F(QuicFramerTest, AckFrame) { TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1194,11 +1193,11 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) { TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1291,11 +1290,11 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) { TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1345,11 +1344,11 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) { TEST_F(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1372,11 +1371,11 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) { TEST_F(QuicFramerTest, RstStreamFrame) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1430,11 +1429,11 @@ TEST_F(QuicFramerTest, RstStreamFrame) { TEST_F(QuicFramerTest, ConnectionCloseFrame) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1516,11 +1515,11 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) { TEST_F(QuicFramerTest, GoAwayFrame) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1576,11 +1575,11 @@ TEST_F(QuicFramerTest, GoAwayFrame) { TEST_F(QuicFramerTest, PublicResetPacket) { unsigned char packet[] = { + // public flags (public reset) + 0x02, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags (public reset) - 0x02, // nonce proof 0x89, 0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB, @@ -1606,12 +1605,12 @@ TEST_F(QuicFramerTest, PublicResetPacket) { for (size_t i = 0; i < GetPublicResetPacketSize(); ++i) { string expected_error; DLOG(INFO) << "iteration: " << i; - if (i < kPublicFlagsOffset) { - expected_error = "Unable to read GUID."; + if (i < kGuidOffset) { + expected_error = "Unable to read public flags."; CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } else if (i < kPublicResetPacketNonceProofOffset) { - expected_error = "Unable to read public flags."; + expected_error = "Unable to read GUID."; CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } else if (i < kPublicResetPacketRejectedSequenceNumberOffset) { @@ -1628,12 +1627,13 @@ TEST_F(QuicFramerTest, PublicResetPacket) { TEST_F(QuicFramerTest, VersionNegotiationPacket) { unsigned char packet[] = { - 0x10, 0x32, 0x54, 0x76, - 0x98, 0xBA, 0xDC, 0xFE, // public flags (version) 0x01, + // guid + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, // version tag - 'Q', '0', '0', '2', + 'Q', '0', '0', '3', 'Q', '2', '.', '0', }; @@ -1647,13 +1647,13 @@ TEST_F(QuicFramerTest, VersionNegotiationPacket) { EXPECT_EQ(kQuicVersion1, visitor_.version_negotiation_packet_->versions[0]); - for (size_t i = 0; i <= kQuicGuidSize + kPublicFlagsSize; ++i) { + for (size_t i = 0; i <= kPublicFlagsSize + kQuicGuidSize; ++i) { string expected_error; QuicErrorCode error_code = QUIC_INVALID_PACKET_HEADER; - if (i < kPublicFlagsOffset) { - expected_error = "Unable to read GUID."; - } else if (i < kVersionOffset) { + if (i < kGuidOffset) { expected_error = "Unable to read public flags."; + } else if (i < kVersionOffset) { + expected_error = "Unable to read GUID."; } else { expected_error = "Unable to read supported version in negotiation."; error_code = QUIC_INVALID_VERSION_NEGOTIATION_PACKET; @@ -1664,11 +1664,11 @@ TEST_F(QuicFramerTest, VersionNegotiationPacket) { TEST_F(QuicFramerTest, FecPacket) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1716,11 +1716,11 @@ TEST_F(QuicFramerTest, ConstructPaddingFramePacket) { frames.push_back(QuicFrame(&padding_frame)); unsigned char packet[kMaxPacketSize] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1766,11 +1766,11 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacket) { frames.push_back(QuicFrame(&stream_frame)); unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1826,13 +1826,13 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) { frames.push_back(QuicFrame(&stream_frame)); unsigned char packet[] = { + // public flags (version) + 0x01, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags (version) - 0x01, // version tag - 'Q', '0', '0', '2', + 'Q', '0', '0', '3', // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1875,12 +1875,13 @@ TEST_F(QuicFramerTest, ConstructVersionNegotiationPacket) { header.version_flag = true; unsigned char packet[] = { - 0x10, 0x32, 0x54, 0x76, - 0x98, 0xBA, 0xDC, 0xFE, // public flags (version) 0x01, + // guid + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, // version tag - 'Q', '0', '0', '2', + 'Q', '0', '0', '3', 'Q', '2', '.', '0', }; @@ -1920,11 +1921,11 @@ TEST_F(QuicFramerTest, ConstructAckFramePacket) { frames.push_back(QuicFrame(&ack_frame)); unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1983,11 +1984,11 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) { frames.push_back(QuicFrame(&congestion_feedback_frame)); unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2045,11 +2046,11 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) { frames.push_back(QuicFrame(&frame)); unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2111,11 +2112,11 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) { frames.push_back(QuicFrame(&congestion_feedback_frame)); unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2181,11 +2182,11 @@ TEST_F(QuicFramerTest, ConstructRstFramePacket) { rst_frame.error_details = "because I can"; unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2247,11 +2248,11 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) { frames.push_back(QuicFrame(&close_frame)); unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2321,11 +2322,11 @@ TEST_F(QuicFramerTest, ConstructGoAwayPacket) { frames.push_back(QuicFrame(&goaway_frame)); unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2367,11 +2368,11 @@ TEST_F(QuicFramerTest, ConstructPublicResetPacket) { reset_packet.nonce_proof = GG_UINT64_C(0xABCDEF0123456789); unsigned char packet[] = { + // public flags + 0x02, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x02, // nonce proof 0x89, 0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB, @@ -2405,11 +2406,11 @@ TEST_F(QuicFramerTest, ConstructFecPacket) { fec_data.redundancy = "abcdefghijklmnop"; unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2437,11 +2438,11 @@ TEST_F(QuicFramerTest, ConstructFecPacket) { TEST_F(QuicFramerTest, EncryptPacket) { QuicPacketSequenceNumber sequence_number = GG_UINT64_C(0x123456789ABC); unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2470,11 +2471,11 @@ TEST_F(QuicFramerTest, EncryptPacket) { TEST_F(QuicFramerTest, EncryptPacketWithVersionFlag) { QuicPacketSequenceNumber sequence_number = GG_UINT64_C(0x123456789ABC); unsigned char packet[] = { + // public flags (version) + 0x01, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags (version) - 0x01, // version tag 'Q', '.', '1', '0', // packet sequence number @@ -2664,11 +2665,11 @@ TEST_F(QuicFramerTest, CleanTruncation) { TEST_F(QuicFramerTest, EntropyFlagTest) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2705,11 +2706,11 @@ TEST_F(QuicFramerTest, EntropyFlagTest) { TEST_F(QuicFramerTest, FecEntropyFlagTest) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2747,11 +2748,11 @@ TEST_F(QuicFramerTest, FecEntropyFlagTest) { TEST_F(QuicFramerTest, StopPacketProcessing) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -2810,11 +2811,11 @@ TEST_F(QuicFramerTest, StopPacketProcessing) { TEST_F(QuicFramerTest, ConnectionCloseWithInvalidAck) { unsigned char packet[] = { + // public flags + 0x00, // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc index bd4f332..4208b46 100644 --- a/net/quic/quic_packet_creator_test.cc +++ b/net/quic/quic_packet_creator_test.cc @@ -173,7 +173,7 @@ TEST_F(QuicPacketCreatorTest, CreateStreamFrameFinOnly) { QuicFrame frame; size_t consumed = creator_.CreateStreamFrame(1u, "", 0u, true, &frame); EXPECT_EQ(0u, consumed); - CheckStreamFrame(frame, 1u, std::string(), 0u, true); + CheckStreamFrame(frame, 1u, string(), 0u, true); delete frame.stream_frame; } diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 27f980f..4c0c88c 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -14,13 +14,13 @@ using std::string; namespace net { size_t GetPacketHeaderSize(bool include_version) { - return kQuicGuidSize + kPublicFlagsSize + + return kPublicFlagsSize + kQuicGuidSize + (include_version ? kQuicVersionSize : 0) + kSequenceNumberSize + kPrivateFlagsSize + kFecGroupSize; } size_t GetPublicResetPacketSize() { - return kQuicGuidSize + kPublicFlagsSize + kPublicResetNonceSize + + return kPublicFlagsSize + kQuicGuidSize + kPublicResetNonceSize + kSequenceNumberSize; } diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index f4c5e95..45676f5 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -48,10 +48,10 @@ const QuicByteCount kMaxPacketSize = 1200; // Maximum number of open streams per connection. const size_t kDefaultMaxStreamsPerConnection = 100; -// Number of bytes reserved for guid in the packet header. -const size_t kQuicGuidSize = 8; // Number of bytes reserved for public flags in the packet header. const size_t kPublicFlagsSize = 1; +// Number of bytes reserved for guid in the packet header. +const size_t kQuicGuidSize = 8; // Number of bytes reserved for version number in the packet header. const size_t kQuicVersionSize = 4; // Number of bytes reserved for sequence number in the packet header. @@ -271,7 +271,7 @@ const QuicTag kUnsupportedVersion = -1; // Each time the wire format changes, this need needs to be incremented. // At some point, we will actually freeze the wire format and make an official // version number, but this works for now. -const QuicTag kQuicVersion1 = TAG('Q', '0', '0', '2'); +const QuicTag kQuicVersion1 = TAG('Q', '0', '0', '3'); #undef TAG // MakeQuicTag returns a value given the four bytes. For example: diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 00003d4..10ede55 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -104,6 +104,8 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { // Servers will simply call it once with HANDSHAKE_CONFIRMED. virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event); + // Returns mutable config for this session. Returned config is owned + // by QuicSession. virtual QuicConfig* config(); // Returns true if the stream existed previously and has been closed. diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index a42993c..ae5f4b5 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc @@ -197,6 +197,17 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { } // static +const char* QuicUtils::EncryptionLevelToString(EncryptionLevel level) { + switch (level) { + RETURN_STRING_LITERAL(ENCRYPTION_NONE); + RETURN_STRING_LITERAL(ENCRYPTION_INITIAL); + RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE); + RETURN_STRING_LITERAL(NUM_ENCRYPTION_LEVELS); + } + return "INVALID_ENCRYPTION_LEVEL"; +} + +// static string QuicUtils::TagToString(QuicTag tag) { char chars[4]; bool ascii = true; diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h index e866a07..e277504 100644 --- a/net/quic/quic_utils.h +++ b/net/quic/quic_utils.h @@ -55,6 +55,9 @@ class NET_EXPORT_PRIVATE QuicUtils { // Returns the name of the QuicErrorCode as a char* static const char* ErrorToString(QuicErrorCode error); + // Returns the level of encryption as a char* + static const char* EncryptionLevelToString(EncryptionLevel level); + // TagToString is a utility function for pretty-printing handshake messages // that converts a tag to a string. It will try to maintain the human friendly // name if possible (i.e. kABCD -> "ABCD"), or will just treat it as a number diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc index 4e285ad..0f203fb 100644 --- a/net/quic/test_tools/crypto_test_utils.cc +++ b/net/quic/test_tools/crypto_test_utils.cc @@ -100,6 +100,24 @@ void MovePackets(PacketSavingConnection* source_conn, } } +// HexChar parses |c| as a hex character. If valid, it sets |*value| to the +// value of the hex character and returns true. Otherwise it returns false. +bool HexChar(char c, uint8* value) { + if (c >= '0' && c <= '9') { + *value = c - '0'; + return true; + } + if (c >= 'a' && c <= 'f') { + *value = c - 'a'; + return true; + } + if (c >= 'A' && c <= 'F') { + *value = c - 'A'; + return true; + } + return false; +} + } // anonymous namespace CryptoTestUtils::FakeClientOptions::FakeClientOptions() @@ -107,29 +125,6 @@ CryptoTestUtils::FakeClientOptions::FakeClientOptions() } // static -void CryptoTestUtils::CommunicateHandshakeMessages( - PacketSavingConnection* a_conn, - QuicCryptoStream* a, - PacketSavingConnection* b_conn, - QuicCryptoStream* b) { - size_t a_i = 0, b_i = 0; - while (!a->handshake_confirmed()) { - ASSERT_GT(a_conn->packets_.size(), a_i); - LOG(INFO) << "Processing " << a_conn->packets_.size() - a_i - << " packets a->b"; - MovePackets(a_conn, &a_i, b, b_conn); - - ASSERT_GT(b_conn->packets_.size(), b_i); - LOG(INFO) << "Processing " << b_conn->packets_.size() - b_i - << " packets b->a"; - if (b_conn->packets_.size() - b_i == 2) { - LOG(INFO) << "here"; - } - MovePackets(b_conn, &b_i, a, a_conn); - } -} - -// static int CryptoTestUtils::HandshakeWithFakeServer( PacketSavingConnection* client_conn, QuicCryptoClientStream* client) { @@ -207,6 +202,29 @@ void CryptoTestUtils::SetupCryptoServerConfigForTest( } // static +void CryptoTestUtils::CommunicateHandshakeMessages( + PacketSavingConnection* a_conn, + QuicCryptoStream* a, + PacketSavingConnection* b_conn, + QuicCryptoStream* b) { + size_t a_i = 0, b_i = 0; + while (!a->handshake_confirmed()) { + ASSERT_GT(a_conn->packets_.size(), a_i); + LOG(INFO) << "Processing " << a_conn->packets_.size() - a_i + << " packets a->b"; + MovePackets(a_conn, &a_i, b, b_conn); + + ASSERT_GT(b_conn->packets_.size(), b_i); + LOG(INFO) << "Processing " << b_conn->packets_.size() - b_i + << " packets b->a"; + if (b_conn->packets_.size() - b_i == 2) { + LOG(INFO) << "here"; + } + MovePackets(b_conn, &b_i, a, a_conn); + } +} + +// static string CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage& message, QuicTag tag) { QuicTagValueMap::const_iterator it = message.tag_value_map().find(tag); @@ -364,5 +382,91 @@ void CryptoTestUtils::CompareClientAndServerKeys( client_forward_secure_decrypter_iv.data(), client_forward_secure_decrypter_iv.length()); } + +// static +QuicTag CryptoTestUtils::ParseTag(const char* tagstr) { + const size_t len = strlen(tagstr); + CHECK_NE(0u, len); + + QuicTag tag = 0; + + if (tagstr[0] == '#') { + CHECK_EQ(static_cast<size_t>(1 + 2*4), len); + tagstr++; + + for (size_t i = 0; i < 8; i++) { + tag <<= 4; + + uint8 v; + CHECK(HexChar(tagstr[i], &v)); + tag |= v; + } + + return tag; + } + + CHECK_LE(len, 4u); + for (size_t i = 0; i < 4; i++) { + tag >>= 8; + if (i < len) { + tag |= static_cast<uint32>(tagstr[i]) << 24; + } + } + + return tag; +} + +// static +CryptoHandshakeMessage CryptoTestUtils::Message(const char* message_tag, ...) { + va_list ap; + va_start(ap, message_tag); + + CryptoHandshakeMessage message = BuildMessage(message_tag, ap); + va_end(ap); + return message; +} + +// static +CryptoHandshakeMessage CryptoTestUtils::BuildMessage(const char* message_tag, + va_list ap) { + CryptoHandshakeMessage msg; + msg.set_tag(ParseTag(message_tag)); + + for (;;) { + const char* tagstr = va_arg(ap, const char*); + if (tagstr == NULL) { + break; + } + + const QuicTag tag = ParseTag(tagstr); + const char* valuestr = va_arg(ap, const char*); + + size_t len = strlen(valuestr); + if (len > 0 && valuestr[0] == '#') { + valuestr++; + len--; + + CHECK(len % 2 == 0); + scoped_ptr<uint8[]> buf(new uint8[len/2]); + + for (size_t i = 0; i < len/2; i++) { + uint8 v; + CHECK(HexChar(valuestr[i*2], &v)); + buf[i] = v << 4; + CHECK(HexChar(valuestr[i*2 + 1], &v)); + buf[i] |= v; + } + + msg.SetStringPiece( + tag, StringPiece(reinterpret_cast<char*>(buf.get()), len/2)); + continue; + } + + msg.SetStringPiece(tag, valuestr); + } + + return msg; +} + } // namespace test } // namespace net diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h index 3a4fdd4..b811d9f 100644 --- a/net/quic/test_tools/crypto_test_utils.h +++ b/net/quic/test_tools/crypto_test_utils.h @@ -5,6 +5,8 @@ #ifndef NET_QUIC_TEST_TOOLS_CRYPTO_TEST_UTILS_H_ #define NET_QUIC_TEST_TOOLS_CRYPTO_TEST_UTILS_H_ +#include <stdarg.h> + #include <vector> #include "base/logging.h" @@ -82,6 +84,32 @@ class CryptoTestUtils { uint64 hash, uint32 index); + // ParseTag returns a QuicTag from parsing |tagstr|. |tagstr| may either be + // in the format "EXMP" (i.e. ASCII format), or "#11223344" (an explicit hex + // format). It CHECK fails if there's a parse error. + static QuicTag ParseTag(const char* tagstr); + + // Message constructs a handshake message from a variable number of + // arguments. |message_tag| is passed to |ParseTag| and used as the tag of + // the resulting message. The arguments are taken in pairs and NULL + // terminated. The first of each pair is the tag of a tag/value and is given + // as an argument to |ParseTag|. The second is the value of the tag/value + // pair and is either a hex dump, preceeded by a '#', or a raw value. + // + // Message( + // "CHLO", + // "NOCE", "#11223344", + // "SNI", "www.example.com", + // NULL); + static CryptoHandshakeMessage Message(const char* message_tag, ...); + + // BuildMessage is the same as |Message|, but takes the variable arguments + // explicitly. TODO(rtenneti): Investigate whether it'd be better for + // Message() and BuildMessage() to return a CryptoHandshakeMessage* pointer + // instead, to avoid copying the return value. + static CryptoHandshakeMessage BuildMessage(const char* message_tag, + va_list ap); + private: static void CompareClientAndServerKeys(QuicCryptoClientStream* client, QuicCryptoServerStream* server); diff --git a/net/quic/test_tools/mock_random.cc b/net/quic/test_tools/mock_random.cc index a8b8956..19a2832 100644 --- a/net/quic/test_tools/mock_random.cc +++ b/net/quic/test_tools/mock_random.cc @@ -23,6 +23,9 @@ bool MockRandom::RandBool() { } void MockRandom::Reseed(const void* additional_entropy, size_t entropy_len) { +} + +void MockRandom::ChangeValue() { increment_++; } diff --git a/net/quic/test_tools/mock_random.h b/net/quic/test_tools/mock_random.h index 1278297..544f5ce 100644 --- a/net/quic/test_tools/mock_random.h +++ b/net/quic/test_tools/mock_random.h @@ -21,12 +21,14 @@ class MockRandom : public QuicRandom { virtual uint64 RandUint64() OVERRIDE; // Returns false. virtual bool RandBool() OVERRIDE; - // Reseed advances |increment_| which causes the value returned by - // |RandUint64| to increment and the byte that |RandBytes| fills with, to - // advance. + // Does nothing. virtual void Reseed(const void* additional_entropy, size_t entropy_len) OVERRIDE; + // ChangeValue increments |increment_|. This causes the value returned by + // |RandUint64| and the byte that |RandBytes| fills with, to change. + void ChangeValue(); + private: uint8 increment_; }; diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 01e9181..281dc4c 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc @@ -12,7 +12,7 @@ #include "base/threading/simple_thread.h" #include "net/base/ip_endpoint.h" // TODO(rtenneti): Delete this when NSS is supported. -#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/null_encrypter.h" #include "net/quic/quic_framer.h" #include "net/quic/quic_packet_creator.h" @@ -62,10 +62,11 @@ void GenerateBody(string* body, int length) { // Simple wrapper class to run server in a thread. class ServerThread : public base::SimpleThread { public: - explicit ServerThread(IPEndPoint address) + explicit ServerThread(IPEndPoint address, const QuicConfig& config) : SimpleThread("server_thread"), listening_(true, false), quit_(true, false), + server_(config), address_(address), port_(0) { } @@ -110,12 +111,13 @@ class ServerThread : public base::SimpleThread { class EndToEndTest : public ::testing::Test { protected: EndToEndTest() - : server_hostname_("localhost"), + : server_hostname_("example.com"), server_started_(false) { net::IPAddressNumber ip; CHECK(net::ParseIPLiteralToNumber("127.0.0.1", &ip)); server_address_ = IPEndPoint(ip, 0); - config_.SetDefaults(); + client_config_.SetDefaults(); + server_config_.SetDefaults(); AddToCache("GET", kLargeRequest, "HTTP/1.1", "200", "OK", kFooResponseBody); AddToCache("GET", "https://www.google.com/foo", @@ -131,7 +133,7 @@ class EndToEndTest : public ::testing::Test { virtual QuicTestClient* CreateQuicClient() { QuicTestClient* client = new QuicTestClient(server_address_, server_hostname_, - config_); + client_config_); client->Connect(); return client; } @@ -149,7 +151,7 @@ class EndToEndTest : public ::testing::Test { } void StartServer() { - server_thread_.reset(new ServerThread(server_address_)); + server_thread_.reset(new ServerThread(server_address_, server_config_)); server_thread_->Start(); server_thread_->listening()->Wait(); server_address_ = IPEndPoint(server_address_.address(), @@ -202,12 +204,13 @@ class EndToEndTest : public ::testing::Test { scoped_ptr<ServerThread> server_thread_; scoped_ptr<QuicTestClient> client_; bool server_started_; - QuicConfig config_; + QuicConfig client_config_; + QuicConfig server_config_; }; TEST_F(EndToEndTest, SimpleRequestResponse) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -220,7 +223,7 @@ TEST_F(EndToEndTest, SimpleRequestResponse) { TEST_F(EndToEndTest, SimpleRequestResponsev6) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -236,7 +239,7 @@ TEST_F(EndToEndTest, SimpleRequestResponsev6) { TEST_F(EndToEndTest, SeparateFinPacket) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -266,7 +269,7 @@ TEST_F(EndToEndTest, SeparateFinPacket) { TEST_F(EndToEndTest, MultipleRequestResponse) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -281,7 +284,7 @@ TEST_F(EndToEndTest, MultipleRequestResponse) { TEST_F(EndToEndTest, MultipleClients) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -310,7 +313,7 @@ TEST_F(EndToEndTest, MultipleClients) { TEST_F(EndToEndTest, RequestOverMultiplePackets) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -340,7 +343,7 @@ TEST_F(EndToEndTest, RequestOverMultiplePackets) { TEST_F(EndToEndTest, MultipleFramesRandomOrder) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -371,7 +374,7 @@ TEST_F(EndToEndTest, MultipleFramesRandomOrder) { TEST_F(EndToEndTest, PostMissingBytes) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -393,7 +396,7 @@ TEST_F(EndToEndTest, PostMissingBytes) { TEST_F(EndToEndTest, LargePost) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -413,7 +416,7 @@ TEST_F(EndToEndTest, LargePost) { TEST_F(EndToEndTest, LargePostFEC) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -451,7 +454,7 @@ TEST_F(EndToEndTest, LargePostFEC) { TEST_F(EndToEndTest, InvalidStream) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -475,7 +478,7 @@ TEST_F(EndToEndTest, InvalidStream) { TEST_F(EndToEndTest, MultipleTermination) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -509,8 +512,8 @@ TEST_F(EndToEndTest, MultipleTermination) { "Check failed: !fin_buffered_"); } -/*TEST_F(EndToEndTest, Timeout) { - config_.set_idle_connection_state_lifetime( +TEST_F(EndToEndTest, Timeout) { + client_config_.set_idle_connection_state_lifetime( QuicTime::Delta::FromMicroseconds(500), QuicTime::Delta::FromMicroseconds(500)); // Note: we do NOT ASSERT_TRUE: we may time out during initial handshake: @@ -519,11 +522,22 @@ TEST_F(EndToEndTest, MultipleTermination) { while (client_->client()->connected()) { client_->client()->WaitForEvents(); } -}*/ +} + +TEST_F(EndToEndTest, LimitMaxOpenStreams) { + // Server limits the number of max streams to 2. + server_config_.set_max_streams_per_connection(2, 2); + // Client tries to negotiate for 10. + client_config_.set_max_streams_per_connection(10, 5); + + ASSERT_TRUE(Initialize()); + QuicConfig* client_negotiated_config = client_->client()->session()->config(); + EXPECT_EQ(2u, client_negotiated_config->max_streams_per_connection()); +} TEST_F(EndToEndTest, ResetConnection) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } @@ -561,7 +575,7 @@ class WrongAddressWriter : public QuicPacketWriter { TEST_F(EndToEndTest, ConnectionMigration) { // TODO(rtenneti): Delete this when NSS is supported. - if (!Aes128GcmEncrypter::IsSupported()) { + if (!Aes128Gcm12Encrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; } diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc index 9ca70a3..e3edac5 100644 --- a/net/tools/quic/quic_client.cc +++ b/net/tools/quic/quic_client.cc @@ -57,8 +57,8 @@ QuicClient::QuicClient(IPEndPoint server_address, QuicClient::~QuicClient() { if (connected()) { - session()->connection() - ->SendConnectionClosePacket(QUIC_PEER_GOING_AWAY, std::string()); + session()->connection()->SendConnectionClosePacket( + QUIC_PEER_GOING_AWAY, string()); } } @@ -67,8 +67,8 @@ bool QuicClient::Initialize() { epoll_server_.set_timeout_in_us(50 * 1000); crypto_config_.SetDefaults(); - int address_family = server_address_.GetSockAddrFamily(); + int address_family = server_address_.GetSockAddrFamily(); fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); if (fd_ < 0) { LOG(ERROR) << "CreateSocket() failed: " << strerror(errno); diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc index 0b9603c..a1dbc16 100644 --- a/net/tools/quic/quic_client_session_test.cc +++ b/net/tools/quic/quic_client_session_test.cc @@ -7,6 +7,7 @@ #include <vector> #include "net/base/ip_endpoint.h" +#include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/tools/quic/quic_reliable_client_stream.h" @@ -48,10 +49,18 @@ class QuicClientSessionTest : public ::testing::Test { }; TEST_F(QuicClientSessionTest, CryptoConnect) { + if (!Aes128Gcm12Encrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } CompleteCryptoHandshake(); } TEST_F(QuicClientSessionTest, DISABLED_MaxNumConnections) { + if (!Aes128Gcm12Encrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } // FLAGS_max_streams_per_connection = 1; // Initialize crypto before the client session will create a stream. CompleteCryptoHandshake(); diff --git a/net/tools/quic/quic_reliable_client_stream_test.cc b/net/tools/quic/quic_reliable_client_stream_test.cc index 1f1eb54..af0ffd5 100644 --- a/net/tools/quic/quic_reliable_client_stream_test.cc +++ b/net/tools/quic/quic_reliable_client_stream_test.cc @@ -25,7 +25,7 @@ namespace { class QuicClientStreamTest : public ::testing::Test { public: QuicClientStreamTest() - : session_("localhost", QuicConfig(), + : session_("example.com", QuicConfig(), new MockConnection(1, IPEndPoint(), 0, &eps_, false), &crypto_config_), body_("hello world") { diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc index a92c4ba..adc2df1 100644 --- a/net/tools/quic/quic_server.cc +++ b/net/tools/quic/quic_server.cc @@ -40,12 +40,29 @@ QuicServer::QuicServer() overflow_supported_(false), use_recvmmsg_(false), crypto_config_(kSourceAddressTokenSecret) { + // Use hardcoded crypto parameters for now. + config_.SetDefaults(); + Initialize(); +} + +QuicServer::QuicServer(const QuicConfig& config) + : port_(0), + packets_dropped_(0), + overflow_supported_(false), + use_recvmmsg_(false), + config_(config), + crypto_config_(kSourceAddressTokenSecret) { + Initialize(); +} + +void QuicServer::Initialize() { +#if MMSG_MORE + use_recvmmsg_ = true; +#endif epoll_server_.set_timeout_in_us(50 * 1000); // Initialize the in memory cache now. QuicInMemoryCache::GetInstance(); - // Use hardcoded crypto parameters for now. - config_.SetDefaults(); QuicEpollClock clock(&epoll_server_); scoped_ptr<CryptoHandshakeMessage> scfg( @@ -123,7 +140,6 @@ bool QuicServer::Listen(const IPEndPoint& address) { } epoll_server_.RegisterFD(fd_, this, kEpollFlags); - dispatcher_.reset(new QuicDispatcher(config_, crypto_config_, fd_, &epoll_server_)); @@ -187,6 +203,11 @@ bool QuicServer::ReadAndDispatchSinglePacket(int fd, QuicEncryptedPacket packet(buf, bytes_read, false); QuicGuid guid; QuicDataReader reader(packet.data(), packet.length()); + uint8 public_flags; + if (!reader.ReadBytes(&public_flags, 1)) { + LOG(DFATAL) << "Unable to read public flags."; + return false; + } if (!reader.ReadUInt64(&guid)) { return true; // We read, we just didn't like the results. } diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h index 99a9d7f..6399566 100644 --- a/net/tools/quic/quic_server.h +++ b/net/tools/quic/quic_server.h @@ -27,6 +27,8 @@ class QuicDispatcher; class QuicServer : public EpollCallbackInterface { public: QuicServer(); + explicit QuicServer(const QuicConfig& config); + virtual ~QuicServer(); // Start listening on the specified address. @@ -64,6 +66,9 @@ class QuicServer : public EpollCallbackInterface { int port() { return port_; } private: + // Initialize the internal state of the server. + void Initialize(); + // Accepts data from the framer and demuxes clients to sessions. scoped_ptr<QuicDispatcher> dispatcher_; // Frames incoming packets and hands them to the dispatcher. |