1c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org/* 2c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org * 4c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org * Use of this source code is governed by a BSD-style license 5c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org * that can be found in the LICENSE file in the root of the source 6c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org * tree. An additional intellectual property rights grant can be found 7c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org * in the file PATENTS. All contributing project authors may 8c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org * be found in the AUTHORS file in the root of the source tree. 9c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org */ 10c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 11c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org#include <string> 12c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 13c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org#include "webrtc/base/gunit.h" 14c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org#include "webrtc/base/ipaddress.h" 15c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org#include "webrtc/base/socketstream.h" 16c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org#include "webrtc/base/ssladapter.h" 17c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org#include "webrtc/base/sslstreamadapter.h" 18b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund#include "webrtc/base/sslidentity.h" 19c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org#include "webrtc/base/stream.h" 20c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org#include "webrtc/base/virtualsocketserver.h" 21c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 22c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.orgstatic const int kTimeout = 5000; 23c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 24c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.orgstatic rtc::AsyncSocket* CreateSocket(const rtc::SSLMode& ssl_mode) { 25c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::SocketAddress address(rtc::IPAddress(INADDR_ANY), 0); 26c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 27c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::AsyncSocket* socket = rtc::Thread::Current()-> 28c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org socketserver()->CreateAsyncSocket( 29c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org address.family(), (ssl_mode == rtc::SSL_MODE_DTLS) ? 30c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org SOCK_DGRAM : SOCK_STREAM); 31c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org socket->Bind(address); 32c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 33c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return socket; 34c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org} 35c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 36c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.orgstatic std::string GetSSLProtocolName(const rtc::SSLMode& ssl_mode) { 37c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return (ssl_mode == rtc::SSL_MODE_DTLS) ? "DTLS" : "TLS"; 38c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org} 39c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 40c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.orgclass SSLAdapterTestDummyClient : public sigslot::has_slots<> { 41c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org public: 42c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org explicit SSLAdapterTestDummyClient(const rtc::SSLMode& ssl_mode) 43c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org : ssl_mode_(ssl_mode) { 44c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::AsyncSocket* socket = CreateSocket(ssl_mode_); 45c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 46c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org ssl_adapter_.reset(rtc::SSLAdapter::Create(socket)); 47c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 48a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ssl_adapter_->SetMode(ssl_mode_); 49a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 50c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // Ignore any certificate errors for the purpose of testing. 51c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // Note: We do this only because we don't have a real certificate. 52c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // NEVER USE THIS IN PRODUCTION CODE! 53c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org ssl_adapter_->set_ignore_bad_cert(true); 54c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 55c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org ssl_adapter_->SignalReadEvent.connect(this, 56c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org &SSLAdapterTestDummyClient::OnSSLAdapterReadEvent); 57c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org ssl_adapter_->SignalCloseEvent.connect(this, 58c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org &SSLAdapterTestDummyClient::OnSSLAdapterCloseEvent); 59c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 60c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 61a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org rtc::SocketAddress GetAddress() const { 62a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org return ssl_adapter_->GetLocalAddress(); 63a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org } 64a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 65c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::AsyncSocket::ConnState GetState() const { 66c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return ssl_adapter_->GetState(); 67c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 68c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 69c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org const std::string& GetReceivedData() const { 70c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return data_; 71c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 72c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 73c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org int Connect(const std::string& hostname, const rtc::SocketAddress& address) { 74a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org LOG(LS_INFO) << "Initiating connection with " << address; 75c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 76a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org int rv = ssl_adapter_->Connect(address); 77c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 78a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org if (rv == 0) { 79a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org LOG(LS_INFO) << "Starting " << GetSSLProtocolName(ssl_mode_) 80a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org << " handshake with " << hostname; 81c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 82a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org if (ssl_adapter_->StartSSL(hostname.c_str(), false) != 0) { 83a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org return -1; 84a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org } 85a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org } 86a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 87a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org return rv; 88c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 89c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 90c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org int Close() { 91c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return ssl_adapter_->Close(); 92c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 93c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 94c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org int Send(const std::string& message) { 95c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org LOG(LS_INFO) << "Client sending '" << message << "'"; 96c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 97c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return ssl_adapter_->Send(message.data(), message.length()); 98c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 99c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 100c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org void OnSSLAdapterReadEvent(rtc::AsyncSocket* socket) { 101c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org char buffer[4096] = ""; 102c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 103c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // Read data received from the server and store it in our internal buffer. 104c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org int read = socket->Recv(buffer, sizeof(buffer) - 1); 105c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org if (read != -1) { 106c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org buffer[read] = '\0'; 107c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 108c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org LOG(LS_INFO) << "Client received '" << buffer << "'"; 109c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 110c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org data_ += buffer; 111c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 112c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 113c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 114c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org void OnSSLAdapterCloseEvent(rtc::AsyncSocket* socket, int error) { 115c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // OpenSSLAdapter signals handshake failure with a close event, but without 116c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // closing the socket! Let's close the socket here. This way GetState() can 117c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // return CS_CLOSED after failure. 118c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org if (socket->GetState() != rtc::AsyncSocket::CS_CLOSED) { 119c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org socket->Close(); 120c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 121c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 122c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 123c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org private: 124c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org const rtc::SSLMode ssl_mode_; 125c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 126c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::scoped_ptr<rtc::SSLAdapter> ssl_adapter_; 127c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 128c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org std::string data_; 129c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org}; 130c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 131c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.orgclass SSLAdapterTestDummyServer : public sigslot::has_slots<> { 132c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org public: 133b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund explicit SSLAdapterTestDummyServer(const rtc::SSLMode& ssl_mode, 1344e572470a3f181a043f9f9b98cc0153b7195b9f5torbjorng const rtc::KeyParams& key_params) 135c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org : ssl_mode_(ssl_mode) { 136c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // Generate a key pair and a certificate for this host. 1374e572470a3f181a043f9f9b98cc0153b7195b9f5torbjorng ssl_identity_.reset(rtc::SSLIdentity::Generate(GetHostname(), key_params)); 138c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 139c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org server_socket_.reset(CreateSocket(ssl_mode_)); 140c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 141a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org if (ssl_mode_ == rtc::SSL_MODE_TLS) { 142a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org server_socket_->SignalReadEvent.connect(this, 143a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org &SSLAdapterTestDummyServer::OnServerSocketReadEvent); 144c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 145a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org server_socket_->Listen(1); 146a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org } 147c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 148c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org LOG(LS_INFO) << ((ssl_mode_ == rtc::SSL_MODE_DTLS) ? "UDP" : "TCP") 149c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org << " server listening on " << server_socket_->GetLocalAddress(); 150c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 151c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 152c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::SocketAddress GetAddress() const { 153c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return server_socket_->GetLocalAddress(); 154c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 155c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 156c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org std::string GetHostname() const { 157c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // Since we don't have a real certificate anyway, the value here doesn't 158c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // really matter. 159c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return "example.com"; 160c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 161c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 162c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org const std::string& GetReceivedData() const { 163c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return data_; 164c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 165c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 166c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org int Send(const std::string& message) { 167c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org if (ssl_stream_adapter_ == NULL 168c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org || ssl_stream_adapter_->GetState() != rtc::SS_OPEN) { 169c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // No connection yet. 170c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return -1; 171c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 172c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 173c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org LOG(LS_INFO) << "Server sending '" << message << "'"; 174c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 175c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org size_t written; 176c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org int error; 177c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 178c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::StreamResult r = ssl_stream_adapter_->Write(message.data(), 179c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org message.length(), &written, &error); 180c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org if (r == rtc::SR_SUCCESS) { 181c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return written; 182c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } else { 183c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org return -1; 184c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 185c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 186c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 187a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org void AcceptConnection(const rtc::SocketAddress& address) { 188a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // Only a single connection is supported. 189a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ASSERT_TRUE(ssl_stream_adapter_ == NULL); 190c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 191a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // This is only for DTLS. 192a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ASSERT_EQ(rtc::SSL_MODE_DTLS, ssl_mode_); 193c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 194a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // Transfer ownership of the socket to the SSLStreamAdapter object. 195a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org rtc::AsyncSocket* socket = server_socket_.release(); 196c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 197a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org socket->Connect(address); 198c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 199a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org DoHandshake(socket); 200a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org } 201c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 202a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org void OnServerSocketReadEvent(rtc::AsyncSocket* socket) { 203a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // Only a single connection is supported. 204a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ASSERT_TRUE(ssl_stream_adapter_ == NULL); 205c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 206a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org DoHandshake(server_socket_->Accept(NULL)); 207c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 208c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 209c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org void OnSSLStreamAdapterEvent(rtc::StreamInterface* stream, int sig, int err) { 210c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org if (sig & rtc::SE_READ) { 211c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org char buffer[4096] = ""; 212c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 213c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org size_t read; 214c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org int error; 215c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 216c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // Read data received from the client and store it in our internal 217c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // buffer. 218c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::StreamResult r = stream->Read(buffer, 219c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org sizeof(buffer) - 1, &read, &error); 220c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org if (r == rtc::SR_SUCCESS) { 221c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org buffer[read] = '\0'; 222c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 223c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org LOG(LS_INFO) << "Server received '" << buffer << "'"; 224c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 225c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org data_ += buffer; 226c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 227c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 228c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 229c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 230c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org private: 231a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org void DoHandshake(rtc::AsyncSocket* socket) { 232a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org rtc::SocketStream* stream = new rtc::SocketStream(socket); 233a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 234a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ssl_stream_adapter_.reset(rtc::SSLStreamAdapter::Create(stream)); 235a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 236a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ssl_stream_adapter_->SetMode(ssl_mode_); 237a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ssl_stream_adapter_->SetServerRole(); 238a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 239a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // SSLStreamAdapter is normally used for peer-to-peer communication, but 240a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // here we're testing communication between a client and a server 241a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // (e.g. a WebRTC-based application and an RFC 5766 TURN server), where 242a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // clients are not required to provide a certificate during handshake. 243a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // Accordingly, we must disable client authentication here. 244a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ssl_stream_adapter_->set_client_auth_enabled(false); 245a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 246a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ssl_stream_adapter_->SetIdentity(ssl_identity_->GetReference()); 247a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 248a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // Set a bogus peer certificate digest. 249a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org unsigned char digest[20]; 250a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org size_t digest_len = sizeof(digest); 251a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ssl_stream_adapter_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, digest, 252a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org digest_len); 253a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 254a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ssl_stream_adapter_->StartSSLWithPeer(); 255a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 256a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org ssl_stream_adapter_->SignalEvent.connect(this, 257a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org &SSLAdapterTestDummyServer::OnSSLStreamAdapterEvent); 258a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org } 259a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 260c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org const rtc::SSLMode ssl_mode_; 261c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 262c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::scoped_ptr<rtc::AsyncSocket> server_socket_; 263c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::scoped_ptr<rtc::SSLStreamAdapter> ssl_stream_adapter_; 264c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 265c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::scoped_ptr<rtc::SSLIdentity> ssl_identity_; 266c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 267c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org std::string data_; 268c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org}; 269c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 270c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.orgclass SSLAdapterTestBase : public testing::Test, 271c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org public sigslot::has_slots<> { 272c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org public: 273b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund explicit SSLAdapterTestBase(const rtc::SSLMode& ssl_mode, 2744e572470a3f181a043f9f9b98cc0153b7195b9f5torbjorng const rtc::KeyParams& key_params) 275c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org : ssl_mode_(ssl_mode), 276c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org ss_scope_(new rtc::VirtualSocketServer(NULL)), 2774e572470a3f181a043f9f9b98cc0153b7195b9f5torbjorng server_(new SSLAdapterTestDummyServer(ssl_mode_, key_params)), 278c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org client_(new SSLAdapterTestDummyClient(ssl_mode_)), 279b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund handshake_wait_(kTimeout) {} 280c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 281c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org void SetHandshakeWait(int wait) { 282c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org handshake_wait_ = wait; 283c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 284c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 285c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org void TestHandshake(bool expect_success) { 286c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org int rv; 287c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 288c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // The initial state is CS_CLOSED 289c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org ASSERT_EQ(rtc::AsyncSocket::CS_CLOSED, client_->GetState()); 290c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 291c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rv = client_->Connect(server_->GetHostname(), server_->GetAddress()); 292c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org ASSERT_EQ(0, rv); 293c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 294c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // Now the state should be CS_CONNECTING 295c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org ASSERT_EQ(rtc::AsyncSocket::CS_CONNECTING, client_->GetState()); 296c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 297a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org if (ssl_mode_ == rtc::SSL_MODE_DTLS) { 298a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org // For DTLS, call AcceptConnection() with the client's address. 299a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org server_->AcceptConnection(client_->GetAddress()); 300a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org } 301a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 302c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org if (expect_success) { 303c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // If expecting success, the client should end up in the CS_CONNECTED 304c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // state after handshake. 305c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org EXPECT_EQ_WAIT(rtc::AsyncSocket::CS_CONNECTED, client_->GetState(), 306c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org handshake_wait_); 307c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 308c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) << " handshake complete."; 309c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 310c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } else { 311c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // On handshake failure the client should end up in the CS_CLOSED state. 312c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org EXPECT_EQ_WAIT(rtc::AsyncSocket::CS_CLOSED, client_->GetState(), 313c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org handshake_wait_); 314c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 315c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) << " handshake failed."; 316c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 317c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 318c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 319c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org void TestTransfer(const std::string& message) { 320c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org int rv; 321c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 322c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rv = client_->Send(message); 323c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org ASSERT_EQ(static_cast<int>(message.length()), rv); 324c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 325c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // The server should have received the client's message. 326c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org EXPECT_EQ_WAIT(message, server_->GetReceivedData(), kTimeout); 327c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 328c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rv = server_->Send(message); 329c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org ASSERT_EQ(static_cast<int>(message.length()), rv); 330c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 331c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org // The client should have received the server's message. 332c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org EXPECT_EQ_WAIT(message, client_->GetReceivedData(), kTimeout); 333c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 334c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org LOG(LS_INFO) << "Transfer complete."; 335c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org } 336c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 337c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org private: 338c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org const rtc::SSLMode ssl_mode_; 339c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 340c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org const rtc::SocketServerScope ss_scope_; 341c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 342c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::scoped_ptr<SSLAdapterTestDummyServer> server_; 343c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org rtc::scoped_ptr<SSLAdapterTestDummyClient> client_; 344c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 345c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org int handshake_wait_; 346c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org}; 347c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 348b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlundclass SSLAdapterTestTLS_RSA : public SSLAdapterTestBase { 349b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund public: 350b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund SSLAdapterTestTLS_RSA() 3514e572470a3f181a043f9f9b98cc0153b7195b9f5torbjorng : SSLAdapterTestBase(rtc::SSL_MODE_TLS, rtc::KeyParams::RSA()) {} 352b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund}; 353b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund 354b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlundclass SSLAdapterTestTLS_ECDSA : public SSLAdapterTestBase { 355c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org public: 356b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund SSLAdapterTestTLS_ECDSA() 3574e572470a3f181a043f9f9b98cc0153b7195b9f5torbjorng : SSLAdapterTestBase(rtc::SSL_MODE_TLS, rtc::KeyParams::ECDSA()) {} 358c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org}; 359c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 360b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlundclass SSLAdapterTestDTLS_RSA : public SSLAdapterTestBase { 361a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org public: 362b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund SSLAdapterTestDTLS_RSA() 3634e572470a3f181a043f9f9b98cc0153b7195b9f5torbjorng : SSLAdapterTestBase(rtc::SSL_MODE_DTLS, rtc::KeyParams::RSA()) {} 364b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund}; 365b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund 366b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlundclass SSLAdapterTestDTLS_ECDSA : public SSLAdapterTestBase { 367b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund public: 368b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund SSLAdapterTestDTLS_ECDSA() 3694e572470a3f181a043f9f9b98cc0153b7195b9f5torbjorng : SSLAdapterTestBase(rtc::SSL_MODE_DTLS, rtc::KeyParams::ECDSA()) {} 370a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org}; 371c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 372c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org#if SSL_USE_OPENSSL 373c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 374c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org// Basic tests: TLS 375c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 376b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund// Test that handshake works, using RSA 377b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn GranlundTEST_F(SSLAdapterTestTLS_RSA, TestTLSConnect) { 378b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund TestHandshake(true); 379b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund} 380b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund 381b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund// Test that handshake works, using ECDSA 382b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn GranlundTEST_F(SSLAdapterTestTLS_ECDSA, TestTLSConnect) { 383b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund TestHandshake(true); 384b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund} 385b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund 386b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund// Test transfer between client and server, using RSA 387b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn GranlundTEST_F(SSLAdapterTestTLS_RSA, TestTLSTransfer) { 388c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org TestHandshake(true); 389b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund TestTransfer("Hello, world!"); 390c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org} 391c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 392b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund// Test transfer between client and server, using ECDSA 393b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn GranlundTEST_F(SSLAdapterTestTLS_ECDSA, TestTLSTransfer) { 394c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org TestHandshake(true); 395c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org TestTransfer("Hello, world!"); 396c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org} 397c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 398a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org// Basic tests: DTLS 399a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 400b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund// Test that handshake works, using RSA 401b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn GranlundTEST_F(SSLAdapterTestDTLS_RSA, TestDTLSConnect) { 402b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund TestHandshake(true); 403b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund} 404b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund 405b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund// Test that handshake works, using ECDSA 406b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn GranlundTEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSConnect) { 407a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org TestHandshake(true); 408a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org} 409a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 410b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund// Test transfer between client and server, using RSA 411b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn GranlundTEST_F(SSLAdapterTestDTLS_RSA, TestDTLSTransfer) { 412a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org TestHandshake(true); 413a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org TestTransfer("Hello, world!"); 414a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org} 415a9b1ec024772564a190a4680cfa30414a5338cd4pthatcher@webrtc.org 416b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund// Test transfer between client and server, using ECDSA 417b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn GranlundTEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSTransfer) { 418b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund TestHandshake(true); 419b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund TestTransfer("Hello, world!"); 420b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund} 421c569a49a3dafdb5017961736c7715624dd059240tkchin@webrtc.org 422b6d4ec418504fd947c6f96829c73180e9487e203Torbjorn Granlund#endif // SSL_USE_OPENSSL 423