blob: 6d4536d2d3c1f9832cd48dc96f8b05971c1e2446 [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
11#include <string>
12
13#include "webrtc/base/gunit.h"
14#include "webrtc/base/ipaddress.h"
15#include "webrtc/base/socketstream.h"
16#include "webrtc/base/ssladapter.h"
17#include "webrtc/base/sslstreamadapter.h"
18#include "webrtc/base/stream.h"
19#include "webrtc/base/virtualsocketserver.h"
20
21static const int kTimeout = 5000;
22
23static rtc::AsyncSocket* CreateSocket(const rtc::SSLMode& ssl_mode) {
24 rtc::SocketAddress address(rtc::IPAddress(INADDR_ANY), 0);
25
26 rtc::AsyncSocket* socket = rtc::Thread::Current()->
27 socketserver()->CreateAsyncSocket(
28 address.family(), (ssl_mode == rtc::SSL_MODE_DTLS) ?
29 SOCK_DGRAM : SOCK_STREAM);
30 socket->Bind(address);
31
32 return socket;
33}
34
35static std::string GetSSLProtocolName(const rtc::SSLMode& ssl_mode) {
36 return (ssl_mode == rtc::SSL_MODE_DTLS) ? "DTLS" : "TLS";
37}
38
39class SSLAdapterTestDummyClient : public sigslot::has_slots<> {
40 public:
41 explicit SSLAdapterTestDummyClient(const rtc::SSLMode& ssl_mode)
42 : ssl_mode_(ssl_mode) {
43 rtc::AsyncSocket* socket = CreateSocket(ssl_mode_);
44
45 ssl_adapter_.reset(rtc::SSLAdapter::Create(socket));
46
47 // Ignore any certificate errors for the purpose of testing.
48 // Note: We do this only because we don't have a real certificate.
49 // NEVER USE THIS IN PRODUCTION CODE!
50 ssl_adapter_->set_ignore_bad_cert(true);
51
52 ssl_adapter_->SignalReadEvent.connect(this,
53 &SSLAdapterTestDummyClient::OnSSLAdapterReadEvent);
54 ssl_adapter_->SignalCloseEvent.connect(this,
55 &SSLAdapterTestDummyClient::OnSSLAdapterCloseEvent);
56 }
57
58 rtc::AsyncSocket::ConnState GetState() const {
59 return ssl_adapter_->GetState();
60 }
61
62 const std::string& GetReceivedData() const {
63 return data_;
64 }
65
66 int Connect(const std::string& hostname, const rtc::SocketAddress& address) {
67 LOG(LS_INFO) << "Starting " << GetSSLProtocolName(ssl_mode_)
68 << " handshake with " << hostname;
69
70 if (ssl_adapter_->StartSSL(hostname.c_str(), false) != 0) {
71 return -1;
72 }
73
74 LOG(LS_INFO) << "Initiating connection with " << address;
75
76 return ssl_adapter_->Connect(address);
77 }
78
79 int Close() {
80 return ssl_adapter_->Close();
81 }
82
83 int Send(const std::string& message) {
84 LOG(LS_INFO) << "Client sending '" << message << "'";
85
86 return ssl_adapter_->Send(message.data(), message.length());
87 }
88
89 void OnSSLAdapterReadEvent(rtc::AsyncSocket* socket) {
90 char buffer[4096] = "";
91
92 // Read data received from the server and store it in our internal buffer.
93 int read = socket->Recv(buffer, sizeof(buffer) - 1);
94 if (read != -1) {
95 buffer[read] = '\0';
96
97 LOG(LS_INFO) << "Client received '" << buffer << "'";
98
99 data_ += buffer;
100 }
101 }
102
103 void OnSSLAdapterCloseEvent(rtc::AsyncSocket* socket, int error) {
104 // OpenSSLAdapter signals handshake failure with a close event, but without
105 // closing the socket! Let's close the socket here. This way GetState() can
106 // return CS_CLOSED after failure.
107 if (socket->GetState() != rtc::AsyncSocket::CS_CLOSED) {
108 socket->Close();
109 }
110 }
111
112 private:
113 const rtc::SSLMode ssl_mode_;
114
115 rtc::scoped_ptr<rtc::SSLAdapter> ssl_adapter_;
116
117 std::string data_;
118};
119
120class SSLAdapterTestDummyServer : public sigslot::has_slots<> {
121 public:
122 explicit SSLAdapterTestDummyServer(const rtc::SSLMode& ssl_mode)
123 : ssl_mode_(ssl_mode) {
124 // Generate a key pair and a certificate for this host.
125 ssl_identity_.reset(rtc::SSLIdentity::Generate(GetHostname()));
126
127 server_socket_.reset(CreateSocket(ssl_mode_));
128
129 server_socket_->SignalReadEvent.connect(this,
130 &SSLAdapterTestDummyServer::OnServerSocketReadEvent);
131
132 server_socket_->Listen(1);
133
134 LOG(LS_INFO) << ((ssl_mode_ == rtc::SSL_MODE_DTLS) ? "UDP" : "TCP")
135 << " server listening on " << server_socket_->GetLocalAddress();
136 }
137
138 rtc::SocketAddress GetAddress() const {
139 return server_socket_->GetLocalAddress();
140 }
141
142 std::string GetHostname() const {
143 // Since we don't have a real certificate anyway, the value here doesn't
144 // really matter.
145 return "example.com";
146 }
147
148 const std::string& GetReceivedData() const {
149 return data_;
150 }
151
152 int Send(const std::string& message) {
153 if (ssl_stream_adapter_ == NULL
154 || ssl_stream_adapter_->GetState() != rtc::SS_OPEN) {
155 // No connection yet.
156 return -1;
157 }
158
159 LOG(LS_INFO) << "Server sending '" << message << "'";
160
161 size_t written;
162 int error;
163
164 rtc::StreamResult r = ssl_stream_adapter_->Write(message.data(),
165 message.length(), &written, &error);
166 if (r == rtc::SR_SUCCESS) {
167 return written;
168 } else {
169 return -1;
170 }
171 }
172
173 void OnServerSocketReadEvent(rtc::AsyncSocket* socket) {
174 if (ssl_stream_adapter_ != NULL) {
175 // Only a single connection is supported.
176 return;
177 }
178
179 rtc::SocketAddress address;
180 rtc::AsyncSocket* new_socket = socket->Accept(&address);
181 rtc::SocketStream* stream = new rtc::SocketStream(new_socket);
182
183 ssl_stream_adapter_.reset(rtc::SSLStreamAdapter::Create(stream));
184 ssl_stream_adapter_->SetServerRole();
185
186 // SSLStreamAdapter is normally used for peer-to-peer communication, but
187 // here we're testing communication between a client and a server
188 // (e.g. a WebRTC-based application and an RFC 5766 TURN server), where
189 // clients are not required to provide a certificate during handshake.
190 // Accordingly, we must disable client authentication here.
191 ssl_stream_adapter_->set_client_auth_enabled(false);
192
193 ssl_stream_adapter_->SetIdentity(ssl_identity_->GetReference());
194
195 // Set a bogus peer certificate digest.
196 unsigned char digest[20];
197 size_t digest_len = sizeof(digest);
198 ssl_stream_adapter_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, digest,
199 digest_len);
200
201 ssl_stream_adapter_->StartSSLWithPeer();
202
203 ssl_stream_adapter_->SignalEvent.connect(this,
204 &SSLAdapterTestDummyServer::OnSSLStreamAdapterEvent);
205 }
206
207 void OnSSLStreamAdapterEvent(rtc::StreamInterface* stream, int sig, int err) {
208 if (sig & rtc::SE_READ) {
209 char buffer[4096] = "";
210
211 size_t read;
212 int error;
213
214 // Read data received from the client and store it in our internal
215 // buffer.
216 rtc::StreamResult r = stream->Read(buffer,
217 sizeof(buffer) - 1, &read, &error);
218 if (r == rtc::SR_SUCCESS) {
219 buffer[read] = '\0';
220
221 LOG(LS_INFO) << "Server received '" << buffer << "'";
222
223 data_ += buffer;
224 }
225 }
226 }
227
228 private:
229 const rtc::SSLMode ssl_mode_;
230
231 rtc::scoped_ptr<rtc::AsyncSocket> server_socket_;
232 rtc::scoped_ptr<rtc::SSLStreamAdapter> ssl_stream_adapter_;
233
234 rtc::scoped_ptr<rtc::SSLIdentity> ssl_identity_;
235
236 std::string data_;
237};
238
239class SSLAdapterTestBase : public testing::Test,
240 public sigslot::has_slots<> {
241 public:
242 explicit SSLAdapterTestBase(const rtc::SSLMode& ssl_mode)
243 : ssl_mode_(ssl_mode),
244 ss_scope_(new rtc::VirtualSocketServer(NULL)),
245 server_(new SSLAdapterTestDummyServer(ssl_mode_)),
246 client_(new SSLAdapterTestDummyClient(ssl_mode_)),
247 handshake_wait_(kTimeout) {
248 }
249
250 static void SetUpTestCase() {
251 rtc::InitializeSSL();
252 }
253
254 static void TearDownTestCase() {
255 rtc::CleanupSSL();
256 }
257
258 void SetHandshakeWait(int wait) {
259 handshake_wait_ = wait;
260 }
261
262 void TestHandshake(bool expect_success) {
263 int rv;
264
265 // The initial state is CS_CLOSED
266 ASSERT_EQ(rtc::AsyncSocket::CS_CLOSED, client_->GetState());
267
268 rv = client_->Connect(server_->GetHostname(), server_->GetAddress());
269 ASSERT_EQ(0, rv);
270
271 // Now the state should be CS_CONNECTING
272 ASSERT_EQ(rtc::AsyncSocket::CS_CONNECTING, client_->GetState());
273
274 if (expect_success) {
275 // If expecting success, the client should end up in the CS_CONNECTED
276 // state after handshake.
277 EXPECT_EQ_WAIT(rtc::AsyncSocket::CS_CONNECTED, client_->GetState(),
278 handshake_wait_);
279
280 LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) << " handshake complete.";
281
282 } else {
283 // On handshake failure the client should end up in the CS_CLOSED state.
284 EXPECT_EQ_WAIT(rtc::AsyncSocket::CS_CLOSED, client_->GetState(),
285 handshake_wait_);
286
287 LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) << " handshake failed.";
288 }
289 }
290
291 void TestTransfer(const std::string& message) {
292 int rv;
293
294 rv = client_->Send(message);
295 ASSERT_EQ(static_cast<int>(message.length()), rv);
296
297 // The server should have received the client's message.
298 EXPECT_EQ_WAIT(message, server_->GetReceivedData(), kTimeout);
299
300 rv = server_->Send(message);
301 ASSERT_EQ(static_cast<int>(message.length()), rv);
302
303 // The client should have received the server's message.
304 EXPECT_EQ_WAIT(message, client_->GetReceivedData(), kTimeout);
305
306 LOG(LS_INFO) << "Transfer complete.";
307 }
308
309 private:
310 const rtc::SSLMode ssl_mode_;
311
312 const rtc::SocketServerScope ss_scope_;
313
314 rtc::scoped_ptr<SSLAdapterTestDummyServer> server_;
315 rtc::scoped_ptr<SSLAdapterTestDummyClient> client_;
316
317 int handshake_wait_;
318};
319
320class SSLAdapterTestTLS : public SSLAdapterTestBase {
321 public:
322 SSLAdapterTestTLS() : SSLAdapterTestBase(rtc::SSL_MODE_TLS) {}
323};
324
325
326#if SSL_USE_OPENSSL
327
328// Basic tests: TLS
329
330// Test that handshake works
331TEST_F(SSLAdapterTestTLS, TestTLSConnect) {
332 TestHandshake(true);
333}
334
335// Test transfer between client and server
336TEST_F(SSLAdapterTestTLS, TestTLSTransfer) {
337 TestHandshake(true);
338 TestTransfer("Hello, world!");
339}
340
341#endif // SSL_USE_OPENSSL
342