diff options
Diffstat (limited to 'net/quic')
97 files changed, 1438 insertions, 1006 deletions
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc index 2ccbc8b..4e3f635 100644 --- a/net/quic/congestion_control/fix_rate_sender.cc +++ b/net/quic/congestion_control/fix_rate_sender.cc @@ -61,7 +61,7 @@ void FixRateSender::SentPacket(QuicTime sent_time, Retransmission is_retransmission) { fix_rate_leaky_bucket_.Add(sent_time, bytes); paced_sender_.SentPacket(sent_time, bytes); - if (!is_retransmission) { + if (is_retransmission == NOT_RETRANSMISSION) { data_in_flight_ += bytes; } } diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc index 4969966..f48dc45 100644 --- a/net/quic/congestion_control/fix_rate_test.cc +++ b/net/quic/congestion_control/fix_rate_test.cc @@ -64,23 +64,23 @@ TEST_F(FixRateTest, SenderAPI) { unused_bandwidth_, unused_packet_map_); EXPECT_EQ(300000, sender_->BandwidthEstimate().ToBytesPerSecond()); EXPECT_TRUE(sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero()); sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, NOT_RETRANSMISSION); EXPECT_TRUE(sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_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_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2)); EXPECT_EQ(QuicTime::Delta::Infinite(), sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA)); + clock_.Now(), NOT_RETRANSMISSION, HAS_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(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero()); } TEST_F(FixRateTest, FixRatePacing) { @@ -96,15 +96,15 @@ TEST_F(FixRateTest, FixRatePacing) { QuicPacketSequenceNumber sequence_number = 0; for (int i = 0; i < num_packets; i += 2) { EXPECT_TRUE(sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_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()); + clock_.Now(), NOT_RETRANSMISSION, HAS_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_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); clock_.AdvanceTime(advance_time); sender_->OnIncomingAck(sequence_number - 1, packet_size, rtt_); sender_->OnIncomingAck(sequence_number - 2, packet_size, rtt_); diff --git a/net/quic/congestion_control/quic_congestion_manager_test.cc b/net/quic/congestion_control/quic_congestion_manager_test.cc index fb6d2e8..8b8f473 100644 --- a/net/quic/congestion_control/quic_congestion_manager_test.cc +++ b/net/quic/congestion_control/quic_congestion_manager_test.cc @@ -39,6 +39,9 @@ class QuicCongestionManagerTest : public ::testing::Test { void SetUpCongestionType(CongestionFeedbackType congestion_type) { manager_.reset(new QuicCongestionManagerPeer(&clock_, congestion_type)); } + + static const HasRetransmittableData kIgnored = HAS_RETRANSMITTABLE_DATA; + MockClock clock_; scoped_ptr<QuicCongestionManagerPeer> manager_; }; @@ -55,10 +58,10 @@ TEST_F(QuicCongestionManagerTest, Bandwidth) { for (int i = 1; i <= 100; ++i) { QuicTime::Delta advance_time = manager_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + clock_.Now(), NOT_RETRANSMISSION, kIgnored); clock_.AdvanceTime(advance_time); EXPECT_TRUE(manager_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, kIgnored).IsZero()); manager_->SentPacket(i, clock_.Now(), 1000, NOT_RETRANSMISSION); // Ack the packet we sent. ack.received_info.largest_observed = i; @@ -83,7 +86,7 @@ TEST_F(QuicCongestionManagerTest, BandwidthWith1SecondGap) { ++sequence_number) { clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); EXPECT_TRUE(manager_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, kIgnored).IsZero()); manager_->SentPacket( sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION); // Ack the packet we sent. @@ -101,7 +104,7 @@ TEST_F(QuicCongestionManagerTest, BandwidthWith1SecondGap) { EXPECT_TRUE(manager_->SentBandwidth(clock_.Now()).IsZero()); for (int i = 1; i <= 150; ++i) { EXPECT_TRUE(manager_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, kIgnored).IsZero()); manager_->SentPacket(i + 100, clock_.Now(), 1000, NOT_RETRANSMISSION); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); // Ack the packet we sent. diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc index 4bed7ed..78bd7d9 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc @@ -87,7 +87,7 @@ void TcpCubicSender::SentPacket(QuicTime /*sent_time*/, QuicByteCount bytes, Retransmission is_retransmission) { bytes_in_flight_ += bytes; - if (!is_retransmission && update_end_sequence_number_) { + if (is_retransmission == NOT_RETRANSMISSION && update_end_sequence_number_) { end_sequence_number_ = sequence_number; if (AvailableCongestionWindow() == 0) { update_end_sequence_number_ = false; @@ -105,7 +105,8 @@ QuicTime::Delta TcpCubicSender::TimeUntilSend( QuicTime now, Retransmission is_retransmission, HasRetransmittableData has_retransmittable_data) { - if (is_retransmission || !has_retransmittable_data) { + if (is_retransmission == IS_RETRANSMISSION || + has_retransmittable_data == NO_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_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index 0cd51fd..71d53c6 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc @@ -44,7 +44,7 @@ class TcpCubicSenderTest : public ::testing::Test { bytes_to_send -= bytes_in_packet; if (bytes_to_send > 0) { EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, - NO_RETRANSMITTABLE_DATA).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); } } } @@ -75,20 +75,20 @@ TEST_F(TcpCubicSenderTest, SimpleSender) { sender_->AvailableCongestionWindow()); // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_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(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_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(), IS_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), IS_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero()); } TEST_F(TcpCubicSenderTest, ExponentialSlowStart) { @@ -96,14 +96,14 @@ TEST_F(TcpCubicSenderTest, ExponentialSlowStart) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_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(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero()); for (int n = 0; n < kNumberOfAck; ++n) { // Send our full congestion window. @@ -125,14 +125,14 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_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(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero()); for (int n = 0; n < kNumberOfAck; ++n) { // Send our full congestion window. @@ -168,14 +168,14 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_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(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero()); + clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero()); for (int i = 0; i < kNumberOfAck; ++i) { // Send our full congestion window. @@ -191,7 +191,7 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { // Make sure that we should not send right now. EXPECT_TRUE(sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsInfinite()); + clock_.Now(), NOT_RETRANSMISSION, HAS_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_openssl.cc b/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc index 105ae8c..0800cb5 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc +++ b/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc @@ -21,13 +21,10 @@ const size_t kAuthTagSize = 16; } // namespace -Aes128GcmDecrypter::Aes128GcmDecrypter() { -} +Aes128GcmDecrypter::Aes128GcmDecrypter() {} // static -bool Aes128GcmDecrypter::IsSupported() { - return true; -} +bool Aes128GcmDecrypter::IsSupported() { return true; } bool Aes128GcmDecrypter::SetKey(StringPiece key) { DCHECK_EQ(key.size(), sizeof(key_)); @@ -63,8 +60,7 @@ bool Aes128GcmDecrypter::Decrypt(StringPiece nonce, 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) { + if (EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_gcm(), NULL, key_, NULL) == 0) { return false; } @@ -74,16 +70,16 @@ bool Aes128GcmDecrypter::Decrypt(StringPiece nonce, return false; } // Set the IV (nonce). - if (EVP_DecryptInit_ex(ctx.get(), NULL, NULL, NULL, - reinterpret_cast<const unsigned char*>( - nonce.data())) == 0) { + if (EVP_DecryptInit_ex( + ctx.get(), NULL, NULL, NULL, + reinterpret_cast<const unsigned char*>(nonce.data())) == 0) { 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) { + if (EVP_CIPHER_CTX_ctrl( + ctx.get(), EVP_CTRL_GCM_SET_TAG, kAuthTagSize, + const_cast<char*>(ciphertext.data()) + plaintext_size) == 0) { return false; } @@ -92,18 +88,18 @@ bool Aes128GcmDecrypter::Decrypt(StringPiece nonce, 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) { + 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, &len, - reinterpret_cast<const unsigned char*>( - ciphertext.data()), - plaintext_size) == 0) { + if (EVP_DecryptUpdate( + ctx.get(), output, &len, + reinterpret_cast<const unsigned char*>(ciphertext.data()), + plaintext_size) == 0) { return false; } output += len; diff --git a/net/quic/crypto/aes_128_gcm_decrypter_test.cc b/net/quic/crypto/aes_128_gcm_decrypter_test.cc index 2ab0dd0..156dfb8 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter_test.cc +++ b/net/quic/crypto/aes_128_gcm_decrypter_test.cc @@ -333,18 +333,15 @@ TEST(Aes128GcmDecrypterTest, Decrypt) { const TestGroupInfo& test_info = test_group_info[i]; for (size_t j = 0; test_vector[j].key != NULL; j++) { // Decode the test vector. - ASSERT_TRUE(DecodeHexString(test_vector[j].key, key, &key_len, - sizeof(key))); - ASSERT_TRUE(DecodeHexString(test_vector[j].iv, iv, &iv_len, - sizeof(iv))); - ASSERT_TRUE(DecodeHexString(test_vector[j].ct, ct, &ct_len, - sizeof(ct))); - ASSERT_TRUE(DecodeHexString(test_vector[j].aad, aad, &aad_len, - sizeof(aad))); - ASSERT_TRUE(DecodeHexString(test_vector[j].tag, tag, &tag_len, - sizeof(tag))); - ASSERT_TRUE(DecodeHexString(test_vector[j].pt, pt, &pt_len, - sizeof(pt))); + ASSERT_TRUE( + DecodeHexString(test_vector[j].key, key, &key_len, sizeof(key))); + ASSERT_TRUE(DecodeHexString(test_vector[j].iv, iv, &iv_len, sizeof(iv))); + ASSERT_TRUE(DecodeHexString(test_vector[j].ct, ct, &ct_len, sizeof(ct))); + ASSERT_TRUE( + DecodeHexString(test_vector[j].aad, aad, &aad_len, sizeof(aad))); + ASSERT_TRUE( + DecodeHexString(test_vector[j].tag, tag, &tag_len, sizeof(tag))); + ASSERT_TRUE(DecodeHexString(test_vector[j].pt, pt, &pt_len, sizeof(pt))); // The test vector's lengths should look sane. Note that the lengths // in |test_info| are in bits. @@ -365,8 +362,7 @@ TEST(Aes128GcmDecrypterTest, Decrypt) { &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)); + StringPiece(aad_len ? aad : NULL, aad_len), ciphertext)); if (!decrypted.get()) { EXPECT_EQ((size_t)-1, pt_len); continue; @@ -374,9 +370,8 @@ TEST(Aes128GcmDecrypterTest, Decrypt) { ASSERT_NE((size_t)-1, pt_len); ASSERT_EQ(pt_len, decrypted->length()); - test::CompareCharArraysWithHexError( - "plaintext", decrypted->data(), pt_len, - pt, pt_len); + test::CompareCharArraysWithHexError("plaintext", decrypted->data(), + pt_len, pt, pt_len); } } } diff --git a/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc index daa85f0..b00dec8 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc +++ b/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc @@ -26,9 +26,7 @@ Aes128GcmEncrypter::Aes128GcmEncrypter() { } // static -bool Aes128GcmEncrypter::IsSupported() { - return true; -} +bool Aes128GcmEncrypter::IsSupported() { return true; } bool Aes128GcmEncrypter::SetKey(StringPiece key) { DCHECK_EQ(key.size(), sizeof(key_)); @@ -63,8 +61,7 @@ bool Aes128GcmEncrypter::Encrypt(StringPiece nonce, 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) { + if (EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_gcm(), NULL, key_, NULL) == 0) { return false; } @@ -74,9 +71,9 @@ bool Aes128GcmEncrypter::Encrypt(StringPiece nonce, return false; } // Set the IV (nonce). - if (EVP_EncryptInit_ex(ctx.get(), NULL, NULL, NULL, - reinterpret_cast<const unsigned char*>( - nonce.data())) == 0) { + if (EVP_EncryptInit_ex( + ctx.get(), NULL, NULL, NULL, + reinterpret_cast<const unsigned char*>(nonce.data())) == 0) { return false; } @@ -85,18 +82,18 @@ bool Aes128GcmEncrypter::Encrypt(StringPiece nonce, 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) { + 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) { + if (EVP_EncryptUpdate( + ctx.get(), output, &output_len, + reinterpret_cast<const unsigned char*>(plaintext.data()), + plaintext.size()) == 0) { return false; } output += output_len; @@ -134,9 +131,7 @@ QuicData* Aes128GcmEncrypter::EncryptPacket( return new QuicData(ciphertext.release(), ciphertext_size, true); } -size_t Aes128GcmEncrypter::GetKeySize() const { - return kKeySize; -} +size_t Aes128GcmEncrypter::GetKeySize() const { return kKeySize; } size_t Aes128GcmEncrypter::GetNoncePrefixSize() const { return kNoncePrefixSize; diff --git a/net/quic/crypto/aes_128_gcm_encrypter_test.cc b/net/quic/crypto/aes_128_gcm_encrypter_test.cc index 0da7a8f..7e07ba9 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter_test.cc +++ b/net/quic/crypto/aes_128_gcm_encrypter_test.cc @@ -285,18 +285,15 @@ TEST(Aes128GcmEncrypterTest, Encrypt) { const TestGroupInfo& test_info = test_group_info[i]; for (size_t j = 0; test_vector[j].key != NULL; j++) { // Decode the test vector. - ASSERT_TRUE(DecodeHexString(test_vector[j].key, key, &key_len, - sizeof(key))); - ASSERT_TRUE(DecodeHexString(test_vector[j].iv, iv, &iv_len, - sizeof(iv))); - ASSERT_TRUE(DecodeHexString(test_vector[j].pt, pt, &pt_len, - sizeof(pt))); - ASSERT_TRUE(DecodeHexString(test_vector[j].aad, aad, &aad_len, - sizeof(aad))); - ASSERT_TRUE(DecodeHexString(test_vector[j].ct, ct, &ct_len, - sizeof(ct))); - ASSERT_TRUE(DecodeHexString(test_vector[j].tag, tag, &tag_len, - sizeof(tag))); + ASSERT_TRUE( + DecodeHexString(test_vector[j].key, key, &key_len, sizeof(key))); + ASSERT_TRUE(DecodeHexString(test_vector[j].iv, iv, &iv_len, sizeof(iv))); + ASSERT_TRUE(DecodeHexString(test_vector[j].pt, pt, &pt_len, sizeof(pt))); + ASSERT_TRUE( + DecodeHexString(test_vector[j].aad, aad, &aad_len, sizeof(aad))); + ASSERT_TRUE(DecodeHexString(test_vector[j].ct, ct, &ct_len, sizeof(ct))); + ASSERT_TRUE( + DecodeHexString(test_vector[j].tag, tag, &tag_len, sizeof(tag))); // The test vector's lengths should look sane. Note that the lengths // in |test_info| are in bits. @@ -314,16 +311,14 @@ TEST(Aes128GcmEncrypterTest, Encrypt) { // 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))); + StringPiece(aad_len ? aad : NULL, aad_len), StringPiece(pt, pt_len))); ASSERT_TRUE(encrypted.get()); ASSERT_EQ(ct_len + tag_len, encrypted->length()); + test::CompareCharArraysWithHexError("ciphertext", encrypted->data(), + ct_len, ct, ct_len); test::CompareCharArraysWithHexError( - "ciphertext", encrypted->data(), ct_len, - ct, ct_len); - test::CompareCharArraysWithHexError( - "authentication tag", encrypted->data() + ct_len, tag_len, - tag, tag_len); + "authentication tag", encrypted->data() + ct_len, tag_len, tag, + tag_len); } } } diff --git a/net/quic/crypto/cert_compressor.cc b/net/quic/crypto/cert_compressor.cc index aaa5f55..2f36c19 100644 --- a/net/quic/crypto/cert_compressor.cc +++ b/net/quic/crypto/cert_compressor.cc @@ -18,7 +18,8 @@ namespace net { namespace { // kCommonCertSubstrings contains ~1500 bytes of common certificate substrings -// in order to help zlib. +// in order to help zlib. This was generated via a fairly dumb algorithm from +// the Alexa Top 5000 set - we could probably do better. static unsigned char kCommonCertSubstrings[] = { 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, @@ -158,7 +159,7 @@ struct CertEntry { // be replaced by its 64-bit hash (in |hash|). CACHED = 2, // COMMON means that the certificate is in a common certificate set known - // to the peer with hash |set_hash| and index |index|. + // to the peer with hash |set_hash| and certificate index |index|. COMMON = 3, }; @@ -171,16 +172,17 @@ struct CertEntry { // MatchCerts returns a vector of CertEntries describing how to most // efficiently represent |certs| to a peer who has the common sets identified // by |client_common_set_hashes| and who has cached the certificates with the -// 64-bit, FNV-1a hashes in |client_cached|. +// 64-bit, FNV-1a hashes in |client_cached_cert_hashes|. vector<CertEntry> MatchCerts(const vector<string>& certs, StringPiece client_common_set_hashes, - StringPiece client_cached, - CommonCertSet* common_set) { + StringPiece client_cached_cert_hashes, + const CommonCertSets* common_set) { vector<CertEntry> entries; entries.reserve(certs.size()); - const bool cached_valid = client_cached.size() % sizeof(uint64) == 0 && - !client_cached.empty(); + const bool cached_valid = + client_cached_cert_hashes.size() % sizeof(uint64) == 0 && + !client_cached_cert_hashes.empty(); for (vector<string>::const_iterator i = certs.begin(); i != certs.end(); ++i) { @@ -191,9 +193,11 @@ vector<CertEntry> MatchCerts(const vector<string>& certs, uint64 hash = QuicUtils::FNV1a_64_Hash(i->data(), i->size()); // This assumes that the machine is little-endian. - for (size_t i = 0; i < client_cached.size(); i += sizeof(uint64)) { + for (size_t i = 0; i < client_cached_cert_hashes.size(); + i += sizeof(uint64)) { uint64 cached_hash; - memcpy(&cached_hash, client_cached.data() + i, sizeof(uint64)); + memcpy(&cached_hash, client_cached_cert_hashes.data() + i, + sizeof(uint64)); if (hash != cached_hash) { continue; } @@ -210,9 +214,8 @@ vector<CertEntry> MatchCerts(const vector<string>& certs, } } - if (common_set && - common_set->MatchCert(*i, client_common_set_hashes, &entry.set_hash, - &entry.index)) { + if (common_set && common_set->MatchCert(*i, client_common_set_hashes, + &entry.set_hash, &entry.index)) { entry.type = CertEntry::COMMON; entries.push_back(entry); continue; @@ -329,7 +332,7 @@ vector<uint64> HashCerts(const vector<string>& certs) { // |in_out| is updated to contain the trailing data. bool ParseEntries(StringPiece* in_out, const vector<string>& cached_certs, - CommonCertSet* common_set, + const CommonCertSets* common_set, vector<CertEntry>* out_entries, vector<string>* out_certs) { StringPiece in = *in_out; @@ -419,14 +422,9 @@ class ScopedZLib { DEFLATE, }; - explicit ScopedZLib(Type type) - : z_(NULL), - type_(type) { - } + explicit ScopedZLib(Type type) : z_(NULL), type_(type) {} - void reset(z_stream* z) { - z_ = z; - } + void reset(z_stream* z) { z_ = z; } ~ScopedZLib() { if (z_) { @@ -450,10 +448,10 @@ class ScopedZLib { // static string CertCompressor::CompressChain(const vector<string>& certs, StringPiece client_common_set_hashes, - StringPiece client_cached, - CommonCertSet* common_set) { + StringPiece client_cached_cert_hashes, + const CommonCertSets* common_set) { const vector<CertEntry> entries = MatchCerts( - certs, client_common_set_hashes, client_cached, common_set); + certs, client_common_set_hashes, client_cached_cert_hashes, common_set); DCHECK_EQ(entries.size(), certs.size()); size_t uncompressed_size = 0; @@ -551,7 +549,7 @@ string CertCompressor::CompressChain(const vector<string>& certs, // static bool CertCompressor::DecompressChain(StringPiece in, const vector<string>& cached_certs, - CommonCertSet* common_set, + const CommonCertSets* common_set, vector<string>* out_certs) { vector<CertEntry> entries; if (!ParseEntries(&in, cached_certs, common_set, &entries, out_certs)) { @@ -600,9 +598,7 @@ bool CertCompressor::DecompressChain(StringPiece in, rv = inflate(&z, Z_FINISH); } - if (Z_STREAM_END != rv || - z.avail_out > 0 || - z.avail_in > 0) { + if (Z_STREAM_END != rv || z.avail_out > 0 || z.avail_in > 0) { return false; } diff --git a/net/quic/crypto/cert_compressor.h b/net/quic/crypto/cert_compressor.h index cf8021b..587684d 100644 --- a/net/quic/crypto/cert_compressor.h +++ b/net/quic/crypto/cert_compressor.h @@ -22,9 +22,9 @@ namespace net { // that they already have. In the event that one of them is to be // compressed, it can be replaced with just the hash. // 2) The peer may provide a number of hashes that represent sets of -// pre-shared certificates. If one of those certificates is to be -// compressed, and it's known to the given CommonCertSet, then it can be -// replaced with a set hash and index. +// pre-shared certificates (CommonCertSets). If one of those certificates +// is to be compressed, and it's known to the given CommonCertSets, then it +// can be replaced with a set hash and certificate index. // 3) Otherwise the certificates are compressed with zlib using a pre-shared // dictionary that consists of the certificates handled with the above // methods and a small chunk of common substrings. @@ -37,8 +37,8 @@ class NET_EXPORT_PRIVATE CertCompressor { // hashes of certificates that the peer already possesses. static std::string CompressChain(const std::vector<std::string>& certs, base::StringPiece client_common_set_hashes, - base::StringPiece client_cached, - CommonCertSet* common_set); + base::StringPiece client_cached_cert_hashes, + const CommonCertSets* common_set); // DecompressChain decompresses the result of |CompressChain|, given in |in|, // into a series of certificates that are written to |out_certs|. @@ -46,7 +46,7 @@ class NET_EXPORT_PRIVATE CertCompressor { // |common_set| contains the common certificate sets known locally. static bool DecompressChain(base::StringPiece in, const std::vector<std::string>& cached_certs, - CommonCertSet* common_set, + const CommonCertSets* common_set, std::vector<std::string>* out_certs); }; diff --git a/net/quic/crypto/cert_compressor_test.cc b/net/quic/crypto/cert_compressor_test.cc index c066e61..ef12ccc 100644 --- a/net/quic/crypto/cert_compressor_test.cc +++ b/net/quic/crypto/cert_compressor_test.cc @@ -23,8 +23,8 @@ TEST(CertCompressor, EmptyChain) { EXPECT_EQ("00", base::HexEncode(compressed.data(), compressed.size())); vector<string> chain2, cached_certs; - ASSERT_TRUE(CertCompressor::DecompressChain( - compressed, cached_certs, NULL, &chain2)); + ASSERT_TRUE( + CertCompressor::DecompressChain(compressed, cached_certs, NULL, &chain2)); EXPECT_EQ(chain.size(), chain2.size()); } @@ -37,8 +37,8 @@ TEST(CertCompressor, Compressed) { EXPECT_EQ("0100", base::HexEncode(compressed.substr(0, 2).data(), 2)); vector<string> chain2, cached_certs; - ASSERT_TRUE(CertCompressor::DecompressChain( - compressed, cached_certs, NULL, &chain2)); + ASSERT_TRUE( + CertCompressor::DecompressChain(compressed, cached_certs, NULL, &chain2)); EXPECT_EQ(chain.size(), chain2.size()); EXPECT_EQ(chain[0], chain2[0]); } @@ -47,22 +47,22 @@ TEST(CertCompressor, Common) { vector<string> chain; chain.push_back("testcert"); static const uint64 set_hash = 42; - scoped_ptr<CommonCertSet> common_set( - CryptoTestUtils::MockCommonCertSet(chain[0], set_hash, 1)); + scoped_ptr<CommonCertSets> common_set( + CryptoTestUtils::MockCommonCertSets(chain[0], set_hash, 1)); const string compressed = CertCompressor::CompressChain( - chain, StringPiece(reinterpret_cast<const char*>(&set_hash), - sizeof(set_hash)), + chain, + StringPiece(reinterpret_cast<const char*>(&set_hash), sizeof(set_hash)), StringPiece(), common_set.get()); - const string common("03" /* common */ + const string common("03" /* common */ "2A00000000000000" /* set hash 42 */ - "01000000" /* index 1 */ - "00" /* end of list */); + "01000000" /* index 1 */ + "00" /* end of list */); EXPECT_EQ(common.data(), base::HexEncode(compressed.data(), compressed.size())); vector<string> chain2, cached_certs; - ASSERT_TRUE(CertCompressor::DecompressChain( - compressed, cached_certs, common_set.get(), &chain2)); + ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, + common_set.get(), &chain2)); EXPECT_EQ(chain.size(), chain2.size()); EXPECT_EQ(chain[0], chain2[0]); } @@ -82,8 +82,8 @@ TEST(CertCompressor, Cached) { vector<string> cached_certs, chain2; cached_certs.push_back(chain[0]); - ASSERT_TRUE(CertCompressor::DecompressChain( - compressed, cached_certs, NULL, &chain2)); + ASSERT_TRUE( + CertCompressor::DecompressChain(compressed, cached_certs, NULL, &chain2)); EXPECT_EQ(chain.size(), chain2.size()); EXPECT_EQ(chain[0], chain2[0]); } @@ -116,7 +116,7 @@ TEST(CertCompressor, BadInputs) { hash_and_index_truncated.size()), cached_certs, NULL, &chain)); - /* without a CommonCertSet */ + /* without a CommonCertSets */ const string without_a_common_cert_set( "03" "0000000000000000" "00000000"); EXPECT_FALSE(CertCompressor::DecompressChain( @@ -124,8 +124,8 @@ TEST(CertCompressor, BadInputs) { without_a_common_cert_set.size()), cached_certs, NULL, &chain)); - scoped_ptr<CommonCertSet> common_set( - CryptoTestUtils::MockCommonCertSet("foo", 42, 1)); + scoped_ptr<CommonCertSets> common_set( + CryptoTestUtils::MockCommonCertSets("foo", 42, 1)); /* incorrect hash and index */ const string incorrect_hash_and_index( diff --git a/net/quic/crypto/common_cert_set.cc b/net/quic/crypto/common_cert_set.cc index a8de6ae..78aa927 100644 --- a/net/quic/crypto/common_cert_set.cc +++ b/net/quic/crypto/common_cert_set.cc @@ -16,11 +16,15 @@ namespace common_cert_set_0 { #include "net/quic/crypto/common_cert_set_0.c" } - struct CertSet { + // num_certs contains the number of certificates in this set. size_t num_certs; + // certs is an array of |num_certs| pointers to the DER encoded certificates. const unsigned char* const* certs; + // lens is an array of |num_certs| integers describing the length, in bytes, + // of each certificate. const size_t* lens; + // hash contains the 64-bit, FNV-1a hash of this set. uint64 hash; }; @@ -37,18 +41,18 @@ static const uint64 kSetHashes[] = { common_cert_set_0::kHash, }; -CommonCertSet::~CommonCertSet() { +CommonCertSets::~CommonCertSets() { } -CommonCertSetQUIC::CommonCertSetQUIC() { +CommonCertSetsQUIC::CommonCertSetsQUIC() { } -StringPiece CommonCertSetQUIC::GetCommonHashes() { +StringPiece CommonCertSetsQUIC::GetCommonHashes() const { return StringPiece(reinterpret_cast<const char*>(kSetHashes), sizeof(uint64) * arraysize(kSetHashes)); } -StringPiece CommonCertSetQUIC::GetCert(uint64 hash, uint32 index) { +StringPiece CommonCertSetsQUIC::GetCert(uint64 hash, uint32 index) const { for (size_t i = 0; i < arraysize(kSets); i++) { if (kSets[i].hash == hash) { if (index >= kSets[i].num_certs) { @@ -82,10 +86,10 @@ static int Compare(StringPiece a, const unsigned char* b, size_t b_len) { return 0; } -bool CommonCertSetQUIC::MatchCert(StringPiece cert, - StringPiece common_set_hashes, - uint64* out_hash, - uint32* out_index) { +bool CommonCertSetsQUIC::MatchCert(StringPiece cert, + StringPiece common_set_hashes, + uint64* out_hash, + uint32* out_index) const { if (common_set_hashes.size() % sizeof(uint64) != 0) { return false; } diff --git a/net/quic/crypto/common_cert_set.h b/net/quic/crypto/common_cert_set.h index d4cabd6..6972926 100644 --- a/net/quic/crypto/common_cert_set.h +++ b/net/quic/crypto/common_cert_set.h @@ -13,19 +13,19 @@ namespace net { -// CommonCertSet is an interface to an object that contains a number of common +// CommonCertSets is an interface to an object that contains a number of common // certificate sets and can match against them. -class NET_EXPORT_PRIVATE CommonCertSet { +class NET_EXPORT_PRIVATE CommonCertSets { public: - virtual ~CommonCertSet(); + virtual ~CommonCertSets(); // GetCommonHashes returns a StringPiece containing the hashes of common sets // supported by this object. - virtual base::StringPiece GetCommonHashes() = 0; + virtual base::StringPiece GetCommonHashes() const = 0; // GetCert returns a specific certificate in the common set identified by // |hash|. If no such certificate is known, an empty StringPiece is returned. - virtual base::StringPiece GetCert(uint64 hash, uint32 index) = 0; + virtual base::StringPiece GetCert(uint64 hash, uint32 index) const = 0; // MatchCert tries to find |cert| in one of the common certificate sets // identified by |common_set_hashes|. On success it puts the hash in @@ -34,27 +34,27 @@ class NET_EXPORT_PRIVATE CommonCertSet { virtual bool MatchCert(base::StringPiece cert, base::StringPiece common_set_hashes, uint64* out_hash, - uint32* out_index) = 0; + uint32* out_index) const = 0; }; -// CommonCertSetQUIC implements the CommonCertSet interface using the default +// CommonCertSetsQUIC implements the CommonCertSet interface using the default // certificate sets. -class NET_EXPORT_PRIVATE CommonCertSetQUIC : public CommonCertSet { +class NET_EXPORT_PRIVATE CommonCertSetsQUIC : public CommonCertSets { public: - CommonCertSetQUIC(); + CommonCertSetsQUIC(); - // CommonCertSet interface. - virtual base::StringPiece GetCommonHashes() OVERRIDE; + // CommonCertSets interface. + virtual base::StringPiece GetCommonHashes() const OVERRIDE; - virtual base::StringPiece GetCert(uint64 hash, uint32 index) OVERRIDE; + virtual base::StringPiece GetCert(uint64 hash, uint32 index) const OVERRIDE; virtual bool MatchCert(base::StringPiece cert, base::StringPiece common_set_hashes, uint64* out_hash, - uint32* out_index) OVERRIDE; + uint32* out_index) const OVERRIDE; private: - DISALLOW_COPY_AND_ASSIGN(CommonCertSetQUIC); + DISALLOW_COPY_AND_ASSIGN(CommonCertSetsQUIC); }; } // namespace net diff --git a/net/quic/crypto/common_cert_set_1_50.inc b/net/quic/crypto/common_cert_set_1_50.inc index 861c9b4..c151f1e 100644 --- a/net/quic/crypto/common_cert_set_1_50.inc +++ b/net/quic/crypto/common_cert_set_1_50.inc @@ -3,6 +3,9 @@ * found in the LICENSE file. */ +/* This file contains common certificates. It's designed to be #included in + * another file, in a namespace. */ + #if 0 Certificate: Data: diff --git a/net/quic/crypto/common_cert_set_51_100.inc b/net/quic/crypto/common_cert_set_51_100.inc index e66298b..0a1b0d1a 100644 --- a/net/quic/crypto/common_cert_set_51_100.inc +++ b/net/quic/crypto/common_cert_set_51_100.inc @@ -3,6 +3,9 @@ * found in the LICENSE file. */ +/* This file contains common certificates. It's designed to be #included in + * another file, in a namespace. */ + #if 0 Certificate: Data: diff --git a/net/quic/crypto/common_cert_set_test.cc b/net/quic/crypto/common_cert_set_test.cc index 0c1b841..51b41d8 100644 --- a/net/quic/crypto/common_cert_set_test.cc +++ b/net/quic/crypto/common_cert_set_test.cc @@ -72,18 +72,18 @@ static unsigned char kGIACertificate[] = { 0x95, 0x87, 0xbc, 0xbc, 0x90, 0xf9, 0x50, 0x32, }; -TEST(CommonCertSet, FindGIA) { +TEST(CommonCertSets, FindGIA) { StringPiece gia(reinterpret_cast<const char*>(kGIACertificate), sizeof(kGIACertificate)); - CommonCertSetQUIC set; + CommonCertSetsQUIC set; const uint64 in_hash = GG_UINT64_C(0xde8086f914a3af54); uint64 hash; uint32 index; ASSERT_TRUE(set.MatchCert( - gia, StringPiece(reinterpret_cast<const char*>(&in_hash), - sizeof(in_hash)), + gia, + StringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)), &hash, &index)); EXPECT_EQ(in_hash, hash); @@ -93,15 +93,15 @@ TEST(CommonCertSet, FindGIA) { EXPECT_TRUE(0 == memcmp(gia.data(), gia_copy.data(), gia.size())); } -TEST(CommonCertSet, NonMatch) { - CommonCertSetQUIC set; +TEST(CommonCertSets, NonMatch) { + CommonCertSetsQUIC set; StringPiece not_a_cert("hello"); const uint64 in_hash = GG_UINT64_C(0xde8086f914a3af54); uint64 hash; uint32 index; EXPECT_FALSE(set.MatchCert( - not_a_cert, StringPiece(reinterpret_cast<const char*>(&in_hash), - sizeof(in_hash)), + not_a_cert, + StringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)), &hash, &index)); } diff --git a/net/quic/crypto/crypto_framer.cc b/net/quic/crypto/crypto_framer.cc index cbc1079..4b3ce64 100644 --- a/net/quic/crypto/crypto_framer.cc +++ b/net/quic/crypto/crypto_framer.cc @@ -17,7 +17,7 @@ namespace net { namespace { -const size_t kCryptoTagSize = sizeof(uint32); +const size_t kQuicTagSize = sizeof(uint32); const size_t kCryptoEndOffsetSize = sizeof(uint32); const size_t kNumEntriesSize = sizeof(uint16); const size_t kValueLenSize = sizeof(uint16); @@ -30,18 +30,14 @@ class OneShotVisitor : public CryptoFramerVisitorInterface { error_(false) { } - virtual void OnError(CryptoFramer* framer) OVERRIDE { - error_ = true; - } + virtual void OnError(CryptoFramer* framer) OVERRIDE { error_ = true; } virtual void OnHandshakeMessage( const CryptoHandshakeMessage& message) OVERRIDE { *out_ = message; } - bool error() const { - return error_; - } + bool error() const { return error_; } private: CryptoHandshakeMessage* const out_; @@ -66,8 +62,7 @@ CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) { CryptoFramer framer; framer.set_visitor(&visitor); - if (!framer.ProcessInput(in) || - visitor.error() || + if (!framer.ProcessInput(in) || visitor.error() || framer.InputBytesRemaining()) { return NULL; } @@ -86,10 +81,10 @@ bool CryptoFramer::ProcessInput(StringPiece input) { switch (state_) { case STATE_READING_TAG: - if (reader.BytesRemaining() < kCryptoTagSize) { + if (reader.BytesRemaining() < kQuicTagSize) { break; } - CryptoTag message_tag; + QuicTag message_tag; reader.ReadUInt32(&message_tag); message_.set_tag(message_tag); state_ = STATE_READING_NUM_ENTRIES; @@ -109,14 +104,14 @@ bool CryptoFramer::ProcessInput(StringPiece input) { state_ = STATE_READING_TAGS_AND_LENGTHS; values_len_ = 0; case STATE_READING_TAGS_AND_LENGTHS: { - if (reader.BytesRemaining() < num_entries_ * (kCryptoTagSize + - kCryptoEndOffsetSize)) { + if (reader.BytesRemaining() < + num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) { break; } uint32 last_end_offset = 0; for (unsigned i = 0; i < num_entries_; ++i) { - CryptoTag tag; + QuicTag tag; reader.ReadUInt32(&tag); if (i > 0 && tag <= tags_and_lengths_[i-1].first) { if (tag == tags_and_lengths_[i-1].first) { @@ -145,7 +140,7 @@ bool CryptoFramer::ProcessInput(StringPiece input) { if (reader.BytesRemaining() < values_len_) { break; } - for (vector<pair<CryptoTag, size_t> >::const_iterator + for (vector<pair<QuicTag, size_t> >::const_iterator it = tags_and_lengths_.begin(); it != tags_and_lengths_.end(); it++) { StringPiece value; @@ -168,14 +163,14 @@ QuicData* CryptoFramer::ConstructHandshakeMessage( if (message.tag_value_map().size() > kMaxEntries) { return NULL; } - size_t len = kCryptoTagSize; // message tag - len += sizeof(uint16); // number of map entries - len += sizeof(uint16); // padding. - CryptoTagValueMap::const_iterator it = message.tag_value_map().begin(); + size_t len = kQuicTagSize; // message tag + len += sizeof(uint16); // number of map entries + len += sizeof(uint16); // padding. + QuicTagValueMap::const_iterator it = message.tag_value_map().begin(); while (it != message.tag_value_map().end()) { - len += kCryptoTagSize; // tag + len += kQuicTagSize; // tag len += kCryptoEndOffsetSize; // end offset - len += it->second.length(); // value + len += it->second.length(); // value ++it; } diff --git a/net/quic/crypto/crypto_framer.h b/net/quic/crypto/crypto_framer.h index 7861284..75cc405 100644 --- a/net/quic/crypto/crypto_framer.h +++ b/net/quic/crypto/crypto_framer.h @@ -56,9 +56,7 @@ class NET_EXPORT_PRIVATE CryptoFramer { visitor_ = visitor; } - QuicErrorCode error() const { - return error_; - } + QuicErrorCode error() const { return error_; } // Processes input data, which must be delivered in order. Returns // false if there was an error, and true otherwise. @@ -66,9 +64,7 @@ class NET_EXPORT_PRIVATE CryptoFramer { // Returns the number of bytes of buffered input data remaining to be // parsed. - size_t InputBytesRemaining() const { - return buffer_.length(); - } + size_t InputBytesRemaining() const { return buffer_.length(); } // Returns a new QuicData owned by the caller that contains a serialized // |message|, or NULL if there was an error. @@ -79,9 +75,7 @@ class NET_EXPORT_PRIVATE CryptoFramer { // Clears per-message state. Does not clear the visitor. void Clear(); - void set_error(QuicErrorCode error) { - error_ = error; - } + void set_error(QuicErrorCode error) { error_ = error; } // Represents the current state of the parsing state machine. enum CryptoFramerState { @@ -105,7 +99,7 @@ class NET_EXPORT_PRIVATE CryptoFramer { uint16 num_entries_; // tags_and_lengths_ contains the tags that are currently being parsed and // their lengths. - std::vector<std::pair<CryptoTag, size_t> > tags_and_lengths_; + std::vector<std::pair<QuicTag, size_t> > tags_and_lengths_; // Cumulative length of all values in the message currently being parsed. size_t values_len_; }; diff --git a/net/quic/crypto/crypto_framer_test.cc b/net/quic/crypto/crypto_framer_test.cc index 0cdbd40..ca4b92e 100644 --- a/net/quic/crypto/crypto_framer_test.cc +++ b/net/quic/crypto/crypto_framer_test.cc @@ -49,16 +49,6 @@ class TestCryptoVisitor : public ::net::CryptoFramerVisitorInterface { vector<CryptoHandshakeMessage> messages_; }; -TEST(CryptoFramerTest, MakeCryptoTag) { - CryptoTag tag = MakeQuicTag('A', 'B', 'C', 'D'); - char bytes[4]; - memcpy(bytes, &tag, 4); - EXPECT_EQ('A', bytes[0]); - EXPECT_EQ('B', bytes[1]); - EXPECT_EQ('C', bytes[2]); - EXPECT_EQ('D', bytes[3]); -} - TEST(CryptoFramerTest, ConstructHandshakeMessage) { CryptoHandshakeMessage message; message.set_tag(0xFFAA7733); @@ -356,8 +346,8 @@ TEST(CryptoFramerTest, ProcessEndOffsetsOutOfOrder) { 0x00, 0x00, 0x00, 0x00, }; - EXPECT_FALSE(framer.ProcessInput(StringPiece(AsChars(input), - arraysize(input)))); + EXPECT_FALSE( + framer.ProcessInput(StringPiece(AsChars(input), arraysize(input)))); EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error()); } @@ -375,8 +365,8 @@ TEST(CryptoFramerTest, ProcessInputTooManyEntries) { 0x00, 0x00, }; - EXPECT_FALSE(framer.ProcessInput(StringPiece(AsChars(input), - arraysize(input)))); + EXPECT_FALSE( + framer.ProcessInput(StringPiece(AsChars(input), arraysize(input)))); EXPECT_EQ(QUIC_CRYPTO_TOO_MANY_ENTRIES, framer.error()); } @@ -402,8 +392,8 @@ TEST(CryptoFramerTest, ProcessInputZeroLength) { 0x05, 0x00, 0x00, 0x00, }; - EXPECT_TRUE(framer.ProcessInput(StringPiece(AsChars(input), - arraysize(input)))); + EXPECT_TRUE( + framer.ProcessInput(StringPiece(AsChars(input), arraysize(input)))); } } // namespace test diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc index 0788508..16d32d6 100644 --- a/net/quic/crypto/crypto_handshake.cc +++ b/net/quic/crypto/crypto_handshake.cc @@ -23,7 +23,6 @@ #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" #include "net/quic/crypto/quic_random.h" -#include "net/quic/quic_clock.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_utils.h" @@ -69,23 +68,23 @@ const QuicData& CryptoHandshakeMessage::GetSerialized() const { return *serialized_.get(); } -void CryptoHandshakeMessage::Insert(CryptoTagValueMap::const_iterator begin, - CryptoTagValueMap::const_iterator end) { +void CryptoHandshakeMessage::Insert(QuicTagValueMap::const_iterator begin, + QuicTagValueMap::const_iterator end) { tag_value_map_.insert(begin, end); } -void CryptoHandshakeMessage::SetTaglist(CryptoTag tag, ...) { - // Warning, if sizeof(CryptoTag) > sizeof(int) then this function will break +void CryptoHandshakeMessage::SetTaglist(QuicTag tag, ...) { + // Warning, if sizeof(QuicTag) > sizeof(int) then this function will break // because the terminating 0 will only be promoted to int. - COMPILE_ASSERT(sizeof(CryptoTag) <= sizeof(int), + COMPILE_ASSERT(sizeof(QuicTag) <= sizeof(int), crypto_tag_not_be_larger_than_int_or_varargs_will_break); - vector<CryptoTag> tags; + vector<QuicTag> tags; va_list ap; va_start(ap, tag); for (;;) { - CryptoTag list_item = va_arg(ap, CryptoTag); + QuicTag list_item = va_arg(ap, QuicTag); if (list_item == 0) { break; } @@ -100,20 +99,20 @@ void CryptoHandshakeMessage::SetTaglist(CryptoTag tag, ...) { va_end(ap); } -void CryptoHandshakeMessage::SetStringPiece(CryptoTag tag, StringPiece value) { +void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, StringPiece value) { tag_value_map_[tag] = value.as_string(); } -QuicErrorCode CryptoHandshakeMessage::GetTaglist(CryptoTag tag, - const CryptoTag** out_tags, +QuicErrorCode CryptoHandshakeMessage::GetTaglist(QuicTag tag, + const QuicTag** out_tags, size_t* out_len) const { - CryptoTagValueMap::const_iterator it = tag_value_map_.find(tag); + QuicTagValueMap::const_iterator it = tag_value_map_.find(tag); *out_len = 0; QuicErrorCode ret = QUIC_NO_ERROR; if (it == tag_value_map_.end()) { ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; - } else if (it->second.size() % sizeof(CryptoTag) != 0) { + } else if (it->second.size() % sizeof(QuicTag) != 0) { ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; } @@ -123,14 +122,14 @@ QuicErrorCode CryptoHandshakeMessage::GetTaglist(CryptoTag tag, return ret; } - *out_tags = reinterpret_cast<const CryptoTag*>(it->second.data()); - *out_len = it->second.size() / sizeof(CryptoTag); + *out_tags = reinterpret_cast<const QuicTag*>(it->second.data()); + *out_len = it->second.size() / sizeof(QuicTag); return ret; } -bool CryptoHandshakeMessage::GetStringPiece(CryptoTag tag, +bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag, StringPiece* out) const { - CryptoTagValueMap::const_iterator it = tag_value_map_.find(tag); + QuicTagValueMap::const_iterator it = tag_value_map_.find(tag); if (it == tag_value_map_.end()) { return false; } @@ -138,7 +137,7 @@ bool CryptoHandshakeMessage::GetStringPiece(CryptoTag tag, return true; } -QuicErrorCode CryptoHandshakeMessage::GetNthValue16(CryptoTag tag, +QuicErrorCode CryptoHandshakeMessage::GetNthValue24(QuicTag tag, unsigned index, StringPiece* out) const { StringPiece value; @@ -150,15 +149,16 @@ QuicErrorCode CryptoHandshakeMessage::GetNthValue16(CryptoTag tag, if (value.empty()) { return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND; } - if (value.size() < 2) { + if (value.size() < 3) { return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; } const unsigned char* data = reinterpret_cast<const unsigned char*>(value.data()); size_t size = static_cast<size_t>(data[0]) | - (static_cast<size_t>(data[1]) << 8); - value.remove_prefix(2); + (static_cast<size_t>(data[1]) << 8) | + (static_cast<size_t>(data[2]) << 16); + value.remove_prefix(3); if (value.size() < size) { return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; @@ -173,8 +173,8 @@ QuicErrorCode CryptoHandshakeMessage::GetNthValue16(CryptoTag tag, } } -bool CryptoHandshakeMessage::GetString(CryptoTag tag, string* out) const { - CryptoTagValueMap::const_iterator it = tag_value_map_.find(tag); +bool CryptoHandshakeMessage::GetString(QuicTag tag, string* out) const { + QuicTagValueMap::const_iterator it = tag_value_map_.find(tag); if (it == tag_value_map_.end()) { return false; } @@ -182,23 +182,28 @@ bool CryptoHandshakeMessage::GetString(CryptoTag tag, string* out) const { return true; } -QuicErrorCode CryptoHandshakeMessage::GetUint16(CryptoTag tag, +QuicErrorCode CryptoHandshakeMessage::GetUint16(QuicTag tag, uint16* out) const { return GetPOD(tag, out, sizeof(uint16)); } -QuicErrorCode CryptoHandshakeMessage::GetUint32(CryptoTag tag, +QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag, uint32* out) const { return GetPOD(tag, out, sizeof(uint32)); } +QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag, + uint64* out) const { + return GetPOD(tag, out, sizeof(uint64)); +} + string CryptoHandshakeMessage::DebugString() const { return DebugStringInternal(0); } QuicErrorCode CryptoHandshakeMessage::GetPOD( - CryptoTag tag, void* out, size_t len) const { - CryptoTagValueMap::const_iterator it = tag_value_map_.find(tag); + QuicTag tag, void* out, size_t len) const { + QuicTagValueMap::const_iterator it = tag_value_map_.find(tag); QuicErrorCode ret = QUIC_NO_ERROR; if (it == tag_value_map_.end()) { @@ -220,10 +225,10 @@ QuicErrorCode CryptoHandshakeMessage::GetPOD( // that converts a tag to a string. It will try to maintain the human friendly // name if possible (i.e. kABCD -> "ABCD"), or will just treat it as a number // if not. -static string TagToString(CryptoTag tag) { +static string TagToString(QuicTag tag) { char chars[4]; bool ascii = true; - const CryptoTag orig_tag = tag; + const QuicTag orig_tag = tag; for (size_t i = 0; i < sizeof(chars); i++) { chars[i] = tag; @@ -247,52 +252,52 @@ static string TagToString(CryptoTag tag) { string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const { string ret = string(2 * indent, ' ') + TagToString(tag_) + "<\n"; ++indent; - for (CryptoTagValueMap::const_iterator it = tag_value_map_.begin(); + for (QuicTagValueMap::const_iterator it = tag_value_map_.begin(); it != tag_value_map_.end(); ++it) { ret += string(2 * indent, ' ') + TagToString(it->first) + ": "; bool done = false; switch (it->first) { - case kKATO: - case kVERS: - // uint32 value - if (it->second.size() == 4) { - uint32 value; - memcpy(&value, it->second.data(), sizeof(value)); - ret += base::UintToString(value); - done = true; - } - break; - case kKEXS: - case kAEAD: - case kCGST: - case kPDMD: - // tag lists - if (it->second.size() % sizeof(CryptoTag) == 0) { - for (size_t j = 0; j < it->second.size(); j += sizeof(CryptoTag)) { - CryptoTag tag; - memcpy(&tag, it->second.data() + j, sizeof(tag)); - if (j > 0) { - ret += ","; - } - ret += TagToString(tag); + case kKATO: + case kVERS: + // uint32 value + if (it->second.size() == 4) { + uint32 value; + memcpy(&value, it->second.data(), sizeof(value)); + ret += base::UintToString(value); + done = true; } - done = true; - } - break; - case kSCFG: - // nested messages. - if (!it->second.empty()) { - scoped_ptr<CryptoHandshakeMessage> msg( - CryptoFramer::ParseMessage(it->second)); - if (msg.get()) { - ret += "\n"; - ret += msg->DebugStringInternal(indent + 1); - + break; + case kKEXS: + case kAEAD: + case kCGST: + case kPDMD: + // tag lists + if (it->second.size() % sizeof(QuicTag) == 0) { + for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) { + QuicTag tag; + memcpy(&tag, it->second.data() + j, sizeof(tag)); + if (j > 0) { + ret += ","; + } + ret += TagToString(tag); + } done = true; } - } - break; + break; + case kSCFG: + // nested messages. + if (!it->second.empty()) { + scoped_ptr<CryptoHandshakeMessage> msg( + CryptoFramer::ParseMessage(it->second)); + if (msg.get()) { + ret += "\n"; + ret += msg->DebugStringInternal(indent + 1); + + done = true; + } + } + break; } if (!done) { @@ -313,16 +318,20 @@ QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters() aead(0) { } -QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() { -} +QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() {} +CrypterPair::CrypterPair() {} +CrypterPair::~CrypterPair() {} // static -const char QuicCryptoConfig::kLabel[] = "QUIC key expansion"; +const char QuicCryptoConfig::kInitialLabel[] = "QUIC key expansion"; + +const char QuicCryptoConfig::kForwardSecureLabel[] = + "QUIC forward secure key expansion"; QuicCryptoConfig::QuicCryptoConfig() : version(0), - common_cert_set_(new CommonCertSetQUIC) { + common_cert_set_(new CommonCertSetsQUIC) { } QuicCryptoConfig::~QuicCryptoConfig() {} @@ -355,8 +364,7 @@ QuicCryptoClientConfig::CachedState::GetServerConfig() const { return scfg_.get(); } -bool QuicCryptoClientConfig::CachedState::SetServerConfig( - StringPiece scfg) { +bool QuicCryptoClientConfig::CachedState::SetServerConfig(StringPiece scfg) { scfg_.reset(CryptoFramer::ParseMessage(scfg)); if (!scfg_.get()) { return false; @@ -365,8 +373,8 @@ bool QuicCryptoClientConfig::CachedState::SetServerConfig( return true; } -void QuicCryptoClientConfig::CachedState::SetProof( - const vector<string>& certs, StringPiece signature) { +void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs, + StringPiece signature) { bool has_changed = signature != server_config_sig_; if (certs_.size() != certs.size()) { @@ -395,8 +403,7 @@ void QuicCryptoClientConfig::CachedState::SetProofValid() { server_config_valid_ = true; } -const string& -QuicCryptoClientConfig::CachedState::server_config() const { +const string& QuicCryptoClientConfig::CachedState::server_config() const { return server_config_; } @@ -466,7 +473,7 @@ void QuicCryptoClientConfig::FillInchoateClientHello( out->SetValue(kVERS, version); if (!cached->source_address_token().empty()) { - out->SetStringPiece(kSRCT, cached->source_address_token()); + out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token()); } out->SetTaglist(kPDMD, kX509, 0); @@ -476,6 +483,7 @@ void QuicCryptoClientConfig::FillInchoateClientHello( } const vector<string>& certs = cached->certs(); + out_params->cached_certs = certs; if (!certs.empty()) { vector<uint64> hashes; hashes.reserve(certs.size()); @@ -488,7 +496,6 @@ void QuicCryptoClientConfig::FillInchoateClientHello( // client config is being used for multiple connections, another connection // doesn't update the cached certificates and cause us to be unable to // process the server's compressed certificate chain. - out_params->cached_certs = certs; } } @@ -496,7 +503,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( const string& server_hostname, QuicGuid guid, const CachedState* cached, - const QuicClock* clock, + QuicWallTime now, QuicRandom* rand, QuicCryptoNegotiatedParameters* out_params, CryptoHandshakeMessage* out, @@ -513,6 +520,17 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( return QUIC_CRYPTO_INTERNAL_ERROR; } + uint64 expiry_seconds; + if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) { + *error_details = "SCFG missing EXPY"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + if (static_cast<uint64>(now.ToUNIXSeconds()) >= expiry_seconds) { + *error_details = "SCFG expired"; + return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED; + } + StringPiece scid; if (!scfg->GetStringPiece(kSCID, &scid)) { *error_details = "SCFG missing SCID"; @@ -527,8 +545,8 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( return QUIC_CRYPTO_VERSION_NOT_SUPPORTED; } - const CryptoTag* their_aeads; - const CryptoTag* their_key_exchanges; + const QuicTag* their_aeads; + const QuicTag* their_key_exchanges; size_t num_their_aeads, num_their_key_exchanges; if (scfg->GetTaglist(kAEAD, &their_aeads, &num_their_aeads) != QUIC_NO_ERROR || @@ -539,16 +557,13 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( } size_t key_exchange_index; - if (!CryptoUtils::FindMutualTag(aead, - their_aeads, num_their_aeads, - CryptoUtils::PEER_PRIORITY, - &out_params->aead, + if (!CryptoUtils::FindMutualTag(aead, their_aeads, num_their_aeads, + CryptoUtils::PEER_PRIORITY, &out_params->aead, NULL) || - !CryptoUtils::FindMutualTag(kexs, - their_key_exchanges, num_their_key_exchanges, - CryptoUtils::PEER_PRIORITY, - &out_params->key_exchange, - &key_exchange_index)) { + !CryptoUtils::FindMutualTag( + kexs, their_key_exchanges, num_their_key_exchanges, + CryptoUtils::PEER_PRIORITY, &out_params->key_exchange, + &key_exchange_index)) { *error_details = "Unsupported AEAD or KEXS"; return QUIC_CRYPTO_NO_SUPPORT; } @@ -556,7 +571,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( out->SetTaglist(kKEXS, out_params->key_exchange, 0); StringPiece public_value; - if (scfg->GetNthValue16(kPUBS, key_exchange_index, &public_value) != + if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) != QUIC_NO_ERROR) { *error_details = "Missing public value"; return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; @@ -568,44 +583,52 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; } - string nonce; - CryptoUtils::GenerateNonce(clock->NowAsDeltaSinceUnixEpoch(), rand, orbit, - &nonce); - out->SetStringPiece(kNONC, nonce); + CryptoUtils::GenerateNonce(now, rand, orbit, &out_params->client_nonce); + out->SetStringPiece(kNONC, out_params->client_nonce); + if (!out_params->server_nonce.empty()) { + out->SetStringPiece(kServerNonceTag, out_params->server_nonce); + } - scoped_ptr<KeyExchange> key_exchange; switch (out_params->key_exchange) { - case kC255: - key_exchange.reset(Curve25519KeyExchange::New( + case kC255: + out_params->client_key_exchange.reset(Curve25519KeyExchange::New( Curve25519KeyExchange::NewPrivateKey(rand))); - break; - case kP256: - key_exchange.reset(P256KeyExchange::New( - P256KeyExchange::NewPrivateKey())); - break; - default: - DCHECK(false); - *error_details = "Configured to support an unknown key exchange"; - return QUIC_CRYPTO_INTERNAL_ERROR; + break; + case kP256: + out_params->client_key_exchange + .reset(P256KeyExchange::New(P256KeyExchange::NewPrivateKey())); + break; + default: + DCHECK(false); + *error_details = "Configured to support an unknown key exchange"; + return QUIC_CRYPTO_INTERNAL_ERROR; } - if (!key_exchange->CalculateSharedKey(public_value, - &out_params->premaster_secret)) { + if (!out_params->client_key_exchange->CalculateSharedKey( + public_value, &out_params->initial_premaster_secret)) { *error_details = "Key exchange failure"; return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; } - out->SetStringPiece(kPUBS, key_exchange->public_value()); - - string hkdf_input(QuicCryptoConfig::kLabel, - strlen(QuicCryptoConfig::kLabel) + 1); - hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid)); + out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value()); + out_params->hkdf_input_suffix.clear(); + out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&guid), + sizeof(guid)); const QuicData& client_hello_serialized = out->GetSerialized(); - hkdf_input.append(client_hello_serialized.data(), - client_hello_serialized.length()); - hkdf_input.append(cached->server_config()); + out_params->hkdf_input_suffix.append(client_hello_serialized.data(), + client_hello_serialized.length()); + out_params->hkdf_input_suffix.append(cached->server_config()); - CryptoUtils::DeriveKeys(out_params, nonce, hkdf_input, CryptoUtils::CLIENT); + string hkdf_input; + const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; + hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size()); + hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len); + hkdf_input.append(out_params->hkdf_input_suffix); + + CryptoUtils::DeriveKeys(out_params->initial_premaster_secret, + out_params->aead, out_params->client_nonce, + out_params->server_nonce, hkdf_input, + CryptoUtils::CLIENT, &out_params->initial_crypters); return QUIC_NO_ERROR; } @@ -629,19 +652,19 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection( } StringPiece token; - if (rej.GetStringPiece(kSRCT, &token)) { + if (rej.GetStringPiece(kSourceAddressTokenTag, &token)) { cached->set_source_address_token(token); } StringPiece nonce; - if (rej.GetStringPiece(kNONC, &nonce) && - nonce.size() == kNonceSize) { + if (rej.GetStringPiece(kServerNonceTag, &nonce) && nonce.size() == + kNonceSize) { out_params->server_nonce = nonce.as_string(); } StringPiece proof, cert_bytes; if (rej.GetStringPiece(kPROF, &proof) && - rej.GetStringPiece(kCERT, &cert_bytes)) { + rej.GetStringPiece(kCertificateTag, &cert_bytes)) { vector<string> certs; if (!CertCompressor::DecompressChain(cert_bytes, out_params->cached_certs, common_cert_set_.get(), &certs)) { @@ -657,7 +680,7 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection( QuicErrorCode QuicCryptoClientConfig::ProcessServerHello( const CryptoHandshakeMessage& server_hello, - const string& nonce, + QuicGuid guid, QuicCryptoNegotiatedParameters* out_params, string* error_details) { DCHECK(error_details != NULL); @@ -669,7 +692,29 @@ QuicErrorCode QuicCryptoClientConfig::ProcessServerHello( // TODO(agl): // learn about updated SCFGs. - // read ephemeral public value for forward-secret keys. + + StringPiece public_value; + if (!server_hello.GetStringPiece(kPUBS, &public_value)) { + *error_details = "server hello missing forward secure public value"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + if (!out_params->client_key_exchange->CalculateSharedKey( + public_value, &out_params->forward_secure_premaster_secret)) { + *error_details = "Key exchange failure"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + string hkdf_input; + const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1; + hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size()); + hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len); + hkdf_input.append(out_params->hkdf_input_suffix); + + CryptoUtils::DeriveKeys( + out_params->forward_secure_premaster_secret, out_params->aead, + out_params->client_nonce, out_params->server_nonce, hkdf_input, + CryptoUtils::CLIENT, &out_params->forward_secure_crypters); return QUIC_NO_ERROR; } diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h index 624471e..6b6c320 100644 --- a/net/quic/crypto/crypto_handshake.h +++ b/net/quic/crypto/crypto_handshake.h @@ -18,10 +18,9 @@ namespace net { -class CommonCertSet; +class CommonCertSets; class KeyExchange; class ProofVerifier; -class QuicClock; class QuicDecrypter; class QuicEncrypter; class QuicRandom; @@ -45,14 +44,14 @@ class NET_EXPORT_PRIVATE CryptoHandshakeMessage { // SetValue sets an element with the given tag to the raw, memory contents of // |v|. - template<class T> void SetValue(CryptoTag tag, const T& v) { - tag_value_map_[tag] = std::string(reinterpret_cast<const char*>(&v), - sizeof(v)); + template<class T> void SetValue(QuicTag tag, const T& v) { + tag_value_map_[tag] = + std::string(reinterpret_cast<const char*>(&v), sizeof(v)); } // SetVector sets an element with the given tag to the raw contents of an // array of elements in |v|. - template<class T> void SetVector(CryptoTag tag, const std::vector<T>& v) { + template<class T> void SetVector(QuicTag tag, const std::vector<T>& v) { if (v.empty()) { tag_value_map_[tag] = std::string(); } else { @@ -62,40 +61,41 @@ class NET_EXPORT_PRIVATE CryptoHandshakeMessage { } // Returns the message tag. - CryptoTag tag() const { return tag_; } + QuicTag tag() const { return tag_; } // Sets the message tag. - void set_tag(CryptoTag tag) { tag_ = tag; } + void set_tag(QuicTag tag) { tag_ = tag; } - const CryptoTagValueMap& tag_value_map() const { return tag_value_map_; } + const QuicTagValueMap& tag_value_map() const { return tag_value_map_; } - void Insert(CryptoTagValueMap::const_iterator begin, - CryptoTagValueMap::const_iterator end); + void Insert(QuicTagValueMap::const_iterator begin, + QuicTagValueMap::const_iterator end); // SetTaglist sets an element with the given tag to contain a list of tags, // passed as varargs. The argument list must be terminated with a 0 element. - void SetTaglist(CryptoTag tag, ...); + void SetTaglist(QuicTag tag, ...); - void SetStringPiece(CryptoTag tag, base::StringPiece value); + void SetStringPiece(QuicTag tag, base::StringPiece value); // GetTaglist finds an element with the given tag containing zero or more // tags. If such a tag doesn't exist, it returns false. Otherwise it sets // |out_tags| and |out_len| to point to the array of tags and returns true. // The array points into the CryptoHandshakeMessage and is valid only for as // long as the CryptoHandshakeMessage exists and is not modified. - QuicErrorCode GetTaglist(CryptoTag tag, const CryptoTag** out_tags, + QuicErrorCode GetTaglist(QuicTag tag, const QuicTag** out_tags, size_t* out_len) const; - bool GetStringPiece(CryptoTag tag, base::StringPiece* out) const; + bool GetStringPiece(QuicTag tag, base::StringPiece* out) const; - // GetNthValue16 interprets the value with the given tag to be a series of - // 16-bit length prefixed values and it returns the subvalue with the given + // GetNthValue24 interprets the value with the given tag to be a series of + // 24-bit, length prefixed values and it returns the subvalue with the given // index. - QuicErrorCode GetNthValue16(CryptoTag tag, + QuicErrorCode GetNthValue24(QuicTag tag, unsigned index, base::StringPiece* out) const; - bool GetString(CryptoTag tag, std::string* out) const; - QuicErrorCode GetUint16(CryptoTag tag, uint16* out) const; - QuicErrorCode GetUint32(CryptoTag tag, uint32* out) const; + bool GetString(QuicTag tag, std::string* out) const; + QuicErrorCode GetUint16(QuicTag tag, uint16* out) const; + QuicErrorCode GetUint32(QuicTag tag, uint32* out) const; + QuicErrorCode GetUint64(QuicTag tag, uint64* out) const; // DebugString returns a multi-line, string representation of the message // suitable for including in debug output. @@ -109,18 +109,26 @@ class NET_EXPORT_PRIVATE CryptoHandshakeMessage { // // If used to copy integers then this assumes that the machine is // little-endian. - QuicErrorCode GetPOD(CryptoTag tag, void* out, size_t len) const; + QuicErrorCode GetPOD(QuicTag tag, void* out, size_t len) const; std::string DebugStringInternal(size_t indent) const; - CryptoTag tag_; - CryptoTagValueMap tag_value_map_; + QuicTag tag_; + QuicTagValueMap tag_value_map_; // The serialized form of the handshake message. This member is constructed // lasily. mutable scoped_ptr<QuicData> serialized_; }; +// A CrypterPair contains the encrypter and decrypter for an encryption level. +struct NET_EXPORT_PRIVATE CrypterPair { + CrypterPair(); + ~CrypterPair(); + scoped_ptr<QuicEncrypter> encrypter; + scoped_ptr<QuicDecrypter> decrypter; +}; + // Parameters negotiated by the crypto handshake. struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters { // Initializes the members to 0 or empty values. @@ -128,16 +136,26 @@ struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters { ~QuicCryptoNegotiatedParameters(); uint16 version; - CryptoTag key_exchange; - CryptoTag aead; - std::string premaster_secret; - scoped_ptr<QuicEncrypter> encrypter; - scoped_ptr<QuicDecrypter> decrypter; + QuicTag key_exchange; + QuicTag aead; + std::string initial_premaster_secret; + std::string forward_secure_premaster_secret; + CrypterPair initial_crypters; + CrypterPair forward_secure_crypters; std::string server_config_id; + std::string client_nonce; std::string server_nonce; + // hkdf_input_suffix contains the HKDF input following the label: the GUID, + // client hello and server config. This is only populated in the client + // because only the client needs to derive the forward secure keys at a later + // time from the initial keys. + std::string hkdf_input_suffix; // cached_certs contains the cached certificates that a client used when // sending a client hello. std::vector<std::string> cached_certs; + // client_key_exchange is used by clients to store the ephemeral KeyExchange + // for the connection. + scoped_ptr<KeyExchange> client_key_exchange; }; // QuicCryptoConfig contains common configuration between clients and servers. @@ -149,9 +167,15 @@ class NET_EXPORT_PRIVATE QuicCryptoConfig { CONFIG_VERSION = 0, }; - // kLabel is constant that is used in key derivation to tie the resulting key - // to this protocol. - static const char kLabel[]; + // kInitialLabel is a constant that is used when deriving the initial + // (non-forward secure) keys for the connection in order to tie the resulting + // key to this protocol. + static const char kInitialLabel[]; + + // kForwardSecureLabel is a constant that is used when deriving the forward + // secure keys for the connection in order to tie the resulting key to this + // protocol. + static const char kForwardSecureLabel[]; QuicCryptoConfig(); ~QuicCryptoConfig(); @@ -160,11 +184,11 @@ class NET_EXPORT_PRIVATE QuicCryptoConfig { uint16 version; // Key exchange methods. The following two members' values correspond by // index. - CryptoTagVector kexs; + QuicTagVector kexs; // Authenticated encryption with associated data (AEAD) algorithms. - CryptoTagVector aead; + QuicTagVector aead; - scoped_ptr<CommonCertSet> common_cert_set_; + scoped_ptr<CommonCertSets> common_cert_set_; private: DISALLOW_COPY_AND_ASSIGN(QuicCryptoConfig); @@ -215,12 +239,12 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { 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. + std::string server_config_id_; // An opaque id from the server. + std::string server_config_; // A serialized handshake message. std::string source_address_token_; // An opaque proof of IP ownership. - std::vector<std::string> certs_; // A list of certificates in leaf-first - // order. - std::string server_config_sig_; // A signature of |server_config_|. + std::vector<std::string> certs_; // A list of certificates in leaf-first + // order. + std::string server_config_sig_; // A signature of |server_config_|. bool server_config_valid_; // true if |server_config_| is correctly signed // and |certs_| has been validated. @@ -240,7 +264,9 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // FillInchoateClientHello sets |out| to be a CHLO message that elicits a // source-address token or SCFG from a server. If |cached| is non-NULL, the - // source-address token will be taken from it. + // source-address token will be taken from it. |out_params| is used in order + // to store the cached certs that were sent as hints to the server in + // |out_params->cached_certs|. void FillInchoateClientHello(const std::string& server_hostname, const CachedState* cached, QuicCryptoNegotiatedParameters* out_params, @@ -257,7 +283,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { QuicErrorCode FillClientHello(const std::string& server_hostname, QuicGuid guid, const CachedState* cached, - const QuicClock* clock, + QuicWallTime now, QuicRandom* rand, QuicCryptoNegotiatedParameters* out_params, CryptoHandshakeMessage* out, @@ -278,7 +304,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // |server_hello| is unacceptable then it puts an error message in // |error_details| and returns an error code. QuicErrorCode ProcessServerHello(const CryptoHandshakeMessage& server_hello, - const std::string& nonce, + QuicGuid guid, QuicCryptoNegotiatedParameters* out_params, std::string* error_details); diff --git a/net/quic/crypto/crypto_handshake_test.cc b/net/quic/crypto/crypto_handshake_test.cc index 7ff0b1f..f3d86a5 100644 --- a/net/quic/crypto/crypto_handshake_test.cc +++ b/net/quic/crypto/crypto_handshake_test.cc @@ -21,18 +21,17 @@ namespace test { class QuicCryptoServerConfigPeer { public: explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig* server_config) - : server_config_(server_config) { - } + : server_config_(server_config) {} string NewSourceAddressToken(IPEndPoint ip, QuicRandom* rand, - QuicTime::Delta now) { + QuicWallTime now) { return server_config_->NewSourceAddressToken(ip, rand, now); } bool ValidateSourceAddressToken(StringPiece srct, IPEndPoint ip, - QuicTime::Delta now) { + QuicWallTime now) { return server_config_->ValidateSourceAddressToken(srct, ip, now); } @@ -46,7 +45,8 @@ TEST(QuicCryptoServerConfigTest, ServerConfig) { CryptoHandshakeMessage extra_tags; scoped_ptr<CryptoHandshakeMessage>( - server.AddDefaultConfig(QuicRandom::GetInstance(), &clock, extra_tags)); + server.AddDefaultConfig(QuicRandom::GetInstance(), &clock, extra_tags, + QuicCryptoServerConfig::kDefaultExpiry)); } TEST(QuicCryptoServerConfigTest, SourceAddressTokens) { @@ -63,10 +63,11 @@ TEST(QuicCryptoServerConfigTest, SourceAddressTokens) { IPEndPoint ip6 = IPEndPoint(ip, 2); QuicRandom* rand = QuicRandom::GetInstance(); MockClock clock; + clock.AdvanceTime(QuicTime::Delta::FromSeconds(1000000)); QuicCryptoServerConfigPeer peer(&server); - QuicTime::Delta now = clock.NowAsDeltaSinceUnixEpoch(); - const QuicTime::Delta original_time = now; + QuicWallTime now = clock.WallNow(); + const QuicWallTime original_time = now; const string token4 = peer.NewSourceAddressToken(ip4, rand, now); const string token6 = peer.NewSourceAddressToken(ip6, rand, now); diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index 213e909..32ec7b1 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h @@ -9,8 +9,8 @@ #include <string> #include <vector> -#include "base/basictypes.h" #include "net/base/net_export.h" +#include "net/quic/quic_protocol.h" // Version and Crypto tags are written to the wire with a big-endian // representation of the name of the tag. For example @@ -20,60 +20,77 @@ // to reverse the order of the bytes. // // We use a macro to ensure that no static initialisers are created. Use the -// QuicTag function in normal code. +// MakeQuicTag function in normal code. #define TAG(a, b, c, d) ((d << 24) + (c << 16) + (b << 8) + a) namespace net { -// CryptoTag is the type of a tag in the wire protocol. -typedef uint32 CryptoTag; typedef std::string ServerConfigID; -typedef std::map<CryptoTag, std::string> CryptoTagValueMap; -typedef std::vector<CryptoTag> CryptoTagVector; +typedef std::map<QuicTag, std::string> QuicTagValueMap; -const CryptoTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello -const CryptoTag kSHLO = TAG('S', 'H', 'L', 'O'); // Server hello -const CryptoTag kSCFG = TAG('S', 'C', 'F', 'G'); // Server config -const CryptoTag kREJ = TAG('R', 'E', 'J', '\0'); // Reject +const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello +const QuicTag kSHLO = TAG('S', 'H', 'L', 'O'); // Server hello +const QuicTag kSCFG = TAG('S', 'C', 'F', 'G'); // Server config +const QuicTag kREJ = TAG('R', 'E', 'J', '\0'); // Reject // Key exchange methods -const CryptoTag kP256 = TAG('P', '2', '5', '6'); // ECDH, Curve P-256 -const CryptoTag kC255 = TAG('C', '2', '5', '5'); // ECDH, Curve25519 +const QuicTag kP256 = TAG('P', '2', '5', '6'); // ECDH, Curve P-256 +const QuicTag kC255 = TAG('C', '2', '5', '5'); // ECDH, Curve25519 // AEAD algorithms -const CryptoTag kNULL = TAG('N', 'U', 'L', 'L'); // null algorithm -const CryptoTag kAESG = TAG('A', 'E', 'S', 'G'); // AES128 + GCM +const QuicTag kNULL = TAG('N', 'U', 'L', 'L'); // null algorithm +const QuicTag kAESG = TAG('A', 'E', 'S', 'G'); // AES128 + GCM // Congestion control feedback types -const CryptoTag kQBIC = TAG('Q', 'B', 'I', 'C'); // TCP cubic -const CryptoTag kINAR = TAG('I', 'N', 'A', 'R'); // Inter arrival +const QuicTag kQBIC = TAG('Q', 'B', 'I', 'C'); // TCP cubic +const QuicTag kINAR = TAG('I', 'N', 'A', 'R'); // Inter arrival // Proof types (i.e. certificate types) -const CryptoTag kX509 = TAG('X', '5', '0', '9'); // X.509 certificate +const QuicTag kX509 = TAG('X', '5', '0', '9'); // X.509 certificate // Client hello tags -const CryptoTag kVERS = TAG('V', 'E', 'R', 'S'); // Version -const CryptoTag kNONC = TAG('N', 'O', 'N', 'C'); // The connection nonce -const CryptoTag kSSID = TAG('S', 'S', 'I', 'D'); // Session ID -const CryptoTag kKEXS = TAG('K', 'E', 'X', 'S'); // Key exchange methods -const CryptoTag kAEAD = TAG('A', 'E', 'A', 'D'); // Authenticated - // encryption algorithms -const CryptoTag kCGST = TAG('C', 'G', 'S', 'T'); // Congestion control - // feedback types -const CryptoTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle connection state - // lifetime -const CryptoTag kKATO = TAG('K', 'A', 'T', 'O'); // Keepalive timeout -const CryptoTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name - // indication -const CryptoTag kPUBS = TAG('P', 'U', 'B', 'S'); // Public key values -const CryptoTag kSCID = TAG('S', 'C', 'I', 'D'); // Server config id -const CryptoTag kSRCT = TAG('S', 'R', 'C', 'T'); // Source-address token -const CryptoTag kORBT = TAG('O', 'B', 'I', 'T'); // Server orbit. -const CryptoTag kPDMD = TAG('P', 'D', 'M', 'D'); // Proof demand. -const CryptoTag kCERT = TAG('C', 'E', 'R', 'T'); // Certificate chain -const CryptoTag kPROF = TAG('P', 'R', 'O', 'F'); // Proof (signature). -const CryptoTag kCCS = TAG('C', 'C', 'S', 0); // Common certificate set -const CryptoTag kCCRT = TAG('C', 'C', 'R', 'T'); // Cached certificate +const QuicTag kVERS = TAG('V', 'E', 'R', 'S'); // Version +const QuicTag kNONC = TAG('N', 'O', 'N', 'C'); // The client's nonce +const QuicTag kSSID = TAG('S', 'S', 'I', 'D'); // Session ID +const QuicTag kKEXS = TAG('K', 'E', 'X', 'S'); // Key exchange methods +const QuicTag kAEAD = TAG('A', 'E', 'A', 'D'); // Authenticated + // encryption algorithms +const QuicTag kCGST = TAG('C', 'G', 'S', 'T'); // Congestion control + // feedback types +const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle connection state + // lifetime +const QuicTag kKATO = TAG('K', 'A', 'T', 'O'); // Keepalive timeout +const QuicTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name + // indication +const QuicTag kPUBS = TAG('P', 'U', 'B', 'S'); // Public key values +const QuicTag kSCID = TAG('S', 'C', 'I', 'D'); // Server config id +const QuicTag kORBT = TAG('O', 'B', 'I', 'T'); // Server orbit. +const QuicTag kPDMD = TAG('P', 'D', 'M', 'D'); // Proof demand. +const QuicTag kPROF = TAG('P', 'R', 'O', 'F'); // Proof (signature). +const QuicTag kCCS = TAG('C', 'C', 'S', 0); // Common certificate set +const QuicTag kCCRT = TAG('C', 'C', 'R', 'T'); // Cached certificate +const QuicTag kEXPY = TAG('E', 'X', 'P', 'Y'); // Expiry + +// These tags have a special form so that they appear either at the beginning +// or the end of a handshake message. Since handshake messages are sorted by +// tag value, the tags with 0 at the end will sort first and those with 255 at +// the end will sort last. +// +// The certificate chain should have a tag that will cause it to be sorted at +// the end of any handshake messages because it's likely to be large and the +// client might be able to get everything that it needs from the small values at +// the beginning. +// +// Likewise tags with random values should be towards the beginning of the +// message because the server mightn't hold state for a rejected client hello +// and therefore the client may have issues reassembling the rejection message +// in the event that it sent two client hellos. +const QuicTag kServerNonceTag = + TAG('S', 'N', 'O', 0); // The server's nonce +const QuicTag kSourceAddressTokenTag = + TAG('S', 'T', 'K', 0); // Source-address token +const QuicTag kCertificateTag = + TAG('C', 'R', 'T', 255); // Certificate chain #undef TAG diff --git a/net/quic/crypto/crypto_server_config.cc b/net/quic/crypto/crypto_server_config.cc index 953f57c..e4ee400 100644 --- a/net/quic/crypto/crypto_server_config.cc +++ b/net/quic/crypto/crypto_server_config.cc @@ -14,6 +14,7 @@ #include "net/quic/crypto/crypto_server_config_protobuf.h" #include "net/quic/crypto/crypto_utils.h" #include "net/quic/crypto/curve25519_key_exchange.h" +#include "net/quic/crypto/ephemeral_key_source.h" #include "net/quic/crypto/key_exchange.h" #include "net/quic/crypto/p256_key_exchange.h" #include "net/quic/crypto/proof_source.h" @@ -52,7 +53,7 @@ QuicCryptoServerConfig::QuicCryptoServerConfig( : strike_register_lock_(), source_address_token_encrypter_(new Aes128GcmEncrypter), source_address_token_decrypter_(new Aes128GcmDecrypter) { - crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */, + 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 */); @@ -68,7 +69,8 @@ QuicCryptoServerConfig::~QuicCryptoServerConfig() { QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig( QuicRandom* rand, const QuicClock* clock, - const CryptoHandshakeMessage& extra_tags) { + const CryptoHandshakeMessage& extra_tags, + uint64 expiry_time) { CryptoHandshakeMessage msg; const string curve25519_private_key = @@ -77,20 +79,20 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig( 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)); + 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. + // First three bytes encode the length of the public value. encoded_public_values.push_back(curve25519_public_value.size()); encoded_public_values.push_back(curve25519_public_value.size() >> 8); + encoded_public_values.push_back(curve25519_public_value.size() >> 16); 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.push_back(p256_public_value.size() >> 16); encoded_public_values.append(p256_public_value.data(), p256_public_value.size()); @@ -102,6 +104,16 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig( msg.Insert(extra_tags.tag_value_map().begin(), extra_tags.tag_value_map().end()); + if (expiry_time == 0) { + const QuicWallTime now = clock->WallNow(); + const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds( + 60 * 60 * 24 * 180 /* 180 days, ~six months */)); + const uint64 expiry_seconds = expiry.ToUNIXSeconds(); + msg.SetValue(kEXPY, expiry_seconds); + } else { + msg.SetValue(kEXPY, expiry_time); + } + char scid_bytes[16]; rand->RandBytes(scid_bytes, sizeof(scid_bytes)); msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes))); @@ -110,8 +122,7 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig( rand->RandBytes(orbit_bytes, sizeof(orbit_bytes)); msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes))); - scoped_ptr<QuicData> serialized( - CryptoFramer::ConstructHandshakeMessage(msg)); + scoped_ptr<QuicData> serialized(CryptoFramer::ConstructHandshakeMessage(msg)); scoped_ptr<QuicServerConfigProtobuf> config(new QuicServerConfigProtobuf); config->set_config(serialized->AsStringPiece()); @@ -135,9 +146,8 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( return NULL; } if (msg->tag() != kSCFG) { - LOG(WARNING) << "Server config message has tag " - << msg->tag() << " expected " - << kSCFG; + LOG(WARNING) << "Server config message has tag " << msg->tag() + << " expected " << kSCFG; return NULL; } @@ -151,15 +161,15 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( } config->id = scid.as_string(); - const CryptoTag* aead_tags; + const QuicTag* aead_tags; size_t aead_len; if (msg->GetTaglist(kAEAD, &aead_tags, &aead_len) != QUIC_NO_ERROR) { LOG(WARNING) << "Server config message is missing AEAD"; return NULL; } - config->aead = vector<CryptoTag>(aead_tags, aead_tags + aead_len); + config->aead = vector<QuicTag>(aead_tags, aead_tags + aead_len); - const CryptoTag* kexs_tags; + const QuicTag* kexs_tags; size_t kexs_len; if (msg->GetTaglist(kKEXS, &kexs_tags, &kexs_len) != QUIC_NO_ERROR) { LOG(WARNING) << "Server config message is missing KEXS"; @@ -181,16 +191,14 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( memcpy(config->orbit, orbit.data(), sizeof(config->orbit)); if (kexs_len != protobuf->key_size()) { - LOG(WARNING) << "Server config has " - << kexs_len + LOG(WARNING) << "Server config has " << kexs_len << " key exchange methods configured, but " - << protobuf->key_size() - << " private keys"; + << protobuf->key_size() << " private keys"; return NULL; } for (size_t i = 0; i < kexs_len; i++) { - const CryptoTag tag = kexs_tags[i]; + const QuicTag tag = kexs_tags[i]; string private_key; config->kexs.push_back(tag); @@ -205,34 +213,32 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( if (private_key.empty()) { LOG(WARNING) << "Server config contains key exchange method without " - "corresponding private key: " - << tag; + "corresponding private key: " << tag; return NULL; } scoped_ptr<KeyExchange> ka; switch (tag) { - case kC255: - ka.reset(Curve25519KeyExchange::New(private_key)); - if (!ka.get()) { - LOG(WARNING) << "Server config contained an invalid curve25519" - " private key."; - 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."; + case kC255: + ka.reset(Curve25519KeyExchange::New(private_key)); + if (!ka.get()) { + LOG(WARNING) << "Server config contained an invalid curve25519" + " private key."; + 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: " << tag; return NULL; - } - break; - default: - LOG(WARNING) << "Server config message contains unknown key exchange " - "method: " - << tag; - return NULL; } for (vector<KeyExchange*>::const_iterator i = config->key_exchanges.begin(); @@ -271,9 +277,10 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig( QuicRandom* rand, const QuicClock* clock, - const CryptoHandshakeMessage& extra_tags) { + const CryptoHandshakeMessage& extra_tags, + uint64 expiry_time) { scoped_ptr<QuicServerConfigProtobuf> config(DefaultConfig( - rand, clock, extra_tags)); + rand, clock, extra_tags, expiry_time)); return AddConfig(config.get()); } @@ -281,7 +288,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( const CryptoHandshakeMessage& client_hello, QuicGuid guid, const IPEndPoint& client_ip, - QuicTime::Delta now_since_unix_epoch, + const QuicClock* clock, QuicRandom* rand, QuicCryptoNegotiatedParameters *params, CryptoHandshakeMessage* out, @@ -299,15 +306,16 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( } const Config* const config(it->second); + const QuicWallTime now = clock->WallNow(); bool valid_source_address_token = false; StringPiece srct; - if (client_hello.GetStringPiece(kSRCT, &srct) && - ValidateSourceAddressToken(srct, client_ip, now_since_unix_epoch)) { + if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct) && + ValidateSourceAddressToken(srct, client_ip, now)) { valid_source_address_token = true; } const string fresh_source_address_token = - NewSourceAddressToken(client_ip, rand, now_since_unix_epoch); + NewSourceAddressToken(client_ip, rand, now); // If we previously sent a REJ to this client then we may have stored a // server nonce in |params|. In which case, we know that the connection @@ -328,14 +336,18 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( strike_register_.reset(new StrikeRegister( // TODO(agl): these magic numbers should come from config. 1024 /* max entries */, - static_cast<uint32>(now_since_unix_epoch.ToSeconds()), + static_cast<uint32>(now.ToUNIXSeconds()), 600 /* window secs */, config->orbit)); } unique_by_strike_register = strike_register_->Insert( reinterpret_cast<const uint8*>(client_nonce.data()), - static_cast<uint32>(now_since_unix_epoch.ToSeconds())); + static_cast<uint32>(now.ToUNIXSeconds())); } + StringPiece server_nonce; + client_hello.GetStringPiece(kServerNonceTag, &server_nonce); + const bool server_nonce_matches = server_nonce == params->server_nonce; + out->Clear(); StringPiece sni; @@ -346,6 +358,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( scid.as_string() != config->id || !valid_source_address_token || !client_nonce_well_formed || + !server_nonce_matches || (!unique_by_strike_register && !unique_by_server_nonce)) { // If the client didn't provide a server config ID, or gave the wrong one, @@ -353,22 +366,20 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( // give the client enough information to do better next time. out->set_tag(kREJ); out->SetStringPiece(kSCFG, config->serialized); - out->SetStringPiece(kSRCT, fresh_source_address_token); + out->SetStringPiece(kSourceAddressTokenTag, fresh_source_address_token); if (params->server_nonce.empty()) { CryptoUtils::GenerateNonce( - now_since_unix_epoch, rand, - StringPiece(reinterpret_cast<const char*>(config->orbit), - sizeof(config->orbit)), + now, rand, StringPiece(reinterpret_cast<const char*>(config->orbit), + sizeof(config->orbit)), ¶ms->server_nonce); } - out->SetStringPiece(kNONC, params->server_nonce); + out->SetStringPiece(kServerNonceTag, params->server_nonce); // The client may have requested a certificate chain. - const CryptoTag* their_proof_demands; + const QuicTag* their_proof_demands; size_t num_their_proof_demands; - if (proof_source_.get() != NULL && - !sni.empty() && + if (proof_source_.get() != NULL && !sni.empty() && client_hello.GetTaglist(kPDMD, &their_proof_demands, &num_their_proof_demands) == QUIC_NO_ERROR) { for (size_t i = 0; i < num_their_proof_demands; i++) { @@ -398,7 +409,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( static const size_t kMaxUnverifiedSize = 400; if (valid_source_address_token || signature.size() + compressed.size() < kMaxUnverifiedSize) { - out->SetStringPiece(kCERT, compressed); + out->SetStringPiece(kCertificateTag, compressed); out->SetStringPiece(kPROF, signature); } break; @@ -408,8 +419,8 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( return QUIC_NO_ERROR; } - const CryptoTag* their_aeads; - const CryptoTag* their_key_exchanges; + const QuicTag* their_aeads; + const QuicTag* their_key_exchanges; size_t num_their_aeads, num_their_key_exchanges; if (client_hello.GetTaglist(kAEAD, &their_aeads, &num_their_aeads) != QUIC_NO_ERROR || @@ -422,16 +433,13 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( } size_t key_exchange_index; - if (!CryptoUtils::FindMutualTag(config->aead, - their_aeads, num_their_aeads, - CryptoUtils::LOCAL_PRIORITY, - ¶ms->aead, + if (!CryptoUtils::FindMutualTag(config->aead, their_aeads, num_their_aeads, + CryptoUtils::LOCAL_PRIORITY, ¶ms->aead, NULL) || - !CryptoUtils::FindMutualTag(config->kexs, - their_key_exchanges, num_their_key_exchanges, - CryptoUtils::LOCAL_PRIORITY, - ¶ms->key_exchange, - &key_exchange_index)) { + !CryptoUtils::FindMutualTag( + config->kexs, their_key_exchanges, num_their_key_exchanges, + CryptoUtils::LOCAL_PRIORITY, ¶ms->key_exchange, + &key_exchange_index)) { *error_details = "Unsupported AEAD or KEXS"; return QUIC_CRYPTO_NO_SUPPORT; } @@ -442,28 +450,67 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; } - if (!config->key_exchanges[key_exchange_index]->CalculateSharedKey( - public_value, ¶ms->premaster_secret)) { + const KeyExchange* key_exchange = config->key_exchanges[key_exchange_index]; + if (!key_exchange->CalculateSharedKey(public_value, + ¶ms->initial_premaster_secret)) { *error_details = "Invalid public value"; return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; } params->server_config_id = scid.as_string(); - string hkdf_input(QuicCryptoConfig::kLabel, - strlen(QuicCryptoConfig::kLabel) + 1); - hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid)); - + string hkdf_suffix; const QuicData& client_hello_serialized = client_hello.GetSerialized(); - hkdf_input.append(client_hello_serialized.data(), - client_hello_serialized.length()); - hkdf_input.append(config->serialized); + hkdf_suffix.reserve(sizeof(guid) + client_hello_serialized.length() + + config->serialized.size()); + hkdf_suffix.append(reinterpret_cast<char*>(&guid), sizeof(guid)); + hkdf_suffix.append(client_hello_serialized.data(), + client_hello_serialized.length()); + hkdf_suffix.append(config->serialized); + + string hkdf_input; + size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; + hkdf_input.reserve(label_len + hkdf_suffix.size()); + hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len); + hkdf_input.append(hkdf_suffix); + + CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead, + client_nonce, params->server_nonce, hkdf_input, + CryptoUtils::SERVER, ¶ms->initial_crypters); + + string forward_secure_public_value; + if (ephemeral_key_source_.get()) { + params->forward_secure_premaster_secret = + ephemeral_key_source_->CalculateForwardSecureKey( + key_exchange, rand, clock->ApproximateNow(), public_value, + &forward_secure_public_value); + } else { + scoped_ptr<KeyExchange> forward_secure_key_exchange( + key_exchange->NewKeyPair(rand)); + forward_secure_public_value = + forward_secure_key_exchange->public_value().as_string(); + if (!forward_secure_key_exchange->CalculateSharedKey( + public_value, ¶ms->forward_secure_premaster_secret)) { + *error_details = "Invalid public value"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + } - CryptoUtils::DeriveKeys(params, client_nonce, hkdf_input, - CryptoUtils::SERVER); + string forward_secure_hkdf_input; + label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1; + forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size()); + forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, + label_len); + forward_secure_hkdf_input.append(hkdf_suffix); + + CryptoUtils::DeriveKeys(params->forward_secure_premaster_secret, params->aead, + client_nonce, params->server_nonce, + forward_secure_hkdf_input, CryptoUtils::SERVER, + ¶ms->forward_secure_crypters); out->set_tag(kSHLO); - out->SetStringPiece(kSRCT, fresh_source_address_token); + out->SetStringPiece(kSourceAddressTokenTag, fresh_source_address_token); + out->SetStringPiece(kPUBS, forward_secure_public_value); return QUIC_NO_ERROR; } @@ -471,19 +518,24 @@ void QuicCryptoServerConfig::SetProofSource(ProofSource* proof_source) { proof_source_.reset(proof_source); } +void QuicCryptoServerConfig::SetEphemeralKeySource( + EphemeralKeySource* ephemeral_key_source) { + ephemeral_key_source_.reset(ephemeral_key_source); +} + string QuicCryptoServerConfig::NewSourceAddressToken( const IPEndPoint& ip, QuicRandom* rand, - QuicTime::Delta now_since_epoch) const { + QuicWallTime now) const { SourceAddressToken source_address_token; source_address_token.set_ip(ip.ToString()); - source_address_token.set_timestamp(now_since_epoch.ToSeconds()); + source_address_token.set_timestamp(now.ToUNIXSeconds()); string plaintext = source_address_token.SerializeAsString(); char nonce[12]; DCHECK_EQ(sizeof(nonce), - source_address_token_encrypter_->GetNoncePrefixSize() + - sizeof(QuicPacketSequenceNumber)); + source_address_token_encrypter_->GetNoncePrefixSize() + + sizeof(QuicPacketSequenceNumber)); rand->RandBytes(nonce, sizeof(nonce)); size_t ciphertext_size = @@ -493,8 +545,8 @@ string QuicCryptoServerConfig::NewSourceAddressToken( 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)]))) { + StringPiece(nonce, sizeof(nonce)), StringPiece(), plaintext, + reinterpret_cast<unsigned char*>(&result[sizeof(nonce)]))) { DCHECK(false); return string(); } @@ -505,11 +557,11 @@ string QuicCryptoServerConfig::NewSourceAddressToken( bool QuicCryptoServerConfig::ValidateSourceAddressToken( StringPiece token, const IPEndPoint& ip, - QuicTime::Delta now_since_epoch) const { + QuicWallTime now) const { char nonce[12]; DCHECK_EQ(sizeof(nonce), - source_address_token_encrypter_->GetNoncePrefixSize() + - sizeof(QuicPacketSequenceNumber)); + source_address_token_encrypter_->GetNoncePrefixSize() + + sizeof(QuicPacketSequenceNumber)); if (token.size() <= sizeof(nonce)) { return false; @@ -529,8 +581,8 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken( size_t plaintext_length; if (!source_address_token_decrypter_->Decrypt( - StringPiece(nonce, sizeof(nonce)), StringPiece(), token, - plaintext, &plaintext_length)) { + StringPiece(nonce, sizeof(nonce)), StringPiece(), token, plaintext, + &plaintext_length)) { return false; } @@ -544,18 +596,18 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken( return false; } - const QuicTime::Delta delta(now_since_epoch.Subtract( - QuicTime::Delta::FromSeconds(source_address_token.timestamp()))); - const int64 delta_secs = delta.ToSeconds(); + const QuicWallTime timestamp( + QuicWallTime::FromUNIXSeconds(source_address_token.timestamp())); + const QuicTime::Delta delta(now.AbsoluteDifference(timestamp)); // TODO(agl): consider whether and how these magic values should be moved to // a config. - if (delta_secs < -3600) { + if (now.IsBefore(timestamp) && delta.ToSeconds() > 3600) { // We only allow timestamps to be from an hour in the future. return false; } - if (delta_secs > 86400) { + if (now.IsAfter(timestamp) && delta.ToSeconds() > 86400) { // We allow one day into the past. return false; } @@ -563,11 +615,8 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken( return true; } -QuicCryptoServerConfig::Config::Config() { -} +QuicCryptoServerConfig::Config::Config() {} -QuicCryptoServerConfig::Config::~Config() { - STLDeleteElements(&key_exchanges); -} +QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); } } // namespace net diff --git a/net/quic/crypto/crypto_server_config.h b/net/quic/crypto/crypto_server_config.h index 4986603..588d83d4 100644 --- a/net/quic/crypto/crypto_server_config.h +++ b/net/quic/crypto/crypto_server_config.h @@ -16,6 +16,7 @@ namespace net { +class EphemeralKeySource; class KeyExchange; class ProofSource; class QuicClock; @@ -36,6 +37,12 @@ class QuicCryptoServerConfigPeer; // need to consider locking. class NET_EXPORT_PRIVATE QuicCryptoServerConfig { public: + enum { + // kDefaultExpiry can be passed to DefaultConfig to select the default + // expiry time. + kDefaultExpiry = 0, + }; + // |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. In tests, use TESTING. @@ -46,25 +53,29 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { // TESTING is a magic parameter for passing to the constructor in tests. static const char TESTING[]; - // DefaultConfig generates a QuicServerConfigProtobuf protobuf suitable - // for using in tests. |extra_tags| contains additional key/value pairs that - // will be inserted into the config. + // DefaultConfig generates a QuicServerConfigProtobuf protobuf suitable for + // using in tests. |extra_tags| contains additional key/value pairs that will + // be inserted into the config. If |expiry_time| is non-zero then it's used + // as the expiry for the server config in UNIX epoch seconds. Otherwise the + // default expiry time is six months from now. static QuicServerConfigProtobuf* DefaultConfig( QuicRandom* rand, const QuicClock* clock, - const CryptoHandshakeMessage& extra_tags); + const CryptoHandshakeMessage& extra_tags, + uint64 expiry_time); // AddConfig adds a QuicServerConfigProtobuf to the availible configurations. // It returns the SCFG message from the config if successful. The caller // takes ownership of the CryptoHandshakeMessage. CryptoHandshakeMessage* AddConfig(QuicServerConfigProtobuf* protobuf); - // AddDefaultConfig creates a config and then calls AddConfig to - // add it. Any tags in |extra_tags| will be copied into the config. + // AddDefaultConfig creates a config and then calls AddConfig to add it. See + // the comment for |DefaultConfig| for details of the arguments. CryptoHandshakeMessage* AddDefaultConfig( QuicRandom* rand, const QuicClock* clock, - const CryptoHandshakeMessage& extra_tags); + const CryptoHandshakeMessage& extra_tags, + uint64 expiry_time); // ProcessClientHello processes |client_hello| and decides whether to accept // or reject the connection. If the connection is to be accepted, |out| is @@ -76,8 +87,7 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { // 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. + // clock: used to validate client nonces and ephemeral keys. // rand: an entropy source // params: the state of the handshake. This may be updated with a server // nonce when we send a rejection. After a successful handshake, this will @@ -87,7 +97,7 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { QuicErrorCode ProcessClientHello(const CryptoHandshakeMessage& client_hello, QuicGuid guid, const IPEndPoint& client_ip, - QuicTime::Delta now_since_epoch, + const QuicClock* now, QuicRandom* rand, QuicCryptoNegotiatedParameters* params, CryptoHandshakeMessage* out, @@ -97,6 +107,12 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { // This object takes ownership of |proof_source|. void SetProofSource(ProofSource* proof_source); + // SetEphemeralKeySource installs an object that can cache ephemeral keys for + // a short period of time. This object takes ownership of + // |ephemeral_key_source|. If not set then ephemeral keys will be generated + // per-connection. + void SetEphemeralKeySource(EphemeralKeySource* ephemeral_key_source); + private: friend class test::QuicCryptoServerConfigPeer; @@ -121,7 +137,7 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { std::vector<KeyExchange*> key_exchanges; // tag_value_map contains the raw key/value pairs for the config. - CryptoTagValueMap tag_value_map; + QuicTagValueMap tag_value_map; private: DISALLOW_COPY_AND_ASSIGN(Config); @@ -131,14 +147,14 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { // IP address. std::string NewSourceAddressToken(const IPEndPoint& ip, QuicRandom* rand, - QuicTime::Delta now_since_epoch) const; + QuicWallTime now) const; // 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) const; + QuicWallTime now) const; std::map<ServerConfigID, Config*> configs_; @@ -157,6 +173,10 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { // proof_source_ contains an object that can provide certificate chains and // signatures. scoped_ptr<ProofSource> proof_source_; + + // ephemeral_key_source_ contains an object that caches ephemeral keys for a + // short period of time. + scoped_ptr<EphemeralKeySource> ephemeral_key_source_; }; } // namespace net diff --git a/net/quic/crypto/crypto_server_config_protobuf.h b/net/quic/crypto/crypto_server_config_protobuf.h index a4ef81b..62b7b6f 100644 --- a/net/quic/crypto/crypto_server_config_protobuf.h +++ b/net/quic/crypto/crypto_server_config_protobuf.h @@ -19,10 +19,10 @@ class QuicServerConfigProtobuf { public: class PrivateKey { public: - CryptoTag tag() const { + QuicTag tag() const { return tag_; } - void set_tag(CryptoTag tag) { + void set_tag(QuicTag tag) { tag_ = tag; } std::string private_key() const { @@ -33,7 +33,7 @@ class QuicServerConfigProtobuf { } private: - CryptoTag tag_; + QuicTag tag_; std::string private_key_; }; diff --git a/net/quic/crypto/crypto_utils.cc b/net/quic/crypto/crypto_utils.cc index e7a2376..bf1f4d2 100644 --- a/net/quic/crypto/crypto_utils.cc +++ b/net/quic/crypto/crypto_utils.cc @@ -18,21 +18,21 @@ using std::string; namespace net { // static -bool CryptoUtils::FindMutualTag(const CryptoTagVector& our_tags_vector, - const CryptoTag* their_tags, +bool CryptoUtils::FindMutualTag(const QuicTagVector& our_tags_vector, + const QuicTag* their_tags, size_t num_their_tags, Priority priority, - CryptoTag* out_result, + QuicTag* out_result, size_t* out_index) { if (our_tags_vector.empty()) { return false; } const size_t num_our_tags = our_tags_vector.size(); - const CryptoTag* our_tags = &our_tags_vector[0]; + const QuicTag* our_tags = &our_tags_vector[0]; size_t num_priority_tags, num_inferior_tags; - const CryptoTag* priority_tags; - const CryptoTag* inferior_tags; + const QuicTag* priority_tags; + const QuicTag* inferior_tags; if (priority == LOCAL_PRIORITY) { num_priority_tags = num_our_tags; priority_tags = our_tags; @@ -64,14 +64,14 @@ bool CryptoUtils::FindMutualTag(const CryptoTagVector& our_tags_vector, return false; } -void CryptoUtils::GenerateNonce(QuicTime::Delta now, +void CryptoUtils::GenerateNonce(QuicWallTime now, QuicRandom* random_generator, StringPiece orbit, string* nonce) { // a 4-byte timestamp + 28 random bytes. nonce->reserve(kNonceSize); nonce->resize(kNonceSize); - uint32 gmt_unix_time = now.ToSeconds(); + uint32 gmt_unix_time = now.ToUNIXSeconds(); // The time in the nonce must be encoded in big-endian because the // strike-register depends on the nonces being ordered by time. (*nonce)[0] = static_cast<char>(gmt_unix_time >> 24); @@ -88,34 +88,37 @@ void CryptoUtils::GenerateNonce(QuicTime::Delta now, kNonceSize - bytes_written); } -void CryptoUtils::DeriveKeys(QuicCryptoNegotiatedParameters* params, +void CryptoUtils::DeriveKeys(StringPiece premaster_secret, + QuicTag aead, StringPiece client_nonce, + StringPiece server_nonce, const string& hkdf_input, - Perspective perspective) { - params->encrypter.reset(QuicEncrypter::Create(params->aead)); - params->decrypter.reset(QuicDecrypter::Create(params->aead)); - size_t key_bytes = params->encrypter->GetKeySize(); - size_t nonce_prefix_bytes = params->encrypter->GetNoncePrefixSize(); + Perspective perspective, + CrypterPair* out) { + out->encrypter.reset(QuicEncrypter::Create(aead)); + out->decrypter.reset(QuicDecrypter::Create(aead)); + size_t key_bytes = out->encrypter->GetKeySize(); + size_t nonce_prefix_bytes = out->encrypter->GetNoncePrefixSize(); StringPiece nonce = client_nonce; string nonce_storage; - if (!params->server_nonce.empty()) { - nonce_storage = client_nonce.as_string() + params->server_nonce; + if (!server_nonce.empty()) { + nonce_storage = client_nonce.as_string() + server_nonce.as_string(); nonce = nonce_storage; } - crypto::HKDF hkdf(params->premaster_secret, nonce, - hkdf_input, key_bytes, nonce_prefix_bytes); + crypto::HKDF hkdf(premaster_secret, nonce, hkdf_input, key_bytes, + nonce_prefix_bytes); if (perspective == SERVER) { - params->encrypter->SetKey(hkdf.server_write_key()); - params->encrypter->SetNoncePrefix(hkdf.server_write_iv()); - params->decrypter->SetKey(hkdf.client_write_key()); - params->decrypter->SetNoncePrefix(hkdf.client_write_iv()); + out->encrypter->SetKey(hkdf.server_write_key()); + out->encrypter->SetNoncePrefix(hkdf.server_write_iv()); + out->decrypter->SetKey(hkdf.client_write_key()); + out->decrypter->SetNoncePrefix(hkdf.client_write_iv()); } else { - params->encrypter->SetKey(hkdf.client_write_key()); - params->encrypter->SetNoncePrefix(hkdf.client_write_iv()); - params->decrypter->SetKey(hkdf.server_write_key()); - params->decrypter->SetNoncePrefix(hkdf.server_write_iv()); + out->encrypter->SetKey(hkdf.client_write_key()); + out->encrypter->SetNoncePrefix(hkdf.client_write_iv()); + out->decrypter->SetKey(hkdf.server_write_key()); + out->decrypter->SetNoncePrefix(hkdf.server_write_iv()); } } diff --git a/net/quic/crypto/crypto_utils.h b/net/quic/crypto/crypto_utils.h index 4ad4149..6c607a5 100644 --- a/net/quic/crypto/crypto_utils.h +++ b/net/quic/crypto/crypto_utils.h @@ -13,6 +13,7 @@ #include "net/base/net_export.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/quic_time.h" namespace net { @@ -40,32 +41,35 @@ class NET_EXPORT_PRIVATE CryptoUtils { // // If |out_index| is non-NULL and a match is found then the index of that // match in |their_tags| is written to |out_index|. - static bool FindMutualTag(const CryptoTagVector& our_tags, - const CryptoTag* their_tags, + static bool FindMutualTag(const QuicTagVector& our_tags, + const QuicTag* their_tags, size_t num_their_tags, Priority priority, - CryptoTag* out_result, + QuicTag* out_result, size_t* out_index); // Generates the connection nonce. The nonce is formed as: // <4 bytes> current time // <8 bytes> |orbit| (or random if |orbit| is empty) // <20 bytes> random - static void GenerateNonce(QuicTime::Delta now, + static void GenerateNonce(QuicWallTime now, QuicRandom* random_generator, base::StringPiece orbit, std::string* nonce); - // DeriveKeys populates |params->encrypter| and |params->decrypter| given the - // contents of |params->premaster_secret|, |client_nonce|, - // |params->server_nonce| and |hkdf_input|. |perspective| controls whether - // the server's keys are assigned to |encrypter| or |decrypter|. - // |params->server_nonce| is optional and, if non-empty, is mixed into the - // key derivation. - static void DeriveKeys(QuicCryptoNegotiatedParameters* params, + // DeriveKeys populates |out->encrypter| and |out->decrypter| given the + // contents of |premaster_secret|, |client_nonce|, |server_nonce| and + // |hkdf_input|. |aead| determines which cipher will be used. |perspective| + // controls whether the server's keys are assigned to |encrypter| or + // |decrypter|. |server_nonce| is optional and, if non-empty, is mixed into + // the key derivation. + static void DeriveKeys(base::StringPiece premaster_secret, + QuicTag aead, base::StringPiece client_nonce, + base::StringPiece server_nonce, const std::string& hkdf_input, - Perspective perspective); + Perspective perspective, + CrypterPair* out); }; } // namespace net diff --git a/net/quic/crypto/curve25519_key_exchange.cc b/net/quic/crypto/curve25519_key_exchange.cc index a4c20fa..3b888045 100644 --- a/net/quic/crypto/curve25519_key_exchange.cc +++ b/net/quic/crypto/curve25519_key_exchange.cc @@ -13,11 +13,9 @@ using std::string; namespace net { -Curve25519KeyExchange::Curve25519KeyExchange() { -} +Curve25519KeyExchange::Curve25519KeyExchange() {} -Curve25519KeyExchange::~Curve25519KeyExchange() { -} +Curve25519KeyExchange::~Curve25519KeyExchange() {} // static Curve25519KeyExchange* Curve25519KeyExchange::New( @@ -29,9 +27,8 @@ Curve25519KeyExchange* Curve25519KeyExchange::New( COMPILE_ASSERT( sizeof(ka->private_key_) == crypto::curve25519::kScalarBytes, header_out_of_sync); - COMPILE_ASSERT( - sizeof(ka->public_key_) == crypto::curve25519::kBytes, - header_out_of_sync); + COMPILE_ASSERT(sizeof(ka->public_key_) == crypto::curve25519::kBytes, + header_out_of_sync); if (private_key.size() != crypto::curve25519::kScalarBytes) { return NULL; @@ -57,6 +54,11 @@ string Curve25519KeyExchange::NewPrivateKey(QuicRandom* rand) { return string(reinterpret_cast<char*>(private_key), sizeof(private_key)); } +KeyExchange* Curve25519KeyExchange::NewKeyPair(QuicRandom* rand) const { + const string private_value = NewPrivateKey(rand); + return Curve25519KeyExchange::New(private_value); +} + bool Curve25519KeyExchange::CalculateSharedKey( const StringPiece& peer_public_value, string* out_result) const { @@ -79,8 +81,6 @@ StringPiece Curve25519KeyExchange::public_value() const { sizeof(public_key_)); } -CryptoTag Curve25519KeyExchange::tag() const { - return kC255; -} +QuicTag Curve25519KeyExchange::tag() const { return kC255; } } // namespace net diff --git a/net/quic/crypto/curve25519_key_exchange.h b/net/quic/crypto/curve25519_key_exchange.h index 73cf741..ecc0880 100644 --- a/net/quic/crypto/curve25519_key_exchange.h +++ b/net/quic/crypto/curve25519_key_exchange.h @@ -31,10 +31,11 @@ class NET_EXPORT_PRIVATE Curve25519KeyExchange : public KeyExchange { static std::string NewPrivateKey(QuicRandom* rand); // KeyExchange interface. + virtual KeyExchange* NewKeyPair(QuicRandom* rand) const OVERRIDE; virtual bool CalculateSharedKey(const base::StringPiece& peer_public_value, std::string* shared_key) const OVERRIDE; virtual base::StringPiece public_value() const OVERRIDE; - virtual CryptoTag tag() const OVERRIDE; + virtual QuicTag tag() const OVERRIDE; private: Curve25519KeyExchange(); diff --git a/net/quic/crypto/curve25519_key_exchange_test.cc b/net/quic/crypto/curve25519_key_exchange_test.cc index 83ddcfb..93ef630 100644 --- a/net/quic/crypto/curve25519_key_exchange_test.cc +++ b/net/quic/crypto/curve25519_key_exchange_test.cc @@ -24,10 +24,9 @@ TEST(Curve25519KeyExchange, SharedKey) { const string alice_key(Curve25519KeyExchange::NewPrivateKey(rand)); const string bob_key(Curve25519KeyExchange::NewPrivateKey(rand)); - scoped_ptr<Curve25519KeyExchange> alice(Curve25519KeyExchange::New( - alice_key)); - scoped_ptr<Curve25519KeyExchange> bob(Curve25519KeyExchange::New( - bob_key)); + scoped_ptr<Curve25519KeyExchange> alice( + Curve25519KeyExchange::New(alice_key)); + scoped_ptr<Curve25519KeyExchange> bob(Curve25519KeyExchange::New(bob_key)); const StringPiece alice_public(alice->public_value()); const StringPiece bob_public(bob->public_value()); diff --git a/net/quic/crypto/ephemeral_key_source.h b/net/quic/crypto/ephemeral_key_source.h new file mode 100644 index 0000000..2700be0 --- /dev/null +++ b/net/quic/crypto/ephemeral_key_source.h @@ -0,0 +1,42 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_CRYPTO_EPHEMERAL_KEY_SOURCE_H_ +#define NET_QUIC_CRYPTO_EPHEMERAL_KEY_SOURCE_H_ + +#include <string> + +#include "base/strings/string_piece.h" +#include "net/base/net_export.h" +#include "net/quic/quic_time.h" + +namespace net { + +class KeyExchange; +class QuicRandom; + +// EphemeralKeySource manages and rotates ephemeral keys as they can be reused +// for several connections in a short space of time. Since the implementation +// of this may involve locking or thread-local data, this interface abstracts +// that away. +class NET_EXPORT_PRIVATE EphemeralKeySource { + public: + virtual ~EphemeralKeySource() {} + + // CalculateForwardSecureKey generates an ephemeral public/private key pair + // using the algorithm |key_exchange|, sets |*public_value| to the public key + // and returns the shared key between |peer_public_value| and the private + // key. |*public_value| will be sent to the peer to be used with the peer's + // private key. + virtual std::string CalculateForwardSecureKey( + const KeyExchange* key_exchange, + QuicRandom* rand, + QuicTime now, + base::StringPiece peer_public_value, + std::string* public_value) = 0; +}; + +} // namespace net + +#endif // NET_QUIC_CRYPTO_EPHEMERAL_KEY_SOURCE_H_ diff --git a/net/quic/crypto/key_exchange.h b/net/quic/crypto/key_exchange.h index 4f043bd..8690f0e 100644 --- a/net/quic/crypto/key_exchange.h +++ b/net/quic/crypto/key_exchange.h @@ -13,11 +13,18 @@ namespace net { +class QuicRandom; + // KeyExchange is an abstract class that provides an interface to a // key-exchange primitive. class NET_EXPORT_PRIVATE KeyExchange { public: - virtual ~KeyExchange() { } + virtual ~KeyExchange() {} + + // NewKeyPair generates a new public, private key pair. The caller takes + // ownership of the return value. (This is intended for servers that need to + // generate forward-secure keys.) + virtual KeyExchange* NewKeyPair(QuicRandom* rand) const = 0; // CalculateSharedKey computes the shared key between the local private key // (which is implicitly known by a KeyExchange object) and a public value @@ -32,7 +39,7 @@ class NET_EXPORT_PRIVATE KeyExchange { virtual base::StringPiece public_value() const = 0; // tag returns the tag value that identifies this key exchange function. - virtual CryptoTag tag() const = 0; + virtual QuicTag tag() const = 0; }; } // namespace net diff --git a/net/quic/crypto/null_decrypter.cc b/net/quic/crypto/null_decrypter.cc index 0875558..7bda75f 100644 --- a/net/quic/crypto/null_decrypter.cc +++ b/net/quic/crypto/null_decrypter.cc @@ -11,9 +11,7 @@ using std::string; namespace net { -bool NullDecrypter::SetKey(StringPiece key) { - return key.empty(); -} +bool NullDecrypter::SetKey(StringPiece key) { return key.empty(); } bool NullDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { return nonce_prefix.empty(); @@ -69,12 +67,8 @@ QuicData* NullDecrypter::DecryptPacket(QuicPacketSequenceNumber /*seq_number*/, return new QuicData(plaintext.data(), plaintext.length()); } -StringPiece NullDecrypter::GetKey() const { - return StringPiece(); -} +StringPiece NullDecrypter::GetKey() const { return StringPiece(); } -StringPiece NullDecrypter::GetNoncePrefix() const { - return StringPiece(); -} +StringPiece NullDecrypter::GetNoncePrefix() const { return StringPiece(); } } // namespace net diff --git a/net/quic/crypto/null_decrypter_test.cc b/net/quic/crypto/null_decrypter_test.cc index 7854b04..e9b9647 100644 --- a/net/quic/crypto/null_decrypter_test.cc +++ b/net/quic/crypto/null_decrypter_test.cc @@ -22,11 +22,9 @@ TEST(NullDecrypterTest, Decrypt) { 'b', 'y', 'e', '!', }; NullDecrypter decrypter; - scoped_ptr<QuicData> decrypted( - decrypter.DecryptPacket( - 0, "hello world!", - StringPiece(reinterpret_cast<const char*>(expected), - arraysize(expected)))); + scoped_ptr<QuicData> decrypted(decrypter.DecryptPacket( + 0, "hello world!", StringPiece(reinterpret_cast<const char*>(expected), + arraysize(expected)))); ASSERT_TRUE(decrypted.get()); EXPECT_EQ("goodbye!", decrypted->AsStringPiece()); } @@ -43,11 +41,9 @@ TEST(NullDecrypterTest, BadHash) { 'b', 'y', 'e', '!', }; NullDecrypter decrypter; - scoped_ptr<QuicData> decrypted( - decrypter.DecryptPacket( - 0, "hello world!", - StringPiece(reinterpret_cast<const char*>(expected), - arraysize(expected)))); + scoped_ptr<QuicData> decrypted(decrypter.DecryptPacket( + 0, "hello world!", StringPiece(reinterpret_cast<const char*>(expected), + arraysize(expected)))); ASSERT_FALSE(decrypted.get()); } @@ -60,11 +56,9 @@ TEST(NullDecrypterTest, ShortInput) { 0x88, 0x79, 0xca, }; NullDecrypter decrypter; - scoped_ptr<QuicData> decrypted( - decrypter.DecryptPacket( - 0, "hello world!", - StringPiece(reinterpret_cast<const char*>(expected), - arraysize(expected)))); + scoped_ptr<QuicData> decrypted(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 d8bb6df..a0a680d 100644 --- a/net/quic/crypto/null_encrypter.cc +++ b/net/quic/crypto/null_encrypter.cc @@ -13,9 +13,7 @@ namespace net { const size_t kHashSize = 16; // size of uint128 serialized -bool NullEncrypter::SetKey(StringPiece key) { - return key.empty(); -} +bool NullEncrypter::SetKey(StringPiece key) { return key.empty(); } bool NullEncrypter::SetNoncePrefix(StringPiece nonce_prefix) { return nonce_prefix.empty(); @@ -44,13 +42,9 @@ QuicData* NullEncrypter::EncryptPacket( return new QuicData(reinterpret_cast<char*>(buffer), len, true); } -size_t NullEncrypter::GetKeySize() const { - return 0; -} +size_t NullEncrypter::GetKeySize() const { return 0; } -size_t NullEncrypter::GetNoncePrefixSize() const { - return 0; -} +size_t NullEncrypter::GetNoncePrefixSize() const { return 0; } size_t NullEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { return ciphertext_size - kHashSize; @@ -60,12 +54,8 @@ size_t NullEncrypter::GetCiphertextSize(size_t plaintext_size) const { return plaintext_size + kHashSize; } -StringPiece NullEncrypter::GetKey() const { - return StringPiece(); -} +StringPiece NullEncrypter::GetKey() const { return StringPiece(); } -StringPiece NullEncrypter::GetNoncePrefix() const { - return StringPiece(); -} +StringPiece NullEncrypter::GetNoncePrefix() const { return StringPiece(); } } // namespace net diff --git a/net/quic/crypto/null_encrypter_test.cc b/net/quic/crypto/null_encrypter_test.cc index e1e6834..4c00f91 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.EncryptPacket(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.h b/net/quic/crypto/p256_key_exchange.h index f30d292..8145cc0 100644 --- a/net/quic/crypto/p256_key_exchange.h +++ b/net/quic/crypto/p256_key_exchange.h @@ -40,10 +40,11 @@ class NET_EXPORT_PRIVATE P256KeyExchange : public KeyExchange { static std::string NewPrivateKey(); // KeyExchange interface. + virtual KeyExchange* NewKeyPair(QuicRandom* rand) const OVERRIDE; virtual bool CalculateSharedKey(const base::StringPiece& peer_public_value, std::string* shared_key) const OVERRIDE; virtual base::StringPiece public_value() const OVERRIDE; - virtual CryptoTag tag() const OVERRIDE; + virtual QuicTag tag() const OVERRIDE; private: enum { diff --git a/net/quic/crypto/p256_key_exchange_nss.cc b/net/quic/crypto/p256_key_exchange_nss.cc index c1de42e..dede5ba 100644 --- a/net/quic/crypto/p256_key_exchange_nss.cc +++ b/net/quic/crypto/p256_key_exchange_nss.cc @@ -149,9 +149,14 @@ string P256KeyExchange::NewPrivateKey() { return string(&result[0], result_size); } -bool P256KeyExchange::CalculateSharedKey( - const StringPiece& peer_public_value, - string* out_result) const { +KeyExchange* P256KeyExchange::NewKeyPair(QuicRandom* /*rand*/) const { + // TODO(agl): avoid the serialisation/deserialisation in this function. + const string private_value = NewPrivateKey(); + return P256KeyExchange::New(private_value); +} + +bool P256KeyExchange::CalculateSharedKey(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."; @@ -222,9 +227,7 @@ StringPiece P256KeyExchange::public_value() const { sizeof(public_key_)); } -CryptoTag P256KeyExchange::tag() const { - return kP256; -} +QuicTag P256KeyExchange::tag() const { return kP256; } } // namespace net diff --git a/net/quic/crypto/p256_key_exchange_openssl.cc b/net/quic/crypto/p256_key_exchange_openssl.cc index 051adcf..6eaa981 100644 --- a/net/quic/crypto/p256_key_exchange_openssl.cc +++ b/net/quic/crypto/p256_key_exchange_openssl.cc @@ -20,8 +20,7 @@ P256KeyExchange::P256KeyExchange(EC_KEY* private_key, const uint8* public_key) memcpy(public_key_, public_key, sizeof(public_key_)); } -P256KeyExchange::~P256KeyExchange() { -} +P256KeyExchange::~P256KeyExchange() {} // static P256KeyExchange* P256KeyExchange::New(StringPiece key) { @@ -39,13 +38,10 @@ P256KeyExchange* P256KeyExchange::New(StringPiece key) { } 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)) { + 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."; return NULL; } @@ -76,34 +72,34 @@ string P256KeyExchange::NewPrivateKey() { return string(reinterpret_cast<char*>(private_key.get()), key_len); } -bool P256KeyExchange::CalculateSharedKey( - const StringPiece& peer_public_value, - string* out_result) const { +KeyExchange* P256KeyExchange::NewKeyPair(QuicRandom* /*rand*/) const { + // TODO(agl): avoid the serialisation/deserialisation in this function. + const string private_value = NewPrivateKey(); + return P256KeyExchange::New(private_value); +} + +bool P256KeyExchange::CalculateSharedKey(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()), point.get(), reinterpret_cast<const uint8*>(peer_public_value.data()), - peer_public_value.size(), - NULL)) { + peer_public_value.size(), NULL)) { DLOG(INFO) << "Can't convert peer public value to curve point."; return false; } uint8 result[kP256FieldBytes]; - if (ECDH_compute_key( - result, - sizeof(result), - point.get(), - private_key_.get(), - NULL) != sizeof(result)) { + if (ECDH_compute_key(result, sizeof(result), point.get(), private_key_.get(), + NULL) != sizeof(result)) { DLOG(INFO) << "Can't compute ECDH shared key."; return false; } @@ -117,9 +113,7 @@ StringPiece P256KeyExchange::public_value() const { sizeof(public_key_)); } -CryptoTag P256KeyExchange::tag() const { - return kP256; -} +QuicTag P256KeyExchange::tag() const { return kP256; } } // namespace net diff --git a/net/quic/crypto/quic_decrypter.cc b/net/quic/crypto/quic_decrypter.cc index 3c0e660..2eafdc3 100644 --- a/net/quic/crypto/quic_decrypter.cc +++ b/net/quic/crypto/quic_decrypter.cc @@ -10,7 +10,7 @@ namespace net { // static -QuicDecrypter* QuicDecrypter::Create(CryptoTag algorithm) { +QuicDecrypter* QuicDecrypter::Create(QuicTag algorithm) { switch (algorithm) { case kAESG: return new Aes128GcmDecrypter(); diff --git a/net/quic/crypto/quic_decrypter.h b/net/quic/crypto/quic_decrypter.h index 349425a..124d98f 100644 --- a/net/quic/crypto/quic_decrypter.h +++ b/net/quic/crypto/quic_decrypter.h @@ -15,7 +15,7 @@ class NET_EXPORT_PRIVATE QuicDecrypter { public: virtual ~QuicDecrypter() {} - static QuicDecrypter* Create(CryptoTag algorithm); + static QuicDecrypter* Create(QuicTag algorithm); // Sets the encryption key. Returns true on success, false on failure. // diff --git a/net/quic/crypto/quic_encrypter.cc b/net/quic/crypto/quic_encrypter.cc index a84530f..2e2b83d 100644 --- a/net/quic/crypto/quic_encrypter.cc +++ b/net/quic/crypto/quic_encrypter.cc @@ -10,7 +10,7 @@ namespace net { // static -QuicEncrypter* QuicEncrypter::Create(CryptoTag algorithm) { +QuicEncrypter* QuicEncrypter::Create(QuicTag algorithm) { switch (algorithm) { case kAESG: return new Aes128GcmEncrypter(); diff --git a/net/quic/crypto/quic_encrypter.h b/net/quic/crypto/quic_encrypter.h index 86d0e3a..edddf36 100644 --- a/net/quic/crypto/quic_encrypter.h +++ b/net/quic/crypto/quic_encrypter.h @@ -15,7 +15,7 @@ class NET_EXPORT_PRIVATE QuicEncrypter { public: virtual ~QuicEncrypter() {} - static QuicEncrypter* Create(CryptoTag algorithm); + static QuicEncrypter* Create(QuicTag algorithm); // Sets the encryption key. Returns true on success, false on failure. // diff --git a/net/quic/crypto/quic_random.cc b/net/quic/crypto/quic_random.cc index be1f3c0..c96f01a 100644 --- a/net/quic/crypto/quic_random.cc +++ b/net/quic/crypto/quic_random.cc @@ -61,8 +61,6 @@ DefaultRandom::DefaultRandom() { } // namespace // static -QuicRandom* QuicRandom::GetInstance() { - return DefaultRandom::GetInstance(); -} +QuicRandom* QuicRandom::GetInstance() { return DefaultRandom::GetInstance(); } } // namespace net diff --git a/net/quic/crypto/scoped_evp_cipher_ctx.h b/net/quic/crypto/scoped_evp_cipher_ctx.h index a241eea..8741c3e 100644 --- a/net/quic/crypto/scoped_evp_cipher_ctx.h +++ b/net/quic/crypto/scoped_evp_cipher_ctx.h @@ -18,9 +18,7 @@ namespace net { // functions. class ScopedEVPCipherCtx { public: - ScopedEVPCipherCtx() { - EVP_CIPHER_CTX_init(&ctx_); - } + ScopedEVPCipherCtx() { EVP_CIPHER_CTX_init(&ctx_); } ~ScopedEVPCipherCtx() { int rv = EVP_CIPHER_CTX_cleanup(&ctx_); diff --git a/net/quic/crypto/strike_register.cc b/net/quic/crypto/strike_register.cc index 565d5c8..95f358c 100644 --- a/net/quic/crypto/strike_register.cc +++ b/net/quic/crypto/strike_register.cc @@ -37,25 +37,15 @@ class StrikeRegister::InternalNode { data_[1] |= otherbits; } - void SetNextPtr(uint32 next) { - data_[0] = next; - } + void SetNextPtr(uint32 next) { data_[0] = next; } - uint32 next() const { - return data_[0]; - } + uint32 next() const { return data_[0]; } - uint32 child(unsigned n) const { - return data_[n] >> 8; - } + uint32 child(unsigned n) const { return data_[n] >> 8; } - uint8 critbyte() const { - return data_[0]; - } + uint8 critbyte() const { return data_[0]; } - uint8 otherbits() const { - return data_[1]; - } + uint8 otherbits() const { return data_[1]; } // These bytes are organised thus: // <24 bits> left child @@ -88,9 +78,7 @@ StrikeRegister::StrikeRegister(unsigned max_entries, Reset(); } -StrikeRegister::~StrikeRegister() { - delete[] internal_nodes_; -} +StrikeRegister::~StrikeRegister() { delete[] internal_nodes_; } void StrikeRegister::Reset() { // Thread a free list through all of the internal nodes. @@ -242,7 +230,7 @@ bool StrikeRegister::Insert(const uint8 nonce[32], uint8 c = value[node->critbyte()]; const int direction = - (1 + static_cast<unsigned>(node->otherbits() | c)) >> 8; + (1 + static_cast<unsigned>(node->otherbits() | c)) >> 8; where_index = &node->data_[direction]; } @@ -299,7 +287,7 @@ uint32 StrikeRegister::BestMatch(const uint8 v[24]) const { InternalNode* node = &internal_nodes_[next]; uint8 b = v[node->critbyte()]; unsigned direction = - (1 + static_cast<unsigned>(node->otherbits() | b)) >> 8; + (1 + static_cast<unsigned>(node->otherbits() | b)) >> 8; next = node->child(direction); } @@ -347,7 +335,7 @@ void StrikeRegister::DropNode() { // (whereq) when walking down the tree. uint32 p = internal_node_head_ >> 8, *wherep = &internal_node_head_, - *whereq = NULL; + *whereq = NULL; while ((p & kExternalFlag) == 0) { whereq = wherep; InternalNode* inode = &internal_nodes_[p]; @@ -440,8 +428,8 @@ void StrikeRegister::ValidateTree( CHECK_EQ(used_external_nodes->count(ext), 0u); used_external_nodes->insert(ext); const uint8* bytes = external_node(ext); - for (vector<pair<unsigned, bool> >::const_iterator - i = bits.begin(); i != bits.end(); i++) { + for (vector<pair<unsigned, bool> >::const_iterator i = bits.begin(); + i != bits.end(); i++) { unsigned byte = i->first / 8; DCHECK_LE(byte, 0xffu); unsigned bit = i->first % 8; diff --git a/net/quic/crypto/strike_register_test.cc b/net/quic/crypto/strike_register_test.cc index 4dd479e..d805269 100644 --- a/net/quic/crypto/strike_register_test.cc +++ b/net/quic/crypto/strike_register_test.cc @@ -16,7 +16,7 @@ using net::StrikeRegister; using std::set; using std::string; -const uint8 kOrbit[8] = {1, 2, 3, 4, 5, 6, 7, 8}; +const uint8 kOrbit[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; void NonceSetTimeAndOrbit(uint8 nonce[32], unsigned time, const uint8 orbit[8]) { @@ -54,7 +54,7 @@ TEST(StrikeRegisterTest, BadOrbit) { StrikeRegister set(10 /* max size */, 1000 /* current time */, 100 /* window secs */, kOrbit); uint8 nonce[32]; - static const uint8 kBadOrbit[8] = {0, 0, 0, 0, 1, 1, 1, 1}; + static const uint8 kBadOrbit[8] = { 0, 0, 0, 0, 1, 1, 1, 1 }; NonceSetTimeAndOrbit(nonce, 1101, kBadOrbit); ASSERT_FALSE(set.Insert(nonce, 1100)); } @@ -186,7 +186,7 @@ class SlowStrikeRegister { void DropOldestEntry() { set<string>::iterator oldest = nonces_.begin(), it; uint32 oldest_time = - TimeFromBytes(reinterpret_cast<const uint8*>(oldest->data())); + TimeFromBytes(reinterpret_cast<const uint8*>(oldest->data())); for (it = oldest; it != nonces_.end(); it++) { uint32 t = TimeFromBytes(reinterpret_cast<const uint8*>(it->data())); @@ -214,10 +214,10 @@ TEST(StrikeRegisterStressTest, Stress) { srand(42); unsigned max_entries = 64; uint32 current_time = 10000, window = 200; - scoped_ptr<StrikeRegister> s1(new StrikeRegister( - max_entries, current_time, window, kOrbit)); - scoped_ptr<SlowStrikeRegister> s2(new SlowStrikeRegister( - max_entries, current_time, window, kOrbit)); + scoped_ptr<StrikeRegister> s1( + new StrikeRegister(max_entries, current_time, window, kOrbit)); + scoped_ptr<SlowStrikeRegister> s2( + new SlowStrikeRegister(max_entries, current_time, window, kOrbit)); uint64 i; // When making changes it's worth removing the limit on this test and running @@ -231,8 +231,8 @@ TEST(StrikeRegisterStressTest, Stress) { current_time = rand() % 10000; window = rand() % 500; s1.reset(new StrikeRegister(max_entries, current_time, window, kOrbit)); - s2.reset(new SlowStrikeRegister(max_entries, current_time, window, - kOrbit)); + s2.reset( + new SlowStrikeRegister(max_entries, current_time, window, kOrbit)); } int32 time_delta = rand() % (window * 4); diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc index 8b7bddb..b347dc3 100644 --- a/net/quic/quic_client_session_test.cc +++ b/net/quic/quic_client_session_test.cc @@ -99,7 +99,7 @@ TEST_F(QuicClientSessionTest, GoAwayReceived) { EXPECT_EQ(NULL, session_.CreateOutgoingReliableStream()); } -TEST_F(QuicClientSessionTest, Logging) { +TEST_F(QuicClientSessionTest, DISABLED_Logging) { if (!Aes128GcmEncrypter::IsSupported()) { LOG(INFO) << "AES GCM not supported. Test skipped."; return; diff --git a/net/quic/quic_clock.cc b/net/quic/quic_clock.cc index 26c1a65..6c8dd48 100644 --- a/net/quic/quic_clock.cc +++ b/net/quic/quic_clock.cc @@ -22,8 +22,9 @@ QuicTime QuicClock::Now() const { return QuicTime(base::TimeTicks::Now()); } -QuicTime::Delta QuicClock::NowAsDeltaSinceUnixEpoch() const { - return QuicTime::Delta(base::Time::Now() - base::Time::UnixEpoch()); +QuicWallTime QuicClock::WallNow() const { + return QuicWallTime::FromUNIXSeconds( + base::Time::Now().ToInternalValue() / 1000000); } } // namespace net diff --git a/net/quic/quic_clock.h b/net/quic/quic_clock.h index 6b6cb31..0b3ef4a 100644 --- a/net/quic/quic_clock.h +++ b/net/quic/quic_clock.h @@ -27,10 +27,9 @@ class NET_EXPORT_PRIVATE QuicClock { // Note: this use significant resources please use only if needed. virtual QuicTime Now() const; - // Returns the current time as an offset from the Unix epoch (1970-01-01 - // 00:00:00 GMT). This function may return a smaller Delta in subsequent - // calls if the system clock is changed. - virtual QuicTime::Delta NowAsDeltaSinceUnixEpoch() const; + // WallNow returns the current wall-time - a time is consistent across + // different clocks. + virtual QuicWallTime WallNow() const; }; } // namespace net diff --git a/net/quic/quic_clock_test.cc b/net/quic/quic_clock_test.cc index 1f285942..7b106c1 100644 --- a/net/quic/quic_clock_test.cc +++ b/net/quic/quic_clock_test.cc @@ -20,15 +20,20 @@ TEST(QuicClockTest, Now) { EXPECT_LE(now, end); } -TEST(QuicClockTest, NowAsDeltaSinceUnixEpoch) { +TEST(QuicClockTest, WallNow) { QuicClock clock; - QuicTime::Delta start(base::Time::Now() - base::Time::UnixEpoch()); - QuicTime::Delta now = clock.NowAsDeltaSinceUnixEpoch(); - QuicTime::Delta end(base::Time::Now() - base::Time::UnixEpoch()); - - EXPECT_LE(start, now); - EXPECT_LE(now, end); + base::Time start = base::Time::Now(); + QuicWallTime now = clock.WallNow(); + base::Time end = base::Time::Now(); + + // If end > start, then we can check now is between start and end. + if (end > start) { + EXPECT_LE(static_cast<uint64>(start.ToInternalValue() / 1000000), + now.ToUNIXSeconds()); + EXPECT_LE(now.ToUNIXSeconds(), + static_cast<uint64>(end.ToInternalValue() / 1000000)); + } } } // namespace test diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc index 70e0b45..867cb6d 100644 --- a/net/quic/quic_config.cc +++ b/net/quic/quic_config.cc @@ -29,7 +29,7 @@ void QuicConfig::SetDefaults() { } bool QuicConfig::SetFromHandshakeMessage(const CryptoHandshakeMessage& scfg) { - const CryptoTag* cgst; + const QuicTag* cgst; size_t num_cgst; QuicErrorCode error; @@ -73,7 +73,7 @@ QuicErrorCode QuicConfig::ProcessFinalPeerHandshake( string* error_details) const { DCHECK(error_details != NULL); - const CryptoTag* their_congestion_controls; + const QuicTag* their_congestion_controls; size_t num_their_congestion_controls; QuicErrorCode error; diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h index 17441d7..013a4f2 100644 --- a/net/quic/quic_config.h +++ b/net/quic/quic_config.h @@ -19,7 +19,7 @@ class NET_EXPORT_PRIVATE QuicNegotiatedParameters { public: QuicNegotiatedParameters(); - CryptoTag congestion_control; + QuicTag congestion_control; QuicTime::Delta idle_connection_state_lifetime; QuicTime::Delta keepalive_timeout; }; @@ -31,6 +31,11 @@ class NET_EXPORT_PRIVATE QuicConfig { QuicConfig(); ~QuicConfig(); + void set_idle_connection_state_lifetime( + QuicTime::Delta idle_connection_state_lifetime) { + idle_connection_state_lifetime_ = idle_connection_state_lifetime; + } + // SetDefaults sets the members to sensible, default values. void SetDefaults(); @@ -54,7 +59,7 @@ class NET_EXPORT_PRIVATE QuicConfig { private: // Congestion control feedback type. - CryptoTagVector congestion_control_; + QuicTagVector congestion_control_; // Idle connection state lifetime QuicTime::Delta idle_connection_state_lifetime_; // Keepalive timeout, or 0 to turn off keepalive probes diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 4851d47..481fca9 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -24,10 +24,6 @@ using std::set; using std::string; namespace net { - -// TODO(pwestin): kDefaultTimeoutUs is in int64. -int32 kNegotiatedTimeoutUs = kDefaultTimeoutUs; - namespace { // The largest gap in packets we'll accept without closing the connection. @@ -77,10 +73,10 @@ QuicConnection::QuicConnection(QuicGuid guid, IPEndPoint address, QuicConnectionHelperInterface* helper, bool is_server) - : helper_(helper), - framer_(kQuicVersion1, + : framer_(kQuicVersion1, helper->GetClock()->ApproximateNow(), is_server), + helper_(helper), encryption_level_(ENCRYPTION_NONE), clock_(helper->GetClock()), random_generator_(helper->GetRandomGenerator()), @@ -136,7 +132,7 @@ QuicConnection::~QuicConnection() { } bool QuicConnection::SelectMutualVersion( - const QuicVersionTagList& available_versions) { + const QuicTagVector& available_versions) { // TODO(satyamshekhar): Make this generic. if (std::find(available_versions.begin(), available_versions.end(), kQuicVersion1) == available_versions.end()) { @@ -178,8 +174,7 @@ void QuicConnection::OnPublicResetPacket( CloseConnection(QUIC_PUBLIC_RESET, true); } -bool QuicConnection::OnProtocolVersionMismatch( - QuicVersionTag received_version) { +bool QuicConnection::OnProtocolVersionMismatch(QuicTag received_version) { // TODO(satyamshekhar): Implement no server state in this mode. if (!is_server_) { LOG(DFATAL) << "Framer called OnProtocolVersionMismatch for server. " @@ -680,7 +675,7 @@ void QuicConnection::MaybeSendAckInResponseToPacket() { } void QuicConnection::SendVersionNegotiationPacket() { - QuicVersionTagList supported_versions; + QuicTagVector supported_versions; supported_versions.push_back(kQuicVersion1); QuicEncryptedPacket* encrypted = packet_creator_.SerializeVersionNegotiationPacket(supported_versions); @@ -1294,6 +1289,11 @@ bool QuicConnection::HasQueuedData() const { return !queued_packets_.empty() || packet_generator_.HasQueuedData(); } +void QuicConnection::SetConnectionTimeout(QuicTime::Delta timeout) { + timeout_ = timeout; + CheckForTimeout(); +} + bool QuicConnection::CheckForTimeout() { QuicTime now = clock_->ApproximateNow(); QuicTime time_of_last_packet = std::max(time_of_last_received_packet_, diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 5e916f8..ce3a263 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -93,8 +93,7 @@ class NET_EXPORT_PRIVATE QuicConnectionDebugVisitorInterface { // Called when the protocol version on the received packet doensn't match // current protocol version of the connection. - virtual void OnProtocolVersionMismatch( - QuicVersionTag version) = 0; + virtual void OnProtocolVersionMismatch(QuicTag version) = 0; // Called when the complete header of a packet has been parsed. virtual void OnPacketHeader(const QuicPacketHeader& header) = 0; @@ -258,14 +257,11 @@ class NET_EXPORT_PRIVATE QuicConnection // queued writes to happen. Returns false if the socket has become blocked. virtual bool OnCanWrite() OVERRIDE; - QuicVersionTag version() const { - return quic_version_; - } + QuicTag version() const { return quic_version_; } // From QuicFramerVisitorInterface virtual void OnError(QuicFramer* framer) OVERRIDE; - virtual bool OnProtocolVersionMismatch( - QuicVersionTag received_version) OVERRIDE; + virtual bool OnProtocolVersionMismatch(QuicTag received_version) OVERRIDE; virtual void OnPacket() OVERRIDE; virtual void OnPublicResetPacket( const QuicPublicResetPacket& packet) OVERRIDE; @@ -330,6 +326,10 @@ class NET_EXPORT_PRIVATE QuicConnection // Returns true if the connection has queued packets or frames. bool HasQueuedData() const; + // Sets (or resets) the idle state connection timeout. Also, checks and times + // out the connection if network timer has expired for |timeout|. + void SetConnectionTimeout(QuicTime::Delta timeout); + // If the connection has timed out, this will close the connection and return // true. Otherwise, it will return false and will reset the timeout alarm. bool CheckForTimeout(); @@ -420,6 +420,9 @@ class NET_EXPORT_PRIVATE QuicConnection QuicConnectionHelperInterface* helper() { return helper_.get(); } + protected: + QuicFramer framer_; + private: friend class test::QuicConnectionPeer; @@ -480,8 +483,7 @@ class NET_EXPORT_PRIVATE QuicConnection // Selects and updates the version of the protocol being used by selecting a // version from |available_versions| which is also supported. Returns true if // such a version exists, false otherwise. - bool SelectMutualVersion( - const QuicVersionTagList& available_versions); + bool SelectMutualVersion(const QuicTagVector& available_versions); // Sends a version negotiation packet to the peer. void SendVersionNegotiationPacket(); @@ -508,7 +510,6 @@ class NET_EXPORT_PRIVATE QuicConnection void CloseFecGroupsBefore(QuicPacketSequenceNumber sequence_number); scoped_ptr<QuicConnectionHelperInterface> helper_; - QuicFramer framer_; EncryptionLevel encryption_level_; const QuicClock* clock_; QuicRandom* random_generator_; @@ -580,7 +581,7 @@ class NET_EXPORT_PRIVATE QuicConnection QuicPacketGenerator packet_generator_; // Network idle time before we kill of this connection. - const QuicTime::Delta timeout_; + QuicTime::Delta timeout_; // Statistics for this session. QuicConnectionStats stats_; @@ -603,7 +604,7 @@ class NET_EXPORT_PRIVATE QuicConnection QuicVersionNegotiationState version_negotiation_state_; // The version of the protocol this connection is using. - QuicVersionTag quic_version_; + QuicTag quic_version_; // Tracks if the connection was created by the server. bool is_server_; diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc index 3576981..0c81722 100644 --- a/net/quic/quic_connection_helper_test.cc +++ b/net/quic/quic_connection_helper_test.cc @@ -372,11 +372,11 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) { Initialize(); EXPECT_TRUE(connection_->connected()); - EXPECT_EQ(0u, clock_.NowAsDeltaSinceUnixEpoch().ToMicroseconds()); + QuicTime start = clock_.ApproximateNow(); // When we send a packet, the timeout will change to 5000 + kDefaultTimeout. clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(5000)); - EXPECT_EQ(5000u, clock_.NowAsDeltaSinceUnixEpoch().ToMicroseconds()); + EXPECT_EQ(5000u, clock_.ApproximateNow().Subtract(start).ToMicroseconds()); EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); // Send an ack so we don't set the retransmission alarm. @@ -395,8 +395,8 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) { EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false)); EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, NOT_RETRANSMISSION)); runner_->RunNextTask(); - EXPECT_EQ(kDefaultTimeoutUs + 5000, - clock_.NowAsDeltaSinceUnixEpoch().ToMicroseconds()); + EXPECT_EQ(kDefaultTimeoutUs + 5000, clock_.ApproximateNow().Subtract( + QuicTime::Zero()).ToMicroseconds()); EXPECT_FALSE(connection_->connected()); EXPECT_TRUE(AtEof()); } diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc index 5b13c92..288d3dd 100644 --- a/net/quic/quic_connection_logger.cc +++ b/net/quic/quic_connection_logger.cc @@ -147,8 +147,7 @@ void QuicConnectionLogger::OnPacketReceived(const IPEndPoint& self_address, packet.length())); } -void QuicConnectionLogger::OnProtocolVersionMismatch( - QuicVersionTag received_version) { +void QuicConnectionLogger::OnProtocolVersionMismatch(QuicTag received_version) { // TODO(rtenneti): Add logging. } diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h index 4fe390b..9f38f22 100644 --- a/net/quic/quic_connection_logger.h +++ b/net/quic/quic_connection_logger.h @@ -24,8 +24,7 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger virtual void OnPacketReceived(const IPEndPoint& self_address, const IPEndPoint& peer_address, const QuicEncryptedPacket& packet) OVERRIDE; - virtual void OnProtocolVersionMismatch( - QuicVersionTag version) OVERRIDE; + virtual void OnProtocolVersionMismatch(QuicTag version) OVERRIDE; virtual void OnPacketHeader(const QuicPacketHeader& header) OVERRIDE; virtual void OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE; virtual void OnAckFrame(const QuicAckFrame& frame) OVERRIDE; diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index e81e011..826681a 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -1889,7 +1889,7 @@ TEST_F(QuicConnectionTest, CheckSentEntropyHash) { // TODO(satyamsehkhar): Add more test when we start supporting more versions. TEST_F(QuicConnectionTest, SendVersionNegotiationPacket) { - QuicVersionTag kRandomVersion = 143; + QuicTag kRandomVersion = 143; QuicFramerPeer::SetVersion(&framer_, kRandomVersion); QuicPacketHeader header; diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index e3ee834..75f5fd3 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc @@ -40,16 +40,6 @@ bool QuicCryptoClientStream::CryptoConnect() { return true; } -const QuicNegotiatedParameters& -QuicCryptoClientStream::negotiated_params() const { - return negotiated_params_; -} - -const QuicCryptoNegotiatedParameters& -QuicCryptoClientStream::crypto_negotiated_params() const { - return crypto_negotiated_params_; -} - int QuicCryptoClientStream::num_sent_client_hellos() const { return num_client_hellos_; } @@ -98,7 +88,7 @@ void QuicCryptoClientStream::DoHandshakeLoop( server_hostname_, session()->connection()->guid(), cached, - session()->connection()->clock(), + session()->connection()->clock()->WallNow(), session()->connection()->random_generator(), &crypto_negotiated_params_, &out, @@ -119,19 +109,25 @@ void QuicCryptoClientStream::DoHandshakeLoop( SendHandshakeMessage(out); // Be prepared to decrypt with the new server write key. session()->connection()->SetAlternativeDecrypter( - crypto_negotiated_params_.decrypter.release(), + crypto_negotiated_params_.initial_crypters.decrypter.release(), true /* latch once used */); // Send subsequent packets under encryption on the assumption that the // server will accept the handshake. session()->connection()->SetEncrypter( ENCRYPTION_INITIAL, - crypto_negotiated_params_.encrypter.release()); + crypto_negotiated_params_.initial_crypters.encrypter.release()); session()->connection()->SetDefaultEncryptionLevel( ENCRYPTION_INITIAL); if (!encryption_established_) { - session()->OnCryptoHandshakeEvent( - QuicSession::ENCRYPTION_FIRST_ESTABLISHED); - encryption_established_ = true; + // TODO(agl): the following, commented code should live here and not + // down when the handshake is confirmed. However, it causes + // EndToEndTest.LargePost to be flaky (b/8074678), seemingly because + // the packets dropped when the client hello is dropped cause the + // congestion control to be too conservative and the server times + // out. + // session()->OnCryptoHandshakeEvent( + // QuicSession::ENCRYPTION_FIRST_ESTABLISHED); + // encryption_established_ = true; } else { session()->OnCryptoHandshakeEvent( QuicSession::ENCRYPTION_REESTABLISHED); @@ -180,10 +176,19 @@ void QuicCryptoClientStream::DoHandshakeLoop( ENCRYPTION_NONE); next_state_ = STATE_SEND_CHLO; break; - case STATE_RECV_SHLO: + case STATE_RECV_SHLO: { // We sent a CHLO that we expected to be accepted and now we're hoping // for a SHLO from the server to confirm that. if (in->tag() == kREJ) { + // alternative_decrypter will be NULL if the original alternative + // decrypter latched and became the primary decrypter. That happens + // if we received a message encrypted with the INITIAL key. + if (session()->connection()->alternative_decrypter() == NULL) { + // The rejection was sent encrypted! + CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, + "encrypted REJ message"); + return; + } next_state_ = STATE_RECV_REJ; break; } @@ -192,11 +197,46 @@ void QuicCryptoClientStream::DoHandshakeLoop( "Expected SHLO or REJ"); return; } - // TODO(agl): enable this once the tests are corrected to permit it. - // DCHECK(session()->connection()->alternative_decrypter() == NULL); + // alternative_decrypter will be NULL if the original alternative + // decrypter latched and became the primary decrypter. That happens + // if we received a message encrypted with the INITIAL key. + if (session()->connection()->alternative_decrypter() != NULL) { + // The server hello was sent without encryption. + CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, + "unencrypted SHLO message"); + return; + } + error = crypto_config_->ProcessServerHello( + *in, session()->connection()->guid(), &crypto_negotiated_params_, + &error_details); + if (error != QUIC_NO_ERROR) { + CloseConnectionWithDetails( + error, "Server hello invalid: " + error_details); + return; + } + CrypterPair* crypters = + &crypto_negotiated_params_.forward_secure_crypters; + // TODO(agl): we don't currently latch this decrypter because the idea + // has been floated that the server shouldn't send packets encrypted + // with the FORWARD_SECURE key until it receives a FORWARD_SECURE + // packet from the client. + session()->connection()->SetAlternativeDecrypter( + crypters->decrypter.release(), false /* don't latch */); + session()->connection()->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release()); + session()->connection()->SetDefaultEncryptionLevel( + ENCRYPTION_FORWARD_SECURE); + + // TODO(agl): this code shouldn't be here. See the TODO further up + // about it. + session()->OnCryptoHandshakeEvent( + QuicSession::ENCRYPTION_FIRST_ESTABLISHED); + encryption_established_ = true; + handshake_confirmed_ = true; session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); return; + } case STATE_IDLE: // This means that the peer sent us a message that we weren't expecting. CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h index 740c892..041d11c 100644 --- a/net/quic/quic_crypto_client_stream.h +++ b/net/quic/quic_crypto_client_stream.h @@ -37,9 +37,6 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { // TODO(agl): this should probably return void. virtual bool CryptoConnect(); - const QuicNegotiatedParameters& negotiated_params() const; - const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const; - // num_sent_client_hellos returns the number of client hello messages that // have been sent. If the handshake has completed then this is one greater // than the number of round-trips needed for the handshake. @@ -67,9 +64,6 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { const QuicConfig& config_; QuicCryptoClientConfig* const crypto_config_; - QuicNegotiatedParameters negotiated_params_; - QuicCryptoNegotiatedParameters crypto_negotiated_params_; - // 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 96547e42..c913964 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc @@ -45,22 +45,6 @@ class TestQuicVisitor : public NoOpFramerVisitor { DISALLOW_COPY_AND_ASSIGN(TestQuicVisitor); }; -// The same as MockSession, except that WriteData() is not mocked. -class TestMockSession : public MockSession { - public: - TestMockSession(QuicConnection* connection, bool is_server) - : MockSession(connection, is_server) { - } - virtual ~TestMockSession() {} - - virtual QuicConsumedData WriteData(QuicStreamId id, - base::StringPiece data, - QuicStreamOffset offset, - bool fin) OVERRIDE { - return QuicSession::WriteData(id, data, offset, fin); - } -}; - class QuicCryptoClientStreamTest : public ::testing::Test { public: QuicCryptoClientStreamTest() @@ -68,6 +52,7 @@ class QuicCryptoClientStreamTest : public ::testing::Test { connection_(new PacketSavingConnection(1, addr_, true)), session_(connection_, true), stream_(kServerHostname, config_, &session_, &crypto_config_) { + session_.SetCryptoStream(&stream_); config_.SetDefaults(); crypto_config_.SetDefaults(); } @@ -84,7 +69,7 @@ class QuicCryptoClientStreamTest : public ::testing::Test { IPEndPoint addr_; PacketSavingConnection* connection_; - TestMockSession session_; + TestSession session_; QuicCryptoClientStream stream_; CryptoHandshakeMessage message_; scoped_ptr<QuicData> message_data_; diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc index 1dab72f..57c1076 100644 --- a/net/quic/quic_crypto_server_stream.cc +++ b/net/quic/quic_crypto_server_stream.cc @@ -40,54 +40,60 @@ void QuicCryptoServerStream::OnHandshakeMessage( string error_details; CryptoHandshakeMessage reply; - crypto_config_.ProcessClientHello( + QuicErrorCode error = crypto_config_.ProcessClientHello( message, session()->connection()->guid(), session()->connection()->peer_address(), - session()->connection()->clock()->NowAsDeltaSinceUnixEpoch(), + session()->connection()->clock(), session()->connection()->random_generator(), &crypto_negotiated_params_, &reply, &error_details); - if (reply.tag() == kSHLO) { - // If we are returning a SHLO then we accepted the handshake. - QuicErrorCode error = config_.ProcessFinalPeerHandshake( - message, CryptoUtils::LOCAL_PRIORITY, &negotiated_params_, - &error_details); - if (error != QUIC_NO_ERROR) { - CloseConnectionWithDetails(error, error_details); - return; - } + if (error != QUIC_NO_ERROR) { + CloseConnectionWithDetails(error, error_details); + return; + } + + if (reply.tag() != kSHLO) { + SendHandshakeMessage(reply); + 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()->SetEncrypter( - ENCRYPTION_INITIAL, - crypto_negotiated_params_.encrypter.release()); - session()->connection()->SetDefaultEncryptionLevel( - ENCRYPTION_INITIAL); - // Set the decrypter immediately so that we no longer accept unencrypted - // packets. - session()->connection()->SetDecrypter( - crypto_negotiated_params_.decrypter.release()); - encryption_established_ = true; - handshake_confirmed_ = true; - session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + // If we are returning a SHLO then we accepted the handshake. + error = config_.ProcessFinalPeerHandshake( + message, CryptoUtils::LOCAL_PRIORITY, &negotiated_params_, + &error_details); + if (error != QUIC_NO_ERROR) { + CloseConnectionWithDetails(error, error_details); + 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()->SetEncrypter( + ENCRYPTION_INITIAL, + crypto_negotiated_params_.initial_crypters.encrypter.release()); + session()->connection()->SetDefaultEncryptionLevel( + ENCRYPTION_INITIAL); + // Set the decrypter immediately so that we no longer accept unencrypted + // packets. + session()->connection()->SetDecrypter( + crypto_negotiated_params_.initial_crypters.decrypter.release()); SendHandshakeMessage(reply); - return; -} -const QuicNegotiatedParameters& -QuicCryptoServerStream::negotiated_params() const { - return negotiated_params_; -} + session()->connection()->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + crypto_negotiated_params_.forward_secure_crypters.encrypter.release()); + session()->connection()->SetDefaultEncryptionLevel( + ENCRYPTION_FORWARD_SECURE); + session()->connection()->SetAlternativeDecrypter( + crypto_negotiated_params_.forward_secure_crypters.decrypter.release(), + false /* don't latch */); -const QuicCryptoNegotiatedParameters& -QuicCryptoServerStream::crypto_negotiated_params() const { - return crypto_negotiated_params_; + encryption_established_ = true; + handshake_confirmed_ = true; + session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); } } // namespace net diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h index 3e4264a..47c1478 100644 --- a/net/quic/quic_crypto_server_stream.h +++ b/net/quic/quic_crypto_server_stream.h @@ -34,9 +34,6 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream { virtual void OnHandshakeMessage( const CryptoHandshakeMessage& message) OVERRIDE; - const QuicNegotiatedParameters& negotiated_params() const; - const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const; - private: friend class test::CryptoTestUtils; @@ -45,9 +42,6 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream { const QuicConfig& config_; // crypto_config_ contains crypto parameters for the handshake. const QuicCryptoServerConfig& crypto_config_; - - QuicNegotiatedParameters negotiated_params_; - QuicCryptoNegotiatedParameters crypto_negotiated_params_; }; } // namespace net diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc index 2cc2746..d12597b 100644 --- a/net/quic/quic_crypto_server_stream_test.cc +++ b/net/quic/quic_crypto_server_stream_test.cc @@ -54,18 +54,6 @@ class TestQuicVisitor : public NoOpFramerVisitor { DISALLOW_COPY_AND_ASSIGN(TestQuicVisitor); }; -class TestSession: public QuicSession { - public: - TestSession(QuicConnection* connection, bool is_server) - : QuicSession(connection, is_server) { - } - - MOCK_METHOD1(CreateIncomingReliableStream, - ReliableQuicStream*(QuicStreamId id)); - MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*()); - MOCK_METHOD0(CreateOutgoingReliableStream, ReliableQuicStream*()); -}; - class QuicCryptoServerStreamTest : public ::testing::Test { public: QuicCryptoServerStreamTest() @@ -76,6 +64,7 @@ class QuicCryptoServerStreamTest : public ::testing::Test { session_(connection_, true), crypto_config_(QuicCryptoServerConfig::TESTING), stream_(config_, crypto_config_, &session_) { + session_.SetCryptoStream(&stream_); // We advance the clock initially because the default time is zero and the // strike register worries that we've just overflowed a uint32 time. connection_->AdvanceTime(QuicTime::Delta::FromSeconds(100000)); @@ -152,8 +141,8 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { new PacketSavingConnection(guid, addr, false); PacketSavingConnection* server_conn = new PacketSavingConnection(guid, addr, false); - client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1000000)); - server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1000000)); + client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000)); + server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000)); scoped_ptr<TestSession> client_session(new TestSession(client_conn, true)); scoped_ptr<TestSession> server_session(new TestSession(server_conn, true)); @@ -167,6 +156,7 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { scoped_ptr<QuicCryptoClientStream> client(new QuicCryptoClientStream( "test.example.com", client_config, client_session.get(), &client_crypto_config)); + client_session->SetCryptoStream(client.get()); // Do a first handshake in order to prime the client config with the server's // information. @@ -176,6 +166,7 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { scoped_ptr<QuicCryptoServerStream> server( new QuicCryptoServerStream(config_, crypto_config_, server_session.get())); + server_session->SetCryptoStream(server.get()); CryptoTestUtils::CommunicateHandshakeMessages( client_conn, client.get(), server_conn, server.get()); @@ -188,8 +179,8 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { server_conn = new PacketSavingConnection(guid, addr, false); // We need to advance time past the strike-server window so that it's // authoritative in this time span. - client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1002000)); - server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1002000)); + client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(102000)); + server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(102000)); // This causes the client's nonce to be different and thus stops the // strike-register from rejecting the repeated nonce. @@ -199,8 +190,11 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { client.reset(new QuicCryptoClientStream( "test.example.com", client_config, client_session.get(), &client_crypto_config)); + client_session->SetCryptoStream(client.get()); + server.reset(new QuicCryptoServerStream(config_, crypto_config_, server_session.get())); + server_session->SetCryptoStream(server.get()); CHECK(client->CryptoConnect()); diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc index df6c610..70bf4d3 100644 --- a/net/quic/quic_crypto_stream.cc +++ b/net/quic/quic_crypto_stream.cc @@ -57,4 +57,14 @@ void QuicCryptoStream::SendHandshakeMessage( WriteData(string(data.data(), data.length()), false); } +const QuicNegotiatedParameters& +QuicCryptoStream::negotiated_params() const { + return negotiated_params_; +} + +const QuicCryptoNegotiatedParameters& +QuicCryptoStream::crypto_negotiated_params() const { + return crypto_negotiated_params_; +} + } // namespace net diff --git a/net/quic/quic_crypto_stream.h b/net/quic/quic_crypto_stream.h index db83503..1352f2e 100644 --- a/net/quic/quic_crypto_stream.h +++ b/net/quic/quic_crypto_stream.h @@ -7,6 +7,7 @@ #include "net/quic/crypto/crypto_framer.h" #include "net/quic/crypto/crypto_utils.h" +#include "net/quic/quic_config.h" #include "net/quic/quic_protocol.h" #include "net/quic/reliable_quic_stream.h" @@ -45,6 +46,9 @@ class NET_EXPORT_PRIVATE QuicCryptoStream bool encryption_established() { return encryption_established_; } bool handshake_confirmed() { return handshake_confirmed_; } + const QuicNegotiatedParameters& negotiated_params() const; + const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const; + protected: // Closes the connection void CloseConnection(QuicErrorCode error); @@ -53,6 +57,9 @@ class NET_EXPORT_PRIVATE QuicCryptoStream bool encryption_established_; bool handshake_confirmed_; + QuicNegotiatedParameters negotiated_params_; + QuicCryptoNegotiatedParameters crypto_negotiated_params_; + private: CryptoFramer crypto_framer_; diff --git a/net/quic/quic_crypto_stream_test.cc b/net/quic/quic_crypto_stream_test.cc index 6e465ab..cc69304 100644 --- a/net/quic/quic_crypto_stream_test.cc +++ b/net/quic/quic_crypto_stream_test.cc @@ -98,7 +98,11 @@ TEST_F(QuicCryptoStreamTest, ProcessData) { TEST_F(QuicCryptoStreamTest, ProcessBadData) { string bad(message_data_->data(), message_data_->length()); - bad[8] = 0x7F; // out of order tag + const int kFirstTagIndex = sizeof(uint32) + // message tag + sizeof(uint16) + // number of tag-value pairs + sizeof(uint16); // padding + EXPECT_EQ(1, bad[kFirstTagIndex]); + bad[kFirstTagIndex] = 0x7F; // out of order tag EXPECT_CALL(*connection_, SendConnectionClose(QUIC_CRYPTO_TAGS_OUT_OF_ORDER)); diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index 95c42b7..67a376e 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -45,7 +45,7 @@ QuicPacketSequenceNumber ClosestTo(QuicPacketSequenceNumber target, } // namespace -QuicFramer::QuicFramer(QuicVersionTag version, +QuicFramer::QuicFramer(QuicTag version, QuicTime creation_time, bool is_server) : visitor_(NULL), @@ -54,6 +54,7 @@ QuicFramer::QuicFramer(QuicVersionTag version, last_sequence_number_(0), quic_version_(version), decrypter_(QuicDecrypter::Create(kNULL)), + alternative_decrypter_latch_(false), is_server_(is_server), creation_time_(creation_time) { DCHECK(IsSupportedVersion(version)); @@ -101,7 +102,7 @@ size_t QuicFramer::GetMinGoAwayFrameSize() { kQuicStreamIdSize; } -bool QuicFramer::IsSupportedVersion(QuicVersionTag version) { +bool QuicFramer::IsSupportedVersion(QuicTag version) { return version == kQuicVersion1; } @@ -288,7 +289,7 @@ QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket( QuicEncryptedPacket* QuicFramer::ConstructVersionNegotiationPacket( const QuicPacketPublicHeader& header, - const QuicVersionTagList& supported_versions) { + const QuicTagVector& supported_versions) { DCHECK(header.version_flag); size_t len = GetVersionNegotiationPacketSize(supported_versions.size()); QuicDataWriter writer(len); @@ -350,7 +351,7 @@ bool QuicFramer::ProcessVersionNegotiationPacket( DCHECK(!is_server_); // Try reading at least once to raise error if the packet is invalid. do { - QuicVersionTag version; + QuicTag version; if (!reader_->ReadBytes(&version, kQuicVersionSize)) { set_detailed_error("Unable to read supported version in negotiation."); return RaiseError(QUIC_INVALID_VERSION_NEGOTIATION_PACKET); @@ -553,7 +554,7 @@ bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) { } if (public_header->version_flag && is_server_) { - QuicVersionTag version; + QuicTag version; if (!reader_->ReadUInt32(&version)) { // Read the version only if the packet is from the client. // version flag from the server means version negotiation packet. @@ -1068,6 +1069,18 @@ const QuicEncrypter* QuicFramer::encrypter(EncryptionLevel level) const { return encrypter_[level].get(); } +void QuicFramer::SwapCryptersForTest(QuicFramer* other) { + for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; i++) { + encrypter_[i].swap(other->encrypter_[i]); + } + decrypter_.swap(other->decrypter_); + alternative_decrypter_.swap(other->alternative_decrypter_); + + const bool other_latch = other->alternative_decrypter_latch_; + other->alternative_decrypter_latch_ = alternative_decrypter_latch_; + alternative_decrypter_latch_ = other_latch; +} + QuicEncryptedPacket* QuicFramer::EncryptPacket( EncryptionLevel level, QuicPacketSequenceNumber packet_sequence_number, @@ -1116,26 +1129,21 @@ bool QuicFramer::DecryptPayload(QuicPacketSequenceNumber sequence_number, return false; } DCHECK(decrypter_.get() != NULL); - LOG(INFO) << "Decrypting packet"; decrypted_.reset(decrypter_->DecryptPacket( sequence_number, GetAssociatedDataFromEncryptedPacket(packet, version_flag), encrypted)); if (decrypted_.get() == NULL && alternative_decrypter_.get() != NULL) { - LOG(INFO) << "Trying alternative"; decrypted_.reset(alternative_decrypter_->DecryptPacket( sequence_number, GetAssociatedDataFromEncryptedPacket(packet, version_flag), encrypted)); if (decrypted_.get() != NULL) { - LOG(INFO) << "alternative ok"; if (alternative_decrypter_latch_) { - LOG(INFO) << " latching"; // Switch to the alternative decrypter and latch so that we cannot // switch back. decrypter_.reset(alternative_decrypter_.release()); } else { - LOG(INFO) << " swapping"; // Switch the alternative decrypter so that we use it first next time. decrypter_.swap(alternative_decrypter_); } diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h index 1802fed..8286844 100644 --- a/net/quic/quic_framer.h +++ b/net/quic/quic_framer.h @@ -64,7 +64,7 @@ class NET_EXPORT_PRIVATE QuicFramerVisitorInterface { // |quic_version_|. The visitor should return true after it updates the // version of the |framer_| to |received_version| or false to stop processing // this packet. - virtual bool OnProtocolVersionMismatch(QuicVersionTag received_version) = 0; + virtual bool OnProtocolVersionMismatch(QuicTag received_version) = 0; // Called when a new packet has been received, before it // has been validated or processed. @@ -153,14 +153,14 @@ class NET_EXPORT_PRIVATE QuicFramer { public: // Constructs a new framer that installs a kNULL QuicEncrypter and // QuicDecrypter for level ENCRYPTION_NONE. - QuicFramer(QuicVersionTag quic_version, + QuicFramer(QuicTag quic_version, QuicTime creation_time, bool is_server); virtual ~QuicFramer(); // Returns true if |version| is a supported protocol version. - bool IsSupportedVersion(QuicVersionTag version); + bool IsSupportedVersion(QuicTag version); // Calculates the largest observed packet to advertise in the case an Ack // Frame was truncated. last_written in this case is the iterator for the @@ -184,11 +184,11 @@ class NET_EXPORT_PRIVATE QuicFramer { fec_builder_ = builder; } - QuicVersionTag version() const { + QuicTag version() const { return quic_version_; } - void set_version(QuicVersionTag version) { + void set_version(QuicTag version) { DCHECK(IsSupportedVersion(version)); quic_version_ = version; } @@ -271,7 +271,7 @@ class NET_EXPORT_PRIVATE QuicFramer { QuicEncryptedPacket* ConstructVersionNegotiationPacket( const QuicPacketPublicHeader& header, - const QuicVersionTagList& supported_versions); + const QuicTagVector& supported_versions); // SetDecrypter sets the primary decrypter, replacing any that already exists, // and takes ownership. If an alternative decrypter is in place then the @@ -296,6 +296,10 @@ class NET_EXPORT_PRIVATE QuicFramer { void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter); const QuicEncrypter* encrypter(EncryptionLevel level) const; + // SwapCryptersForTest exchanges the state of the crypters with |other|. To + // be used in tests only. + void SwapCryptersForTest(QuicFramer* other); + // Returns a new encrypted packet, owned by the caller. QuicEncryptedPacket* EncryptPacket(EncryptionLevel level, QuicPacketSequenceNumber sequence_number, @@ -396,7 +400,7 @@ class NET_EXPORT_PRIVATE QuicFramer { // Buffer containing decrypted payload data during parsing. scoped_ptr<QuicData> decrypted_; // Version of the protocol being used. - QuicVersionTag quic_version_; + QuicTag quic_version_; // Primary decrypter used to decrypt packets during parsing. scoped_ptr<QuicDecrypter> decrypter_; // Alternative decrypter that can also be used to decrypt packets. diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index 6e2556c..6986443 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -190,8 +190,7 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface { revived_packets_++; } - virtual bool OnProtocolVersionMismatch( - QuicVersionTag version) OVERRIDE { + virtual bool OnProtocolVersionMismatch(QuicTag version) OVERRIDE { DCHECK(false); return true; } @@ -573,7 +572,7 @@ TEST_F(QuicFramerTest, PacketHeaderWithVersionFlag) { // public flags (version) 0x01, // version tag - 'Q', '1', '.', '0', + 'Q', '0', '0', '1', // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -818,7 +817,7 @@ TEST_F(QuicFramerTest, StreamFrameWithVersion) { // public flags (version) 0x01, // version tag - 'Q', '1', '.', '0', + 'Q', '0', '0', '1', // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1627,7 +1626,7 @@ TEST_F(QuicFramerTest, VersionNegotiationPacket) { // public flags (version) 0x01, // version tag - 'Q', '1', '.', '0', + 'Q', '0', '0', '1', 'Q', '2', '.', '0', }; @@ -1826,7 +1825,7 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) { // public flags (version) 0x01, // version tag - 'Q', '1', '.', '0', + 'Q', '0', '0', '1', // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1874,12 +1873,12 @@ TEST_F(QuicFramerTest, ConstructVersionNegotiationPacket) { // public flags (version) 0x01, // version tag - 'Q', '1', '.', '0', + 'Q', '0', '0', '1', 'Q', '2', '.', '0', }; const int kQuicVersion2 = MakeQuicTag('Q', '2', '.', '0'); - QuicVersionTagList versions; + QuicTagVector versions; versions.push_back(kQuicVersion1); versions.push_back(kQuicVersion2); scoped_ptr<QuicEncryptedPacket> data( diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc index 5339a7f..2cdfd69 100644 --- a/net/quic/quic_packet_creator.cc +++ b/net/quic/quic_packet_creator.cc @@ -177,7 +177,7 @@ SerializedPacket QuicPacketCreator::SerializeConnectionClose( } QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket( - const QuicVersionTagList& supported_versions) { + const QuicTagVector& supported_versions) { DCHECK(is_server_); QuicPacketPublicHeader header; header.guid = guid_; diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h index 2e5c596..6f557c0a 100644 --- a/net/quic/quic_packet_creator.h +++ b/net/quic/quic_packet_creator.h @@ -120,7 +120,7 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { // serialized packet to a random bool and returns that value as a member of // SerializedPacket. QuicEncryptedPacket* SerializeVersionNegotiationPacket( - const QuicVersionTagList& supported_versions); + const QuicTagVector& supported_versions); QuicPacketSequenceNumber sequence_number() const { return sequence_number_; diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc index 4fe4f18..bd4f332 100644 --- a/net/quic/quic_packet_creator_test.cc +++ b/net/quic/quic_packet_creator_test.cc @@ -179,7 +179,7 @@ TEST_F(QuicPacketCreatorTest, CreateStreamFrameFinOnly) { TEST_F(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) { QuicPacketCreatorPeer::SetIsServer(&creator_, true); - QuicVersionTagList versions; + QuicTagVector versions; versions.push_back(kQuicVersion1); scoped_ptr<QuicEncryptedPacket> encrypted( creator_.SerializeVersionNegotiationPacket(versions)); diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index c3fd9a0..31fab86 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -36,9 +36,10 @@ typedef uint64 QuicPacketSequenceNumber; typedef QuicPacketSequenceNumber QuicFecGroupNumber; typedef uint64 QuicPublicResetNonceProof; typedef uint8 QuicPacketEntropyHash; -typedef uint32 QuicVersionTag; -typedef std::vector<QuicVersionTag> QuicVersionTagList; typedef uint32 QuicHeaderId; +// QuicTag is the type of a tag in the wire protocol. +typedef uint32 QuicTag; +typedef std::vector<QuicTag> QuicTagVector; // TODO(rch): Consider Quic specific names for these constants. // Maximum size in bytes of a QUIC packet. @@ -75,7 +76,7 @@ NET_EXPORT_PRIVATE size_t GetStartOfFecProtectedData(bool include_version); // Index of the first byte in a QUIC packet of encrypted data. NET_EXPORT_PRIVATE size_t GetStartOfEncryptedData(bool include_version); // Returns true if |version| is a supported protocol version. -NET_EXPORT_PRIVATE bool IsSupportedVersion(QuicVersionTag version); +NET_EXPORT_PRIVATE bool IsSupportedVersion(QuicTag version); // Index of the first byte in a QUIC packet which is used in hash calculation. const size_t kStartOfHashData = 0; @@ -95,13 +96,13 @@ const uint8 kNoFecOffset = 0xFF; const int64 kDefaultTimeoutUs = 600000000; // 10 minutes. enum Retransmission { - NOT_RETRANSMISSION = 0, - IS_RETRANSMISSION = 1, + NOT_RETRANSMISSION, + IS_RETRANSMISSION, }; enum HasRetransmittableData { - HAS_RETRANSMITTABLE_DATA = 0, - NO_RETRANSMITTABLE_DATA = 1, + NO_RETRANSMITTABLE_DATA, + HAS_RETRANSMITTABLE_DATA, }; enum QuicFrameType { @@ -233,6 +234,11 @@ enum QuicErrorCode { QUIC_PROOF_INVALID, // A crypto message was received with a duplicate tag. QUIC_CRYPTO_DUPLICATE_TAG, + // A crypto message was received with the wrong encryption level (i.e. it + // should have been encrypted but was not.) + QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, + // The server config for a server has expired. + QUIC_CRYPTO_SERVER_CONFIG_EXPIRED, // No error. Used as bound while iterating. QUIC_LAST_ERROR, @@ -248,8 +254,11 @@ enum QuicErrorCode { // The TAG macro is used in header files to ensure that we don't create static // initialisers. In normal code, the MakeQuicTag function should be used. #define TAG(a, b, c, d) ((d << 24) + (c << 16) + (b << 8) + a) -const QuicVersionTag kUnsupportedVersion = -1; -const QuicVersionTag kQuicVersion1 = TAG('Q', '1', '.', '0'); +const QuicTag kUnsupportedVersion = -1; +// Each time the wire format changes, this need needs to be incremented. +// At some point, we will actually freeze the wire format and make an official +// version number, but this works for now. +const QuicTag kQuicVersion1 = TAG('Q', '0', '0', '1'); #undef TAG // MakeQuicTag returns a value given the four bytes. For example: @@ -267,7 +276,7 @@ struct NET_EXPORT_PRIVATE QuicPacketPublicHeader { QuicGuid guid; bool reset_flag; bool version_flag; - QuicVersionTagList versions; + QuicTagVector versions; }; // Header for Data or FEC packets. diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc index 80f6f6a..271cca6 100644 --- a/net/quic/quic_protocol_test.cc +++ b/net/quic/quic_protocol_test.cc @@ -11,6 +11,16 @@ namespace net { namespace test { namespace { +TEST(QuicProtocolTest, MakeQuicTag) { + QuicTag tag = MakeQuicTag('A', 'B', 'C', 'D'); + char bytes[4]; + memcpy(bytes, &tag, 4); + EXPECT_EQ('A', bytes[0]); + EXPECT_EQ('B', bytes[1]); + EXPECT_EQ('C', bytes[2]); + EXPECT_EQ('D', bytes[3]); +} + TEST(QuicProtocolTest, IsAawaitingPacket) { ReceivedPacketInfo received_info; received_info.largest_observed = 10u; diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 8cd605a..66879300 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -213,6 +213,10 @@ bool QuicSession::IsCryptoHandshakeConfirmed() { } void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { + if (event == QuicSession::HANDSHAKE_CONFIRMED) { + connection_->SetConnectionTimeout( + GetCryptoStream()->negotiated_params().idle_connection_state_lifetime); + } } void QuicSession::ActivateStream(ReliableQuicStream* stream) { diff --git a/net/quic/quic_time.cc b/net/quic/quic_time.cc index c4c80b0..fa0d516 100644 --- a/net/quic/quic_time.cc +++ b/net/quic/quic_time.cc @@ -99,4 +99,56 @@ QuicTime::Delta QuicTime::Subtract(const QuicTime& other) const { return QuicTime::Delta(ticks_ - other.ticks_); } +// static +QuicWallTime QuicWallTime::FromUNIXSeconds(uint64 seconds) { + return QuicWallTime(seconds); +} + +uint64 QuicWallTime::ToUNIXSeconds() const { + return seconds_; +} + +bool QuicWallTime::IsAfter(QuicWallTime other) const { + return seconds_ > other.seconds_; +} + +bool QuicWallTime::IsBefore(QuicWallTime other) const { + return seconds_ < other.seconds_; +} + +QuicTime::Delta QuicWallTime::AbsoluteDifference(QuicWallTime other) const { + uint64 d; + + if (seconds_ > other.seconds_) { + d = seconds_ - other.seconds_; + } else { + d = other.seconds_ - seconds_; + } + + if (d > static_cast<uint64>(kint64max)) { + d = kint64max; + } + return QuicTime::Delta::FromSeconds(d); +} + +QuicWallTime QuicWallTime::Add(QuicTime::Delta delta) const { + uint64 seconds = seconds_ + delta.ToSeconds(); + if (seconds < seconds_) { + seconds = kuint64max; + } + return QuicWallTime(seconds); +} + +QuicWallTime QuicWallTime::Subtract(QuicTime::Delta delta) const { + uint64 seconds = seconds_ - delta.ToSeconds(); + if (seconds > seconds_) { + seconds = 0; + } + return QuicWallTime(seconds); +} + +QuicWallTime::QuicWallTime(uint64 seconds) + : seconds_(seconds) { +} + } // namespace net diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h index dc919fc..067027b 100644 --- a/net/quic/quic_time.h +++ b/net/quic/quic_time.h @@ -19,6 +19,9 @@ namespace net { static const uint64 kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond; +// A QuicTime is a purely relative time. QuicTime values from different clocks +// cannot be compared to each other. If you need an absolute time, see +// QuicWallTime, below. class NET_EXPORT_PRIVATE QuicTime { public: // A QuicTime::Delta represents the signed difference between two points in @@ -96,6 +99,40 @@ class NET_EXPORT_PRIVATE QuicTime { base::TimeTicks ticks_; }; +// A QuicWallTime represents an absolute time that is globally consistent. It +// provides, at most, one second granularity and, in practice, clock-skew means +// that you shouldn't even depend on that. +class NET_EXPORT_PRIVATE QuicWallTime { + public: + // FromUNIXSeconds constructs a QuicWallTime from a count of the seconds + // since the UNIX epoch. + static QuicWallTime FromUNIXSeconds(uint64 seconds); + + // ToUNIXSeconds converts a QuicWallTime into a count of seconds since the + // UNIX epoch. + uint64 ToUNIXSeconds() const; + + bool IsAfter(QuicWallTime other) const; + bool IsBefore(QuicWallTime other) const; + + // AbsoluteDifference returns the absolute value of the time difference + // between |this| and |other|. + QuicTime::Delta AbsoluteDifference(QuicWallTime other) const; + + // Add returns a new QuicWallTime that represents the time of |this| plus + // |delta|. + QuicWallTime Add(QuicTime::Delta delta) const; + + // Subtract returns a new QuicWallTime that represents the time of |this| + // minus |delta|. + QuicWallTime Subtract(QuicTime::Delta delta) const; + + private: + explicit QuicWallTime(uint64 seconds); + + uint64 seconds_; +}; + // Non-member relational operators for QuicTime::Delta. inline bool operator==(QuicTime::Delta lhs, QuicTime::Delta rhs) { return lhs.ToMicroseconds() == rhs.ToMicroseconds(); diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index 142f9cc..228b796 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc @@ -127,6 +127,8 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_CONNECTION_TIMED_OUT); RETURN_STRING_LITERAL(QUIC_PROOF_INVALID); RETURN_STRING_LITERAL(QUIC_CRYPTO_DUPLICATE_TAG); + RETURN_STRING_LITERAL(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT); + RETURN_STRING_LITERAL(QUIC_CRYPTO_SERVER_CONFIG_EXPIRED); RETURN_STRING_LITERAL(QUIC_LAST_ERROR); // Intentionally have no default case, so we'll break the build // if we add errors and don't put them here. diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index cdcec21..cadbe9a 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -20,7 +20,7 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id, visitor_(NULL), stream_bytes_read_(0), stream_bytes_written_(0), - headers_complete_(false), + headers_decompressed_(false), headers_id_(0), stream_error_(QUIC_STREAM_NO_ERROR), connection_error_(QUIC_NO_ERROR), @@ -99,7 +99,7 @@ void ReliableQuicStream::Close(QuicRstStreamErrorCode error) { } int ReliableQuicStream::Readv(const struct iovec* iov, int iov_len) { - if (headers_complete_ && decompressed_headers_.empty()) { + if (headers_decompressed_ && decompressed_headers_.empty()) { return sequencer_.Readv(iov, iov_len); } size_t bytes_consumed = 0; @@ -119,7 +119,7 @@ int ReliableQuicStream::Readv(const struct iovec* iov, int iov_len) { } int ReliableQuicStream::GetReadableRegions(iovec* iov, int iov_len) { - if (headers_complete_ && decompressed_headers_.empty()) { + if (headers_decompressed_ && decompressed_headers_.empty()) { return sequencer_.GetReadableRegions(iov, iov_len); } if (iov_len == 0) { @@ -132,7 +132,7 @@ int ReliableQuicStream::GetReadableRegions(iovec* iov, int iov_len) { } bool ReliableQuicStream::IsHalfClosed() const { - if (!headers_complete_ || !decompressed_headers_.empty()) { + if (!headers_decompressed_ || !decompressed_headers_.empty()) { return false; } return sequencer_.IsHalfClosed(); @@ -254,9 +254,16 @@ uint32 ReliableQuicStream::ProcessRawData(const char* data, uint32 data_len) { DCHECK_NE(0u, headers_id_); // Once the headers are finished, we simply pass the data through. - if (headers_complete_ && decompressed_headers_.empty()) { - DVLOG(1) << "Delegating procesing to ProcessData"; - return total_bytes_consumed + ProcessData(data, data_len); + if (headers_decompressed_) { + // Some buffered header data remains. + if (!decompressed_headers_.empty()) { + ProcessHeaderData(); + } + if (decompressed_headers_.empty()) { + DVLOG(1) << "Delegating procesing to ProcessData"; + total_bytes_consumed += ProcessData(data, data_len); + } + return total_bytes_consumed; } QuicHeaderId current_header_id = @@ -264,9 +271,11 @@ uint32 ReliableQuicStream::ProcessRawData(const char* data, uint32 data_len) { // Ensure that this header id looks sane. if (headers_id_ < current_header_id || headers_id_ > kMaxHeaderIdDelta + current_header_id) { - DVLOG(1) << "Invalud headers for stream: " << id() - << " header_id: " << headers_id_; + DVLOG(1) << "Invalid headers for stream: " << id() + << " header_id: " << headers_id_ + << " current_header_id: " << current_header_id; session_->connection()->SendConnectionClose(QUIC_INVALID_HEADER_ID); + return total_bytes_consumed; } // If we are head-of-line blocked on decompression, then back up. @@ -284,18 +293,10 @@ uint32 ReliableQuicStream::ProcessRawData(const char* data, uint32 data_len) { // Headers are complete if the decompressor has moved on to the // next stream. - headers_complete_ = + headers_decompressed_ = session_->decompressor()->current_header_id() != headers_id_; - if (!decompressed_headers_.empty()) { - size_t bytes_processed = ProcessData(decompressed_headers_.data(), - decompressed_headers_.length()); - if (bytes_processed == decompressed_headers_.length()) { - decompressed_headers_.clear(); - } else { - decompressed_headers_ = decompressed_headers_.erase(0, bytes_processed); - } - } + ProcessHeaderData(); // We have processed all of the decompressed data but we might // have some more raw data to process. @@ -327,24 +328,24 @@ uint32 ReliableQuicStream::ProcessHeaderData() { void ReliableQuicStream::OnDecompressorAvailable() { DCHECK_EQ(headers_id_, session_->decompressor()->current_header_id()); - DCHECK(!headers_complete_); + DCHECK(!headers_decompressed_); DCHECK_EQ(0u, decompressed_headers_.length()); size_t total_bytes_consumed = 0; struct iovec iovecs[5]; - while (!headers_complete_) { + while (!headers_decompressed_) { size_t num_iovecs = sequencer_.GetReadableRegions(iovecs, arraysize(iovecs)); if (num_iovecs == 0) { return; } - for (size_t i = 0; i < num_iovecs && !headers_complete_; i++) { + for (size_t i = 0; i < num_iovecs && !headers_decompressed_; i++) { total_bytes_consumed += session_->decompressor()->DecompressData( StringPiece(static_cast<char*>(iovecs[i].iov_base), iovecs[i].iov_len), this); - headers_complete_ = + headers_decompressed_ = session_->decompressor()->current_header_id() != headers_id_; } } @@ -354,7 +355,7 @@ void ReliableQuicStream::OnDecompressorAvailable() { ProcessHeaderData(); // Unprocessed headers remain in decompressed_headers_. - if (headers_complete_ && decompressed_headers_.empty()) { + if (headers_decompressed_ && decompressed_headers_.empty()) { sequencer_.FlushBufferedFrames(); } } diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index 2aa66e6..726cc9c 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h @@ -126,6 +126,8 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public // Close the write side of the socket. Further writes will fail. void CloseWriteSide(); + bool fin_buffered() { return fin_buffered_; } + QuicSession* session() { return session_; } // Sends as much of 'data' to the connection as the connection will consume, @@ -154,7 +156,7 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public uint64 stream_bytes_read_; uint64 stream_bytes_written_; // True if the headers have been completely decompresssed. - bool headers_complete_; + bool headers_decompressed_; // ID of the header block sent by the peer, once parsed. QuicHeaderId headers_id_; // Buffer into which we write bytes from the headers_id_ diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index d86a0b6..ede58bd 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc @@ -43,7 +43,7 @@ class TestStream : public ReliableQuicStream { } virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE { - LOG(INFO) << "data_len: " << data_len; + DVLOG(1) << "ProcessData data_len: " << data_len; data_ += string(data, data_len); return should_process_data_ ? data_len : 0; } @@ -68,8 +68,10 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> { } void Initialize(bool stream_should_process_data) { - connection_ = new MockConnection(kGuid, IPEndPoint(), kIsServer); - session_.reset(new MockSession(connection_, kIsServer)); + connection_ = new testing::StrictMock<MockConnection>( + kGuid, IPEndPoint(), kIsServer); + session_.reset(new testing::StrictMock<MockSession>( + connection_, kIsServer)); stream_.reset(new TestStream(kStreamId, session_.get(), stream_should_process_data)); stream2_.reset(new TestStream(kStreamId + 2, session_.get(), @@ -307,6 +309,26 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersEarly) { stream2_->OnDecompressorAvailable(); EXPECT_EQ(decompressed_headers2, stream2_->data()); } +TEST_F(ReliableQuicStreamTest, ProcessHeadersDelay) { + Initialize(!kShouldProcessData); + + string compressed_headers = compressor_->CompressHeaders(headers_); + QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers); + string decompressed_headers = + SpdyUtils::SerializeUncompressedHeaders(headers_); + + // Send the headers to the stream and verify they were decompressed. + stream_->OnStreamFrame(frame1); + EXPECT_EQ(2u, session_->decompressor()->current_header_id()); + + // Verify that we are now able to handle the body data, + // even though the stream has not processed the headers. + EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_HEADER_ID)) + .Times(0); + QuicStreamFrame frame2(stream_->id(), false, compressed_headers.length(), + "body data"); + stream_->OnStreamFrame(frame2); +} } // namespace } // namespace test diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc index 99af86f..058157e 100644 --- a/net/quic/test_tools/crypto_test_utils.cc +++ b/net/quic/test_tools/crypto_test_utils.cc @@ -14,6 +14,7 @@ #include "net/quic/quic_crypto_client_stream.h" #include "net/quic/quic_crypto_server_stream.h" #include "net/quic/quic_crypto_stream.h" +#include "net/quic/test_tools/quic_connection_peer.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/quic/test_tools/simple_quic_framer.h" @@ -26,18 +27,6 @@ namespace test { namespace { -class TestSession : public QuicSession { - public: - TestSession(QuicConnection* connection, bool is_server) - : QuicSession(connection, is_server) { - } - - MOCK_METHOD1(CreateIncomingReliableStream, - ReliableQuicStream*(QuicStreamId id)); - MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*()); - MOCK_METHOD0(CreateOutgoingReliableStream, ReliableQuicStream*()); -}; - // CryptoFramerVisitor is a framer visitor that records handshake messages. class CryptoFramerVisitor : public CryptoFramerVisitorInterface { public: @@ -73,16 +62,24 @@ class CryptoFramerVisitor : public CryptoFramerVisitorInterface { // than the last packet processed. void MovePackets(PacketSavingConnection* source_conn, size_t *inout_packet_index, - QuicCryptoStream* dest_stream) { + QuicCryptoStream* dest_stream, + PacketSavingConnection* dest_conn) { SimpleQuicFramer framer; CryptoFramer crypto_framer; CryptoFramerVisitor crypto_visitor; + // In order to properly test the code we need to perform encryption and + // decryption so that the crypters latch when expected. The crypters are in + // |dest_conn|, but we don't want to try and use them there. Instead we swap + // them into |framer|, perform the decryption with them, and then swap them + // back. + QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); + crypto_framer.set_visitor(&crypto_visitor); size_t index = *inout_packet_index; - for (; index < source_conn->packets_.size(); index++) { - ASSERT_TRUE(framer.ProcessPacket(*source_conn->packets_[index])); + for (; index < source_conn->encrypted_packets_.size(); index++) { + ASSERT_TRUE(framer.ProcessPacket(*source_conn->encrypted_packets_[index])); for (vector<QuicStreamFrame>::const_iterator i = framer.stream_frames().begin(); i != framer.stream_frames().end(); ++i) { @@ -92,6 +89,8 @@ void MovePackets(PacketSavingConnection* source_conn, } *inout_packet_index = index; + QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); + ASSERT_EQ(0u, crypto_framer.InputBytesRemaining()); for (vector<CryptoHandshakeMessage>::const_iterator @@ -114,7 +113,7 @@ void CryptoTestUtils::CommunicateHandshakeMessages( ASSERT_GT(a_conn->packets_.size(), a_i); LOG(INFO) << "Processing " << a_conn->packets_.size() - a_i << " packets a->b"; - MovePackets(a_conn, &a_i, b); + MovePackets(a_conn, &a_i, b, b_conn); ASSERT_GT(b_conn->packets_.size(), b_i); LOG(INFO) << "Processing " << b_conn->packets_.size() - b_i @@ -122,7 +121,7 @@ void CryptoTestUtils::CommunicateHandshakeMessages( if (b_conn->packets_.size() - b_i == 2) { LOG(INFO) << "here"; } - MovePackets(b_conn, &b_i, a); + MovePackets(b_conn, &b_i, a, a_conn); } } @@ -146,6 +145,7 @@ int CryptoTestUtils::HandshakeWithFakeServer( &config, &crypto_config); QuicCryptoServerStream server(config, crypto_config, &server_session); + server_session.SetCryptoStream(&server); // The client's handshake must have been started already. CHECK_NE(0u, client_conn->packets_.size()); @@ -177,6 +177,7 @@ int CryptoTestUtils::HandshakeWithFakeClient( // crypto_config.SetProofVerifier(ProofVerifierForTesting()); QuicCryptoClientStream client("test.example.com", config, &client_session, &crypto_config); + client_session.SetCryptoStream(&client); CHECK(client.CryptoConnect()); CHECK_EQ(1u, client_conn->packets_.size()); @@ -199,7 +200,8 @@ void CryptoTestUtils::SetupCryptoServerConfigForTest( config->ToHandshakeMessage(&extra_tags); scoped_ptr<CryptoHandshakeMessage> scfg( - crypto_config->AddDefaultConfig(rand, clock, extra_tags)); + crypto_config->AddDefaultConfig( + rand, clock, extra_tags, QuicCryptoServerConfig::kDefaultExpiry)); if (!config->SetFromHandshakeMessage(*scfg)) { CHECK(false) << "Crypto config could not be parsed by QuicConfig."; } @@ -207,28 +209,28 @@ void CryptoTestUtils::SetupCryptoServerConfigForTest( // static string CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage& message, - CryptoTag tag) { - CryptoTagValueMap::const_iterator it = message.tag_value_map().find(tag); + QuicTag tag) { + QuicTagValueMap::const_iterator it = message.tag_value_map().find(tag); if (it == message.tag_value_map().end()) { return string(); } return it->second; } -class MockCommonCertSet : public CommonCertSet { +class MockCommonCertSets : public CommonCertSets { public: - MockCommonCertSet(StringPiece cert, uint64 hash, uint32 index) + MockCommonCertSets(StringPiece cert, uint64 hash, uint32 index) : cert_(cert.as_string()), hash_(hash), index_(index) { } - virtual StringPiece GetCommonHashes() OVERRIDE { + virtual StringPiece GetCommonHashes() const OVERRIDE { CHECK(false) << "not implemented"; return StringPiece(); } - virtual StringPiece GetCert(uint64 hash, uint32 index) OVERRIDE { + virtual StringPiece GetCert(uint64 hash, uint32 index) const OVERRIDE { if (hash == hash_ && index == index_) { return cert_; } @@ -238,7 +240,7 @@ class MockCommonCertSet : public CommonCertSet { virtual bool MatchCert(StringPiece cert, StringPiece common_set_hashes, uint64* out_hash, - uint32* out_index) OVERRIDE { + uint32* out_index) const OVERRIDE { if (cert != cert_) { return false; } @@ -271,10 +273,10 @@ class MockCommonCertSet : public CommonCertSet { const uint32 index_; }; -CommonCertSet* CryptoTestUtils::MockCommonCertSet(StringPiece cert, - uint64 hash, - uint32 index) { - return new class MockCommonCertSet(cert, hash, index); +CommonCertSets* CryptoTestUtils::MockCommonCertSets(StringPiece cert, + uint64 hash, + uint32 index) { + return new class MockCommonCertSets(cert, hash, index); } void CryptoTestUtils::CompareClientAndServerKeys( @@ -282,26 +284,45 @@ void CryptoTestUtils::CompareClientAndServerKeys( QuicCryptoServerStream* server) { const QuicEncrypter* client_encrypter( client->session()->connection()->encrypter(ENCRYPTION_INITIAL)); - // Normally we would expect the client's INITIAL decrypter to have latched - // from the receipt of the server hello. However, when using a - // PacketSavingConnection (at the tests do) we don't actually encrypt with - // the correct encrypter. - // TODO(agl): make the tests more realistic. const QuicDecrypter* client_decrypter( + client->session()->connection()->decrypter()); + const QuicEncrypter* client_forward_secure_encrypter( + client->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE)); + const QuicDecrypter* client_forward_secure_decrypter( client->session()->connection()->alternative_decrypter()); const QuicEncrypter* server_encrypter( server->session()->connection()->encrypter(ENCRYPTION_INITIAL)); const QuicDecrypter* server_decrypter( server->session()->connection()->decrypter()); + const QuicEncrypter* server_forward_secure_encrypter( + server->session()->connection()->encrypter(ENCRYPTION_FORWARD_SECURE)); + const QuicDecrypter* server_forward_secure_decrypter( + server->session()->connection()->alternative_decrypter()); StringPiece client_encrypter_key = client_encrypter->GetKey(); StringPiece client_encrypter_iv = client_encrypter->GetNoncePrefix(); StringPiece client_decrypter_key = client_decrypter->GetKey(); StringPiece client_decrypter_iv = client_decrypter->GetNoncePrefix(); + StringPiece client_forward_secure_encrypter_key = + client_forward_secure_encrypter->GetKey(); + StringPiece client_forward_secure_encrypter_iv = + client_forward_secure_encrypter->GetNoncePrefix(); + StringPiece client_forward_secure_decrypter_key = + client_forward_secure_decrypter->GetKey(); + StringPiece client_forward_secure_decrypter_iv = + client_forward_secure_decrypter->GetNoncePrefix(); StringPiece server_encrypter_key = server_encrypter->GetKey(); StringPiece server_encrypter_iv = server_encrypter->GetNoncePrefix(); StringPiece server_decrypter_key = server_decrypter->GetKey(); StringPiece server_decrypter_iv = server_decrypter->GetNoncePrefix(); + StringPiece server_forward_secure_encrypter_key = + server_forward_secure_encrypter->GetKey(); + StringPiece server_forward_secure_encrypter_iv = + server_forward_secure_encrypter->GetNoncePrefix(); + StringPiece server_forward_secure_decrypter_key = + server_forward_secure_decrypter->GetKey(); + StringPiece server_forward_secure_decrypter_iv = + server_forward_secure_decrypter->GetNoncePrefix(); CompareCharArraysWithHexError("client write key", client_encrypter_key.data(), @@ -323,6 +344,26 @@ void CryptoTestUtils::CompareClientAndServerKeys( server_encrypter_iv.length(), client_decrypter_iv.data(), client_decrypter_iv.length()); + CompareCharArraysWithHexError("client forward secure write key", + client_forward_secure_encrypter_key.data(), + client_forward_secure_encrypter_key.length(), + server_forward_secure_decrypter_key.data(), + server_forward_secure_decrypter_key.length()); + CompareCharArraysWithHexError("client forward secure write IV", + client_forward_secure_encrypter_iv.data(), + client_forward_secure_encrypter_iv.length(), + server_forward_secure_decrypter_iv.data(), + server_forward_secure_decrypter_iv.length()); + CompareCharArraysWithHexError("server forward secure write key", + server_forward_secure_encrypter_key.data(), + server_forward_secure_encrypter_key.length(), + client_forward_secure_decrypter_key.data(), + client_forward_secure_decrypter_key.length()); + CompareCharArraysWithHexError("server forward secure write IV", + server_forward_secure_encrypter_iv.data(), + server_forward_secure_encrypter_iv.length(), + client_forward_secure_decrypter_iv.data(), + client_forward_secure_decrypter_iv.length()); } } // namespace test } // namespace net diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h index 62d813a..62748a3 100644 --- a/net/quic/test_tools/crypto_test_utils.h +++ b/net/quic/test_tools/crypto_test_utils.h @@ -15,7 +15,7 @@ namespace net { -class CommonCertSet; +class CommonCertSets; class ProofSource; class ProofVerifier; class QuicClock; @@ -57,7 +57,7 @@ class CryptoTestUtils { // Returns the value for the tag |tag| in the tag value map of |message|. static std::string GetValueForTag(const CryptoHandshakeMessage& message, - CryptoTag tag); + QuicTag tag); // Returns a |ProofSource| that serves up test certificates. static ProofSource* ProofSourceForTesting(); @@ -65,11 +65,11 @@ class CryptoTestUtils { // Returns a |ProofVerifier| that uses the QUIC testing root CA. static ProofVerifier* ProofVerifierForTesting(); - // MockCommonCertSet returns a CommonCertSet that contains a single set with + // MockCommonCertSets returns a CommonCertSets that contains a single set with // hash |hash|, consisting of the certificate |cert| at index |index|. - static CommonCertSet* MockCommonCertSet(base::StringPiece cert, - uint64 hash, - uint32 index); + static CommonCertSets* MockCommonCertSets(base::StringPiece cert, + uint64 hash, + uint32 index); private: static void CompareClientAndServerKeys(QuicCryptoClientStream* client, diff --git a/net/quic/test_tools/mock_clock.cc b/net/quic/test_tools/mock_clock.cc index 4e5864d..47f2380 100644 --- a/net/quic/test_tools/mock_clock.cc +++ b/net/quic/test_tools/mock_clock.cc @@ -24,8 +24,9 @@ QuicTime MockClock::ApproximateNow() const { return now_; } -QuicTime::Delta MockClock::NowAsDeltaSinceUnixEpoch() const { - return now_.Subtract(QuicTime::Zero()); +QuicWallTime MockClock::WallNow() const { + return QuicWallTime::FromUNIXSeconds( + now_.Subtract(QuicTime::Zero()).ToSeconds()); } base::TimeTicks MockClock::NowInTicks() const { diff --git a/net/quic/test_tools/mock_clock.h b/net/quic/test_tools/mock_clock.h index 7497aa2..33a93b4 100644 --- a/net/quic/test_tools/mock_clock.h +++ b/net/quic/test_tools/mock_clock.h @@ -25,7 +25,7 @@ class MockClock : public QuicClock { virtual QuicTime ApproximateNow() const OVERRIDE; - virtual QuicTime::Delta NowAsDeltaSinceUnixEpoch() const OVERRIDE; + virtual QuicWallTime WallNow() const OVERRIDE; base::TimeTicks NowInTicks() const; diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc index 102b2d7..6816e54 100644 --- a/net/quic/test_tools/quic_connection_peer.cc +++ b/net/quic/test_tools/quic_connection_peer.cc @@ -115,5 +115,11 @@ void QuicConnectionPeer::SetIsServer(QuicConnection* connection, QuicFramerPeer::SetIsServer(&connection->framer_, is_server); } +// static +void QuicConnectionPeer::SwapCrypters(QuicConnection* connection, + QuicFramer* framer) { + framer->SwapCryptersForTest(&connection->framer_); +} + } // namespace test } // namespace net diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h index 97f7afa..89c6482 100644 --- a/net/quic/test_tools/quic_connection_peer.h +++ b/net/quic/test_tools/quic_connection_peer.h @@ -14,6 +14,7 @@ namespace net { struct QuicAckFrame; class QuicConnection; class QuicConnectionVisitorInterface; +class QuicFramer; class QuicPacketCreator; class ReceiveAlgorithmInterface; class SendAlgorithmInterface; @@ -67,6 +68,8 @@ class QuicConnectionPeer { static void SetIsServer(QuicConnection* connection, bool is_server); + static void SwapCrypters(QuicConnection* connection, QuicFramer* framer); + private: DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer); }; diff --git a/net/quic/test_tools/quic_framer_peer.cc b/net/quic/test_tools/quic_framer_peer.cc index 15a8067..9a3b968 100644 --- a/net/quic/test_tools/quic_framer_peer.cc +++ b/net/quic/test_tools/quic_framer_peer.cc @@ -28,7 +28,7 @@ void QuicFramerPeer::SetIsServer(QuicFramer* framer, bool is_server) { framer->is_server_ = is_server; } -void QuicFramerPeer::SetVersion(QuicFramer* framer, QuicVersionTag version) { +void QuicFramerPeer::SetVersion(QuicFramer* framer, QuicTag version) { framer->quic_version_ = version; } diff --git a/net/quic/test_tools/quic_framer_peer.h b/net/quic/test_tools/quic_framer_peer.h index 3880412..0c59d2d 100644 --- a/net/quic/test_tools/quic_framer_peer.h +++ b/net/quic/test_tools/quic_framer_peer.h @@ -22,7 +22,7 @@ class QuicFramerPeer { QuicFramer* framer, QuicPacketSequenceNumber packet_sequence_number); static void SetIsServer(QuicFramer* framer, bool is_server); - static void SetVersion(QuicFramer* framer, QuicVersionTag version); + static void SetVersion(QuicFramer* framer, QuicTag version); private: DISALLOW_COPY_AND_ASSIGN(QuicFramerPeer); diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index cd83756..c987277 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc @@ -5,7 +5,6 @@ #include "net/quic/test_tools/quic_test_utils.h" #include "base/stl_util.h" -#include "base/strings/string_piece.h" #include "net/quic/crypto/crypto_framer.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/crypto_utils.h" @@ -56,7 +55,7 @@ MockFramerVisitor::MockFramerVisitor() { MockFramerVisitor::~MockFramerVisitor() { } -bool NoOpFramerVisitor::OnProtocolVersionMismatch(QuicVersionTag version) { +bool NoOpFramerVisitor::OnProtocolVersionMismatch(QuicTag version) { return false; } @@ -189,7 +188,8 @@ void MockHelper::AdvanceTime(QuicTime::Delta delta) { MockConnection::MockConnection(QuicGuid guid, IPEndPoint address, bool is_server) - : QuicConnection(guid, address, new MockHelper(), is_server), + : QuicConnection(guid, address, new testing::NiceMock<MockHelper>(), + is_server), has_mock_helper_(true) { } @@ -218,6 +218,7 @@ PacketSavingConnection::PacketSavingConnection(QuicGuid guid, PacketSavingConnection::~PacketSavingConnection() { STLDeleteElements(&packets_); + STLDeleteElements(&encrypted_packets_); } bool PacketSavingConnection::SendOrQueuePacket( @@ -227,6 +228,9 @@ bool PacketSavingConnection::SendOrQueuePacket( QuicPacketEntropyHash entropy_hash, HasRetransmittableData retransmittable) { packets_.push_back(packet); + QuicEncryptedPacket* encrypted = + framer_.EncryptPacket(level, sequence_number, *packet); + encrypted_packets_.push_back(encrypted); return true; } @@ -239,6 +243,22 @@ MockSession::MockSession(QuicConnection* connection, bool is_server) MockSession::~MockSession() { } +TestSession::TestSession(QuicConnection* connection, bool is_server) + : QuicSession(connection, is_server), + crypto_stream_(NULL) { +} + +TestSession::~TestSession() { +} + +void TestSession::SetCryptoStream(QuicCryptoStream* stream) { + crypto_stream_ = stream; +} + +QuicCryptoStream* TestSession::GetCryptoStream() { + return crypto_stream_; +} + MockSendAlgorithm::MockSendAlgorithm() { } @@ -355,7 +375,7 @@ static QuicPacket* ConstructPacketFromHandshakeMessage( return quic_framer.ConstructFrameDataPacket(header, frames).packet; } -QuicPacket* ConstructHandshakePacket(QuicGuid guid, CryptoTag tag) { +QuicPacket* ConstructHandshakePacket(QuicGuid guid, QuicTag tag) { CryptoHandshakeMessage message; message.set_tag(tag); return ConstructPacketFromHandshakeMessage(guid, message, false); diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 13e7a8d..5ea2a78 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -7,8 +7,10 @@ #ifndef NET_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_ #define NET_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_ +#include <string> #include <vector> +#include "base/strings/string_piece.h" #include "net/quic/congestion_control/send_algorithm_interface.h" #include "net/quic/quic_connection.h" #include "net/quic/quic_framer.h" @@ -46,7 +48,7 @@ class MockFramerVisitor : public QuicFramerVisitorInterface { MOCK_METHOD1(OnError, void(QuicFramer* framer)); // The constructor sets this up to return false by default. - MOCK_METHOD1(OnProtocolVersionMismatch, bool(QuicVersionTag version)); + MOCK_METHOD1(OnProtocolVersionMismatch, bool(QuicTag version)); MOCK_METHOD0(OnPacket, void()); MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header)); MOCK_METHOD1(OnVersionNegotiationPacket, @@ -81,7 +83,7 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface { virtual void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) OVERRIDE {} virtual void OnRevivedPacket() OVERRIDE {} - virtual bool OnProtocolVersionMismatch(QuicVersionTag version) OVERRIDE; + virtual bool OnProtocolVersionMismatch(QuicTag version) OVERRIDE; virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE; virtual void OnFecProtectedPayload(base::StringPiece payload) OVERRIDE {} virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE; @@ -238,7 +240,7 @@ class MockConnection : public QuicConnection { QuicConnection::ProcessUdpPacket(self_address, peer_address, packet); } - virtual bool OnProtocolVersionMismatch(QuicVersionTag version) OVERRIDE { + virtual bool OnProtocolVersionMismatch(QuicTag version) OVERRIDE { return false; } @@ -261,6 +263,7 @@ class PacketSavingConnection : public MockConnection { HasRetransmittableData has_retransmittable_data) OVERRIDE; std::vector<QuicPacket*> packets_; + std::vector<QuicEncryptedPacket*> encrypted_packets_; private: DISALLOW_COPY_AND_ASSIGN(PacketSavingConnection); @@ -290,6 +293,24 @@ class MockSession : public QuicSession { DISALLOW_COPY_AND_ASSIGN(MockSession); }; +class TestSession : public QuicSession { + public: + TestSession(QuicConnection* connection, bool is_server); + virtual ~TestSession(); + + MOCK_METHOD1(CreateIncomingReliableStream, + ReliableQuicStream*(QuicStreamId id)); + MOCK_METHOD0(CreateOutgoingReliableStream, ReliableQuicStream*()); + + void SetCryptoStream(QuicCryptoStream* stream); + + virtual QuicCryptoStream* GetCryptoStream(); + + private: + QuicCryptoStream* crypto_stream_; + DISALLOW_COPY_AND_ASSIGN(TestSession); +}; + class MockSendAlgorithm : public SendAlgorithmInterface { public: MockSendAlgorithm(); diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc index c39a724..7e77b0f 100644 --- a/net/quic/test_tools/simple_quic_framer.cc +++ b/net/quic/test_tools/simple_quic_framer.cc @@ -25,7 +25,7 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { error_ = framer->error(); } - virtual bool OnProtocolVersionMismatch(QuicVersionTag version) OVERRIDE { + virtual bool OnProtocolVersionMismatch(QuicTag version) OVERRIDE { return false; } @@ -128,9 +128,7 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { }; SimpleQuicFramer::SimpleQuicFramer() - : framer_(kQuicVersion1, - QuicTime::Zero(), - true) { + : framer_(kQuicVersion1, QuicTime::Zero(), true) { } SimpleQuicFramer::~SimpleQuicFramer() { @@ -156,6 +154,10 @@ const QuicFecData& SimpleQuicFramer::fec_data() const { return visitor_->fec_data(); } +QuicFramer* SimpleQuicFramer::framer() { + return &framer_; +} + size_t SimpleQuicFramer::num_frames() const { return ack_frames().size() + stream_frames().size() + diff --git a/net/quic/test_tools/simple_quic_framer.h b/net/quic/test_tools/simple_quic_framer.h index bda2b89..4416019 100644 --- a/net/quic/test_tools/simple_quic_framer.h +++ b/net/quic/test_tools/simple_quic_framer.h @@ -43,6 +43,7 @@ class SimpleQuicFramer { const std::vector<QuicRstStreamFrame>& rst_stream_frames() const; const std::vector<QuicStreamFrame>& stream_frames() const; const QuicFecData& fec_data() const; + QuicFramer* framer(); private: QuicFramer framer_; |