summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/net.gyp26
-rw-r--r--net/quic/crypto/aes_128_gcm_12_decrypter.h (renamed from net/quic/crypto/aes_128_gcm_decrypter.h)25
-rw-r--r--net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc (renamed from net/quic/crypto/aes_128_gcm_decrypter_nss.cc)48
-rw-r--r--net/quic/crypto/aes_128_gcm_12_decrypter_openssl.cc (renamed from net/quic/crypto/aes_128_gcm_decrypter_openssl.cc)27
-rw-r--r--net/quic/crypto/aes_128_gcm_12_decrypter_test.cc (renamed from net/quic/crypto/aes_128_gcm_decrypter_test.cc)16
-rw-r--r--net/quic/crypto/aes_128_gcm_12_encrypter.h (renamed from net/quic/crypto/aes_128_gcm_encrypter.h)25
-rw-r--r--net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc (renamed from net/quic/crypto/aes_128_gcm_encrypter_nss.cc)47
-rw-r--r--net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc (renamed from net/quic/crypto/aes_128_gcm_encrypter_openssl.cc)35
-rw-r--r--net/quic/crypto/aes_128_gcm_12_encrypter_test.cc (renamed from net/quic/crypto/aes_128_gcm_encrypter_test.cc)37
-rw-r--r--net/quic/crypto/crypto_framer.cc91
-rw-r--r--net/quic/crypto/crypto_framer.h7
-rw-r--r--net/quic/crypto/crypto_framer_test.cc78
-rw-r--r--net/quic/crypto/crypto_handshake.cc48
-rw-r--r--net/quic/crypto/crypto_handshake.h19
-rw-r--r--net/quic/crypto/crypto_handshake_test.cc4
-rw-r--r--net/quic/crypto/crypto_protocol.h11
-rw-r--r--net/quic/crypto/crypto_server_config.cc32
-rw-r--r--net/quic/crypto/crypto_server_test.cc148
-rw-r--r--net/quic/crypto/crypto_utils.cc36
-rw-r--r--net/quic/crypto/crypto_utils.h12
-rw-r--r--net/quic/crypto/crypto_utils_test.cc49
-rw-r--r--net/quic/crypto/quic_decrypter.cc4
-rw-r--r--net/quic/crypto/quic_encrypter.cc4
-rw-r--r--net/quic/quic_client_session_test.cc8
-rw-r--r--net/quic/quic_connection.cc92
-rw-r--r--net/quic/quic_connection.h5
-rw-r--r--net/quic/quic_connection_test.cc14
-rw-r--r--net/quic/quic_crypto_client_stream_test.cc56
-rw-r--r--net/quic/quic_crypto_server_stream.cc1
-rw-r--r--net/quic/quic_crypto_server_stream_test.cc16
-rw-r--r--net/quic/quic_data_writer.cc12
-rw-r--r--net/quic/quic_data_writer.h1
-rw-r--r--net/quic/quic_framer.cc46
-rw-r--r--net/quic/quic_framer_test.cc211
-rw-r--r--net/quic/quic_packet_creator_test.cc2
-rw-r--r--net/quic/quic_protocol.cc4
-rw-r--r--net/quic/quic_protocol.h6
-rw-r--r--net/quic/quic_session.h2
-rw-r--r--net/quic/quic_utils.cc11
-rw-r--r--net/quic/quic_utils.h3
-rw-r--r--net/quic/test_tools/crypto_test_utils.cc150
-rw-r--r--net/quic/test_tools/crypto_test_utils.h28
-rw-r--r--net/quic/test_tools/mock_random.cc3
-rw-r--r--net/quic/test_tools/mock_random.h8
-rw-r--r--net/tools/quic/end_to_end_test.cc62
-rw-r--r--net/tools/quic/quic_client.cc6
-rw-r--r--net/tools/quic/quic_client_session_test.cc9
-rw-r--r--net/tools/quic/quic_reliable_client_stream_test.cc2
-rw-r--r--net/tools/quic/quic_server.cc27
-rw-r--r--net/tools/quic/quic_server.h5
50 files changed, 1184 insertions, 435 deletions
diff --git a/net/net.gyp b/net/net.gyp
index f7f5b1d..9eb53fd 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -708,12 +708,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',
@@ -1175,8 +1175,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',
@@ -1207,8 +1207,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',
@@ -1643,12 +1643,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_, &params_, &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_, &params_, &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..40a61a4 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 = 0;
+ 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 = 0;
+ 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.