diff options
Diffstat (limited to 'chromium/net/quic/crypto/crypto_server_test.cc')
-rw-r--r-- | chromium/net/quic/crypto/crypto_server_test.cc | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/chromium/net/quic/crypto/crypto_server_test.cc b/chromium/net/quic/crypto/crypto_server_test.cc new file mode 100644 index 00000000000..6744d12e5e0 --- /dev/null +++ b/chromium/net/quic/crypto/crypto_server_test.cc @@ -0,0 +1,256 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/string_number_conversions.h" +#include "net/quic/crypto/crypto_server_config.h" +#include "net/quic/crypto/crypto_utils.h" +#include "net/quic/crypto/quic_random.h" +#include "net/quic/test_tools/crypto_test_utils.h" +#include "net/quic/test_tools/mock_clock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::StringPiece; +using std::string; + +namespace net { +namespace test { + +class CryptoServerTest : public ::testing::Test { + public: + CryptoServerTest() + : rand_(QuicRandom::GetInstance()), + config_(QuicCryptoServerConfig::TESTING, rand_), + addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_) ? + ip_ : IPAddressNumber(), 1) { + config_.SetProofSource(CryptoTestUtils::ProofSourceForTesting()); + } + + virtual void SetUp() { + scoped_ptr<CryptoHandshakeMessage> msg( + config_.AddDefaultConfig(rand_, &clock_, + QuicCryptoServerConfig::ConfigOptions())); + + StringPiece orbit; + CHECK(msg->GetStringPiece(kORBT, &orbit)); + CHECK_EQ(sizeof(orbit_), orbit.size()); + memcpy(orbit_, orbit.data(), orbit.size()); + + char public_value[32]; + memset(public_value, 42, sizeof(public_value)); + + const string nonce_str = GenerateNonce(); + nonce_hex_ = "#" + base::HexEncode(nonce_str.data(), nonce_str.size()); + pub_hex_ = "#" + base::HexEncode(public_value, sizeof(public_value)); + + CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( + "CHLO", + "AEAD", "AESG", + "KEXS", "C255", + "PUBS", pub_hex_.c_str(), + "NONC", nonce_hex_.c_str(), + "$padding", static_cast<int>(kClientHelloMinimumSize), + NULL); + ShouldSucceed(client_hello); + // The message should be rejected because the source-address token is + // missing. + ASSERT_EQ(kREJ, out_.tag()); + + StringPiece srct; + ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct)); + srct_hex_ = "#" + base::HexEncode(srct.data(), srct.size()); + + StringPiece scfg; + ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg)); + server_config_.reset(CryptoFramer::ParseMessage(scfg)); + + StringPiece scid; + ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid)); + scid_hex_ = "#" + base::HexEncode(scid.data(), scid.size()); + } + + void ShouldSucceed(const CryptoHandshakeMessage& message) { + string error_details; + QuicErrorCode error = config_.ProcessClientHello( + message, QuicVersionMax(), 1 /* GUID */, addr_, + &clock_, rand_, ¶ms_, &out_, &error_details); + + ASSERT_EQ(error, QUIC_NO_ERROR) + << "Message failed with error " << error_details << ": " + << message.DebugString(); + } + + void ShouldFailMentioning(const char* error_substr, + const CryptoHandshakeMessage& message) { + string error_details; + QuicErrorCode error = config_.ProcessClientHello( + message, QuicVersionMax(), 1 /* GUID */, addr_, + &clock_, rand_, ¶ms_, &out_, &error_details); + + ASSERT_NE(error, QUIC_NO_ERROR) + << "Message didn't fail: " << message.DebugString(); + + EXPECT_TRUE(error_details.find(error_substr) != string::npos) + << error_substr << " not in " << error_details; + } + + CryptoHandshakeMessage InchoateClientHello(const char* message_tag, ...) { + va_list ap; + va_start(ap, message_tag); + + CryptoHandshakeMessage message = + CryptoTestUtils::BuildMessage(message_tag, ap); + va_end(ap); + + message.SetStringPiece(kPAD, string(kClientHelloMinimumSize, '-')); + return message; + } + + string GenerateNonce() { + string nonce; + CryptoUtils::GenerateNonce( + clock_.WallNow(), rand_, + StringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)), + &nonce); + return nonce; + } + + protected: + QuicRandom* const rand_; + MockClock clock_; + QuicCryptoServerConfig config_; + QuicCryptoNegotiatedParameters params_; + CryptoHandshakeMessage out_; + IPAddressNumber ip_; + IPEndPoint addr_; + uint8 orbit_[kOrbitSize]; + + // These strings contain hex escaped values from the server suitable for + // passing to |InchoateClientHello| when constructing client hello messages. + string nonce_hex_, pub_hex_, srct_hex_, scid_hex_; + scoped_ptr<CryptoHandshakeMessage> server_config_; +}; + +TEST_F(CryptoServerTest, BadSNI) { + static const char* kBadSNIs[] = { + "", + "foo", + "#00", + "#ff00", + "127.0.0.1", + "ffee::1", + }; + + for (size_t i = 0; i < arraysize(kBadSNIs); i++) { + ShouldFailMentioning("SNI", InchoateClientHello( + "CHLO", + "SNI", kBadSNIs[i], + NULL)); + } +} + +// TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource. +TEST_F(CryptoServerTest, DISABLED_DefaultCert) { + // Check that the server replies with a default certificate when no SNI is + // specified. + ShouldSucceed(InchoateClientHello( + "CHLO", + "AEAD", "AESG", + "KEXS", "C255", + "SCID", scid_hex_.c_str(), + "#004b5453", srct_hex_.c_str(), + "PUBS", pub_hex_.c_str(), + "NONC", nonce_hex_.c_str(), + "$padding", static_cast<int>(kClientHelloMinimumSize), + "PDMD", "X509", + NULL)); + + StringPiece cert, proof; + EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); + EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof)); + EXPECT_NE(0u, cert.size()); + EXPECT_NE(0u, proof.size()); +} + +TEST_F(CryptoServerTest, TooSmall) { + ShouldFailMentioning("too small", CryptoTestUtils::Message( + "CHLO", + NULL)); +} + +TEST_F(CryptoServerTest, BadSourceAddressToken) { + // Invalid source-address tokens should be ignored. + static const char* kBadSourceAddressTokens[] = { + "", + "foo", + "#0000", + "#0000000000000000000000000000000000000000", + }; + + for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) { + ShouldSucceed(InchoateClientHello( + "CHLO", + "STK", kBadSourceAddressTokens[i], + NULL)); + } +} + +TEST_F(CryptoServerTest, BadClientNonce) { + // Invalid nonces should be ignored. + static const char* kBadNonces[] = { + "", + "#0000", + "#0000000000000000000000000000000000000000", + }; + + for (size_t i = 0; i < arraysize(kBadNonces); i++) { + ShouldSucceed(InchoateClientHello( + "CHLO", + "NONC", kBadNonces[i], + NULL)); + } +} + +TEST_F(CryptoServerTest, ReplayProtection) { + // This tests that disabling replay protection works. + CryptoHandshakeMessage msg = CryptoTestUtils::Message( + "CHLO", + "AEAD", "AESG", + "KEXS", "C255", + "SCID", scid_hex_.c_str(), + "#004b5453", srct_hex_.c_str(), + "PUBS", pub_hex_.c_str(), + "NONC", nonce_hex_.c_str(), + "$padding", static_cast<int>(kClientHelloMinimumSize), + NULL); + ShouldSucceed(msg); + // The message should be rejected because the strike-register is still + // quiescent. + ASSERT_EQ(kREJ, out_.tag()); + + config_.set_replay_protection(false); + + ShouldSucceed(msg); + // The message should be accepted now. + ASSERT_EQ(kSHLO, out_.tag()); + + ShouldSucceed(msg); + // The message should accepted twice when replay protection is off. + ASSERT_EQ(kSHLO, out_.tag()); +} + +class CryptoServerTestNoConfig : public CryptoServerTest { + public: + virtual void SetUp() { + // Deliberately don't add a config so that we can test this situation. + } +}; + +TEST_F(CryptoServerTestNoConfig, DontCrash) { + ShouldFailMentioning("No config", InchoateClientHello( + "CHLO", + NULL)); +} + +} // namespace test +} // namespace net |