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