blob: 959776b864eaeb189249afe77b01b58efcbba81a [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/quic/quic_chromium_client_session.h"
#include <vector>
#include "base/base64.h"
#include "base/files/file_path.h"
#include "base/rand_util.h"
#include "base/thread_task_runner_handle.h"
#include "net/base/test_completion_callback.h"
#include "net/base/test_data_directory.h"
#include "net/cert/cert_verify_result.h"
#include "net/http/transport_security_state.h"
#include "net/log/test_net_log.h"
#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/proof_verifier_chromium.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/crypto/quic_server_info.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_chromium_client_session_peer.h"
#include "net/quic/test_tools/quic_spdy_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/simple_quic_framer.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_test_utils.h"
#include "net/test/cert_test_util.h"
#include "net/udp/datagram_client_socket.h"
using testing::_;
namespace net {
namespace test {
namespace {
const char kServerHostname[] = "www.example.org";
const uint16 kServerPort = 80;
class QuicChromiumClientSessionTest
: public ::testing::TestWithParam<QuicVersion> {
protected:
QuicChromiumClientSessionTest()
: connection_(new PacketSavingConnection(Perspective::IS_CLIENT,
SupportedVersions(GetParam()))),
session_(connection_,
GetSocket().Pass(),
/*stream_factory=*/nullptr,
/*crypto_client_stream_factory=*/nullptr,
&transport_security_state_,
make_scoped_ptr((QuicServerInfo*)nullptr),
QuicServerId(kServerHostname,
kServerPort,
/*is_secure=*/false,
PRIVACY_MODE_DISABLED),
/*cert_verify_flags=*/0,
DefaultQuicConfig(),
&crypto_config_,
"CONNECTION_UNKNOWN",
base::TimeTicks::Now(),
base::ThreadTaskRunnerHandle::Get().get(),
&net_log_) {
session_.Initialize();
// Advance the time, because timers do not like uninitialized times.
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
}
void TearDown() override {
session_.CloseSessionOnError(ERR_ABORTED, QUIC_INTERNAL_ERROR);
}
scoped_ptr<DatagramClientSocket> GetSocket() {
socket_factory_.AddSocketDataProvider(&socket_data_);
return socket_factory_.CreateDatagramClientSocket(
DatagramSocket::DEFAULT_BIND, base::Bind(&base::RandInt), &net_log_,
NetLog::Source());
}
void CompleteCryptoHandshake() {
ASSERT_EQ(ERR_IO_PENDING,
session_.CryptoConnect(false, callback_.callback()));
CryptoTestUtils::HandshakeWithFakeServer(connection_,
session_.GetCryptoStream());
ASSERT_EQ(OK, callback_.WaitForResult());
}
PacketSavingConnection* connection_;
TestNetLog net_log_;
MockClientSocketFactory socket_factory_;
StaticSocketDataProvider socket_data_;
TransportSecurityState transport_security_state_;
QuicChromiumClientSession session_;
MockClock clock_;
MockRandom random_;
QuicConnectionVisitorInterface* visitor_;
TestCompletionCallback callback_;
QuicCryptoClientConfig crypto_config_;
};
INSTANTIATE_TEST_CASE_P(Tests,
QuicChromiumClientSessionTest,
::testing::ValuesIn(QuicSupportedVersions()));
TEST_P(QuicChromiumClientSessionTest, CryptoConnect) {
CompleteCryptoHandshake();
}
TEST_P(QuicChromiumClientSessionTest, MaxNumStreams) {
CompleteCryptoHandshake();
std::vector<QuicReliableClientStream*> streams;
for (size_t i = 0; i < kDefaultMaxStreamsPerConnection; i++) {
QuicReliableClientStream* stream = session_.CreateOutgoingDynamicStream();
EXPECT_TRUE(stream);
streams.push_back(stream);
}
EXPECT_FALSE(session_.CreateOutgoingDynamicStream());
// Close a stream and ensure I can now open a new one.
session_.CloseStream(streams[0]->id());
EXPECT_TRUE(session_.CreateOutgoingDynamicStream());
}
TEST_P(QuicChromiumClientSessionTest, MaxNumStreamsViaRequest) {
CompleteCryptoHandshake();
std::vector<QuicReliableClientStream*> streams;
for (size_t i = 0; i < kDefaultMaxStreamsPerConnection; i++) {
QuicReliableClientStream* stream = session_.CreateOutgoingDynamicStream();
EXPECT_TRUE(stream);
streams.push_back(stream);
}
QuicReliableClientStream* stream;
QuicChromiumClientSession::StreamRequest stream_request;
TestCompletionCallback callback;
ASSERT_EQ(ERR_IO_PENDING,
stream_request.StartRequest(session_.GetWeakPtr(), &stream,
callback.callback()));
// Close a stream and ensure I can now open a new one.
session_.CloseStream(streams[0]->id());
ASSERT_TRUE(callback.have_result());
EXPECT_EQ(OK, callback.WaitForResult());
EXPECT_TRUE(stream != nullptr);
}
TEST_P(QuicChromiumClientSessionTest, GoAwayReceived) {
CompleteCryptoHandshake();
// After receiving a GoAway, I should no longer be able to create outgoing
// streams.
session_.OnGoAway(QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away."));
EXPECT_EQ(nullptr, session_.CreateOutgoingDynamicStream());
}
TEST_P(QuicChromiumClientSessionTest, CanPool) {
// Load a cert that is valid for:
// www.example.org
// mail.example.org
// www.example.com
ProofVerifyDetailsChromium details;
details.cert_verify_result.verified_cert =
ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
session_.OnProofVerifyDetailsAvailable(details);
CompleteCryptoHandshake();
EXPECT_TRUE(session_.CanPool("www.example.org", PRIVACY_MODE_DISABLED));
EXPECT_FALSE(session_.CanPool("www.example.org", PRIVACY_MODE_ENABLED));
EXPECT_TRUE(session_.CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
EXPECT_TRUE(session_.CanPool("mail.example.com", PRIVACY_MODE_DISABLED));
EXPECT_FALSE(session_.CanPool("mail.google.com", PRIVACY_MODE_DISABLED));
}
TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithTlsChannelId) {
// Load a cert that is valid for:
// www.example.org
// mail.example.org
// www.example.com
ProofVerifyDetailsChromium details;
details.cert_verify_result.verified_cert =
ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
session_.OnProofVerifyDetailsAvailable(details);
CompleteCryptoHandshake();
QuicChromiumClientSessionPeer::SetChannelIDSent(&session_, true);
EXPECT_TRUE(session_.CanPool("www.example.org", PRIVACY_MODE_DISABLED));
EXPECT_TRUE(session_.CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
EXPECT_FALSE(session_.CanPool("mail.example.com", PRIVACY_MODE_DISABLED));
EXPECT_FALSE(session_.CanPool("mail.google.com", PRIVACY_MODE_DISABLED));
}
TEST_P(QuicChromiumClientSessionTest, ConnectionNotPooledWithDifferentPin) {
uint8 primary_pin = 1;
uint8 backup_pin = 2;
uint8 bad_pin = 3;
AddPin(&transport_security_state_, "mail.example.org", primary_pin,
backup_pin);
ProofVerifyDetailsChromium details;
details.cert_verify_result.verified_cert =
ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
details.cert_verify_result.is_issued_by_known_root = true;
details.cert_verify_result.public_key_hashes.push_back(
GetTestHashValue(bad_pin));
ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
session_.OnProofVerifyDetailsAvailable(details);
CompleteCryptoHandshake();
QuicChromiumClientSessionPeer::SetChannelIDSent(&session_, true);
EXPECT_FALSE(session_.CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
}
TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithMatchingPin) {
uint8 primary_pin = 1;
uint8 backup_pin = 2;
AddPin(&transport_security_state_, "mail.example.org", primary_pin,
backup_pin);
ProofVerifyDetailsChromium details;
details.cert_verify_result.verified_cert =
ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
details.cert_verify_result.is_issued_by_known_root = true;
details.cert_verify_result.public_key_hashes.push_back(
GetTestHashValue(primary_pin));
ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
session_.OnProofVerifyDetailsAvailable(details);
CompleteCryptoHandshake();
QuicChromiumClientSessionPeer::SetChannelIDSent(&session_, true);
EXPECT_TRUE(session_.CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
}
} // namespace
} // namespace test
} // namespace net