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: Patch Set 4 : Create QuartcFactory. Made modification on the API. Change the constructor of QuartcS… Created 4 years, 3 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 // 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 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::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_fingerprint_value,
271 Perspective perspective,
272 QuartcSessionInterface::Transport* session_transport)
273 : QuartcSession(std::move(connection),
274 config,
275 remote_fingerprint_value,
276 perspective,
277 session_transport) {
278 stream_observer_.reset(new FakeQuartcReliableStreamObserver);
279 session_observer_.reset(
280 new FakeQuartcSessionObserver(stream_observer_.get()));
281
282 SetObserver(session_observer_.get());
283 }
284
285 // QuartcPacketWriter override.
286 void OnTransportChannelReadPacket(const std::string& data) override {
287 OnReceived(data.c_str(), data.length());
288 }
289
290 std::string data() { return stream_observer_->data(); }
291
292 bool has_data() { return !data().empty(); }
293
294 FakeQuartcSessionObserver* session_observer() {
295 return session_observer_.get();
296 }
297
298 FakeQuartcReliableStreamObserver* stream_observer() {
299 return stream_observer_.get();
300 }
301
302 private:
303 std::unique_ptr<FakeQuartcReliableStreamObserver> stream_observer_;
304 std::unique_ptr<FakeQuartcSessionObserver> session_observer_;
305 };
306
307 class QuartcSessionTest : public ::testing::Test {
308 public:
309 ~QuartcSessionTest() override {}
310
311 void Init() {
312 helper_.reset(new QuartcConnectionHelper);
313 clock_.reset(new QuicClock);
314 config_.reset(new QuicConfig);
315
316 client_channel_.reset(new FakeTransportChannel);
317 server_channel_.reset(new FakeTransportChannel);
318 // Make the channel asynchronous so that two peer will not keep calling each
319 // other when they exchange information.
320 client_channel_->SetAsync(true);
321 client_channel_->SetDestination(server_channel_.get());
322
323 client_transport_.reset(new FakeTransport(client_channel_.get()));
324 server_transport_.reset(new FakeTransport(server_channel_.get()));
325
326 client_writer_.reset(new QuartcPacketWriter(client_transport_.get()));
327 server_writer_.reset(new QuartcPacketWriter(server_transport_.get()));
328 }
329
330 // The parameters are used to control whether the handshake will success or
331 // not.
332 void CreateClientAndServerSessions(bool client_handshake_success = true,
333 bool server_handshake_success = true) {
334 Init();
335 client_peer_ = CreateSession(Perspective::IS_CLIENT);
336 server_peer_ = CreateSession(Perspective::IS_SERVER);
337
338 client_channel_->SetObserver(client_peer_.get());
339 server_channel_->SetObserver(server_peer_.get());
340
341 client_peer_->SetClientCryptoConfig(
342 new QuicCryptoClientConfig(std::unique_ptr<ProofVerifier>(
343 new FakeProofVerifier(client_handshake_success))));
344
345 QuicCryptoServerConfig* server_config = new QuicCryptoServerConfig(
346 "TESTING", QuicRandom::GetInstance(),
347 std::unique_ptr<FakeProofSource>(
348 new FakeProofSource(server_handshake_success)));
349 // Provide server with serialized config string to prove ownership.
350 QuicCryptoServerConfig::ConfigOptions options;
351 QuicServerConfigProtobuf* primary_config = server_config->GenerateConfig(
352 QuicRandom::GetInstance(), clock_.get(), options);
353 server_config->AddConfig(primary_config, clock_->WallNow());
354
355 server_peer_->SetServerCryptoConfig(server_config);
356 }
357
358 std::unique_ptr<QuartcSessionForTest> CreateSession(Perspective perspective) {
359 std::unique_ptr<QuicConnection> quic_connection =
360 CreateConnection(perspective);
361 QuartcSessionInterface::Transport* transport =
362 perspective == Perspective::IS_CLIENT ? client_transport_.get()
363 : server_transport_.get();
364 std::string remote_fingerprint_value = "value";
365 return std::unique_ptr<QuartcSessionForTest>(new QuartcSessionForTest(
366 std::move(quic_connection), *(config_.get()), remote_fingerprint_value,
367 perspective, transport));
368 }
369
370 std::unique_ptr<QuicConnection> CreateConnection(Perspective perspective) {
371 QuartcPacketWriter* writer = perspective == Perspective::IS_CLIENT
372 ? client_writer_.get()
373 : server_writer_.get();
374 IPAddress ip(0, 0, 0, 0);
375 bool owns_writer = false;
376 alarm_factory_.reset(new QuartcAlarmFactory(
377 base::ThreadTaskRunnerHandle::Get().get(), helper_->GetClock()));
378 return std::unique_ptr<QuicConnection>(new QuicConnection(
379 0, IPEndPoint(ip, 0), helper_.get(), alarm_factory_.get(), writer,
380 owns_writer, perspective, AllSupportedVersions()));
381 }
382 void StartHandshake() {
383 server_peer_->StartCryptoHandshake();
384 client_peer_->StartCryptoHandshake();
385 RunLoopWithTimeout();
386 }
387
388 // Test handshake establishment and sending/receiving of data for two
389 // directions.
390 void TestStreamConnection() {
391 ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed() &&
392 client_peer_->IsCryptoHandshakeConfirmed());
393 ASSERT_TRUE(server_peer_->IsEncryptionEstablished());
394 ASSERT_TRUE(client_peer_->IsEncryptionEstablished());
395
396 uint8_t server_key[kOutputKeyLength];
397 uint8_t client_key[kOutputKeyLength];
398 bool use_context = true;
399 bool server_success = server_peer_->ExportKeyingMaterial(
400 kExporterLabel, kExporterContext, kExporterContextLen, use_context,
401 server_key, kOutputKeyLength);
402 ASSERT_TRUE(server_success);
403 bool client_success = client_peer_->ExportKeyingMaterial(
404 kExporterLabel, kExporterContext, kExporterContextLen, use_context,
405 client_key, kOutputKeyLength);
406 ASSERT_TRUE(client_success);
407 EXPECT_EQ(0, memcmp(server_key, client_key, sizeof(server_key)));
408
409 // Now we can establish encrypted outgoing stream.
410 QuartcReliableStreamInterface* outgoing_stream =
411 server_peer_->CreateOutgoingStream(kDefaultStreamParam);
412 ASSERT_NE(nullptr, outgoing_stream);
413 EXPECT_TRUE(server_peer_->HasOpenDynamicStreams());
414
415 outgoing_stream->SetObserver(server_peer_->stream_observer());
416
417 // Send a test message from peer 1 to peer 2.
418 const char kTestMessage[] = "Hello";
419 outgoing_stream->Write(kTestMessage, strlen(kTestMessage),
420 kDefaultWriteParam);
421 RunLoopWithTimeout();
422
423 // Wait for peer 2 to receive messages.
424 ASSERT_TRUE(client_peer_->has_data());
425
426 QuartcReliableStreamInterface* incoming =
427 client_peer_->session_observer()->incoming_stream();
428 ASSERT_TRUE(incoming);
429 EXPECT_TRUE(client_peer_->HasOpenDynamicStreams());
430
431 EXPECT_EQ(client_peer_->data(), kTestMessage);
432 // Send a test message from peer 2 to peer 1.
433 const char kTestResponse[] = "Response";
434 incoming->Write(kTestResponse, strlen(kTestResponse), kDefaultWriteParam);
435 RunLoopWithTimeout();
436 // Wait for peer 1 to receive messages.
437 ASSERT_TRUE(server_peer_->has_data());
438
439 EXPECT_EQ(server_peer_->data(), kTestResponse);
440 }
441
442 // Test that client and server are not connected after handshake failure.
443 void TestDisconnectAfterFailedHandshake() {
444 EXPECT_TRUE(!client_peer_->session_observer()->connected());
445 EXPECT_TRUE(!server_peer_->session_observer()->connected());
446
447 EXPECT_FALSE(client_peer_->IsEncryptionEstablished());
448 EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed());
449
450 EXPECT_FALSE(server_peer_->IsEncryptionEstablished());
451 EXPECT_FALSE(server_peer_->IsCryptoHandshakeConfirmed());
452 }
453
454 protected:
455 std::unique_ptr<QuicConfig> config_;
456 std::unique_ptr<QuartcConnectionHelper> helper_;
457 std::unique_ptr<QuicClock> clock_;
458 std::unique_ptr<QuicAlarmFactory> alarm_factory_;
459
460 std::unique_ptr<FakeTransportChannel> client_channel_;
461 std::unique_ptr<FakeTransportChannel> server_channel_;
462 std::unique_ptr<FakeTransport> client_transport_;
463 std::unique_ptr<FakeTransport> server_transport_;
464 std::unique_ptr<QuartcPacketWriter> client_writer_;
465 std::unique_ptr<QuartcPacketWriter> server_writer_;
466 std::unique_ptr<QuartcSessionForTest> client_peer_;
467 std::unique_ptr<QuartcSessionForTest> server_peer_;
468 };
469
470 TEST_F(QuartcSessionTest, StreamConnection) {
471 CreateClientAndServerSessions();
472 StartHandshake();
473 TestStreamConnection();
474 }
475
476 TEST_F(QuartcSessionTest, ClientRejection) {
477 CreateClientAndServerSessions(false /*client_handshake_success*/,
478 true /*server_handshake_success*/);
479 StartHandshake();
480 TestDisconnectAfterFailedHandshake();
481 }
482
483 TEST_F(QuartcSessionTest, ServerRejection) {
484 CreateClientAndServerSessions(true /*client_handshake_success*/,
485 false /*server_handshake_success*/);
486 StartHandshake();
487 TestDisconnectAfterFailedHandshake();
488 }
489
490 // Test that data streams are not created before handshake.
491 TEST_F(QuartcSessionTest, CannotCreateDataStreamBeforeHandshake) {
492 CreateClientAndServerSessions();
493 EXPECT_EQ(nullptr, server_peer_->CreateOutgoingStream(kDefaultStreamParam));
494 EXPECT_EQ(nullptr, client_peer_->CreateOutgoingStream(kDefaultStreamParam));
495 }
496
497 TEST_F(QuartcSessionTest, CloseQuartcStream) {
498 CreateClientAndServerSessions();
499 StartHandshake();
500 ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed() &&
501 server_peer_->IsCryptoHandshakeConfirmed());
502 QuartcReliableStreamInterface* stream =
503 client_peer_->CreateOutgoingStream(kDefaultStreamParam);
504 ASSERT_NE(nullptr, stream);
505
506 uint32_t id = stream->stream_id();
507 EXPECT_FALSE(client_peer_->IsClosedStream(id));
508 stream->SetObserver(client_peer_->stream_observer());
509 stream->Close();
510 EXPECT_TRUE(client_peer_->IsClosedStream(id));
511 }
512
513 } // namespace
514 } // namespace test
515 } // 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