blob: c591f19658f30d19acfa9a338ccf7ddd2ce59a65 [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
14#include "webrtc/base/gunit.h"
15#include "webrtc/base/ipaddress.h"
16#include "webrtc/base/socketstream.h"
17#include "webrtc/base/ssladapter.h"
18#include "webrtc/base/sslstreamadapter.h"
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020019#include "webrtc/base/sslidentity.h"
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000020#include "webrtc/base/stream.h"
21#include "webrtc/base/virtualsocketserver.h"
22
23static const int kTimeout = 5000;
24
25static rtc::AsyncSocket* CreateSocket(const rtc::SSLMode& ssl_mode) {
26 rtc::SocketAddress address(rtc::IPAddress(INADDR_ANY), 0);
27
28 rtc::AsyncSocket* socket = rtc::Thread::Current()->
29 socketserver()->CreateAsyncSocket(
30 address.family(), (ssl_mode == rtc::SSL_MODE_DTLS) ?
31 SOCK_DGRAM : SOCK_STREAM);
32 socket->Bind(address);
33
34 return socket;
35}
36
37static std::string GetSSLProtocolName(const rtc::SSLMode& ssl_mode) {
38 return (ssl_mode == rtc::SSL_MODE_DTLS) ? "DTLS" : "TLS";
39}
40
41class SSLAdapterTestDummyClient : public sigslot::has_slots<> {
42 public:
43 explicit SSLAdapterTestDummyClient(const rtc::SSLMode& ssl_mode)
44 : ssl_mode_(ssl_mode) {
45 rtc::AsyncSocket* socket = CreateSocket(ssl_mode_);
46
47 ssl_adapter_.reset(rtc::SSLAdapter::Create(socket));
48
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +000049 ssl_adapter_->SetMode(ssl_mode_);
50
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000051 // Ignore any certificate errors for the purpose of testing.
52 // Note: We do this only because we don't have a real certificate.
53 // NEVER USE THIS IN PRODUCTION CODE!
54 ssl_adapter_->set_ignore_bad_cert(true);
55
56 ssl_adapter_->SignalReadEvent.connect(this,
57 &SSLAdapterTestDummyClient::OnSSLAdapterReadEvent);
58 ssl_adapter_->SignalCloseEvent.connect(this,
59 &SSLAdapterTestDummyClient::OnSSLAdapterCloseEvent);
60 }
61
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +000062 rtc::SocketAddress GetAddress() const {
63 return ssl_adapter_->GetLocalAddress();
64 }
65
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000066 rtc::AsyncSocket::ConnState GetState() const {
67 return ssl_adapter_->GetState();
68 }
69
70 const std::string& GetReceivedData() const {
71 return data_;
72 }
73
74 int Connect(const std::string& hostname, const rtc::SocketAddress& address) {
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000075 LOG(LS_INFO) << "Initiating connection with " << address;
76
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +000077 int rv = ssl_adapter_->Connect(address);
78
79 if (rv == 0) {
80 LOG(LS_INFO) << "Starting " << GetSSLProtocolName(ssl_mode_)
81 << " handshake with " << hostname;
82
83 if (ssl_adapter_->StartSSL(hostname.c_str(), false) != 0) {
84 return -1;
85 }
86 }
87
88 return rv;
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +000089 }
90
91 int Close() {
92 return ssl_adapter_->Close();
93 }
94
95 int Send(const std::string& message) {
96 LOG(LS_INFO) << "Client sending '" << message << "'";
97
98 return ssl_adapter_->Send(message.data(), message.length());
99 }
100
101 void OnSSLAdapterReadEvent(rtc::AsyncSocket* socket) {
102 char buffer[4096] = "";
103
104 // Read data received from the server and store it in our internal buffer.
Stefan Holmer9131efd2016-05-23 18:19:26 +0200105 int read = socket->Recv(buffer, sizeof(buffer) - 1, nullptr);
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000106 if (read != -1) {
107 buffer[read] = '\0';
108
109 LOG(LS_INFO) << "Client received '" << buffer << "'";
110
111 data_ += buffer;
112 }
113 }
114
115 void OnSSLAdapterCloseEvent(rtc::AsyncSocket* socket, int error) {
116 // OpenSSLAdapter signals handshake failure with a close event, but without
117 // closing the socket! Let's close the socket here. This way GetState() can
118 // return CS_CLOSED after failure.
119 if (socket->GetState() != rtc::AsyncSocket::CS_CLOSED) {
120 socket->Close();
121 }
122 }
123
124 private:
125 const rtc::SSLMode ssl_mode_;
126
jbauch555604a2016-04-26 03:13:22 -0700127 std::unique_ptr<rtc::SSLAdapter> ssl_adapter_;
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000128
129 std::string data_;
130};
131
132class SSLAdapterTestDummyServer : public sigslot::has_slots<> {
133 public:
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200134 explicit SSLAdapterTestDummyServer(const rtc::SSLMode& ssl_mode,
torbjorng4e572472015-10-08 09:42:49 -0700135 const rtc::KeyParams& key_params)
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000136 : ssl_mode_(ssl_mode) {
137 // Generate a key pair and a certificate for this host.
torbjorng4e572472015-10-08 09:42:49 -0700138 ssl_identity_.reset(rtc::SSLIdentity::Generate(GetHostname(), key_params));
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000139
140 server_socket_.reset(CreateSocket(ssl_mode_));
141
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000142 if (ssl_mode_ == rtc::SSL_MODE_TLS) {
143 server_socket_->SignalReadEvent.connect(this,
144 &SSLAdapterTestDummyServer::OnServerSocketReadEvent);
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000145
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000146 server_socket_->Listen(1);
147 }
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000148
149 LOG(LS_INFO) << ((ssl_mode_ == rtc::SSL_MODE_DTLS) ? "UDP" : "TCP")
150 << " server listening on " << server_socket_->GetLocalAddress();
151 }
152
153 rtc::SocketAddress GetAddress() const {
154 return server_socket_->GetLocalAddress();
155 }
156
157 std::string GetHostname() const {
158 // Since we don't have a real certificate anyway, the value here doesn't
159 // really matter.
160 return "example.com";
161 }
162
163 const std::string& GetReceivedData() const {
164 return data_;
165 }
166
167 int Send(const std::string& message) {
168 if (ssl_stream_adapter_ == NULL
169 || ssl_stream_adapter_->GetState() != rtc::SS_OPEN) {
170 // No connection yet.
171 return -1;
172 }
173
174 LOG(LS_INFO) << "Server sending '" << message << "'";
175
176 size_t written;
177 int error;
178
179 rtc::StreamResult r = ssl_stream_adapter_->Write(message.data(),
180 message.length(), &written, &error);
181 if (r == rtc::SR_SUCCESS) {
182 return written;
183 } else {
184 return -1;
185 }
186 }
187
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000188 void AcceptConnection(const rtc::SocketAddress& address) {
189 // Only a single connection is supported.
190 ASSERT_TRUE(ssl_stream_adapter_ == NULL);
191
192 // This is only for DTLS.
193 ASSERT_EQ(rtc::SSL_MODE_DTLS, ssl_mode_);
194
195 // Transfer ownership of the socket to the SSLStreamAdapter object.
196 rtc::AsyncSocket* socket = server_socket_.release();
197
198 socket->Connect(address);
199
200 DoHandshake(socket);
201 }
202
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000203 void OnServerSocketReadEvent(rtc::AsyncSocket* socket) {
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000204 // Only a single connection is supported.
205 ASSERT_TRUE(ssl_stream_adapter_ == NULL);
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000206
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000207 DoHandshake(server_socket_->Accept(NULL));
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000208 }
209
210 void OnSSLStreamAdapterEvent(rtc::StreamInterface* stream, int sig, int err) {
211 if (sig & rtc::SE_READ) {
212 char buffer[4096] = "";
213
214 size_t read;
215 int error;
216
217 // Read data received from the client and store it in our internal
218 // buffer.
219 rtc::StreamResult r = stream->Read(buffer,
220 sizeof(buffer) - 1, &read, &error);
221 if (r == rtc::SR_SUCCESS) {
222 buffer[read] = '\0';
223
224 LOG(LS_INFO) << "Server received '" << buffer << "'";
225
226 data_ += buffer;
227 }
228 }
229 }
230
231 private:
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000232 void DoHandshake(rtc::AsyncSocket* socket) {
233 rtc::SocketStream* stream = new rtc::SocketStream(socket);
234
235 ssl_stream_adapter_.reset(rtc::SSLStreamAdapter::Create(stream));
236
237 ssl_stream_adapter_->SetMode(ssl_mode_);
238 ssl_stream_adapter_->SetServerRole();
239
240 // SSLStreamAdapter is normally used for peer-to-peer communication, but
241 // here we're testing communication between a client and a server
242 // (e.g. a WebRTC-based application and an RFC 5766 TURN server), where
243 // clients are not required to provide a certificate during handshake.
244 // Accordingly, we must disable client authentication here.
245 ssl_stream_adapter_->set_client_auth_enabled(false);
246
247 ssl_stream_adapter_->SetIdentity(ssl_identity_->GetReference());
248
249 // Set a bogus peer certificate digest.
250 unsigned char digest[20];
251 size_t digest_len = sizeof(digest);
252 ssl_stream_adapter_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, digest,
253 digest_len);
254
Taylor Brandstetterc8762a82016-08-11 12:01:49 -0700255 ssl_stream_adapter_->StartSSL();
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000256
257 ssl_stream_adapter_->SignalEvent.connect(this,
258 &SSLAdapterTestDummyServer::OnSSLStreamAdapterEvent);
259 }
260
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000261 const rtc::SSLMode ssl_mode_;
262
jbauch555604a2016-04-26 03:13:22 -0700263 std::unique_ptr<rtc::AsyncSocket> server_socket_;
264 std::unique_ptr<rtc::SSLStreamAdapter> ssl_stream_adapter_;
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000265
jbauch555604a2016-04-26 03:13:22 -0700266 std::unique_ptr<rtc::SSLIdentity> ssl_identity_;
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000267
268 std::string data_;
269};
270
271class SSLAdapterTestBase : public testing::Test,
272 public sigslot::has_slots<> {
273 public:
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200274 explicit SSLAdapterTestBase(const rtc::SSLMode& ssl_mode,
torbjorng4e572472015-10-08 09:42:49 -0700275 const rtc::KeyParams& key_params)
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000276 : ssl_mode_(ssl_mode),
277 ss_scope_(new rtc::VirtualSocketServer(NULL)),
torbjorng4e572472015-10-08 09:42:49 -0700278 server_(new SSLAdapterTestDummyServer(ssl_mode_, key_params)),
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000279 client_(new SSLAdapterTestDummyClient(ssl_mode_)),
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200280 handshake_wait_(kTimeout) {}
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000281
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000282 void SetHandshakeWait(int wait) {
283 handshake_wait_ = wait;
284 }
285
286 void TestHandshake(bool expect_success) {
287 int rv;
288
289 // The initial state is CS_CLOSED
290 ASSERT_EQ(rtc::AsyncSocket::CS_CLOSED, client_->GetState());
291
292 rv = client_->Connect(server_->GetHostname(), server_->GetAddress());
293 ASSERT_EQ(0, rv);
294
295 // Now the state should be CS_CONNECTING
296 ASSERT_EQ(rtc::AsyncSocket::CS_CONNECTING, client_->GetState());
297
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000298 if (ssl_mode_ == rtc::SSL_MODE_DTLS) {
299 // For DTLS, call AcceptConnection() with the client's address.
300 server_->AcceptConnection(client_->GetAddress());
301 }
302
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000303 if (expect_success) {
304 // If expecting success, the client should end up in the CS_CONNECTED
305 // state after handshake.
306 EXPECT_EQ_WAIT(rtc::AsyncSocket::CS_CONNECTED, client_->GetState(),
307 handshake_wait_);
308
309 LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) << " handshake complete.";
310
311 } else {
312 // On handshake failure the client should end up in the CS_CLOSED state.
313 EXPECT_EQ_WAIT(rtc::AsyncSocket::CS_CLOSED, client_->GetState(),
314 handshake_wait_);
315
316 LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) << " handshake failed.";
317 }
318 }
319
320 void TestTransfer(const std::string& message) {
321 int rv;
322
323 rv = client_->Send(message);
324 ASSERT_EQ(static_cast<int>(message.length()), rv);
325
326 // The server should have received the client's message.
327 EXPECT_EQ_WAIT(message, server_->GetReceivedData(), kTimeout);
328
329 rv = server_->Send(message);
330 ASSERT_EQ(static_cast<int>(message.length()), rv);
331
332 // The client should have received the server's message.
333 EXPECT_EQ_WAIT(message, client_->GetReceivedData(), kTimeout);
334
335 LOG(LS_INFO) << "Transfer complete.";
336 }
337
338 private:
339 const rtc::SSLMode ssl_mode_;
340
341 const rtc::SocketServerScope ss_scope_;
342
jbauch555604a2016-04-26 03:13:22 -0700343 std::unique_ptr<SSLAdapterTestDummyServer> server_;
344 std::unique_ptr<SSLAdapterTestDummyClient> client_;
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000345
346 int handshake_wait_;
347};
348
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200349class SSLAdapterTestTLS_RSA : public SSLAdapterTestBase {
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000350 public:
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200351 SSLAdapterTestTLS_RSA()
torbjorng4e572472015-10-08 09:42:49 -0700352 : SSLAdapterTestBase(rtc::SSL_MODE_TLS, rtc::KeyParams::RSA()) {}
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000353};
354
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200355class SSLAdapterTestTLS_ECDSA : public SSLAdapterTestBase {
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000356 public:
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200357 SSLAdapterTestTLS_ECDSA()
torbjorng4e572472015-10-08 09:42:49 -0700358 : SSLAdapterTestBase(rtc::SSL_MODE_TLS, rtc::KeyParams::ECDSA()) {}
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200359};
360
361class SSLAdapterTestDTLS_RSA : public SSLAdapterTestBase {
362 public:
363 SSLAdapterTestDTLS_RSA()
torbjorng4e572472015-10-08 09:42:49 -0700364 : SSLAdapterTestBase(rtc::SSL_MODE_DTLS, rtc::KeyParams::RSA()) {}
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200365};
366
367class SSLAdapterTestDTLS_ECDSA : public SSLAdapterTestBase {
368 public:
369 SSLAdapterTestDTLS_ECDSA()
torbjorng4e572472015-10-08 09:42:49 -0700370 : SSLAdapterTestBase(rtc::SSL_MODE_DTLS, rtc::KeyParams::ECDSA()) {}
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000371};
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000372
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000373// Basic tests: TLS
374
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200375// Test that handshake works, using RSA
376TEST_F(SSLAdapterTestTLS_RSA, TestTLSConnect) {
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000377 TestHandshake(true);
378}
379
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200380// Test that handshake works, using ECDSA
381TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSConnect) {
382 TestHandshake(true);
383}
384
385// Test transfer between client and server, using RSA
386TEST_F(SSLAdapterTestTLS_RSA, TestTLSTransfer) {
387 TestHandshake(true);
388 TestTransfer("Hello, world!");
389}
390
391// Test transfer between client and server, using ECDSA
392TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSTransfer) {
tkchin@webrtc.orgc569a492014-09-23 05:56:44 +0000393 TestHandshake(true);
394 TestTransfer("Hello, world!");
395}
396
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000397// Basic tests: DTLS
398
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200399// Test that handshake works, using RSA
400TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSConnect) {
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000401 TestHandshake(true);
402}
403
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200404// Test that handshake works, using ECDSA
405TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSConnect) {
406 TestHandshake(true);
407}
408
409// Test transfer between client and server, using RSA
410TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSTransfer) {
411 TestHandshake(true);
412 TestTransfer("Hello, world!");
413}
414
415// Test transfer between client and server, using ECDSA
416TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSTransfer) {
pthatcher@webrtc.orga9b1ec02014-12-29 23:00:14 +0000417 TestHandshake(true);
418 TestTransfer("Hello, world!");
419}