1 #ifndef SIMPLE_WEB_SERVER_HTTPS_HPP 2 #define SIMPLE_WEB_SERVER_HTTPS_HPP 3 4 #include "server_http.hpp" 5 6 #ifdef ASIO_STANDALONE 7 #include <asio/ssl.hpp> 8 #else 9 #include <boost/asio/ssl.hpp> 10 #endif 11 12 #include <algorithm> 13 #include <openssl/ssl.h> 14 15 namespace SimpleWeb { 16 using HTTPS = asio::ssl::stream<asio::ip::tcp::socket>; 17 18 template <> 19 class Server<HTTPS> : public ServerBase<HTTPS> { 20 bool set_session_id_context = false; 21 22 public: 23 /** 24 * Constructs a server object. 25 * 26 * @param certification_file Sends the given certification file to client. 27 * @param private_key_file Specifies the file containing the private key for certification_file. 28 * @param verify_file If non-empty, use this certificate authority file to perform verification of client's certificate and hostname according to RFC 2818. 29 */ Server(const std::string & certification_file,const std::string & private_key_file,const std::string & verify_file=std::string ())30 Server(const std::string &certification_file, const std::string &private_key_file, const std::string &verify_file = std::string()) 31 : ServerBase<HTTPS>::ServerBase(443), 32 #if(ASIO_STANDALONE && ASIO_VERSION >= 101300) || BOOST_ASIO_VERSION >= 101300 33 context(asio::ssl::context::tls_server) { 34 // Disabling TLS 1.0 and 1.1 (see RFC 8996) 35 context.set_options(asio::ssl::context::no_tlsv1); 36 context.set_options(asio::ssl::context::no_tlsv1_1); 37 #else 38 context(asio::ssl::context::tlsv12) { 39 #endif 40 41 context.use_certificate_chain_file(certification_file); 42 context.use_private_key_file(private_key_file, asio::ssl::context::pem); 43 44 if(verify_file.size() > 0) { 45 context.load_verify_file(verify_file); 46 context.set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert | asio::ssl::verify_client_once); 47 set_session_id_context = true; 48 } 49 } 50 51 protected: 52 asio::ssl::context context; 53 54 void after_bind() override { 55 if(set_session_id_context) { 56 // Creating session_id_context from address:port but reversed due to small SSL_MAX_SSL_SESSION_ID_LENGTH 57 auto session_id_context = std::to_string(acceptor->local_endpoint().port()) + ':'; 58 session_id_context.append(config.address.rbegin(), config.address.rend()); 59 SSL_CTX_set_session_id_context(context.native_handle(), 60 reinterpret_cast<const unsigned char *>(session_id_context.data()), 61 static_cast<unsigned int>(std::min<std::size_t>(session_id_context.size(), SSL_MAX_SSL_SESSION_ID_LENGTH))); 62 } 63 } 64 65 void accept() override { 66 auto connection = create_connection(*io_service, context); 67 68 acceptor->async_accept(connection->socket->lowest_layer(), [this, connection](const error_code &ec) { 69 auto lock = connection->handler_runner->continue_lock(); 70 if(!lock) 71 return; 72 73 if(ec != error::operation_aborted) 74 this->accept(); 75 76 auto session = std::make_shared<Session>(config.max_request_streambuf_size, connection); 77 78 if(!ec) { 79 asio::ip::tcp::no_delay option(true); 80 error_code ec; 81 session->connection->socket->lowest_layer().set_option(option, ec); 82 83 session->connection->set_timeout(config.timeout_request); 84 session->connection->socket->async_handshake(asio::ssl::stream_base::server, [this, session](const error_code &ec) { 85 session->connection->cancel_timeout(); 86 auto lock = session->connection->handler_runner->continue_lock(); 87 if(!lock) 88 return; 89 if(!ec) 90 this->read(session); 91 else if(this->on_error) 92 this->on_error(session->request, ec); 93 }); 94 } 95 else if(this->on_error) 96 this->on_error(session->request, ec); 97 }); 98 } 99 }; 100 } // namespace SimpleWeb 101 102 #endif /* SIMPLE_WEB_SERVER_HTTPS_HPP */ 103