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

Side by Side Diff: net/quic/quartc/quartc_session_test.cc

Issue 2324833004: Define Stable API for WebRTC/Quartc (Closed)
Patch Set: Fix the IOS simulator and merge. Created 4 years, 1 month 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
« no previous file with comments | « net/quic/quartc/quartc_session_interface.h ('k') | net/quic/quartc/quartc_stream.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2016 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/quartc/quartc_session.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "net/base/ip_endpoint.h"
12 #include "net/quic/core/crypto/crypto_server_config_protobuf.h"
13 #include "net/quic/core/crypto/proof_source.h"
14 #include "net/quic/core/crypto/proof_verifier.h"
15 #include "net/quic/core/crypto/quic_crypto_client_config.h"
16 #include "net/quic/core/crypto/quic_crypto_server_config.h"
17 #include "net/quic/core/crypto/quic_random.h"
18 #include "net/quic/core/quic_crypto_client_stream.h"
19 #include "net/quic/core/quic_crypto_server_stream.h"
20 #include "net/quic/core/quic_simple_buffer_allocator.h"
21 #include "net/quic/quartc/quartc_alarm_factory.h"
22 #include "net/quic/quartc/quartc_packet_writer.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace net {
26 namespace test {
27 namespace {
28
29 static const char kExporterLabel[] = "label";
30 static const uint8_t kExporterContext[] = "context";
31 static const size_t kExporterContextLen = sizeof(kExporterContext);
32 static const size_t kOutputKeyLength = 20;
33 static QuartcStreamInterface::WriteParameters kDefaultWriteParam;
34 static QuartcSessionInterface::OutgoingStreamParameters kDefaultStreamParam;
35 static QuicByteCount kDefaultMaxPacketSize = 1200;
36
37 // Use the MessageLoop to simulate the asynchronous P2P communication. The
38 // RunLoop is used for handling the posted tasks.
39 void RunLoopWithTimeout() {
40 base::RunLoop run_loop;
41 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
42 FROM_HERE, run_loop.QuitClosure(),
43 base::TimeDelta::FromMilliseconds(200));
44 run_loop.Run();
45 }
46
47 // Used by QuicCryptoServerConfig to provide server credentials, returning a
48 // canned response equal to |success|.
49 class FakeProofSource : public net::ProofSource {
50 public:
51 explicit FakeProofSource(bool success) : success_(success) {}
52
53 // ProofSource override.
54 bool GetProof(const IPAddress& server_ip,
55 const std::string& hostname,
56 const std::string& server_config,
57 net::QuicVersion quic_version,
58 base::StringPiece chlo_hash,
59 scoped_refptr<net::ProofSource::Chain>* out_certs,
60 std::string* out_signature,
61 std::string* out_leaf_cert_sct) override {
62 if (success_) {
63 std::vector<std::string> certs;
64 certs.push_back("Required to establish handshake");
65 *out_certs = new ProofSource::Chain(certs);
66 *out_signature = "Signature";
67 *out_leaf_cert_sct = "Time";
68 }
69 return success_;
70 }
71
72 void GetProof(const net::IPAddress& server_ip,
73 const std::string& hostname,
74 const std::string& server_config,
75 net::QuicVersion quic_version,
76 base::StringPiece chlo_hash,
77 std::unique_ptr<Callback> callback) override {
78 LOG(INFO) << "GetProof() providing dummy credentials for insecure QUIC";
79 }
80
81 private:
82 // Whether or not obtaining proof source succeeds.
83 bool success_;
84 };
85
86 // Used by QuicCryptoClientConfig to verify server credentials, returning a
87 // canned response of QUIC_SUCCESS if |success| is true.
88 class FakeProofVerifier : public net::ProofVerifier {
89 public:
90 explicit FakeProofVerifier(bool success) : success_(success) {}
91
92 // ProofVerifier override
93 net::QuicAsyncStatus VerifyProof(
94 const std::string& hostname,
95 const uint16_t port,
96 const std::string& server_config,
97 net::QuicVersion quic_version,
98 base::StringPiece chlo_hash,
99 const std::vector<std::string>& certs,
100 const std::string& cert_sct,
101 const std::string& signature,
102 const ProofVerifyContext* context,
103 std::string* error_details,
104 std::unique_ptr<net::ProofVerifyDetails>* verify_details,
105 std::unique_ptr<net::ProofVerifierCallback> callback) override {
106 return success_ ? net::QUIC_SUCCESS : net::QUIC_FAILURE;
107 }
108
109 net::QuicAsyncStatus VerifyCertChain(
110 const std::string& hostname,
111 const std::vector<std::string>& certs,
112 const net::ProofVerifyContext* context,
113 std::string* error_details,
114 std::unique_ptr<net::ProofVerifyDetails>* details,
115 std::unique_ptr<net::ProofVerifierCallback> callback) override {
116 LOG(INFO) << "VerifyProof() ignoring credentials and returning success";
117 return success_ ? net::QUIC_SUCCESS : net::QUIC_FAILURE;
118 }
119
120 private:
121 // Whether or not proof verification succeeds.
122 bool success_;
123 };
124
125 // Used by the FakeTransportChannel.
126 class FakeTransportChannelObserver {
127 public:
128 // Called when the other peer is trying to send message.
129 virtual void OnTransportChannelReadPacket(const std::string& data) = 0;
130 };
131
132 // Simulate the P2P communication transport. Used by the
133 // QuartcSessionInterface::Transport.
134 class FakeTransportChannel {
135 public:
136 void SetDestination(FakeTransportChannel* dest) {
137 if (!dest_) {
138 dest_ = dest;
139 dest_->SetDestination(this);
140 }
141 }
142
143 int SendPacket(const char* data, size_t len) {
144 // If the destination is not set.
145 if (!dest_) {
146 return -1;
147 }
148 if (async_) {
149 base::ThreadTaskRunnerHandle::Get()->PostTask(
150 FROM_HERE,
151 base::Bind(&FakeTransportChannel::send, base::Unretained(this),
152 std::string(data, len)));
153 } else {
154 send(std::string(data, len));
155 }
156 return static_cast<int>(len);
157 }
158
159 void send(const std::string& data) {
160 DCHECK(dest_);
161 DCHECK(dest_->observer());
162 dest_->observer()->OnTransportChannelReadPacket(data);
163 }
164
165 FakeTransportChannelObserver* observer() { return observer_; }
166
167 void SetObserver(FakeTransportChannelObserver* observer) {
168 observer_ = observer;
169 }
170
171 void SetAsync(bool async) { async_ = async; }
172
173 private:
174 // The writing destination of this channel.
175 FakeTransportChannel* dest_ = nullptr;
176 // The observer of this channel. Called when the received the data.
177 FakeTransportChannelObserver* observer_ = nullptr;
178 // If async, will send packets by "Post"-ing to message queue instead of
179 // synchronously "Send"-ing.
180 bool async_ = false;
181 };
182
183 // Used by the QuartcPacketWriter.
184 class FakeTransport : public QuartcSessionInterface::PacketTransport {
185 public:
186 FakeTransport(FakeTransportChannel* channel) : channel_(channel) {}
187
188 bool CanWrite() override { return true; }
189
190 int Write(const char* buffer, size_t buf_len) override {
191 DCHECK(channel_);
192 return channel_->SendPacket(buffer, buf_len);
193 }
194
195 private:
196 FakeTransportChannel* channel_;
197 };
198
199 class FakeQuartcSessionDelegate : public QuartcSessionInterface::Delegate {
200 public:
201 FakeQuartcSessionDelegate(QuartcStreamInterface::Delegate* stream_delegate)
202 : stream_delegate_(stream_delegate) {}
203 // Called when peers have established forward-secure encryption
204 void OnCryptoHandshakeComplete() override {
205 LOG(INFO) << "Crypto handshake complete!";
206 }
207 // Called when connection closes locally, or remotely by peer.
208 void OnConnectionClosed(int error_code, bool from_remote) override {
209 connected_ = false;
210 }
211 // Called when an incoming QUIC stream is created.
212 void OnIncomingStream(QuartcStreamInterface* quartc_stream) override {
213 last_incoming_stream_ = quartc_stream;
214 last_incoming_stream_->SetDelegate(stream_delegate_);
215 }
216
217 QuartcStreamInterface* incoming_stream() { return last_incoming_stream_; }
218
219 bool connected() { return connected_; }
220
221 private:
222 QuartcStreamInterface* last_incoming_stream_;
223 bool connected_ = true;
224 QuartcStream::Delegate* stream_delegate_;
225 };
226
227 class FakeQuartcStreamDelegate : public QuartcStreamInterface::Delegate {
228 public:
229 void OnReceived(QuartcStreamInterface* stream,
230 const char* data,
231 size_t size) override {
232 last_received_data_ = std::string(data, size);
233 }
234
235 void OnClose(QuartcStreamInterface* stream, int error_code) override {}
236
237 void OnBufferedAmountDecrease(QuartcStreamInterface* stream) override {}
238
239 std::string data() { return last_received_data_; }
240
241 private:
242 std::string last_received_data_;
243 };
244
245 class QuartcSessionForTest : public QuartcSession,
246 public FakeTransportChannelObserver {
247 public:
248 QuartcSessionForTest(std::unique_ptr<QuicConnection> connection,
249 const QuicConfig& config,
250 const std::string& remote_fingerprint_value,
251 Perspective perspective,
252 QuicConnectionHelperInterface* helper)
253 : QuartcSession(std::move(connection),
254 config,
255 remote_fingerprint_value,
256 perspective,
257 helper) {
258 stream_delegate_.reset(new FakeQuartcStreamDelegate);
259 session_delegate_.reset(
260 new FakeQuartcSessionDelegate(stream_delegate_.get()));
261
262 SetDelegate(session_delegate_.get());
263 }
264
265 // QuartcPacketWriter override.
266 void OnTransportChannelReadPacket(const std::string& data) override {
267 OnTransportReceived(data.c_str(), data.length());
268 }
269
270 std::string data() { return stream_delegate_->data(); }
271
272 bool has_data() { return !data().empty(); }
273
274 FakeQuartcSessionDelegate* session_delegate() {
275 return session_delegate_.get();
276 }
277
278 FakeQuartcStreamDelegate* stream_delegate() { return stream_delegate_.get(); }
279
280 private:
281 std::unique_ptr<FakeQuartcStreamDelegate> stream_delegate_;
282 std::unique_ptr<FakeQuartcSessionDelegate> session_delegate_;
283 };
284
285 class QuartcSessionTest : public ::testing::Test,
286 public QuicConnectionHelperInterface {
287 public:
288 ~QuartcSessionTest() override {
289 // Check if there is message left in the message queue so that it won't
290 // affect other tests.
291 RunLoopWithTimeout();
292 }
293
294 void Init() {
295 client_channel_.reset(new FakeTransportChannel);
296 server_channel_.reset(new FakeTransportChannel);
297 // Make the channel asynchronous so that two peer will not keep calling each
298 // other when they exchange information.
299 client_channel_->SetAsync(true);
300 client_channel_->SetDestination(server_channel_.get());
301
302 client_transport_.reset(new FakeTransport(client_channel_.get()));
303 server_transport_.reset(new FakeTransport(server_channel_.get()));
304
305 client_writer_.reset(
306 new QuartcPacketWriter(client_transport_.get(), kDefaultMaxPacketSize));
307 server_writer_.reset(
308 new QuartcPacketWriter(server_transport_.get(), kDefaultMaxPacketSize));
309 }
310
311 // The parameters are used to control whether the handshake will success or
312 // not.
313 void CreateClientAndServerSessions(bool client_handshake_success = true,
314 bool server_handshake_success = true) {
315 Init();
316 client_peer_ = CreateSession(Perspective::IS_CLIENT);
317 server_peer_ = CreateSession(Perspective::IS_SERVER);
318
319 client_channel_->SetObserver(client_peer_.get());
320 server_channel_->SetObserver(server_peer_.get());
321
322 client_peer_->SetClientCryptoConfig(
323 new QuicCryptoClientConfig(std::unique_ptr<ProofVerifier>(
324 new FakeProofVerifier(client_handshake_success))));
325
326 QuicCryptoServerConfig* server_config = new QuicCryptoServerConfig(
327 "TESTING", QuicRandom::GetInstance(),
328 std::unique_ptr<FakeProofSource>(
329 new FakeProofSource(server_handshake_success)));
330 // Provide server with serialized config string to prove ownership.
331 QuicCryptoServerConfig::ConfigOptions options;
332 std::unique_ptr<QuicServerConfigProtobuf> primary_config(
333 server_config->GenerateConfig(QuicRandom::GetInstance(), &clock_,
334 options));
335 std::unique_ptr<CryptoHandshakeMessage> message(
336 server_config->AddConfig(std::move(primary_config), clock_.WallNow()));
337
338 server_peer_->SetServerCryptoConfig(server_config);
339 }
340
341 std::unique_ptr<QuartcSessionForTest> CreateSession(Perspective perspective) {
342 std::unique_ptr<QuicConnection> quic_connection =
343 CreateConnection(perspective);
344 std::string remote_fingerprint_value = "value";
345 QuicConfig config;
346 return std::unique_ptr<QuartcSessionForTest>(
347 new QuartcSessionForTest(std::move(quic_connection), config,
348 remote_fingerprint_value, perspective, this));
349 }
350
351 std::unique_ptr<QuicConnection> CreateConnection(Perspective perspective) {
352 QuartcPacketWriter* writer = perspective == Perspective::IS_CLIENT
353 ? client_writer_.get()
354 : server_writer_.get();
355 IPAddress ip(0, 0, 0, 0);
356 bool owns_writer = false;
357 alarm_factory_.reset(new QuartcAlarmFactory(
358 base::ThreadTaskRunnerHandle::Get().get(), GetClock()));
359 return std::unique_ptr<QuicConnection>(new QuicConnection(
360 0, IPEndPoint(ip, 0), this /*QuicConnectionHelperInterface*/,
361 alarm_factory_.get(), writer, owns_writer, perspective,
362 AllSupportedVersions()));
363 }
364 void StartHandshake() {
365 server_peer_->StartCryptoHandshake();
366 client_peer_->StartCryptoHandshake();
367 RunLoopWithTimeout();
368 }
369
370 // Test handshake establishment and sending/receiving of data for two
371 // directions.
372 void TestStreamConnection() {
373 ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed() &&
374 client_peer_->IsCryptoHandshakeConfirmed());
375 ASSERT_TRUE(server_peer_->IsEncryptionEstablished());
376 ASSERT_TRUE(client_peer_->IsEncryptionEstablished());
377
378 uint8_t server_key[kOutputKeyLength];
379 uint8_t client_key[kOutputKeyLength];
380 bool use_context = true;
381 bool server_success = server_peer_->ExportKeyingMaterial(
382 kExporterLabel, kExporterContext, kExporterContextLen, use_context,
383 server_key, kOutputKeyLength);
384 ASSERT_TRUE(server_success);
385 bool client_success = client_peer_->ExportKeyingMaterial(
386 kExporterLabel, kExporterContext, kExporterContextLen, use_context,
387 client_key, kOutputKeyLength);
388 ASSERT_TRUE(client_success);
389 EXPECT_EQ(0, memcmp(server_key, client_key, sizeof(server_key)));
390
391 // Now we can establish encrypted outgoing stream.
392 QuartcStreamInterface* outgoing_stream =
393 server_peer_->CreateOutgoingStream(kDefaultStreamParam);
394 ASSERT_NE(nullptr, outgoing_stream);
395 EXPECT_TRUE(server_peer_->HasOpenDynamicStreams());
396
397 outgoing_stream->SetDelegate(server_peer_->stream_delegate());
398
399 // Send a test message from peer 1 to peer 2.
400 const char kTestMessage[] = "Hello";
401 outgoing_stream->Write(kTestMessage, strlen(kTestMessage),
402 kDefaultWriteParam);
403 RunLoopWithTimeout();
404
405 // Wait for peer 2 to receive messages.
406 ASSERT_TRUE(client_peer_->has_data());
407
408 QuartcStreamInterface* incoming =
409 client_peer_->session_delegate()->incoming_stream();
410 ASSERT_TRUE(incoming);
411 EXPECT_TRUE(client_peer_->HasOpenDynamicStreams());
412
413 EXPECT_EQ(client_peer_->data(), kTestMessage);
414 // Send a test message from peer 2 to peer 1.
415 const char kTestResponse[] = "Response";
416 incoming->Write(kTestResponse, strlen(kTestResponse), kDefaultWriteParam);
417 RunLoopWithTimeout();
418 // Wait for peer 1 to receive messages.
419 ASSERT_TRUE(server_peer_->has_data());
420
421 EXPECT_EQ(server_peer_->data(), kTestResponse);
422 }
423
424 // Test that client and server are not connected after handshake failure.
425 void TestDisconnectAfterFailedHandshake() {
426 EXPECT_TRUE(!client_peer_->session_delegate()->connected());
427 EXPECT_TRUE(!server_peer_->session_delegate()->connected());
428
429 EXPECT_FALSE(client_peer_->IsEncryptionEstablished());
430 EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed());
431
432 EXPECT_FALSE(server_peer_->IsEncryptionEstablished());
433 EXPECT_FALSE(server_peer_->IsCryptoHandshakeConfirmed());
434 }
435
436 const QuicClock* GetClock() const override { return &clock_; }
437
438 QuicRandom* GetRandomGenerator() override {
439 return QuicRandom::GetInstance();
440 }
441
442 QuicBufferAllocator* GetBufferAllocator() override {
443 return &buffer_allocator_;
444 }
445
446 protected:
447 std::unique_ptr<QuicAlarmFactory> alarm_factory_;
448 SimpleBufferAllocator buffer_allocator_;
449 QuicClock clock_;
450
451 std::unique_ptr<FakeTransportChannel> client_channel_;
452 std::unique_ptr<FakeTransportChannel> server_channel_;
453 std::unique_ptr<FakeTransport> client_transport_;
454 std::unique_ptr<FakeTransport> server_transport_;
455 std::unique_ptr<QuartcPacketWriter> client_writer_;
456 std::unique_ptr<QuartcPacketWriter> server_writer_;
457 std::unique_ptr<QuartcSessionForTest> client_peer_;
458 std::unique_ptr<QuartcSessionForTest> server_peer_;
459 };
460
461 TEST_F(QuartcSessionTest, StreamConnection) {
462 CreateClientAndServerSessions();
463 StartHandshake();
464 TestStreamConnection();
465 }
466
467 TEST_F(QuartcSessionTest, ClientRejection) {
468 CreateClientAndServerSessions(false /*client_handshake_success*/,
469 true /*server_handshake_success*/);
470 StartHandshake();
471 TestDisconnectAfterFailedHandshake();
472 }
473
474 TEST_F(QuartcSessionTest, ServerRejection) {
475 CreateClientAndServerSessions(true /*client_handshake_success*/,
476 false /*server_handshake_success*/);
477 StartHandshake();
478 TestDisconnectAfterFailedHandshake();
479 }
480
481 // Test that data streams are not created before handshake.
482 TEST_F(QuartcSessionTest, CannotCreateDataStreamBeforeHandshake) {
483 CreateClientAndServerSessions();
484 EXPECT_EQ(nullptr, server_peer_->CreateOutgoingStream(kDefaultStreamParam));
485 EXPECT_EQ(nullptr, client_peer_->CreateOutgoingStream(kDefaultStreamParam));
486 }
487
488 TEST_F(QuartcSessionTest, CloseQuartcStream) {
489 CreateClientAndServerSessions();
490 StartHandshake();
491 ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed() &&
492 server_peer_->IsCryptoHandshakeConfirmed());
493 QuartcStreamInterface* stream =
494 client_peer_->CreateOutgoingStream(kDefaultStreamParam);
495 ASSERT_NE(nullptr, stream);
496
497 uint32_t id = stream->stream_id();
498 EXPECT_FALSE(client_peer_->IsClosedStream(id));
499 stream->SetDelegate(client_peer_->stream_delegate());
500 stream->Close();
501 RunLoopWithTimeout();
502 EXPECT_TRUE(client_peer_->IsClosedStream(id));
503 }
504
505 } // namespace
506 } // namespace test
507 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/quartc/quartc_session_interface.h ('k') | net/quic/quartc/quartc_stream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698