blob: 929b14f87b4af0dfdd08aae6b4e27117443f033d [file] [log] [blame]
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +00001/*
2 * Copyright 2014 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
jbauch555604a2016-04-26 03:13:22 -070011#include <memory>
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000012#include <string>
13
kjellandere96c45b2017-06-30 10:45:21 -070014#include "webrtc/rtc_base/gunit.h"
15#include "webrtc/rtc_base/ipaddress.h"
16#include "webrtc/rtc_base/socketstream.h"
17#include "webrtc/rtc_base/ssladapter.h"
18#include "webrtc/rtc_base/sslidentity.h"
19#include "webrtc/rtc_base/sslstreamadapter.h"
20#include "webrtc/rtc_base/stream.h"
21#include "webrtc/rtc_base/stringencode.h"
22#include "webrtc/rtc_base/virtualsocketserver.h"
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000023
24static const int kTimeout = 5000;
25
26static rtc::AsyncSocket* CreateSocket(const rtc::SSLMode& ssl_mode) {
27 rtc::SocketAddress address(rtc::IPAddress(INADDR_ANY), 0);
28
29 rtc::AsyncSocket* socket = rtc::Thread::Current()->
30 socketserver()->CreateAsyncSocket(
31 address.family(), (ssl_mode == rtc::SSL_MODE_DTLS) ?
32 SOCK_DGRAM : SOCK_STREAM);
33 socket->Bind(address);
34
35 return socket;
36}
37
38static std::string GetSSLProtocolName(const rtc::SSLMode& ssl_mode) {
39 return (ssl_mode == rtc::SSL_MODE_DTLS) ? "DTLS" : "TLS";
40}
41
42class SSLAdapterTestDummyClient : public sigslot::has_slots<> {
43 public:
44 explicit SSLAdapterTestDummyClient(const rtc::SSLMode& ssl_mode)
45 : ssl_mode_(ssl_mode) {
46 rtc::AsyncSocket* socket = CreateSocket(ssl_mode_);
47
48 ssl_adapter_.reset(rtc::SSLAdapter::Create(socket));
49
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +000050 ssl_adapter_->SetMode(ssl_mode_);
51
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000052 // Ignore any certificate errors for the purpose of testing.
53 // Note: We do this only because we don't have a real certificate.
54 // NEVER USE THIS IN PRODUCTION CODE!
55 ssl_adapter_->set_ignore_bad_cert(true);
56
57 ssl_adapter_->SignalReadEvent.connect(this,
58 &SSLAdapterTestDummyClient::OnSSLAdapterReadEvent);
59 ssl_adapter_->SignalCloseEvent.connect(this,
60 &SSLAdapterTestDummyClient::OnSSLAdapterCloseEvent);
61 }
62
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +000063 rtc::SocketAddress GetAddress() const {
64 return ssl_adapter_->GetLocalAddress();
65 }
66
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000067 rtc::AsyncSocket::ConnState GetState() const {
68 return ssl_adapter_->GetState();
69 }
70
71 const std::string& GetReceivedData() const {
72 return data_;
73 }
74
75 int Connect(const std::string& hostname, const rtc::SocketAddress& address) {
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000076 LOG(LS_INFO) << "Initiating connection with " << address;
77
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +000078 int rv = ssl_adapter_->Connect(address);
79
80 if (rv == 0) {
81 LOG(LS_INFO) << "Starting " << GetSSLProtocolName(ssl_mode_)
82 << " handshake with " << hostname;
83
84 if (ssl_adapter_->StartSSL(hostname.c_str(), false) != 0) {
85 return -1;
86 }
87 }
88
89 return rv;
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000090 }
91
92 int Close() {
93 return ssl_adapter_->Close();
94 }
95
96 int Send(const std::string& message) {
97 LOG(LS_INFO) << "Client sending '" << message << "'";
98
99 return ssl_adapter_->Send(message.data(), message.length());
100 }
101
102 void OnSSLAdapterReadEvent(rtc::AsyncSocket* socket) {
103 char buffer[4096] = "";
104
105 // Read data received from the server and store it in our internal buffer.
Stefan Holmer9131efd2016-05-23 18:19:26 +0200106 int read = socket->Recv(buffer, sizeof(buffer) - 1, nullptr);
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000107 if (read != -1) {
108 buffer[read] = '\0';
109
110 LOG(LS_INFO) << "Client received '" << buffer << "'";
111
112 data_ += buffer;
113 }
114 }
115
116 void OnSSLAdapterCloseEvent(rtc::AsyncSocket* socket, int error) {
117 // OpenSSLAdapter signals handshake failure with a close event, but without
118 // closing the socket! Let's close the socket here. This way GetState() can
119 // return CS_CLOSED after failure.
120 if (socket->GetState() != rtc::AsyncSocket::CS_CLOSED) {
121 socket->Close();
122 }
123 }
124
125 private:
126 const rtc::SSLMode ssl_mode_;
127
jbauch555604a2016-04-26 03:13:22 -0700128 std::unique_ptr<rtc::SSLAdapter> ssl_adapter_;
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000129
130 std::string data_;
131};
132
133class SSLAdapterTestDummyServer : public sigslot::has_slots<> {
134 public:
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200135 explicit SSLAdapterTestDummyServer(const rtc::SSLMode& ssl_mode,
torbjorng4e572472015-10-08 09:42:49 -0700136 const rtc::KeyParams& key_params)
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000137 : ssl_mode_(ssl_mode) {
138 // Generate a key pair and a certificate for this host.
torbjorng4e572472015-10-08 09:42:49 -0700139 ssl_identity_.reset(rtc::SSLIdentity::Generate(GetHostname(), key_params));
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000140
141 server_socket_.reset(CreateSocket(ssl_mode_));
142
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000143 if (ssl_mode_ == rtc::SSL_MODE_TLS) {
144 server_socket_->SignalReadEvent.connect(this,
145 &SSLAdapterTestDummyServer::OnServerSocketReadEvent);
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000146
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000147 server_socket_->Listen(1);
148 }
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000149
150 LOG(LS_INFO) << ((ssl_mode_ == rtc::SSL_MODE_DTLS) ? "UDP" : "TCP")
151 << " server listening on " << server_socket_->GetLocalAddress();
152 }
153
154 rtc::SocketAddress GetAddress() const {
155 return server_socket_->GetLocalAddress();
156 }
157
158 std::string GetHostname() const {
159 // Since we don't have a real certificate anyway, the value here doesn't
160 // really matter.
161 return "example.com";
162 }
163
164 const std::string& GetReceivedData() const {
165 return data_;
166 }
167
168 int Send(const std::string& message) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800169 if (ssl_stream_adapter_ == nullptr ||
170 ssl_stream_adapter_->GetState() != rtc::SS_OPEN) {
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000171 // No connection yet.
172 return -1;
173 }
174
175 LOG(LS_INFO) << "Server sending '" << message << "'";
176
177 size_t written;
178 int error;
179
180 rtc::StreamResult r = ssl_stream_adapter_->Write(message.data(),
181 message.length(), &written, &error);
182 if (r == rtc::SR_SUCCESS) {
183 return written;
184 } else {
185 return -1;
186 }
187 }
188
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000189 void AcceptConnection(const rtc::SocketAddress& address) {
190 // Only a single connection is supported.
deadbeef37f5ecf2017-02-27 14:06:41 -0800191 ASSERT_TRUE(ssl_stream_adapter_ == nullptr);
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000192
193 // This is only for DTLS.
194 ASSERT_EQ(rtc::SSL_MODE_DTLS, ssl_mode_);
195
196 // Transfer ownership of the socket to the SSLStreamAdapter object.
197 rtc::AsyncSocket* socket = server_socket_.release();
198
199 socket->Connect(address);
200
201 DoHandshake(socket);
202 }
203
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000204 void OnServerSocketReadEvent(rtc::AsyncSocket* socket) {
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000205 // Only a single connection is supported.
deadbeef37f5ecf2017-02-27 14:06:41 -0800206 ASSERT_TRUE(ssl_stream_adapter_ == nullptr);
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000207
deadbeef37f5ecf2017-02-27 14:06:41 -0800208 DoHandshake(server_socket_->Accept(nullptr));
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000209 }
210
211 void OnSSLStreamAdapterEvent(rtc::StreamInterface* stream, int sig, int err) {
212 if (sig & rtc::SE_READ) {
213 char buffer[4096] = "";
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000214 size_t read;
215 int error;
216
217 // Read data received from the client and store it in our internal
218 // buffer.
deadbeefed3b9862017-06-02 10:33:16 -0700219 rtc::StreamResult r =
220 stream->Read(buffer, sizeof(buffer) - 1, &read, &error);
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000221 if (r == rtc::SR_SUCCESS) {
222 buffer[read] = '\0';
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000223 LOG(LS_INFO) << "Server received '" << buffer << "'";
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000224 data_ += buffer;
225 }
226 }
227 }
228
229 private:
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000230 void DoHandshake(rtc::AsyncSocket* socket) {
231 rtc::SocketStream* stream = new rtc::SocketStream(socket);
232
233 ssl_stream_adapter_.reset(rtc::SSLStreamAdapter::Create(stream));
234
235 ssl_stream_adapter_->SetMode(ssl_mode_);
236 ssl_stream_adapter_->SetServerRole();
237
238 // SSLStreamAdapter is normally used for peer-to-peer communication, but
239 // here we're testing communication between a client and a server
240 // (e.g. a WebRTC-based application and an RFC 5766 TURN server), where
241 // clients are not required to provide a certificate during handshake.
242 // Accordingly, we must disable client authentication here.
243 ssl_stream_adapter_->set_client_auth_enabled(false);
244
245 ssl_stream_adapter_->SetIdentity(ssl_identity_->GetReference());
246
247 // Set a bogus peer certificate digest.
248 unsigned char digest[20];
249 size_t digest_len = sizeof(digest);
250 ssl_stream_adapter_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, digest,
251 digest_len);
252
Taylor Brandstetterc8762a82016-08-11 12:01:49 -0700253 ssl_stream_adapter_->StartSSL();
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000254
255 ssl_stream_adapter_->SignalEvent.connect(this,
256 &SSLAdapterTestDummyServer::OnSSLStreamAdapterEvent);
257 }
258
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000259 const rtc::SSLMode ssl_mode_;
260
jbauch555604a2016-04-26 03:13:22 -0700261 std::unique_ptr<rtc::AsyncSocket> server_socket_;
262 std::unique_ptr<rtc::SSLStreamAdapter> ssl_stream_adapter_;
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000263
jbauch555604a2016-04-26 03:13:22 -0700264 std::unique_ptr<rtc::SSLIdentity> ssl_identity_;
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000265
266 std::string data_;
267};
268
269class SSLAdapterTestBase : public testing::Test,
270 public sigslot::has_slots<> {
271 public:
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200272 explicit SSLAdapterTestBase(const rtc::SSLMode& ssl_mode,
torbjorng4e572472015-10-08 09:42:49 -0700273 const rtc::KeyParams& key_params)
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000274 : ssl_mode_(ssl_mode),
deadbeef98e186c2017-05-16 18:00:06 -0700275 vss_(new rtc::VirtualSocketServer()),
nisse7eaa4ea2017-05-08 05:25:41 -0700276 thread_(vss_.get()),
torbjorng4e572472015-10-08 09:42:49 -0700277 server_(new SSLAdapterTestDummyServer(ssl_mode_, key_params)),
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000278 client_(new SSLAdapterTestDummyClient(ssl_mode_)),
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200279 handshake_wait_(kTimeout) {}
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000280
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000281 void SetHandshakeWait(int wait) {
282 handshake_wait_ = wait;
283 }
284
285 void TestHandshake(bool expect_success) {
286 int rv;
287
288 // The initial state is CS_CLOSED
289 ASSERT_EQ(rtc::AsyncSocket::CS_CLOSED, client_->GetState());
290
291 rv = client_->Connect(server_->GetHostname(), server_->GetAddress());
292 ASSERT_EQ(0, rv);
293
294 // Now the state should be CS_CONNECTING
295 ASSERT_EQ(rtc::AsyncSocket::CS_CONNECTING, client_->GetState());
296
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000297 if (ssl_mode_ == rtc::SSL_MODE_DTLS) {
298 // For DTLS, call AcceptConnection() with the client's address.
299 server_->AcceptConnection(client_->GetAddress());
300 }
301
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000302 if (expect_success) {
303 // If expecting success, the client should end up in the CS_CONNECTED
304 // state after handshake.
305 EXPECT_EQ_WAIT(rtc::AsyncSocket::CS_CONNECTED, client_->GetState(),
306 handshake_wait_);
307
308 LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) << " handshake complete.";
309
310 } else {
311 // On handshake failure the client should end up in the CS_CLOSED state.
312 EXPECT_EQ_WAIT(rtc::AsyncSocket::CS_CLOSED, client_->GetState(),
313 handshake_wait_);
314
315 LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) << " handshake failed.";
316 }
317 }
318
319 void TestTransfer(const std::string& message) {
320 int rv;
321
322 rv = client_->Send(message);
323 ASSERT_EQ(static_cast<int>(message.length()), rv);
324
325 // The server should have received the client's message.
326 EXPECT_EQ_WAIT(message, server_->GetReceivedData(), kTimeout);
327
328 rv = server_->Send(message);
329 ASSERT_EQ(static_cast<int>(message.length()), rv);
330
331 // The client should have received the server's message.
332 EXPECT_EQ_WAIT(message, client_->GetReceivedData(), kTimeout);
333
334 LOG(LS_INFO) << "Transfer complete.";
335 }
336
deadbeefed3b9862017-06-02 10:33:16 -0700337 protected:
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000338 const rtc::SSLMode ssl_mode_;
339
nisse7eaa4ea2017-05-08 05:25:41 -0700340 std::unique_ptr<rtc::VirtualSocketServer> vss_;
341 rtc::AutoSocketServerThread thread_;
jbauch555604a2016-04-26 03:13:22 -0700342 std::unique_ptr<SSLAdapterTestDummyServer> server_;
343 std::unique_ptr<SSLAdapterTestDummyClient> client_;
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000344
345 int handshake_wait_;
346};
347
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200348class SSLAdapterTestTLS_RSA : public SSLAdapterTestBase {
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000349 public:
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200350 SSLAdapterTestTLS_RSA()
torbjorng4e572472015-10-08 09:42:49 -0700351 : SSLAdapterTestBase(rtc::SSL_MODE_TLS, rtc::KeyParams::RSA()) {}
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000352};
353
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200354class SSLAdapterTestTLS_ECDSA : public SSLAdapterTestBase {
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000355 public:
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200356 SSLAdapterTestTLS_ECDSA()
torbjorng4e572472015-10-08 09:42:49 -0700357 : SSLAdapterTestBase(rtc::SSL_MODE_TLS, rtc::KeyParams::ECDSA()) {}
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200358};
359
360class SSLAdapterTestDTLS_RSA : public SSLAdapterTestBase {
361 public:
362 SSLAdapterTestDTLS_RSA()
torbjorng4e572472015-10-08 09:42:49 -0700363 : SSLAdapterTestBase(rtc::SSL_MODE_DTLS, rtc::KeyParams::RSA()) {}
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200364};
365
366class SSLAdapterTestDTLS_ECDSA : public SSLAdapterTestBase {
367 public:
368 SSLAdapterTestDTLS_ECDSA()
torbjorng4e572472015-10-08 09:42:49 -0700369 : SSLAdapterTestBase(rtc::SSL_MODE_DTLS, rtc::KeyParams::ECDSA()) {}
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000370};
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000371
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000372// Basic tests: TLS
373
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200374// Test that handshake works, using RSA
375TEST_F(SSLAdapterTestTLS_RSA, TestTLSConnect) {
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000376 TestHandshake(true);
377}
378
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200379// Test that handshake works, using ECDSA
380TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSConnect) {
381 TestHandshake(true);
382}
383
384// Test transfer between client and server, using RSA
385TEST_F(SSLAdapterTestTLS_RSA, TestTLSTransfer) {
386 TestHandshake(true);
387 TestTransfer("Hello, world!");
388}
389
deadbeefed3b9862017-06-02 10:33:16 -0700390TEST_F(SSLAdapterTestTLS_RSA, TestTLSTransferWithBlockedSocket) {
391 TestHandshake(true);
392
393 // Tell the underlying socket to simulate being blocked.
394 vss_->SetSendingBlocked(true);
395
396 std::string expected;
397 int rv;
398 // Send messages until the SSL socket adapter starts applying backpressure.
399 // Note that this may not occur immediately since there may be some amount of
400 // intermediate buffering (either in our code or in BoringSSL).
401 for (int i = 0; i < 1024; ++i) {
402 std::string message = "Hello, world: " + rtc::ToString(i);
403 rv = client_->Send(message);
404 if (rv != static_cast<int>(message.size())) {
405 // This test assumes either the whole message or none of it is sent.
406 ASSERT_EQ(-1, rv);
407 break;
408 }
409 expected += message;
410 }
411 // Assert that the loop above exited due to Send returning -1.
412 ASSERT_EQ(-1, rv);
413
414 // Try sending another message while blocked. -1 should be returned again and
415 // it shouldn't end up received by the server later.
416 EXPECT_EQ(-1, client_->Send("Never sent"));
417
418 // Unblock the underlying socket. All of the buffered messages should be sent
419 // without any further action.
420 vss_->SetSendingBlocked(false);
421 EXPECT_EQ_WAIT(expected, server_->GetReceivedData(), kTimeout);
422
423 // Send another message. This previously wasn't working
424 std::string final_message = "Fin.";
425 expected += final_message;
426 EXPECT_EQ(static_cast<int>(final_message.size()),
427 client_->Send(final_message));
428 EXPECT_EQ_WAIT(expected, server_->GetReceivedData(), kTimeout);
429}
430
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200431// Test transfer between client and server, using ECDSA
432TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSTransfer) {
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000433 TestHandshake(true);
434 TestTransfer("Hello, world!");
435}
436
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000437// Basic tests: DTLS
438
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200439// Test that handshake works, using RSA
440TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSConnect) {
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000441 TestHandshake(true);
442}
443
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200444// Test that handshake works, using ECDSA
445TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSConnect) {
446 TestHandshake(true);
447}
448
449// Test transfer between client and server, using RSA
450TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSTransfer) {
451 TestHandshake(true);
452 TestTransfer("Hello, world!");
453}
454
455// Test transfer between client and server, using ECDSA
456TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSTransfer) {
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000457 TestHandshake(true);
458 TestTransfer("Hello, world!");
459}