C/C++ boost::asio::ssl.hpp + openssl 1.x (老版本库)设置SSL/TLS链接对象的 SNI(SSL扩展域名指示额外参数)。
static std::shared_ptr<boost::asio::ssl::context> HttpSslClientContext(const char* host)
{
class HttpSslContext : public boost::asio::ssl::context
{
public:
HttpSslContext(method m) : context(m) {}
public:
std::string host;
};
std::shared_ptr<HttpSslContext> ssl_context = make_shared_object<HttpSslContext>(boost::asio::ssl::context::tlsv12_client);
ssl_context->host = host;
ssl_context->set_verify_mode(boost::asio::ssl::context::verify_none);
ssl_context->set_verify_callback(
[](bool preverified, boost::asio::ssl::verify_context& context)
{
return true;
});
typedef int(*SSL_CTX_SET_SNI_CALLBACK)(SSL*, int, void*);
if (NULL != host && *host != '\x0')
{
SSL_CTX_SET_SNI_CALLBACK sni = [](SSL* ssl, int /*ad*/, void* arg)
{
HttpSslContext* context = static_cast<HttpSslContext*>(arg);
if (NULL == context)
{
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
std::string hostname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (hostname.empty())
{
hostname = context->host;
}
if (hostname.size() > 0)
{
SSL_set_tlsext_host_name(ssl, hostname.data());
}
SSL_set_SSL_CTX(ssl, context->native_handle());
return SSL_TLSEXT_ERR_OK;
};
SSL_CTX_set_tlsext_servername_callback(ssl_context->native_handle(), (void(*)())sni);
SSL_CTX_set_tlsext_servername_arg(ssl_context->native_handle(), ssl_context.get());
}
return ssl_context;
}