summaryrefslogtreecommitdiffstats
path: root/net/quic
diff options
context:
space:
mode:
Diffstat (limited to 'net/quic')
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc1
-rw-r--r--net/quic/crypto/crypto_framer.cc111
-rw-r--r--net/quic/crypto/crypto_framer.h14
-rw-r--r--net/quic/crypto/crypto_framer_test.cc134
-rw-r--r--net/quic/crypto/crypto_protocol.h2
-rw-r--r--net/quic/quic_client_session.cc26
-rw-r--r--net/quic/quic_client_session.h5
-rw-r--r--net/quic/quic_client_session_test.cc21
-rw-r--r--net/quic/quic_connection.cc73
-rw-r--r--net/quic/quic_connection.h82
-rw-r--r--net/quic/quic_connection_helper_test.cc15
-rw-r--r--net/quic/quic_connection_test.cc245
-rw-r--r--net/quic/quic_crypto_client_stream.cc44
-rw-r--r--net/quic/quic_crypto_client_stream.h6
-rw-r--r--net/quic/quic_crypto_client_stream_test.cc6
-rw-r--r--net/quic/quic_crypto_server_stream.cc19
-rw-r--r--net/quic/quic_crypto_server_stream_test.cc6
-rw-r--r--net/quic/quic_crypto_stream.cc12
-rw-r--r--net/quic/quic_crypto_stream.h7
-rw-r--r--net/quic/quic_crypto_stream_test.cc5
-rw-r--r--net/quic/quic_framer.cc88
-rw-r--r--net/quic/quic_framer.h48
-rw-r--r--net/quic/quic_framer_test.cc20
-rw-r--r--net/quic/quic_http_stream_test.cc11
-rw-r--r--net/quic/quic_network_transaction_unittest.cc84
-rw-r--r--net/quic/quic_packet_creator_test.cc15
-rw-r--r--net/quic/quic_packet_generator_test.cc6
-rw-r--r--net/quic/quic_protocol.cc8
-rw-r--r--net/quic/quic_protocol.h20
-rw-r--r--net/quic/quic_session.cc11
-rw-r--r--net/quic/quic_session.h41
-rw-r--r--net/quic/quic_session_test.cc10
-rw-r--r--net/quic/quic_stream_factory_test.cc20
-rw-r--r--net/quic/quic_utils.cc1
-rw-r--r--net/quic/test_tools/crypto_test_utils.cc41
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream.cc18
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream.h24
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream_factory.cc7
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream_factory.h11
-rw-r--r--net/quic/test_tools/quic_test_utils.cc7
-rw-r--r--net/quic/test_tools/quic_test_utils.h1
-rw-r--r--net/quic/test_tools/simple_quic_framer.cc9
42 files changed, 906 insertions, 429 deletions
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 97eb896..4bed7ed 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -227,7 +227,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/crypto_framer.cc b/net/quic/crypto/crypto_framer.cc
index b0ff9ea..cbc1079 100644
--- a/net/quic/crypto/crypto_framer.cc
+++ b/net/quic/crypto/crypto_framer.cc
@@ -9,12 +9,16 @@
#include "net/quic/quic_data_writer.h"
using base::StringPiece;
+using std::make_pair;
+using std::pair;
+using std::vector;
namespace net {
namespace {
const size_t kCryptoTagSize = sizeof(uint32);
+const size_t kCryptoEndOffsetSize = sizeof(uint32);
const size_t kNumEntriesSize = sizeof(uint16);
const size_t kValueLenSize = sizeof(uint16);
@@ -90,7 +94,7 @@ bool CryptoFramer::ProcessInput(StringPiece input) {
message_.set_tag(message_tag);
state_ = STATE_READING_NUM_ENTRIES;
case STATE_READING_NUM_ENTRIES:
- if (reader.BytesRemaining() < kNumEntriesSize) {
+ if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16)) {
break;
}
reader.ReadUInt16(&num_entries_);
@@ -98,56 +102,55 @@ bool CryptoFramer::ProcessInput(StringPiece input) {
error_ = QUIC_CRYPTO_TOO_MANY_ENTRIES;
return false;
}
- state_ = STATE_READING_KEY_TAGS;
- case STATE_READING_KEY_TAGS:
- if (reader.BytesRemaining() < num_entries_ * kCryptoTagSize) {
+ 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_ * (kCryptoTagSize +
+ kCryptoEndOffsetSize)) {
break;
}
- for (int i = 0; i < num_entries_; ++i) {
+
+ uint32 last_end_offset = 0;
+ for (unsigned i = 0; i < num_entries_; ++i) {
CryptoTag tag;
reader.ReadUInt32(&tag);
- if (i > 0 && tag <= tags_.back()) {
- error_ = QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
+ 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;
}
- tags_.push_back(tag);
- }
- state_ = STATE_READING_LENGTHS;
- case STATE_READING_LENGTHS: {
- size_t expected_bytes = num_entries_ * kValueLenSize;
- bool has_padding = (num_entries_ % 2 == 1);
- if (has_padding) {
- expected_bytes += kValueLenSize;
- }
- if (reader.BytesRemaining() < expected_bytes) {
- break;
- }
- values_len_ = 0;
- for (int i = 0; i < num_entries_; ++i) {
- uint16 len;
- reader.ReadUInt16(&len);
- tag_length_map_[tags_[i]] = len;
- values_len_ += len;
- }
- // Possible padding
- if (has_padding) {
- uint16 len;
- reader.ReadUInt16(&len);
- if (len != 0) {
- error_ = QUIC_CRYPTO_INVALID_VALUE_LENGTH;
+
+ 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 (int i = 0; i < num_entries_; ++i) {
+ for (vector<pair<CryptoTag, size_t> >::const_iterator
+ it = tags_and_lengths_.begin(); it != tags_and_lengths_.end();
+ it++) {
StringPiece value;
- reader.ReadStringPiece(&value, tag_length_map_[tags_[i]]);
- message_.SetStringPiece(tags_[i], value);
+ reader.ReadStringPiece(&value, it->second);
+ message_.SetStringPiece(it->first, value);
}
visitor_->OnHandshakeMessage(message_);
Clear();
@@ -165,18 +168,16 @@ QuicData* CryptoFramer::ConstructHandshakeMessage(
if (message.tag_value_map().size() > kMaxEntries) {
return NULL;
}
- size_t len = sizeof(uint32); // message tag
+ size_t len = kCryptoTagSize; // message tag
len += sizeof(uint16); // number of map entries
+ len += sizeof(uint16); // padding.
CryptoTagValueMap::const_iterator it = message.tag_value_map().begin();
while (it != message.tag_value_map().end()) {
- len += sizeof(uint32); // tag
- len += sizeof(uint16); // value len
+ len += kCryptoTagSize; // tag
+ len += kCryptoEndOffsetSize; // end offset
len += it->second.length(); // value
++it;
}
- if (message.tag_value_map().size() % 2 == 1) {
- len += sizeof(uint16); // padding
- }
QuicDataWriter writer(len);
if (!writer.WriteUInt32(message.tag())) {
@@ -187,29 +188,26 @@ QuicData* CryptoFramer::ConstructHandshakeMessage(
DCHECK(false) << "Failed to write size.";
return NULL;
}
- // Tags
+ if (!writer.WriteUInt16(0)) {
+ DCHECK(false) << "Failed to write padding.";
+ return NULL;
+ }
+
+ uint32 end_offset = 0;
+ // Tags and offsets
for (it = message.tag_value_map().begin();
it != message.tag_value_map().end(); ++it) {
if (!writer.WriteUInt32(it->first)) {
DCHECK(false) << "Failed to write tag.";
return NULL;
}
- }
- // Lengths
- for (it = message.tag_value_map().begin();
- it != message.tag_value_map().end(); ++it) {
- if (!writer.WriteUInt16(it->second.length())) {
- DCHECK(false) << "Failed to write length.";
- return NULL;
- }
- }
- // Possible padding
- if (message.tag_value_map().size() % 2 == 1) {
- if (!writer.WriteUInt16(0)) {
- DCHECK(false) << "Failed to write padding.";
+ end_offset += it->second.length();
+ if (!writer.WriteUInt32(end_offset)) {
+ DCHECK(false) << "Failed to write end offset.";
return NULL;
}
}
+
// Values
for (it = message.tag_value_map().begin();
it != message.tag_value_map().end(); ++it) {
@@ -223,8 +221,7 @@ QuicData* CryptoFramer::ConstructHandshakeMessage(
void CryptoFramer::Clear() {
message_.Clear();
- tag_length_map_.clear();
- tags_.clear();
+ tags_and_lengths_.clear();
error_ = QUIC_NO_ERROR;
state_ = STATE_READING_TAG;
}
diff --git a/net/quic/crypto/crypto_framer.h b/net/quic/crypto/crypto_framer.h
index 07ffa39..7861284 100644
--- a/net/quic/crypto/crypto_framer.h
+++ b/net/quic/crypto/crypto_framer.h
@@ -5,7 +5,8 @@
#ifndef NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
#define NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
-#include <map>
+#include <utility>
+#include <vector>
#include "base/basictypes.h"
#include "base/logging.h"
@@ -86,8 +87,7 @@ class NET_EXPORT_PRIVATE CryptoFramer {
enum CryptoFramerState {
STATE_READING_TAG,
STATE_READING_NUM_ENTRIES,
- STATE_READING_KEY_TAGS,
- STATE_READING_LENGTHS,
+ STATE_READING_TAGS_AND_LENGTHS,
STATE_READING_VALUES
};
@@ -103,11 +103,9 @@ class NET_EXPORT_PRIVATE CryptoFramer {
CryptoHandshakeMessage message_;
// Number of entires in the message currently being parsed.
uint16 num_entries_;
- // Vector of tags in the message currently being parsed.
- CryptoTagVector tags_;
- // Length of the data associated with each tag in the message currently
- // being parsed.
- std::map<CryptoTag, size_t> tag_length_map_;
+ // tags_and_lengths_ contains the tags that are currently being parsed and
+ // their lengths.
+ std::vector<std::pair<CryptoTag, size_t> > tags_and_lengths_;
// Cumulative length of all values in the message currently being parsed.
size_t values_len_;
};
diff --git a/net/quic/crypto/crypto_framer_test.cc b/net/quic/crypto/crypto_framer_test.cc
index 1335e8b..0cdbd40 100644
--- a/net/quic/crypto/crypto_framer_test.cc
+++ b/net/quic/crypto/crypto_framer_test.cc
@@ -71,20 +71,20 @@ TEST(CryptoFramerTest, ConstructHandshakeMessage) {
0x33, 0x77, 0xAA, 0xFF,
// num entries
0x03, 0x00,
+ // padding
+ 0x00, 0x00,
// tag 1
0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x06, 0x00, 0x00, 0x00,
// tag 2
0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x0b, 0x00, 0x00, 0x00,
// tag 3
0x7A, 0x56, 0x34, 0x12,
- // len 1
- 0x06, 0x00,
- // len 2
- 0x05, 0x00,
- // len 3
- 0x07, 0x00,
- // padding
- 0x00, 0x00,
+ // end offset 3
+ 0x12, 0x00, 0x00, 0x00,
// value 1
'a', 'b', 'c', 'd',
'e', 'f',
@@ -115,14 +115,16 @@ TEST(CryptoFramerTest, ConstructHandshakeMessageWithTwoKeys) {
0x33, 0x77, 0xAA, 0xFF,
// num entries
0x02, 0x00,
+ // padding
+ 0x00, 0x00,
// tag 1
0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x06, 0x00, 0x00, 0x00,
// tag 2
0x79, 0x56, 0x34, 0x12,
- // len 1
- 0x06, 0x00,
- // len 2
- 0x05, 0x00,
+ // end offset 2
+ 0x0b, 0x00, 0x00, 0x00,
// value 1
'a', 'b', 'c', 'd',
'e', 'f',
@@ -150,12 +152,12 @@ TEST(CryptoFramerTest, ConstructHandshakeMessageZeroLength) {
0x33, 0x77, 0xAA, 0xFF,
// num entries
0x01, 0x00,
- // tag 1
- 0x78, 0x56, 0x34, 0x12,
- // len 1
- 0x00, 0x00,
// padding
0x00, 0x00,
+ // tag 1
+ 0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x00, 0x00, 0x00, 0x00,
};
CryptoFramer framer;
@@ -189,14 +191,16 @@ TEST(CryptoFramerTest, ProcessInput) {
0x33, 0x77, 0xAA, 0xFF,
// num entries
0x02, 0x00,
+ // padding
+ 0x00, 0x00,
// tag 1
0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x06, 0x00, 0x00, 0x00,
// tag 2
0x79, 0x56, 0x34, 0x12,
- // len 1
- 0x06, 0x00,
- // len 2
- 0x05, 0x00,
+ // end offset 2
+ 0x0b, 0x00, 0x00, 0x00,
// value 1
'a', 'b', 'c', 'd',
'e', 'f',
@@ -226,20 +230,20 @@ TEST(CryptoFramerTest, ProcessInputWithThreeKeys) {
0x33, 0x77, 0xAA, 0xFF,
// num entries
0x03, 0x00,
+ // padding
+ 0x00, 0x00,
// tag 1
0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x06, 0x00, 0x00, 0x00,
// tag 2
0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x0b, 0x00, 0x00, 0x00,
// tag 3
0x7A, 0x56, 0x34, 0x12,
- // len 1
- 0x06, 0x00,
- // len 2
- 0x05, 0x00,
- // len 3
- 0x07, 0x00,
- // padding
- 0x00, 0x00,
+ // end offset 3
+ 0x12, 0x00, 0x00, 0x00,
// value 1
'a', 'b', 'c', 'd',
'e', 'f',
@@ -273,14 +277,16 @@ TEST(CryptoFramerTest, ProcessInputIncrementally) {
0x33, 0x77, 0xAA, 0xFF,
// num entries
0x02, 0x00,
+ // padding
+ 0x00, 0x00,
// tag 1
0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x06, 0x00, 0x00, 0x00,
// tag 2
0x79, 0x56, 0x34, 0x12,
- // len 1
- 0x06, 0x00,
- // len 2
- 0x05, 0x00,
+ // end offset 2
+ 0x0b, 0x00, 0x00, 0x00,
// value 1
'a', 'b', 'c', 'd',
'e', 'f',
@@ -311,10 +317,16 @@ TEST(CryptoFramerTest, ProcessInputTagsOutOfOrder) {
0x33, 0x77, 0xAA, 0xFF,
// num entries
0x02, 0x00,
+ // padding
+ 0x00, 0x00,
// tag 1
0x78, 0x56, 0x34, 0x13,
+ // end offset 1
+ 0x01, 0x00, 0x00, 0x00,
// tag 2
0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x02, 0x00, 0x00, 0x00,
};
EXPECT_FALSE(
@@ -322,7 +334,7 @@ TEST(CryptoFramerTest, ProcessInputTagsOutOfOrder) {
EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
}
-TEST(CryptoFramerTest, ProcessInputTooManyEntries) {
+TEST(CryptoFramerTest, ProcessEndOffsetsOutOfOrder) {
test::TestCryptoVisitor visitor;
CryptoFramer framer;
framer.set_visitor(&visitor);
@@ -331,15 +343,25 @@ TEST(CryptoFramerTest, ProcessInputTooManyEntries) {
// tag
0x33, 0x77, 0xAA, 0xFF,
// num entries
- 0xA0, 0x00,
+ 0x02, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x79, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x01, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x78, 0x56, 0x34, 0x13,
+ // end offset 2
+ 0x00, 0x00, 0x00, 0x00,
};
- EXPECT_FALSE(
- framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
- EXPECT_EQ(QUIC_CRYPTO_TOO_MANY_ENTRIES, framer.error());
+ EXPECT_FALSE(framer.ProcessInput(StringPiece(AsChars(input),
+ arraysize(input))));
+ EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
}
-TEST(CryptoFramerTest, ProcessInputZeroLength) {
+TEST(CryptoFramerTest, ProcessInputTooManyEntries) {
test::TestCryptoVisitor visitor;
CryptoFramer framer;
framer.set_visitor(&visitor);
@@ -348,22 +370,17 @@ TEST(CryptoFramerTest, ProcessInputZeroLength) {
// tag
0x33, 0x77, 0xAA, 0xFF,
// num entries
- 0x02, 0x00,
- // tag 1
- 0x78, 0x56, 0x34, 0x12,
- // tag 2
- 0x79, 0x56, 0x34, 0x12,
- // len 1
+ 0xA0, 0x00,
+ // padding
0x00, 0x00,
- // len 2
- 0x05, 0x00,
};
- EXPECT_TRUE(
- framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
+ EXPECT_FALSE(framer.ProcessInput(StringPiece(AsChars(input),
+ arraysize(input))));
+ EXPECT_EQ(QUIC_CRYPTO_TOO_MANY_ENTRIES, framer.error());
}
-TEST(CryptoFramerTest, ProcessInputInvalidLengthPadding) {
+TEST(CryptoFramerTest, ProcessInputZeroLength) {
test::TestCryptoVisitor visitor;
CryptoFramer framer;
framer.set_visitor(&visitor);
@@ -372,18 +389,21 @@ TEST(CryptoFramerTest, ProcessInputInvalidLengthPadding) {
// tag
0x33, 0x77, 0xAA, 0xFF,
// num entries
- 0x01, 0x00,
+ 0x02, 0x00,
+ // padding
+ 0x00, 0x00,
// tag 1
0x78, 0x56, 0x34, 0x12,
- // len 1
- 0x05, 0x00,
- // padding
- 0x05, 0x00,
+ // end offset 1
+ 0x00, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x05, 0x00, 0x00, 0x00,
};
- EXPECT_FALSE(
- framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
- EXPECT_EQ(QUIC_CRYPTO_INVALID_VALUE_LENGTH, framer.error());
+ EXPECT_TRUE(framer.ProcessInput(StringPiece(AsChars(input),
+ arraysize(input))));
}
} // namespace test
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 3e22e7b..baceeae 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -75,7 +75,7 @@ const CryptoTag kPROF = TAG('P', 'R', 'O', 'F'); // Proof (signature).
#undef TAG
-const size_t kMaxEntries = 16; // Max number of entries in a message.
+const size_t kMaxEntries = 128; // Max number of entries in a message.
const size_t kNonceSize = 32; // Size in bytes of the connection nonce.
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index b1bcd549..c3b8d3a 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -4,6 +4,7 @@
#include "net/quic/quic_client_session.h"
+#include "base/callback_helpers.h"
#include "base/message_loop.h"
#include "base/stl_util.h"
#include "base/string_number_conversions.h"
@@ -50,13 +51,14 @@ QuicClientSession::QuicClientSession(
}
QuicClientSession::~QuicClientSession() {
+ DCHECK(callback_.is_null());
connection()->set_debug_visitor(NULL);
net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
}
QuicReliableClientStream* QuicClientSession::CreateOutgoingReliableStream() {
- if (!crypto_stream_->handshake_complete()) {
- DLOG(INFO) << "Crypto handshake not complete, no outgoing stream created.";
+ if (!crypto_stream_->encryption_established()) {
+ DLOG(INFO) << "Encryption not active so no outgoing stream created.";
return NULL;
}
if (GetNumOpenStreams() >= get_max_open_streams()) {
@@ -87,7 +89,7 @@ int QuicClientSession::CryptoConnect(const CompletionCallback& callback) {
return ERR_CONNECTION_FAILED;
}
- if (IsCryptoHandshakeComplete()) {
+ if (IsEncryptionEstablished()) {
return OK;
}
@@ -109,12 +111,23 @@ void QuicClientSession::CloseStream(QuicStreamId stream_id) {
}
}
-void QuicClientSession::OnCryptoHandshakeComplete(QuicErrorCode error) {
+void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
if (!callback_.is_null()) {
- callback_.Run(error == QUIC_NO_ERROR ? OK : ERR_UNEXPECTED);
+ // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
+ // could be called because there are no error events in CryptoHandshakeEvent
+ // enum. If error events are added to CryptoHandshakeEvent, then the
+ // following code needs to changed.
+ base::ResetAndReturn(&callback_).Run(OK);
}
}
+void QuicClientSession::ConnectionClose(QuicErrorCode error, bool from_peer) {
+ if (!callback_.is_null()) {
+ base::ResetAndReturn(&callback_).Run(error);
+ }
+ QuicSession::ConnectionClose(error, from_peer);
+}
+
void QuicClientSession::StartReading() {
if (read_pending_) {
return;
@@ -137,6 +150,9 @@ void QuicClientSession::StartReading() {
}
void QuicClientSession::CloseSessionOnError(int error) {
+ if (!callback_.is_null()) {
+ base::ResetAndReturn(&callback_).Run(error);
+ }
while (!streams()->empty()) {
ReliableQuicStream* stream = streams()->begin()->second;
QuicStreamId id = stream->id();
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index 2bf6e78..fbbbecf 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -45,7 +45,10 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicSession {
virtual QuicReliableClientStream* CreateOutgoingReliableStream() OVERRIDE;
virtual QuicCryptoClientStream* GetCryptoStream() OVERRIDE;
virtual void CloseStream(QuicStreamId stream_id) OVERRIDE;
- virtual void OnCryptoHandshakeComplete(QuicErrorCode error) OVERRIDE;
+ virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) OVERRIDE;
+
+ // QuicConnectionVisitorInterface methods:
+ virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE;
// Performs a crypto handshake with the server.
int CryptoConnect(const CompletionCallback& callback);
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 6d26541..8b7bddb 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -86,12 +86,12 @@ TEST_F(QuicClientSessionTest, MaxNumConnections) {
}
TEST_F(QuicClientSessionTest, GoAwayReceived) {
- // Initialize crypto before the client session will create a stream.
- ASSERT_TRUE(session_.CryptoConnect(callback_.callback()));
- // Simulate the server crypto handshake.
- CryptoHandshakeMessage server_message;
- server_message.set_tag(kSHLO);
- session_.GetCryptoStream()->OnHandshakeMessage(server_message);
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
+ CompleteCryptoHandshake();
// After receiving a GoAway, I should no longer be able to create outgoing
// streams.
@@ -109,11 +109,7 @@ TEST_F(QuicClientSessionTest, Logging) {
// TODO(rch): Add some helper methods to simplify packet creation in tests.
// Receive a packet, and verify that it was logged.
- QuicFramer framer(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false);
+ QuicFramer framer(kQuicVersion1, QuicTime::Zero(), false);
QuicRstStreamFrame frame;
frame.stream_id = 2;
frame.error_code = QUIC_STREAM_CONNECTION_ERROR;
@@ -132,7 +128,8 @@ TEST_F(QuicClientSessionTest, Logging) {
header.fec_group = 0;
scoped_ptr<QuicPacket> p(
framer.ConstructFrameDataPacket(header, frames).packet);
- scoped_ptr<QuicEncryptedPacket> packet(framer.EncryptPacket(1, *p));
+ scoped_ptr<QuicEncryptedPacket> packet(framer.EncryptPacket(
+ ENCRYPTION_NONE, 1, *p));
IPAddressNumber ip;
CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
IPEndPoint peer_addr = IPEndPoint(ip, 443);
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 766274b..4851d47 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -79,10 +79,9 @@ QuicConnection::QuicConnection(QuicGuid guid,
bool is_server)
: helper_(helper),
framer_(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
helper->GetClock()->ApproximateNow(),
is_server),
+ encryption_level_(ENCRYPTION_NONE),
clock_(helper->GetClock()),
random_generator_(helper->GetRandomGenerator()),
guid_(guid),
@@ -151,7 +150,9 @@ bool QuicConnection::SelectMutualVersion(
}
void QuicConnection::OnError(QuicFramer* framer) {
- if (!connected_) {
+ // Packets that we cannot decrypt are dropped.
+ // TODO(rch): add stats to measure this.
+ if (!connected_ || framer->error() == QUIC_DECRYPTION_FAILURE) {
return;
}
SendConnectionClose(framer->error());
@@ -727,7 +728,9 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
stats_.bytes_received += packet.length();
++stats_.packets_received;
- framer_.ProcessPacket(packet);
+ if (!framer_.ProcessPacket(packet)) {
+ return;
+ }
MaybeProcessRevivedPacket();
}
@@ -770,7 +773,8 @@ bool QuicConnection::WriteQueuedPackets() {
// TODO(rch): clean up and close the connection if we really hit this.
DCHECK_LT(queued_packets_.size(), num_queued_packets);
num_queued_packets = queued_packets_.size();
- if (WritePacket(packet_iterator->sequence_number,
+ if (WritePacket(packet_iterator->encryption_level,
+ packet_iterator->sequence_number,
packet_iterator->packet,
packet_iterator->retransmittable,
NO_FORCE)) {
@@ -883,7 +887,8 @@ void QuicConnection::RetransmitPacket(
unacked_packets_.rbegin()->first < serialized_packet.sequence_number);
unacked_packets_.insert(make_pair(serialized_packet.sequence_number,
unacked));
- SendOrQueuePacket(serialized_packet.sequence_number,
+ SendOrQueuePacket(unacked->encryption_level(),
+ serialized_packet.sequence_number,
serialized_packet.packet,
serialized_packet.entropy_hash,
HAS_RETRANSMITTABLE_DATA);
@@ -901,7 +906,8 @@ bool QuicConnection::CanWrite(Retransmission retransmission,
QuicTime::Delta delay = congestion_manager_.TimeUntilSend(
now, retransmission, retransmittable);
if (delay.IsInfinite()) {
- return false;
+ // TODO(pwestin): should be false but trigger other bugs see b/8350327.
+ return true;
}
// If the scheduler requires a delay, then we can not send this packet now.
@@ -946,7 +952,8 @@ void QuicConnection::MaybeSetupRetransmission(
// SendStreamData().
}
-bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number,
+bool QuicConnection::WritePacket(EncryptionLevel level,
+ QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
HasRetransmittableData retransmittable,
Force forced) {
@@ -967,7 +974,7 @@ bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number,
}
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer_.EncryptPacket(sequence_number, *packet));
+ framer_.EncryptPacket(level, sequence_number, *packet));
DLOG(INFO) << ENDPOINT << "Sending packet number " << sequence_number
<< " : " << (packet->is_fec_packet() ? "FEC " :
(retransmittable == HAS_RETRANSMITTABLE_DATA
@@ -1022,6 +1029,10 @@ bool QuicConnection::OnSerializedPacket(
DCHECK(unacked_packets_.empty() ||
unacked_packets_.rbegin()->first <
serialized_packet.sequence_number);
+ // Retransmitted frames will be sent with the same encryption level as the
+ // original.
+ serialized_packet.retransmittable_frames->set_encryption_level(
+ encryption_level_);
unacked_packets_.insert(
make_pair(serialized_packet.sequence_number,
serialized_packet.retransmittable_frames));
@@ -1030,7 +1041,8 @@ bool QuicConnection::OnSerializedPacket(
make_pair(serialized_packet.sequence_number,
RetransmissionInfo(serialized_packet.sequence_number)));
}
- return SendOrQueuePacket(serialized_packet.sequence_number,
+ return SendOrQueuePacket(encryption_level_,
+ serialized_packet.sequence_number,
serialized_packet.packet,
serialized_packet.entropy_hash,
serialized_packet.retransmittable_frames != NULL ?
@@ -1038,13 +1050,14 @@ bool QuicConnection::OnSerializedPacket(
NO_RETRANSMITTABLE_DATA);
}
-bool QuicConnection::SendOrQueuePacket(QuicPacketSequenceNumber sequence_number,
+bool QuicConnection::SendOrQueuePacket(EncryptionLevel level,
+ QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
QuicPacketEntropyHash entropy_hash,
HasRetransmittableData retransmittable) {
entropy_manager_.RecordSentPacketEntropyHash(sequence_number, entropy_hash);
- if (!WritePacket(sequence_number, packet, retransmittable, NO_FORCE)) {
- queued_packets_.push_back(QueuedPacket(sequence_number, packet,
+ if (!WritePacket(level, sequence_number, packet, retransmittable, NO_FORCE)) {
+ queued_packets_.push_back(QueuedPacket(sequence_number, packet, level,
retransmittable));
return false;
}
@@ -1134,16 +1147,35 @@ QuicTime QuicConnection::OnRetransmissionTimeout() {
return retransmission_timeouts_.top().scheduled_time;
}
-void QuicConnection::ChangeEncrypter(QuicEncrypter* encrypter) {
- framer_.set_encrypter(encrypter);
+void QuicConnection::SetEncrypter(EncryptionLevel level,
+ QuicEncrypter* encrypter) {
+ framer_.SetEncrypter(level, encrypter);
+}
+
+const QuicEncrypter* QuicConnection::encrypter(EncryptionLevel level) const {
+ return framer_.encrypter(level);
+}
+
+void QuicConnection::SetDefaultEncryptionLevel(
+ EncryptionLevel level) {
+ encryption_level_ = level;
+}
+
+void QuicConnection::SetDecrypter(QuicDecrypter* decrypter) {
+ framer_.SetDecrypter(decrypter);
+}
+
+void QuicConnection::SetAlternativeDecrypter(QuicDecrypter* decrypter,
+ bool latch_once_used) {
+ framer_.SetAlternativeDecrypter(decrypter, latch_once_used);
}
-void QuicConnection::PushDecrypter(QuicDecrypter* decrypter) {
- framer_.push_decrypter(decrypter);
+const QuicDecrypter* QuicConnection::decrypter() const {
+ return framer_.decrypter();
}
-void QuicConnection::PopDecrypter() {
- framer_.pop_decrypter();
+const QuicDecrypter* QuicConnection::alternative_decrypter() const {
+ return framer_.alternative_decrypter();
}
void QuicConnection::MaybeProcessRevivedPacket() {
@@ -1208,7 +1240,8 @@ void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
serialized_packet.sequence_number,
serialized_packet.entropy_hash);
- WritePacket(serialized_packet.sequence_number,
+ WritePacket(encryption_level_,
+ serialized_packet.sequence_number,
serialized_packet.packet,
serialized_packet.retransmittable_frames != NULL ?
HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA,
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 2845dbec..5e916f8 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -345,26 +345,32 @@ class NET_EXPORT_PRIVATE QuicConnection
// should next fire, or 0 if no retransmission alarm should be set.
QuicTime OnRetransmissionTimeout();
- // Changes the encrypter used by |framer_| to |encrypter|. The function
+ // Changes the encrypter used for level |level| to |encrypter|. The function
// takes ownership of |encrypter|.
- void ChangeEncrypter(QuicEncrypter* encrypter);
-
- // Sets the primary decrypter used by |framer_| to |decrypter|. The current
- // primary decrypter becomes the backup decrypter. The function takes
- // ownership of |decrypter|.
- //
- // After the function is called, |framer_| starts to decrypt packets using
- // |decrypter|. If the decryption fails, |framer_| falls back on the backup
- // decrypter. Eventually |framer_| determines that the backup decrypter is
- // no longer needed and deletes it.
- void PushDecrypter(QuicDecrypter* decrypter);
-
- // Deletes the current primary decrypter and promotes the backup decrypter
- // to be the primary decrypter.
- void PopDecrypter();
-
- QuicDecrypter* decrypter() const { return framer_.decrypter(); }
- QuicEncrypter* encrypter() const { return framer_.encrypter(); }
+ void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
+ const QuicEncrypter* encrypter(EncryptionLevel level) const;
+
+ // SetDefaultEncryptionLevel sets the encryption level that will be applied
+ // to new packets.
+ void SetDefaultEncryptionLevel(EncryptionLevel level);
+
+ // SetDecrypter sets the primary decrypter, replacing any that already exists,
+ // and takes ownership. If an alternative decrypter is in place then the
+ // function DCHECKs. This is intended for cases where one knows that future
+ // packets will be using the new decrypter and the previous decrypter is now
+ // obsolete.
+ void SetDecrypter(QuicDecrypter* decrypter);
+
+ // SetAlternativeDecrypter sets a decrypter that may be used to decrypt
+ // future packets and takes ownership of it. If |latch_once_used| is true,
+ // then the first time that the decrypter is successful it will replace the
+ // primary decrypter. Otherwise both decrypters will remain active and the
+ // primary decrypter will be the one last used.
+ void SetAlternativeDecrypter(QuicDecrypter* decrypter,
+ bool latch_once_used);
+
+ const QuicDecrypter* decrypter() const;
+ const QuicDecrypter* alternative_decrypter() const;
protected:
// Deletes all missing packets before least unacked. The connection won't
@@ -373,27 +379,29 @@ class NET_EXPORT_PRIVATE QuicConnection
// |least_unacked| unacked, false otherwise.
bool DontWaitForPacketsBefore(QuicPacketSequenceNumber least_unacked);
- // Send a packet to the peer. If |sequence_number| is present in the
- // |retransmission_map_|, then contents of this packet will be retransmitted
- // with a new sequence number if it's not acked by the peer. Deletes
- // |packet| via WritePacket call or transfers ownership to QueuedPacket,
- // ultimately deleted via WritePacket. Also, it updates the entropy map
- // corresponding to |sequence_number| using |entropy_hash|.
+ // Send a packet to the peer using encryption |level|. If |sequence_number|
+ // is present in the |retransmission_map_|, then contents of this packet will
+ // be retransmitted with a new sequence number if it's not acked by the peer.
+ // Deletes |packet| via WritePacket call or transfers ownership to
+ // QueuedPacket, ultimately deleted via WritePacket. Also, it updates the
+ // entropy map corresponding to |sequence_number| using |entropy_hash|.
// TODO(wtc): none of the callers check the return value.
- virtual bool SendOrQueuePacket(QuicPacketSequenceNumber sequence_number,
+ virtual bool SendOrQueuePacket(EncryptionLevel level,
+ QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
QuicPacketEntropyHash entropy_hash,
HasRetransmittableData retransmittable);
- // Writes the given packet to socket with the help of helper. Returns true on
- // successful write, false otherwise. However, behavior is undefined if
- // connection is not established or broken. In any circumstances, a return
- // value of true implies that |packet| has been deleted and should not be
- // accessed. If |sequence_number| is present in |retransmission_map_| it also
- // sets up retransmission of the given packet in case of successful write. If
- // |force| is FORCE, then the packet will be sent immediately and the send
- // scheduler will not be consulted.
- bool WritePacket(QuicPacketSequenceNumber sequence_number,
+ // Writes the given packet to socket, encrypted with |level|, with the help
+ // of helper. Returns true on successful write, false otherwise. However,
+ // behavior is undefined if connection is not established or broken. In any
+ // circumstances, a return value of true implies that |packet| has been
+ // deleted and should not be accessed. If |sequence_number| is present in
+ // |retransmission_map_| it also sets up retransmission of the given packet
+ // in case of successful write. If |force| is FORCE, then the packet will be
+ // sent immediately and the send scheduler will not be consulted.
+ bool WritePacket(EncryptionLevel level,
+ QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
HasRetransmittableData retransmittable,
Force force);
@@ -420,14 +428,17 @@ class NET_EXPORT_PRIVATE QuicConnection
struct QueuedPacket {
QueuedPacket(QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
+ EncryptionLevel level,
HasRetransmittableData retransmittable)
: sequence_number(sequence_number),
packet(packet),
+ encryption_level(level),
retransmittable(retransmittable) {
}
QuicPacketSequenceNumber sequence_number;
QuicPacket* packet;
+ const EncryptionLevel encryption_level;
HasRetransmittableData retransmittable;
};
@@ -498,6 +509,7 @@ class NET_EXPORT_PRIVATE QuicConnection
scoped_ptr<QuicConnectionHelperInterface> helper_;
QuicFramer framer_;
+ EncryptionLevel encryption_level_;
const QuicClock* clock_;
QuicRandom* random_generator_;
diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc
index 1bddba2..3576981 100644
--- a/net/quic/quic_connection_helper_test.cc
+++ b/net/quic/quic_connection_helper_test.cc
@@ -59,11 +59,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
QuicConnectionHelperTest()
: guid_(2),
- framer_(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false),
+ framer_(kQuicVersion1, QuicTime::Zero(), false),
net_log_(BoundNetLog()),
frame_(1, false, 0, kData) {
Initialize();
@@ -152,7 +148,8 @@ class QuicConnectionHelperTest : public ::testing::Test {
frames.push_back(QuicFrame(&feedback));
scoped_ptr<QuicPacket> packet(
framer_.ConstructFrameDataPacket(header_, frames).packet);
- return framer_.EncryptPacket(header_.packet_sequence_number, *packet);
+ return framer_.EncryptPacket(
+ ENCRYPTION_NONE, header_.packet_sequence_number, *packet);
}
// Returns a newly created packet to send a connection close frame.
@@ -200,7 +197,8 @@ class QuicConnectionHelperTest : public ::testing::Test {
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
framer_.ConstructFrameDataPacket(header_, frames).packet);
- return framer_.EncryptPacket(header_.packet_sequence_number, *packet);
+ return framer_.EncryptPacket(
+ ENCRYPTION_NONE, header_.packet_sequence_number, *packet);
}
QuicGuid guid_;
@@ -413,7 +411,8 @@ TEST_F(QuicConnectionHelperTest, SendSchedulerDelayThenSend) {
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
QuicPacket* packet = ConstructRawDataPacket(1);
- connection_->SendOrQueuePacket(1, packet, 0, HAS_RETRANSMITTABLE_DATA);
+ connection_->SendOrQueuePacket(
+ ENCRYPTION_NONE, 1, packet, 0, HAS_RETRANSMITTABLE_DATA);
EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
EXPECT_EQ(1u, connection_->NumQueuedPackets());
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index e4b4400..e81e011 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -4,6 +4,7 @@
#include "net/quic/quic_connection.h"
+#include "base/basictypes.h"
#include "base/bind.h"
#include "net/base/net_errors.h"
#include "net/quic/congestion_control/receive_algorithm_interface.h"
@@ -72,6 +73,131 @@ class TestReceiveAlgorithm : public ReceiveAlgorithmInterface {
DISALLOW_COPY_AND_ASSIGN(TestReceiveAlgorithm);
};
+// TaggingEncrypter appends 16 bytes of |tag| to the end of each message.
+class TaggingEncrypter : public QuicEncrypter {
+ public:
+ explicit TaggingEncrypter(uint8 tag)
+ : tag_(tag) {
+ }
+
+ virtual ~TaggingEncrypter() {}
+
+ // QuicEncrypter interface.
+ virtual bool SetKey(StringPiece key) OVERRIDE { return true; }
+ virtual bool SetNoncePrefix(StringPiece nonce_prefix) OVERRIDE {
+ return true;
+ }
+
+ virtual bool Encrypt(StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece plaintext,
+ unsigned char* output) OVERRIDE {
+ memcpy(output, plaintext.data(), plaintext.size());
+ output += plaintext.size();
+ memset(output, tag_, kTagSize);
+ return true;
+ }
+
+ virtual QuicData* EncryptPacket(QuicPacketSequenceNumber sequence_number,
+ StringPiece associated_data,
+ StringPiece plaintext) OVERRIDE {
+ const size_t len = plaintext.size() + kTagSize;
+ uint8* buffer = new uint8[len];
+ Encrypt(StringPiece(), associated_data, plaintext, buffer);
+ return new QuicData(reinterpret_cast<char*>(buffer), len, true);
+ }
+
+ virtual size_t GetKeySize() const OVERRIDE { return 0; }
+ virtual size_t GetNoncePrefixSize() const OVERRIDE { return 0; }
+
+ virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const OVERRIDE {
+ return ciphertext_size - kTagSize;
+ }
+
+ virtual size_t GetCiphertextSize(size_t plaintext_size) const OVERRIDE {
+ return plaintext_size + kTagSize;
+ }
+
+ virtual StringPiece GetKey() const OVERRIDE {
+ return StringPiece();
+ }
+
+ virtual StringPiece GetNoncePrefix() const OVERRIDE {
+ return StringPiece();
+ }
+
+ private:
+ enum {
+ kTagSize = 16,
+ };
+
+ const uint8 tag_;
+};
+
+// TaggingDecrypter ensures that the final 16 bytes of the message all have the
+// same value and then removes them.
+class TaggingDecrypter : public QuicDecrypter {
+ public:
+ virtual ~TaggingDecrypter() {}
+
+ // QuicDecrypter interface
+ virtual bool SetKey(StringPiece key) OVERRIDE { return true; }
+ virtual bool SetNoncePrefix(StringPiece nonce_prefix) OVERRIDE {
+ return true;
+ }
+
+ virtual bool Decrypt(StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece ciphertext,
+ unsigned char* output,
+ size_t* output_length) OVERRIDE {
+ if (ciphertext.size() < kTagSize) {
+ return false;
+ }
+ if (!CheckTag(ciphertext)) {
+ return false;
+ }
+ *output_length = ciphertext.size() - kTagSize;
+ memcpy(output, ciphertext.data(), *output_length);
+ return true;
+ }
+
+ virtual QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number,
+ StringPiece associated_data,
+ StringPiece ciphertext) OVERRIDE {
+ if (ciphertext.size() < kTagSize) {
+ return NULL;
+ }
+ if (!CheckTag(ciphertext)) {
+ return NULL;
+ }
+ const size_t len = ciphertext.size() - kTagSize;
+ uint8* buf = new uint8[len];
+ memcpy(buf, ciphertext.data(), len);
+ return new QuicData(reinterpret_cast<char*>(buf), len,
+ true /* owns buffer */);
+ }
+
+ virtual StringPiece GetKey() const OVERRIDE { return StringPiece(); }
+ virtual StringPiece GetNoncePrefix() const OVERRIDE { return StringPiece(); }
+
+ private:
+ enum {
+ kTagSize = 16,
+ };
+
+ bool CheckTag(StringPiece ciphertext) {
+ uint8 tag = ciphertext.data()[ciphertext.size()-1];
+ for (size_t i = ciphertext.size() - kTagSize; i < ciphertext.size(); i++) {
+ if (ciphertext.data()[i] != tag) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
class TestConnectionHelper : public QuicConnectionHelperInterface {
public:
TestConnectionHelper(MockClock* clock, MockRandom* random_generator)
@@ -82,7 +208,8 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
QuicTime::Delta::FromMilliseconds(1))),
timeout_alarm_(QuicTime::Zero()),
blocked_(false),
- is_server_(true) {
+ is_server_(true),
+ use_tagging_decrypter_(false) {
}
// QuicConnectionHelperInterface
@@ -98,11 +225,15 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
virtual int WritePacketToWire(const QuicEncryptedPacket& packet,
int* error) OVERRIDE {
- QuicFramer framer(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- is_server_);
+ if (packet.length() >= sizeof(final_bytes_of_last_packet_)) {
+ memcpy(&final_bytes_of_last_packet_, packet.data() + packet.length() - 4,
+ sizeof(final_bytes_of_last_packet_));
+ }
+
+ QuicFramer framer(kQuicVersion1, QuicTime::Zero(), is_server_);
+ if (use_tagging_decrypter_) {
+ framer.SetDecrypter(new TaggingDecrypter);
+ }
FramerVisitorCapturingFrames visitor;
framer.set_visitor(&visitor);
EXPECT_TRUE(framer.ProcessPacket(packet));
@@ -192,6 +323,16 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
void set_is_server(bool is_server) { is_server_ = is_server; }
+ // final_bytes_of_last_packet_ returns the last four bytes of the previous
+ // packet as a little-endian, uint32. This is intended to be used with a
+ // TaggingEncrypter so that tests can determine which encrypter was used for
+ // a given packet.
+ uint32 final_bytes_of_last_packet() { return final_bytes_of_last_packet_; }
+
+ void use_tagging_decrypter() {
+ use_tagging_decrypter_ = true;
+ }
+
private:
MockClock* clock_;
MockRandom* random_generator_;
@@ -207,6 +348,8 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
size_t last_packet_size_;
bool blocked_;
bool is_server_;
+ uint32 final_bytes_of_last_packet_;
+ bool use_tagging_decrypter_;
DISALLOW_COPY_AND_ASSIGN(TestConnectionHelper);
};
@@ -266,11 +409,7 @@ class QuicConnectionTest : public ::testing::Test {
protected:
QuicConnectionTest()
: guid_(42),
- framer_(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false),
+ framer_(kQuicVersion1, QuicTime::Zero(), false),
creator_(guid_, &framer_, QuicRandom::GetInstance(), false),
send_algorithm_(new StrictMock<MockSendAlgorithm>),
helper_(new TestConnectionHelper(&clock_, &random_generator_)),
@@ -309,6 +448,14 @@ class QuicConnectionTest : public ::testing::Test {
return helper_->last_packet_size();
}
+ uint32 final_bytes_of_last_packet() {
+ return helper_->final_bytes_of_last_packet();
+ }
+
+ void use_tagging_decrypter() {
+ helper_->use_tagging_decrypter();
+ }
+
void ProcessPacket(QuicPacketSequenceNumber number) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _))
.WillOnce(Return(accept_packet_));
@@ -323,7 +470,8 @@ class QuicConnectionTest : public ::testing::Test {
SerializedPacket serialized_packet = creator_.SerializeAllFrames(frames);
scoped_ptr<QuicPacket> packet(serialized_packet.packet);
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer_.EncryptPacket(serialized_packet.sequence_number, *packet));
+ framer_.EncryptPacket(ENCRYPTION_NONE,
+ serialized_packet.sequence_number, *packet));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
return serialized_packet.entropy_hash;
}
@@ -345,8 +493,8 @@ class QuicConnectionTest : public ::testing::Test {
bool entropy_flag) {
scoped_ptr<QuicPacket> packet(ConstructDataPacket(number, fec_group,
entropy_flag));
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(number,
- *packet));
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ ENCRYPTION_NONE, number, *packet));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
return encrypted->length();
}
@@ -354,8 +502,8 @@ class QuicConnectionTest : public ::testing::Test {
void ProcessClosePacket(QuicPacketSequenceNumber number,
QuicFecGroupNumber fec_group) {
scoped_ptr<QuicPacket> packet(ConstructClosePacket(number, fec_group));
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(number,
- *packet));
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ ENCRYPTION_NONE, number, *packet));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
@@ -409,7 +557,7 @@ class QuicConnectionTest : public ::testing::Test {
scoped_ptr<QuicPacket> fec_packet(
framer_.ConstructFecPacket(header_, fec_data).packet);
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer_.EncryptPacket(number, *fec_packet));
+ framer_.EncryptPacket(ENCRYPTION_NONE, number, *fec_packet));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
return encrypted->length();
@@ -1150,6 +1298,41 @@ TEST_F(QuicConnectionTest, TestRetransmit) {
EXPECT_EQ(2u, outgoing_ack()->sent_info.least_unacked);
}
+TEST_F(QuicConnectionTest, RetransmitWithSameEncryptionLevel) {
+ const QuicTime::Delta kDefaultRetransmissionTime =
+ QuicTime::Delta::FromMilliseconds(500);
+
+ QuicTime default_retransmission_time = clock_.ApproximateNow().Add(
+ 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.
+ connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
+ SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
+ EXPECT_EQ(0x01010101u, final_bytes_of_last_packet());
+
+ connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
+ EXPECT_EQ(0x02020202u, final_bytes_of_last_packet());
+
+ EXPECT_EQ(default_retransmission_time, helper_->retransmission_alarm());
+ // Simulate the retransimission alarm firing
+ clock_.AdvanceTime(kDefaultRetransmissionTime);
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2);
+
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ connection_.RetransmitPacket(1);
+ // Packet should have been sent with ENCRYPTION_NONE.
+ EXPECT_EQ(0x01010101u, final_bytes_of_last_packet());
+
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ connection_.RetransmitPacket(2);
+ // Packet should have been sent with ENCRYPTION_INITIAL.
+ EXPECT_EQ(0x02020202u, final_bytes_of_last_packet());
+}
+
TEST_F(QuicConnectionTest, TestRetransmitOrder) {
QuicByteCount first_packet_size;
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce(
@@ -1355,7 +1538,7 @@ TEST_F(QuicConnectionTest, SendScheduler) {
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
connection_.SendOrQueuePacket(
- 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
@@ -1367,7 +1550,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelay) {
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
connection_.SendOrQueuePacket(
- 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
@@ -1378,7 +1561,7 @@ TEST_F(QuicConnectionTest, SendSchedulerForce) {
TimeUntilSend(_, IS_RETRANSMISSION, _)).Times(0);
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
connection_.SendOrQueuePacket(
- 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
// XXX: fixme. was: connection_.SendOrQueuePacket(1, packet, kForce);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
@@ -1391,7 +1574,7 @@ TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) {
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
connection_.SendOrQueuePacket(
- 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
@@ -1402,7 +1585,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) {
TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
connection_.SendOrQueuePacket(
- 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Advance the clock to fire the alarm, and configure the scheduler
@@ -1457,13 +1640,13 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) {
TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
connection_.SendOrQueuePacket(
- 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Attempt to send another packet and make sure that it gets queued.
packet = ConstructDataPacket(2, 0, !kEntropyFlag);
connection_.SendOrQueuePacket(
- 2, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 2, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(2u, connection_.NumQueuedPackets());
}
@@ -1473,7 +1656,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
connection_.SendOrQueuePacket(
- 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Now send non-retransmitting information, that we're not going to
@@ -1498,7 +1681,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
connection_.SendOrQueuePacket(
- 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Now send non-retransmitting information, that we're not going to
@@ -1518,7 +1701,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) {
TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
connection_.SendOrQueuePacket(
- 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// OnCanWrite should not send the packet (because of the delay)
@@ -1570,7 +1753,7 @@ TEST_F(QuicConnectionTest, SendWhenDisconnected) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
connection_.SendOrQueuePacket(
- 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
}
TEST_F(QuicConnectionTest, PublicReset) {
@@ -1689,7 +1872,8 @@ TEST_F(QuicConnectionTest, CheckSentEntropyHash) {
}
QuicPacket* packet = ConstructDataPacket(i, 0, entropy_flag);
connection_.SendOrQueuePacket(
- i, packet, packet_entropy_hash, HAS_RETRANSMITTABLE_DATA);
+ ENCRYPTION_NONE, i, packet, packet_entropy_hash,
+ HAS_RETRANSMITTABLE_DATA);
if (is_missing) {
missing_packets.insert(i);
@@ -1723,7 +1907,8 @@ TEST_F(QuicConnectionTest, SendVersionNegotiationPacket) {
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
framer_.ConstructFrameDataPacket(header, frames).packet);
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(12, *packet));
+ scoped_ptr<QuicEncryptedPacket> encrypted(
+ framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
QuicFramerPeer::SetVersion(&framer_, kQuicVersion1);
connection_.set_is_server(true);
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 97b2b78..03b5c28 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -6,6 +6,7 @@
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_utils.h"
+#include "net/quic/crypto/null_encrypter.h"
#include "net/quic/crypto/proof_verifier.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_session.h"
@@ -22,7 +23,6 @@ QuicCryptoClientStream::QuicCryptoClientStream(
num_client_hellos_(0),
config_(config),
crypto_config_(crypto_config),
- decrypter_pushed_(false),
server_hostname_(server_hostname) {
}
@@ -118,9 +118,24 @@ void QuicCryptoClientStream::DoHandshakeLoop(
DLOG(INFO) << "Client Sending: " << out.DebugString();
SendHandshakeMessage(out);
// Be prepared to decrypt with the new server write key.
- session()->connection()->PushDecrypter(
- crypto_negotiated_params_.decrypter.release());
- decrypter_pushed_ = true;
+ session()->connection()->SetAlternativeDecrypter(
+ crypto_negotiated_params_.decrypter.release(),
+ true /* latch once used */);
+ // Send subsequent packets under encryption on the assumption that the
+ // server will accept the handshake.
+ session()->connection()->SetEncrypter(
+ ENCRYPTION_INITIAL,
+ crypto_negotiated_params_.encrypter.release());
+ session()->connection()->SetDefaultEncryptionLevel(
+ ENCRYPTION_INITIAL);
+ if (!encryption_established_) {
+ session()->OnCryptoHandshakeEvent(
+ QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
+ encryption_established_ = true;
+ } else {
+ session()->OnCryptoHandshakeEvent(
+ QuicSession::ENCRYPTION_REESTABLISHED);
+ }
return;
}
case STATE_RECV_REJ:
@@ -160,11 +175,9 @@ void QuicCryptoClientStream::DoHandshakeLoop(
cached->SetProofValid();
}
}
- // Clear any new server write key that we may have set before.
- if (decrypter_pushed_) {
- session()->connection()->PopDecrypter();
- decrypter_pushed_ = false;
- }
+ // Send the subsequent client hello in plaintext.
+ session()->connection()->SetDefaultEncryptionLevel(
+ ENCRYPTION_NONE);
next_state_ = STATE_SEND_CHLO;
break;
case STATE_RECV_SHLO:
@@ -179,15 +192,10 @@ void QuicCryptoClientStream::DoHandshakeLoop(
"Expected SHLO or REJ");
return;
}
- // Receiving SHLO implies the server must have processed our full
- // CHLO and is ready to decrypt with the new client write key. We
- // can start to encrypt with the new client write key.
- // TODO(wtc): when we support 0-RTT, we will need to change the
- // encrypter when we send a full CHLO because we will be sending
- // application data immediately after.
- session()->connection()->ChangeEncrypter(
- crypto_negotiated_params_.encrypter.release());
- SetHandshakeComplete(QUIC_NO_ERROR);
+ // TODO(agl): enable this once the tests are corrected to permit it.
+ // DCHECK(session()->connection()->alternative_decrypter() == NULL);
+ handshake_confirmed_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
return;
case STATE_IDLE:
// This means that the peer sent us a message that we weren't expecting.
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h
index 3381c8a..740c892 100644
--- a/net/quic/quic_crypto_client_stream.h
+++ b/net/quic/quic_crypto_client_stream.h
@@ -70,12 +70,6 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
QuicNegotiatedParameters negotiated_params_;
QuicCryptoNegotiatedParameters crypto_negotiated_params_;
- // decrypter_pushed_ is true if we have installed a QuicDecrypter in the
- // connection. We need to track this because, in the event of a handshake
- // failure, we have to remove any previous decrypters as they will have the
- // wrong keys.
- bool decrypter_pushed_;
-
// Client's connection nonce (4-byte timestamp + 28 random bytes)
std::string nonce_;
// Server's hostname
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index a840c3c..96547e42 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -98,7 +98,8 @@ TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
return;
}
- EXPECT_FALSE(stream_.handshake_complete());
+ EXPECT_FALSE(stream_.encryption_established());
+ EXPECT_FALSE(stream_.handshake_confirmed());
}
TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
@@ -108,7 +109,8 @@ TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
}
CompleteCryptoHandshake();
- EXPECT_TRUE(stream_.handshake_complete());
+ EXPECT_TRUE(stream_.encryption_established());
+ EXPECT_TRUE(stream_.handshake_confirmed());
}
TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 5fa33e1..1dab72f 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -27,8 +27,8 @@ QuicCryptoServerStream::~QuicCryptoServerStream() {
void QuicCryptoServerStream::OnHandshakeMessage(
const CryptoHandshakeMessage& message) {
- // Do not process handshake messages after the handshake is complete.
- if (handshake_complete()) {
+ // Do not process handshake messages after the handshake is confirmed.
+ if (handshake_confirmed_) {
CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
return;
}
@@ -62,13 +62,18 @@ void QuicCryptoServerStream::OnHandshakeMessage(
// write key.
//
// NOTE: the SHLO will be encrypted with the new server write key.
- session()->connection()->ChangeEncrypter(
+ session()->connection()->SetEncrypter(
+ ENCRYPTION_INITIAL,
crypto_negotiated_params_.encrypter.release());
- // Be prepared to decrypt with the new client write key, as the client
- // will start to use it upon receiving the SHLO.
- session()->connection()->PushDecrypter(
+ session()->connection()->SetDefaultEncryptionLevel(
+ ENCRYPTION_INITIAL);
+ // Set the decrypter immediately so that we no longer accept unencrypted
+ // packets.
+ session()->connection()->SetDecrypter(
crypto_negotiated_params_.decrypter.release());
- SetHandshakeComplete(QUIC_NO_ERROR);
+ encryption_established_ = true;
+ handshake_confirmed_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
}
SendHandshakeMessage(reply);
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index 50fc2ca..2cc2746 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -115,7 +115,8 @@ TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) {
return;
}
- EXPECT_FALSE(stream_.handshake_complete());
+ EXPECT_FALSE(stream_.encryption_established());
+ EXPECT_FALSE(stream_.handshake_confirmed());
}
TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
@@ -133,7 +134,8 @@ TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
// have sent the following client hello.
// * One to get the server's certificates
EXPECT_EQ(2, CompleteCryptoHandshake());
- EXPECT_TRUE(stream_.handshake_complete());
+ EXPECT_TRUE(stream_.encryption_established());
+ EXPECT_TRUE(stream_.handshake_confirmed());
}
TEST_F(QuicCryptoServerStreamTest, ZeroRTT) {
diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc
index 9167e6f..df6c610 100644
--- a/net/quic/quic_crypto_stream.cc
+++ b/net/quic/quic_crypto_stream.cc
@@ -18,7 +18,8 @@ namespace net {
QuicCryptoStream::QuicCryptoStream(QuicSession* session)
: ReliableQuicStream(kCryptoStreamId, session),
- handshake_complete_(false) {
+ encryption_established_(false),
+ handshake_confirmed_(false) {
crypto_framer_.set_visitor(this);
}
@@ -28,8 +29,8 @@ void QuicCryptoStream::OnError(CryptoFramer* framer) {
uint32 QuicCryptoStream::ProcessData(const char* data,
uint32 data_len) {
- // Do not process handshake messages after the handshake is complete.
- if (handshake_complete()) {
+ // Do not process handshake messages after the handshake is confirmed.
+ if (handshake_confirmed()) {
CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
return 0;
}
@@ -49,11 +50,6 @@ void QuicCryptoStream::CloseConnectionWithDetails(QuicErrorCode error,
session()->connection()->SendConnectionCloseWithDetails(error, details);
}
-void QuicCryptoStream::SetHandshakeComplete(QuicErrorCode error) {
- handshake_complete_ = true;
- session()->OnCryptoHandshakeComplete(error);
-}
-
void QuicCryptoStream::SendHandshakeMessage(
const CryptoHandshakeMessage& message) {
const QuicData& data = message.GetSerialized();
diff --git a/net/quic/quic_crypto_stream.h b/net/quic/quic_crypto_stream.h
index b43cb38..db83503 100644
--- a/net/quic/quic_crypto_stream.h
+++ b/net/quic/quic_crypto_stream.h
@@ -42,18 +42,19 @@ class NET_EXPORT_PRIVATE QuicCryptoStream
// TODO(wtc): return a success/failure status.
void SendHandshakeMessage(const CryptoHandshakeMessage& message);
- bool handshake_complete() { return handshake_complete_; }
+ bool encryption_established() { return encryption_established_; }
+ bool handshake_confirmed() { return handshake_confirmed_; }
protected:
// Closes the connection
void CloseConnection(QuicErrorCode error);
void CloseConnectionWithDetails(QuicErrorCode error, const string& details);
- void SetHandshakeComplete(QuicErrorCode error);
+ bool encryption_established_;
+ bool handshake_confirmed_;
private:
CryptoFramer crypto_framer_;
- bool handshake_complete_;
DISALLOW_COPY_AND_ASSIGN(QuicCryptoStream);
};
diff --git a/net/quic/quic_crypto_stream_test.cc b/net/quic/quic_crypto_stream_test.cc
index 8f8028b..6e465ab 100644
--- a/net/quic/quic_crypto_stream_test.cc
+++ b/net/quic/quic_crypto_stream_test.cc
@@ -74,7 +74,8 @@ class QuicCryptoStreamTest : public ::testing::Test {
};
TEST_F(QuicCryptoStreamTest, NotInitiallyConected) {
- EXPECT_FALSE(stream_.handshake_complete());
+ EXPECT_FALSE(stream_.encryption_established());
+ EXPECT_FALSE(stream_.handshake_confirmed());
}
TEST_F(QuicCryptoStreamTest, OnErrorClosesConnection) {
@@ -97,7 +98,7 @@ TEST_F(QuicCryptoStreamTest, ProcessData) {
TEST_F(QuicCryptoStreamTest, ProcessBadData) {
string bad(message_data_->data(), message_data_->length());
- bad[6] = 0x7F; // out of order tag
+ bad[8] = 0x7F; // out of order tag
EXPECT_CALL(*connection_,
SendConnectionClose(QUIC_CRYPTO_TAGS_OUT_OF_ORDER));
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index fafd2e3..70084a5 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -46,8 +46,6 @@ QuicPacketSequenceNumber ClosestTo(QuicPacketSequenceNumber target,
} // namespace
QuicFramer::QuicFramer(QuicVersionTag version,
- QuicDecrypter* decrypter,
- QuicEncrypter* encrypter,
QuicTime creation_time,
bool is_server)
: visitor_(NULL),
@@ -55,11 +53,11 @@ QuicFramer::QuicFramer(QuicVersionTag version,
error_(QUIC_NO_ERROR),
last_sequence_number_(0),
quic_version_(version),
- decrypter_(decrypter),
- encrypter_(encrypter),
+ decrypter_(QuicDecrypter::Create(kNULL)),
is_server_(is_server),
creation_time_(creation_time) {
DCHECK(IsSupportedVersion(version));
+ encrypter_[ENCRYPTION_NONE].reset(QuicEncrypter::Create(kNULL));
}
QuicFramer::~QuicFramer() {}
@@ -1037,27 +1035,47 @@ StringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket(
kStartOfHashData);
}
-void QuicFramer::push_decrypter(QuicDecrypter* decrypter) {
- DCHECK(backup_decrypter_.get() == NULL);
- backup_decrypter_.reset(decrypter_.release());
+void QuicFramer::SetDecrypter(QuicDecrypter* decrypter) {
+ DCHECK(alternative_decrypter_.get() == NULL);
decrypter_.reset(decrypter);
}
-void QuicFramer::pop_decrypter() {
- DCHECK(backup_decrypter_.get() != NULL);
- decrypter_.reset(backup_decrypter_.release());
+void QuicFramer::SetAlternativeDecrypter(QuicDecrypter* decrypter,
+ bool latch_once_used) {
+ alternative_decrypter_.reset(decrypter);
+ alternative_decrypter_latch_ = latch_once_used;
}
-void QuicFramer::set_encrypter(QuicEncrypter* encrypter) {
- encrypter_.reset(encrypter);
+const QuicDecrypter* QuicFramer::decrypter() const {
+ return decrypter_.get();
+}
+
+const QuicDecrypter* QuicFramer::alternative_decrypter() const {
+ return alternative_decrypter_.get();
+}
+
+void QuicFramer::SetEncrypter(EncryptionLevel level,
+ QuicEncrypter* encrypter) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, NUM_ENCRYPTION_LEVELS);
+ encrypter_[level].reset(encrypter);
+}
+
+const QuicEncrypter* QuicFramer::encrypter(EncryptionLevel level) const {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, NUM_ENCRYPTION_LEVELS);
+ DCHECK(encrypter_[level].get() != NULL);
+ return encrypter_[level].get();
}
QuicEncryptedPacket* QuicFramer::EncryptPacket(
+ EncryptionLevel level,
QuicPacketSequenceNumber packet_sequence_number,
const QuicPacket& packet) {
- scoped_ptr<QuicData> out(encrypter_->EncryptPacket(packet_sequence_number,
- packet.AssociatedData(),
- packet.Plaintext()));
+ DCHECK(encrypter_[level].get() != NULL);
+
+ scoped_ptr<QuicData> out(encrypter_[level]->EncryptPacket(
+ packet_sequence_number, packet.AssociatedData(), packet.Plaintext()));
if (out.get() == NULL) {
RaiseError(QUIC_ENCRYPTION_FAILURE);
return NULL;
@@ -1072,7 +1090,22 @@ QuicEncryptedPacket* QuicFramer::EncryptPacket(
}
size_t QuicFramer::GetMaxPlaintextSize(size_t ciphertext_size) {
- return encrypter_->GetMaxPlaintextSize(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.
+ size_t min_plaintext_size = ciphertext_size;
+
+ for (int i = ENCRYPTION_NONE; i <= ENCRYPTION_FORWARD_SECURE; i++) {
+ if (encrypter_[i].get() != NULL) {
+ size_t size = encrypter_[i]->GetMaxPlaintextSize(ciphertext_size);
+ if (size < min_plaintext_size) {
+ min_plaintext_size = size;
+ }
+ }
+ }
+
+ return min_plaintext_size;
}
bool QuicFramer::DecryptPayload(QuicPacketSequenceNumber sequence_number,
@@ -1083,19 +1116,32 @@ bool QuicFramer::DecryptPayload(QuicPacketSequenceNumber sequence_number,
return false;
}
DCHECK(decrypter_.get() != NULL);
+ LOG(INFO) << "Decrypting packet";
decrypted_.reset(decrypter_->DecryptPacket(
sequence_number,
GetAssociatedDataFromEncryptedPacket(packet, version_flag),
encrypted));
- if (decrypted_.get() == NULL && backup_decrypter_.get() != NULL) {
- decrypted_.reset(backup_decrypter_->DecryptPacket(
+ if (decrypted_.get() == NULL && alternative_decrypter_.get() != NULL) {
+ LOG(INFO) << "Trying alternative";
+ decrypted_.reset(alternative_decrypter_->DecryptPacket(
sequence_number,
GetAssociatedDataFromEncryptedPacket(packet, version_flag),
encrypted));
+ if (decrypted_.get() != NULL) {
+ LOG(INFO) << "alternative ok";
+ if (alternative_decrypter_latch_) {
+ LOG(INFO) << " latching";
+ // Switch to the alternative decrypter and latch so that we cannot
+ // switch back.
+ decrypter_.reset(alternative_decrypter_.release());
+ } else {
+ LOG(INFO) << " swapping";
+ // Switch the alternative decrypter so that we use it first next time.
+ decrypter_.swap(alternative_decrypter_);
+ }
+ }
}
- // TODO(wtc): tell the caller or visitor which decrypter was used, so that
- // they can verify a packet that should be encrypted is encrypted.
- // TODO(wtc): figure out when it is safe to delete backup_decrypter_.
+
if (decrypted_.get() == NULL) {
return false;
}
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index ff5e4f8..1802fed 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -151,10 +151,9 @@ class NET_EXPORT_PRIVATE QuicReceivedEntropyHashCalculatorInterface {
// in order to generate FEC data for subsequently building FEC packets.
class NET_EXPORT_PRIVATE QuicFramer {
public:
- // Constructs a new framer that will own |decrypter| and |encrypter|.
+ // Constructs a new framer that installs a kNULL QuicEncrypter and
+ // QuicDecrypter for level ENCRYPTION_NONE.
QuicFramer(QuicVersionTag quic_version,
- QuicDecrypter* decrypter,
- QuicEncrypter* encrypter,
QuicTime creation_time,
bool is_server);
@@ -274,15 +273,32 @@ class NET_EXPORT_PRIVATE QuicFramer {
const QuicPacketPublicHeader& header,
const QuicVersionTagList& supported_versions);
- QuicDecrypter* decrypter() const { return decrypter_.get(); }
- void push_decrypter(QuicDecrypter* decrypter);
- void pop_decrypter();
-
- QuicEncrypter* encrypter() const { return encrypter_.get(); }
- void set_encrypter(QuicEncrypter* encrypter);
+ // SetDecrypter sets the primary decrypter, replacing any that already exists,
+ // and takes ownership. If an alternative decrypter is in place then the
+ // function DCHECKs. This is intended for cases where one knows that future
+ // packets will be using the new decrypter and the previous decrypter is not
+ // obsolete.
+ void SetDecrypter(QuicDecrypter* decrypter);
+
+ // SetAlternativeDecrypter sets a decrypter that may be used to decrypt
+ // future packets and takes ownership of it. If |latch_once_used| is true,
+ // then the first time that the decrypter is successful it will replace the
+ // primary decrypter. Otherwise both decrypters will remain active and the
+ // primary decrypter will be the one last used.
+ void SetAlternativeDecrypter(QuicDecrypter* decrypter,
+ bool latch_once_used);
+
+ const QuicDecrypter* decrypter() const;
+ const QuicDecrypter* alternative_decrypter() const;
+
+ // Changes the encrypter used for level |level| to |encrypter|. The function
+ // takes ownership of |encrypter|.
+ void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
+ const QuicEncrypter* encrypter(EncryptionLevel level) const;
// Returns a new encrypted packet, owned by the caller.
- QuicEncryptedPacket* EncryptPacket(QuicPacketSequenceNumber sequence_number,
+ QuicEncryptedPacket* EncryptPacket(EncryptionLevel level,
+ QuicPacketSequenceNumber sequence_number,
const QuicPacket& packet);
// Returns the maximum length of plaintext that can be encrypted
@@ -383,10 +399,14 @@ class NET_EXPORT_PRIVATE QuicFramer {
QuicVersionTag quic_version_;
// Primary decrypter used to decrypt packets during parsing.
scoped_ptr<QuicDecrypter> decrypter_;
- // Backup decrypter used to decrypt packets during parsing. May be NULL.
- scoped_ptr<QuicDecrypter> backup_decrypter_;
- // Encrypter used to encrypt packets via EncryptPacket().
- scoped_ptr<QuicEncrypter> encrypter_;
+ // Alternative decrypter that can also be used to decrypt packets.
+ scoped_ptr<QuicDecrypter> alternative_decrypter_;
+ // alternative_decrypter_latch_is true if, when |alternative_decrypter_|
+ // successfully decrypts a packet, we should install it as the only
+ // decrypter.
+ bool alternative_decrypter_latch_;
+ // Encrypters used to encrypt packets via EncryptPacket().
+ scoped_ptr<QuicEncrypter> encrypter_[NUM_ENCRYPTION_LEVELS];
// Tracks if the framer is being used by the entity that received the
// connection or the entity that initiated it.
bool is_server_;
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index ebb8cd0..6e2556c 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -279,7 +279,9 @@ class QuicFramerTest : public ::testing::Test {
: encrypter_(new test::TestEncrypter()),
decrypter_(new test::TestDecrypter()),
start_(QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(0x10))),
- framer_(kQuicVersion1, decrypter_, encrypter_, start_, true) {
+ framer_(kQuicVersion1, start_, true) {
+ framer_.SetDecrypter(decrypter_);
+ framer_.SetEncrypter(ENCRYPTION_NONE, encrypter_);
framer_.set_visitor(&visitor_);
framer_.set_entropy_calculator(&entropy_calculator_);
}
@@ -2453,7 +2455,7 @@ TEST_F(QuicFramerTest, EncryptPacket) {
QuicPacket::NewDataPacket(AsChars(packet), arraysize(packet), false,
!kIncludeVersion));
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer_.EncryptPacket(sequence_number, *raw));
+ framer_.EncryptPacket(ENCRYPTION_NONE, sequence_number, *raw));
ASSERT_TRUE(encrypted.get() != NULL);
EXPECT_TRUE(CheckEncryption(sequence_number, raw.get()));
@@ -2488,7 +2490,7 @@ TEST_F(QuicFramerTest, EncryptPacketWithVersionFlag) {
QuicPacket::NewDataPacket(AsChars(packet), arraysize(packet), false,
kIncludeVersion));
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer_.EncryptPacket(sequence_number, *raw));
+ framer_.EncryptPacket(ENCRYPTION_NONE, sequence_number, *raw));
ASSERT_TRUE(encrypted.get() != NULL);
EXPECT_TRUE(CheckEncryption(sequence_number, raw.get()));
@@ -2549,7 +2551,8 @@ TEST_F(QuicFramerTest, DISABLED_Truncation) {
ASSERT_TRUE(raw_ack_packet != NULL);
scoped_ptr<QuicEncryptedPacket> ack_packet(
- framer_.EncryptPacket(header.packet_sequence_number, *raw_ack_packet));
+ framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
+ *raw_ack_packet));
// Create a packet with just connection close.
frames.clear();
@@ -2562,7 +2565,8 @@ TEST_F(QuicFramerTest, DISABLED_Truncation) {
ASSERT_TRUE(raw_close_packet != NULL);
scoped_ptr<QuicEncryptedPacket> close_packet(
- framer_.EncryptPacket(header.packet_sequence_number, *raw_close_packet));
+ framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
+ *raw_close_packet));
// Now make sure we can turn our ack packet back into an ack frame
ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
@@ -2604,7 +2608,8 @@ TEST_F(QuicFramerTest, CleanTruncation) {
ASSERT_TRUE(raw_ack_packet != NULL);
scoped_ptr<QuicEncryptedPacket> ack_packet(
- framer_.EncryptPacket(header.packet_sequence_number, *raw_ack_packet));
+ framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
+ *raw_ack_packet));
// Create a packet with just connection close.
frames.clear();
@@ -2617,7 +2622,8 @@ TEST_F(QuicFramerTest, CleanTruncation) {
ASSERT_TRUE(raw_close_packet != NULL);
scoped_ptr<QuicEncryptedPacket> close_packet(
- framer_.EncryptPacket(header.packet_sequence_number, *raw_close_packet));
+ framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
+ *raw_close_packet));
// Now make sure we can turn our ack packet back into an ack frame
ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index e5bcdcc..3068d5f 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -118,11 +118,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
use_closing_stream_(false),
read_buffer_(new IOBufferWithSize(4096)),
guid_(2),
- framer_(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false),
+ framer_(kQuicVersion1, QuicTime::Zero(), false),
creator_(guid_, &framer_, &random_, false) {
IPAddressNumber ip;
CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
@@ -186,7 +182,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
"www.google.com", &crypto_config_,
NULL));
session_->GetCryptoStream()->CryptoConnect();
- EXPECT_TRUE(session_->IsCryptoHandshakeComplete());
+ EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
QuicReliableClientStream* stream =
session_->CreateOutgoingReliableStream();
stream_.reset(use_closing_stream_ ?
@@ -298,7 +294,8 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
framer_.ConstructFrameDataPacket(header_, frames).packet);
- return framer_.EncryptPacket(header.packet_sequence_number, *packet);
+ return framer_.EncryptPacket(
+ ENCRYPTION_NONE, header.packet_sequence_number, *packet);
}
const QuicGuid guid_;
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 240728b..3f7cf12 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -121,18 +121,14 @@ class QuicNetworkTransactionTest : public PlatformTest {
feedback.tcp.accumulated_number_of_lost_packets = 0;
feedback.tcp.receive_window = 256000;
- QuicFramer framer(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false);
+ QuicFramer framer(kQuicVersion1, QuicTime::Zero(), false);
QuicFrames frames;
frames.push_back(QuicFrame(&ack));
frames.push_back(QuicFrame(&feedback));
scoped_ptr<QuicPacket> packet(
framer.ConstructFrameDataPacket(header, frames).packet);
- return scoped_ptr<QuicEncryptedPacket>(
- framer.EncryptPacket(header.packet_sequence_number, *packet));
+ return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
+ ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
std::string GetRequestString(const std::string& method,
@@ -178,17 +174,13 @@ class QuicNetworkTransactionTest : public PlatformTest {
scoped_ptr<QuicEncryptedPacket> ConstructPacket(
const QuicPacketHeader& header,
const QuicFrame& frame) {
- QuicFramer framer(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false);
+ QuicFramer framer(kQuicVersion1, QuicTime::Zero(), false);
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
framer.ConstructFrameDataPacket(header, frames).packet);
- return scoped_ptr<QuicEncryptedPacket>(
- framer.EncryptPacket(header.packet_sequence_number, *packet));
+ return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
+ ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
void InitializeHeader(QuicPacketSequenceNumber sequence_number,
@@ -496,5 +488,69 @@ TEST_F(QuicNetworkTransactionTest, DontUseAlternateProtocolForQuicHttps) {
EXPECT_EQ("hello!", response_data);
}
+TEST_F(QuicNetworkTransactionTest, ZeroRTT) {
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::SetNextProtos(QuicNextProtos());
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.load_flags = 0;
+
+ scoped_ptr<QuicEncryptedPacket> data(
+ ConstructDataPacket(1, true, true, 0, GetRequestString("GET", "/")));
+ scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 0));
+
+ MockWrite quic_writes[] = {
+ MockWrite(SYNCHRONOUS, data->data(), data->length()),
+ MockWrite(SYNCHRONOUS, ack->data(), ack->length()),
+ };
+
+ scoped_ptr<QuicEncryptedPacket> resp(
+ ConstructDataPacket(
+ 1, false, true, 0, GetResponseString("200 OK", "hello!")));
+ MockRead quic_reads[] = {
+ MockRead(SYNCHRONOUS, resp->data(), resp->length()),
+ MockRead(ASYNC, OK), // EOF
+ };
+
+ DelayedSocketData quic_data(
+ 1, // wait for one write to finish before reading.
+ quic_reads, arraysize(quic_reads),
+ quic_writes, arraysize(quic_writes));
+
+ socket_factory_.AddSocketDataProvider(&quic_data);
+
+ TestCompletionCallback callback;
+
+ CreateSession();
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::ZERO_RTT);
+
+ HttpServerProperties* http_server_properties =
+ session_->http_server_properties();
+ http_server_properties->SetAlternateProtocol(
+ HostPortPair("www.google.com", 80), 80, QUIC);
+
+ scoped_ptr<HttpNetworkTransaction> trans(
+ new HttpNetworkTransaction(DEFAULT_PRIORITY, session_));
+
+ int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+ EXPECT_TRUE(response->was_npn_negotiated);
+ EXPECT_EQ("quic/1+spdy/3", response->npn_negotiated_protocol);
+
+ std::string response_data;
+ ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_EQ("hello!", response_data);
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 60d48d0..4fe4f18 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -30,16 +30,8 @@ namespace {
class QuicPacketCreatorTest : public ::testing::TestWithParam<bool> {
protected:
QuicPacketCreatorTest()
- : server_framer_(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- true),
- client_framer_(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false),
+ : server_framer_(kQuicVersion1, QuicTime::Zero(), true),
+ client_framer_(kQuicVersion1, QuicTime::Zero(), false),
id_(1),
sequence_number_(0),
guid_(2),
@@ -53,7 +45,8 @@ class QuicPacketCreatorTest : public ::testing::TestWithParam<bool> {
void ProcessPacket(QuicPacket* packet) {
scoped_ptr<QuicEncryptedPacket> encrypted(
- server_framer_.EncryptPacket(sequence_number_, *packet));
+ server_framer_.EncryptPacket(ENCRYPTION_NONE, sequence_number_,
+ *packet));
server_framer_.ProcessPacket(*encrypted);
}
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 4e84d0b..edf67e9 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -76,11 +76,7 @@ struct PacketContents {
class QuicPacketGeneratorTest : public ::testing::Test {
protected:
QuicPacketGeneratorTest()
- : framer_(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false),
+ : framer_(kQuicVersion1, QuicTime::Zero(), false),
creator_(42, &framer_, &random_, false),
generator_(&delegate_, &creator_),
packet_(0, NULL, 0, NULL),
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index faa5c78..27f980f 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -274,7 +274,9 @@ StringPiece QuicPacket::Plaintext() const {
length() - start_of_encrypted_data);
}
-RetransmittableFrames::RetransmittableFrames() {}
+RetransmittableFrames::RetransmittableFrames()
+ : encryption_level_(NUM_ENCRYPTION_LEVELS) {
+}
RetransmittableFrames::~RetransmittableFrames() {
for (QuicFrames::iterator it = frames_.begin(); it != frames_.end(); ++it) {
@@ -326,6 +328,10 @@ const QuicFrame& RetransmittableFrames::AddNonStreamFrame(
return frames_.back();
}
+void RetransmittableFrames::set_encryption_level(EncryptionLevel level) {
+ encryption_level_ = level;
+}
+
ostream& operator<<(ostream& os, const QuicEncryptedPacket& s) {
os << s.length() << "-byte data";
return os;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index d4f23de..efb2459 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -224,6 +224,8 @@ enum QuicErrorCode {
QUIC_CRYPTO_TOO_MANY_REJECTS,
// The client rejected the server's certificate chain or signature.
QUIC_PROOF_INVALID,
+ // A crypto message was received with a duplicate tag.
+ QUIC_CRYPTO_DUPLICATE_TAG,
// No error. Used as bound while iterating.
QUIC_LAST_ERROR,
@@ -461,6 +463,18 @@ struct NET_EXPORT_PRIVATE QuicGoAwayFrame {
std::string reason_phrase;
};
+// EncryptionLevel enumerates the stages of encryption that a QUIC connection
+// progresses through. When retransmitting a packet, the encryption level needs
+// to be specified so that it is retransmitted at a level which the peer can
+// understand.
+enum EncryptionLevel {
+ ENCRYPTION_NONE = 0,
+ ENCRYPTION_INITIAL = 1,
+ ENCRYPTION_FORWARD_SECURE = 2,
+
+ NUM_ENCRYPTION_LEVELS,
+};
+
struct NET_EXPORT_PRIVATE QuicFrame {
QuicFrame() {}
explicit QuicFrame(QuicPaddingFrame* padding_frame)
@@ -628,8 +642,14 @@ class NET_EXPORT_PRIVATE RetransmittableFrames {
const QuicFrame& AddNonStreamFrame(const QuicFrame& frame);
const QuicFrames& frames() const { return frames_; }
+ void set_encryption_level(EncryptionLevel level);
+ EncryptionLevel encryption_level() const {
+ return encryption_level_;
+ }
+
private:
QuicFrames frames_;
+ EncryptionLevel encryption_level_;
// Data referenced by the StringPiece of a QuicStreamFrame.
std::vector<std::string*> stream_data_;
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 8e9e411..35f764f 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -190,12 +190,15 @@ void QuicSession::CloseStream(QuicStreamId stream_id) {
stream->OnClose();
}
-bool QuicSession::IsCryptoHandshakeComplete() {
- return GetCryptoStream()->handshake_complete();
+bool QuicSession::IsEncryptionEstablished() {
+ return GetCryptoStream()->encryption_established();
}
-void QuicSession::OnCryptoHandshakeComplete(QuicErrorCode error) {
- // TODO(rch): tear down the connection if error != QUIC_NO_ERROR.
+bool QuicSession::IsCryptoHandshakeConfirmed() {
+ return GetCryptoStream()->handshake_confirmed();
+}
+
+void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
}
void QuicSession::ActivateStream(ReliableQuicStream* stream) {
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 963a53a..9d2d2b7 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -31,6 +31,23 @@ class QuicSessionPeer;
class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
public:
+ // CryptoHandshakeEvent enumerates the events generated by a QuicCryptoStream.
+ enum CryptoHandshakeEvent {
+ // ENCRYPTION_FIRST_ESTABLISHED indicates that a full client hello has been
+ // sent by a client and that subsequent packets will be encrypted. (Client
+ // only.)
+ ENCRYPTION_FIRST_ESTABLISHED,
+ // ENCRYPTION_REESTABLISHED indicates that a client hello was rejected by
+ // the server and thus the encryption key has been updated. Therefore the
+ // connection should resend any packets that were sent under
+ // ENCRYPTION_INITIAL. (Client only.)
+ ENCRYPTION_REESTABLISHED,
+ // HANDSHAKE_CONFIRMED, in a client, indicates the the server has accepted
+ // our handshake. In a server it indicates that a full, valid client hello
+ // has been received. (Client and server.)
+ HANDSHAKE_CONFIRMED,
+ };
+
QuicSession(QuicConnection* connection, bool is_server);
virtual ~QuicSession();
@@ -65,13 +82,23 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// Removes the stream associated with 'stream_id' from the active stream map.
virtual void CloseStream(QuicStreamId stream_id);
- // Returns true once the crypto handshake is complete.
- virtual bool IsCryptoHandshakeComplete();
-
- // Called by the QuicCryptoStream when the handshake completes.
- // If |error| is QUIC_NO_ERROR then the handshake was succesful,
- // otherwise it failed.
- virtual void OnCryptoHandshakeComplete(QuicErrorCode error);
+ // Returns true if outgoing packets will be encrypted, even if the server
+ // hasn't confirmed the handshake yet.
+ virtual bool IsEncryptionEstablished();
+
+ // For a client, returns true if the server has confirmed our handshake. For
+ // a server, returns true if a full, valid client hello has been received.
+ virtual bool IsCryptoHandshakeConfirmed();
+
+ // Called by the QuicCryptoStream when the handshake enters a new state.
+ //
+ // Clients will call this function in the order:
+ // ENCRYPTION_FIRST_ESTABLISHED
+ // zero or more ENCRYPTION_REESTABLISHED
+ // HANDSHAKE_CONFIRMED
+ //
+ // Servers will simply call it once with HANDSHAKE_CONFIRMED.
+ virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event);
// Returns true if the stream existed previously and has been closed.
// Returns false if the stream is still active or if the stream has
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index bd18ec8..f993625 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -30,7 +30,9 @@ class TestCryptoStream : public QuicCryptoStream {
virtual void OnHandshakeMessage(
const CryptoHandshakeMessage& message) OVERRIDE {
- SetHandshakeComplete(QUIC_NO_ERROR);
+ encryption_established_ = true;
+ handshake_confirmed_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
}
};
@@ -115,11 +117,11 @@ class QuicSessionTest : public ::testing::Test {
set<QuicStreamId> closed_streams_;
};
-TEST_F(QuicSessionTest, IsCryptoHandshakeComplete) {
- EXPECT_FALSE(session_.IsCryptoHandshakeComplete());
+TEST_F(QuicSessionTest, IsCryptoHandshakeConfirmed) {
+ EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
CryptoHandshakeMessage message;
session_.crypto_stream_.OnHandshakeMessage(message);
- EXPECT_TRUE(session_.IsCryptoHandshakeComplete());
+ EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed());
}
TEST_F(QuicSessionTest, IsClosedStreamDefault) {
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index c9c9177..0ebeb79 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -71,18 +71,14 @@ class QuicStreamFactoryTest : public ::testing::Test {
feedback.tcp.accumulated_number_of_lost_packets = 0;
feedback.tcp.receive_window = 16000;
- QuicFramer framer(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false);
+ QuicFramer framer(kQuicVersion1, QuicTime::Zero(), false);
QuicFrames frames;
frames.push_back(QuicFrame(&ack));
frames.push_back(QuicFrame(&feedback));
scoped_ptr<QuicPacket> packet(
framer.ConstructFrameDataPacket(header, frames).packet);
- return scoped_ptr<QuicEncryptedPacket>(
- framer.EncryptPacket(header.packet_sequence_number, *packet));
+ return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
+ ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
// Returns a newly created packet to send congestion feedback data.
@@ -110,17 +106,13 @@ class QuicStreamFactoryTest : public ::testing::Test {
scoped_ptr<QuicEncryptedPacket> ConstructPacket(
const QuicPacketHeader& header,
const QuicFrame& frame) {
- QuicFramer framer(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false);
+ QuicFramer framer(kQuicVersion1, QuicTime::Zero(), false);
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
framer.ConstructFrameDataPacket(header, frames).packet);
- return scoped_ptr<QuicEncryptedPacket>(
- framer.EncryptPacket(header.packet_sequence_number, *packet));
+ return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
+ ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
MockHostResolver host_resolver_;
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 6de120d..8a9d01b 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -90,6 +90,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_INVALID_VERSION);
RETURN_STRING_LITERAL(QUIC_CONNECTION_TIMED_OUT);
RETURN_STRING_LITERAL(QUIC_PROOF_INVALID);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_DUPLICATE_TAG);
RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
// Intentionally have no default case, so we'll break the build
// if we add errors and don't put them here.
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 9504949..4fec83d 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -110,7 +110,7 @@ void CryptoTestUtils::CommunicateHandshakeMessages(
PacketSavingConnection* b_conn,
QuicCryptoStream* b) {
size_t a_i = 0, b_i = 0;
- while (!a->handshake_complete()) {
+ while (!a->handshake_confirmed()) {
ASSERT_GT(a_conn->packets_.size(), a_i);
LOG(INFO) << "Processing " << a_conn->packets_.size() - a_i
<< " packets a->b";
@@ -218,22 +218,29 @@ string CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage& message,
void CryptoTestUtils::CompareClientAndServerKeys(
QuicCryptoClientStream* client,
QuicCryptoServerStream* server) {
- StringPiece client_encrypter_key =
- client->session()->connection()->encrypter()->GetKey();
- StringPiece client_encrypter_iv =
- client->session()->connection()->encrypter()->GetNoncePrefix();
- StringPiece client_decrypter_key =
- client->session()->connection()->decrypter()->GetKey();
- StringPiece client_decrypter_iv =
- client->session()->connection()->decrypter()->GetNoncePrefix();
- StringPiece server_encrypter_key =
- server->session()->connection()->encrypter()->GetKey();
- StringPiece server_encrypter_iv =
- server->session()->connection()->encrypter()->GetNoncePrefix();
- StringPiece server_decrypter_key =
- server->session()->connection()->decrypter()->GetKey();
- StringPiece server_decrypter_iv =
- server->session()->connection()->decrypter()->GetNoncePrefix();
+ const QuicEncrypter* client_encrypter(
+ client->session()->connection()->encrypter(ENCRYPTION_INITIAL));
+ // Normally we would expect the client's INITIAL decrypter to have latched
+ // from the receipt of the server hello. However, when using a
+ // PacketSavingConnection (at the tests do) we don't actually encrypt with
+ // the correct encrypter.
+ // TODO(agl): make the tests more realistic.
+ const QuicDecrypter* client_decrypter(
+ client->session()->connection()->alternative_decrypter());
+ const QuicEncrypter* server_encrypter(
+ server->session()->connection()->encrypter(ENCRYPTION_INITIAL));
+ const QuicDecrypter* server_decrypter(
+ server->session()->connection()->decrypter());
+
+ StringPiece client_encrypter_key = client_encrypter->GetKey();
+ StringPiece client_encrypter_iv = client_encrypter->GetNoncePrefix();
+ StringPiece client_decrypter_key = client_decrypter->GetKey();
+ StringPiece client_decrypter_iv = client_decrypter->GetNoncePrefix();
+ StringPiece server_encrypter_key = server_encrypter->GetKey();
+ StringPiece server_encrypter_iv = server_encrypter->GetNoncePrefix();
+ StringPiece server_decrypter_key = server_decrypter->GetKey();
+ StringPiece server_decrypter_iv = server_decrypter->GetNoncePrefix();
+
CompareCharArraysWithHexError("client write key",
client_encrypter_key.data(),
client_encrypter_key.length(),
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc
index c63d0f0..8ac7c12 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -10,8 +10,10 @@ MockCryptoClientStream::MockCryptoClientStream(
const string& server_hostname,
const QuicConfig& config,
QuicSession* session,
- QuicCryptoClientConfig* crypto_config)
- : QuicCryptoClientStream(server_hostname, config, session, crypto_config) {
+ QuicCryptoClientConfig* crypto_config,
+ HandshakeMode handshake_mode)
+ : QuicCryptoClientStream(server_hostname, config, session, crypto_config),
+ handshake_mode_(handshake_mode) {
}
MockCryptoClientStream::~MockCryptoClientStream() {
@@ -23,7 +25,17 @@ void MockCryptoClientStream::OnHandshakeMessage(
}
bool MockCryptoClientStream::CryptoConnect() {
- SetHandshakeComplete(QUIC_NO_ERROR);
+ if (handshake_mode_ == ZERO_RTT) {
+ encryption_established_ = true;
+ handshake_confirmed_ = false;
+ session()->OnCryptoHandshakeEvent(
+ QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
+ return true;
+ }
+
+ encryption_established_ = true;
+ handshake_confirmed_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
return true;
}
diff --git a/net/quic/test_tools/mock_crypto_client_stream.h b/net/quic/test_tools/mock_crypto_client_stream.h
index 2d9fdc3..f244ca9 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.h
+++ b/net/quic/test_tools/mock_crypto_client_stream.h
@@ -15,10 +15,24 @@ namespace net {
class MockCryptoClientStream : public QuicCryptoClientStream {
public:
- MockCryptoClientStream(const string& server_hostname,
- const QuicConfig& config,
- QuicSession* session,
- QuicCryptoClientConfig* crypto_config);
+ // HandshakeMode enumerates the handshake mode MockCryptoClientStream should
+ // mock in CryptoConnect.
+ enum HandshakeMode {
+ // CONFIRM_HANDSHAKE indicates that CryptoConnect will immediately confirm
+ // the handshake and establish encryption.
+ CONFIRM_HANDSHAKE,
+
+ // ZERO_RTT indicates that CryptoConnect will establish encryption but will
+ // not confirm the handshake.
+ ZERO_RTT,
+ };
+
+ MockCryptoClientStream(
+ const string& server_hostname,
+ const QuicConfig& config,
+ QuicSession* session,
+ QuicCryptoClientConfig* crypto_config,
+ HandshakeMode handshake_mode);
virtual ~MockCryptoClientStream();
// CryptoFramerVisitorInterface implementation.
@@ -27,6 +41,8 @@ class MockCryptoClientStream : public QuicCryptoClientStream {
// QuicCryptoClientStream implementation.
virtual bool CryptoConnect() OVERRIDE;
+
+ HandshakeMode handshake_mode_;
};
} // namespace net
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.cc b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
index f774328..20926ce 100644
--- a/net/quic/test_tools/mock_crypto_client_stream_factory.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
@@ -6,12 +6,15 @@
#include "base/lazy_instance.h"
#include "net/quic/quic_crypto_client_stream.h"
-#include "net/quic/test_tools/mock_crypto_client_stream.h"
using std::string;
namespace net {
+MockCryptoClientStreamFactory::MockCryptoClientStreamFactory()
+ : handshake_mode_(MockCryptoClientStream::CONFIRM_HANDSHAKE) {
+}
+
QuicCryptoClientStream*
MockCryptoClientStreamFactory::CreateQuicCryptoClientStream(
const string& server_hostname,
@@ -19,7 +22,7 @@ MockCryptoClientStreamFactory::CreateQuicCryptoClientStream(
QuicSession* session,
QuicCryptoClientConfig* crypto_config) {
return new MockCryptoClientStream(server_hostname, config, session,
- crypto_config);
+ crypto_config, handshake_mode_);
}
} // namespace net
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.h b/net/quic/test_tools/mock_crypto_client_stream_factory.h
index 445e766..01d0c75 100644
--- a/net/quic/test_tools/mock_crypto_client_stream_factory.h
+++ b/net/quic/test_tools/mock_crypto_client_stream_factory.h
@@ -10,11 +10,14 @@
#include "net/quic/quic_crypto_client_stream.h"
#include "net/quic/quic_crypto_client_stream_factory.h"
#include "net/quic/quic_session.h"
+#include "net/quic/test_tools/mock_crypto_client_stream.h"
namespace net {
class MockCryptoClientStreamFactory : public QuicCryptoClientStreamFactory {
public:
+ MockCryptoClientStreamFactory();
+
virtual ~MockCryptoClientStreamFactory() {}
virtual QuicCryptoClientStream* CreateQuicCryptoClientStream(
@@ -22,6 +25,14 @@ class MockCryptoClientStreamFactory : public QuicCryptoClientStreamFactory {
const QuicConfig& config,
QuicSession* session,
QuicCryptoClientConfig* crypto_config) OVERRIDE;
+
+ void set_handshake_mode(
+ MockCryptoClientStream::HandshakeMode handshake_mode) {
+ handshake_mode_ = handshake_mode;
+ }
+
+ private:
+ MockCryptoClientStream::HandshakeMode handshake_mode_;
};
} // namespace net
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 6777810..07d1f20 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -218,6 +218,7 @@ PacketSavingConnection::~PacketSavingConnection() {
}
bool PacketSavingConnection::SendOrQueuePacket(
+ EncryptionLevel level,
QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
QuicPacketEntropyHash entropy_hash,
@@ -329,11 +330,7 @@ static QuicPacket* ConstructPacketFromHandshakeMessage(
bool should_include_version) {
CryptoFramer crypto_framer;
scoped_ptr<QuicData> data(crypto_framer.ConstructHandshakeMessage(message));
- QuicFramer quic_framer(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- false);
+ QuicFramer quic_framer(kQuicVersion1, QuicTime::Zero(), false);
QuicPacketHeader header;
header.public_header.guid = guid;
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index cec4b31..7d34031 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -250,6 +250,7 @@ class PacketSavingConnection : public MockConnection {
virtual ~PacketSavingConnection();
virtual bool SendOrQueuePacket(
+ EncryptionLevel level,
QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
QuicPacketEntropyHash entropy_hash,
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc
index 7bd1ff1..546ae99 100644
--- a/net/quic/test_tools/simple_quic_framer.cc
+++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -128,11 +128,7 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
};
SimpleQuicFramer::SimpleQuicFramer()
- : framer_(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL),
- QuicTime::Zero(),
- true),
+ : framer_(kQuicVersion1, QuicTime::Zero(), true),
visitor_(NULL) {
}
@@ -140,7 +136,8 @@ SimpleQuicFramer::~SimpleQuicFramer() {
}
bool SimpleQuicFramer::ProcessPacket(const QuicPacket& packet) {
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(0, packet));
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ ENCRYPTION_NONE, 0, packet));
return ProcessPacket(*encrypted);
}