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

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

Issue 2324833004: Define Stable API for WebRTC/Quartc (Closed)
Patch Set: Create Quartc API 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) 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/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 // Testing SpdyPriority value for creating outgoing ReliableQuicStream.
28 // static const uint8_t kDefaultPriority = 3;
29 // TExport keying material function
30 static const char kExporterLabel[] = "label";
31 static const uint8_t kExporterContext[] = "context";
32 static const size_t kExporterContextLen = sizeof(kExporterContext);
33 static const size_t kOutputKeyLength = 20;
34 static QuartcReliableStreamInterface::WriteParameters kDefaultWriteParam;
35 static QuartcSessionInterface::OutgoingStreamParameters kDefaultStreamParam;
36
37 // We use the MessageLoop to simulate the synchronous 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::Transport {
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 void SetObserver(Observer* observer) override { observer_ = observer; }
207
208 private:
209 FakeTransportChannel* channel_;
210 // QuartcSessionInterface::Transport::Observer
211 Observer* observer_;
212 };
213
214 class FakeQuartcSessionObserver : public QuartcSessionInterface::Observer {
215 public:
216 FakeQuartcSessionObserver(QuartcReliableStream::Observer* stream_observer)
217 : stream_observer_(stream_observer) {}
218 // Called when peers have established forward-secure encryption
219 void OnCryptoHandshakeComplete() override {
220 LOG(INFO) << "Crypto handshake complete!";
221 }
222 // Called when connection closes locally, or remotely by peer.
223 void OnConnectionClosed(int error_code, bool from_remote) override {
224 connected_ = false;
225 }
226 // Called when an incoming QUIC stream is created.
227 void OnIncomingStream(QuartcReliableStreamInterface* quartc_stream) override {
228 last_incoming_stream_ = quartc_stream;
229 last_incoming_stream_->SetObserver(stream_observer_);
230 }
231
232 QuartcReliableStreamInterface* incoming_stream() {
233 return last_incoming_stream_;
234 }
235
236 bool connected() { return connected_; }
237
238 private:
239 QuartcReliableStreamInterface* last_incoming_stream_;
240 bool connected_ = true;
241 QuartcReliableStream::Observer* stream_observer_;
242 };
243
244 class FakeQuartcReliableStreamObserver
245 : public QuartcReliableStreamInterface::Observer {
246 public:
247 void OnReceived(QuartcReliableStreamInterface* stream,
248 const char* data,
249 size_t size) override {
250 last_received_data_ = std::string(data, size);
251 }
252
253 void OnClose(QuartcReliableStreamInterface* stream, int error_code) override {
254 }
255
256 void OnBufferedAmountChanged(QuartcReliableStreamInterface* stream) override {
257 }
258
259 std::string data() { return last_received_data_; }
260
261 private:
262 std::string last_received_data_;
263 };
264
265 class QuartcSessionForTest : public QuartcSession,
266 public FakeTransportChannelObserver {
267 public:
268 QuartcSessionForTest(std::unique_ptr<QuicConnection> connection,
269 const QuicConfig& config,
270 const std::string& remote_finger_print_value,
271 Perspective perspective)
272 : QuartcSession(std::move(connection),
273 config,
274 remote_finger_print_value,
275 perspective) {
276 stream_observer_.reset(new FakeQuartcReliableStreamObserver);
277 session_observer_.reset(
278 new FakeQuartcSessionObserver(stream_observer_.get()));
279
280 SetObserver(session_observer_.get());
281 }
282
283 // QuartcPacketWriter override.
284 void OnTransportChannelReadPacket(const std::string& data) override {
285 OnReceived(data.c_str(), data.length());
286 }
287
288 std::string data() { return stream_observer_->data(); }
289
290 bool has_data() { return !data().empty(); }
291
292 FakeQuartcSessionObserver* session_observer() {
293 return session_observer_.get();
294 }
295
296 FakeQuartcReliableStreamObserver* stream_observer() {
297 return stream_observer_.get();
298 }
299
300 private:
301 std::unique_ptr<FakeQuartcReliableStreamObserver> stream_observer_;
302 std::unique_ptr<FakeQuartcSessionObserver> session_observer_;
303 };
304
305 class QuartcSessionTest : public ::testing::Test {
306 public:
307 ~QuartcSessionTest() override {}
308
309 void Init() {
310 helper_.reset(new QuartcConnectionHelper);
311 clock_.reset(new QuicClock);
312 config_.reset(new QuicConfig);
313
314 client_channel_.reset(new FakeTransportChannel);
315 server_channel_.reset(new FakeTransportChannel);
316 // Make the channel synchronous so that two peer will not keep calling each
skvlad-chromium 2016/09/22 01:54:26 "asynchronous"?
zhihuang1 2016/09/22 18:53:52 Yes. Silly mistake. :)
317 // other when they exchange information.
318 client_channel_->SetAsync(true);
319 client_channel_->SetDestination(server_channel_.get());
320
321 client_transport_.reset(new FakeTransport(client_channel_.get()));
322 server_transport_.reset(new FakeTransport(server_channel_.get()));
323
324 client_writer_.reset(new QuartcPacketWriter(client_transport_.get()));
325 server_writer_.reset(new QuartcPacketWriter(server_transport_.get()));
326 }
327
328 // The parameters are used to control whether the handshake will success or
329 // not.
330 void CreateClientAndServerSessions(bool client_handshake_success = true,
331 bool server_handshake_success = true) {
332 Init();
333 client_peer_ = CreateSession(Perspective::IS_CLIENT);
334 server_peer_ = CreateSession(Perspective::IS_SERVER);
335
336 client_peer_->SetTransport(client_transport_.get());
337 server_peer_->SetTransport(server_transport_.get());
338
339 client_channel_->SetObserver(client_peer_.get());
340 server_channel_->SetObserver(server_peer_.get());
341
342 client_peer_->SetClientCryptoConfig(
343 new QuicCryptoClientConfig(std::unique_ptr<ProofVerifier>(
344 new FakeProofVerifier(client_handshake_success))));
345
346 QuicCryptoServerConfig* server_config = new QuicCryptoServerConfig(
347 "TESTING", QuicRandom::GetInstance(),
348 std::unique_ptr<FakeProofSource>(
349 new FakeProofSource(server_handshake_success)));
350 // Provide server with serialized config string to prove ownership.
351 QuicCryptoServerConfig::ConfigOptions options;
352 QuicServerConfigProtobuf* primary_config = server_config->GenerateConfig(
353 QuicRandom::GetInstance(), clock_.get(), options);
354 server_config->AddConfig(primary_config, clock_->WallNow());
355
356 server_peer_->SetServerCryptoConfig(server_config);
357 }
358
359 std::unique_ptr<QuartcSessionForTest> CreateSession(Perspective perspective) {
360 std::unique_ptr<QuicConnection> quic_connection =
361 CreateConnection(perspective);
362 std::string remote_finger_print_value = "value";
363 return std::unique_ptr<QuartcSessionForTest>(
364 new QuartcSessionForTest(std::move(quic_connection), *(config_.get()),
365 remote_finger_print_value, perspective));
366 }
367
368 std::unique_ptr<QuicConnection> CreateConnection(Perspective perspective) {
369 QuartcPacketWriter* writer = perspective == Perspective::IS_CLIENT
370 ? client_writer_.get()
371 : server_writer_.get();
372 IPAddress ip(0, 0, 0, 0);
373 bool owns_writer = false;
374 alarm_factory_.reset(new QuartcAlarmFactory(
375 base::ThreadTaskRunnerHandle::Get().get(), helper_->GetClock()));
376 return std::unique_ptr<QuicConnection>(new QuicConnection(
377 0, IPEndPoint(ip, 0), helper_.get(), alarm_factory_.get(), writer,
378 owns_writer, perspective, AllSupportedVersions()));
379 }
380 void StartHandshake() {
381 server_peer_->StartCryptoHandshake();
382 client_peer_->StartCryptoHandshake();
383 RunLoopWithTimeout();
384 }
385
386 // Test handshake establishment and sending/receiving of data for two
387 // directions.
388 void TestStreamConnection() {
389 ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed() &&
390 client_peer_->IsCryptoHandshakeConfirmed());
391 ASSERT_TRUE(server_peer_->IsEncryptionEstablished());
392 ASSERT_TRUE(client_peer_->IsEncryptionEstablished());
393
394 uint8_t server_key[kOutputKeyLength];
395 uint8_t client_key[kOutputKeyLength];
396 bool server_success = server_peer_->ExportKeyingMaterial(
397 kExporterLabel, kExporterContext, kExporterContextLen, server_key,
398 kOutputKeyLength);
399 ASSERT_TRUE(server_success);
400 bool client_success = client_peer_->ExportKeyingMaterial(
401 kExporterLabel, kExporterContext, kExporterContextLen, client_key,
402 kOutputKeyLength);
403 ASSERT_TRUE(client_success);
404 EXPECT_EQ(0, memcmp(server_key, client_key, sizeof(server_key)));
405
406 // Now we can establish encrypted outgoing stream.
407 QuartcReliableStreamInterface* outgoing_stream =
408 server_peer_->CreateOutgoingStream(kDefaultStreamParam);
409 ASSERT_NE(nullptr, outgoing_stream);
410 EXPECT_TRUE(server_peer_->HasOpenDynamicStreams());
411
412 outgoing_stream->SetObserver(server_peer_->stream_observer());
413
414 // Send a test message from peer 1 to peer 2.
415 const char kTestMessage[] = "Hello";
416 outgoing_stream->Write(kTestMessage, strlen(kTestMessage),
417 kDefaultWriteParam);
418 RunLoopWithTimeout();
419
420 // Wait for peer 2 to receive messages.
421 ASSERT_TRUE(client_peer_->has_data());
422
423 QuartcReliableStreamInterface* incoming =
424 client_peer_->session_observer()->incoming_stream();
425 ASSERT_TRUE(incoming);
426 EXPECT_TRUE(client_peer_->HasOpenDynamicStreams());
427
428 EXPECT_EQ(client_peer_->data(), kTestMessage);
429 // Send a test message from peer 2 to peer 1.
430 const char kTestResponse[] = "Response";
431 incoming->Write(kTestResponse, strlen(kTestResponse), kDefaultWriteParam);
432 RunLoopWithTimeout();
433 // Wait for peer 1 to receive messages.
434 ASSERT_TRUE(server_peer_->has_data());
435
436 EXPECT_EQ(server_peer_->data(), kTestResponse);
437 }
438
439 // Test that client and server are not connected after handshake failure.
440 void TestDisconnectAfterFailedHandshake() {
441 EXPECT_TRUE(!client_peer_->session_observer()->connected());
442 EXPECT_TRUE(!server_peer_->session_observer()->connected());
443
444 EXPECT_FALSE(client_peer_->IsEncryptionEstablished());
445 EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed());
446
447 EXPECT_FALSE(server_peer_->IsEncryptionEstablished());
448 EXPECT_FALSE(server_peer_->IsCryptoHandshakeConfirmed());
449 }
450
451 protected:
452 std::unique_ptr<QuicConfig> config_;
453 std::unique_ptr<QuartcConnectionHelper> helper_;
454 std::unique_ptr<QuicClock> clock_;
455 std::unique_ptr<QuicAlarmFactory> alarm_factory_;
456
457 std::unique_ptr<FakeTransportChannel> client_channel_;
458 std::unique_ptr<FakeTransportChannel> server_channel_;
459 std::unique_ptr<FakeTransport> client_transport_;
460 std::unique_ptr<FakeTransport> server_transport_;
461 std::unique_ptr<QuartcPacketWriter> client_writer_;
462 std::unique_ptr<QuartcPacketWriter> server_writer_;
463 std::unique_ptr<QuartcSessionForTest> client_peer_;
464 std::unique_ptr<QuartcSessionForTest> server_peer_;
465 };
466
467 TEST_F(QuartcSessionTest, StreamConnection) {
468 CreateClientAndServerSessions();
469 StartHandshake();
470 TestStreamConnection();
471 }
472
473 TEST_F(QuartcSessionTest, ClientRejection) {
474 CreateClientAndServerSessions(false /*client_handshake_success*/,
475 true /*server_handshake_success*/);
476 StartHandshake();
477 TestDisconnectAfterFailedHandshake();
478 }
479
480 TEST_F(QuartcSessionTest, ServerRejection) {
481 CreateClientAndServerSessions(true /*client_handshake_success*/,
482 false /*server_handshake_success*/);
483 StartHandshake();
484 TestDisconnectAfterFailedHandshake();
485 }
486
487 // Test that data streams are not created before handshake.
488 TEST_F(QuartcSessionTest, CannotCreateDataStreamBeforeHandshake) {
489 CreateClientAndServerSessions();
490 EXPECT_EQ(nullptr, server_peer_->CreateOutgoingStream(kDefaultStreamParam));
491 EXPECT_EQ(nullptr, client_peer_->CreateOutgoingStream(kDefaultStreamParam));
492 }
493
494 TEST_F(QuartcSessionTest, CloseQuartcStream) {
495 CreateClientAndServerSessions();
496 StartHandshake();
497 ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed() &&
498 server_peer_->IsCryptoHandshakeConfirmed());
499 QuartcReliableStreamInterface* stream =
500 client_peer_->CreateOutgoingStream(kDefaultStreamParam);
501 ASSERT_NE(nullptr, stream);
502
503 uint32_t id = stream->stream_id();
504 EXPECT_FALSE(client_peer_->IsClosedStream(id));
505 stream->SetObserver(client_peer_->stream_observer());
506 stream->Close();
507 EXPECT_TRUE(client_peer_->IsClosedStream(id));
508 }
509
510 } // namespace
511 } // namespace test
512 } // namespace net
OLDNEW
« net/quic/quartc/quartc_session_interface.h ('K') | « net/quic/quartc/quartc_session_interface.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698