我有一个基于 Boost Beast asio 的 websocket 服务器,它(以缩写形式)像这样启动
ssl_context_.set_options(
boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::no_tlsv1 |
boost::asio::ssl::context::no_tlsv1_1
);
ssl_context_.use_certificate_file(
auth->server_cert,
boost::asio::ssl::context::file_format::pem
);
ssl_context_.use_private_key_file(
auth->server_key,
boost::asio::ssl::context::file_format::pem
);
ssl_context_.load_verify_file(auth->ca);
ssl_context_.set_verify_mode(
boost::asio::ssl::verify_peer |
boost::asio::ssl::verify_fail_if_no_peer_cert
);
ssl_context_.set_verify_callback(
std::bind(
&verify_certificate_cb, std::placeholders::_1, std::placeholders::_2
)
);
try
{
const boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::make_address(ip), port);
acceptor_.open(endpoint.protocol());
acceptor_.set_option(boost::asio::socket_base::reuse_address(true));
acceptor_.bind(endpoint);
acceptor_.listen();
}
catch(const boost::system::system_error &e)
{
LOG_ERROR("Acceptor error: " << e.what());
return;
}
acceptor_.async_accept(io_context_, boost::beast::bind_front_handler(&server::accept_handler, this));
然后,我有
static bool verify_certificate_cb(bool preverified, boost::asio::ssl::verify_context& ctx)
{
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_INFO("TLS connection verification for: " << subject_name);
return preverified;
}
void server::accept_handler(const boost::system::error_code& error, boost::asio::ip::tcp::socket socket) noexcept
{
if (!error)
{
// Using Boost's asio paradigm, websocket binds its completion handlers to a shared ptr of this object.
// This allows the object to extend its lifetime beyond this scope until it's operations are done.
// Once the all async operations are done, no reference remains, finally ending the lifetime of this object.
const auto ws(std::make_shared<websocket>(std::move(socket), ssl_context_, auth_));
// Initiate websocket handshake
ws->handshake();
// Continue with accepting the next available connection
acceptor_.async_accept(io_context_, boost::beast::bind_front_handler(&server::accept_handler, this));
}
else
{
LOG_ERROR("Acceptor error: " << error.message());
}
}
这对于在初始连接时验证客户端证书非常有用。问题是这个 websocket 服务器期望客户端连接很长时间,可能比客户端证书的有效期更长。换句话说,我需要在初始连接建立后定期重新检查客户端证书。最好的方法是什么?
要在连接上多次验证客户端证书,您可以实现自定义验证回调,在每次握手时检查证书。确保正确处理连接状态以避免出现问题。