1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/quic/quic_client_session.h"
6
7#include <vector>
8
9#include "base/base64.h"
10#include "base/files/file_path.h"
11#include "base/rand_util.h"
12#include "net/base/capturing_net_log.h"
13#include "net/base/test_completion_callback.h"
14#include "net/base/test_data_directory.h"
15#include "net/cert/cert_verify_result.h"
16#include "net/http/transport_security_state.h"
17#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
18#include "net/quic/crypto/crypto_protocol.h"
19#include "net/quic/crypto/proof_verifier_chromium.h"
20#include "net/quic/crypto/quic_decrypter.h"
21#include "net/quic/crypto/quic_encrypter.h"
22#include "net/quic/crypto/quic_server_info.h"
23#include "net/quic/test_tools/crypto_test_utils.h"
24#include "net/quic/test_tools/quic_client_session_peer.h"
25#include "net/quic/test_tools/quic_test_utils.h"
26#include "net/quic/test_tools/simple_quic_framer.h"
27#include "net/socket/socket_test_util.h"
28#include "net/spdy/spdy_test_utils.h"
29#include "net/test/cert_test_util.h"
30#include "net/udp/datagram_client_socket.h"
31
32using testing::_;
33
34namespace net {
35namespace test {
36namespace {
37
38const char kServerHostname[] = "www.example.org";
39const uint16 kServerPort = 80;
40
41class QuicClientSessionTest : public ::testing::TestWithParam<QuicVersion> {
42 protected:
43  QuicClientSessionTest()
44      : connection_(
45            new PacketSavingConnection(false, SupportedVersions(GetParam()))),
46        session_(connection_, GetSocket().Pass(), NULL,
47                 &transport_security_state_,
48                 make_scoped_ptr((QuicServerInfo*)NULL), DefaultQuicConfig(),
49                 base::MessageLoop::current()->message_loop_proxy().get(),
50                 &net_log_) {
51    session_.InitializeSession(QuicServerId(kServerHostname, kServerPort, false,
52                                            PRIVACY_MODE_DISABLED),
53                                &crypto_config_, NULL);
54    session_.config()->SetDefaults();
55    crypto_config_.SetDefaults();
56  }
57
58  virtual void TearDown() OVERRIDE {
59    session_.CloseSessionOnError(ERR_ABORTED);
60  }
61
62  scoped_ptr<DatagramClientSocket> GetSocket() {
63    socket_factory_.AddSocketDataProvider(&socket_data_);
64    return socket_factory_.CreateDatagramClientSocket(
65        DatagramSocket::DEFAULT_BIND, base::Bind(&base::RandInt),
66        &net_log_, NetLog::Source());
67  }
68
69  void CompleteCryptoHandshake() {
70    ASSERT_EQ(ERR_IO_PENDING,
71              session_.CryptoConnect(false, callback_.callback()));
72    CryptoTestUtils::HandshakeWithFakeServer(
73        connection_, session_.GetCryptoStream());
74    ASSERT_EQ(OK, callback_.WaitForResult());
75  }
76
77  PacketSavingConnection* connection_;
78  CapturingNetLog net_log_;
79  MockClientSocketFactory socket_factory_;
80  StaticSocketDataProvider socket_data_;
81  TransportSecurityState transport_security_state_;
82  QuicClientSession session_;
83  MockClock clock_;
84  MockRandom random_;
85  QuicConnectionVisitorInterface* visitor_;
86  TestCompletionCallback callback_;
87  QuicCryptoClientConfig crypto_config_;
88};
89
90INSTANTIATE_TEST_CASE_P(Tests, QuicClientSessionTest,
91                        ::testing::ValuesIn(QuicSupportedVersions()));
92
93TEST_P(QuicClientSessionTest, CryptoConnect) {
94  CompleteCryptoHandshake();
95}
96
97TEST_P(QuicClientSessionTest, MaxNumStreams) {
98  CompleteCryptoHandshake();
99
100  std::vector<QuicReliableClientStream*> streams;
101  for (size_t i = 0; i < kDefaultMaxStreamsPerConnection; i++) {
102    QuicReliableClientStream* stream = session_.CreateOutgoingDataStream();
103    EXPECT_TRUE(stream);
104    streams.push_back(stream);
105  }
106  EXPECT_FALSE(session_.CreateOutgoingDataStream());
107
108  // Close a stream and ensure I can now open a new one.
109  session_.CloseStream(streams[0]->id());
110  EXPECT_TRUE(session_.CreateOutgoingDataStream());
111}
112
113TEST_P(QuicClientSessionTest, MaxNumStreamsViaRequest) {
114  CompleteCryptoHandshake();
115
116  std::vector<QuicReliableClientStream*> streams;
117  for (size_t i = 0; i < kDefaultMaxStreamsPerConnection; i++) {
118    QuicReliableClientStream* stream = session_.CreateOutgoingDataStream();
119    EXPECT_TRUE(stream);
120    streams.push_back(stream);
121  }
122
123  QuicReliableClientStream* stream;
124  QuicClientSession::StreamRequest stream_request;
125  TestCompletionCallback callback;
126  ASSERT_EQ(ERR_IO_PENDING,
127            stream_request.StartRequest(session_.GetWeakPtr(), &stream,
128                                        callback.callback()));
129
130  // Close a stream and ensure I can now open a new one.
131  session_.CloseStream(streams[0]->id());
132  ASSERT_TRUE(callback.have_result());
133  EXPECT_EQ(OK, callback.WaitForResult());
134  EXPECT_TRUE(stream != NULL);
135}
136
137TEST_P(QuicClientSessionTest, GoAwayReceived) {
138  CompleteCryptoHandshake();
139
140  // After receiving a GoAway, I should no longer be able to create outgoing
141  // streams.
142  session_.OnGoAway(QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away."));
143  EXPECT_EQ(NULL, session_.CreateOutgoingDataStream());
144}
145
146TEST_P(QuicClientSessionTest, CanPool) {
147  // Load a cert that is valid for:
148  //   www.example.org
149  //   mail.example.org
150  //   www.example.com
151
152  ProofVerifyDetailsChromium details;
153  details.cert_verify_result.verified_cert =
154      ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
155  ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
156
157  session_.OnProofVerifyDetailsAvailable(details);
158  CompleteCryptoHandshake();
159
160
161  EXPECT_TRUE(session_.CanPool("www.example.org"));
162  EXPECT_TRUE(session_.CanPool("mail.example.org"));
163  EXPECT_TRUE(session_.CanPool("mail.example.com"));
164  EXPECT_FALSE(session_.CanPool("mail.google.com"));
165}
166
167TEST_P(QuicClientSessionTest, ConnectionPooledWithTlsChannelId) {
168  // Load a cert that is valid for:
169  //   www.example.org
170  //   mail.example.org
171  //   www.example.com
172
173  ProofVerifyDetailsChromium details;
174  details.cert_verify_result.verified_cert =
175      ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
176  ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
177
178  session_.OnProofVerifyDetailsAvailable(details);
179  CompleteCryptoHandshake();
180  QuicClientSessionPeer::SetChannelIDSent(&session_, true);
181
182  EXPECT_TRUE(session_.CanPool("www.example.org"));
183  EXPECT_TRUE(session_.CanPool("mail.example.org"));
184  EXPECT_FALSE(session_.CanPool("mail.example.com"));
185  EXPECT_FALSE(session_.CanPool("mail.google.com"));
186}
187
188TEST_P(QuicClientSessionTest, ConnectionNotPooledWithDifferentPin) {
189  uint8 primary_pin = 1;
190  uint8 backup_pin = 2;
191  uint8 bad_pin = 3;
192  AddPin(&transport_security_state_, "mail.example.org", primary_pin,
193         backup_pin);
194
195  ProofVerifyDetailsChromium details;
196  details.cert_verify_result.verified_cert =
197      ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
198  details.cert_verify_result.is_issued_by_known_root = true;
199  details.cert_verify_result.public_key_hashes.push_back(
200      GetTestHashValue(bad_pin));
201
202  ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
203
204  session_.OnProofVerifyDetailsAvailable(details);
205  CompleteCryptoHandshake();
206  QuicClientSessionPeer::SetChannelIDSent(&session_, true);
207
208  EXPECT_FALSE(session_.CanPool("mail.example.org"));
209}
210
211TEST_P(QuicClientSessionTest, ConnectionPooledWithMatchingPin) {
212  uint8 primary_pin = 1;
213  uint8 backup_pin = 2;
214  AddPin(&transport_security_state_, "mail.example.org", primary_pin,
215         backup_pin);
216
217  ProofVerifyDetailsChromium details;
218  details.cert_verify_result.verified_cert =
219      ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
220  details.cert_verify_result.is_issued_by_known_root = true;
221  details.cert_verify_result.public_key_hashes.push_back(
222      GetTestHashValue(primary_pin));
223
224  ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
225
226  session_.OnProofVerifyDetailsAvailable(details);
227  CompleteCryptoHandshake();
228  QuicClientSessionPeer::SetChannelIDSent(&session_, true);
229
230  EXPECT_TRUE(session_.CanPool("mail.example.org"));
231}
232
233}  // namespace
234}  // namespace test
235}  // namespace net
236