Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: webrtc/p2p/base/quicsession_unittest.cc

Issue 1648763002: Create QuicSession (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <string>
12 #include <vector>
13
14 #include "webrtc/p2p/base/quicconnectionhelper.h"
15 #include "webrtc/p2p/base/quicsession.h"
16 #include "webrtc/p2p/base/reliablequicstream.h"
17
18 #include "net/base/ip_endpoint.h"
19 #include "net/quic/crypto/crypto_server_config_protobuf.h"
20 #include "net/quic/crypto/quic_random.h"
21 #include "net/quic/crypto/proof_source.h"
22 #include "net/quic/crypto/proof_verifier.h"
23 #include "net/quic/crypto/quic_crypto_client_config.h"
24 #include "net/quic/crypto/quic_crypto_server_config.h"
25 #include "net/quic/quic_crypto_client_stream.h"
26 #include "net/quic/quic_crypto_server_stream.h"
27
28 #include "webrtc/base/common.h"
29 #include "webrtc/base/gunit.h"
30
31 #include "webrtc/p2p/base/faketransportcontroller.h"
32
33 using net::IPAddressNumber;
34 using net::IPEndPoint;
35 using net::Perspective;
36 using net::ProofVerifyContext;
37 using net::ProofVerifyDetails;
38 using net::QuicByteCount;
39 using net::QuicClock;
40 using net::QuicConfig;
41 using net::QuicConnection;
42 using net::QuicCryptoClientConfig;
43 using net::QuicCryptoServerConfig;
44 using net::QuicCryptoClientStream;
45 using net::QuicCryptoServerStream;
46 using net::QuicCryptoStream;
47 using net::QuicErrorCode;
48 using net::QuicPacketWriter;
49 using net::QuicRandom;
50 using net::QuicServerConfigProtobuf;
51 using net::QuicServerId;
52 using net::QuicStreamId;
53 using net::WriteResult;
54 using net::WriteStatus;
55
56 using cricket::FakeTransportChannel;
57 using cricket::QuicConnectionHelper;
58 using cricket::QuicSession;
59 using cricket::ReliableQuicStream;
60 using cricket::TransportChannel;
61
62 using rtc::Thread;
63
64 // Timeout for running asynchronous operations within unit tests
65 const int kTimeoutMs = 1000;
66 // Testing SpdyPriority value for creating outgoing ReliableQuicStream
67 const uint8 kDefaultPriority = 3;
68 // TExport keying material function
69 const char kExporterLabel[] = "label";
70 const char kExporterContext[] = "context";
71 const size_t kExporterContextLen = sizeof(kExporterContext);
72 // Identifies QUIC server session
73 const QuicServerId kServerId("www.google.com", 443);
74
75 // Used by QuicCryptoServerConfig to provide server credentials, returning a
76 // canned response equal to |success|
77 class FakeProofSource : public net::ProofSource {
78 public:
79 explicit FakeProofSource(bool success) : success_(success) {}
80 ~FakeProofSource() override {}
81
82 // ProofSource override
83 bool GetProof(const net::IPAddressNumber& server_ip,
84 const std::string& hostname,
85 const std::string& server_config,
86 bool ecdsa_ok,
87 const std::vector<std::string>** out_certs,
88 std::string* out_signature,
89 std::string* out_leaf_cert_sct) override {
90 if (success_) {
91 std::vector<std::string>* certs = new std::vector<std::string>();
92 certs->push_back("Certificate 1");
93 certs->push_back("Certificate 2");
94 certs->push_back("Certificate 3");
95 std::string signature("Signature");
96
97 *out_certs = certs;
98 *out_signature = signature;
99 }
100 return success_;
101 }
102
103 private:
104 // Whether or not obtaining proof source succeeds
105 bool success_;
106 };
107
108 // Used by QuicCryptoClientConfig to verify server credentials, returning a
109 // canned response of QUIC_SUCCESS if |success| is true
110 class FakeProofVerifier : public net::ProofVerifier {
111 public:
112 explicit FakeProofVerifier(bool success) : success_(success) {}
113 ~FakeProofVerifier() override {}
114
115 // ProofVerifier override
116 net::QuicAsyncStatus VerifyProof(
117 const std::string& hostname,
118 const std::string& server_config,
119 const std::vector<std::string>& certs,
120 const std::string& cert_sct,
121 const std::string& signature,
122 const net::ProofVerifyContext* verify_context,
123 std::string* error_details,
124 scoped_ptr<net::ProofVerifyDetails>* verify_details,
125 net::ProofVerifierCallback* callback) override {
126 return success_ ? net::QUIC_SUCCESS : net::QUIC_FAILURE;
127 }
128
129 private:
130 // Whether or not proof verification succeeds
131 bool success_;
132 };
133
134 // Writes QUIC packets to a fake transport channel that simulates a network
135 class FakeQuicPacketWriter : public QuicPacketWriter {
136 public:
137 explicit FakeQuicPacketWriter(FakeTransportChannel* fake_channel)
138 : fake_channel_(fake_channel) {}
139
140 virtual ~FakeQuicPacketWriter() {}
141
142 // Sends packets across the network
143 WriteResult WritePacket(const char* buffer,
144 size_t buf_len,
145 const IPAddressNumber& self_address,
146 const IPEndPoint& peer_address) override {
147 rtc::PacketOptions packet_options;
148 int rv = fake_channel_->SendPacket(buffer, buf_len, packet_options, 0);
149 net::WriteStatus status;
150 if (rv > 0) {
151 status = net::WRITE_STATUS_OK;
152 } else if (fake_channel_->GetError() == EWOULDBLOCK) {
153 status = net::WRITE_STATUS_BLOCKED;
154 } else {
155 status = net::WRITE_STATUS_ERROR;
156 }
157 return net::WriteResult(status, rv);
158 }
159
160 // Returns true if the writer buffers and subsequently rewrites data
161 // when an attempt to write results in the underlying socket becoming
162 // write blocked.
163 bool IsWriteBlockedDataBuffered() const override { return true; }
164
165 // Returns true if the network socket is not writable.
166 bool IsWriteBlocked() const override { return !fake_channel_->writable(); }
167
168 // Records that the socket has become writable, for example when an EPOLLOUT
169 // is received or an asynchronous write completes.
170 void SetWritable() override { fake_channel_->SetWritable(true); }
171
172 // Returns the maximum size of the packet which can be written using this
173 // writer for the supplied peer address. This size may actually exceed the
174 // size of a valid QUIC packet.
175 QuicByteCount GetMaxPacketSize(
176 const IPEndPoint& peer_address) const override {
177 return net::kMaxPacketSize;
178 }
179
180 void SetConnection(QuicConnection* connection) { connection_ = connection; }
181
182 void OnWriteComplete(int rv) {
183 DCHECK_NE(rv, -1 /* ERR_IO_PENDING*/);
184 if (rv < 0) {
185 connection_->OnWriteError(rv);
186 }
187 connection_->OnCanWrite();
188 }
189
190 private:
191 FakeTransportChannel* fake_channel_;
192
193 QuicConnection* connection_;
194 };
195
196 // Creates a FakePacketWriter with a given QuicConnection instance
197 class FakePacketWriterFactory : public QuicConnection::PacketWriterFactory {
198 public:
199 explicit FakePacketWriterFactory(FakeTransportChannel* channel)
200 : channel_(channel) {}
201 ~FakePacketWriterFactory() override {}
202
203 QuicPacketWriter* Create(QuicConnection* connection) const override {
204 FakeQuicPacketWriter* writer = new FakeQuicPacketWriter(channel_);
205 writer->SetConnection(connection);
206 return writer;
207 }
208
209 private:
210 FakeTransportChannel* channel_;
211 };
212
213 // Wrapper for QuicSession and transport channel that stores incoming data
214 class QuicSessionForTest : public QuicSession {
215 public:
216 QuicSessionForTest(const net::QuicConfig& config,
217 scoped_ptr<net::QuicConnection> connection,
218 scoped_ptr<FakeTransportChannel> channel)
219 : QuicSession(config, std::move(connection)),
220 channel_(channel.release()) {
221 channel_->SignalReadPacket.connect(
222 this, &QuicSessionForTest::OnChannelReadPacket);
223 }
224
225 // Called when channel has packets to read
226 void OnChannelReadPacket(TransportChannel* channel,
227 const char* data,
228 size_t size,
229 const rtc::PacketTime& packet_time,
230 int flags) {
231 OnReadPacket(data, size);
232 }
233
234 // Called when peer receives incoming stream from another peer
235 void OnIncomingStream(ReliableQuicStream* stream) {
236 stream->SignalDataReceived.connect(this,
237 &QuicSessionForTest::OnDataReceived);
238 last_incoming_stream_ = stream;
239 }
240
241 // Called when peer has data to read from incoming stream
242 void OnDataReceived(net::QuicStreamId id, const char* data, size_t length) {
243 last_received_data_ = std::string(data, length);
244 }
245
246 std::string data() { return last_received_data_; }
247
248 bool has_data() { return data().size() > 0; }
249
250 FakeTransportChannel* channel() { return channel_.get(); }
251
252 ReliableQuicStream* incoming_stream() { return last_incoming_stream_; }
253
254 private:
255 // Transports QUIC packets to/from peer
256 scoped_ptr<FakeTransportChannel> channel_;
257 // Stores data received by peer once it is sent from the other peer
258 std::string last_received_data_ = "";
259 // Handles incoming streams from sender
260 ReliableQuicStream* last_incoming_stream_;
261 };
262
263 // Simulates data transfer between two peers using QUIC
264 class QuicSessionTest : public ::testing::Test,
265 public QuicCryptoClientStream::ProofHandler {
266 public:
267 QuicSessionTest() : quic_helper_(rtc::Thread::Current()) {}
268
269 virtual ~QuicSessionTest() {}
270
271 // Instantiates |client_peer_| and |server_peer_|
272 void CreateClientAndServerSessions();
273
274 scoped_ptr<QuicSessionForTest> CreateSession(
275 scoped_ptr<FakeTransportChannel> channel,
276 Perspective perspective);
277
278 QuicCryptoClientStream* CreateCryptoClientStream(QuicSessionForTest* session,
279 bool handshake_success);
280 QuicCryptoServerStream* CreateCryptoServerStream(QuicSessionForTest* session,
281 bool handshake_success);
282
283 scoped_ptr<QuicConnection> CreateConnection(FakeTransportChannel* channel,
284 Perspective perspective);
285
286 void StartHandshake(bool client_handshake_success,
287 bool server_handshake_success);
288
289 // Test handshake establishment and sending/receiving of data
290 void TestStreamConnection(QuicSessionForTest* from_session,
291 QuicSessionForTest* to_session);
292 // Test that client and server are not connected after handshake failure
293 void TestDisconnectAfterFailedHandshake();
294
295 // QuicCryptoClientStream::ProofHelper overrides.
296 void OnProofValid(
297 const QuicCryptoClientConfig::CachedState& cached) override {}
298 void OnProofVerifyDetailsAvailable(
299 const ProofVerifyDetails& verify_details) override {}
300
301 protected:
302 QuicConnectionHelper quic_helper_;
303 QuicConfig config_;
304 QuicClock clock_;
305
306 scoped_ptr<QuicSessionForTest> client_peer_;
307 scoped_ptr<QuicSessionForTest> server_peer_;
308 };
309
310 // Initializes "client peer" who begins crypto handshake and "server peer" who
311 // establishes encryption with client
312 void QuicSessionTest::CreateClientAndServerSessions() {
313 scoped_ptr<FakeTransportChannel> channel1(
314 new FakeTransportChannel(nullptr, "channel1", 0));
315 scoped_ptr<FakeTransportChannel> channel2(
316 new FakeTransportChannel(nullptr, "channel2", 0));
317
318 // Prevent channel1->OnReadPacket and channel2->OnReadPacket from calling
319 // themselves in a loop, which causes to future packets to be recursively
320 // consumed while the current thread blocks consumption of current ones
321 channel2->SetAsync(true);
322
323 // Configure peers to send packets to each other
324 channel1->Connect();
325 channel2->Connect();
326 channel1->SetDestination(channel2.get());
327
328 client_peer_ = CreateSession(std::move(channel1), Perspective::IS_CLIENT);
329 server_peer_ = CreateSession(std::move(channel2), Perspective::IS_SERVER);
330 }
331
332 scoped_ptr<QuicSessionForTest> QuicSessionTest::CreateSession(
333 scoped_ptr<FakeTransportChannel> channel,
334 Perspective perspective) {
335 scoped_ptr<QuicConnection> quic_connection =
336 CreateConnection(channel.get(), perspective);
337 return scoped_ptr<QuicSessionForTest>(new QuicSessionForTest(
338 config_, std::move(quic_connection), std::move(channel)));
339 }
340
341 QuicCryptoClientStream* QuicSessionTest::CreateCryptoClientStream(
342 QuicSessionForTest* session,
343 bool handshake_success) {
344 QuicCryptoClientConfig* client_config =
345 new QuicCryptoClientConfig(new FakeProofVerifier(handshake_success));
346 return new QuicCryptoClientStream(
347 kServerId, session, new ProofVerifyContext(), client_config, this);
348 }
349
350 QuicCryptoServerStream* QuicSessionTest::CreateCryptoServerStream(
351 QuicSessionForTest* session,
352 bool handshake_success) {
353 QuicCryptoServerConfig* server_config =
354 new QuicCryptoServerConfig("TESTING", QuicRandom::GetInstance(),
355 new FakeProofSource(handshake_success));
356 // Provide server with serialized config string to prove ownership
357 QuicCryptoServerConfig::ConfigOptions options;
358 QuicServerConfigProtobuf* primary_config = server_config->GenerateConfig(
359 QuicRandom::GetInstance(), &clock_, options);
360 server_config->AddConfig(primary_config, clock_.WallNow());
361 return new QuicCryptoServerStream(server_config, session);
362 }
363
364 scoped_ptr<QuicConnection> QuicSessionTest::CreateConnection(
365 FakeTransportChannel* channel,
366 Perspective perspective) {
367 FakePacketWriterFactory writer_factory(channel);
368
369 IPAddressNumber ip(net::kIPv4AddressSize, 0);
370
371 return scoped_ptr<QuicConnection>(new QuicConnection(
372 0, net::IPEndPoint(ip, 0), &quic_helper_, writer_factory,
373 true /* owns_writer */, perspective, net::QuicSupportedVersions()));
374 }
375
376 void QuicSessionTest::StartHandshake(bool client_handshake_success,
377 bool server_handshake_success) {
378 server_peer_->StartServerHandshake(
379 CreateCryptoServerStream(server_peer_.get(), server_handshake_success));
380 client_peer_->StartClientHandshake(
381 CreateCryptoClientStream(client_peer_.get(), client_handshake_success));
382 }
383
384 void QuicSessionTest::TestStreamConnection(QuicSessionForTest* from_session,
385 QuicSessionForTest* to_session) {
386 // Wait for crypto handshake to finish then check if encryption established
387 ASSERT_TRUE_WAIT(from_session->IsCryptoHandshakeConfirmed() &&
388 to_session->IsCryptoHandshakeConfirmed(),
389 kTimeoutMs);
390
391 EXPECT_TRUE(from_session->IsEncryptionEstablished());
392 EXPECT_TRUE(to_session->IsEncryptionEstablished());
393
394 string from_out;
395 string to_out;
396
397 bool from_success = from_session->ExportKeyingMaterial(
398 kExporterLabel, kExporterContext, kExporterContextLen, &from_out);
399 EXPECT_TRUE(from_success);
400 bool to_success = to_session->ExportKeyingMaterial(
401 kExporterLabel, kExporterContext, kExporterContextLen, &to_out);
402 EXPECT_TRUE(to_success);
403
404 if (!from_success || !to_success) {
405 return;
406 }
407
408 EXPECT_EQ(from_out.size(), kExporterContextLen);
409 EXPECT_EQ(0, from_out.compare(to_out));
410
411 // Now we can establish encrypted outgoing stream
412 ReliableQuicStream* outgoing_stream =
413 from_session->CreateOutgoingDynamicStream(kDefaultPriority);
414 ASSERT_NE(nullptr, outgoing_stream);
415 EXPECT_TRUE(from_session->HasOpenDynamicStreams());
416
417 outgoing_stream->SignalDataReceived.connect(
418 from_session, &QuicSessionForTest::OnDataReceived);
419 to_session->SignalIncomingStream.connect(
420 to_session, &QuicSessionForTest::OnIncomingStream);
421
422 // Send a test message from peer 1 to peer 2
423 const std::string kTestMessage = "Hello, World!";
424 outgoing_stream->Write(kTestMessage);
425
426 // Wait for peer 2 to receive messages
427 ASSERT_TRUE_WAIT(to_session->has_data(), kTimeoutMs);
428
429 ReliableQuicStream* incoming = to_session->incoming_stream();
430 ASSERT_TRUE(incoming);
431 EXPECT_TRUE(to_session->HasOpenDynamicStreams());
432
433 EXPECT_EQ(0, to_session->data().compare(kTestMessage));
434
435 // Send a test message from peer 2 to peer 1
436 const std::string kTestResponse = "Response";
437 incoming->Write(kTestResponse);
438
439 // Wait for peer 1 to receive messages
440 ASSERT_TRUE_WAIT(from_session->has_data(), kTimeoutMs);
441
442 EXPECT_EQ(0, from_session->data().compare(kTestResponse));
443 }
444
445 // Client and server should disconnect when proof verification fails
446 void QuicSessionTest::TestDisconnectAfterFailedHandshake() {
447 EXPECT_TRUE_WAIT(!client_peer_->connection()->connected(), kTimeoutMs);
448 EXPECT_TRUE_WAIT(!server_peer_->connection()->connected(), kTimeoutMs);
449
450 EXPECT_FALSE(client_peer_->IsEncryptionEstablished());
451 EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed());
452
453 EXPECT_FALSE(server_peer_->IsEncryptionEstablished());
454 EXPECT_FALSE(server_peer_->IsCryptoHandshakeConfirmed());
455 }
456
457 TEST_F(QuicSessionTest, ClientToServer) {
458 CreateClientAndServerSessions();
459 StartHandshake(true, true);
460 TestStreamConnection(client_peer_.get(), server_peer_.get());
461 }
462
463 TEST_F(QuicSessionTest, ServerToClient) {
464 CreateClientAndServerSessions();
465 StartHandshake(true, true);
466 TestStreamConnection(server_peer_.get(), client_peer_.get());
467 }
468
469 // Make client fail to verify proof from server
470 TEST_F(QuicSessionTest, ClientRejection) {
471 CreateClientAndServerSessions();
472 StartHandshake(false, true);
473 TestDisconnectAfterFailedHandshake();
474 }
475
476 // Make server fail to give proof to client
477 TEST_F(QuicSessionTest, ServerRejection) {
478 CreateClientAndServerSessions();
479 StartHandshake(true, false);
480 TestDisconnectAfterFailedHandshake();
481 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698