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

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

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

Powered by Google App Engine
This is Rietveld 408576698