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

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

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

Powered by Google App Engine
This is Rietveld 408576698