Line data Source code
1 : /* 2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. 3 : * Copyright Contributors to the OpenSDN project 4 : */ 5 : 6 : #include <boost/asio.hpp> 7 : #include <boost/bind/bind.hpp> 8 : 9 : #include "io/ssl_server.h" 10 : #include "io/ssl_session.h" 11 : 12 : #include "io/event_manager.h" 13 : #include "io/io_utils.h" 14 : #include "io/io_log.h" 15 : 16 : using namespace boost::placeholders; 17 : 18 7415 : SslServer::SslServer(EventManager *evm, boost::asio::ssl::context::method m, 19 7415 : bool ssl_enabled, bool ssl_handshake_delayed) 20 7415 : : TcpServer(evm), context_(m), 21 7415 : ssl_enabled_(ssl_enabled), ssl_handshake_delayed_(ssl_handshake_delayed) { 22 7415 : boost::system::error_code ec; 23 : // By default set verify mode to none, to be set by derived class later. 24 7415 : context_.set_verify_mode(boost::asio::ssl::context::verify_none, ec); 25 7415 : assert(ec.value() == 0); 26 7415 : context_.set_options(boost::asio::ssl::context::default_workarounds | 27 : boost::asio::ssl::context::no_sslv3 | 28 : boost::asio::ssl::context::no_sslv2 | 29 : boost::asio::ssl::context::no_tlsv1 | 30 : boost::asio::ssl::context::no_tlsv1_1, ec); 31 7415 : assert(ec.value() == 0); 32 : 33 : #if BOOST_VERSION >= 105400 34 7415 : if (getenv("CONTRAIL_SSL_SOCKET_COMPRESSION_ENABLE")) { 35 0 : context_.clear_options(boost::asio::ssl::context::no_compression, ec); 36 0 : assert(ec.value() == 0); 37 : } 38 : #endif 39 7415 : } 40 : 41 7414 : SslServer::~SslServer() { 42 7414 : } 43 : 44 1198 : boost::asio::ssl::context *SslServer::context() { 45 1198 : return &context_; 46 : } 47 : 48 14474 : TcpSession *SslServer::AllocSession(bool server_session) { 49 : SslSession *session; 50 14474 : if (server_session) { 51 6596 : session = AllocSession(so_ssl_accept_.get()); 52 : 53 : // if session allocate succeeds release ownership to so_accept. 54 6596 : if (session != NULL) { 55 6596 : so_ssl_accept_.release(); 56 : } 57 : } else { 58 7878 : SslSocket *socket = new SslSocket(*event_manager()->io_service(), 59 7878 : context_); 60 7878 : session = AllocSession(socket); 61 : } 62 : 63 14474 : return session; 64 : } 65 : 66 6596 : void SslServer::AcceptHandlerComplete(TcpSessionPtr session) { 67 6596 : SslSession *ssl = static_cast<SslSession*>(session.get()); 68 6596 : if (ssl->IsSslDisabled() || ssl->IsSslHandShakeDelayed()) { 69 6591 : TcpServer::AcceptHandlerComplete(session); 70 : } else { 71 : // trigger ssl server handshake 72 5 : std::srand(static_cast<unsigned>(std::time(0))); 73 5 : ssl->ssl_handshake_in_progress_ = true; 74 : ssl->ssl_socket_->async_handshake 75 10 : (boost::asio::ssl::stream_base::server, 76 10 : boost::bind(&SslServer::AcceptHandShakeHandler, 77 10 : TcpServerPtr(this), TcpSessionPtr(ssl), 78 : boost::asio::placeholders::error)); 79 : } 80 6596 : } 81 : 82 5 : void SslServer::AcceptHandShakeHandler(TcpServerPtr server, 83 : TcpSessionPtr session, 84 : const boost::system::error_code& error) { 85 5 : SslServer *ssl_server = static_cast<SslServer *>(server.get()); 86 5 : SslSession *ssl_session = static_cast<SslSession *>(session.get()); 87 5 : ssl_session->ssl_handshake_in_progress_ = false; 88 5 : if (!error) { 89 : // on successful handshake continue with tcp server state machine. 90 3 : ssl_session->SetSslHandShakeSuccess(); 91 3 : ssl_server->TcpServer::AcceptHandlerComplete(session); 92 : } else { 93 : // close session on failure 94 2 : ssl_session->SetSslHandShakeFailure(); 95 2 : TCP_SESSION_LOG_ERROR(ssl_session, TCP_DIR_OUT, 96 : "SSL Handshake failed due to error: " 97 : << error.value() << " category: " 98 : << error.category().name() 99 : << " message: " << error.message()); 100 2 : ssl_session->CloseInternal(error, false, false); 101 : } 102 5 : } 103 : 104 6645 : void SslServer::ConnectHandlerComplete(TcpSessionPtr session) { 105 6645 : SslSession *ssl = static_cast<SslSession*>(session.get()); 106 6645 : if (ssl->IsSslDisabled() || ssl->IsSslHandShakeDelayed()) { 107 6639 : TcpServer::ConnectHandlerComplete(session); 108 : } else { 109 : // trigger ssl client handshake 110 6 : std::srand(static_cast<unsigned>(std::time(0))); 111 6 : ssl->ssl_handshake_in_progress_ = true; 112 : ssl->ssl_socket_->async_handshake 113 12 : (boost::asio::ssl::stream_base::client, 114 12 : boost::bind(&SslServer::ConnectHandShakeHandler, 115 12 : TcpServerPtr(this), TcpSessionPtr(ssl), 116 : boost::asio::placeholders::error)); 117 : } 118 6645 : } 119 : 120 6 : void SslServer::ConnectHandShakeHandler(TcpServerPtr server, 121 : TcpSessionPtr session, const boost::system::error_code& error) { 122 6 : SslServer *ssl_server = static_cast<SslServer *>(server.get()); 123 6 : SslSession *ssl_session = static_cast<SslSession *>(session.get()); 124 6 : ssl_session->ssl_handshake_in_progress_ = false; 125 6 : if (!error) { 126 : // on successful handshake continue with tcp server state machine. 127 4 : ssl_session->SetSslHandShakeSuccess(); 128 4 : ssl_server->TcpServer::ConnectHandlerComplete(session); 129 : } else { 130 : // report connect failure and close the session 131 2 : ssl_session->SetSslHandShakeFailure(); 132 2 : ssl_session->CloseInternal(error, false, false); 133 2 : TCP_SESSION_LOG_ERROR(ssl_session, TCP_DIR_OUT, 134 : "SSL Handshake failed due to error: " 135 : << error.value() << " category: " 136 : << error.category().name() 137 : << " message: " << error.message()); 138 2 : ssl_session->ConnectFailed(); 139 : } 140 6 : } 141 : 142 15475 : TcpServer::Socket *SslServer::accept_socket() const { 143 : // return tcp socket 144 15475 : return &(so_ssl_accept_->next_layer()); 145 : } 146 : 147 8879 : void SslServer::set_accept_socket() { 148 17758 : so_ssl_accept_.reset(new SslSocket(*event_manager()->io_service(), 149 8879 : context_)); 150 8879 : }