std::shared_ptr<ssl_context> WSService::on_tls_init(websocketpp::connection_hdl hdl) { log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION; auto ssl_ctx_ptr = make_ssl_ctx(); ssl_ctx_ptr->set_verify_callback(std::bind(&WSService::on_tls_verify, this, hdl, std::placeholders::_1, std::placeholders::_2)); return ssl_ctx_ptr; }
void TcpServer::AsyncSecureAccept() { auto errorHandler = std::bind(&TcpServer::ErrorHandler, this, std::placeholders::_1, std::placeholders::_2); auto context = boost::asio::ssl::context(boost::asio::ssl::context::sslv23); auto optionsMask = boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use; if (_securityOptions.VerifyClient) { auto verifyCallback = [](bool preverified, boost::asio::ssl::verify_context& ctx) { std::cout << "Verifying certificate, pre-verified: " << std::string(preverified ? "true" : "false"); char subject_name[256]; X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); LOG() << "Verifying, subject: " << subject_name << "\n"; char issuer_name[256]; X509_NAME_oneline(X509_get_issuer_name(cert), issuer_name, 256); LOG() << "Verifying, issuer: " << issuer_name << "\n"; return preverified; }; context.set_verify_mode(boost::asio::ssl::context::verify_fail_if_no_peer_cert | boost::asio::ssl::verify_peer); context.set_verify_callback(verifyCallback); context.load_verify_file(_securityOptions.ClientVerifyFile); } context.set_options(optionsMask); context.set_password_callback(std::bind(&TcpServer::GetPassword, this)); context.use_certificate_chain_file(_securityOptions.CertificateFilename); context.use_rsa_private_key_file(_securityOptions.PrivKeyFilename, boost::asio::ssl::context::pem); context.use_tmp_dh_file(_securityOptions.DHExchangeFilename); auto conn = std::make_shared<TcpSslConnection>(_ioService, std::move(context), std::move(errorHandler)); auto acceptor = std::bind(&TcpServer::SecureAcceptHandler, this, conn, std::placeholders::_1); // Async accept does not block and takes references to the socket and end point of the connection. // The connection smart pointer is kept alive by being bound to the acceptor callback. _acceptor->async_accept(conn->PeerSocket, conn->PeerEndPoint, std::move(acceptor)); }
client connect(const uri& uri) { static asio::io_service service; if (uri.scheme() == "http") { auto socket = std::make_unique<http_socket_t>(service); connect(uri, socket); return std::make_shared<client_impl<http_socket_t>>(std::move(socket), uri.host()); } else { ssl::context context(ssl::context::sslv23_client); context.set_default_verify_paths(); auto socket = std::make_unique<https_socket_t>(service, context); connect(uri, socket); socket->set_verify_mode(ssl::verify_peer); socket->set_verify_callback(ssl::rfc2818_verification(uri.host())); socket->handshake(ssl::stream_base::client); return std::make_shared<client_impl<https_socket_t>>(std::move(socket), uri.host()); } }
bool TLSClient::BeginConnect(const IPEndpoint& remote, const connect_callback_t& callback) { if (canceled) return false; auto stream = std::make_shared<asio::ssl::stream<asio::ip::tcp::socket>>(this->executor->strand.get_io_service(), this->ctx.value); auto verify = [self = shared_from_this()](bool preverified, asio::ssl::verify_context& ctx) -> bool { self->LogVerifyCallback(preverified, ctx); return preverified; }; std::error_code ec; stream->set_verify_callback(verify, ec); if (ec) { auto cb = [self = shared_from_this(), callback, stream, ec] { if (!self->canceled) { callback(self->executor, stream, ec); } }; this->executor->strand.post(cb); return true; } SocketHelpers::BindToLocalAddress(this->adapter, this->localEndpoint, stream->lowest_layer(), ec); if (ec) { auto cb = [self = shared_from_this(), callback, stream, ec] { if (!self->canceled) { callback(self->executor, stream, ec); } }; this->executor->strand.post(cb); return true; } const auto address = asio::ip::address::from_string(remote.address, ec); auto self = this->shared_from_this(); if (ec) { // Try DNS resolution instead auto cb = [self, callback, stream](const std::error_code& ec, asio::ip::tcp::resolver::iterator endpoints) { self->HandleResolveResult(callback, stream, endpoints, ec); }; std::stringstream portstr; portstr << remote.port; resolver.async_resolve(asio::ip::tcp::resolver::query(remote.address, portstr.str()), executor->strand.wrap(cb)); return true; } asio::ip::tcp::endpoint remoteEndpoint(address, remote.port); auto cb = [self, stream, callback](const std::error_code& ec) { self->HandleConnectResult(callback, stream, ec); }; stream->lowest_layer().async_connect(remoteEndpoint, executor->strand.wrap(cb)); return true; }