summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-23 23:17:18 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-23 23:17:18 +0000
commit1354bf6e1de7b7025fbec462eaf214985f502222 (patch)
tree1446a1bfe026b30692125634bfdd2dcb224df08f
parent4fa66a47e8be08a10a88e4b4bbecc237778f3da2 (diff)
downloadchromium_src-1354bf6e1de7b7025fbec462eaf214985f502222.zip
chromium_src-1354bf6e1de7b7025fbec462eaf214985f502222.tar.gz
chromium_src-1354bf6e1de7b7025fbec462eaf214985f502222.tar.bz2
Land Recent QUIC changes.
Blacklisting PCI domains for quic such that we won't even complete the crypto handshake for those domains on port 443. Merge internal change: 46392850 Dont retransmit packets which are NULL encrypted when encryption level is FORWARD_SECURE. This solves a bug when the client kept retrying to send a retransmitted CHLO which the server kept dropping. Merge internal change: 46380016 QUIC: various cleanups. * The AES code no longer does key expansion for every packet. * The CryptoFramer now actually calls Visitor::OnError. Merge internal change: 46227160 QUIC: add a CryptSecretBoxer object for server-internal needs Quic[En|De]crypter isn't actually thread-safe. I thought that it was because we were doing the key schedule every time, but it subtly isn't because the nonce is stored in the object, not on the stack. With cl/46095856 (not yet landed) I changed the AES-GCM encrypter/decrypter to really be non-thread-safe, which seemed fine because it wasn't previously either, but then I recalled that the server code was assuming otherwise. Initially I tried adding a thread-safe wrapper that could use thread-local storage on the server side and just locks in Chrome. That's done in cl/46136485 which is alternative to this CL. However, after writing it, it seemed that it might be easier just to have a thread-safe boxer, since this is internal to the server, and be done with it. At the same time we can also solve the short-nonce worry with the existing, AES-GCM based boxer. Merge internal change: 46226208 For chromimum: Used sha256 to compute the hash of nonce and plaintext and stored it at the end of Box message. In Unbox, verified the sha256 hash stored in the ciphertext, matches the sha256 hash of nonce and plaintext in the ciphertext. TODO: Use Aes128Gcm12[En|De]crypter instead of sha256. QUIC - updated the comment in NormalizeHostname to say "stopping at the first trailing dot." QUIC - moved destructor to out of line. Merging cleanup changes from chromium - CL 14718011 Merge internal change: 46099778 Adding infrastructure to blacklist domains for QUIC Merge internal change: 46093221 Changing to be aware of variable length guids, but not yet support reading, writing, or negotiating non-8 byte guids. Merge internal change: 46050640 QUIC: invalidate validity when server config changes. When writing cl/44509151 I started by altering SetServerConfig but changed my mind and split SetProof from SetServerConfig. I used git to revert the changes to SetProof to avoid diff noise, but failed to add back the important change: the validity flag needs to be cleared when the proof is set. I will be wearing a brown paper bag for the rest of the day. Merge internal change: 46050043 R=rch@chromium.org Review URL: https://chromiumcodereview.appspot.com/15910002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@201925 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/net.gyp5
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc1
-rw-r--r--net/quic/crypto/aes_128_gcm_12_decrypter.h15
-rw-r--r--net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc22
-rw-r--r--net/quic/crypto/aes_128_gcm_12_decrypter_openssl.cc68
-rw-r--r--net/quic/crypto/aes_128_gcm_12_encrypter.h15
-rw-r--r--net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc26
-rw-r--r--net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc68
-rw-r--r--net/quic/crypto/cert_compressor.cc49
-rw-r--r--net/quic/crypto/common_cert_set.cc6
-rw-r--r--net/quic/crypto/crypto_framer.cc163
-rw-r--r--net/quic/crypto/crypto_framer.h6
-rw-r--r--net/quic/crypto/crypto_framer_test.cc6
-rw-r--r--net/quic/crypto/crypto_handshake.cc5
-rw-r--r--net/quic/crypto/crypto_secret_boxer.cc90
-rw-r--r--net/quic/crypto/crypto_secret_boxer.h49
-rw-r--r--net/quic/crypto/crypto_secret_boxer_test.cc41
-rw-r--r--net/quic/crypto/crypto_server_config.cc71
-rw-r--r--net/quic/crypto/crypto_server_config.h8
-rw-r--r--net/quic/crypto/crypto_utils.cc2
-rw-r--r--net/quic/crypto/scoped_evp_cipher_ctx.cc22
-rw-r--r--net/quic/crypto/scoped_evp_cipher_ctx.h16
-rw-r--r--net/quic/crypto/source_address_token.cc4
-rw-r--r--net/quic/crypto/source_address_token.h2
-rw-r--r--net/quic/quic_connection.cc53
-rw-r--r--net/quic/quic_connection.h19
-rw-r--r--net/quic/quic_connection_test.cc43
-rw-r--r--net/quic/quic_crypto_server_stream.cc22
-rw-r--r--net/quic/quic_crypto_server_stream.h8
-rw-r--r--net/quic/quic_framer.cc19
-rw-r--r--net/quic/quic_framer.h2
-rw-r--r--net/quic/quic_framer_test.cc168
-rw-r--r--net/quic/quic_packet_generator_test.cc3
-rw-r--r--net/quic/quic_protocol.h11
-rw-r--r--net/quic/quic_session.cc28
-rw-r--r--net/quic/quic_utils.cc1
-rw-r--r--net/tools/quic/quic_client.h7
-rw-r--r--net/tools/quic/quic_dispatcher.cc7
-rw-r--r--net/tools/quic/quic_server_session.cc14
-rw-r--r--net/tools/quic/quic_server_session.h11
-rw-r--r--net/tools/quic/test_tools/quic_test_client.cc14
41 files changed, 793 insertions, 397 deletions
diff --git a/net/net.gyp b/net/net.gyp
index 9eb53fd..29f1473 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -723,6 +723,8 @@
'quic/crypto/crypto_handshake.cc',
'quic/crypto/crypto_handshake.h',
'quic/crypto/crypto_protocol.h',
+ 'quic/crypto/crypto_secret_boxer.cc',
+ 'quic/crypto/crypto_secret_boxer.h',
'quic/crypto/crypto_server_config.cc',
'quic/crypto/crypto_server_config.h',
'quic/crypto/crypto_server_config_protobuf.cc',
@@ -747,6 +749,7 @@
'quic/crypto/quic_encrypter.h',
'quic/crypto/quic_random.cc',
'quic/crypto/quic_random.h',
+ 'quic/crypto/scoped_evp_cipher_ctx.cc',
'quic/crypto/scoped_evp_cipher_ctx.h',
'quic/crypto/strike_register.cc',
'quic/crypto/strike_register.h',
@@ -1210,6 +1213,7 @@
'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.cc',
'quic/crypto/scoped_evp_cipher_ctx.h',
'socket/ssl_client_socket_openssl.cc',
'socket/ssl_client_socket_openssl.h',
@@ -1649,6 +1653,7 @@
'quic/crypto/common_cert_set_test.cc',
'quic/crypto/crypto_framer_test.cc',
'quic/crypto/crypto_handshake_test.cc',
+ 'quic/crypto/crypto_secret_boxer_test.cc',
'quic/crypto/crypto_server_test.cc',
'quic/crypto/crypto_utils_test.cc',
'quic/crypto/curve25519_key_exchange_test.cc',
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index e6ed9d3..78bd7d9 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -228,7 +228,6 @@ void TcpCubicSender::AckAccounting(QuicTime::Delta rtt) {
}
hybrid_slow_start_.Update(rtt, delay_min_);
if (hybrid_slow_start_.Exit()) {
- DLOG(INFO) << "Set slowstart threshold:" << congestion_window_;
slowstart_threshold_ = congestion_window_;
}
}
diff --git a/net/quic/crypto/aes_128_gcm_12_decrypter.h b/net/quic/crypto/aes_128_gcm_12_decrypter.h
index 0a066659..5dc12c8 100644
--- a/net/quic/crypto/aes_128_gcm_12_decrypter.h
+++ b/net/quic/crypto/aes_128_gcm_12_decrypter.h
@@ -10,6 +10,10 @@
#include "base/compiler_specific.h"
#include "net/quic/crypto/quic_decrypter.h"
+#if defined(USE_OPENSSL)
+#include "net/quic/crypto/scoped_evp_cipher_ctx.h"
+#endif
+
namespace net {
namespace test {
@@ -30,7 +34,7 @@ class NET_EXPORT_PRIVATE Aes128Gcm12Decrypter : public QuicDecrypter {
};
Aes128Gcm12Decrypter();
- virtual ~Aes128Gcm12Decrypter() {}
+ virtual ~Aes128Gcm12Decrypter();
// Returns true if the underlying crypto library supports AES GCM.
static bool IsSupported();
@@ -52,9 +56,12 @@ class NET_EXPORT_PRIVATE Aes128Gcm12Decrypter : public QuicDecrypter {
private:
// The 128-bit AES key.
unsigned char key_[16];
- // The nonce, a concatenation of a four-byte fixed prefix and a 8-byte
- // packet sequence number.
- unsigned char nonce_[12];
+ // The nonce prefix.
+ unsigned char nonce_prefix_[4];
+
+#if defined(USE_OPENSSL)
+ ScopedEVPCipherCtx ctx_;
+#endif
};
} // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc b/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc
index c2a9788..e3fc1b6 100644
--- a/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc
+++ b/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc
@@ -106,6 +106,7 @@ base::LazyInstance<GcmSupportChecker>::Leaky g_gcm_support_checker =
const size_t kKeySize = 16;
const size_t kNoncePrefixSize = 4;
+const size_t kAESNonceSize = 12;
// Calls PK11_Decrypt if it's available. Otherwise, emulates CKM_AES_GCM using
// CKM_AES_CTR and the GaloisHash class.
@@ -254,6 +255,8 @@ Aes128Gcm12Decrypter::Aes128Gcm12Decrypter() {
ignore_result(g_gcm_support_checker.Get());
}
+Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {}
+
// static
bool Aes128Gcm12Decrypter::IsSupported() {
// NSS 3.15 supports CKM_AES_GCM directly.
@@ -276,14 +279,15 @@ bool Aes128Gcm12Decrypter::SetNoncePrefix(StringPiece nonce_prefix) {
if (nonce_prefix.size() != kNoncePrefixSize) {
return false;
}
- memcpy(nonce_, nonce_prefix.data(), nonce_prefix.size());
+ COMPILE_ASSERT(sizeof(nonce_prefix_) == kNoncePrefixSize, bad_nonce_length);
+ memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
return true;
}
bool Aes128Gcm12Decrypter::Decrypt(StringPiece nonce,
StringPiece associated_data,
StringPiece ciphertext,
- unsigned char* output,
+ uint8* output,
size_t* output_length) {
if (ciphertext.length() < kAuthTagSize ||
nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) {
@@ -352,18 +356,19 @@ QuicData* Aes128Gcm12Decrypter::DecryptPacket(
QuicPacketSequenceNumber sequence_number,
StringPiece associated_data,
StringPiece ciphertext) {
- COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
- incorrect_nonce_size);
if (ciphertext.length() < kAuthTagSize) {
return NULL;
}
size_t plaintext_size;
scoped_ptr<char[]> plaintext(new char[ciphertext.length()]);
- memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
- if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)),
+ uint8 nonce[kNoncePrefixSize + sizeof(sequence_number)];
+ COMPILE_ASSERT(sizeof(nonce) == kAESNonceSize, bad_sequence_number_size);
+ memcpy(nonce, nonce_prefix_, kNoncePrefixSize);
+ memcpy(nonce + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
+ if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce), sizeof(nonce)),
associated_data, ciphertext,
- reinterpret_cast<unsigned char*>(plaintext.get()),
+ reinterpret_cast<uint8*>(plaintext.get()),
&plaintext_size)) {
return NULL;
}
@@ -375,7 +380,8 @@ StringPiece Aes128Gcm12Decrypter::GetKey() const {
}
StringPiece Aes128Gcm12Decrypter::GetNoncePrefix() const {
- return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize);
+ return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
+ kNoncePrefixSize);
}
} // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_12_decrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_12_decrypter_openssl.cc
index cf0f5c5..cbc7a84 100644
--- a/net/quic/crypto/aes_128_gcm_12_decrypter_openssl.cc
+++ b/net/quic/crypto/aes_128_gcm_12_decrypter_openssl.cc
@@ -7,7 +7,6 @@
#include <openssl/evp.h>
#include "base/memory/scoped_ptr.h"
-#include "net/quic/crypto/scoped_evp_cipher_ctx.h"
using base::StringPiece;
@@ -17,11 +16,14 @@ namespace {
const size_t kKeySize = 16;
const size_t kNoncePrefixSize = 4;
+const size_t kAESNonceSize = 12;
} // namespace
Aes128Gcm12Decrypter::Aes128Gcm12Decrypter() {}
+Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {}
+
// static
bool Aes128Gcm12Decrypter::IsSupported() { return true; }
@@ -31,6 +33,19 @@ bool Aes128Gcm12Decrypter::SetKey(StringPiece key) {
return false;
}
memcpy(key_, key.data(), key.size());
+
+ // Set the cipher type and the key.
+ if (EVP_EncryptInit_ex(ctx_.get(), EVP_aes_128_gcm(), NULL, key_,
+ NULL) == 0) {
+ return false;
+ }
+
+ // Set the IV (nonce) length.
+ if (EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_GCM_SET_IVLEN, kAESNonceSize,
+ NULL) == 0) {
+ return false;
+ }
+
return true;
}
@@ -39,45 +54,32 @@ bool Aes128Gcm12Decrypter::SetNoncePrefix(StringPiece nonce_prefix) {
if (nonce_prefix.size() != kNoncePrefixSize) {
return false;
}
- memcpy(nonce_, nonce_prefix.data(), nonce_prefix.size());
+ COMPILE_ASSERT(sizeof(nonce_prefix_) == kNoncePrefixSize, bad_nonce_length);
+ memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
return true;
}
bool Aes128Gcm12Decrypter::Decrypt(StringPiece nonce,
StringPiece associated_data,
StringPiece ciphertext,
- unsigned char* output,
+ uint8* output,
size_t* output_length) {
if (ciphertext.length() < kAuthTagSize ||
nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) {
return false;
}
const size_t plaintext_size = ciphertext.length() - kAuthTagSize;
- // |len| is passed to an OpenSSL function to receive the output length.
- int len;
-
- ScopedEVPCipherCtx ctx;
-
- // Set the cipher type and the key. The IV (nonce) is set below.
- if (EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_gcm(), NULL, key_, NULL) == 0) {
- return false;
- }
- // Set the IV (nonce) length.
- if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, nonce.size(),
- NULL) == 0) {
- return false;
- }
// Set the IV (nonce).
if (EVP_DecryptInit_ex(
- ctx.get(), NULL, NULL, NULL,
- reinterpret_cast<const unsigned char*>(nonce.data())) == 0) {
+ ctx_.get(), NULL, NULL, NULL,
+ reinterpret_cast<const uint8*>(nonce.data())) == 0) {
return false;
}
// Set the authentication tag.
if (EVP_CIPHER_CTX_ctrl(
- ctx.get(), EVP_CTRL_GCM_SET_TAG, kAuthTagSize,
+ ctx_.get(), EVP_CTRL_GCM_SET_TAG, kAuthTagSize,
const_cast<char*>(ciphertext.data()) + plaintext_size) == 0) {
return false;
}
@@ -87,23 +89,25 @@ bool Aes128Gcm12Decrypter::Decrypt(StringPiece nonce,
if (!associated_data.empty()) {
// Set the associated data. The second argument (output buffer) must be
// NULL.
+ int unused_len;
if (EVP_DecryptUpdate(
- ctx.get(), NULL, &len,
- reinterpret_cast<const unsigned char*>(associated_data.data()),
+ ctx_.get(), NULL, &unused_len,
+ reinterpret_cast<const uint8*>(associated_data.data()),
associated_data.size()) == 0) {
return false;
}
}
+ int len;
if (EVP_DecryptUpdate(
- ctx.get(), output, &len,
- reinterpret_cast<const unsigned char*>(ciphertext.data()),
+ ctx_.get(), output, &len,
+ reinterpret_cast<const uint8*>(ciphertext.data()),
plaintext_size) == 0) {
return false;
}
output += len;
- if (EVP_DecryptFinal_ex(ctx.get(), output, &len) == 0) {
+ if (EVP_DecryptFinal_ex(ctx_.get(), output, &len) == 0) {
return false;
}
output += len;
@@ -117,18 +121,19 @@ QuicData* Aes128Gcm12Decrypter::DecryptPacket(
QuicPacketSequenceNumber sequence_number,
StringPiece associated_data,
StringPiece ciphertext) {
- COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
- incorrect_nonce_size);
if (ciphertext.length() < kAuthTagSize) {
return NULL;
}
size_t plaintext_size;
scoped_ptr<char[]> plaintext(new char[ciphertext.length()]);
- memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
- if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)),
+ uint8 nonce[kNoncePrefixSize + sizeof(sequence_number)];
+ COMPILE_ASSERT(sizeof(nonce) == kAESNonceSize, bad_sequence_number_size);
+ memcpy(nonce, nonce_prefix_, kNoncePrefixSize);
+ memcpy(nonce + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
+ if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce), sizeof(nonce)),
associated_data, ciphertext,
- reinterpret_cast<unsigned char*>(plaintext.get()),
+ reinterpret_cast<uint8*>(plaintext.get()),
&plaintext_size)) {
return NULL;
}
@@ -140,7 +145,8 @@ StringPiece Aes128Gcm12Decrypter::GetKey() const {
}
StringPiece Aes128Gcm12Decrypter::GetNoncePrefix() const {
- return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize);
+ return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
+ kNoncePrefixSize);
}
} // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter.h b/net/quic/crypto/aes_128_gcm_12_encrypter.h
index b8380c7..ca9a2b1 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter.h
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter.h
@@ -10,6 +10,10 @@
#include "base/compiler_specific.h"
#include "net/quic/crypto/quic_encrypter.h"
+#if defined(USE_OPENSSL)
+#include "net/quic/crypto/scoped_evp_cipher_ctx.h"
+#endif
+
namespace net {
namespace test {
@@ -30,7 +34,7 @@ class NET_EXPORT_PRIVATE Aes128Gcm12Encrypter : public QuicEncrypter {
};
Aes128Gcm12Encrypter();
- virtual ~Aes128Gcm12Encrypter() {}
+ virtual ~Aes128Gcm12Encrypter();
// Returns true if the underlying crypto library supports AES GCM.
static bool IsSupported();
@@ -55,9 +59,12 @@ class NET_EXPORT_PRIVATE Aes128Gcm12Encrypter : public QuicEncrypter {
private:
// The 128-bit AES key.
unsigned char key_[16];
- // The nonce, a concatenation of a four-byte fixed prefix and a 8-byte
- // packet sequence number.
- unsigned char nonce_[12];
+ // The nonce prefix.
+ unsigned char nonce_prefix_[4];
+
+#if defined(USE_OPENSSL)
+ ScopedEVPCipherCtx ctx_;
+#endif
};
} // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
index 9084b7c..4729ef8 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
@@ -106,6 +106,7 @@ base::LazyInstance<GcmSupportChecker>::Leaky g_gcm_support_checker =
const size_t kKeySize = 16;
const size_t kNoncePrefixSize = 4;
+const size_t kAESNonceSize = 12;
// Calls PK11_Encrypt if it's available. Otherwise, emulates CKM_AES_GCM using
// CKM_AES_CTR and the GaloisHash class.
@@ -253,6 +254,8 @@ Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() {
ignore_result(g_gcm_support_checker.Get());
}
+Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {}
+
// static
bool Aes128Gcm12Encrypter::IsSupported() {
// NSS 3.15 supports CKM_AES_GCM directly.
@@ -275,7 +278,8 @@ bool Aes128Gcm12Encrypter::SetNoncePrefix(StringPiece nonce_prefix) {
if (nonce_prefix.size() != kNoncePrefixSize) {
return false;
}
- memcpy(nonce_, nonce_prefix.data(), nonce_prefix.size());
+ COMPILE_ASSERT(sizeof(nonce_prefix_) == kNoncePrefixSize, bad_nonce_length);
+ memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
return true;
}
@@ -343,24 +347,23 @@ QuicData* Aes128Gcm12Encrypter::EncryptPacket(
QuicPacketSequenceNumber sequence_number,
StringPiece associated_data,
StringPiece plaintext) {
- COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
- incorrect_nonce_size);
- memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
-
size_t ciphertext_size = GetCiphertextSize(plaintext.length());
scoped_ptr<char[]> ciphertext(new char[ciphertext_size]);
- if (!Encrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)),
+ uint8 nonce[kNoncePrefixSize + sizeof(sequence_number)];
+ COMPILE_ASSERT(sizeof(nonce) == kAESNonceSize, bad_sequence_number_size);
+ memcpy(nonce, nonce_prefix_, kNoncePrefixSize);
+ memcpy(nonce + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
+ if (!Encrypt(StringPiece(reinterpret_cast<char*>(nonce), sizeof(nonce)),
associated_data, plaintext,
reinterpret_cast<unsigned char*>(ciphertext.get()))) {
return NULL;
}
+
return new QuicData(ciphertext.release(), ciphertext_size, true);
}
-size_t Aes128Gcm12Encrypter::GetKeySize() const {
- return kKeySize;
-}
+size_t Aes128Gcm12Encrypter::GetKeySize() const { return kKeySize; }
size_t Aes128Gcm12Encrypter::GetNoncePrefixSize() const {
return kNoncePrefixSize;
@@ -370,7 +373,7 @@ 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 Aes128Gcm12Encrypter::GetCiphertextSize(size_t plaintext_size) const {
return plaintext_size + kAuthTagSize;
@@ -381,7 +384,8 @@ StringPiece Aes128Gcm12Encrypter::GetKey() const {
}
StringPiece Aes128Gcm12Encrypter::GetNoncePrefix() const {
- return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize);
+ return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
+ kNoncePrefixSize);
}
} // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc
index 7481184..c32efcf 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc
@@ -8,7 +8,6 @@
#include <string.h>
#include "base/memory/scoped_ptr.h"
-#include "net/quic/crypto/scoped_evp_cipher_ctx.h"
using base::StringPiece;
@@ -18,11 +17,13 @@ namespace {
const size_t kKeySize = 16;
const size_t kNoncePrefixSize = 4;
+const size_t kAESNonceSize = 12;
} // namespace
-Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() {
-}
+Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() {}
+
+Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {}
// static
bool Aes128Gcm12Encrypter::IsSupported() { return true; }
@@ -33,6 +34,19 @@ bool Aes128Gcm12Encrypter::SetKey(StringPiece key) {
return false;
}
memcpy(key_, key.data(), key.size());
+
+ // Set the cipher type and the key.
+ if (EVP_EncryptInit_ex(ctx_.get(), EVP_aes_128_gcm(), NULL, key_,
+ NULL) == 0) {
+ return false;
+ }
+
+ // Set the IV (nonce) length.
+ if (EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_GCM_SET_IVLEN, kAESNonceSize,
+ NULL) == 0) {
+ return false;
+ }
+
return true;
}
@@ -41,7 +55,8 @@ bool Aes128Gcm12Encrypter::SetNoncePrefix(StringPiece nonce_prefix) {
if (nonce_prefix.size() != kNoncePrefixSize) {
return false;
}
- memcpy(nonce_, nonce_prefix.data(), nonce_prefix.size());
+ COMPILE_ASSERT(sizeof(nonce_prefix_) == kNoncePrefixSize, bad_nonce_length);
+ memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
return true;
}
@@ -49,29 +64,13 @@ 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;
-
if (nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) {
return false;
}
- ScopedEVPCipherCtx ctx;
-
- // Set the cipher type and the key. The IV (nonce) is set below.
- if (EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_gcm(), NULL, key_, NULL) == 0) {
- return false;
- }
-
- // Set the IV (nonce) length.
- if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, nonce.size(),
- NULL) == 0) {
- return false;
- }
// Set the IV (nonce).
if (EVP_EncryptInit_ex(
- ctx.get(), NULL, NULL, NULL,
+ ctx_.get(), NULL, NULL, NULL,
reinterpret_cast<const unsigned char*>(nonce.data())) == 0) {
return false;
}
@@ -81,28 +80,30 @@ bool Aes128Gcm12Encrypter::Encrypt(StringPiece nonce,
if (!associated_data.empty()) {
// Set the associated data. The second argument (output buffer) must be
// NULL.
+ int unused_len;
if (EVP_EncryptUpdate(
- ctx.get(), NULL, &output_len,
+ ctx_.get(), NULL, &unused_len,
reinterpret_cast<const unsigned char*>(associated_data.data()),
associated_data.size()) == 0) {
return false;
}
}
+ int len;
if (EVP_EncryptUpdate(
- ctx.get(), output, &output_len,
+ ctx_.get(), output, &len,
reinterpret_cast<const unsigned char*>(plaintext.data()),
plaintext.size()) == 0) {
return false;
}
- output += output_len;
+ output += len;
- if (EVP_EncryptFinal_ex(ctx.get(), output, &output_len) == 0) {
+ if (EVP_EncryptFinal_ex(ctx_.get(), output, &len) == 0) {
return false;
}
- output += output_len;
+ output += len;
- if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kAuthTagSize,
+ if (EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_GCM_GET_TAG, kAuthTagSize,
output) == 0) {
return false;
}
@@ -114,14 +115,14 @@ QuicData* Aes128Gcm12Encrypter::EncryptPacket(
QuicPacketSequenceNumber sequence_number,
StringPiece associated_data,
StringPiece plaintext) {
- COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
- incorrect_nonce_size);
- memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
-
size_t ciphertext_size = GetCiphertextSize(plaintext.length());
scoped_ptr<char[]> ciphertext(new char[ciphertext_size]);
- if (!Encrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)),
+ uint8 nonce[kNoncePrefixSize + sizeof(sequence_number)];
+ COMPILE_ASSERT(sizeof(nonce) == kAESNonceSize, bad_sequence_number_size);
+ memcpy(nonce, nonce_prefix_, kNoncePrefixSize);
+ memcpy(nonce + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
+ if (!Encrypt(StringPiece(reinterpret_cast<char*>(nonce), sizeof(nonce)),
associated_data, plaintext,
reinterpret_cast<unsigned char*>(ciphertext.get()))) {
return NULL;
@@ -151,7 +152,8 @@ StringPiece Aes128Gcm12Encrypter::GetKey() const {
}
StringPiece Aes128Gcm12Encrypter::GetNoncePrefix() const {
- return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize);
+ return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
+ kNoncePrefixSize);
}
} // namespace net
diff --git a/net/quic/crypto/cert_compressor.cc b/net/quic/crypto/cert_compressor.cc
index 58d259a..023701b 100644
--- a/net/quic/crypto/cert_compressor.cc
+++ b/net/quic/crypto/cert_compressor.cc
@@ -152,6 +152,8 @@ static const unsigned char kCommonCertSubstrings[] = {
struct CertEntry {
public:
enum Type {
+ // Type 0 is reserved to mean "end of list" in the wire format.
+
// COMPRESSED means that the certificate is included in the trailing zlib
// data.
COMPRESSED = 1,
@@ -235,15 +237,15 @@ size_t CertEntriesSize(const vector<CertEntry>& entries) {
for (vector<CertEntry>::const_iterator i = entries.begin();
i != entries.end(); ++i) {
+ entries_size++;
switch (i->type) {
case CertEntry::COMPRESSED:
- entries_size++;
break;
case CertEntry::CACHED:
- entries_size += 1 + sizeof(uint64);
+ entries_size += sizeof(uint64);
break;
case CertEntry::COMMON:
- entries_size += 1 + sizeof(uint64) + sizeof(uint32);
+ entries_size += sizeof(uint64) + sizeof(uint32);
break;
}
}
@@ -317,6 +319,7 @@ string ZlibDictForEntries(const vector<CertEntry>& entries,
// HashCerts returns the FNV-1a hashes of |certs|.
vector<uint64> HashCerts(const vector<string>& certs) {
vector<uint64> ret;
+ ret.reserve(certs.size());
for (vector<string>::const_iterator i = certs.begin();
i != certs.end(); ++i) {
@@ -386,15 +389,11 @@ bool ParseEntries(StringPiece* in_out,
if (!common_sets) {
return false;
}
- if (in.size() < sizeof(uint64)) {
+ if (in.size() < sizeof(uint64) + sizeof(uint32)) {
return false;
}
memcpy(&entry.set_hash, in.data(), sizeof(uint64));
in.remove_prefix(sizeof(uint64));
-
- if (in.size() < sizeof(uint32)) {
- return false;
- }
memcpy(&entry.index, in.data(), sizeof(uint32));
in.remove_prefix(sizeof(uint32));
@@ -415,6 +414,7 @@ bool ParseEntries(StringPiece* in_out,
return true;
}
+// ScopedZLib deals with the automatic destruction of a zlib context.
class ScopedZLib {
public:
enum Type {
@@ -424,20 +424,29 @@ class ScopedZLib {
explicit ScopedZLib(Type type) : z_(NULL), type_(type) {}
- void reset(z_stream* z) { z_ = z; }
+ void reset(z_stream* z) {
+ Clear();
+ z_ = z;
+ }
~ScopedZLib() {
- if (z_) {
- if (type_ == DEFLATE) {
- deflateEnd(z_);
- } else {
- inflateEnd(z_);
- }
- z_ = NULL;
- }
+ Clear();
}
private:
+ void Clear() {
+ if (!z_) {
+ return;
+ }
+
+ if (type_ == DEFLATE) {
+ deflateEnd(z_);
+ } else {
+ inflateEnd(z_);
+ }
+ z_ = NULL;
+ }
+
z_stream* z_;
const Type type_;
};
@@ -514,9 +523,9 @@ string CertCompressor::CompressChain(const vector<string>& certs,
continue;
}
- uint32 length = certs[i].size();
- z.next_in = reinterpret_cast<uint8*>(&length);
- z.avail_in = sizeof(length);
+ uint32 length32 = certs[i].size();
+ z.next_in = reinterpret_cast<uint8*>(&length32);
+ z.avail_in = sizeof(length32);
rv = deflate(&z, Z_NO_FLUSH);
DCHECK_EQ(Z_OK, rv);
DCHECK_EQ(0u, z.avail_in);
diff --git a/net/quic/crypto/common_cert_set.cc b/net/quic/crypto/common_cert_set.cc
index ee1ac67..01a54ce 100644
--- a/net/quic/crypto/common_cert_set.cc
+++ b/net/quic/crypto/common_cert_set.cc
@@ -53,17 +53,17 @@ StringPiece CommonCertSetsQUIC::GetCommonHashes() const {
}
StringPiece CommonCertSetsQUIC::GetCert(uint64 hash, uint32 index) const {
- StringPiece cert;
for (size_t i = 0; i < arraysize(kSets); i++) {
if (kSets[i].hash == hash) {
if (index < kSets[i].num_certs) {
- cert.set(kSets[i].certs[index], kSets[i].lens[index]);
+ return StringPiece(reinterpret_cast<const char*>(kSets[i].certs[index]),
+ kSets[i].lens[index]);
}
break;
}
}
- return cert;
+ return StringPiece();
}
// Compare returns a value less than, equal to or greater than zero if |a| is
diff --git a/net/quic/crypto/crypto_framer.cc b/net/quic/crypto/crypto_framer.cc
index 6307d82..dd5d24f 100644
--- a/net/quic/crypto/crypto_framer.cc
+++ b/net/quic/crypto/crypto_framer.cc
@@ -20,7 +20,6 @@ namespace {
const size_t kQuicTagSize = sizeof(uint32);
const size_t kCryptoEndOffsetSize = sizeof(uint32);
const size_t kNumEntriesSize = sizeof(uint16);
-const size_t kValueLenSize = sizeof(uint16);
// OneShotVisitor is a framer visitor that records a single handshake message.
class OneShotVisitor : public CryptoFramerVisitorInterface {
@@ -75,85 +74,12 @@ bool CryptoFramer::ProcessInput(StringPiece input) {
if (error_ != QUIC_NO_ERROR) {
return false;
}
- // Add this data to the buffer.
- buffer_.append(input.data(), input.length());
- QuicDataReader reader(buffer_.data(), buffer_.length());
-
- switch (state_) {
- case STATE_READING_TAG:
- if (reader.BytesRemaining() < kQuicTagSize) {
- break;
- }
- QuicTag message_tag;
- reader.ReadUInt32(&message_tag);
- message_.set_tag(message_tag);
- state_ = STATE_READING_NUM_ENTRIES;
- case STATE_READING_NUM_ENTRIES:
- if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16)) {
- break;
- }
- reader.ReadUInt16(&num_entries_);
- if (num_entries_ > kMaxEntries) {
- error_ = QUIC_CRYPTO_TOO_MANY_ENTRIES;
- return false;
- }
- uint16 padding;
- reader.ReadUInt16(&padding);
-
- tags_and_lengths_.reserve(num_entries_);
- state_ = STATE_READING_TAGS_AND_LENGTHS;
- values_len_ = 0;
- case STATE_READING_TAGS_AND_LENGTHS: {
- if (reader.BytesRemaining() <
- num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) {
- break;
- }
-
- uint32 last_end_offset = 0;
- for (unsigned i = 0; i < num_entries_; ++i) {
- QuicTag tag;
- reader.ReadUInt32(&tag);
- if (i > 0 && tag <= tags_and_lengths_[i-1].first) {
- if (tag == tags_and_lengths_[i-1].first) {
- error_ = QUIC_CRYPTO_DUPLICATE_TAG;
- } else {
- error_ = QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
- }
- return false;
- }
-
- uint32 end_offset;
- reader.ReadUInt32(&end_offset);
-
- if (end_offset < last_end_offset) {
- error_ = QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
- return false;
- }
- tags_and_lengths_.push_back(
- make_pair(tag, static_cast<size_t>(end_offset - last_end_offset)));
- last_end_offset = end_offset;
- }
- values_len_ = last_end_offset;
- state_ = STATE_READING_VALUES;
- }
- case STATE_READING_VALUES:
- if (reader.BytesRemaining() < values_len_) {
- break;
- }
- for (vector<pair<QuicTag, size_t> >::const_iterator
- it = tags_and_lengths_.begin(); it != tags_and_lengths_.end();
- it++) {
- StringPiece value;
- reader.ReadStringPiece(&value, it->second);
- message_.SetStringPiece(it->first, value);
- }
- visitor_->OnHandshakeMessage(message_);
- Clear();
- state_ = STATE_READING_TAG;
- break;
+ error_ = Process(input);
+ if (error_ != QUIC_NO_ERROR) {
+ visitor_->OnError(this);
+ return false;
}
- // Save any remaining data.
- buffer_ = reader.PeekRemainingPayload().as_string();
+
return true;
}
@@ -268,6 +194,85 @@ void CryptoFramer::Clear() {
state_ = STATE_READING_TAG;
}
+QuicErrorCode CryptoFramer::Process(StringPiece input) {
+ // Add this data to the buffer.
+ buffer_.append(input.data(), input.length());
+ QuicDataReader reader(buffer_.data(), buffer_.length());
+
+ switch (state_) {
+ case STATE_READING_TAG:
+ if (reader.BytesRemaining() < kQuicTagSize) {
+ break;
+ }
+ QuicTag message_tag;
+ reader.ReadUInt32(&message_tag);
+ message_.set_tag(message_tag);
+ state_ = STATE_READING_NUM_ENTRIES;
+ case STATE_READING_NUM_ENTRIES:
+ if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16)) {
+ break;
+ }
+ reader.ReadUInt16(&num_entries_);
+ if (num_entries_ > kMaxEntries) {
+ return QUIC_CRYPTO_TOO_MANY_ENTRIES;
+ }
+ uint16 padding;
+ reader.ReadUInt16(&padding);
+
+ tags_and_lengths_.reserve(num_entries_);
+ state_ = STATE_READING_TAGS_AND_LENGTHS;
+ values_len_ = 0;
+ case STATE_READING_TAGS_AND_LENGTHS: {
+ if (reader.BytesRemaining() <
+ num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) {
+ break;
+ }
+
+ uint32 last_end_offset = 0;
+ for (unsigned i = 0; i < num_entries_; ++i) {
+ QuicTag tag;
+ reader.ReadUInt32(&tag);
+ if (i > 0 && tag <= tags_and_lengths_[i-1].first) {
+ if (tag == tags_and_lengths_[i-1].first) {
+ return QUIC_CRYPTO_DUPLICATE_TAG;
+ }
+ return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
+ }
+
+ uint32 end_offset;
+ reader.ReadUInt32(&end_offset);
+
+ if (end_offset < last_end_offset) {
+ return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
+ }
+ tags_and_lengths_.push_back(
+ make_pair(tag, static_cast<size_t>(end_offset - last_end_offset)));
+ last_end_offset = end_offset;
+ }
+ values_len_ = last_end_offset;
+ state_ = STATE_READING_VALUES;
+ }
+ case STATE_READING_VALUES:
+ if (reader.BytesRemaining() < values_len_) {
+ break;
+ }
+ for (vector<pair<QuicTag, size_t> >::const_iterator
+ it = tags_and_lengths_.begin(); it != tags_and_lengths_.end();
+ it++) {
+ StringPiece value;
+ reader.ReadStringPiece(&value, it->second);
+ message_.SetStringPiece(it->first, value);
+ }
+ visitor_->OnHandshakeMessage(message_);
+ Clear();
+ state_ = STATE_READING_TAG;
+ break;
+ }
+ // Save any remaining data.
+ buffer_ = reader.PeekRemainingPayload().as_string();
+ return QUIC_NO_ERROR;
+}
+
// static
bool CryptoFramer::WritePadTag(QuicDataWriter* writer,
size_t pad_length,
diff --git a/net/quic/crypto/crypto_framer.h b/net/quic/crypto/crypto_framer.h
index ad1768d..b070c66 100644
--- a/net/quic/crypto/crypto_framer.h
+++ b/net/quic/crypto/crypto_framer.h
@@ -59,7 +59,7 @@ class NET_EXPORT_PRIVATE CryptoFramer {
QuicErrorCode error() const { return error_; }
- // Processes input data, which must be delivered in order. Returns
+ // Processes input data, which must be delivered in order. Returns
// false if there was an error, and true otherwise.
bool ProcessInput(base::StringPiece input);
@@ -76,6 +76,10 @@ class NET_EXPORT_PRIVATE CryptoFramer {
// Clears per-message state. Does not clear the visitor.
void Clear();
+ // Process does does the work of |ProcessInput|, but returns an error code,
+ // doesn't set error_ and doesn't call |visitor_->OnError()|.
+ QuicErrorCode Process(base::StringPiece input);
+
static bool WritePadTag(QuicDataWriter* writer,
size_t pad_length,
uint32* end_offset);
diff --git a/net/quic/crypto/crypto_framer_test.cc b/net/quic/crypto/crypto_framer_test.cc
index f33c6c7..4486f59 100644
--- a/net/quic/crypto/crypto_framer_test.cc
+++ b/net/quic/crypto/crypto_framer_test.cc
@@ -280,6 +280,7 @@ TEST(CryptoFramerTest, ProcessInput) {
EXPECT_TRUE(
framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
EXPECT_EQ(0u, framer.InputBytesRemaining());
+ EXPECT_EQ(0, visitor.error_count_);
ASSERT_EQ(1u, visitor.messages_.size());
const CryptoHandshakeMessage& message = visitor.messages_[0];
EXPECT_EQ(0xFFAA7733, message.tag());
@@ -326,6 +327,7 @@ TEST(CryptoFramerTest, ProcessInputWithThreeKeys) {
EXPECT_TRUE(
framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
EXPECT_EQ(0u, framer.InputBytesRemaining());
+ EXPECT_EQ(0, visitor.error_count_);
ASSERT_EQ(1u, visitor.messages_.size());
const CryptoHandshakeMessage& message = visitor.messages_[0];
EXPECT_EQ(0xFFAA7733, message.tag());
@@ -400,6 +402,7 @@ TEST(CryptoFramerTest, ProcessInputTagsOutOfOrder) {
EXPECT_FALSE(
framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
+ EXPECT_EQ(1, visitor.error_count_);
}
TEST(CryptoFramerTest, ProcessEndOffsetsOutOfOrder) {
@@ -427,6 +430,7 @@ TEST(CryptoFramerTest, ProcessEndOffsetsOutOfOrder) {
EXPECT_FALSE(
framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
+ EXPECT_EQ(1, visitor.error_count_);
}
TEST(CryptoFramerTest, ProcessInputTooManyEntries) {
@@ -446,6 +450,7 @@ TEST(CryptoFramerTest, ProcessInputTooManyEntries) {
EXPECT_FALSE(
framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
EXPECT_EQ(QUIC_CRYPTO_TOO_MANY_ENTRIES, framer.error());
+ EXPECT_EQ(1, visitor.error_count_);
}
TEST(CryptoFramerTest, ProcessInputZeroLength) {
@@ -472,6 +477,7 @@ TEST(CryptoFramerTest, ProcessInputZeroLength) {
EXPECT_TRUE(
framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
+ EXPECT_EQ(0, visitor.error_count_);
}
} // namespace test
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
index db66f4b..445361a 100644
--- a/net/quic/crypto/crypto_handshake.cc
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -371,11 +371,16 @@ QuicCryptoClientConfig::CachedState::GetServerConfig() const {
}
bool QuicCryptoClientConfig::CachedState::SetServerConfig(StringPiece scfg) {
+ if (scfg == server_config_) {
+ return true;
+ }
+
scfg_.reset(CryptoFramer::ParseMessage(scfg));
if (!scfg_.get()) {
return false;
}
server_config_ = scfg.as_string();
+ server_config_valid_ = false;
return true;
}
diff --git a/net/quic/crypto/crypto_secret_boxer.cc b/net/quic/crypto/crypto_secret_boxer.cc
new file mode 100644
index 0000000..73562c6
--- /dev/null
+++ b/net/quic/crypto/crypto_secret_boxer.cc
@@ -0,0 +1,90 @@
+// 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_secret_boxer.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
+#include "net/quic/crypto/quic_random.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+// Defined kKeySize for GetKeySize() and SetKey().
+static const size_t kKeySize = 16;
+
+// kBoxNonceSize contains the number of bytes of nonce that we use in each box.
+static const size_t kBoxNonceSize = 16;
+
+// static
+size_t CryptoSecretBoxer::GetKeySize() { return kKeySize; }
+
+void CryptoSecretBoxer::SetKey(StringPiece key) {
+ DCHECK_EQ(static_cast<size_t>(kKeySize), key.size());
+ key_ = key.as_string();
+}
+
+// TODO(rtenneti): Delete sha256 based code. Use Aes128Gcm12Encrypter to Box the
+// plaintext. This is temporary solution for tests to pass.
+string CryptoSecretBoxer::Box(QuicRandom* rand, StringPiece plaintext) const {
+ string ret;
+ const size_t len = kBoxNonceSize + plaintext.size() + crypto::kSHA256Length;
+ ret.resize(len);
+ char* data = &ret[0];
+
+ // Generate nonce.
+ rand->RandBytes(data, kBoxNonceSize);
+ memcpy(data + kBoxNonceSize, plaintext.data(), plaintext.size());
+
+ // Compute sha256 for nonce + plaintext.
+ scoped_ptr<crypto::SecureHash> sha256(crypto::SecureHash::Create(
+ crypto::SecureHash::SHA256));
+ sha256->Update(data, kBoxNonceSize + plaintext.size());
+ sha256->Finish(data + kBoxNonceSize + plaintext.size(),
+ crypto::kSHA256Length);
+
+ return ret;
+}
+
+// TODO(rtenneti): Delete sha256 based code. Use Aes128Gcm12Decrypter to Unbox
+// the plaintext. This is temporary solution for tests to pass.
+bool CryptoSecretBoxer::Unbox(StringPiece ciphertext,
+ string* out_storage,
+ StringPiece* out) const {
+ if (ciphertext.size() < kBoxNonceSize + crypto::kSHA256Length) {
+ return false;
+ }
+
+ const size_t plaintext_len =
+ ciphertext.size() - kBoxNonceSize - crypto::kSHA256Length;
+ out_storage->resize(plaintext_len);
+ char* data = const_cast<char*>(out_storage->data());
+
+ // Copy plaintext from ciphertext.
+ if (plaintext_len != 0) {
+ memcpy(data, ciphertext.data() + kBoxNonceSize, plaintext_len);
+ }
+
+ // Compute sha256 for nonce + plaintext.
+ scoped_ptr<crypto::SecureHash> sha256(crypto::SecureHash::Create(
+ crypto::SecureHash::SHA256));
+ sha256->Update(ciphertext.data(), ciphertext.size() - crypto::kSHA256Length);
+ char sha256_bytes[crypto::kSHA256Length];
+ sha256->Finish(sha256_bytes, sizeof(sha256_bytes));
+
+ // Verify sha256.
+ if (0 != memcmp(ciphertext.data() + ciphertext.size() - crypto::kSHA256Length,
+ sha256_bytes, crypto::kSHA256Length)) {
+ return false;
+ }
+
+ out->set(data, plaintext_len);
+ return true;
+}
+
+} // namespace net
diff --git a/net/quic/crypto/crypto_secret_boxer.h b/net/quic/crypto/crypto_secret_boxer.h
new file mode 100644
index 0000000..ba9baf2
--- /dev/null
+++ b/net/quic/crypto/crypto_secret_boxer.h
@@ -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.
+
+#ifndef NET_QUIC_CRYPTO_CRYPTO_SECRET_BOXER_H_
+#define NET_QUIC_CRYPTO_CRYPTO_SECRET_BOXER_H_
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+class QuicRandom;
+
+// CryptoSecretBoxer encrypts small chunks of plaintext (called 'boxing') and
+// then, later, can authenticate+decrypt the resulting boxes. This object is
+// thread-safe.
+class NET_EXPORT_PRIVATE CryptoSecretBoxer {
+ public:
+ // GetKeySize returns the number of bytes in a key.
+ static size_t GetKeySize();
+
+ // SetKey sets the key for this object. This must be done before |Box| or
+ // |Unbox| are called. |key| must be |GetKeySize()| bytes long.
+ void SetKey(base::StringPiece key);
+
+ // Box encrypts |plaintext| using a random nonce generated from |rand| and
+ // returns the resulting ciphertext. Since an authenticator and nonce are
+ // included, the result will be slightly larger than |plaintext|.
+ std::string Box(QuicRandom* rand, base::StringPiece plaintext) const;
+
+ // Unbox takes the result of a previous call to |Box| in |ciphertext| and
+ // authenticates+decrypts it. If |ciphertext| is not authentic then it
+ // returns false. Otherwise, |out_storage| is used to store the result and
+ // |out| is set to point into |out_storage| and contains the original
+ // plaintext.
+ bool Unbox(base::StringPiece ciphertext,
+ std::string* out_storage,
+ base::StringPiece* out) const;
+
+ private:
+ std::string key_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CRYPTO_SECRET_BOXER_H_
diff --git a/net/quic/crypto/crypto_secret_boxer_test.cc b/net/quic/crypto/crypto_secret_boxer_test.cc
new file mode 100644
index 0000000..11797c3
--- /dev/null
+++ b/net/quic/crypto/crypto_secret_boxer_test.cc
@@ -0,0 +1,41 @@
+// 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_secret_boxer.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/crypto/quic_random.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+namespace test {
+
+TEST(CryptoSecretBoxerTest, BoxAndUnbox) {
+ StringPiece message("hello world");
+ const size_t key_size = CryptoSecretBoxer::GetKeySize();
+ scoped_ptr<uint8[]> key(new uint8[key_size]);
+ memset(key.get(), 0x11, key_size);
+
+ CryptoSecretBoxer boxer;
+ boxer.SetKey(StringPiece(reinterpret_cast<char*>(key.get()), key_size));
+
+ const string box = boxer.Box(QuicRandom::GetInstance(), message);
+
+ string storage;
+ StringPiece result;
+ EXPECT_TRUE(boxer.Unbox(box, &storage, &result));
+ EXPECT_EQ(result, message);
+
+ EXPECT_FALSE(boxer.Unbox(string(1, 'X') + box, &storage, &result));
+ EXPECT_FALSE(boxer.Unbox(box.substr(1, string::npos), &storage, &result));
+ EXPECT_FALSE(boxer.Unbox(string(), &storage, &result));
+ EXPECT_FALSE(boxer.Unbox(string(1, 'X') + box.substr(1, string::npos),
+ &storage, &result));
+}
+
+} // namespace test
+} // namespace net
diff --git a/net/quic/crypto/crypto_server_config.cc b/net/quic/crypto/crypto_server_config.cc
index d766c20..1b5ce76 100644
--- a/net/quic/crypto/crypto_server_config.cc
+++ b/net/quic/crypto/crypto_server_config.cc
@@ -42,29 +42,16 @@ const char QuicCryptoServerConfig::TESTING[] = "secret string for testing";
QuicCryptoServerConfig::QuicCryptoServerConfig(
StringPiece source_address_token_secret)
- // AES-GCM is used to encrypt and authenticate source address tokens. The
- // full, 96-bit nonce is used but we must ensure that an attacker cannot
- // obtain two source address tokens with the same nonce. This occurs with
- // probability 0.5 after 2**48 values. We assume that obtaining 2**48
- // source address tokens is not possible: at a rate of 10M packets per
- // second, it would still take the attacker a year to obtain the needed
- // number of packets.
- //
- // TODO(agl): switch to an encrypter with a larger nonce space (i.e.
- // Salsa20+Poly1305).
: strike_register_lock_(),
- 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),
source_address_token_lifetime_secs_(86400) {
crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */,
"QUIC source address token key",
- source_address_token_encrypter_->GetKeySize(),
+ CryptoSecretBoxer::GetKeySize(),
0 /* no fixed IV needed */);
- source_address_token_encrypter_->SetKey(hkdf.server_write_key());
- source_address_token_decrypter_->SetKey(hkdf.server_write_key());
+ source_address_token_boxer_.SetKey(hkdf.server_write_key());
}
QuicCryptoServerConfig::~QuicCryptoServerConfig() {
@@ -573,63 +560,23 @@ string QuicCryptoServerConfig::NewSourceAddressToken(
source_address_token.set_ip(ip.ToString());
source_address_token.set_timestamp(now.ToUNIXSeconds());
- string plaintext = source_address_token.SerializeAsString();
- char nonce[12];
- DCHECK_EQ(sizeof(nonce),
- source_address_token_encrypter_->GetNoncePrefixSize() +
- sizeof(QuicPacketSequenceNumber));
- rand->RandBytes(nonce, sizeof(nonce));
-
- size_t ciphertext_size =
- source_address_token_encrypter_->GetCiphertextSize(plaintext.size());
- string result;
- result.resize(sizeof(nonce) + ciphertext_size);
- memcpy(&result[0], &nonce, sizeof(nonce));
-
- if (!source_address_token_encrypter_->Encrypt(
- StringPiece(nonce, sizeof(nonce)), StringPiece(), plaintext,
- reinterpret_cast<unsigned char*>(&result[sizeof(nonce)]))) {
- DCHECK(false);
- return string();
- }
-
- return result;
+ return source_address_token_boxer_.Box(
+ rand, source_address_token.SerializeAsString());
}
bool QuicCryptoServerConfig::ValidateSourceAddressToken(
StringPiece token,
const IPEndPoint& ip,
QuicWallTime now) const {
- char nonce[12];
- DCHECK_EQ(sizeof(nonce),
- source_address_token_encrypter_->GetNoncePrefixSize() +
- sizeof(QuicPacketSequenceNumber));
-
- if (token.size() <= sizeof(nonce)) {
- return false;
- }
- memcpy(&nonce, token.data(), sizeof(nonce));
- token.remove_prefix(sizeof(nonce));
-
- unsigned char plaintext_stack[128];
- scoped_ptr<unsigned char[]> plaintext_heap;
- unsigned char* plaintext;
- if (token.size() <= sizeof(plaintext_stack)) {
- plaintext = plaintext_stack;
- } else {
- plaintext_heap.reset(new unsigned char[token.size()]);
- plaintext = plaintext_heap.get();
- }
- size_t plaintext_length;
-
- if (!source_address_token_decrypter_->Decrypt(
- StringPiece(nonce, sizeof(nonce)), StringPiece(), token, plaintext,
- &plaintext_length)) {
+ string storage;
+ StringPiece plaintext;
+ if (!source_address_token_boxer_.Unbox(token, &storage, &plaintext)) {
return false;
}
SourceAddressToken source_address_token;
- if (!source_address_token.ParseFromArray(plaintext, plaintext_length)) {
+ if (!source_address_token.ParseFromArray(plaintext.data(),
+ plaintext.size())) {
return false;
}
diff --git a/net/quic/crypto/crypto_server_config.h b/net/quic/crypto/crypto_server_config.h
index 5c7d4da..ed64ee3 100644
--- a/net/quic/crypto/crypto_server_config.h
+++ b/net/quic/crypto/crypto_server_config.h
@@ -12,6 +12,7 @@
#include "net/base/net_export.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/crypto_protocol.h"
+#include "net/quic/crypto/crypto_secret_boxer.h"
#include "net/quic/quic_time.h"
namespace net {
@@ -184,10 +185,9 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// observed client nonces in order to prevent replay attacks.
mutable scoped_ptr<StrikeRegister> strike_register_;
- // These members are used to encrypt and decrypt the source address tokens
- // that we receive from and send to clients.
- scoped_ptr<QuicEncrypter> source_address_token_encrypter_;
- scoped_ptr<QuicDecrypter> source_address_token_decrypter_;
+ // source_address_token_boxer_ is used to protect the source-address tokens
+ // that are given to clients.
+ CryptoSecretBoxer source_address_token_boxer_;
// proof_source_ contains an object that can provide certificate chains and
// signatures.
diff --git a/net/quic/crypto/crypto_utils.cc b/net/quic/crypto/crypto_utils.cc
index a5bed6a..89ce4b4 100644
--- a/net/quic/crypto/crypto_utils.cc
+++ b/net/quic/crypto/crypto_utils.cc
@@ -63,7 +63,7 @@ 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.
+ // Walk backwards over the string, stopping at the first trailing dot.
size_t host_end = host.length();
while (host_end != 0 && host[host_end - 1] == '.') {
host_end--;
diff --git a/net/quic/crypto/scoped_evp_cipher_ctx.cc b/net/quic/crypto/scoped_evp_cipher_ctx.cc
new file mode 100644
index 0000000..b904f87
--- /dev/null
+++ b/net/quic/crypto/scoped_evp_cipher_ctx.cc
@@ -0,0 +1,22 @@
+// 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/scoped_evp_cipher_ctx.h"
+
+#include <openssl/evp.h>
+
+namespace net {
+
+ScopedEVPCipherCtx::ScopedEVPCipherCtx()
+ : ctx_(EVP_CIPHER_CTX_new()) { }
+
+ScopedEVPCipherCtx::~ScopedEVPCipherCtx() {
+ EVP_CIPHER_CTX_free(ctx_);
+}
+
+EVP_CIPHER_CTX* ScopedEVPCipherCtx::get() const {
+ return ctx_;
+}
+
+} // namespace net
diff --git a/net/quic/crypto/scoped_evp_cipher_ctx.h b/net/quic/crypto/scoped_evp_cipher_ctx.h
index 8741c3e..ec0fd51 100644
--- a/net/quic/crypto/scoped_evp_cipher_ctx.h
+++ b/net/quic/crypto/scoped_evp_cipher_ctx.h
@@ -5,9 +5,7 @@
#ifndef NET_QUIC_CRYPTO_SCOPED_EVP_CIPHER_CTX_H_
#define NET_QUIC_CRYPTO_SCOPED_EVP_CIPHER_CTX_H_
-#include <openssl/evp.h>
-
-#include "base/logging.h"
+typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
namespace net {
@@ -18,17 +16,13 @@ namespace net {
// functions.
class ScopedEVPCipherCtx {
public:
- ScopedEVPCipherCtx() { EVP_CIPHER_CTX_init(&ctx_); }
-
- ~ScopedEVPCipherCtx() {
- int rv = EVP_CIPHER_CTX_cleanup(&ctx_);
- DCHECK_EQ(rv, 1);
- }
+ ScopedEVPCipherCtx();
+ ~ScopedEVPCipherCtx();
- EVP_CIPHER_CTX* get() { return &ctx_; }
+ EVP_CIPHER_CTX* get() const;
private:
- EVP_CIPHER_CTX ctx_;
+ EVP_CIPHER_CTX* const ctx_;
};
} // namespace net
diff --git a/net/quic/crypto/source_address_token.cc b/net/quic/crypto/source_address_token.cc
index d664a08..d15afeb 100644
--- a/net/quic/crypto/source_address_token.cc
+++ b/net/quic/crypto/source_address_token.cc
@@ -24,9 +24,9 @@ string SourceAddressToken::SerializeAsString() const {
return ip_ + " " + base::Int64ToString(timestamp_);
}
-bool SourceAddressToken::ParseFromArray(unsigned char* plaintext,
+bool SourceAddressToken::ParseFromArray(const char* plaintext,
size_t plaintext_length) {
- string data(reinterpret_cast<const char*>(plaintext), plaintext_length);
+ string data(plaintext, plaintext_length);
vector<string> results;
base::SplitString(data, ' ', &results);
if (results.size() < 2) {
diff --git a/net/quic/crypto/source_address_token.h b/net/quic/crypto/source_address_token.h
index 5f8388b..8c50965 100644
--- a/net/quic/crypto/source_address_token.h
+++ b/net/quic/crypto/source_address_token.h
@@ -20,7 +20,7 @@ class SourceAddressToken {
std::string SerializeAsString() const;
- bool ParseFromArray(unsigned char* plaintext, size_t plaintext_length);
+ bool ParseFromArray(const char* plaintext, size_t plaintext_length);
std::string ip() const {
return ip_;
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index e75bc1a7..be0c1eb 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -241,7 +241,7 @@ void QuicConnection::OnVersionNegotiationPacket(
}
version_negotiation_state_ = NEGOTIATED_VERSION;
- RetransmitAllUnackedPackets();
+ RetransmitUnackedPackets(ALL_PACKETS);
}
void QuicConnection::OnRevivedPacket() {
@@ -591,7 +591,8 @@ bool QuicConnection::OnConnectionCloseFrame(
debug_visitor_->OnConnectionCloseFrame(frame);
}
DLOG(INFO) << ENDPOINT << "Connection closed with error "
- << QuicUtils::ErrorToString(frame.error_code);
+ << QuicUtils::ErrorToString(frame.error_code)
+ << " " << frame.error_details;
CloseConnection(frame.error_code, true);
return false;
}
@@ -863,10 +864,23 @@ bool QuicConnection::MaybeRetransmitPacketForRTO(
}
}
-void QuicConnection::RetransmitAllUnackedPackets() {
- for (UnackedPacketMap::iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it) {
- RetransmitPacket(it->first);
+void QuicConnection::RetransmitUnackedPackets(
+ RetransmissionType retransmission_type) {
+ UnackedPacketMap::iterator current_it = unacked_packets_.begin();
+ UnackedPacketMap::iterator next_it;
+ while (current_it != unacked_packets_.end()) {
+ next_it = current_it;
+ ++next_it;
+
+ if (retransmission_type != INITIAL_ENCRYPTION_ONLY ||
+ current_it->second->encryption_level() == ENCRYPTION_INITIAL) {
+ // TODO(satyamshekhar): Think about congestion control here.
+ // Specifically, about the retransmission count of packets being sent
+ // proactively to achieve 0 (minimal) RTT.
+ RetransmitPacket(current_it->first);
+ }
+
+ current_it = next_it;
}
}
@@ -886,6 +900,7 @@ void QuicConnection::RetransmitPacket(
// TODO(pwestin): Need to fix potential issue with FEC and a 1 packet
// congestion window see b/8331807 for details.
congestion_manager_.AbandoningPacket(sequence_number);
+
// TODO(ianswett): Never change the sequence number of the connect packet.
// Re-packetize the frames with a new sequence number for retransmission.
// Retransmitted data packets do not use FEC, even when it's enabled.
@@ -969,6 +984,21 @@ void QuicConnection::MaybeSetupRetransmission(
// SendStreamData().
}
+void QuicConnection::DropPacket(QuicPacketSequenceNumber sequence_number) {
+ UnackedPacketMap::iterator unacked_it =
+ unacked_packets_.find(sequence_number);
+ // Packet was not meant to be retransmitted.
+ if (unacked_it == unacked_packets_.end()) {
+ DCHECK(!ContainsKey(retransmission_map_, sequence_number));
+ return;
+ }
+ // Delete the unacked packet.
+ delete unacked_it->second;
+ unacked_packets_.erase(unacked_it);
+ retransmission_map_.erase(sequence_number);
+ return;
+}
+
bool QuicConnection::WritePacket(EncryptionLevel level,
QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
@@ -983,6 +1013,17 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
return true;
}
+ if (encryption_level_ == ENCRYPTION_FORWARD_SECURE &&
+ level == ENCRYPTION_NONE) {
+ // Drop packets that are NULL encrypted since the peer won't accept them
+ // anymore.
+ DLOG(INFO) << ENDPOINT << "Dropped packet: " << sequence_number
+ << " since the packet is NULL encrypted.";
+ DropPacket(sequence_number);
+ delete packet;
+ return true;
+ }
+
Retransmission retransmission = IsRetransmission(sequence_number) ?
IS_RETRANSMISSION : NOT_RETRANSMISSION;
// If we are not forced and we can't write, then simply return false;
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index f3096ad..773de2a 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -202,6 +202,11 @@ class NET_EXPORT_PRIVATE QuicConnection
FORCE
};
+ enum RetransmissionType {
+ INITIAL_ENCRYPTION_ONLY,
+ ALL_PACKETS
+ };
+
// Constructs a new QuicConnection for the specified |guid| and |address|.
// |helper| will be owned by this connection.
QuicConnection(QuicGuid guid,
@@ -350,6 +355,13 @@ class NET_EXPORT_PRIVATE QuicConnection
// should next fire, or 0 if no retransmission alarm should be set.
QuicTime OnRetransmissionTimeout();
+ // Retransmits unacked packets which were sent with initial encryption, if
+ // |initial_encryption_only| is true, otherwise retransmits all unacked
+ // packets. Used when the negotiated protocol version is different than what
+ // was initially assumed and when the visitor wants to re-transmit packets
+ // with initial encryption when the initial encrypter changes.
+ void RetransmitUnackedPackets(RetransmissionType retransmission_type);
+
// Changes the encrypter used for level |level| to |encrypter|. The function
// takes ownership of |encrypter|.
void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
@@ -494,7 +506,12 @@ class NET_EXPORT_PRIVATE QuicConnection
void MaybeSetupRetransmission(QuicPacketSequenceNumber sequence_number);
bool IsRetransmission(QuicPacketSequenceNumber sequence_number);
- void RetransmitAllUnackedPackets();
+
+ // Drop packet corresponding to |sequence_number| by deleting entries from
+ // |unacked_packets_| and |retransmission_map_|, if present. We need to drop
+ // all packets with encryption level NONE after the default level has been set
+ // to FORWARD_SECURE.
+ void DropPacket(QuicPacketSequenceNumber sequence_number);
// Writes as many queued packets as possible. The connection must not be
// blocked when this is called.
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index cf28e46..bee2781 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -1370,6 +1370,49 @@ TEST_F(QuicConnectionTest, RetransmitWithSameEncryptionLevel) {
EXPECT_EQ(0x02020202u, final_bytes_of_last_packet());
}
+TEST_F(QuicConnectionTest,
+ DropRetransmitsForNullEncryptedPacketAfterForwardSecure) {
+ use_tagging_decrypter();
+ connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
+ QuicPacketSequenceNumber sequence_number;
+ SendStreamDataToPeer(1, "foo", 0, !kFin, &sequence_number);
+
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ new TaggingEncrypter(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(0);
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(sequence_number, _)).Times(1);
+
+ const QuicTime::Delta kDefaultRetransmissionTime =
+ QuicTime::Delta::FromMilliseconds(500);
+ QuicTime default_retransmission_time = clock_.ApproximateNow().Add(
+ kDefaultRetransmissionTime);
+
+ EXPECT_EQ(default_retransmission_time, helper_->retransmission_alarm());
+ // Simulate the retransimission alarm firing
+ clock_.AdvanceTime(kDefaultRetransmissionTime);
+ connection_.OnRetransmissionTimeout();
+}
+
+TEST_F(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
+ use_tagging_decrypter();
+ connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_NONE);
+
+ SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
+
+ connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+
+ SendStreamDataToPeer(2, "bar", 0, !kFin, NULL);
+
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(1);
+
+ connection_.RetransmitUnackedPackets(QuicConnection::INITIAL_ENCRYPTION_ONLY);
+}
+
TEST_F(QuicConnectionTest, TestRetransmitOrder) {
QuicByteCount first_packet_size;
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce(
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 6aef276..9b0d989 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -38,12 +38,9 @@ void QuicCryptoServerStream::OnHandshakeMessage(
string error_details;
CryptoHandshakeMessage reply;
- QuicErrorCode error = crypto_config_.ProcessClientHello(
- message, session()->connection()->guid(),
- session()->connection()->peer_address(),
- session()->connection()->clock(),
- session()->connection()->random_generator(),
- &crypto_negotiated_params_, &reply, &error_details);
+
+ QuicErrorCode error = ProcessClientHello(message, &reply, &error_details);
+
if (error != QUIC_NO_ERROR) {
CloseConnectionWithDetails(error, error_details);
return;
@@ -94,4 +91,17 @@ void QuicCryptoServerStream::OnHandshakeMessage(
session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
}
+QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
+ const CryptoHandshakeMessage& message,
+ CryptoHandshakeMessage* reply,
+ string* error_details) {
+ return crypto_config_.ProcessClientHello(
+ message,
+ session()->connection()->guid(),
+ session()->connection()->peer_address(),
+ session()->connection()->clock(),
+ session()->connection()->random_generator(),
+ &crypto_negotiated_params_, reply, error_details);
+}
+
} // namespace net
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index 1c7ac06..7287659 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -32,6 +32,14 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
virtual void OnHandshakeMessage(
const CryptoHandshakeMessage& message) OVERRIDE;
+ protected:
+ virtual QuicErrorCode ProcessClientHello(
+ const CryptoHandshakeMessage& message,
+ CryptoHandshakeMessage* reply,
+ string* error_details);
+
+ const QuicCryptoServerConfig* crypto_config() { return &crypto_config_; }
+
private:
friend class test::CryptoTestUtils;
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index e900e2c..deb55e6 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -276,7 +276,8 @@ QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket(
size_t len = GetPublicResetPacketSize();
QuicDataWriter writer(len);
- uint8 flags = static_cast<uint8>(PACKET_PUBLIC_FLAGS_RST);
+ uint8 flags = static_cast<uint8>(PACKET_PUBLIC_FLAGS_RST |
+ PACKET_PUBLIC_FLAGS_8BYTE_GUID);
if (!writer.WriteUInt8(flags)) {
return NULL;
}
@@ -304,7 +305,8 @@ QuicEncryptedPacket* QuicFramer::ConstructVersionNegotiationPacket(
size_t len = GetVersionNegotiationPacketSize(supported_versions.size());
QuicDataWriter writer(len);
- uint8 flags = static_cast<uint8>(PACKET_PUBLIC_FLAGS_VERSION);
+ uint8 flags = static_cast<uint8>(PACKET_PUBLIC_FLAGS_VERSION |
+ PACKET_PUBLIC_FLAGS_8BYTE_GUID);
if (!writer.WriteUInt8(flags)) {
return NULL;
}
@@ -472,6 +474,7 @@ bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header,
if (header.public_header.version_flag) {
flags |= PACKET_PUBLIC_FLAGS_VERSION;
}
+ flags |= PACKET_PUBLIC_FLAGS_8BYTE_GUID;
if (!writer->WriteUInt8(flags)) {
return false;
}
@@ -551,6 +554,12 @@ bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) {
return false;
}
+ if ((public_flags & PACKET_PUBLIC_FLAGS_8BYTE_GUID) !=
+ PACKET_PUBLIC_FLAGS_8BYTE_GUID) {
+ set_detailed_error("Only full length guids (8 bytes) currently supported.");
+ return false;
+ }
+
public_header->reset_flag = (public_flags & PACKET_PUBLIC_FLAGS_RST) != 0;
public_header->version_flag =
(public_flags & PACKET_PUBLIC_FLAGS_VERSION) != 0;
@@ -581,12 +590,16 @@ 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;
}
+ // Ensure it's an 8 byte guid.
+ if ((public_flags & PACKET_PUBLIC_FLAGS_8BYTE_GUID) !=
+ PACKET_PUBLIC_FLAGS_8BYTE_GUID) {
+ return false;
+ }
return reader.ReadUInt64(guid);
}
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index b13a257..fb6ced9 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -314,7 +314,7 @@ class NET_EXPORT_PRIVATE QuicFramer {
const std::string& detailed_error() { return detailed_error_; }
- // Read the guid from a packet header.
+ // Read the full 8 byte guid from a packet header.
// Return true on success, else false.
static bool ReadGuidFromPacket(const QuicEncryptedPacket& packet,
QuicGuid* guid);
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index d75d9a6..2677665 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -485,8 +485,8 @@ TEST_F(QuicFramerTest, EmptyPacket) {
TEST_F(QuicFramerTest, LargePacket) {
unsigned char packet[kMaxPacketSize + 1] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -515,8 +515,8 @@ TEST_F(QuicFramerTest, LargePacket) {
TEST_F(QuicFramerTest, PacketHeader) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -566,12 +566,12 @@ TEST_F(QuicFramerTest, PacketHeader) {
TEST_F(QuicFramerTest, PacketHeaderWithVersionFlag) {
unsigned char packet[] = {
// public flags (version)
- 0x01,
+ 0x0D,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
- 'Q', '0', '0', '3',
+ 'Q', '0', '0', '4',
// packet sequence number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
@@ -621,8 +621,8 @@ TEST_F(QuicFramerTest, PacketHeaderWithVersionFlag) {
TEST_F(QuicFramerTest, InvalidPublicFlag) {
unsigned char packet[] = {
- // public flags
- 0x07,
+ // public flags (8 byte guid)
+ 0x10,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -660,8 +660,8 @@ TEST_F(QuicFramerTest, InvalidPublicFlag) {
TEST_F(QuicFramerTest, InvalidPrivateFlag) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -699,8 +699,8 @@ TEST_F(QuicFramerTest, InvalidPrivateFlag) {
TEST_F(QuicFramerTest, PaddingFrame) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -741,8 +741,8 @@ TEST_F(QuicFramerTest, PaddingFrame) {
TEST_F(QuicFramerTest, StreamFrame) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -810,13 +810,13 @@ TEST_F(QuicFramerTest, StreamFrame) {
TEST_F(QuicFramerTest, StreamFrameWithVersion) {
unsigned char packet[] = {
- // public flags (version)
- 0x01,
+ // public flags (version, 8 byte guid)
+ 0x0D,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
- 'Q', '0', '0', '3',
+ 'Q', '0', '0', '4',
// packet sequence number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
@@ -885,8 +885,8 @@ TEST_F(QuicFramerTest, RejectPacket) {
visitor_.accept_packet_ = false;
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -987,8 +987,8 @@ TEST_F(QuicFramerTest, RevivedStreamFrame) {
TEST_F(QuicFramerTest, StreamFrameInFecGroup) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1041,8 +1041,8 @@ TEST_F(QuicFramerTest, StreamFrameInFecGroup) {
TEST_F(QuicFramerTest, AckFrame) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1135,8 +1135,8 @@ TEST_F(QuicFramerTest, AckFrame) {
TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1193,8 +1193,8 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) {
TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1290,8 +1290,8 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) {
TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1344,8 +1344,8 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) {
TEST_F(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1371,8 +1371,8 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) {
TEST_F(QuicFramerTest, RstStreamFrame) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1429,8 +1429,8 @@ TEST_F(QuicFramerTest, RstStreamFrame) {
TEST_F(QuicFramerTest, ConnectionCloseFrame) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1515,8 +1515,8 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) {
TEST_F(QuicFramerTest, GoAwayFrame) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1575,8 +1575,8 @@ TEST_F(QuicFramerTest, GoAwayFrame) {
TEST_F(QuicFramerTest, PublicResetPacket) {
unsigned char packet[] = {
- // public flags (public reset)
- 0x02,
+ // public flags (public reset, 8 byte guid)
+ 0x0E,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1627,13 +1627,13 @@ TEST_F(QuicFramerTest, PublicResetPacket) {
TEST_F(QuicFramerTest, VersionNegotiationPacket) {
unsigned char packet[] = {
- // public flags (version)
- 0x01,
+ // public flags (version, 8 byte guid)
+ 0x0D,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
- 'Q', '0', '0', '3',
+ 'Q', '0', '0', '4',
'Q', '2', '.', '0',
};
@@ -1664,8 +1664,8 @@ TEST_F(QuicFramerTest, VersionNegotiationPacket) {
TEST_F(QuicFramerTest, FecPacket) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1716,8 +1716,8 @@ TEST_F(QuicFramerTest, ConstructPaddingFramePacket) {
frames.push_back(QuicFrame(&padding_frame));
unsigned char packet[kMaxPacketSize] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1766,8 +1766,8 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacket) {
frames.push_back(QuicFrame(&stream_frame));
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1826,13 +1826,13 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
frames.push_back(QuicFrame(&stream_frame));
unsigned char packet[] = {
- // public flags (version)
- 0x01,
+ // public flags (version, 8 byte guid)
+ 0x0D,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
- 'Q', '0', '0', '3',
+ 'Q', '0', '0', '4',
// packet sequence number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
@@ -1875,13 +1875,13 @@ TEST_F(QuicFramerTest, ConstructVersionNegotiationPacket) {
header.version_flag = true;
unsigned char packet[] = {
- // public flags (version)
- 0x01,
+ // public flags (version, 8 byte guid)
+ 0x0D,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
- 'Q', '0', '0', '3',
+ 'Q', '0', '0', '4',
'Q', '2', '.', '0',
};
@@ -1921,8 +1921,8 @@ TEST_F(QuicFramerTest, ConstructAckFramePacket) {
frames.push_back(QuicFrame(&ack_frame));
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -1984,8 +1984,8 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) {
frames.push_back(QuicFrame(&congestion_feedback_frame));
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2046,8 +2046,8 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) {
frames.push_back(QuicFrame(&frame));
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2112,8 +2112,8 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) {
frames.push_back(QuicFrame(&congestion_feedback_frame));
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2182,8 +2182,8 @@ TEST_F(QuicFramerTest, ConstructRstFramePacket) {
rst_frame.error_details = "because I can";
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2248,8 +2248,8 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) {
frames.push_back(QuicFrame(&close_frame));
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2322,8 +2322,8 @@ TEST_F(QuicFramerTest, ConstructGoAwayPacket) {
frames.push_back(QuicFrame(&goaway_frame));
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2368,8 +2368,8 @@ TEST_F(QuicFramerTest, ConstructPublicResetPacket) {
reset_packet.nonce_proof = GG_UINT64_C(0xABCDEF0123456789);
unsigned char packet[] = {
- // public flags
- 0x02,
+ // public flags (public reset, 8 byte GUID)
+ 0x0E,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2406,8 +2406,8 @@ TEST_F(QuicFramerTest, ConstructFecPacket) {
fec_data.redundancy = "abcdefghijklmnop";
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2438,8 +2438,8 @@ TEST_F(QuicFramerTest, ConstructFecPacket) {
TEST_F(QuicFramerTest, EncryptPacket) {
QuicPacketSequenceNumber sequence_number = GG_UINT64_C(0x123456789ABC);
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2471,8 +2471,8 @@ TEST_F(QuicFramerTest, EncryptPacket) {
TEST_F(QuicFramerTest, EncryptPacketWithVersionFlag) {
QuicPacketSequenceNumber sequence_number = GG_UINT64_C(0x123456789ABC);
unsigned char packet[] = {
- // public flags (version)
- 0x01,
+ // public flags (version, 8 byte guid)
+ 0x0D,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2665,8 +2665,8 @@ TEST_F(QuicFramerTest, CleanTruncation) {
TEST_F(QuicFramerTest, EntropyFlagTest) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2706,8 +2706,8 @@ TEST_F(QuicFramerTest, EntropyFlagTest) {
TEST_F(QuicFramerTest, FecEntropyFlagTest) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2748,8 +2748,8 @@ TEST_F(QuicFramerTest, FecEntropyFlagTest) {
TEST_F(QuicFramerTest, StopPacketProcessing) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
@@ -2811,8 +2811,8 @@ TEST_F(QuicFramerTest, StopPacketProcessing) {
TEST_F(QuicFramerTest, ConnectionCloseWithInvalidAck) {
unsigned char packet[] = {
- // public flags
- 0x00,
+ // public flags (8 byte guid)
+ 0x0C,
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index edf67e9..a6af6c2 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -17,6 +17,7 @@
#include "testing/gtest/include/gtest/gtest.h"
using base::StringPiece;
+using std::string;
using testing::InSequence;
using testing::Return;
using testing::SaveArg;
@@ -116,7 +117,7 @@ class QuicPacketGeneratorTest : public ::testing::Test {
}
QuicGoAwayFrame* CreateGoAwayFrame() {
- return new QuicGoAwayFrame(QUIC_NO_ERROR, 1, std::string());
+ return new QuicGoAwayFrame(QUIC_NO_ERROR, 1, string());
}
void CheckPacketContains(const PacketContents& contents,
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 45676f5..08d168c4f 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -123,7 +123,12 @@ enum QuicPacketPublicFlags {
PACKET_PUBLIC_FLAGS_NONE = 0,
PACKET_PUBLIC_FLAGS_VERSION = 1 << 0, // Packet header contains version info.
PACKET_PUBLIC_FLAGS_RST = 1 << 1, // Packet is a public reset packet.
- PACKET_PUBLIC_FLAGS_MAX = (1 << 2) - 1 // All bits set.
+ // Packet header guid length in bytes.
+ PACKET_PUBLIC_FLAGS_0BYTE_GUID = 0,
+ PACKET_PUBLIC_FLAGS_1BYTE_GUID = 1 << 2,
+ PACKET_PUBLIC_FLAGS_4BYTE_GUID = 1 << 3,
+ PACKET_PUBLIC_FLAGS_8BYTE_GUID = 1 << 3 | 1 << 2,
+ PACKET_PUBLIC_FLAGS_MAX = (1 << 4) - 1 // All bits set.
};
enum QuicPacketPrivateFlags {
@@ -214,6 +219,8 @@ enum QuicErrorCode {
// Crypto errors.
+ // Hanshake failed.
+ QUIC_HANDSHAKE_FAILED,
// Handshake message contained out of order tags.
QUIC_CRYPTO_TAGS_OUT_OF_ORDER,
// Handshake message contained too many entries.
@@ -271,7 +278,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', '3');
+const QuicTag kQuicVersion1 = TAG('Q', '0', '0', '4');
#undef TAG
// MakeQuicTag returns a value given the four bytes. For example:
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 5d5df18..12bec26 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -216,11 +216,29 @@ bool QuicSession::IsCryptoHandshakeConfirmed() {
}
void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
- if (event == QuicSession::HANDSHAKE_CONFIRMED) {
- LOG_IF(DFATAL, !config_.negotiated())
- << "Handshake confirmed without parameter negotiation.";
- connection_->SetConnectionTimeout(config_.idle_connection_state_lifetime());
- max_open_streams_ = config_.max_streams_per_connection();
+ switch (event) {
+ // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
+ // to QuicSession since it is the glue.
+ case ENCRYPTION_FIRST_ESTABLISHED:
+ break;
+
+ case ENCRYPTION_REESTABLISHED:
+ // Retransmit originally packets that were sent, since they can't be
+ // decrypted by the peer.
+ connection_->RetransmitUnackedPackets(
+ QuicConnection::INITIAL_ENCRYPTION_ONLY);
+ break;
+
+ case HANDSHAKE_CONFIRMED:
+ LOG_IF(DFATAL, !config_.negotiated())
+ << "Handshake confirmed without parameter negotiation.";
+ connection_->SetConnectionTimeout(
+ config_.idle_connection_state_lifetime());
+ max_open_streams_ = config_.max_streams_per_connection();
+ break;
+
+ default:
+ LOG(ERROR) << "Got unknown handshake event: " << event;
}
}
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index ae5f4b5..9d18f7a 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -158,6 +158,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_PACKET_TOO_LARGE);
RETURN_STRING_LITERAL(QUIC_PACKET_FOR_NONEXISTENT_STREAM);
RETURN_STRING_LITERAL(QUIC_PEER_GOING_AWAY);
+ RETURN_STRING_LITERAL(QUIC_HANDSHAKE_FAILED);
RETURN_STRING_LITERAL(QUIC_CRYPTO_TAGS_OUT_OF_ORDER);
RETURN_STRING_LITERAL(QUIC_CRYPTO_TOO_MANY_ENTRIES);
RETURN_STRING_LITERAL(QUIC_CRYPTO_TOO_MANY_REJECTS);
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index 0ce9104..31ef6b8 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -111,6 +111,11 @@ class QuicClient : public EpollCallbackInterface {
int fd() { return fd_; }
+ // This should only be set before the initial Connect()
+ void set_server_hostname(const string& hostname) {
+ server_hostname_ = hostname;
+ }
+
private:
friend class net::tools::test::QuicClientPeer;
@@ -124,7 +129,7 @@ class QuicClient : public EpollCallbackInterface {
const IPEndPoint server_address_;
// Hostname of the server. This may be a DNS name or an IP address literal.
- const std::string server_hostname_;
+ std::string server_hostname_;
// config_ and crypto_config_ contain configuration and cached state about
// servers.
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 3cacde3..14de2b0 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -181,9 +181,10 @@ QuicSession* QuicDispatcher::CreateQuicSession(
EpollServer* epoll_server) {
QuicConnectionHelperInterface* helper =
new QuicEpollConnectionHelper(this, epoll_server);
- return new QuicServerSession(
- config_, crypto_config_,
- new QuicConnection(guid, client_address, helper, true), this);
+ QuicServerSession* session = new QuicServerSession(
+ config_, new QuicConnection(guid, client_address, helper, true), this);
+ session->Initialize(crypto_config_);
+ return session;
}
} // namespace tools
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 330c307..13f064d 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -13,11 +13,9 @@ namespace tools {
QuicServerSession::QuicServerSession(
const QuicConfig& config,
- const QuicCryptoServerConfig& crypto_config,
QuicConnection* connection,
QuicSessionOwner* owner)
: QuicSession(connection, config, true),
- crypto_stream_(crypto_config, this),
owner_(owner) {
set_max_open_streams(config.max_streams_per_connection());
}
@@ -25,6 +23,16 @@ QuicServerSession::QuicServerSession(
QuicServerSession::~QuicServerSession() {
}
+void QuicServerSession::Initialize(
+ const QuicCryptoServerConfig& crypto_config) {
+ crypto_stream_.reset(CreateQuicCryptoServerStream(crypto_config));
+}
+
+QuicCryptoServerStream* QuicServerSession::CreateQuicCryptoServerStream(
+ const QuicCryptoServerConfig& crypto_config) {
+ return new QuicCryptoServerStream(crypto_config, this);
+}
+
void QuicServerSession::ConnectionClose(QuicErrorCode error, bool from_peer) {
QuicSession::ConnectionClose(error, from_peer);
owner_->OnConnectionClose(connection()->guid(), error);
@@ -60,7 +68,7 @@ ReliableQuicStream* QuicServerSession::CreateOutgoingReliableStream() {
}
QuicCryptoServerStream* QuicServerSession::GetCryptoStream() {
- return &crypto_stream_;
+ return crypto_stream_.get();
}
} // namespace tools
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index be92871a..8405372 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -11,6 +11,7 @@
#include <vector>
#include "base/hash_tables.h"
+#include "base/memory/scoped_ptr.h"
#include "net/quic/quic_crypto_server_stream.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_session.h"
@@ -37,8 +38,7 @@ class QuicSessionOwner {
class QuicServerSession : public QuicSession {
public:
QuicServerSession(const QuicConfig& config,
- const QuicCryptoServerConfig& crypto_config,
- QuicConnection* connection,
+ QuicConnection *connection,
QuicSessionOwner* owner);
// Override the base class to notify the owner of the connection close.
@@ -46,6 +46,8 @@ class QuicServerSession : public QuicSession {
virtual ~QuicServerSession();
+ virtual void Initialize(const QuicCryptoServerConfig& crypto_config);
+
protected:
// QuicSession methods:
virtual ReliableQuicStream* CreateIncomingReliableStream(
@@ -58,8 +60,11 @@ class QuicServerSession : public QuicSession {
// possibly closing the connection, and returns false.
virtual bool ShouldCreateIncomingReliableStream(QuicStreamId id);
+ virtual QuicCryptoServerStream* CreateQuicCryptoServerStream(
+ const QuicCryptoServerConfig& crypto_config);
+
private:
- QuicCryptoServerStream crypto_stream_;
+ scoped_ptr<QuicCryptoServerStream> crypto_stream_;
QuicSessionOwner* owner_;
DISALLOW_COPY_AND_ASSIGN(QuicServerSession);
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 1a7539f..5325e48 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -4,6 +4,7 @@
#include "net/tools/quic/test_tools/quic_test_client.h"
+#include "googleurl/src/gurl.h"
#include "net/tools/flip_server/balsa_headers.h"
#include "net/tools/quic/test_tools/http_message_test_utils.h"
@@ -72,8 +73,17 @@ ssize_t QuicTestClient::SendRequest(const string& uri) {
ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) {
stream_ = NULL; // Always force creation of a stream for SendMessage.
+ // If we're not connected, try to find an sni hostname.
+ if (!connected()) {
+ GURL url(message.headers()->request_uri().as_string());
+ if (!url.host().empty()) {
+ client_.set_server_hostname(url.host());
+ }
+ }
+
QuicReliableClientStream* stream = GetOrCreateStream();
if (!stream) { return 0; }
+
scoped_ptr<BalsaHeaders> munged_headers(MungeHeaders(message.headers()));
return GetOrCreateStream()->SendRequest(
munged_headers.get() ? *munged_headers.get() : *message.headers(),
@@ -97,8 +107,8 @@ string QuicTestClient::SendCustomSynchronousRequest(
string QuicTestClient::SendSynchronousRequest(const string& uri) {
if (SendRequest(uri) == 0) {
- DLOG(ERROR) << "Failed to the request for uri:" << uri;
- return std::string();
+ DLOG(ERROR) << "Failed the request for uri:" << uri;
+ return "";
}
WaitForResponse();
return response_;