OLD | NEW |
---|---|
(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 | |
OLD | NEW |