diff options
Diffstat (limited to 'net')
79 files changed, 1662 insertions, 736 deletions
diff --git a/net/net.gyp b/net/net.gyp index 9b94caa..743507c 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -1602,6 +1602,7 @@ 'quic/quic_stream_factory_test.cc', 'quic/quic_stream_sequencer_test.cc', 'quic/quic_time_test.cc', + 'quic/quic_utils_test.cc', 'quic/reliable_quic_stream_test.cc', 'socket/buffered_write_stream_socket_unittest.cc', 'socket/client_socket_pool_base_unittest.cc', diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc index 19549a47..2ccbc8b 100644 --- a/net/quic/congestion_control/fix_rate_sender.cc +++ b/net/quic/congestion_control/fix_rate_sender.cc @@ -58,7 +58,7 @@ void FixRateSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) { void FixRateSender::SentPacket(QuicTime sent_time, QuicPacketSequenceNumber /*sequence_number*/, QuicByteCount bytes, - bool is_retransmission) { + Retransmission is_retransmission) { fix_rate_leaky_bucket_.Add(sent_time, bytes); paced_sender_.SentPacket(sent_time, bytes); if (!is_retransmission) { @@ -73,8 +73,8 @@ void FixRateSender::AbandoningPacket( QuicTime::Delta FixRateSender::TimeUntilSend( QuicTime now, - bool /*is_retransmission*/, - bool /*has_retransmittable_data*/) { + Retransmission /*is_retransmission*/, + HasRetransmittableData /*has_retransmittable_data*/) { if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending(now)) { if (CongestionWindow() <= data_in_flight_) { // We need an ack before we send more. diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h index e81981a..42915e1 100644 --- a/net/quic/congestion_control/fix_rate_sender.h +++ b/net/quic/congestion_control/fix_rate_sender.h @@ -36,12 +36,13 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface { virtual void SentPacket(QuicTime sent_time, QuicPacketSequenceNumber equence_number, QuicByteCount bytes, - bool is_retransmission) OVERRIDE; + Retransmission is_retransmission) OVERRIDE; virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes) OVERRIDE; - virtual QuicTime::Delta TimeUntilSend(QuicTime now, - bool is_retransmission, - bool has_retransmittable_data) OVERRIDE; + virtual QuicTime::Delta TimeUntilSend( + QuicTime now, + Retransmission is_retransmission, + HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() OVERRIDE; virtual QuicTime::Delta SmoothedRtt() OVERRIDE; // End implementation of SendAlgorithmInterface. diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc index bbbb3cd..4969966 100644 --- a/net/quic/congestion_control/fix_rate_test.cc +++ b/net/quic/congestion_control/fix_rate_test.cc @@ -32,7 +32,8 @@ class FixRateTest : public ::testing::Test { : rtt_(QuicTime::Delta::FromMilliseconds(30)), unused_bandwidth_(QuicBandwidth::Zero()), sender_(new FixRateSender(&clock_)), - receiver_(new FixRateReceiverPeer()) { + receiver_(new FixRateReceiverPeer()), + start_(clock_.Now()) { // Make sure clock does not start at 0. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2)); } @@ -42,6 +43,7 @@ class FixRateTest : public ::testing::Test { SendAlgorithmInterface::SentPacketsMap unused_packet_map_; scoped_ptr<FixRateSender> sender_; scoped_ptr<FixRateReceiverPeer> receiver_; + const QuicTime start_; }; TEST_F(FixRateTest, ReceiverAPI) { @@ -61,21 +63,24 @@ TEST_F(FixRateTest, SenderAPI) { sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), unused_bandwidth_, unused_packet_map_); EXPECT_EQ(300000, sender_->BandwidthEstimate().ToBytesPerSecond()); - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); - sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, false); - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); - sender_->SentPacket(clock_.Now(), 2, kMaxPacketSize, false); - sender_->SentPacket(clock_.Now(), 3, 600, false); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), - sender_->TimeUntilSend(clock_.Now(), false, true)); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, NOT_RETRANSMISSION); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + sender_->SentPacket(clock_.Now(), 2, kMaxPacketSize, NOT_RETRANSMISSION); + sender_->SentPacket(clock_.Now(), 3, 600, NOT_RETRANSMISSION); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2)); - EXPECT_EQ(QuicTime::Delta::Infinite(), - sender_->TimeUntilSend(clock_.Now(), false, true)); + EXPECT_EQ(QuicTime::Delta::Infinite(), sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8)); sender_->OnIncomingAck(1, kMaxPacketSize, rtt_); sender_->OnIncomingAck(2, kMaxPacketSize, rtt_); sender_->OnIncomingAck(3, 600, rtt_); - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); } TEST_F(FixRateTest, FixRatePacing) { @@ -90,19 +95,24 @@ TEST_F(FixRateTest, FixRatePacing) { QuicTime acc_advance_time(QuicTime::Zero()); QuicPacketSequenceNumber sequence_number = 0; for (int i = 0; i < num_packets; i += 2) { - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); - sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, false); - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); - sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, false); - QuicTime::Delta advance_time = sender_->TimeUntilSend(clock_.Now(), false, - true); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, + NOT_RETRANSMISSION); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, + NOT_RETRANSMISSION); + QuicTime::Delta advance_time = sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA); clock_.AdvanceTime(advance_time); sender_->OnIncomingAck(sequence_number - 1, packet_size, rtt_); sender_->OnIncomingAck(sequence_number - 2, packet_size, rtt_); acc_advance_time = acc_advance_time.Add(advance_time); } EXPECT_EQ(num_packets * packet_size * 1000000 / bitrate.ToBytesPerSecond(), - static_cast<uint64>(acc_advance_time.ToMicroseconds())); + static_cast<uint64>(acc_advance_time.Subtract(start_) + .ToMicroseconds())); } } // namespace test diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc index d4dcdb3..48091c3 100644 --- a/net/quic/congestion_control/quic_congestion_manager.cc +++ b/net/quic/congestion_control/quic_congestion_manager.cc @@ -46,10 +46,10 @@ QuicCongestionManager::~QuicCongestionManager() { void QuicCongestionManager::SentPacket(QuicPacketSequenceNumber sequence_number, QuicTime sent_time, QuicByteCount bytes, - bool is_retransmission) { + Retransmission retransmission) { DCHECK(!ContainsKey(pending_packets_, sequence_number)); send_algorithm_->SentPacket(sent_time, sequence_number, bytes, - is_retransmission); + retransmission); packet_history_map_[sequence_number] = new class SendAlgorithmInterface::SentPacket(bytes, sent_time); @@ -122,10 +122,9 @@ void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame, QuicTime::Delta QuicCongestionManager::TimeUntilSend( QuicTime now, - bool is_retransmission, - bool has_retransmittable_data) { - return send_algorithm_->TimeUntilSend(now, is_retransmission, - has_retransmittable_data); + Retransmission retransmission, + HasRetransmittableData retransmittable) { + return send_algorithm_->TimeUntilSend(now, retransmission, retransmittable); } bool QuicCongestionManager::GenerateCongestionFeedback( diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h index 4560957..5840444 100644 --- a/net/quic/congestion_control/quic_congestion_manager.h +++ b/net/quic/congestion_control/quic_congestion_manager.h @@ -46,7 +46,7 @@ class QuicCongestionManager { virtual void SentPacket(QuicPacketSequenceNumber sequence_number, QuicTime sent_time, QuicByteCount bytes, - bool is_retransmission); + Retransmission retransmission); // Called when a packet is timed out. virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number); @@ -57,8 +57,8 @@ class QuicCongestionManager { // Note 2: Send algorithms may or may not use |retransmit| in their // calculations. virtual QuicTime::Delta TimeUntilSend(QuicTime now, - bool is_retransmission, - bool has_retransmittable_data); + Retransmission retransmission, + HasRetransmittableData retransmittable); // Should be called before sending an ACK packet, to decide if we need // to attach a QuicCongestionFeedbackFrame block. diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h index effa671..fd8ec3e 100644 --- a/net/quic/congestion_control/send_algorithm_interface.h +++ b/net/quic/congestion_control/send_algorithm_interface.h @@ -7,6 +7,8 @@ #ifndef NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_ #define NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_ +#include <map> + #include "base/basictypes.h" #include "net/base/net_export.h" #include "net/quic/quic_bandwidth.h" @@ -58,16 +60,17 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { virtual void SentPacket(QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - bool is_retransmission) = 0; + Retransmission is_retransmission) = 0; // Called when a packet is timed out. virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes) = 0; // Calculate the time until we can send the next packet. - virtual QuicTime::Delta TimeUntilSend(QuicTime now, - bool is_retransmission, - bool has_retransmittable_data) = 0; + virtual QuicTime::Delta TimeUntilSend( + QuicTime now, + Retransmission is_retransmission, + HasRetransmittableData has_retransmittable_data) = 0; // What's the current estimated bandwidth in bytes per second. // Returns 0 when it does not have an estimate. diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc index 70367ff..4bed7ed 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc @@ -85,7 +85,7 @@ void TcpCubicSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) { void TcpCubicSender::SentPacket(QuicTime /*sent_time*/, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - bool is_retransmission) { + Retransmission is_retransmission) { bytes_in_flight_ += bytes; if (!is_retransmission && update_end_sequence_number_) { end_sequence_number_ = sequence_number; @@ -101,9 +101,10 @@ void TcpCubicSender::AbandoningPacket(QuicPacketSequenceNumber sequence_number, bytes_in_flight_ -= abandoned_bytes; } -QuicTime::Delta TcpCubicSender::TimeUntilSend(QuicTime now, - bool is_retransmission, - bool has_retransmittable_data) { +QuicTime::Delta TcpCubicSender::TimeUntilSend( + QuicTime now, + Retransmission is_retransmission, + HasRetransmittableData has_retransmittable_data) { if (is_retransmission || !has_retransmittable_data) { // For TCP we can always send a retransmission and/or an ACK immediately. return QuicTime::Delta::Zero(); diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index 6943044..2a1066d 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h @@ -42,12 +42,13 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { virtual void SentPacket(QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - bool is_retransmission) OVERRIDE; + Retransmission is_retransmission) OVERRIDE; virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes) OVERRIDE; - virtual QuicTime::Delta TimeUntilSend(QuicTime now, - bool is_retransmission, - bool has_retransmittable_data) OVERRIDE; + virtual QuicTime::Delta TimeUntilSend( + QuicTime now, + Retransmission is_retransmission, + HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() OVERRIDE; virtual QuicTime::Delta SmoothedRtt() OVERRIDE; // End implementation of SendAlgorithmInterface. diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index 2aab55a..0cd51fd 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc @@ -40,10 +40,11 @@ class TcpCubicSenderTest : public ::testing::Test { while (bytes_to_send > 0) { QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, bytes_to_send); sender_->SentPacket(clock_.Now(), sequence_number_++, bytes_in_packet, - false); + NOT_RETRANSMISSION); bytes_to_send -= bytes_in_packet; if (bytes_to_send > 0) { - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, + NO_RETRANSMITTABLE_DATA).IsZero()); } } } @@ -73,31 +74,36 @@ TEST_F(TcpCubicSenderTest, SimpleSender) { EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableCongestionWindow()); // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); // Get default QuicCongestionFeedbackFrame from receiver. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), fake_bandwidth_, not_used_); // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); // And that window is un-affected. EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableCongestionWindow()); // A retransmitt should always retun 0. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), true, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), IS_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); } TEST_F(TcpCubicSenderTest, ExponentialSlowStart) { const int kNumberOfAck = 20; QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); // Get default QuicCongestionFeedbackFrame from receiver. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), fake_bandwidth_, not_used_); // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); for (int n = 0; n < kNumberOfAck; ++n) { // Send our full congestion window. @@ -118,13 +124,15 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) { const int kNumberOfAck = 65; QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); // Get default QuicCongestionFeedbackFrame from receiver. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), fake_bandwidth_, not_used_); // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); for (int n = 0; n < kNumberOfAck; ++n) { // Send our full congestion window. @@ -159,13 +167,15 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { const int kNumberOfAck = 10; QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); // Get default QuicCongestionFeedbackFrame from receiver. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), fake_bandwidth_, not_used_); // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); for (int i = 0; i < kNumberOfAck; ++i) { // Send our full congestion window. @@ -180,7 +190,8 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { sender_->OnIncomingLoss(clock_.Now()); // Make sure that we should not send right now. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsInfinite()); + EXPECT_TRUE(sender_->TimeUntilSend( + clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsInfinite()); // We should now have fallen out of slow start. // We expect window to be cut in half. diff --git a/net/quic/crypto/aes_128_gcm_decrypter.h b/net/quic/crypto/aes_128_gcm_decrypter.h index 88ce90e..bcd1d25 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter.h +++ b/net/quic/crypto/aes_128_gcm_decrypter.h @@ -32,22 +32,18 @@ class NET_EXPORT_PRIVATE Aes128GcmDecrypter : public QuicDecrypter { // QuicDecrypter implementation virtual bool SetKey(base::StringPiece key) OVERRIDE; virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE; - virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number, - base::StringPiece associated_data, - base::StringPiece ciphertext) OVERRIDE; + virtual bool Decrypt(base::StringPiece nonce, + base::StringPiece associated_data, + base::StringPiece ciphertext, + unsigned char* output, + size_t* output_length) OVERRIDE; + virtual QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number, + base::StringPiece associated_data, + base::StringPiece ciphertext) OVERRIDE; virtual base::StringPiece GetKey() const OVERRIDE; virtual base::StringPiece GetNoncePrefix() const OVERRIDE; private: - friend class test::Aes128GcmDecrypterPeer; - - // The same as Decrypt(), except that the supplied |nonce| argument rather - // than the |nonce_| member is used as the nonce. This method is useful - // for testing the underlying AES GCM implementation. - QuicData* DecryptWithNonce(base::StringPiece nonce, - base::StringPiece associated_data, - base::StringPiece ciphertext); - // The 128-bit AES key. unsigned char key_[16]; // The nonce, a concatenation of a four-byte fixed prefix and a 8-byte diff --git a/net/quic/crypto/aes_128_gcm_decrypter_nss.cc b/net/quic/crypto/aes_128_gcm_decrypter_nss.cc index 1d5c485..6c9bf1d 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter_nss.cc +++ b/net/quic/crypto/aes_128_gcm_decrypter_nss.cc @@ -52,41 +52,23 @@ bool Aes128GcmDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { return true; } -QuicData* Aes128GcmDecrypter::Decrypt(QuicPacketSequenceNumber sequence_number, - StringPiece associated_data, - StringPiece ciphertext) { - COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number), - incorrect_nonce_size); - memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number)); - return DecryptWithNonce(StringPiece(reinterpret_cast<char*>(nonce_), - sizeof(nonce_)), - associated_data, ciphertext); -} - -StringPiece Aes128GcmDecrypter::GetKey() const { - return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); -} - -StringPiece Aes128GcmDecrypter::GetNoncePrefix() const { - return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); -} - -QuicData* Aes128GcmDecrypter::DecryptWithNonce(StringPiece nonce, - StringPiece associated_data, - StringPiece ciphertext) { +bool Aes128GcmDecrypter::Decrypt(StringPiece nonce, + StringPiece associated_data, + StringPiece ciphertext, + unsigned char* output, + size_t* output_length) { #if defined(USE_NSS) // See the comment in IsSupported(). - return NULL; + return false; #else - if (ciphertext.length() < kAuthTagSize) { - return NULL; + if (ciphertext.length() < kAuthTagSize || + nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) { + return false; } // NSS 3.14.x incorrectly requires an output buffer at least as long as - // the ciphertext (NSS bug 853674). So the capacity of the |plaintext| - // buffer needs to be larger than the plaintext size. - size_t plaintext_capacity = ciphertext.length(); + // the ciphertext (NSS bug 853674). Fortunately QuicDecrypter::Decrypt() + // specifies that |output| must be as long as |ciphertext| on entry. size_t plaintext_size = ciphertext.length() - kAuthTagSize; - scoped_ptr<char[]> plaintext(new char[plaintext_capacity]); // Import key_ into NSS. SECItem key_item; @@ -103,7 +85,7 @@ QuicData* Aes128GcmDecrypter::DecryptWithNonce(StringPiece nonce, slot = NULL; if (!aes_key) { DLOG(INFO) << "PK11_ImportSymKey failed"; - return NULL; + return false; } CK_GCM_PARAMS gcm_params; @@ -124,21 +106,50 @@ QuicData* Aes128GcmDecrypter::DecryptWithNonce(StringPiece nonce, // If an incorrect authentication tag causes a decryption failure, the NSS // error is SEC_ERROR_BAD_DATA (-8190). if (PK11_Decrypt(aes_key.get(), CKM_AES_GCM, ¶m, - reinterpret_cast<unsigned char*>(plaintext.get()), - &output_len, plaintext_capacity, - reinterpret_cast<const unsigned char*>(ciphertext.data()), - ciphertext.size()) != SECSuccess) { + output, &output_len, ciphertext.length(), + reinterpret_cast<const unsigned char*>( + ciphertext.data()), ciphertext.length()) != SECSuccess) { DLOG(INFO) << "PK11_Decrypt failed: NSS error " << PORT_GetError(); - return NULL; + return false; } if (output_len != plaintext_size) { DLOG(INFO) << "Wrong output length"; + return false; + } + *output_length = output_len; + return true; +#endif +} + +QuicData* Aes128GcmDecrypter::DecryptPacket( + QuicPacketSequenceNumber sequence_number, + StringPiece associated_data, + StringPiece ciphertext) { + COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number), + incorrect_nonce_size); + if (ciphertext.length() < kAuthTagSize) { return NULL; } + size_t plaintext_size; + scoped_ptr<char[]> plaintext(new char[ciphertext.length()]); + memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number)); + if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)), + associated_data, ciphertext, + reinterpret_cast<unsigned char*>(plaintext.get()), + &plaintext_size)) { + return NULL; + } return new QuicData(plaintext.release(), plaintext_size, true); -#endif +} + +StringPiece Aes128GcmDecrypter::GetKey() const { + return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); +} + +StringPiece Aes128GcmDecrypter::GetNoncePrefix() const { + return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); } } // namespace net diff --git a/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc index 3b73779..8cf52e6 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc +++ b/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc @@ -44,91 +44,105 @@ bool Aes128GcmDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { return true; } -QuicData* Aes128GcmDecrypter::Decrypt(QuicPacketSequenceNumber sequence_number, - StringPiece associated_data, - StringPiece ciphertext) { - COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number), - incorrect_nonce_size); - memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number)); - return DecryptWithNonce(StringPiece(reinterpret_cast<char*>(nonce_), - sizeof(nonce_)), - associated_data, ciphertext); -} - -StringPiece Aes128GcmDecrypter::GetKey() const { - return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); -} - -StringPiece Aes128GcmDecrypter::GetNoncePrefix() const { - return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); -} - -QuicData* Aes128GcmDecrypter::DecryptWithNonce(StringPiece nonce, - StringPiece associated_data, - StringPiece ciphertext) { - if (ciphertext.length() < kAuthTagSize) { - return NULL; +bool Aes128GcmDecrypter::Decrypt(StringPiece nonce, + StringPiece associated_data, + StringPiece ciphertext, + unsigned char* output, + size_t* output_length) { + if (ciphertext.length() < kAuthTagSize || + nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) { + return false; } - size_t plaintext_size = ciphertext.length() - kAuthTagSize; - scoped_ptr<char[]> plaintext(new char[plaintext_size]); - - // |output| points to the position in the |plaintext| buffer to receive - // the next output. - unsigned char* output = reinterpret_cast<unsigned char*>(plaintext.get()); - // |output_len| is passed to an OpenSSL function to receive the output - // length. - int output_len; + const size_t plaintext_size = ciphertext.length() - kAuthTagSize; + // |len| is passed to an OpenSSL function to receive the output length. + int len; ScopedEVPCipherCtx ctx; // Set the cipher type and the key. The IV (nonce) is set below. if (EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_gcm(), NULL, key_, NULL) == 0) { - return NULL; + return false; } // Set the IV (nonce) length. if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, nonce.size(), NULL) == 0) { - return NULL; + return false; } // Set the IV (nonce). if (EVP_DecryptInit_ex(ctx.get(), NULL, NULL, NULL, reinterpret_cast<const unsigned char*>( nonce.data())) == 0) { - return NULL; + return false; } // Set the authentication tag. if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kAuthTagSize, const_cast<char*>(ciphertext.data()) + plaintext_size) == 0) { - return NULL; + return false; } - // Set the associated data. The second argument (output buffer) must be - // NULL. - if (EVP_DecryptUpdate(ctx.get(), NULL, &output_len, - reinterpret_cast<const unsigned char*>( - associated_data.data()), - associated_data.size()) == 0) { - return NULL; + // If we pass a NULL, zero-length associated data to OpenSSL then it breaks. + // Thus we only set non-empty associated data. + if (!associated_data.empty()) { + // Set the associated data. The second argument (output buffer) must be + // NULL. + if (EVP_DecryptUpdate(ctx.get(), NULL, &len, + reinterpret_cast<const unsigned char*>( + associated_data.data()), + associated_data.size()) == 0) { + return false; + } } - if (EVP_DecryptUpdate(ctx.get(), output, &output_len, + if (EVP_DecryptUpdate(ctx.get(), output, &len, reinterpret_cast<const unsigned char*>( ciphertext.data()), plaintext_size) == 0) { - return NULL; + return false; + } + output += len; + + if (EVP_DecryptFinal_ex(ctx.get(), output, &len) == 0) { + return false; } - output += output_len; + output += len; - if (EVP_DecryptFinal_ex(ctx.get(), output, &output_len) == 0) { + *output_length = plaintext_size; + + return true; +} + +QuicData* Aes128GcmDecrypter::DecryptPacket( + QuicPacketSequenceNumber sequence_number, + StringPiece associated_data, + StringPiece ciphertext) { + COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number), + incorrect_nonce_size); + if (ciphertext.length() < kAuthTagSize) { return NULL; } - output += output_len; + size_t plaintext_size; + scoped_ptr<char[]> plaintext(new char[ciphertext.length()]); + memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number)); + if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)), + associated_data, ciphertext, + reinterpret_cast<unsigned char*>(plaintext.get()), + &plaintext_size)) { + return NULL; + } return new QuicData(plaintext.release(), plaintext_size, true); } +StringPiece Aes128GcmDecrypter::GetKey() const { + return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); +} + +StringPiece Aes128GcmDecrypter::GetNoncePrefix() const { + return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); +} + } // namespace net diff --git a/net/quic/crypto/aes_128_gcm_decrypter_test.cc b/net/quic/crypto/aes_128_gcm_decrypter_test.cc index ac09581..2ab0dd0 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter_test.cc +++ b/net/quic/crypto/aes_128_gcm_decrypter_test.cc @@ -291,15 +291,22 @@ bool DecodeHexString(const char* in, namespace net { namespace test { -class Aes128GcmDecrypterPeer { - public: - static QuicData* Decrypt(Aes128GcmDecrypter* decrypter, +// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the plaintext. +QuicData* DecryptWithNonce(Aes128GcmDecrypter* decrypter, StringPiece nonce, StringPiece associated_data, StringPiece ciphertext) { - return decrypter->DecryptWithNonce(nonce, associated_data, ciphertext); + size_t plaintext_size = ciphertext.length(); + scoped_ptr<char[]> plaintext(new char[plaintext_size]); + + if (!decrypter->Decrypt(nonce, associated_data, ciphertext, + reinterpret_cast<unsigned char*>(plaintext.get()), + &plaintext_size)) { + return NULL; } -}; + return new QuicData(plaintext.release(), plaintext_size, true); +} TEST(Aes128GcmDecrypterTest, Decrypt) { if (!Aes128GcmDecrypter::IsSupported()) { @@ -321,6 +328,7 @@ TEST(Aes128GcmDecrypterTest, Decrypt) { size_t pt_len; for (size_t i = 0; i < arraysize(test_group_array); i++) { + SCOPED_TRACE(i); const TestVector* test_vector = test_group_array[i]; const TestGroupInfo& test_info = test_group_info[i]; for (size_t j = 0; test_vector[j].key != NULL; j++) { @@ -353,8 +361,11 @@ TEST(Aes128GcmDecrypterTest, Decrypt) { ASSERT_TRUE(decrypter.SetKey(StringPiece(key, key_len))); string ciphertext(ct, ct_len); ciphertext.append(tag, tag_len); - scoped_ptr<QuicData> decrypted(Aes128GcmDecrypterPeer::Decrypt( - &decrypter, StringPiece(iv, iv_len), StringPiece(aad, aad_len), + scoped_ptr<QuicData> decrypted(DecryptWithNonce( + &decrypter, StringPiece(iv, iv_len), + // OpenSSL fails if NULL is set as the AAD, as opposed to a + // zero-length, non-NULL pointer. + StringPiece(aad_len ? aad : NULL, aad_len), ciphertext)); if (!decrypted.get()) { EXPECT_EQ((size_t)-1, pt_len); diff --git a/net/quic/crypto/aes_128_gcm_encrypter.h b/net/quic/crypto/aes_128_gcm_encrypter.h index 1b1df9e..790c1d17 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter.h +++ b/net/quic/crypto/aes_128_gcm_encrypter.h @@ -32,9 +32,13 @@ class NET_EXPORT_PRIVATE Aes128GcmEncrypter : public QuicEncrypter { // QuicEncrypter implementation virtual bool SetKey(base::StringPiece key) OVERRIDE; virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE; - virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number, - base::StringPiece associated_data, - base::StringPiece plaintext) OVERRIDE; + virtual bool Encrypt(base::StringPiece nonce, + base::StringPiece associated_data, + base::StringPiece plaintext, + unsigned char* output) OVERRIDE; + virtual QuicData* EncryptPacket(QuicPacketSequenceNumber sequence_number, + base::StringPiece associated_data, + base::StringPiece plaintext) OVERRIDE; virtual size_t GetKeySize() const OVERRIDE; virtual size_t GetNoncePrefixSize() const OVERRIDE; virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const OVERRIDE; @@ -43,15 +47,6 @@ class NET_EXPORT_PRIVATE Aes128GcmEncrypter : public QuicEncrypter { virtual base::StringPiece GetNoncePrefix() const OVERRIDE; private: - friend class test::Aes128GcmEncrypterPeer; - - // The same as Encrypt(), except that the supplied |nonce| argument rather - // than the |nonce_| member is used as the nonce. This method is useful - // for testing the underlying AES GCM implementation. - QuicData* EncryptWithNonce(base::StringPiece nonce, - base::StringPiece associated_data, - base::StringPiece plaintext); - // The 128-bit AES key. unsigned char key_[16]; // The nonce, a concatenation of a four-byte fixed prefix and a 8-byte diff --git a/net/quic/crypto/aes_128_gcm_encrypter_nss.cc b/net/quic/crypto/aes_128_gcm_encrypter_nss.cc index 57d364c..789c16d 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter_nss.cc +++ b/net/quic/crypto/aes_128_gcm_encrypter_nss.cc @@ -53,52 +53,19 @@ bool Aes128GcmEncrypter::SetNoncePrefix(StringPiece nonce_prefix) { return true; } -QuicData* Aes128GcmEncrypter::Encrypt(QuicPacketSequenceNumber sequence_number, - StringPiece associated_data, - StringPiece plaintext) { - COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number), - incorrect_nonce_size); - memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number)); - return EncryptWithNonce(StringPiece(reinterpret_cast<char*>(nonce_), - sizeof(nonce_)), - associated_data, plaintext); -} - -size_t Aes128GcmEncrypter::GetKeySize() const { - return kKeySize; -} - -size_t Aes128GcmEncrypter::GetNoncePrefixSize() const { - return kNoncePrefixSize; -} - -size_t Aes128GcmEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { - return ciphertext_size - kAuthTagSize; -} - -// An AEAD_AES_128_GCM ciphertext is exactly 16 bytes longer than its -// corresponding plaintext. -size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const { - return plaintext_size + kAuthTagSize; -} - -StringPiece Aes128GcmEncrypter::GetKey() const { - return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); -} - -StringPiece Aes128GcmEncrypter::GetNoncePrefix() const { - return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); -} - -QuicData* Aes128GcmEncrypter::EncryptWithNonce(StringPiece nonce, - StringPiece associated_data, - StringPiece plaintext) { +bool Aes128GcmEncrypter::Encrypt(StringPiece nonce, + StringPiece associated_data, + StringPiece plaintext, + unsigned char* output) { #if defined(USE_NSS) // See the comment in IsSupported(). - return NULL; + return false; #else + if (nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) { + return false; + } + size_t ciphertext_size = GetCiphertextSize(plaintext.length()); - scoped_ptr<char[]> ciphertext(new char[ciphertext_size]); // Import key_ into NSS. SECItem key_item; @@ -115,7 +82,7 @@ QuicData* Aes128GcmEncrypter::EncryptWithNonce(StringPiece nonce, slot = NULL; if (!aes_key) { DLOG(INFO) << "PK11_ImportSymKey failed"; - return NULL; + return false; } CK_GCM_PARAMS gcm_params; @@ -134,21 +101,66 @@ QuicData* Aes128GcmEncrypter::EncryptWithNonce(StringPiece nonce, unsigned int output_len; if (PK11_Encrypt(aes_key.get(), CKM_AES_GCM, ¶m, - reinterpret_cast<unsigned char*>(ciphertext.get()), - &output_len, ciphertext_size, + output, &output_len, ciphertext_size, reinterpret_cast<const unsigned char*>(plaintext.data()), plaintext.size()) != SECSuccess) { DLOG(INFO) << "PK11_Encrypt failed"; - return NULL; + return false; } if (output_len != ciphertext_size) { DLOG(INFO) << "Wrong output length"; + return false; + } + + return true; +#endif +} + +QuicData* Aes128GcmEncrypter::EncryptPacket( + QuicPacketSequenceNumber sequence_number, + StringPiece associated_data, + StringPiece plaintext) { + COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number), + incorrect_nonce_size); + memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number)); + + size_t ciphertext_size = GetCiphertextSize(plaintext.length()); + scoped_ptr<char[]> ciphertext(new char[ciphertext_size]); + + if (!Encrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)), + associated_data, plaintext, + reinterpret_cast<unsigned char*>(ciphertext.get()))) { return NULL; } return new QuicData(ciphertext.release(), ciphertext_size, true); -#endif +} + +size_t Aes128GcmEncrypter::GetKeySize() const { + return kKeySize; +} + +size_t Aes128GcmEncrypter::GetNoncePrefixSize() const { + return kNoncePrefixSize; +} + +size_t Aes128GcmEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { + return ciphertext_size - kAuthTagSize; +} + +// An AEAD_AES_128_GCM ciphertext is exactly 16 bytes longer than its +// corresponding plaintext. +size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const { + return plaintext_size + kAuthTagSize; +} + +StringPiece Aes128GcmEncrypter::GetKey() const { + return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); +} + +StringPiece Aes128GcmEncrypter::GetNoncePrefix() const { + return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); } } // namespace net diff --git a/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc index 41d9177..87b8f53 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc +++ b/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc @@ -45,98 +45,110 @@ bool Aes128GcmEncrypter::SetNoncePrefix(StringPiece nonce_prefix) { return true; } -QuicData* Aes128GcmEncrypter::Encrypt(QuicPacketSequenceNumber sequence_number, - StringPiece associated_data, - StringPiece plaintext) { - COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number), - incorrect_nonce_size); - memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number)); - return EncryptWithNonce(StringPiece(reinterpret_cast<char*>(nonce_), - sizeof(nonce_)), - associated_data, plaintext); -} - -size_t Aes128GcmEncrypter::GetKeySize() const { - return kKeySize; -} - -size_t Aes128GcmEncrypter::GetNoncePrefixSize() const { - return kNoncePrefixSize; -} - -size_t Aes128GcmEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { - return ciphertext_size - kAuthTagSize; -} - -// An AEAD_AES_128_GCM ciphertext is exactly 16 bytes longer than its -// corresponding plaintext. -size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const { - return plaintext_size + kAuthTagSize; -} - -QuicData* Aes128GcmEncrypter::EncryptWithNonce(StringPiece nonce, - StringPiece associated_data, - StringPiece plaintext) { - size_t ciphertext_size = GetCiphertextSize(plaintext.length()); - scoped_ptr<char[]> ciphertext(new char[ciphertext_size]); - - // |output| points to the position in the |ciphertext| buffer to receive - // the next output. - unsigned char* output = reinterpret_cast<unsigned char*>(ciphertext.get()); +bool Aes128GcmEncrypter::Encrypt(StringPiece nonce, + StringPiece associated_data, + StringPiece plaintext, + unsigned char* output) { // |output_len| is passed to an OpenSSL function to receive the output // length. int output_len; + if (nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) { + return false; + } + ScopedEVPCipherCtx ctx; // Set the cipher type and the key. The IV (nonce) is set below. if (EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_gcm(), NULL, key_, NULL) == 0) { - return NULL; + return false; } // Set the IV (nonce) length. if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, nonce.size(), NULL) == 0) { - return NULL; + return false; } // Set the IV (nonce). if (EVP_EncryptInit_ex(ctx.get(), NULL, NULL, NULL, reinterpret_cast<const unsigned char*>( nonce.data())) == 0) { - return NULL; + return false; } - // Set the associated data. The second argument (output buffer) must be - // NULL. - if (EVP_EncryptUpdate(ctx.get(), NULL, &output_len, - reinterpret_cast<const unsigned char*>( - associated_data.data()), - associated_data.size()) == 0) { - return NULL; + // If we pass a NULL, zero-length associated data to OpenSSL then it breaks. + // Thus we only set non-empty associated data. + if (!associated_data.empty()) { + // Set the associated data. The second argument (output buffer) must be + // NULL. + if (EVP_EncryptUpdate(ctx.get(), NULL, &output_len, + reinterpret_cast<const unsigned char*>( + associated_data.data()), + associated_data.size()) == 0) { + return false; + } } if (EVP_EncryptUpdate(ctx.get(), output, &output_len, reinterpret_cast<const unsigned char*>( plaintext.data()), plaintext.size()) == 0) { - return NULL; + return false; } output += output_len; if (EVP_EncryptFinal_ex(ctx.get(), output, &output_len) == 0) { - return NULL; + return false; } output += output_len; if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kAuthTagSize, output) == 0) { + return false; + } + + return true; +} + +QuicData* Aes128GcmEncrypter::EncryptPacket( + QuicPacketSequenceNumber sequence_number, + StringPiece associated_data, + StringPiece plaintext) { + COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number), + incorrect_nonce_size); + memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number)); + + size_t ciphertext_size = GetCiphertextSize(plaintext.length()); + scoped_ptr<char[]> ciphertext(new char[ciphertext_size]); + + if (!Encrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)), + associated_data, plaintext, + reinterpret_cast<unsigned char*>(ciphertext.get()))) { return NULL; } return new QuicData(ciphertext.release(), ciphertext_size, true); } +size_t Aes128GcmEncrypter::GetKeySize() const { + return kKeySize; +} + +size_t Aes128GcmEncrypter::GetNoncePrefixSize() const { + return kNoncePrefixSize; +} + +size_t Aes128GcmEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { + return ciphertext_size - kAuthTagSize; +} + +// An AEAD_AES_128_GCM ciphertext is exactly 16 bytes longer than its +// corresponding plaintext. +size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const { + return plaintext_size + kAuthTagSize; +} + StringPiece Aes128GcmEncrypter::GetKey() const { return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); } diff --git a/net/quic/crypto/aes_128_gcm_encrypter_test.cc b/net/quic/crypto/aes_128_gcm_encrypter_test.cc index 4dd38b4..0da7a8f 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter_test.cc +++ b/net/quic/crypto/aes_128_gcm_encrypter_test.cc @@ -243,15 +243,22 @@ bool DecodeHexString(const char* in, namespace net { namespace test { -class Aes128GcmEncrypterPeer { - public: - static QuicData* Encrypt(Aes128GcmEncrypter* encrypter, +// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the ciphertext. +QuicData* EncryptWithNonce(Aes128GcmEncrypter* encrypter, StringPiece nonce, StringPiece associated_data, StringPiece plaintext) { - return encrypter->EncryptWithNonce(nonce, associated_data, plaintext); + size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length()); + scoped_ptr<char[]> ciphertext(new char[ciphertext_size]); + + if (!encrypter->Encrypt(nonce, associated_data, plaintext, + reinterpret_cast<unsigned char*>(ciphertext.get()))) { + return NULL; } -}; + + return new QuicData(ciphertext.release(), ciphertext_size, true); +} TEST(Aes128GcmEncrypterTest, Encrypt) { if (!Aes128GcmEncrypter::IsSupported()) { @@ -273,6 +280,7 @@ TEST(Aes128GcmEncrypterTest, Encrypt) { size_t tag_len; for (size_t i = 0; i < arraysize(test_group_array); i++) { + SCOPED_TRACE(i); const TestVector* test_vector = test_group_array[i]; const TestGroupInfo& test_info = test_group_info[i]; for (size_t j = 0; test_vector[j].key != NULL; j++) { @@ -301,8 +309,12 @@ TEST(Aes128GcmEncrypterTest, Encrypt) { Aes128GcmEncrypter encrypter; ASSERT_TRUE(encrypter.SetKey(StringPiece(key, key_len))); - scoped_ptr<QuicData> encrypted(Aes128GcmEncrypterPeer::Encrypt( - &encrypter, StringPiece(iv, iv_len), StringPiece(aad, aad_len), + scoped_ptr<QuicData> encrypted(EncryptWithNonce( + &encrypter, StringPiece(iv, iv_len), + // OpenSSL fails if NULL is set as the AAD, as opposed to a + // zero-length, non-NULL pointer. This deliberately tests that we + // handle this case. + StringPiece(aad_len ? aad : NULL, aad_len), StringPiece(pt, pt_len))); ASSERT_TRUE(encrypted.get()); ASSERT_EQ(ct_len + tag_len, encrypted->length()); diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc index f25133d..5956e45 100644 --- a/net/quic/crypto/crypto_handshake.cc +++ b/net/quic/crypto/crypto_handshake.cc @@ -9,9 +9,12 @@ #include "base/memory/scoped_ptr.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" #include "crypto/hkdf.h" #include "crypto/secure_hash.h" #include "net/base/net_util.h" +#include "net/quic/crypto/aes_128_gcm_decrypter.h" +#include "net/quic/crypto/aes_128_gcm_encrypter.h" #include "net/quic/crypto/crypto_framer.h" #include "net/quic/crypto/crypto_utils.h" #include "net/quic/crypto/curve25519_key_exchange.h" @@ -319,6 +322,34 @@ string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const { return ret; } +SourceAddressToken::SourceAddressToken() { +} + +SourceAddressToken::~SourceAddressToken() { +} + +string SourceAddressToken::SerializeAsString() const { + return ip_ + " " + base::Int64ToString(timestamp_); +} + +bool SourceAddressToken::ParseFromArray(unsigned char* plaintext, + size_t plaintext_length) { + string data(reinterpret_cast<const char*>(plaintext), plaintext_length); + std::vector<std::string> results; + base::SplitString(data, ' ', &results); + if (results.size() < 2) { + return false; + } + + int64 timestamp; + if (!base::StringToInt64(results[1], ×tamp)) { + return false; + } + + ip_ = results[0]; + timestamp_ = timestamp; + return true; +} QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters() : version(0), @@ -392,13 +423,19 @@ const string& QuicCryptoClientConfig::CachedState::orbit() const { return orbit_; } +void QuicCryptoClientConfig::CachedState::set_source_address_token( + StringPiece token) { + source_address_token_ = token.as_string(); +} + void QuicCryptoClientConfig::SetDefaults() { // Version must be 0. version = kVersion; // Key exchange methods. - kexs.resize(1); + kexs.resize(2); kexs[0] = kC255; + kexs[1] = kP256; // Authenticated encryption algorithms. aead.resize(1); @@ -431,7 +468,7 @@ void QuicCryptoClientConfig::FillInchoateClientHello( out->SetValue(kVERS, version); if (cached && !cached->source_address_token().empty()) { - out->SetValue(kSRCT, cached->source_address_token()); + out->SetStringPiece(kSRCT, cached->source_address_token()); } } @@ -527,7 +564,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( break; case kP256: key_exchange.reset(P256KeyExchange::New( - Curve25519KeyExchange::NewPrivateKey(rand))); + P256KeyExchange::NewPrivateKey())); break; default: DCHECK(false); @@ -589,6 +626,11 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection( return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; } + StringPiece token; + if (rej.GetStringPiece(kSRCT, &token)) { + cached->set_source_address_token(token); + } + return QUIC_NO_ERROR; } @@ -610,7 +652,26 @@ QuicErrorCode QuicCryptoClientConfig::ProcessServerHello( } -QuicCryptoServerConfig::QuicCryptoServerConfig() { +QuicCryptoServerConfig::QuicCryptoServerConfig( + StringPiece source_address_token_secret) + // AES-GCM is used to encrypt and authenticate source address tokens. The + // full, 96-bit nonce is used but we must ensure that an attacker cannot + // obtain two source address tokens with the same nonce. This occurs with + // probability 0.5 after 2**48 values. We assume that obtaining 2**48 + // source address tokens is not possible: at a rate of 10M packets per + // second, it would still take the attacker a year to obtain the needed + // number of packets. + // + // TODO(agl): switch to an encrypter with a larger nonce space (i.e. + // Salsa20+Poly1305). + : source_address_token_encrypter_(new Aes128GcmEncrypter), + source_address_token_decrypter_(new Aes128GcmDecrypter) { + crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */, + "QUIC source address token key", + source_address_token_encrypter_->GetKeySize(), + 0 /* no fixed IV needed */); + source_address_token_encrypter_->SetKey(hkdf.server_write_key()); + source_address_token_decrypter_->SetKey(hkdf.server_write_key()); } QuicCryptoServerConfig::~QuicCryptoServerConfig() { @@ -624,21 +685,34 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::ConfigForTesting( const CryptoHandshakeMessage& extra_tags) { CryptoHandshakeMessage msg; - const string private_key = Curve25519KeyExchange::NewPrivateKey(rand); + const string curve25519_private_key = + Curve25519KeyExchange::NewPrivateKey(rand); scoped_ptr<Curve25519KeyExchange> curve25519( - Curve25519KeyExchange::New(private_key)); - StringPiece public_value = curve25519->public_value(); - string encoded_public_value; + Curve25519KeyExchange::New(curve25519_private_key)); + StringPiece curve25519_public_value = curve25519->public_value(); + + const string p256_private_key = + P256KeyExchange::NewPrivateKey(); + scoped_ptr<P256KeyExchange> p256( + P256KeyExchange::New(p256_private_key)); + StringPiece p256_public_value = p256->public_value(); + + string encoded_public_values; // First two bytes encode the length of the public value. - encoded_public_value.push_back(public_value.size()); - encoded_public_value.push_back(public_value.size() >> 8); - encoded_public_value.append(public_value.data(), public_value.size()); + encoded_public_values.push_back(curve25519_public_value.size()); + encoded_public_values.push_back(curve25519_public_value.size() >> 8); + encoded_public_values.append(curve25519_public_value.data(), + curve25519_public_value.size()); + encoded_public_values.push_back(p256_public_value.size()); + encoded_public_values.push_back(p256_public_value.size() >> 8); + encoded_public_values.append(p256_public_value.data(), + p256_public_value.size()); msg.set_tag(kSCFG); - msg.SetTaglist(kKEXS, kC255, 0); + msg.SetTaglist(kKEXS, kC255, kP256, 0); msg.SetTaglist(kAEAD, kAESG, 0); msg.SetValue(kVERS, static_cast<uint16>(0)); - msg.SetStringPiece(kPUBS, encoded_public_value); + msg.SetStringPiece(kPUBS, encoded_public_values); msg.Insert(extra_tags.tag_value_map().begin(), extra_tags.tag_value_map().end()); @@ -651,9 +725,12 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::ConfigForTesting( scoped_ptr<QuicServerConfigProtobuf> config(new QuicServerConfigProtobuf); config->set_config(serialized->AsStringPiece()); - QuicServerConfigProtobuf::PrivateKey* key = config->add_key(); - key->set_tag(kC255); - key->set_private_key(private_key); + QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key(); + curve25519_key->set_tag(kC255); + curve25519_key->set_private_key(curve25519_private_key); + QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key(); + p256_key->set_tag(kP256); + p256_key->set_private_key(p256_private_key); return config.release(); } @@ -739,6 +816,14 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( return NULL; } break; + case kP256: + ka.reset(P256KeyExchange::New(private_key)); + if (!ka.get()) { + LOG(WARNING) << "Server config contained an invalid P-256" + " private key."; + return NULL; + } + break; default: LOG(WARNING) << "Server config message contains unknown key exchange " "method: " @@ -791,6 +876,9 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddTestingConfig( QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( const CryptoHandshakeMessage& client_hello, QuicGuid guid, + const IPEndPoint& client_ip, + QuicTime::Delta now_since_unix_epoch, + QuicRandom* rand, CryptoHandshakeMessage* out, QuicCryptoNegotiatedParameters *out_params, string* error_details) { @@ -798,15 +886,27 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( // FIXME(agl): we should use the client's SCID, not just the active config. const Config* config(configs_[active_config_]); + bool valid_source_address_token = false; + StringPiece srct; + if (client_hello.GetStringPiece(kSRCT, &srct) && + ValidateSourceAddressToken(srct, client_ip, now_since_unix_epoch)) { + valid_source_address_token = true; + } + + const string fresh_source_address_token = + NewSourceAddressToken(client_ip, rand, now_since_unix_epoch); + StringPiece scid; if (!client_hello.GetStringPiece(kSCID, &scid) || - scid.as_string() != config->id) { + scid.as_string() != config->id || + !valid_source_address_token) { // If the client didn't provide a server config ID, or gave the wrong one, // then the handshake cannot possibly complete. We reject the handshake and // give the client enough information to do better next time. out->Clear(); out->set_tag(kREJ); out->SetStringPiece(kSCFG, config->serialized); + out->SetStringPiece(kSRCT, fresh_source_address_token); return QUIC_NO_ERROR; } @@ -880,9 +980,102 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( CryptoUtils::SERVER); out->set_tag(kSHLO); + out->SetStringPiece(kSRCT, fresh_source_address_token); return QUIC_NO_ERROR; } +string QuicCryptoServerConfig::NewSourceAddressToken( + const IPEndPoint& ip, + QuicRandom* rand, + QuicTime::Delta now_since_epoch) { + SourceAddressToken source_address_token; + source_address_token.set_ip(ip.ToString()); + source_address_token.set_timestamp(now_since_epoch.ToSeconds()); + + string plaintext = source_address_token.SerializeAsString(); + char nonce[12]; + DCHECK_EQ(sizeof(nonce), + source_address_token_encrypter_->GetNoncePrefixSize() + + sizeof(QuicPacketSequenceNumber)); + rand->RandBytes(nonce, sizeof(nonce)); + + size_t ciphertext_size = + source_address_token_encrypter_->GetCiphertextSize(plaintext.size()); + string result; + result.resize(sizeof(nonce) + ciphertext_size); + memcpy(&result[0], &nonce, sizeof(nonce)); + + if (!source_address_token_encrypter_->Encrypt( + StringPiece(nonce, sizeof(nonce)), StringPiece(), plaintext, + reinterpret_cast<unsigned char*>(&result[sizeof(nonce)]))) { + DCHECK(false); + return string(); + } + + return result; +} + +bool QuicCryptoServerConfig::ValidateSourceAddressToken( + StringPiece token, + const IPEndPoint& ip, + QuicTime::Delta now_since_epoch) { + char nonce[12]; + DCHECK_EQ(sizeof(nonce), + source_address_token_encrypter_->GetNoncePrefixSize() + + sizeof(QuicPacketSequenceNumber)); + + if (token.size() <= sizeof(nonce)) { + return false; + } + memcpy(&nonce, token.data(), sizeof(nonce)); + token.remove_prefix(sizeof(nonce)); + + unsigned char plaintext_stack[128]; + scoped_ptr<unsigned char[]> plaintext_heap; + unsigned char* plaintext; + if (token.size() <= sizeof(plaintext_stack)) { + plaintext = plaintext_stack; + } else { + plaintext_heap.reset(new unsigned char[token.size()]); + plaintext = plaintext_heap.get(); + } + size_t plaintext_length; + + if (!source_address_token_decrypter_->Decrypt( + StringPiece(nonce, sizeof(nonce)), StringPiece(), token, + plaintext, &plaintext_length)) { + return false; + } + + SourceAddressToken source_address_token; + if (!source_address_token.ParseFromArray(plaintext, plaintext_length)) { + return false; + } + + if (source_address_token.ip() != ip.ToString()) { + // It's for a different IP address. + return false; + } + + const QuicTime::Delta delta(now_since_epoch.Subtract( + QuicTime::Delta::FromSeconds(source_address_token.timestamp()))); + const int64 delta_secs = delta.ToSeconds(); + + // TODO(agl): consider whether and how these magic values should be moved to + // a config. + if (delta_secs < -3600) { + // We only allow timestamps to be from an hour in the future. + return false; + } + + if (delta_secs > 86400) { + // We allow one day into the past. + return false; + } + + return true; +} + QuicCryptoServerConfig::Config::Config() { } diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h index fe2565e..e433d15 100644 --- a/net/quic/crypto/crypto_handshake.h +++ b/net/quic/crypto/crypto_handshake.h @@ -11,16 +11,23 @@ #include "base/memory/scoped_ptr.h" #include "base/string_piece.h" +#include "net/base/ip_endpoint.h" #include "net/base/net_export.h" #include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/quic_time.h" namespace net { class KeyExchange; +class QuicClock; class QuicDecrypter; class QuicEncrypter; class QuicRandom; -class QuicClock; +class QuicServerConfigProtobuf; + +namespace test { +class QuicCryptoServerConfigPeer; +} // namespace test // An intermediate format of a handshake message that's convenient for a // CryptoFramer to serialize from or parse into. @@ -170,6 +177,37 @@ class NET_EXPORT_PRIVATE QuicServerConfigProtobuf { std::string config_; }; +// TODO(rtenneti): sync with server more rationally. +class NET_EXPORT_PRIVATE SourceAddressToken { + public: + SourceAddressToken(); + ~SourceAddressToken(); + + std::string SerializeAsString() const; + + bool ParseFromArray(unsigned char* plaintext, size_t plaintext_length); + + std::string ip() const { + return ip_; + } + + int64 timestamp() const { + return timestamp_; + } + + void set_ip(base::StringPiece ip) { + ip_ = ip.as_string(); + } + + void set_timestamp(int64 timestamp) { + timestamp_ = timestamp; + } + + private: + std::string ip_; + int64 timestamp_; +}; + // Parameters negotiated by the crypto handshake. struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters { // Initializes the members to 0 or empty values. @@ -233,6 +271,8 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { const std::string& source_address_token() const; const std::string& orbit() const; + void set_source_address_token(base::StringPiece token); + private: std::string server_config_id_; // An opaque id from the server. std::string server_config_; // A serialized handshake message. @@ -306,7 +346,11 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // need to consider locking. class NET_EXPORT_PRIVATE QuicCryptoServerConfig { public: - QuicCryptoServerConfig(); + // |source_address_token_secret|: secret key material used for encrypting and + // decrypting source address tokens. It can be of any length as it is fed + // into a KDF before use. + explicit QuicCryptoServerConfig( + base::StringPiece source_address_token_secret); ~QuicCryptoServerConfig(); // ConfigForTesting generates a QuicServerConfigProtobuf protobuf suitable @@ -332,15 +376,31 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { // ProcessClientHello processes |client_hello| and decides whether to accept // or reject the connection. If the connection is to be accepted, |out| is // set to the contents of the ServerHello, |out_params| is completed and - // QUIC_NO_ERROR is returned. |nonce| is used as the server's nonce. - // Otherwise |out| is set to be a REJ message and an error code is returned. + // QUIC_NO_ERROR is returned. Otherwise |out| is set to be a REJ message and + // an error code is returned. + // + // client_hello: the incoming client hello message. + // guid: the GUID for the connection, which is used in key derivation. + // client_ip: the IP address of the client, which is used to generate and + // validate source-address tokens. + // now_since_epoch: the current time, as a delta since the unix epoch, + // which is used to validate client nonces. + // rand: an entropy source + // out: the resulting handshake message (either REJ or SHLO) + // out_params: the state of the handshake + // error_details: used to store a string describing any error. QuicErrorCode ProcessClientHello(const CryptoHandshakeMessage& client_hello, QuicGuid guid, + const IPEndPoint& client_ip, + QuicTime::Delta now_since_epoch, + QuicRandom* rand, CryptoHandshakeMessage* out, QuicCryptoNegotiatedParameters* out_params, std::string* error_details); private: + friend class test::QuicCryptoServerConfigPeer; + // Config represents a server config: a collection of preferences and // Diffie-Hellman public values. struct Config : public QuicCryptoConfig { @@ -365,9 +425,27 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { DISALLOW_COPY_AND_ASSIGN(Config); }; + // NewSourceAddressToken returns a fresh source address token for the given + // IP address. + std::string NewSourceAddressToken(const IPEndPoint& ip, + QuicRandom* rand, + QuicTime::Delta now_since_epoch); + + // ValidateSourceAddressToken returns true if the source address token in + // |token| is a valid and timely token for the IP address |ip| given that the + // current time is |now|. + bool ValidateSourceAddressToken(base::StringPiece token, + const IPEndPoint& ip, + QuicTime::Delta now_since_epoch); + std::map<ServerConfigID, Config*> configs_; - std::string active_config_; + ServerConfigID active_config_; + + // These members are used to encrypt and decrypt the source address tokens + // that we receive from and send to clients. + scoped_ptr<QuicEncrypter> source_address_token_encrypter_; + scoped_ptr<QuicDecrypter> source_address_token_decrypter_; }; } // namespace net diff --git a/net/quic/crypto/crypto_handshake_test.cc b/net/quic/crypto/crypto_handshake_test.cc index 0ce2ed4..911bc29 100644 --- a/net/quic/crypto/crypto_handshake_test.cc +++ b/net/quic/crypto/crypto_handshake_test.cc @@ -4,11 +4,83 @@ #include "net/quic/crypto/crypto_handshake.h" +#include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/crypto/quic_random.h" +#include "net/quic/quic_time.h" +#include "net/quic/test_tools/mock_clock.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using base::StringPiece; +using std::string; + namespace net { namespace test { +class QuicCryptoServerConfigPeer { + public: + explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig* server_config) + : server_config_(server_config) { + } + + string NewSourceAddressToken(IPEndPoint ip, + QuicRandom* rand, + QuicTime::Delta now) { + return server_config_->NewSourceAddressToken(ip, rand, now); + } + + bool ValidateSourceAddressToken(StringPiece srct, + IPEndPoint ip, + QuicTime::Delta now) { + return server_config_->ValidateSourceAddressToken(srct, ip, now); + } + + private: + QuicCryptoServerConfig* const server_config_; +}; + +TEST(QuicCryptoServerConfigTest, ServerConfig) { + QuicCryptoServerConfig server("source address token secret"); + MockClock clock; + CryptoHandshakeMessage extra_tags; + + scoped_ptr<CryptoHandshakeMessage>( + server.AddTestingConfig(QuicRandom::GetInstance(), &clock, extra_tags)); +} + +TEST(QuicCryptoServerConfigTest, SourceAddressTokens) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + + QuicCryptoServerConfig server("source address token secret"); + IPAddressNumber ip; + CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip)); + IPEndPoint ip4 = IPEndPoint(ip, 1); + CHECK(ParseIPLiteralToNumber("2001:db8:0::42", &ip)); + IPEndPoint ip6 = IPEndPoint(ip, 2); + QuicRandom* rand = QuicRandom::GetInstance(); + MockClock clock; + QuicCryptoServerConfigPeer peer(&server); + + QuicTime::Delta now = clock.NowAsDeltaSinceUnixEpoch(); + const QuicTime::Delta original_time = now; + + const string token4 = peer.NewSourceAddressToken(ip4, rand, now); + LOG(INFO) << __LINE__ << token4; + const string token6 = peer.NewSourceAddressToken(ip6, rand, now); + LOG(INFO) << __LINE__ << token6; + EXPECT_TRUE(peer.ValidateSourceAddressToken(token4, ip4, now)); + EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip6, now)); + EXPECT_TRUE(peer.ValidateSourceAddressToken(token6, ip6, now)); + + now = original_time.Add(QuicTime::Delta::FromSeconds(86400 * 7)); + EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip4, now)); + + now = original_time.Subtract(QuicTime::Delta::FromSeconds(3600 * 2)); + EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip4, now)); +} + } // namespace test } // namespace net diff --git a/net/quic/crypto/null_decrypter.cc b/net/quic/crypto/null_decrypter.cc index 05d6bda..0875558 100644 --- a/net/quic/crypto/null_decrypter.cc +++ b/net/quic/crypto/null_decrypter.cc @@ -19,9 +19,37 @@ bool NullDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { return nonce_prefix.empty(); } -QuicData* NullDecrypter::Decrypt(QuicPacketSequenceNumber /*sequence_number*/, - StringPiece associated_data, - StringPiece ciphertext) { +bool NullDecrypter::Decrypt(StringPiece /*nonce*/, + StringPiece associated_data, + StringPiece ciphertext, + unsigned char* output, + size_t* output_length) { + QuicDataReader reader(ciphertext.data(), ciphertext.length()); + + uint128 hash; + if (!reader.ReadUInt128(&hash)) { + return false; + } + + StringPiece plaintext = reader.ReadRemainingPayload(); + + // TODO(rch): avoid buffer copy here + string buffer = associated_data.as_string(); + plaintext.AppendToString(&buffer); + + if (hash != QuicUtils::FNV1a_128_Hash(buffer.data(), buffer.length())) { + return false; + } + memcpy(output, plaintext.data(), plaintext.length()); + *output_length = plaintext.length(); + return true; +} + +QuicData* NullDecrypter::DecryptPacket(QuicPacketSequenceNumber /*seq_number*/, + StringPiece associated_data, + StringPiece ciphertext) { + // It's worth duplicating |Decrypt|, above, in order to save a copy by using + // the shared-data QuicData constructor directly. QuicDataReader reader(ciphertext.data(), ciphertext.length()); uint128 hash; diff --git a/net/quic/crypto/null_decrypter.h b/net/quic/crypto/null_decrypter.h index bd4a7ea..01beb2d 100644 --- a/net/quic/crypto/null_decrypter.h +++ b/net/quic/crypto/null_decrypter.h @@ -21,9 +21,14 @@ class NET_EXPORT_PRIVATE NullDecrypter : public QuicDecrypter { // QuicDecrypter implementation virtual bool SetKey(base::StringPiece key) OVERRIDE; virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE; - virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number, - base::StringPiece associated_data, - base::StringPiece ciphertext) OVERRIDE; + virtual bool Decrypt(base::StringPiece nonce, + base::StringPiece associated_data, + base::StringPiece ciphertext, + unsigned char* output, + size_t* output_length) OVERRIDE; + virtual QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number, + base::StringPiece associated_data, + base::StringPiece ciphertext) OVERRIDE; virtual base::StringPiece GetKey() const OVERRIDE; virtual base::StringPiece GetNoncePrefix() const OVERRIDE; }; diff --git a/net/quic/crypto/null_decrypter_test.cc b/net/quic/crypto/null_decrypter_test.cc index 56aa531..7854b04 100644 --- a/net/quic/crypto/null_decrypter_test.cc +++ b/net/quic/crypto/null_decrypter_test.cc @@ -23,9 +23,10 @@ TEST(NullDecrypterTest, Decrypt) { }; NullDecrypter decrypter; scoped_ptr<QuicData> decrypted( - decrypter.Decrypt(0, "hello world!", - StringPiece(reinterpret_cast<const char*>(expected), - arraysize(expected)))); + decrypter.DecryptPacket( + 0, "hello world!", + StringPiece(reinterpret_cast<const char*>(expected), + arraysize(expected)))); ASSERT_TRUE(decrypted.get()); EXPECT_EQ("goodbye!", decrypted->AsStringPiece()); } @@ -43,9 +44,10 @@ TEST(NullDecrypterTest, BadHash) { }; NullDecrypter decrypter; scoped_ptr<QuicData> decrypted( - decrypter.Decrypt(0, "hello world!", - StringPiece(reinterpret_cast<const char*>(expected), - arraysize(expected)))); + decrypter.DecryptPacket( + 0, "hello world!", + StringPiece(reinterpret_cast<const char*>(expected), + arraysize(expected)))); ASSERT_FALSE(decrypted.get()); } @@ -59,9 +61,10 @@ TEST(NullDecrypterTest, ShortInput) { }; NullDecrypter decrypter; scoped_ptr<QuicData> decrypted( - decrypter.Decrypt(0, "hello world!", - StringPiece(reinterpret_cast<const char*>(expected), - arraysize(expected)))); + decrypter.DecryptPacket( + 0, "hello world!", + StringPiece(reinterpret_cast<const char*>(expected), + arraysize(expected)))); ASSERT_FALSE(decrypted.get()); } diff --git a/net/quic/crypto/null_encrypter.cc b/net/quic/crypto/null_encrypter.cc index b563107..22370ba 100644 --- a/net/quic/crypto/null_encrypter.cc +++ b/net/quic/crypto/null_encrypter.cc @@ -21,18 +21,27 @@ bool NullEncrypter::SetNoncePrefix(StringPiece nonce_prefix) { return nonce_prefix.empty(); } -QuicData* NullEncrypter::Encrypt(QuicPacketSequenceNumber /*sequence_number*/, - StringPiece associated_data, - StringPiece plaintext) { - // TODO(rch): avoid buffer copy here +bool NullEncrypter::Encrypt( + StringPiece /*nonce*/, + StringPiece associated_data, + StringPiece plaintext, + unsigned char* output) { string buffer = associated_data.as_string(); plaintext.AppendToString(&buffer); uint128 hash = QuicUtils::FNV1a_128_Hash(buffer.data(), buffer.length()); - QuicDataWriter writer(plaintext.length() + kHashSize); - writer.WriteUInt128(hash); - writer.WriteBytes(plaintext.data(), plaintext.length()); - size_t len = writer.length(); - return new QuicData(writer.take(), len, true); + memcpy(output, &hash, sizeof(hash)); + memcpy(output + sizeof(hash), plaintext.data(), plaintext.size()); + return true; +} + +QuicData* NullEncrypter::EncryptPacket( + QuicPacketSequenceNumber /*sequence_number*/, + StringPiece associated_data, + StringPiece plaintext) { + const size_t len = plaintext.size() + sizeof(uint128); + uint8* buffer = new uint8[len]; + Encrypt(StringPiece(), associated_data, plaintext, buffer); + return new QuicData(reinterpret_cast<char*>(buffer), len, true); } size_t NullEncrypter::GetKeySize() const { diff --git a/net/quic/crypto/null_encrypter.h b/net/quic/crypto/null_encrypter.h index c452348..ed05e1f 100644 --- a/net/quic/crypto/null_encrypter.h +++ b/net/quic/crypto/null_encrypter.h @@ -21,9 +21,13 @@ class NET_EXPORT_PRIVATE NullEncrypter : public QuicEncrypter { // QuicEncrypter implementation virtual bool SetKey(base::StringPiece key) OVERRIDE; virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE; - virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number, - base::StringPiece associated_data, - base::StringPiece plaintext) OVERRIDE; + virtual bool Encrypt(base::StringPiece nonce, + base::StringPiece associated_data, + base::StringPiece plaintext, + unsigned char* output) OVERRIDE; + virtual QuicData* EncryptPacket(QuicPacketSequenceNumber sequence_number, + base::StringPiece associated_data, + base::StringPiece plaintext) OVERRIDE; virtual size_t GetKeySize() const OVERRIDE; virtual size_t GetNoncePrefixSize() const OVERRIDE; virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const OVERRIDE; diff --git a/net/quic/crypto/null_encrypter_test.cc b/net/quic/crypto/null_encrypter_test.cc index df9bcdc..e1e6834 100644 --- a/net/quic/crypto/null_encrypter_test.cc +++ b/net/quic/crypto/null_encrypter_test.cc @@ -22,8 +22,8 @@ TEST(NullEncrypterTest, Encrypt) { 'b', 'y', 'e', '!', }; NullEncrypter encrypter; - scoped_ptr<QuicData> encrypted(encrypter.Encrypt(0, "hello world!", - "goodbye!")); + scoped_ptr<QuicData> encrypted(encrypter.EncryptPacket(0, "hello world!", + "goodbye!")); ASSERT_TRUE(encrypted.get()); test::CompareCharArraysWithHexError( "encrypted data", encrypted->data(), encrypted->length(), diff --git a/net/quic/crypto/p256_key_exchange_nss.cc b/net/quic/crypto/p256_key_exchange_nss.cc index eff2028..c1de42e 100644 --- a/net/quic/crypto/p256_key_exchange_nss.cc +++ b/net/quic/crypto/p256_key_exchange_nss.cc @@ -7,6 +7,10 @@ #include "base/logging.h" #include "base/sys_byteorder.h" +using base::StringPiece; +using std::string; +using std::vector; + namespace net { namespace { @@ -17,9 +21,9 @@ namespace { // use the same approach. const char kExportPassword[] = ""; -// Convert StringPiece to vector of uint8 -static std::vector<uint8> StringPieceToVector(base::StringPiece piece) { - return std::vector<uint8>(piece.data(), piece.data() + piece.length()); +// Convert StringPiece to vector of uint8. +static vector<uint8> StringPieceToVector(StringPiece piece) { + return vector<uint8>(piece.data(), piece.data() + piece.length()); } } // namespace @@ -34,9 +38,9 @@ P256KeyExchange::~P256KeyExchange() { } // static -P256KeyExchange* P256KeyExchange::New(base::StringPiece key) { +P256KeyExchange* P256KeyExchange::New(StringPiece key) { if (key.size() < 2) { - DLOG(INFO) << "Key pair is too small"; + DLOG(INFO) << "Key pair is too small."; return NULL; } @@ -45,18 +49,18 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) { (static_cast<size_t>(data[1]) << 8); key.remove_prefix(2); if (key.size() < size) { - DLOG(INFO) << "Key pair does not contain key material"; + DLOG(INFO) << "Key pair does not contain key material."; return NULL; } - base::StringPiece private_piece(key.data(), size); + StringPiece private_piece(key.data(), size); key.remove_prefix(size); if (key.empty()) { - DLOG(INFO) << "Key pair does not contain public key"; + DLOG(INFO) << "Key pair does not contain public key."; return NULL; } - base::StringPiece public_piece(key); + StringPiece public_piece(key); scoped_ptr<crypto::ECPrivateKey> key_pair( crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( @@ -66,7 +70,7 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) { StringPieceToVector(public_piece))); if (!key_pair.get()) { - DLOG(INFO) << "Can't decrypt private key"; + DLOG(INFO) << "Can't decrypt private key."; return NULL; } @@ -76,14 +80,14 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) { public_key->u.ec.publicValue.len != kUncompressedP256PointBytes || !public_key->u.ec.publicValue.data || public_key->u.ec.publicValue.data[0] != kUncompressedECPointForm) { - DLOG(INFO) << "Key is invalid"; + DLOG(INFO) << "Key is invalid."; return NULL; } // Ensure that the key is using the correct curve, i.e., NIST P-256. const SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); if (!oid_data) { - DLOG(INFO) << "Can't get P-256's OID"; + DLOG(INFO) << "Can't get P-256's OID."; return NULL; } @@ -93,7 +97,7 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) { public_key->u.ec.DEREncodedParams.data[1] != oid_data->oid.len || memcmp(public_key->u.ec.DEREncodedParams.data + 2, oid_data->oid.data, oid_data->oid.len) != 0) { - DLOG(INFO) << "Key is invalid"; + DLOG(INFO) << "Key is invalid."; } return new P256KeyExchange(key_pair.release(), @@ -101,29 +105,29 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) { } // static -std::string P256KeyExchange::NewPrivateKey() { +string P256KeyExchange::NewPrivateKey() { scoped_ptr<crypto::ECPrivateKey> key_pair(crypto::ECPrivateKey::Create()); if (!key_pair.get()) { - DLOG(INFO) << "Can't generate new key pair"; - return std::string(); + DLOG(INFO) << "Can't generate new key pair."; + return string(); } - std::vector<uint8> private_key; + vector<uint8> private_key; if (!key_pair->ExportEncryptedPrivateKey(kExportPassword, 1 /* iteration */, &private_key)) { - DLOG(INFO) << "Can't export private key"; - return std::string(); + DLOG(INFO) << "Can't export private key."; + return string(); } // NSS lacks the ability to import an ECC private key without // also importing the public key, so it is necessary to also // store the public key. - std::vector<uint8> public_key; + vector<uint8> public_key; if (!key_pair->ExportPublicKey(&public_key)) { - DLOG(INFO) << "Can't export public key"; - return std::string(); + DLOG(INFO) << "Can't export public key."; + return string(); } // TODO(thaidn): determine how large encrypted private key can be @@ -131,7 +135,7 @@ std::string P256KeyExchange::NewPrivateKey() { const size_t result_size = sizeof(private_key_size) + private_key_size + public_key.size(); - std::vector<char> result(result_size); + vector<char> result(result_size); char* resultp = &result[0]; // Export the key string. // The first two bytes are the private key's size in little endian. @@ -142,15 +146,15 @@ std::string P256KeyExchange::NewPrivateKey() { resultp += private_key.size(); memcpy(resultp, &public_key[0], public_key.size()); - return std::string(&result[0], result_size); + return string(&result[0], result_size); } bool P256KeyExchange::CalculateSharedKey( - const base::StringPiece& peer_public_value, - std::string* out_result) const { + const StringPiece& peer_public_value, + string* out_result) const { if (peer_public_value.size() != kUncompressedP256PointBytes || peer_public_value[0] != kUncompressedECPointForm) { - DLOG(INFO) << "Peer public value is invalid"; + DLOG(INFO) << "Peer public value is invalid."; return false; } @@ -194,18 +198,18 @@ bool P256KeyExchange::CalculateSharedKey( NULL)); if (!premaster_secret.get()) { - DLOG(INFO) << "Can't derive ECDH shared key"; + DLOG(INFO) << "Can't derive ECDH shared key."; return false; } if (PK11_ExtractKeyValue(premaster_secret.get()) != SECSuccess) { - DLOG(INFO) << "Can't extract raw ECDH shared key"; + DLOG(INFO) << "Can't extract raw ECDH shared key."; return false; } SECItem* key_data = PK11_GetKeyData(premaster_secret.get()); if (!key_data || !key_data->data || key_data->len != kP256FieldBytes) { - DLOG(INFO) << "ECDH shared key is invalid"; + DLOG(INFO) << "ECDH shared key is invalid."; return false; } @@ -213,9 +217,9 @@ bool P256KeyExchange::CalculateSharedKey( return true; } -base::StringPiece P256KeyExchange::public_value() const { - return base::StringPiece(reinterpret_cast<const char*>(public_key_), - sizeof(public_key_)); +StringPiece P256KeyExchange::public_value() const { + return StringPiece(reinterpret_cast<const char*>(public_key_), + sizeof(public_key_)); } CryptoTag P256KeyExchange::tag() const { diff --git a/net/quic/crypto/p256_key_exchange_openssl.cc b/net/quic/crypto/p256_key_exchange_openssl.cc index ae7f30e..051adcf 100644 --- a/net/quic/crypto/p256_key_exchange_openssl.cc +++ b/net/quic/crypto/p256_key_exchange_openssl.cc @@ -10,6 +10,9 @@ #include "base/logging.h" +using base::StringPiece; +using std::string; + namespace net { P256KeyExchange::P256KeyExchange(EC_KEY* private_key, const uint8* public_key) @@ -21,7 +24,7 @@ P256KeyExchange::~P256KeyExchange() { } // static -P256KeyExchange* P256KeyExchange::New(base::StringPiece key) { +P256KeyExchange* P256KeyExchange::New(StringPiece key) { if (key.empty()) { DLOG(INFO) << "Private key is empty"; return NULL; @@ -31,19 +34,19 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) { crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> private_key( d2i_ECPrivateKey(NULL, &keyp, key.size())); if (!private_key.get() || !EC_KEY_check_key(private_key.get())) { - DLOG(INFO) << "Private key is invalid"; + DLOG(INFO) << "Private key is invalid."; return NULL; } uint8 public_key[kUncompressedP256PointBytes]; if (EC_POINT_point2oct( - EC_KEY_get0_group(private_key.get()), - EC_KEY_get0_public_key(private_key.get()), - POINT_CONVERSION_UNCOMPRESSED, - public_key, - sizeof(public_key), - NULL) != sizeof(public_key)) { - DLOG(INFO) << "Can't get public key"; + EC_KEY_get0_group(private_key.get()), + EC_KEY_get0_public_key(private_key.get()), + POINT_CONVERSION_UNCOMPRESSED, + public_key, + sizeof(public_key), + NULL) != sizeof(public_key)) { + DLOG(INFO) << "Can't get public key."; return NULL; } @@ -51,38 +54,38 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) { } // static -std::string P256KeyExchange::NewPrivateKey() { +string P256KeyExchange::NewPrivateKey() { crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> key( EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); if (!key.get() || !EC_KEY_generate_key(key.get())) { - DLOG(INFO) << "Can't generate a new private key"; - return std::string(); + DLOG(INFO) << "Can't generate a new private key."; + return string(); } int key_len = i2d_ECPrivateKey(key.get(), NULL); if (key_len <= 0) { DLOG(INFO) << "Can't convert private key to string"; - return std::string(); + return string(); } scoped_ptr<uint8[]> private_key(new uint8[key_len]); uint8* keyp = private_key.get(); if (!i2d_ECPrivateKey(key.get(), &keyp)) { - DLOG(INFO) << "Can't convert private key to string"; - return std::string(); + DLOG(INFO) << "Can't convert private key to string."; + return string(); } - return std::string(reinterpret_cast<char*>(private_key.get()), key_len); + return string(reinterpret_cast<char*>(private_key.get()), key_len); } bool P256KeyExchange::CalculateSharedKey( - const base::StringPiece& peer_public_value, - std::string* out_result) const { + const StringPiece& peer_public_value, + string* out_result) const { if (peer_public_value.size() != kUncompressedP256PointBytes) { DLOG(INFO) << "Peer public value is invalid"; return false; } crypto::ScopedOpenSSL<EC_POINT, EC_POINT_free> point( - EC_POINT_new(EC_KEY_get0_group(private_key_.get()))); + EC_POINT_new(EC_KEY_get0_group(private_key_.get()))); if (!point.get() || !EC_POINT_oct2point( /* also test if point is on curve */ EC_KEY_get0_group(private_key_.get()), @@ -90,7 +93,7 @@ bool P256KeyExchange::CalculateSharedKey( reinterpret_cast<const uint8*>(peer_public_value.data()), peer_public_value.size(), NULL)) { - DLOG(INFO) << "Can't convert peer public value to curve point"; + DLOG(INFO) << "Can't convert peer public value to curve point."; return false; } @@ -101,7 +104,7 @@ bool P256KeyExchange::CalculateSharedKey( point.get(), private_key_.get(), NULL) != sizeof(result)) { - DLOG(INFO) << "Can't compute ECDH shared key"; + DLOG(INFO) << "Can't compute ECDH shared key."; return false; } @@ -109,9 +112,9 @@ bool P256KeyExchange::CalculateSharedKey( return true; } -base::StringPiece P256KeyExchange::public_value() const { - return base::StringPiece(reinterpret_cast<const char*>(public_key_), - sizeof(public_key_)); +StringPiece P256KeyExchange::public_value() const { + return StringPiece(reinterpret_cast<const char*>(public_key_), + sizeof(public_key_)); } CryptoTag P256KeyExchange::tag() const { diff --git a/net/quic/crypto/p256_key_exchange_test.cc b/net/quic/crypto/p256_key_exchange_test.cc index 799c853..8ea59da 100644 --- a/net/quic/crypto/p256_key_exchange_test.cc +++ b/net/quic/crypto/p256_key_exchange_test.cc @@ -7,6 +7,8 @@ #include "base/logging.h" #include "testing/gtest/include/gtest/gtest.h" +using std::string; + namespace net { namespace test { @@ -14,8 +16,8 @@ namespace test { // parties end up with the same key. TEST(P256KeyExchange, SharedKey) { for (int i = 0; i < 5; i++) { - std::string alice_private(P256KeyExchange::NewPrivateKey()); - std::string bob_private(P256KeyExchange::NewPrivateKey()); + string alice_private(P256KeyExchange::NewPrivateKey()); + string bob_private(P256KeyExchange::NewPrivateKey()); ASSERT_FALSE(alice_private.empty()); ASSERT_FALSE(bob_private.empty()); diff --git a/net/quic/crypto/quic_decrypter.h b/net/quic/crypto/quic_decrypter.h index c648668..349425a 100644 --- a/net/quic/crypto/quic_decrypter.h +++ b/net/quic/crypto/quic_decrypter.h @@ -40,15 +40,27 @@ class NET_EXPORT_PRIVATE QuicDecrypter { // packet sequence number, even when retransmitting a lost packet. virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0; + // Decrypt authenticates |associated_data| and |ciphertext| and then decrypts + // |ciphertext| into |output|, using |nonce|. |nonce| must be 8 bytes longer + // than the nonce prefix length returned by GetNoncePrefixSize() (of the + // encrypter). |output| must be as long as |ciphertext| on entry and, on + // successful return, the true length of the plaintext will be written to + // |*output_length|. + virtual bool Decrypt(base::StringPiece nonce, + base::StringPiece associated_data, + base::StringPiece ciphertext, + unsigned char* output, + size_t* output_length) = 0; + // Returns a newly created QuicData object containing the decrypted // |ciphertext| or NULL if there is an error. |sequence_number| is // appended to the |nonce_prefix| value provided in SetNoncePrefix() // to form the nonce. - // TODO(wtc): add a way for Decrypt to report decryption failure due + // TODO(wtc): add a way for DecryptPacket to report decryption failure due // to non-authentic inputs, as opposed to other reasons for failure. - virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number, - base::StringPiece associated_data, - base::StringPiece ciphertext) = 0; + virtual QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number, + base::StringPiece associated_data, + base::StringPiece ciphertext) = 0; // For use by unit tests only. virtual base::StringPiece GetKey() const = 0; diff --git a/net/quic/crypto/quic_encrypter.h b/net/quic/crypto/quic_encrypter.h index 013aff1..86d0e3a 100644 --- a/net/quic/crypto/quic_encrypter.h +++ b/net/quic/crypto/quic_encrypter.h @@ -40,13 +40,23 @@ class NET_EXPORT_PRIVATE QuicEncrypter { // packet sequence number, even when retransmitting a lost packet. virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0; + // Encrypt encrypts |plaintext| and writes the ciphertext, plus a MAC over + // both |associated_data| and |plaintext| to |output|, using |nonce| as the + // nonce. |nonce| must be |8+GetNoncePrefixSize()| bytes long and |output| + // must point to a buffer that is at least + // |GetCiphertextSize(plaintext.size()| bytes long. + virtual bool Encrypt(base::StringPiece nonce, + base::StringPiece associated_data, + base::StringPiece plaintext, + unsigned char* output) = 0; + // Returns a newly created QuicData object containing the encrypted // |plaintext| as well as a MAC over both |plaintext| and |associated_data|, // or NULL if there is an error. |sequence_number| is appended to the // |nonce_prefix| value provided in SetNoncePrefix() to form the nonce. - virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number, - base::StringPiece associated_data, - base::StringPiece plaintext) = 0; + virtual QuicData* EncryptPacket(QuicPacketSequenceNumber sequence_number, + base::StringPiece associated_data, + base::StringPiece plaintext) = 0; // GetKeySize() and GetNoncePrefixSize() tell the HKDF class how many bytes // of key material needs to be derived from the master secret. diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc index d87f903..1ca0080 100644 --- a/net/quic/quic_client_session_test.cc +++ b/net/quic/quic_client_session_test.cc @@ -10,6 +10,7 @@ #include "net/base/capturing_net_log.h" #include "net/base/net_log_unittest.h" #include "net/base/test_completion_callback.h" +#include "net/quic/crypto/aes_128_gcm_encrypter.h" #include "net/quic/crypto/crypto_protocol.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" @@ -51,10 +52,20 @@ class QuicClientSessionTest : public ::testing::Test { }; TEST_F(QuicClientSessionTest, CryptoConnect) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + CompleteCryptoHandshake(); } TEST_F(QuicClientSessionTest, MaxNumConnections) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + CompleteCryptoHandshake(); std::vector<QuicReliableClientStream*> streams; @@ -85,6 +96,11 @@ TEST_F(QuicClientSessionTest, GoAwayReceived) { } TEST_F(QuicClientSessionTest, Logging) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + CompleteCryptoHandshake(); // TODO(rch): Add some helper methods to simplify packet creation in tests. @@ -92,10 +108,11 @@ TEST_F(QuicClientSessionTest, Logging) { QuicFramer framer(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false); QuicRstStreamFrame frame; frame.stream_id = 2; - frame.error_code = QUIC_CONNECTION_TIMED_OUT; + frame.error_code = QUIC_STREAM_CONNECTION_ERROR; frame.error_details = "doh!"; QuicFrames frames; @@ -143,7 +160,7 @@ TEST_F(QuicClientSessionTest, Logging) { EXPECT_EQ(frame.stream_id, static_cast<QuicStreamId>(stream_id)); int error_code; ASSERT_TRUE(entries[pos].GetIntegerValue("error_code", &error_code)); - EXPECT_EQ(frame.error_code, static_cast<QuicErrorCode>(error_code)); + EXPECT_EQ(frame.error_code, static_cast<QuicRstStreamErrorCode>(error_code)); std::string details; ASSERT_TRUE(entries[pos].GetStringValue("details", &details)); EXPECT_EQ(frame.error_details, details); diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 5bb15c6..6449ee1 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -64,13 +64,6 @@ const int kMaxPacketsToSerializeAtOnce = 6; // eventually cede. 10 is arbitrary. const int kMaxPacketsPerRetransmissionAlarm = 10; -// Named constant for WritePacket() -const bool kForce = true; -// Named constant for CanWrite(). -const bool kIsRetransmission = true; -// Named constant for WritePacket. -const bool kHasRetransmittableData = true; - bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) { QuicPacketSequenceNumber delta = (a > b) ? a - b : b - a; return delta <= kMaxPacketGap; @@ -78,6 +71,8 @@ bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) { } // namespace +#define ENDPOINT (is_server_ ? "Server: " : " Client: ") + QuicConnection::QuicConnection(QuicGuid guid, IPEndPoint address, QuicConnectionHelperInterface* helper, @@ -86,6 +81,7 @@ QuicConnection::QuicConnection(QuicGuid guid, framer_(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + helper->GetClock()->ApproximateNow(), is_server), clock_(helper->GetClock()), random_generator_(helper->GetRandomGenerator()), @@ -116,7 +112,6 @@ QuicConnection::QuicConnection(QuicGuid guid, helper_->SetTimeoutAlarm(timeout_); framer_.set_visitor(this); framer_.set_entropy_calculator(&entropy_manager_); - memset(&last_header_, 0, sizeof(last_header_)); outgoing_ack_.sent_info.least_unacked = 0; outgoing_ack_.sent_info.entropy_hash = 0; outgoing_ack_.received_info.largest_observed = 0; @@ -125,7 +120,7 @@ QuicConnection::QuicConnection(QuicGuid guid, /* if (FLAGS_fake_packet_loss_percentage > 0) { int32 seed = RandomBase::WeakSeed32(); - LOG(INFO) << "Seeding packet loss with " << seed; + LOG(INFO) << ENDPOINT << "Seeding packet loss with " << seed; random_.reset(new MTRandom(seed)); } */ @@ -163,7 +158,7 @@ void QuicConnection::OnPacket() { // since it affects the timeout of the connection. time_of_last_received_packet_ = clock_->Now(); DVLOG(1) << "time of last received packet: " - << time_of_last_received_packet_.ToMicroseconds(); + << time_of_last_received_packet_.ToDebuggingValue(); // TODO(alyssar, rch) handle migration! self_address_ = last_self_address_; @@ -275,14 +270,14 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { ++stats_.packets_dropped; if (header.public_header.guid != guid_) { - DLOG(INFO) << "Ignoring packet from unexpected GUID: " + DLOG(INFO) << ENDPOINT << "Ignoring packet from unexpected GUID: " << header.public_header.guid << " instead of " << guid_; return false; } if (!Near(header.packet_sequence_number, last_header_.packet_sequence_number)) { - DLOG(INFO) << "Packet " << header.packet_sequence_number + DLOG(INFO) << ENDPOINT << "Packet " << header.packet_sequence_number << " out of bounds. Discarding"; // TODO(alyssar) close the connection entirely. return false; @@ -298,8 +293,8 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { if (version_negotiation_state_ != NEGOTIATED_VERSION) { if (is_server_) { if (!header.public_header.version_flag) { - DLOG(WARNING) << "Got packet without version flag before version " - << "negotiated."; + DLOG(WARNING) << ENDPOINT << "Got packet without version flag before " + << "version negotiated."; // Packets should have the version flag till version negotiation is // done. CloseConnection(QUIC_INVALID_VERSION, false); @@ -346,7 +341,7 @@ void QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { DVLOG(1) << "OnAckFrame: " << incoming_ack; if (last_header_.packet_sequence_number <= largest_seen_packet_with_ack_) { - DLOG(INFO) << "Received an old ack frame: ignoring"; + DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring"; return; } largest_seen_packet_with_ack_ = last_header_.packet_sequence_number; @@ -376,10 +371,9 @@ void QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { if (queued_packets_.empty()) { return; } - bool has_retransmittable_data = true; - QuicTime::Delta delay = congestion_manager_.TimeUntilSend( - time_of_last_received_packet_, false, has_retransmittable_data); + time_of_last_received_packet_, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); if (delay.IsZero()) { helper_->UnregisterSendAlarmIfRegistered(); if (!write_blocked_) { @@ -402,7 +396,7 @@ void QuicConnection::OnCongestionFeedbackFrame( bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { if (incoming_ack.received_info.largest_observed > packet_creator_.sequence_number()) { - DLOG(ERROR) << "Client observed unsent packet:" + DLOG(ERROR) << ENDPOINT << "Peer's observed unsent packet:" << incoming_ack.received_info.largest_observed << " vs " << packet_creator_.sequence_number(); // We got an error for data we have not sent. Error out. @@ -411,7 +405,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { if (incoming_ack.received_info.largest_observed < peer_largest_observed_packet_) { - DLOG(ERROR) << "Client's largest_observed packet decreased:" + DLOG(ERROR) << ENDPOINT << "Peer's largest_observed packet decreased:" << incoming_ack.received_info.largest_observed << " vs " << peer_largest_observed_packet_; // We got an error for data we have not sent. Error out. @@ -424,7 +418,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { GetMaxUnackedPackets(last_header_.public_header.version_flag)); if (incoming_ack.sent_info.least_unacked < peer_least_packet_awaiting_ack_) { - DLOG(ERROR) << "Client sent low least_unacked: " + DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: " << incoming_ack.sent_info.least_unacked << " vs " << peer_least_packet_awaiting_ack_; // We never process old ack frames, so this number should only increase. @@ -433,7 +427,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { if (incoming_ack.sent_info.least_unacked > last_header_.packet_sequence_number) { - DLOG(ERROR) << "Client sent least_unacked:" + DLOG(ERROR) << ENDPOINT << "Peer sent least_unacked:" << incoming_ack.sent_info.least_unacked << " greater than the enclosing packet sequence number:" << last_header_.packet_sequence_number; @@ -443,7 +437,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { if (!incoming_ack.received_info.missing_packets.empty() && *incoming_ack.received_info.missing_packets.rbegin() > incoming_ack.received_info.largest_observed) { - DLOG(ERROR) << "Client sent missing packet: " + DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: " << *incoming_ack.received_info.missing_packets.rbegin() << " greater than largest observed: " << incoming_ack.received_info.largest_observed; @@ -453,7 +447,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { if (!incoming_ack.received_info.missing_packets.empty() && *incoming_ack.received_info.missing_packets.begin() < least_packet_awaited_by_peer_) { - DLOG(ERROR) << "Client sent missing packet: " + DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: " << *incoming_ack.received_info.missing_packets.begin() << "smaller than least_packet_awaited_by_peer_: " << least_packet_awaited_by_peer_; @@ -464,7 +458,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { incoming_ack.received_info.largest_observed, incoming_ack.received_info.missing_packets, incoming_ack.received_info.entropy_hash)) { - DLOG(ERROR) << "Client sent invalid entropy."; + DLOG(ERROR) << ENDPOINT << "Peer sent invalid entropy."; return false; } @@ -589,7 +583,7 @@ void QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) { debug_visitor_->OnRstStreamFrame(frame); } DLOG(INFO) << "Stream reset with error " - << QuicUtils::ErrorToString(frame.error_code); + << QuicUtils::StreamErrorToString(frame.error_code); visitor_->OnRstStream(frame); } @@ -598,13 +592,13 @@ void QuicConnection::OnConnectionCloseFrame( if (debug_visitor_) { debug_visitor_->OnConnectionCloseFrame(frame); } - DLOG(INFO) << "Connection closed with error " + DLOG(INFO) << ENDPOINT << "Connection closed with error " << QuicUtils::ErrorToString(frame.error_code); CloseConnection(frame.error_code, true); } void QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) { - DLOG(INFO) << "Go away received with error " + DLOG(INFO) << ENDPOINT << "Go away received with error " << QuicUtils::ErrorToString(frame.error_code) << " and reason:" << frame.reason_phrase; visitor_->OnGoAway(frame); @@ -614,15 +608,16 @@ void QuicConnection::OnPacketComplete() { // TODO(satyamshekhar): Don't do anything if this packet closed the // connection. if (!last_packet_revived_) { - DLOG(INFO) << "Got packet " << last_header_.packet_sequence_number + DLOG(INFO) << ENDPOINT << "Got packet " + << last_header_.packet_sequence_number << " with " << last_stream_frames_.size() << " stream frames for " << last_header_.public_header.guid; congestion_manager_.RecordIncomingPacket( last_size_, last_header_.packet_sequence_number, time_of_last_received_packet_, last_packet_revived_); } else { - DLOG(INFO) << "Got revived packet with " << last_stream_frames_.size() - << " frames."; + DLOG(INFO) << ENDPOINT << "Got revived packet with " + << last_stream_frames_.size() << " frames."; } if ((last_stream_frames_.empty() || @@ -673,7 +668,7 @@ QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, } void QuicConnection::SendRstStream(QuicStreamId id, - QuicErrorCode error) { + QuicRstStreamErrorCode error) { packet_generator_.AddControlFrame( QuicFrame(new QuicRstStreamFrame(id, error))); } @@ -716,14 +711,15 @@ bool QuicConnection::OnCanWrite() { // or the congestion manager to prohibit sending. If we've sent everything // we had queued and we're still not blocked, let the visitor know it can // write more. - if (CanWrite(false, true)) { + if (CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) { packet_generator_.StartBatchOperations(); bool all_bytes_written = visitor_->OnCanWrite(); packet_generator_.FinishBatchOperations(); // After the visitor writes, it may have caused the socket to become write // blocked or the congestion manager to prohibit sending, so check again. - if (!write_blocked_ && !all_bytes_written && CanWrite(false, true)) { + if (!write_blocked_ && !all_bytes_written && + CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) { // We're not write blocked, but some stream didn't write out all of its // bytes. Register for 'immediate' resumption so we'll keep writing after // other quic connections have had a chance to use the socket. @@ -747,8 +743,8 @@ bool QuicConnection::WriteQueuedPackets() { num_queued_packets = queued_packets_.size(); if (WritePacket(packet_iterator->sequence_number, packet_iterator->packet, - packet_iterator->has_retransmittable_data, - !kForce)) { + packet_iterator->retransmittable, + NO_FORCE)) { packet_iterator = queued_packets_.erase(packet_iterator); } else { // Continue, because some queued packets may still be writable. @@ -761,7 +757,8 @@ bool QuicConnection::WriteQueuedPackets() { } void QuicConnection::RecordPacketReceived(const QuicPacketHeader& header) { - DLOG(INFO) << "Recording received packet: " << header.packet_sequence_number; + DLOG(INFO) << ENDPOINT << "Recording received packet: " + << header.packet_sequence_number; QuicPacketSequenceNumber sequence_number = header.packet_sequence_number; DCHECK(IsAwaitingPacket(outgoing_ack_.received_info, sequence_number)); @@ -858,11 +855,11 @@ void QuicConnection::RetransmitPacket( SendOrQueuePacket(serialized_packet.sequence_number, serialized_packet.packet, serialized_packet.entropy_hash, - true); + HAS_RETRANSMITTABLE_DATA); } -bool QuicConnection::CanWrite(bool is_retransmission, - bool has_retransmittable_data) { +bool QuicConnection::CanWrite(Retransmission retransmission, + HasRetransmittableData retransmittable) { // TODO(ianswett): If the packet is a retransmit, the current send alarm may // be too long. if (write_blocked_ || helper_->IsSendAlarmSet()) { @@ -871,7 +868,7 @@ bool QuicConnection::CanWrite(bool is_retransmission, QuicTime now = clock_->Now(); QuicTime::Delta delay = congestion_manager_.TimeUntilSend( - now, is_retransmission, has_retransmittable_data); + now, retransmission, retransmittable); if (delay.IsInfinite()) { // TODO(pwestin): should be false but trigger other bugs see b/8350327. return true; @@ -915,40 +912,42 @@ void QuicConnection::MaybeSetupRetransmission( if (!handling_retransmission_timeout_) { helper_->SetRetransmissionAlarm(retransmission_delay); } - // TODO(satyamshekhar): restore pacekt reordering with Ian's TODO in + // TODO(satyamshekhar): restore packet reordering with Ian's TODO in // SendStreamData(). } bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, - bool has_retransmittable_data, - bool forced) { + HasRetransmittableData retransmittable, + Force forced) { if (!connected_) { - DLOG(INFO) - << "Dropping packet to be sent since connection is disconnected."; + DLOG(INFO) << ENDPOINT + << "Not sending packet as connection is disconnected."; delete packet; // Returning true because we deleted the packet and the caller shouldn't // delete it again. return true; } - bool is_retransmission = IsRetransmission(sequence_number); + Retransmission retransmission = IsRetransmission(sequence_number) ? + IS_RETRANSMISSION : NOT_RETRANSMISSION; // If we are not forced and we can't write, then simply return false; - if (!forced && !CanWrite(is_retransmission, has_retransmittable_data)) { + if (forced == NO_FORCE && !CanWrite(retransmission, retransmittable)) { return false; } scoped_ptr<QuicEncryptedPacket> encrypted( framer_.EncryptPacket(sequence_number, *packet)); - DLOG(INFO) << "Sending packet number " << sequence_number << " : " - << (packet->is_fec_packet() ? "FEC " : - (has_retransmittable_data ? "data bearing " : " ack only ")) + DLOG(INFO) << ENDPOINT << "Sending packet number " << sequence_number + << " : " << (packet->is_fec_packet() ? "FEC " : + (retransmittable == HAS_RETRANSMITTABLE_DATA + ? "data bearing " : " ack only ")) << " Packet length:" << packet->length(); DCHECK(encrypted->length() <= kMaxPacketSize) << "Packet " << sequence_number << " will not be read; too large: " << packet->length() << " " << encrypted->length() << " " - << outgoing_ack_ << " forced: " << (forced ? "yes" : "no"); + << outgoing_ack_ << " forced: " << (forced == FORCE ? "yes" : "no"); int error; QuicTime now = clock_->Now(); @@ -964,7 +963,7 @@ bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number, return helper_->IsWriteBlockedDataBuffered(); } time_of_last_sent_packet_ = now; - DVLOG(1) << "time of last sent packet: " << now.ToMicroseconds(); + DVLOG(1) << "time of last sent packet: " << now.ToDebuggingValue(); // TODO(wtc): Is it correct to continue if the write failed. // Set the retransmit alarm only when we have sent the packet to the client @@ -973,12 +972,12 @@ bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number, MaybeSetupRetransmission(sequence_number); congestion_manager_.SentPacket(sequence_number, now, packet->length(), - is_retransmission); + retransmission); stats_.bytes_sent += encrypted->length(); ++stats_.packets_sent; - if (is_retransmission) { + if (retransmission == IS_RETRANSMISSION) { stats_.bytes_retransmitted += encrypted->length(); ++stats_.packets_retransmitted; } @@ -1004,19 +1003,19 @@ bool QuicConnection::OnSerializedPacket( return SendOrQueuePacket(serialized_packet.sequence_number, serialized_packet.packet, serialized_packet.entropy_hash, - serialized_packet.retransmittable_frames != NULL); + serialized_packet.retransmittable_frames != NULL ? + HAS_RETRANSMITTABLE_DATA : + NO_RETRANSMITTABLE_DATA); } bool QuicConnection::SendOrQueuePacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, QuicPacketEntropyHash entropy_hash, - bool has_retransmittable_data) { - entropy_manager_.RecordSentPacketEntropyHash(sequence_number, - entropy_hash); - if (!WritePacket(sequence_number, packet, has_retransmittable_data, - !kForce)) { + 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, - has_retransmittable_data)); + retransmittable)); return false; } return true; @@ -1085,7 +1084,7 @@ QuicTime QuicConnection::OnRetransmissionTimeout() { } retransmission_timeouts_.pop(); if (!MaybeRetransmitPacketForRTO(retransmission_info.sequence_number)) { - DLOG(INFO) << "MaybeRetransmitPacketForRTO failed: " + DLOG(INFO) << ENDPOINT << "MaybeRetransmitPacketForRTO failed: " << "adding an extra delay for " << retransmission_info.sequence_number; retransmission_info.scheduled_time = clock_->ApproximateNow().Add( @@ -1097,7 +1096,7 @@ QuicTime QuicConnection::OnRetransmissionTimeout() { handling_retransmission_timeout_ = false; if (retransmission_timeouts_.empty()) { - return QuicTime::FromMilliseconds(0); + return QuicTime::Zero(); } // We have packets remaining. Return the absolute RTO of the oldest packet @@ -1105,6 +1104,18 @@ QuicTime QuicConnection::OnRetransmissionTimeout() { return retransmission_timeouts_.top().scheduled_time; } +void QuicConnection::ChangeEncrypter(QuicEncrypter* encrypter) { + framer_.set_encrypter(encrypter); +} + +void QuicConnection::PushDecrypter(QuicDecrypter* decrypter) { + framer_.push_decrypter(decrypter); +} + +void QuicConnection::PopDecrypter() { + framer_.pop_decrypter(); +} + void QuicConnection::MaybeProcessRevivedPacket() { QuicFecGroup* group = GetFecGroup(); if (group == NULL || !group->CanRevive()) { @@ -1150,8 +1161,8 @@ void QuicConnection::SendConnectionClose(QuicErrorCode error) { void QuicConnection::SendConnectionClosePacket(QuicErrorCode error, const string& details) { - DLOG(INFO) << "Force closing with error " << QuicUtils::ErrorToString(error) - << " (" << error << ")"; + DLOG(INFO) << ENDPOINT << "Force closing with error " + << QuicUtils::ErrorToString(error) << " (" << error << ")"; QuicConnectionCloseFrame frame; frame.error_code = error; frame.error_details = details; @@ -1168,8 +1179,9 @@ void QuicConnection::SendConnectionClosePacket(QuicErrorCode error, WritePacket(serialized_packet.sequence_number, serialized_packet.packet, - serialized_packet.retransmittable_frames != NULL, - kForce); + serialized_packet.retransmittable_frames != NULL ? + HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA, + FORCE); } void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error, @@ -1186,7 +1198,8 @@ void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) { void QuicConnection::SendGoAway(QuicErrorCode error, QuicStreamId last_good_stream_id, const string& reason) { - DLOG(INFO) << "Going away with error " << QuicUtils::ErrorToString(error) + DLOG(INFO) << ENDPOINT << "Going away with error " + << QuicUtils::ErrorToString(error) << " (" << error << ")"; packet_generator_.AddControlFrame( QuicFrame(new QuicGoAwayFrame(error, last_good_stream_id, reason))); @@ -1223,8 +1236,8 @@ bool QuicConnection::CheckForTimeout() { time_of_last_sent_packet_); QuicTime::Delta delta = now.Subtract(time_of_last_packet); - DVLOG(1) << "last packet " << time_of_last_packet.ToMicroseconds() - << " now:" << now.ToMicroseconds() + DVLOG(1) << "last packet " << time_of_last_packet.ToDebuggingValue() + << " now:" << now.ToDebuggingValue() << " delta:" << delta.ToMicroseconds(); if (delta >= timeout_) { SendConnectionClose(QUIC_CONNECTION_TIMED_OUT); diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 3c3c00d..d097acb 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -66,7 +66,8 @@ class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface { // Called when the connection is closed either locally by the framer, or // remotely by the peer. - virtual void ConnectionClose(QuicErrorCode error, bool from_peer) = 0; + virtual void ConnectionClose(QuicErrorCode error, + bool from_peer) = 0; // Called when packets are acked by the peer. virtual void OnAck(const SequenceNumberSet& acked_packets) = 0; @@ -197,6 +198,11 @@ class NET_EXPORT_PRIVATE QuicConnection public QuicBlockedWriterInterface, public QuicPacketGenerator::DelegateInterface { public: + enum Force { + NO_FORCE, + FORCE + }; + // Constructs a new QuicConnection for the specified |guid| and |address|. // |helper| will be owned by this connection. QuicConnection(QuicGuid guid, @@ -218,7 +224,7 @@ class NET_EXPORT_PRIVATE QuicConnection bool fin); // Send a stream reset frame to the peer. virtual void SendRstStream(QuicStreamId id, - QuicErrorCode error); + QuicRstStreamErrorCode error); // Sends the connection close packet without affecting the state of the // connection. This should only be called if the session is actively being @@ -280,6 +286,9 @@ class NET_EXPORT_PRIVATE QuicConnection virtual void OnPacketComplete() OVERRIDE; // QuicPacketGenerator::DelegateInterface + virtual bool CanWrite( + Retransmission is_retransmission, + HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual QuicAckFrame* CreateAckFrame() OVERRIDE; virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() OVERRIDE; virtual bool OnSerializedPacket(const SerializedPacket& packet) OVERRIDE; @@ -336,6 +345,27 @@ 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 + // 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(); } + protected: // Deletes all missing packets before least unacked. The connection won't // process any packets with sequence number before |least_unacked| that it @@ -353,7 +383,7 @@ class NET_EXPORT_PRIVATE QuicConnection virtual bool SendOrQueuePacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, QuicPacketEntropyHash entropy_hash, - bool has_retransmittable_data); + 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 @@ -361,12 +391,12 @@ class NET_EXPORT_PRIVATE QuicConnection // 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 true, then the packet will be sent immediately and the send + // |force| is FORCE, then the packet will be sent immediately and the send // scheduler will not be consulted. bool WritePacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, - bool has_retransmittable_data, - bool force); + HasRetransmittableData retransmittable, + Force force); // Make sure an ack we got from our peer is sane. bool ValidateAckFrame(const QuicAckFrame& incoming_ack); @@ -390,15 +420,15 @@ class NET_EXPORT_PRIVATE QuicConnection struct QueuedPacket { QueuedPacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, - bool has_retransmittable_data) + HasRetransmittableData retransmittable) : sequence_number(sequence_number), packet(packet), - has_retransmittable_data(has_retransmittable_data) { + retransmittable(retransmittable) { } QuicPacketSequenceNumber sequence_number; QuicPacket* packet; - bool has_retransmittable_data; + HasRetransmittableData retransmittable; }; struct RetransmissionInfo { @@ -444,10 +474,6 @@ class NET_EXPORT_PRIVATE QuicConnection // Sends a version negotiation packet to the peer. void SendVersionNegotiationPacket(); - // Checks if a packet can be written now, and sets the timer if necessary. - virtual bool CanWrite(bool is_retransmission, - bool has_retransmittable_data) OVERRIDE; - void MaybeSetupRetransmission(QuicPacketSequenceNumber sequence_number); bool IsRetransmission(QuicPacketSequenceNumber sequence_number); void RetransmitAllUnackedPackets(); diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc index 08743d05..2b2c633 100644 --- a/net/quic/quic_connection_helper_test.cc +++ b/net/quic/quic_connection_helper_test.cc @@ -62,6 +62,7 @@ class QuicConnectionHelperTest : public ::testing::Test { framer_(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false), net_log_(BoundNetLog()), frame_(1, false, 0, kData) { @@ -251,7 +252,7 @@ TEST_F(QuicConnectionHelperTest, SetAckAlarm) { EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()), runner_->GetPostedTasks()[1].delay); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); runner_->RunNextTask(); EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.ApproximateNow()); } @@ -295,7 +296,7 @@ TEST_F(QuicConnectionHelperTest, ResetAckAlarm) { // Verify that the ack alarm task has been re-posted. ASSERT_EQ(2u, runner_->GetPostedTasks().size()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); runner_->RunNextTask(); EXPECT_EQ(QuicTime::Zero().Add(delta2), clock_.ApproximateNow()); } @@ -309,11 +310,11 @@ TEST_F(QuicConnectionHelperTest, TestRetransmission) { QuicTime::Delta::FromMilliseconds(500); QuicTime start = clock_.ApproximateNow(); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)); // Send a packet. connection_->SendStreamData(1, kData, 0, false); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, true)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION)); // Since no ack was received, the retransmission alarm will fire and // retransmit it. runner_->RunNextTask(); @@ -332,12 +333,13 @@ TEST_F(QuicConnectionHelperTest, InitialTimeout) { EXPECT_EQ(base::TimeDelta::FromMicroseconds(kDefaultTimeoutUs), runner_->GetPostedTasks().front().delay); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); // After we run the next task, we should close the connection. EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false)); runner_->RunNextTask(); - EXPECT_EQ(QuicTime::FromMicroseconds(kDefaultTimeoutUs), + EXPECT_EQ(QuicTime::Zero().Add( + QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)), clock_.ApproximateNow()); EXPECT_FALSE(connection_->connected()); EXPECT_TRUE(AtEof()); @@ -372,12 +374,12 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) { Initialize(); EXPECT_TRUE(connection_->connected()); - EXPECT_EQ(0u, clock_.ApproximateNow().ToMicroseconds()); + EXPECT_EQ(0u, clock_.NowAsDeltaSinceUnixEpoch().ToMicroseconds()); // When we send a packet, the timeout will change to 5000 + kDefaultTimeout. clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(5000)); - EXPECT_EQ(5000u, clock_.ApproximateNow().ToMicroseconds()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); + EXPECT_EQ(5000u, clock_.NowAsDeltaSinceUnixEpoch().ToMicroseconds()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); // Send an ack so we don't set the retransmission alarm. connection_->SendAck(); @@ -386,15 +388,17 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) { // network event at t=5000. The alarm will reregister. runner_->RunNextTask(); - EXPECT_EQ(QuicTime::FromMicroseconds(kDefaultTimeoutUs), + EXPECT_EQ(QuicTime::Zero().Add( + QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)), clock_.ApproximateNow()); EXPECT_TRUE(connection_->connected()); // This time, we should time out. EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, NOT_RETRANSMISSION)); runner_->RunNextTask(); - EXPECT_EQ(kDefaultTimeoutUs + 5000, clock_.ApproximateNow().ToMicroseconds()); + EXPECT_EQ(kDefaultTimeoutUs + 5000, + clock_.NowAsDeltaSinceUnixEpoch().ToMicroseconds()); EXPECT_FALSE(connection_->connected()); EXPECT_TRUE(AtEof()); } @@ -404,18 +408,20 @@ TEST_F(QuicConnectionHelperTest, SendSchedulerDelayThenSend) { Initialize(); // Test that if we send a packet with a delay, it ends up queued. - EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, false, _)).WillOnce( - testing::Return(QuicTime::Delta::FromMicroseconds(1))); + EXPECT_CALL( + *send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(1))); QuicPacket* packet = ConstructRawDataPacket(1); - connection_->SendOrQueuePacket(1, packet, 0, kHasData); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); + connection_->SendOrQueuePacket(1, packet, 0, HAS_RETRANSMITTABLE_DATA); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); EXPECT_EQ(1u, connection_->NumQueuedPackets()); // Advance the clock to fire the alarm, and configure the scheduler // to permit the packet to be sent. - EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, false, _)).WillRepeatedly( - testing::Return(QuicTime::Delta::Zero())); + EXPECT_CALL( + *send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillRepeatedly( + testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(testing::Return(true)); runner_->RunNextTask(); EXPECT_EQ(0u, connection_->NumQueuedPackets()); diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc index 3679d1ce3..5b13c92 100644 --- a/net/quic/quic_connection_logger.cc +++ b/net/quic/quic_connection_logger.cc @@ -89,7 +89,7 @@ Value* NetLogQuicCongestionFeedbackFrameCallback( frame->inter_arrival.received_packet_times.begin(); it != frame->inter_arrival.received_packet_times.end(); ++it) { std::string value = base::Uint64ToString(it->first) + "@" + - base::Uint64ToString(it->second.ToMilliseconds()); + base::Uint64ToString(it->second.ToDebuggingValue()); received->Append(new base::StringValue(value)); } break; diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 72322ff..f2811f3 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -44,9 +44,6 @@ const char data1[] = "foo"; const char data2[] = "bar"; const bool kFin = true; -const bool kForce = true; -const bool kIsRetransmission = true; -const bool kHasData = true; const bool kEntropyFlag = true; const bool kFecEntropyFlag = true; const QuicPacketEntropyHash kTestEntropyHash = 76; @@ -81,7 +78,8 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { : clock_(clock), random_generator_(random_generator), retransmission_alarm_(QuicTime::Zero()), - send_alarm_(QuicTime::FromMilliseconds(-1)), + send_alarm_(QuicTime::Zero().Subtract( + QuicTime::Delta::FromMilliseconds(1))), timeout_alarm_(QuicTime::Zero()), blocked_(false), is_server_(true) { @@ -103,6 +101,7 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { QuicFramer framer(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), is_server_); FramerVisitorCapturingFrames visitor; framer.set_visitor(&visitor); @@ -156,7 +155,8 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { } virtual void UnregisterSendAlarmIfRegistered() OVERRIDE { - send_alarm_ = QuicTime::FromMilliseconds(-1); + send_alarm_ = + QuicTime::Zero().Subtract(QuicTime::Delta::FromMilliseconds(1)); } virtual void SetAckAlarm(QuicTime::Delta delay) OVERRIDE {} @@ -248,6 +248,8 @@ class TestConnection : public QuicConnection { void set_is_server(bool is_server) { helper_->set_is_server(!is_server); + QuicPacketCreatorPeer::SetIsServer( + QuicConnectionPeer::GetPacketCreator(this), is_server); QuicConnectionPeer::SetIsServer(this, is_server); } @@ -267,6 +269,7 @@ class QuicConnectionTest : public ::testing::Test { framer_(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false), creator_(guid_, &framer_, QuicRandom::GetInstance(), false), send_algorithm_(new StrictMock<MockSendAlgorithm>), @@ -832,7 +835,7 @@ TEST_F(QuicConnectionTest, FramePacking) { // Unblock the connection. helper_->UnregisterSendAlarmIfRegistered(); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, !kIsRetransmission)) + SentPacket(_, _, _, NOT_RETRANSMISSION)) .Times(1); connection_.OnCanWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -866,7 +869,7 @@ TEST_F(QuicConnectionTest, FramePackingFEC) { // Unblock the connection. helper_->UnregisterSendAlarmIfRegistered(); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, !kIsRetransmission)).Times(2); + SentPacket(_, _, _, NOT_RETRANSMISSION)).Times(2); connection_.OnCanWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); @@ -886,7 +889,7 @@ TEST_F(QuicConnectionTest, OnCanWrite) { Return(false))); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillRepeatedly( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillRepeatedly( testing::Return(QuicTime::Delta::Zero())); // Unblock the connection. @@ -941,7 +944,7 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) { // The third nack should trigger a retransimission. EXPECT_CALL(*send_algorithm_, SentPacket(_, _, second_packet_size - kQuicVersionSize, - kIsRetransmission)).Times(1); + IS_RETRANSMISSION)).Times(1); ProcessAckPacket(&nack_two); } @@ -949,7 +952,7 @@ TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) { EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); QuicPacketSequenceNumber largest_observed; QuicByteCount packet_size; - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission)) + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION)) .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size))); EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1); connection_.SendStreamData(1, "foo", 0, !kFin); @@ -960,11 +963,11 @@ TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) { ProcessAckPacket(&frame); // Second udp packet will force an ack frame. EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, !kIsRetransmission)); + SentPacket(_, _, _, NOT_RETRANSMISSION)); ProcessAckPacket(&frame); // Third nack should retransmit the largest observed packet. EXPECT_CALL(*send_algorithm_, SentPacket(_, _, packet_size - kQuicVersionSize, - kIsRetransmission)); + IS_RETRANSMISSION)); ProcessAckPacket(&frame); } @@ -1176,7 +1179,7 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2); QuicPacketSequenceNumber original_sequence_number; EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, !kIsRetransmission)) + SentPacket(_, _, _, NOT_RETRANSMISSION)) .WillOnce(SaveArg<1>(&original_sequence_number)); connection_.SendStreamData(1, "foo", 0, !kFin); EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission( @@ -1187,7 +1190,7 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); QuicPacketSequenceNumber rto_sequence_number; EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, kIsRetransmission)) + SentPacket(_, _, _, IS_RETRANSMISSION)) .WillOnce(SaveArg<1>(&rto_sequence_number)); connection_.OnRetransmissionTimeout(); EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission( @@ -1200,9 +1203,9 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { QuicPacketSequenceNumber nack_sequence_number; // Ack packets might generate some other packets, which are not // retransmissions. (More ack packets). - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission)) + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION)) .Times(AnyNumber()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, kIsRetransmission)) + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_RETRANSMISSION)) .WillOnce(SaveArg<1>(&nack_sequence_number)); QuicAckFrame ack(rto_sequence_number, QuicTime::Zero(), 0); // Ack the retransmitted packet. @@ -1348,10 +1351,11 @@ TEST_F(QuicConnectionTest, SendScheduler) { // Test that if we send a packet without delay, it is not queued. QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); - connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true); + connection_.SendOrQueuePacket( + 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } @@ -1359,10 +1363,11 @@ TEST_F(QuicConnectionTest, SendSchedulerDelay) { // Test that if we send a packet with a delay, it ends up queued. QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0); - connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true); + connection_.SendOrQueuePacket( + 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); } @@ -1370,9 +1375,10 @@ TEST_F(QuicConnectionTest, SendSchedulerForce) { // Test that if we force send a packet, it is not queued. QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, kIsRetransmission, _)).Times(0); + TimeUntilSend(_, IS_RETRANSMISSION, _)).Times(0); EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); - connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true); + connection_.SendOrQueuePacket( + 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); // XXX: fixme. was: connection_.SendOrQueuePacket(1, packet, kForce); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } @@ -1381,10 +1387,11 @@ TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) { QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); helper_->set_blocked(true); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0); - connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true); + connection_.SendOrQueuePacket( + 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); } @@ -1392,15 +1399,16 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) { // Test that if we send a packet with a delay, it ends up queued. QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); - connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true); + connection_.SendOrQueuePacket( + 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Advance the clock to fire the alarm, and configure the scheduler // to permit the packet to be sent. EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillRepeatedly( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillRepeatedly( testing::Return(QuicTime::Delta::Zero())); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1)); helper_->UnregisterSendAlarmIfRegistered(); @@ -1411,18 +1419,18 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) { } TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { - EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission, _)) + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _)) .WillRepeatedly(testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1); EXPECT_CALL(*send_algorithm_, - SentPacket(_, 1, _, !kIsRetransmission)); + SentPacket(_, 1, _, NOT_RETRANSMISSION)); connection_.SendStreamData(1, "foo", 0, !kFin); EXPECT_EQ(0u, connection_.NumQueuedPackets()); // Advance the time for retransmission of lost packet. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(501)); // Test that if we send a retransmit with a delay, it ends up queued. EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, IS_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); connection_.OnRetransmissionTimeout(); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -1430,12 +1438,12 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { // Advance the clock to fire the alarm, and configure the scheduler // to permit the packet to be sent. EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, IS_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); // Ensure the scheduler is notified this is a retransmit. EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, kIsRetransmission)); + SentPacket(_, _, _, IS_RETRANSMISSION)); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1)); helper_->UnregisterSendAlarmIfRegistered(); EXPECT_CALL(visitor_, OnCanWrite()); @@ -1446,30 +1454,33 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) { QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); - connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true); + connection_.SendOrQueuePacket( + 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, true); + connection_.SendOrQueuePacket( + 2, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(2u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); - connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true); + connection_.SendOrQueuePacket( + 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Now send non-retransmitting information, that we're not going to // retransmit 3. The far end should stop waiting for it. QuicAckFrame frame(0, QuicTime::Zero(), 1); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillRepeatedly( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillRepeatedly( testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); @@ -1484,16 +1495,17 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) { QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); - connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, kHasData); + connection_.SendOrQueuePacket( + 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Now send non-retransmitting information, that we're not going to // retransmit 3. The far end should stop waiting for it. QuicAckFrame frame(0, QuicTime::Zero(), 1); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); ProcessAckPacket(&frame); @@ -1503,9 +1515,10 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) { TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) { QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); - connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, kHasData); + connection_.SendOrQueuePacket( + 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // OnCanWrite should not send the packet (because of the delay) @@ -1522,7 +1535,7 @@ TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) { // Queue the first packet. EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission, _)).WillOnce( + TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); EXPECT_EQ(0u, connection_.SendStreamData( 1, "EnoughDataToQueue", 0, !kFin).bytes_consumed); @@ -1556,7 +1569,8 @@ TEST_F(QuicConnectionTest, SendWhenDisconnected) { EXPECT_FALSE(connection_.connected()); QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0); - connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, kHasData); + connection_.SendOrQueuePacket( + 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); } TEST_F(QuicConnectionTest, PublicReset) { @@ -1674,7 +1688,8 @@ TEST_F(QuicConnectionTest, CheckSentEntropyHash) { packet_entropy_hash = 1 << (i % 8); } QuicPacket* packet = ConstructDataPacket(i, 0, entropy_flag); - connection_.SendOrQueuePacket(i, packet, packet_entropy_hash, true); + connection_.SendOrQueuePacket( + i, packet, packet_entropy_hash, HAS_RETRANSMITTABLE_DATA); if (is_missing) { missing_packets.insert(i); @@ -1723,18 +1738,18 @@ TEST_F(QuicConnectionTest, SendVersionNegotiationPacket) { TEST_F(QuicConnectionTest, CheckSendStats) { EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(3); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, !kIsRetransmission)); + SentPacket(_, _, _, NOT_RETRANSMISSION)); connection_.SendStreamData(1u, "first", 0, !kFin); size_t first_packet_size = last_sent_packet_size(); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, !kIsRetransmission)).Times(2); + SentPacket(_, _, _, NOT_RETRANSMISSION)).Times(2); connection_.SendStreamData(1u, "second", 0, !kFin); size_t second_packet_size = last_sent_packet_size(); // 2 retransmissions due to rto, 1 due to explicit nack. EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, kIsRetransmission)).Times(3); + SentPacket(_, _, _, IS_RETRANSMISSION)).Times(3); // Retransmit due to RTO. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index badddce..63a4f44 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc @@ -15,6 +15,7 @@ QuicCryptoClientStream::QuicCryptoClientStream(QuicSession* session, const string& server_hostname) : QuicCryptoStream(session), next_state_(STATE_IDLE), + decrypter_pushed_(false), server_hostname_(server_hostname) { config_.SetDefaults(); crypto_config_.SetDefaults(); @@ -94,6 +95,10 @@ void QuicCryptoClientStream::DoHandshakeLoop( next_state_ = STATE_RECV_SHLO; 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; return; } case STATE_RECV_REJ: @@ -111,6 +116,11 @@ void QuicCryptoClientStream::DoHandshakeLoop( CloseConnectionWithDetails(error, error_details); return; } + // Clear any new server write key that we may have set before. + if (decrypter_pushed_) { + session()->connection()->PopDecrypter(); + decrypter_pushed_ = false; + } next_state_ = STATE_SEND_CHLO; break; case STATE_RECV_SHLO: @@ -122,6 +132,14 @@ void QuicCryptoClientStream::DoHandshakeLoop( "Expected SHLO"); 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); return; case STATE_IDLE: diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h index 463994e..fb67ee4 100644 --- a/net/quic/quic_crypto_client_stream.h +++ b/net/quic/quic_crypto_client_stream.h @@ -57,6 +57,8 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { QuicNegotiatedParameters negotiated_params_; QuicCryptoNegotiatedParameters crypto_negotiated_params_; + 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 9c33d5b..251a8ef 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc @@ -5,6 +5,7 @@ #include "net/quic/quic_crypto_client_stream.h" #include "base/memory/scoped_ptr.h" +#include "net/quic/crypto/aes_128_gcm_encrypter.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" #include "net/quic/test_tools/crypto_test_utils.h" @@ -87,15 +88,30 @@ class QuicCryptoClientStreamTest : public ::testing::Test { }; TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + EXPECT_FALSE(stream_.handshake_complete()); } TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + CompleteCryptoHandshake(); EXPECT_TRUE(stream_.handshake_complete()); } TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + CompleteCryptoHandshake(); EXPECT_CALL(*connection_, SendConnectionClose( @@ -106,6 +122,11 @@ TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { } TEST_F(QuicCryptoClientStreamTest, BadMessageType) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + EXPECT_TRUE(stream_.CryptoConnect()); message_.set_tag(kCHLO); @@ -117,6 +138,11 @@ TEST_F(QuicCryptoClientStreamTest, BadMessageType) { } TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + CompleteCryptoHandshake(); const QuicNegotiatedParameters& params(stream_.negotiated_params()); diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc index 6fc508d..d1c21ff 100644 --- a/net/quic/quic_crypto_server_stream.cc +++ b/net/quic/quic_crypto_server_stream.cc @@ -12,7 +12,9 @@ namespace net { QuicCryptoServerStream::QuicCryptoServerStream(QuicSession* session) - : QuicCryptoStream(session) { + : QuicCryptoStream(session), + // TODO(agl): use real secret. + crypto_config_("secret") { config_.SetDefaults(); // Use hardcoded crypto parameters for now. CryptoHandshakeMessage extra_tags; @@ -56,8 +58,11 @@ void QuicCryptoServerStream::OnHandshakeMessage( string error_details; CryptoHandshakeMessage reply; crypto_config_.ProcessClientHello( - message, session()->connection()->guid(), &reply, - &crypto_negotiated_params_, &error_details); + message, session()->connection()->guid(), + session()->connection()->peer_address(), + session()->connection()->clock()->NowAsDeltaSinceUnixEpoch(), + session()->connection()->random_generator(), + &reply, &crypto_negotiated_params_, &error_details); if (reply.tag() == kSHLO) { // If we are returning a SHLO then we accepted the handshake. @@ -69,6 +74,17 @@ void QuicCryptoServerStream::OnHandshakeMessage( return; } + // Receiving a full CHLO implies the client is prepared to decrypt with + // the new server write key. We can start to encrypt with the new server + // write key. + // + // NOTE: the SHLO will be encrypted with the new server write key. + session()->connection()->ChangeEncrypter( + 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( + crypto_negotiated_params_.decrypter.release()); SetHandshakeComplete(QUIC_NO_ERROR); } diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc index 1d2b11d..173122d8 100644 --- a/net/quic/quic_crypto_server_stream_test.cc +++ b/net/quic/quic_crypto_server_stream_test.cc @@ -8,6 +8,7 @@ #include <vector> #include "base/memory/scoped_ptr.h" +#include "net/quic/crypto/aes_128_gcm_encrypter.h" #include "net/quic/crypto/crypto_framer.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/crypto_protocol.h" @@ -66,7 +67,8 @@ class QuicCryptoServerStreamTest : public ::testing::Test { public: QuicCryptoServerStreamTest() : guid_(1), - addr_(), + addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_) ? + ip_ : IPAddressNumber(), 1), connection_(new PacketSavingConnection(guid_, addr_, true)), session_(connection_, true), stream_(&session_) { @@ -82,6 +84,7 @@ class QuicCryptoServerStreamTest : public ::testing::Test { } protected: + IPAddressNumber ip_; QuicGuid guid_; IPEndPoint addr_; PacketSavingConnection* connection_; @@ -92,15 +95,30 @@ class QuicCryptoServerStreamTest : public ::testing::Test { }; TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + EXPECT_FALSE(stream_.handshake_complete()); } TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + CompleteCryptoHandshake(); EXPECT_TRUE(stream_.handshake_complete()); } TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + CompleteCryptoHandshake(); EXPECT_CALL(*connection_, SendConnectionClose( QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)); @@ -110,6 +128,11 @@ TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) { } TEST_F(QuicCryptoServerStreamTest, BadMessageType) { + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + message_.set_tag(kSHLO); ConstructHandshakeMessage(); EXPECT_CALL(*connection_, SendConnectionClose( diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index 0b8e27b..c97b857 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -46,6 +46,7 @@ QuicPacketSequenceNumber ClosestTo(QuicPacketSequenceNumber target, QuicFramer::QuicFramer(QuicVersionTag version, QuicDecrypter* decrypter, QuicEncrypter* encrypter, + QuicTime creation_time, bool is_server) : visitor_(NULL), fec_builder_(NULL), @@ -54,7 +55,8 @@ QuicFramer::QuicFramer(QuicVersionTag version, quic_version_(version), decrypter_(decrypter), encrypter_(encrypter), - is_server_(is_server) { + is_server_(is_server), + creation_time_(creation_time) { DCHECK(IsSupportedVersion(version)); } @@ -814,10 +816,11 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame( set_detailed_error("Unable to read time received."); return false; } + QuicTime time_received = creation_time_.Add( + QuicTime::Delta::FromMicroseconds(time_received_us)); inter_arrival->received_packet_times.insert( - make_pair(smallest_received, - QuicTime::FromMicroseconds(time_received_us))); + make_pair(smallest_received, time_received)); for (int i = 0; i < num_received_packets - 1; ++i) { uint16 sequence_delta; @@ -835,8 +838,8 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame( } QuicPacketSequenceNumber packet = smallest_received + sequence_delta; inter_arrival->received_packet_times.insert( - make_pair(packet, QuicTime::FromMicroseconds(time_received_us + - time_delta_us))); + make_pair(packet, time_received.Add( + QuicTime::Delta::FromMicroseconds(time_delta_us)))); } } break; @@ -889,7 +892,14 @@ bool QuicFramer::ProcessRstStreamFrame() { set_detailed_error("Unable to read rst stream error code."); return false; } - frame.error_code = static_cast<QuicErrorCode>(error_code); + + if (error_code >= QUIC_STREAM_LAST_ERROR || + error_code < QUIC_STREAM_NO_ERROR) { + set_detailed_error("Invalid rst stream error code."); + return false; + } + + frame.error_code = static_cast<QuicRstStreamErrorCode>(error_code); StringPiece error_details; if (!reader_->ReadStringPiece16(&error_details)) { @@ -910,6 +920,13 @@ bool QuicFramer::ProcessConnectionCloseFrame() { set_detailed_error("Unable to read connection close error code."); return false; } + + if (error_code >= QUIC_LAST_ERROR || + error_code < QUIC_NO_ERROR) { + set_detailed_error("Invalid error code."); + return false; + } + frame.error_code = static_cast<QuicErrorCode>(error_code); StringPiece error_details; @@ -938,12 +955,18 @@ bool QuicFramer::ProcessGoAwayFrame() { } frame.error_code = static_cast<QuicErrorCode>(error_code); + if (error_code >= QUIC_LAST_ERROR || + error_code < QUIC_NO_ERROR) { + set_detailed_error("Invalid error code."); + return false; + } + uint32 stream_id; if (!reader_->ReadUInt32(&stream_id)) { set_detailed_error("Unable to read last good stream id."); return false; } - frame.last_good_stream_id = static_cast<QuicErrorCode>(stream_id); + frame.last_good_stream_id = static_cast<QuicStreamId>(stream_id); StringPiece reason_phrase; if (!reader_->ReadStringPiece16(&reason_phrase)) { @@ -956,6 +979,7 @@ bool QuicFramer::ProcessGoAwayFrame() { return true; } +// static StringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket( const QuicEncryptedPacket& encrypted, bool includes_version) { return StringPiece(encrypted.data() + kStartOfHashData, @@ -963,12 +987,27 @@ StringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket( kStartOfHashData); } +void QuicFramer::push_decrypter(QuicDecrypter* decrypter) { + DCHECK(backup_decrypter_.get() == NULL); + backup_decrypter_.reset(decrypter_.release()); + decrypter_.reset(decrypter); +} + +void QuicFramer::pop_decrypter() { + DCHECK(backup_decrypter_.get() != NULL); + decrypter_.reset(backup_decrypter_.release()); +} + +void QuicFramer::set_encrypter(QuicEncrypter* encrypter) { + encrypter_.reset(encrypter); +} + QuicEncryptedPacket* QuicFramer::EncryptPacket( QuicPacketSequenceNumber packet_sequence_number, const QuicPacket& packet) { - scoped_ptr<QuicData> out(encrypter_->Encrypt(packet_sequence_number, - packet.AssociatedData(), - packet.Plaintext())); + scoped_ptr<QuicData> out(encrypter_->EncryptPacket(packet_sequence_number, + packet.AssociatedData(), + packet.Plaintext())); if (out.get() == NULL) { RaiseError(QUIC_ENCRYPTION_FAILURE); return NULL; @@ -994,10 +1033,19 @@ bool QuicFramer::DecryptPayload(QuicPacketSequenceNumber sequence_number, return false; } DCHECK(decrypter_.get() != NULL); - decrypted_.reset(decrypter_->Decrypt( + decrypted_.reset(decrypter_->DecryptPacket( sequence_number, GetAssociatedDataFromEncryptedPacket(packet, version_flag), encrypted)); + if (decrypted_.get() == NULL && backup_decrypter_.get() != NULL) { + decrypted_.reset(backup_decrypter_->DecryptPacket( + sequence_number, + GetAssociatedDataFromEncryptedPacket(packet, version_flag), + encrypted)); + } + // 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; } @@ -1221,9 +1269,8 @@ bool QuicFramer::AppendQuicCongestionFeedbackFramePayload( } QuicTime lowest_time = it->second; - // TODO(ianswett): Use time deltas from the connection's first received - // packet. - if (!writer->WriteUInt64(lowest_time.ToMicroseconds())) { + if (!writer->WriteUInt64( + lowest_time.Subtract(creation_time_).ToMicroseconds())) { return false; } diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h index 7a00aaa..80d7854 100644 --- a/net/quic/quic_framer.h +++ b/net/quic/quic_framer.h @@ -151,6 +151,7 @@ class NET_EXPORT_PRIVATE QuicFramer { QuicFramer(QuicVersionTag quic_version, QuicDecrypter* decrypter, QuicEncrypter* encrypter, + QuicTime creation_time, bool is_server); virtual ~QuicFramer(); @@ -269,6 +270,13 @@ 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); + // Returns a new encrypted packet, owned by the caller. QuicEncryptedPacket* EncryptPacket(QuicPacketSequenceNumber sequence_number, const QuicPacket& packet); @@ -369,13 +377,18 @@ class NET_EXPORT_PRIVATE QuicFramer { scoped_ptr<QuicData> decrypted_; // Version of the protocol being used. QuicVersionTag quic_version_; - // Decrypter used to decrypt packets during parsing. + // 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_; // Tracks if the framer is being used by the entity that received the // connection or the entity that initiated it. bool is_server_; + // The time this frames was created. Time written to the wire will be + // written as a delta from this value. + QuicTime creation_time_; DISALLOW_COPY_AND_ASSIGN(QuicFramer); }; diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index 12d6b2f..8856897 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -73,9 +73,16 @@ class TestEncrypter : public QuicEncrypter { virtual bool SetNoncePrefix(StringPiece nonce_prefix) OVERRIDE { return true; } - virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number, - StringPiece associated_data, - StringPiece plaintext) OVERRIDE { + virtual bool Encrypt(StringPiece nonce, + StringPiece associated_data, + StringPiece plaintext, + unsigned char* output) { + CHECK(false) << "Not implemented"; + return false; + } + virtual QuicData* EncryptPacket(QuicPacketSequenceNumber sequence_number, + StringPiece associated_data, + StringPiece plaintext) { sequence_number_ = sequence_number; associated_data_ = associated_data.as_string(); plaintext_ = plaintext.as_string(); @@ -113,9 +120,17 @@ class TestDecrypter : public QuicDecrypter { virtual bool SetNoncePrefix(StringPiece nonce_prefix) OVERRIDE { return true; } - virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number, - StringPiece associated_data, - StringPiece ciphertext) OVERRIDE { + virtual bool Decrypt(StringPiece nonce, + StringPiece associated_data, + StringPiece ciphertext, + unsigned char* output, + size_t* output_length) { + CHECK(false) << "Not implemented"; + return false; + } + virtual QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number, + StringPiece associated_data, + StringPiece ciphertext) { sequence_number_ = sequence_number; associated_data_ = associated_data.as_string(); ciphertext_ = ciphertext.as_string(); @@ -255,7 +270,8 @@ class QuicFramerTest : public ::testing::Test { QuicFramerTest() : encrypter_(new test::TestEncrypter()), decrypter_(new test::TestDecrypter()), - framer_(kQuicVersion1, decrypter_, encrypter_, true) { + start_(QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(0x10))), + framer_(kQuicVersion1, decrypter_, encrypter_, start_, true) { framer_.set_visitor(&visitor_); framer_.set_entropy_calculator(&entropy_calculator_); } @@ -347,6 +363,7 @@ class QuicFramerTest : public ::testing::Test { test::TestEncrypter* encrypter_; test::TestDecrypter* decrypter_; + QuicTime start_; QuicFramer framer_; test::TestQuicVisitor visitor_; test::TestEntropyCalculator entropy_calculator_; @@ -1183,10 +1200,10 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) { 0x02, 0x03, // num received packets 0x03, - // smallest ack sequence number + // lowest sequence number 0xBA, 0x9A, 0x78, 0x56, 0x34, 0x12, - // ack time + // receive time 0x87, 0x96, 0xA5, 0xB4, 0xC3, 0xD2, 0xE1, 0x07, // sequence delta @@ -1217,16 +1234,16 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) { TimeMap::const_iterator iter = frame.inter_arrival.received_packet_times.begin(); EXPECT_EQ(GG_UINT64_C(0x0123456789ABA), iter->first); - EXPECT_EQ(QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59687)), - iter->second); + EXPECT_EQ(GG_INT64_C(0x07E1D2C3B4A59687), + iter->second.Subtract(start_).ToMicroseconds()); ++iter; EXPECT_EQ(GG_UINT64_C(0x0123456789ABB), iter->first); - EXPECT_EQ(QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59688)), - iter->second); + EXPECT_EQ(GG_INT64_C(0x07E1D2C3B4A59688), + iter->second.Subtract(start_).ToMicroseconds()); ++iter; EXPECT_EQ(GG_UINT64_C(0x0123456789ABD), iter->first); - EXPECT_EQ(QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59689)), - iter->second); + EXPECT_EQ(GG_INT64_C(0x07E1D2C3B4A59689), + iter->second.Subtract(start_).ToMicroseconds()); // Now test framing boundaries for (size_t i = 0; i < 31; ++i) { @@ -1358,7 +1375,7 @@ TEST_F(QuicFramerTest, RstStreamFrame) { // stream id 0x04, 0x03, 0x02, 0x01, // error code - 0x08, 0x07, 0x06, 0x05, + 0x01, 0x00, 0x00, 0x00, // error details length 0x0d, 0x00, @@ -1377,7 +1394,7 @@ TEST_F(QuicFramerTest, RstStreamFrame) { EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id); - EXPECT_EQ(0x05060708, visitor_.rst_stream_frame_.error_code); + EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code); EXPECT_EQ("because I can", visitor_.rst_stream_frame_.error_details); // Now test framing boundaries @@ -1414,7 +1431,7 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) { // frame type (connection close frame) 0x05, // error code - 0x08, 0x07, 0x06, 0x05, + 0x11, 0x00, 0x00, 0x00, // error details length 0x0d, 0x00, @@ -1451,7 +1468,7 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) { EXPECT_EQ(0u, visitor_.stream_frames_.size()); - EXPECT_EQ(0x05060708, visitor_.connection_close_frame_.error_code); + EXPECT_EQ(0x11, visitor_.connection_close_frame_.error_code); EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details); ASSERT_EQ(1u, visitor_.ack_frames_.size()); @@ -1498,7 +1515,7 @@ TEST_F(QuicFramerTest, GoAwayFrame) { // frame type (go away frame) 0x06, // error code - 0x08, 0x07, 0x06, 0x05, + 0x09, 0x00, 0x00, 0x00, // stream id 0x04, 0x03, 0x02, 0x01, // error details length @@ -1519,7 +1536,7 @@ TEST_F(QuicFramerTest, GoAwayFrame) { EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.goaway_frame_.last_good_stream_id); - EXPECT_EQ(0x05060708, visitor_.goaway_frame_.error_code); + EXPECT_EQ(0x9, visitor_.goaway_frame_.error_code); EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase); const size_t reason_size = arraysize("because I can") - 1; @@ -1987,13 +2004,16 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) { frame.inter_arrival.accumulated_number_of_lost_packets = 0x0302; frame.inter_arrival.received_packet_times.insert( make_pair(GG_UINT64_C(0x0123456789ABA), - QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59687)))); + start_.Add(QuicTime::Delta::FromMicroseconds( + GG_UINT64_C(0x07E1D2C3B4A59687))))); frame.inter_arrival.received_packet_times.insert( make_pair(GG_UINT64_C(0x0123456789ABB), - QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59688)))); + start_.Add(QuicTime::Delta::FromMicroseconds( + GG_UINT64_C(0x07E1D2C3B4A59688))))); frame.inter_arrival.received_packet_times.insert( make_pair(GG_UINT64_C(0x0123456789ABD), - QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59689)))); + start_.Add(QuicTime::Delta::FromMicroseconds( + GG_UINT64_C(0x07E1D2C3B4A59689))))); QuicFrames frames; frames.push_back(QuicFrame(&frame)); @@ -2019,10 +2039,10 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) { 0x02, 0x03, // num received packets 0x03, - // smallest ack sequence number + // lowest sequence number 0xBA, 0x9A, 0x78, 0x56, 0x34, 0x12, - // ack time + // receive time 0x87, 0x96, 0xA5, 0xB4, 0xC3, 0xD2, 0xE1, 0x07, // sequence delta @@ -2130,7 +2150,7 @@ TEST_F(QuicFramerTest, ConstructRstFramePacket) { QuicRstStreamFrame rst_frame; rst_frame.stream_id = 0x01020304; - rst_frame.error_code = static_cast<QuicErrorCode>(0x05060708); + rst_frame.error_code = static_cast<QuicRstStreamErrorCode>(0x05060708); rst_frame.error_details = "because I can"; unsigned char packet[] = { @@ -2488,7 +2508,7 @@ TEST_F(QuicFramerTest, DISABLED_Truncation) { QuicConnectionCloseFrame close_frame; QuicAckFrame* ack_frame = &close_frame.ack_frame; - close_frame.error_code = static_cast<QuicErrorCode>(0x05060708); + close_frame.error_code = static_cast<QuicErrorCode>(0x05); close_frame.error_details = "because I can"; ack_frame->received_info.largest_observed = 201; ack_frame->sent_info.least_unacked = 0; @@ -2543,7 +2563,7 @@ TEST_F(QuicFramerTest, CleanTruncation) { QuicConnectionCloseFrame close_frame; QuicAckFrame* ack_frame = &close_frame.ack_frame; - close_frame.error_code = static_cast<QuicErrorCode>(0x05060708); + close_frame.error_code = static_cast<QuicErrorCode>(0x05); close_frame.error_details = "because I can"; ack_frame->received_info.largest_observed = 201; ack_frame->sent_info.least_unacked = 0; diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc index 3020610..8aa3723 100644 --- a/net/quic/quic_http_stream.cc +++ b/net/quic/quic_http_stream.cc @@ -181,7 +181,7 @@ void QuicHttpStream::Close(bool not_reusable) { // Note: the not_reusable flag has no meaning for SPDY streams. if (stream_) { stream_->SetDelegate(NULL); - stream_->Close(QUIC_NO_ERROR); + stream_->Close(QUIC_STREAM_NO_ERROR); stream_ = NULL; } } diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 7f4fef7..34165d6 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -121,6 +121,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { framer_(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false), creator_(guid_, &framer_, &random_, false) { IPAddressNumber ip; @@ -249,7 +250,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { QuicStreamId stream_id) { InitializeHeader(sequence_number, false); - QuicRstStreamFrame rst(stream_id, QUIC_NO_ERROR); + QuicRstStreamFrame rst(stream_id, QUIC_STREAM_NO_ERROR); return ConstructPacket(header_, QuicFrame(&rst)); } diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index e18f357..82b1075 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc @@ -96,7 +96,7 @@ class QuicNetworkTransactionTest : public PlatformTest { header.fec_entropy_flag = false; header.fec_group = 0; - QuicRstStreamFrame rst(stream_id, QUIC_NO_ERROR); + QuicRstStreamFrame rst(stream_id, QUIC_STREAM_NO_ERROR); return scoped_ptr<QuicEncryptedPacket>( ConstructPacket(header, QuicFrame(&rst))); } @@ -124,6 +124,7 @@ class QuicNetworkTransactionTest : public PlatformTest { QuicFramer framer(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false); QuicFrames frames; frames.push_back(QuicFrame(&ack)); @@ -180,6 +181,7 @@ class QuicNetworkTransactionTest : public PlatformTest { QuicFramer framer(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false); QuicFrames frames; frames.push_back(frame); diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc index 05a6893..5339a7f 100644 --- a/net/quic/quic_packet_creator.cc +++ b/net/quic/quic_packet_creator.cc @@ -178,7 +178,7 @@ SerializedPacket QuicPacketCreator::SerializeConnectionClose( QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket( const QuicVersionTagList& supported_versions) { - DCHECK(!is_server_); + DCHECK(is_server_); QuicPacketPublicHeader header; header.guid = guid_; header.reset_flag = false; diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc index 423028a..5e7ed61 100644 --- a/net/quic/quic_packet_creator_test.cc +++ b/net/quic/quic_packet_creator_test.cc @@ -33,10 +33,12 @@ class QuicPacketCreatorTest : public ::testing::TestWithParam<bool> { : server_framer_(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), true), client_framer_(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false), id_(1), sequence_number_(0), @@ -183,6 +185,7 @@ TEST_F(QuicPacketCreatorTest, CreateStreamFrameFinOnly) { } TEST_F(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) { + QuicPacketCreatorPeer::SetIsServer(&creator_, true); QuicVersionTagList versions; versions.push_back(kQuicVersion1); scoped_ptr<QuicEncryptedPacket> encrypted( diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc index 87464f7..d0e491a 100644 --- a/net/quic/quic_packet_generator.cc +++ b/net/quic/quic_packet_generator.cc @@ -72,9 +72,8 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id, size_t total_bytes_consumed = 0; bool fin_consumed = false; - bool has_retransmittable_data = true; - while (delegate_->CanWrite(false, has_retransmittable_data)) { + while (delegate_->CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) { // TODO(rch) figure out FEC. // packet_creator_.MaybeStartFEC(); QuicFrame frame; @@ -114,8 +113,9 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id, } void QuicPacketGenerator::SendQueuedData() { - while (HasPendingData() && - delegate_->CanWrite(false, packet_creator_->HasPendingFrames())) { + while (HasPendingData() && delegate_->CanWrite(NOT_RETRANSMISSION, + packet_creator_->HasPendingFrames() ? + HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA)) { if (!AddNextPendingFrame()) { // Packet was full, so serialize and send it. SerializeAndSendPacket(); diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h index 73e310f..dad1924 100644 --- a/net/quic/quic_packet_generator.h +++ b/net/quic/quic_packet_generator.h @@ -62,8 +62,8 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator { class NET_EXPORT_PRIVATE DelegateInterface { public: virtual ~DelegateInterface() {} - virtual bool CanWrite(bool is_retransmission, - bool has_retransmittable_data) = 0; + virtual bool CanWrite(Retransmission retransmission, + HasRetransmittableData retransmittable) = 0; virtual QuicAckFrame* CreateAckFrame() = 0; virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() = 0; // Takes ownership of |packet.packet| and |packet.retransmittable_frames|. diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc index 5ed1df5..c7e2918 100644 --- a/net/quic/quic_packet_generator_test.cc +++ b/net/quic/quic_packet_generator_test.cc @@ -31,15 +31,16 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface { MockDelegate() {} virtual ~MockDelegate() {} - MOCK_METHOD2(CanWrite, bool(bool is_retransmission, - bool has_retransmittable_data)); + MOCK_METHOD2(CanWrite, bool(Retransmission retransmission, + HasRetransmittableData retransmittable)); MOCK_METHOD0(CreateAckFrame, QuicAckFrame*()); MOCK_METHOD0(CreateFeedbackFrame, QuicCongestionFeedbackFrame*()); MOCK_METHOD1(OnSerializedPacket, bool(const SerializedPacket& packet)); void SetCanWrite(bool can_write) { - EXPECT_CALL(*this, CanWrite(false, _)).WillRepeatedly(Return(can_write)); + EXPECT_CALL(*this, CanWrite(NOT_RETRANSMISSION, _)) + .WillRepeatedly(Return(can_write)); } private: @@ -78,6 +79,7 @@ class QuicPacketGeneratorTest : public ::testing::Test { : framer_(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false), creator_(42, &framer_, &random_, false), generator_(&delegate_, &creator_), @@ -114,7 +116,7 @@ class QuicPacketGeneratorTest : public ::testing::Test { } QuicRstStreamFrame* CreateRstStreamFrame() { - return new QuicRstStreamFrame(1, QUIC_NO_ERROR); + return new QuicRstStreamFrame(1, QUIC_STREAM_NO_ERROR); } QuicGoAwayFrame* CreateGoAwayFrame() { diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 6fca452..4faec5e 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -15,8 +15,8 @@ namespace net { size_t GetPacketHeaderSize(bool include_version) { return kQuicGuidSize + kPublicFlagsSize + - (include_version ? kQuicVersionSize : 0) + kPrivateFlagsSize + - kSequenceNumberSize + kFecGroupSize; + (include_version ? kQuicVersionSize : 0) + kSequenceNumberSize + + kPrivateFlagsSize + kFecGroupSize; } size_t GetPublicResetPacketSize() { @@ -29,11 +29,15 @@ size_t GetStartOfFecProtectedData(bool include_version) { } size_t GetStartOfEncryptedData(bool include_version) { - return GetPacketHeaderSize(include_version) - kPrivateFlagsSize - + return GetPacketHeaderSize(include_version) - kPrivateFlagsSize - kFecGroupSize; } -QuicPacketPublicHeader::QuicPacketPublicHeader() {} +QuicPacketPublicHeader::QuicPacketPublicHeader() + : guid(0), + reset_flag(false), + version_flag(false) { +} QuicPacketPublicHeader::QuicPacketPublicHeader( const QuicPacketPublicHeader& other) @@ -50,12 +54,29 @@ QuicPacketPublicHeader& QuicPacketPublicHeader::operator=( guid = other.guid; reset_flag = other.reset_flag; version_flag = other.version_flag; - // Window's STL crashes when empty std::vectors are copied. - if (other.versions.size() > 0) - versions = other.versions; + versions = other.versions; return *this; } +QuicPacketHeader::QuicPacketHeader() + : fec_flag(false), + fec_entropy_flag(false), + entropy_flag(false), + entropy_hash(0), + packet_sequence_number(0), + fec_group(0) { +} + +QuicPacketHeader::QuicPacketHeader(const QuicPacketPublicHeader& header) + : public_header(header), + fec_flag(false), + fec_entropy_flag(false), + entropy_flag(false), + entropy_hash(0), + packet_sequence_number(0), + fec_group(0) { +} + QuicStreamFrame::QuicStreamFrame() {} QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id, @@ -160,7 +181,7 @@ ostream& operator<<(ostream& os, for (TimeMap::const_iterator it = inter_arrival.received_packet_times.begin(); it != inter_arrival.received_packet_times.end(); ++it) { - os << it->first << "@" << it->second.ToMilliseconds() << " "; + os << it->first << "@" << it->second.ToDebuggingValue() << " "; } os << "]"; break; diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index c72c7a7..44aedf9 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -91,6 +91,16 @@ const uint8 kNoFecOffset = 0xFF; const int64 kDefaultTimeoutUs = 600000000; // 10 minutes. +enum Retransmission { + NOT_RETRANSMISSION = 0, + IS_RETRANSMISSION = 1, +}; + +enum HasRetransmittableData { + HAS_RETRANSMITTABLE_DATA = 0, + NO_RETRANSMITTABLE_DATA = 1, +}; + enum QuicFrameType { PADDING_FRAME = 0, STREAM_FRAME, @@ -117,24 +127,32 @@ enum QuicPacketPrivateFlags { PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1 // All bits set. }; -enum QuicErrorCode { - // Stream errors. - QUIC_NO_ERROR = 0, - - // Connection has reached an invalid state. - QUIC_INTERNAL_ERROR, +enum QuicRstStreamErrorCode { + QUIC_STREAM_NO_ERROR = 0, - // There were data frames after the a fin or reset. - QUIC_STREAM_DATA_AFTER_TERMINATION, // There was some server error which halted stream processing. QUIC_SERVER_ERROR_PROCESSING_STREAM, // We got two fin or reset offsets which did not match. QUIC_MULTIPLE_TERMINATION_OFFSETS, // We got bad payload and can not respond to it at the protocol level. QUIC_BAD_APPLICATION_PAYLOAD, + // Stream closed due to connection error. No reset frame is sent when this + // happens. + QUIC_STREAM_CONNECTION_ERROR, + // GoAway frame sent. No more stream can be created. + QUIC_STREAM_PEER_GOING_AWAY, + + // No error. Used as bound while iterating. + QUIC_STREAM_LAST_ERROR, +}; - // Connection errors. +enum QuicErrorCode { + QUIC_NO_ERROR = 0, + // Connection has reached an invalid state. + QUIC_INTERNAL_ERROR, + // There were data frames after the a fin or reset. + QUIC_STREAM_DATA_AFTER_TERMINATION, // Control frame is malformed. QUIC_INVALID_PACKET_HEADER, // Frame data is malformed. @@ -203,6 +221,7 @@ enum QuicErrorCode { // peer and ourselves. QUIC_CRYPTO_NO_SUPPORT, + // No error. Used as bound while iterating. QUIC_LAST_ERROR, }; @@ -232,10 +251,9 @@ struct NET_EXPORT_PRIVATE QuicPacketPublicHeader { }; // Header for Data or FEC packets. -struct QuicPacketHeader { - QuicPacketHeader() {} - explicit QuicPacketHeader(const QuicPacketPublicHeader& header) - : public_header(header) {} +struct NET_EXPORT_PRIVATE QuicPacketHeader { + QuicPacketHeader(); + explicit QuicPacketHeader(const QuicPacketPublicHeader& header); NET_EXPORT_PRIVATE friend std::ostream& operator<<( std::ostream& os, const QuicPacketHeader& s); @@ -249,7 +267,7 @@ struct QuicPacketHeader { QuicFecGroupNumber fec_group; }; -struct QuicPublicResetPacket { +struct NET_EXPORT_PRIVATE QuicPublicResetPacket { QuicPublicResetPacket() {} explicit QuicPublicResetPacket(const QuicPacketPublicHeader& header) : public_header(header) {} @@ -405,13 +423,13 @@ struct NET_EXPORT_PRIVATE QuicCongestionFeedbackFrame { struct NET_EXPORT_PRIVATE QuicRstStreamFrame { QuicRstStreamFrame() {} - QuicRstStreamFrame(QuicStreamId stream_id, QuicErrorCode error_code) + QuicRstStreamFrame(QuicStreamId stream_id, QuicRstStreamErrorCode error_code) : stream_id(stream_id), error_code(error_code) { DCHECK_LE(error_code, std::numeric_limits<uint8>::max()); } QuicStreamId stream_id; - QuicErrorCode error_code; + QuicRstStreamErrorCode error_code; std::string error_details; }; diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc index 676db77..1951ae8 100644 --- a/net/quic/quic_reliable_client_stream.cc +++ b/net/quic/quic_reliable_client_stream.cc @@ -19,7 +19,7 @@ QuicReliableClientStream::QuicReliableClientStream(QuicStreamId id, QuicReliableClientStream::~QuicReliableClientStream() { if (delegate_) - delegate_->OnClose(error()); + delegate_->OnClose(connection_error()); } uint32 QuicReliableClientStream::ProcessData(const char* data, @@ -39,7 +39,7 @@ uint32 QuicReliableClientStream::ProcessData(const char* data, void QuicReliableClientStream::TerminateFromPeer(bool half_close) { if (delegate_) { - delegate_->OnClose(error()); + delegate_->OnClose(connection_error()); delegate_ = NULL; } ReliableQuicStream::TerminateFromPeer(half_close); diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc index 3da022b..b5f57e5 100644 --- a/net/quic/quic_reliable_client_stream_test.cc +++ b/net/quic/quic_reliable_client_stream_test.cc @@ -63,7 +63,7 @@ TEST_F(QuicReliableClientStreamTest, ProcessDataWithError) { EXPECT_CALL(delegate_, OnDataReceived(StrEq(data), arraysize(data))).WillOnce(Return(ERR_UNEXPECTED)); - EXPECT_CALL(delegate_, OnClose(QUIC_BAD_APPLICATION_PAYLOAD)); + EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR)); EXPECT_EQ(0u, stream_.ProcessData(data, arraysize(data))); diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 39abb68..dd90fec 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -166,7 +166,7 @@ QuicConsumedData QuicSession::WriteData(QuicStreamId id, } void QuicSession::SendRstStream(QuicStreamId id, - QuicErrorCode error) { + QuicRstStreamErrorCode error) { connection_->SendRstStream(id, error); CloseStream(id); } @@ -242,7 +242,7 @@ ReliableQuicStream* QuicSession::GetIncomingReliableStream( if (goaway_sent_) { // We've already sent a GoAway - connection()->SendRstStream(stream_id, QUIC_PEER_GOING_AWAY); + SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY); return NULL; } diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 7152aa0..963a53a 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -57,8 +57,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { QuicStreamOffset offset, bool fin); // Called by streams when they want to close the stream in both directions. - void SendRstStream(QuicStreamId id, - QuicErrorCode error); + virtual void SendRstStream(QuicStreamId id, QuicRstStreamErrorCode error); // Called when the session wants to go away and not accept any new streams. void SendGoAway(QuicErrorCode error_code, const std::string& reason); diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index a629f20..bd18ec8 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc @@ -207,7 +207,7 @@ TEST_F(QuicSessionTest, SendGoAway) { session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); EXPECT_TRUE(session_.goaway_sent()); - EXPECT_CALL(*connection_, SendRstStream(3u, QUIC_PEER_GOING_AWAY)); + EXPECT_CALL(*connection_, SendRstStream(3u, QUIC_STREAM_PEER_GOING_AWAY)); EXPECT_FALSE(session_.GetIncomingReliableStream(3u)); } } // namespace diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index e5f74b6..c9c9177 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc @@ -47,7 +47,7 @@ class QuicStreamFactoryTest : public ::testing::Test { header.fec_flag = false; header.fec_group = 0; - QuicRstStreamFrame rst(stream_id, QUIC_NO_ERROR); + QuicRstStreamFrame rst(stream_id, QUIC_STREAM_NO_ERROR); return scoped_ptr<QuicEncryptedPacket>( ConstructPacket(header, QuicFrame(&rst))); } @@ -74,6 +74,7 @@ class QuicStreamFactoryTest : public ::testing::Test { QuicFramer framer(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false); QuicFrames frames; frames.push_back(QuicFrame(&ack)); @@ -112,6 +113,7 @@ class QuicStreamFactoryTest : public ::testing::Test { QuicFramer framer(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false); QuicFrames frames; frames.push_back(frame); diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc index 74937ae..787d8f5 100644 --- a/net/quic/quic_stream_sequencer_test.cc +++ b/net/quic/quic_stream_sequencer_test.cc @@ -63,7 +63,7 @@ class MockStream : public ReliableQuicStream { MOCK_METHOD1(TerminateFromPeer, void(bool half_close)); MOCK_METHOD2(ProcessData, uint32(const char* data, uint32 data_len)); - MOCK_METHOD1(Close, void(QuicErrorCode error)); + MOCK_METHOD1(Close, void(QuicRstStreamErrorCode error)); MOCK_METHOD0(OnCanWrite, void()); }; diff --git a/net/quic/quic_time.cc b/net/quic/quic_time.cc index dac6231..c4c80b0 100644 --- a/net/quic/quic_time.cc +++ b/net/quic/quic_time.cc @@ -72,36 +72,14 @@ bool QuicTime::Delta::IsInfinite() const { // static QuicTime QuicTime::Zero() { - return QuicTime::FromMilliseconds(0); -} - -// static -QuicTime QuicTime::FromMilliseconds(int64 time_ms) { - // DateTime use 100 ns as resolution make sure we don't pass down too high - // values. - DCHECK(time_ms < kQuicInfiniteTimeUs / 1000); - return QuicTime(base::TimeTicks() + - base::TimeDelta::FromMilliseconds(time_ms)); -} - -// static -QuicTime QuicTime::FromMicroseconds(int64 time_us) { - // DateTime use 100 ns as resolution make sure we don't pass down too high - // values. - DCHECK(time_us < kQuicInfiniteTimeUs); - return QuicTime(base::TimeTicks() + - base::TimeDelta::FromMicroseconds(time_us)); + return QuicTime(base::TimeTicks()); } QuicTime::QuicTime(base::TimeTicks ticks) : ticks_(ticks) { } -int64 QuicTime::ToMilliseconds() const { - return (ticks_ - base::TimeTicks()).InMilliseconds(); -} - -int64 QuicTime::ToMicroseconds() const { +int64 QuicTime::ToDebuggingValue() const { return (ticks_ - base::TimeTicks()).InMicroseconds(); } diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h index e780ca5..bfb476d 100644 --- a/net/quic/quic_time.h +++ b/net/quic/quic_time.h @@ -70,15 +70,11 @@ class NET_EXPORT_PRIVATE QuicTime { // will return false for these times. static QuicTime Zero(); - // Create a new QuicTime holding the time_ms. - static QuicTime FromMilliseconds(int64 time_ms); - - // Create a new QuicTime holding the time_us. - static QuicTime FromMicroseconds(int64 time_us); - - int64 ToMilliseconds() const; - - int64 ToMicroseconds() const; + // Produce the internal value to be used when logging. This value + // represents the number of microseconds since some epoch. It may + // be the UNIX epoch on some platforms. On others, it may + // be a CPU ticks based value. + int64 ToDebuggingValue() const; bool IsInitialized() const; @@ -89,10 +85,13 @@ class NET_EXPORT_PRIVATE QuicTime { Delta Subtract(const QuicTime& other) const; private: - base::TimeTicks ticks_; + friend bool operator==(QuicTime lhs, QuicTime rhs); + friend bool operator<(QuicTime lhs, QuicTime rhs); friend class QuicClock; friend class QuicClockTest; + + base::TimeTicks ticks_; }; // Non-member relational operators for QuicTime::Delta. @@ -116,13 +115,13 @@ inline bool operator>=(QuicTime::Delta lhs, QuicTime::Delta rhs) { } // Non-member relational operators for QuicTime. inline bool operator==(QuicTime lhs, QuicTime rhs) { - return lhs.ToMicroseconds() == rhs.ToMicroseconds(); + return lhs.ticks_ == rhs.ticks_; } inline bool operator!=(QuicTime lhs, QuicTime rhs) { return !(lhs == rhs); } inline bool operator<(QuicTime lhs, QuicTime rhs) { - return lhs.ToMicroseconds() < rhs.ToMicroseconds(); + return lhs.ticks_ < rhs.ticks_; } inline bool operator>(QuicTime lhs, QuicTime rhs) { return rhs < lhs; diff --git a/net/quic/quic_time_test.cc b/net/quic/quic_time_test.cc index a4a6c55..c4ea0e2 100644 --- a/net/quic/quic_time_test.cc +++ b/net/quic/quic_time_test.cc @@ -59,21 +59,15 @@ class QuicTimeTest : public ::testing::Test { TEST_F(QuicTimeTest, Initialized) { EXPECT_FALSE(QuicTime::Zero().IsInitialized()); - EXPECT_TRUE(QuicTime::FromMilliseconds(1).IsInitialized()); -} - -TEST_F(QuicTimeTest, FromTo) { - EXPECT_EQ(QuicTime::FromMilliseconds(1), - QuicTime::FromMicroseconds(1000)); - EXPECT_EQ(1u, QuicTime::FromMicroseconds(1000).ToMilliseconds()); - EXPECT_EQ(1000u, QuicTime::FromMilliseconds(1).ToMicroseconds()); + EXPECT_TRUE(QuicTime::Zero().Add( + QuicTime::Delta::FromMicroseconds(1)).IsInitialized()); } TEST_F(QuicTimeTest, Add) { - QuicTime time_1 = QuicTime::FromMilliseconds(1); - QuicTime time_2 = QuicTime::FromMilliseconds(1); - - time_1 = time_1.Subtract(QuicTime::Delta::FromMilliseconds(1)); + QuicTime time_1 = QuicTime::Zero().Add( + QuicTime::Delta::FromMilliseconds(1)); + QuicTime time_2 = QuicTime::Zero().Add( + QuicTime::Delta::FromMilliseconds(2)); QuicTime::Delta diff = time_2.Subtract(time_1); @@ -83,15 +77,18 @@ TEST_F(QuicTimeTest, Add) { } TEST_F(QuicTimeTest, Subtract) { - QuicTime time_1 = QuicTime::FromMilliseconds(1); - QuicTime time_2 = QuicTime::FromMilliseconds(2); + QuicTime time_1 = QuicTime::Zero().Add( + QuicTime::Delta::FromMilliseconds(1)); + QuicTime time_2 = QuicTime::Zero().Add( + QuicTime::Delta::FromMilliseconds(2)); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1), time_2.Subtract(time_1)); } TEST_F(QuicTimeTest, SubtractDelta) { - QuicTime time = QuicTime::FromMilliseconds(2); - EXPECT_EQ(QuicTime::FromMilliseconds(1), + QuicTime time = QuicTime::Zero().Add( + QuicTime::Delta::FromMilliseconds(2)); + EXPECT_EQ(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1)), time.Subtract(QuicTime::Delta::FromMilliseconds(1))); } @@ -99,7 +96,7 @@ TEST_F(QuicTimeTest, MockClock) { clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); QuicTime now = clock_.ApproximateNow(); - QuicTime time = QuicTime::FromMicroseconds(1000); + QuicTime time = QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(1000)); EXPECT_EQ(now, time); diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index d28bc63..616e809 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc @@ -36,14 +36,28 @@ case x: \ return #x; // static +const char* QuicUtils::StreamErrorToString(QuicRstStreamErrorCode error) { + switch (error) { + RETURN_STRING_LITERAL(QUIC_STREAM_NO_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_CONNECTION_ERROR); + RETURN_STRING_LITERAL(QUIC_SERVER_ERROR_PROCESSING_STREAM); + RETURN_STRING_LITERAL(QUIC_MULTIPLE_TERMINATION_OFFSETS); + RETURN_STRING_LITERAL(QUIC_BAD_APPLICATION_PAYLOAD); + RETURN_STRING_LITERAL(QUIC_STREAM_PEER_GOING_AWAY); + RETURN_STRING_LITERAL(QUIC_STREAM_LAST_ERROR); + } + // Return a default value so that we return this when |error| doesn't match + // any of the QuicRstStreamErrorCodes. This can happen when the RstStream + // frame sent by the peer (attacker) has invalid error code. + return "INVALID_RST_STREAM_ERROR_CODE"; +} + +// static const char* QuicUtils::ErrorToString(QuicErrorCode error) { switch (error) { RETURN_STRING_LITERAL(QUIC_NO_ERROR); RETURN_STRING_LITERAL(QUIC_INTERNAL_ERROR); RETURN_STRING_LITERAL(QUIC_STREAM_DATA_AFTER_TERMINATION); - RETURN_STRING_LITERAL(QUIC_SERVER_ERROR_PROCESSING_STREAM); - RETURN_STRING_LITERAL(QUIC_MULTIPLE_TERMINATION_OFFSETS); - RETURN_STRING_LITERAL(QUIC_BAD_APPLICATION_PAYLOAD); RETURN_STRING_LITERAL(QUIC_INVALID_PACKET_HEADER); RETURN_STRING_LITERAL(QUIC_INVALID_FRAME_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_FEC_DATA); @@ -78,7 +92,10 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { // Intentionally have no default case, so we'll break the build // if we add errors and don't put them here. } - return ""; + // Return a default value so that we return this when |error| doesn't match + // any of the QuicErrorCodes. This can happen when the ConnectionClose + // frame sent by the peer (attacker) has invalid error code. + return "INVALID_ERROR_CODE"; } } // namespace net diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h index 34f749e..32dc15f 100644 --- a/net/quic/quic_utils.h +++ b/net/quic/quic_utils.h @@ -19,7 +19,10 @@ class NET_EXPORT_PRIVATE QuicUtils { // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param static uint128 FNV1a_128_Hash(const char* data, int len); - // Returns the name of the quic error code as a char* + // Returns the name of the QuicRstStreamErrorCode as a char* + static const char* StreamErrorToString(QuicRstStreamErrorCode error); + + // Returns the name of the QuicErrorCode as a char* static const char* ErrorToString(QuicErrorCode error); }; diff --git a/net/quic/quic_utils_test.cc b/net/quic/quic_utils_test.cc new file mode 100644 index 0000000..a59c1e7 --- /dev/null +++ b/net/quic/quic_utils_test.cc @@ -0,0 +1,25 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_utils.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { +namespace test { +namespace { + +TEST(QuicUtilsTest, StreamErrorToString) { + EXPECT_STREQ("QUIC_BAD_APPLICATION_PAYLOAD", + QuicUtils::StreamErrorToString(QUIC_BAD_APPLICATION_PAYLOAD)); +} + +TEST(QuicUtilsTest, ErrorToString) { + EXPECT_STREQ("QUIC_NO_ERROR", + QuicUtils::ErrorToString(QUIC_NO_ERROR)); +} + +} // namespace +} // namespace test +} // namespace net diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 79b060e..3e1b821 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -18,7 +18,8 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id, visitor_(NULL), stream_bytes_read_(0), stream_bytes_written_(0), - error_(QUIC_NO_ERROR), + stream_error_(QUIC_STREAM_NO_ERROR), + connection_error_(QUIC_NO_ERROR), read_side_closed_(false), write_side_closed_(false), fin_buffered_(false), @@ -59,13 +60,17 @@ bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) { return accepted; } -void ReliableQuicStream::OnStreamReset(QuicErrorCode error) { - error_ = error; +void ReliableQuicStream::OnStreamReset(QuicRstStreamErrorCode error) { + stream_error_ = error; TerminateFromPeer(false); // Full close. } void ReliableQuicStream::ConnectionClose(QuicErrorCode error, bool from_peer) { - error_ = error; + if (error != QUIC_NO_ERROR) { + stream_error_ = QUIC_STREAM_CONNECTION_ERROR; + connection_error_ = error; + } + if (from_peer) { TerminateFromPeer(false); } else { @@ -81,8 +86,8 @@ void ReliableQuicStream::TerminateFromPeer(bool half_close) { CloseReadSide(); } -void ReliableQuicStream::Close(QuicErrorCode error) { - error_ = error; +void ReliableQuicStream::Close(QuicRstStreamErrorCode error) { + stream_error_ = error; session()->SendRstStream(id(), error); } diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index 8249c96..a26595be 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h @@ -54,7 +54,7 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { virtual void OnClose(); // Called when we get a stream reset from the client. - void OnStreamReset(QuicErrorCode error); + virtual void OnStreamReset(QuicRstStreamErrorCode error); // Called when we get or send a connection close, and should immediately // close the stream. This is not passed through the sequencer, @@ -68,7 +68,7 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { virtual uint32 ProcessData(const char* data, uint32 data_len) = 0; // Called to close the stream from this end. - virtual void Close(QuicErrorCode error); + virtual void Close(QuicRstStreamErrorCode error); // This block of functions wraps the sequencer's functions of the same // name. @@ -77,7 +77,8 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { QuicStreamId id() const { return id_; } - QuicErrorCode error() const { return error_; } + QuicRstStreamErrorCode stream_error() const { return stream_error_; } + QuicErrorCode connection_error() const { return connection_error_; } bool read_side_closed() const { return read_side_closed_; } bool write_side_closed() const { return write_side_closed_; } @@ -134,7 +135,15 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { // framing, encryption overhead etc. uint64 stream_bytes_read_; uint64 stream_bytes_written_; - QuicErrorCode error_; + + // Stream error code received from a RstStreamFrame or error code sent by the + // visitor or sequencer in the RstStreamFrame. + QuicRstStreamErrorCode stream_error_; + // Connection error code due to which the stream was closed. |stream_error_| + // is set to |QUIC_STREAM_CONNECTION_ERROR| when this happens and consumers + // should check |connection_error_|. + QuicErrorCode connection_error_; + // True if the read side is closed and further frames should be rejected. bool read_side_closed_; // True if the write side is closed, and further writes should fail. diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc index fcb04ab..7afad69 100644 --- a/net/quic/test_tools/crypto_test_utils.cc +++ b/net/quic/test_tools/crypto_test_utils.cc @@ -120,21 +120,21 @@ void CryptoTestUtils::CompareClientAndServerKeys( QuicCryptoClientStream* client, QuicCryptoServerStream* server) { StringPiece client_encrypter_key = - client->crypto_negotiated_params_.encrypter->GetKey(); + client->session()->connection()->encrypter()->GetKey(); StringPiece client_encrypter_iv = - client->crypto_negotiated_params_.encrypter->GetNoncePrefix(); + client->session()->connection()->encrypter()->GetNoncePrefix(); StringPiece client_decrypter_key = - client->crypto_negotiated_params_.decrypter->GetKey(); + client->session()->connection()->decrypter()->GetKey(); StringPiece client_decrypter_iv = - client->crypto_negotiated_params_.decrypter->GetNoncePrefix(); + client->session()->connection()->decrypter()->GetNoncePrefix(); StringPiece server_encrypter_key = - server->crypto_negotiated_params_.encrypter->GetKey(); + server->session()->connection()->encrypter()->GetKey(); StringPiece server_encrypter_iv = - server->crypto_negotiated_params_.encrypter->GetNoncePrefix(); + server->session()->connection()->encrypter()->GetNoncePrefix(); StringPiece server_decrypter_key = - server->crypto_negotiated_params_.decrypter->GetKey(); + server->session()->connection()->decrypter()->GetKey(); StringPiece server_decrypter_iv = - server->crypto_negotiated_params_.decrypter->GetNoncePrefix(); + server->session()->connection()->decrypter()->GetNoncePrefix(); CompareCharArraysWithHexError("client write key", client_encrypter_key.data(), client_encrypter_key.length(), diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index ce726e1..1fb7f4f 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc @@ -157,7 +157,7 @@ bool PacketSavingConnection::SendOrQueuePacket( QuicPacketSequenceNumber sequence_number, QuicPacket* packet, QuicPacketEntropyHash entropy_hash, - bool has_retransmittable_data) { + HasRetransmittableData retransmittable) { packets_.push_back(packet); return true; } @@ -268,6 +268,7 @@ static QuicPacket* ConstructPacketFromHandshakeMessage( QuicFramer quic_framer(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), false); QuicPacketHeader header; diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 523daaf..2f1f382 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -217,7 +217,7 @@ class MockConnection : public QuicConnection { MOCK_METHOD2(SendConnectionCloseWithDetails, void(QuicErrorCode error, const string& details)); MOCK_METHOD2(SendRstStream, void(QuicStreamId id, - QuicErrorCode error)); + QuicRstStreamErrorCode error)); MOCK_METHOD3(SendGoAway, void(QuicErrorCode error, QuicStreamId last_good_stream_id, const string& reason)); @@ -242,10 +242,11 @@ class PacketSavingConnection : public MockConnection { PacketSavingConnection(QuicGuid guid, IPEndPoint address, bool is_server); virtual ~PacketSavingConnection(); - virtual bool SendOrQueuePacket(QuicPacketSequenceNumber sequence_number, - QuicPacket* packet, - QuicPacketEntropyHash entropy_hash, - bool has_retransmittable_data) OVERRIDE; + virtual bool SendOrQueuePacket( + QuicPacketSequenceNumber sequence_number, + QuicPacket* packet, + QuicPacketEntropyHash entropy_hash, + HasRetransmittableData has_retransmittable_data) OVERRIDE; std::vector<QuicPacket*> packets_; @@ -291,10 +292,11 @@ class MockSendAlgorithm : public SendAlgorithmInterface { void(QuicPacketSequenceNumber, QuicByteCount, QuicTime::Delta)); MOCK_METHOD1(OnIncomingLoss, void(QuicTime)); MOCK_METHOD4(SentPacket, void(QuicTime sent_time, QuicPacketSequenceNumber, - QuicByteCount, bool)); + QuicByteCount, Retransmission)); MOCK_METHOD2(AbandoningPacket, void(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes)); - MOCK_METHOD3(TimeUntilSend, QuicTime::Delta(QuicTime now, bool, bool)); + MOCK_METHOD3(TimeUntilSend, QuicTime::Delta(QuicTime now, Retransmission, + HasRetransmittableData)); MOCK_METHOD0(BandwidthEstimate, QuicBandwidth(void)); MOCK_METHOD0(SmoothedRtt, QuicTime::Delta(void)); diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc index b9b690d..5d21b73 100644 --- a/net/quic/test_tools/simple_quic_framer.cc +++ b/net/quic/test_tools/simple_quic_framer.cc @@ -125,6 +125,7 @@ SimpleQuicFramer::SimpleQuicFramer() : framer_(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), true), visitor_(NULL) { } diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 68968ca..70b9a76 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc @@ -11,6 +11,8 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/simple_thread.h" #include "net/base/ip_endpoint.h" +// TODO(rtenneti): Delete this when NSS is supported. +#include "net/quic/crypto/aes_128_gcm_encrypter.h" #include "net/quic/crypto/null_encrypter.h" #include "net/quic/quic_framer.h" #include "net/quic/quic_packet_creator.h" @@ -99,7 +101,8 @@ class ServerThread : public base::SimpleThread { class EndToEndTest : public ::testing::Test { protected: EndToEndTest() - : server_hostname_("localhost") { + : server_hostname_("localhost"), + server_started_(false) { net::IPAddressNumber ip; CHECK(net::ParseIPLiteralToNumber("127.0.0.1", &ip)); server_address_ = IPEndPoint(ip, 0); @@ -136,9 +139,12 @@ class EndToEndTest : public ::testing::Test { server_thread_->listening()->Wait(); server_address_ = IPEndPoint(server_address_.address(), server_thread_->GetPort()); + server_started_ = true; } void StopServer() { + if (!server_started_) + return; server_thread_->quit()->Signal(); server_thread_->Join(); } @@ -178,9 +184,16 @@ class EndToEndTest : public ::testing::Test { string server_hostname_; scoped_ptr<ServerThread> server_thread_; scoped_ptr<QuicTestClient> client_; + bool server_started_; }; TEST_F(EndToEndTest, SimpleRequestResponse) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -188,6 +201,12 @@ TEST_F(EndToEndTest, SimpleRequestResponse) { } TEST_F(EndToEndTest, SimpleRequestResponsev6) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + IPAddressNumber ip; CHECK(net::ParseIPLiteralToNumber("::", &ip)); server_address_ = IPEndPoint(ip, server_address_.port()); @@ -198,6 +217,12 @@ TEST_F(EndToEndTest, SimpleRequestResponsev6) { } TEST_F(EndToEndTest, SeparateFinPacket) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + ASSERT_TRUE(Initialize()); HTTPMessage request(HttpConstants::HTTP_1_1, @@ -222,6 +247,12 @@ TEST_F(EndToEndTest, SeparateFinPacket) { } TEST_F(EndToEndTest, MultipleRequestResponse) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -231,6 +262,12 @@ TEST_F(EndToEndTest, MultipleRequestResponse) { } TEST_F(EndToEndTest, MultipleClients) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + ASSERT_TRUE(Initialize()); scoped_ptr<QuicTestClient> client2(CreateQuicClient()); @@ -254,6 +291,12 @@ TEST_F(EndToEndTest, MultipleClients) { } TEST_F(EndToEndTest, RequestOverMultiplePackets) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + ASSERT_TRUE(Initialize()); // Set things up so we have a small payload, to guarantee fragmentation. // A congestion feedback frame can't be split into multiple packets, make sure @@ -278,6 +321,12 @@ TEST_F(EndToEndTest, RequestOverMultiplePackets) { } TEST_F(EndToEndTest, MultipleFramesRandomOrder) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + ASSERT_TRUE(Initialize()); // Set things up so we have a small payload, to guarantee fragmentation. // A congestion feedback frame can't be split into multiple packets, make sure @@ -303,6 +352,12 @@ TEST_F(EndToEndTest, MultipleFramesRandomOrder) { } TEST_F(EndToEndTest, PostMissingBytes) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + ASSERT_TRUE(Initialize()); // Add a content length header with no body. @@ -319,6 +374,12 @@ TEST_F(EndToEndTest, PostMissingBytes) { } TEST_F(EndToEndTest, LargePost) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + // FLAGS_fake_packet_loss_percentage = 30; ASSERT_TRUE(Initialize()); @@ -333,6 +394,12 @@ TEST_F(EndToEndTest, LargePost) { } TEST_F(EndToEndTest, LargePostFEC) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + // FLAGS_fake_packet_loss_percentage = 30; ASSERT_TRUE(Initialize()); client_->options()->max_packets_per_fec_group = 6; @@ -365,6 +432,12 @@ TEST_F(EndToEndTest, LargePostFEC) { }*/ TEST_F(EndToEndTest, InvalidStream) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + ASSERT_TRUE(Initialize()); string body; @@ -383,6 +456,12 @@ TEST_F(EndToEndTest, InvalidStream) { } TEST_F(EndToEndTest, MultipleTermination) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + ASSERT_TRUE(Initialize()); scoped_ptr<QuicTestClient> client2(CreateQuicClient()); @@ -424,6 +503,12 @@ TEST_F(EndToEndTest, MultipleTermination) { }*/ TEST_F(EndToEndTest, ResetConnection) { + // TODO(rtenneti): Delete this when NSS is supported. + if (!Aes128GcmEncrypter::IsSupported()) { + LOG(INFO) << "AES GCM not supported. Test skipped."; + return; + } + ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc index 04fd922..02dbb63 100644 --- a/net/tools/quic/quic_time_wait_list_manager.cc +++ b/net/tools/quic/quic_time_wait_list_manager.cc @@ -93,6 +93,7 @@ QuicTimeWaitListManager::QuicTimeWaitListManager( : framer_(kQuicVersion1, QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL), + QuicTime::Zero(), true), epoll_server_(epoll_server), kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)), diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index 22e3827..43ac914 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc @@ -37,7 +37,7 @@ QuicTestClient::QuicTestClient(IPEndPoint address, const string& hostname) : server_address_(address), client_(address, hostname), stream_(NULL), - stream_error_(QUIC_NO_ERROR), + stream_error_(QUIC_STREAM_NO_ERROR), connection_error_(QUIC_NO_ERROR), bytes_read_(0), bytes_written_(0), @@ -135,7 +135,7 @@ IPEndPoint QuicTestClient::LocalSocketAddress() const { } void QuicTestClient::ClearPerRequestState() { - stream_error_ = QUIC_NO_ERROR; + stream_error_ = QUIC_STREAM_NO_ERROR; connection_error_ = QUIC_NO_ERROR; stream_ = NULL; response_ = ""; @@ -170,8 +170,8 @@ size_t QuicTestClient::bytes_written() const { void QuicTestClient::OnClose(ReliableQuicStream* stream) { response_ = stream_->data(); headers_.CopyFrom(stream_->headers()); - stream_error_ = stream_->error(); - connection_error_ = stream_->error(); + stream_error_ = stream_->stream_error(); + connection_error_ = stream_->connection_error(); bytes_read_ = stream_->stream_bytes_read(); bytes_written_ = stream_->stream_bytes_written(); stream_ = NULL; diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h index d02905a..1bb4f07 100644 --- a/net/tools/quic/test_tools/quic_test_client.h +++ b/net/tools/quic/test_tools/quic_test_client.h @@ -61,7 +61,7 @@ class QuicTestClient : public ReliableQuicStream::Visitor { // Returns NULL if the maximum number of streams have already been created. QuicReliableClientStream* GetOrCreateStream(); - QuicErrorCode stream_error() { return stream_error_; } + QuicRstStreamErrorCode stream_error() { return stream_error_; } QuicErrorCode connection_error() { return connection_error_; } QuicClient* client() { return &client_; } @@ -75,7 +75,7 @@ class QuicTestClient : public ReliableQuicStream::Visitor { QuicClient client_; // The actual client QuicReliableClientStream* stream_; - QuicErrorCode stream_error_; + QuicRstStreamErrorCode stream_error_; QuicErrorCode connection_error_; BalsaHeaders headers_; |