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

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

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

Powered by Google App Engine
This is Rietveld 408576698