openssl使用sni支持多域名、多证书服务

本文探讨了如何在SSL_CTX中实现服务器名称指示(SNI)扩展,通过回调函数serverNameCallback选择合适的SSL_CTX实例,根据客户端请求的主机名进行证书切换,确保HTTPS服务能正确响应多域名请求。

 

map<string,SSL_CTX*> g_ctxMap;
SSL_CTX* serverSslCtx = NULL;
static int serverNameCallback(SSL * ssl, int * ad, void * arg)
{
	if(ssl == NULL)
		return SSL_TLSEXT_ERR_NOACK;

	const char * servername = SSL_get_servername(ssl,TLSEXT_NAMETYPE_host_name);
    SSL_CTX* ctx = NULL;    
	if (servername && strlen(servername) > 0)
	{
        //从g_ctxMap中找到servername对应的SSL_CTX
		_OUTPUT(INFO, "%s name = %s\n", __FUNCTION__, servername);
	}
	else
	{
        //选一个默认的SSL_CTX
		_OUTPUT(INFO, "%s name is NULL\n", __FUNCTION__);
	}
    
	SSL_set_SSL_CTX(ssl, ctx);
	SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ctx),                             
    SSL_CTX_get_verify_callback(ctx));
	SSL_set_verify_depth(ssl, SSL_CTX_get_verify_depth(ctx));
	SSL_set_options(ssl, SSL_CTX_get_options(ctx));
	return SSL_TLSEXT_ERR_OK;
}

//初始化一个通用的SSL_CTX,设置好回调函数
//接受客户端的连接sock,与通用SSL_CTX绑定,后面收到包就会触发回调,再根据域名绑定对应的SSL_CTX
serverSslCtx = SSL_CTX_new(SSLv23_server_method());
SSL_CTX_set_tlsext_servername_callback(serverSslCtx, serverNameCallback);


//获取证书里的域名
X509* x509 = SSL_CTX_get0_certificate(serverSslCtx);
X509_NAME* pSubName = X509_get_subject_name(x509);
char csBuf[256] = { 0 };
X509_NAME_get_text_by_NID(pSubName, NID_commonName, csBuf, 256);

 

OpenSSL 客户端中配置多个 SNI(Server Name Indication)主要用于测试或模拟客户端连接不同域名的 HTTPS 服务OpenSSL 提供了命令行工具和编程接口来实现 SNI 的设置。 ### 使用 OpenSSL 命令行配置多个 SNI OpenSSL 的 `s_client` 子命令支持通过 `-servername` 参数指定 SNI 主机名,从而在客户端连接时发送目标域名信息。这种方式适用于测试不同域名的证书是否正确加载[^2]。 例如,连接 `example.com` 并指定 SNI 为 `example.com`: ```bash openssl s_client -showcerts -connect example.com:443 -servername example.com ``` 如果需要测试多个域名,可以依次更改 `-servername` 参数的值: ```bash openssl s_client -showcerts -connect example.com:443 -servername test.com ``` 这种方式可以验证服务器是否根据 SNI 返回了正确的证书。 ### 使用 OpenSSL 编程接口配置多个 SNI 在编程层面,OpenSSL 提供了 `SSL_set_tlsext_host_name()` 函数用于设置客户端的 SNI 扩展。该函数应在连接建立之前调用,以确保TLS 握手期间发送正确的主机名。 以下是一个使用 OpenSSL 编程接口设置多个 SNI 的示例代码: ```c #include <openssl/ssl.h> #include <openssl/err.h> void connect_with_sni(const char *hostname, const char *sni_name) { SSL_library_init(); SSL_CTX *ctx = SSL_CTX_new(TLS_client_method()); SSL *ssl = SSL_new(ctx); // 设置 SNI 名称 SSL_set_tlsext_host_name(ssl, sni_name); // 建立连接的代码省略 // ... // 清理资源 SSL_free(ssl); SSL_CTX_free(ctx); } int main() { connect_with_sni("example.com", "example.com"); connect_with_sni("example.com", "test.com"); return 0; } ``` 上述代码中,`connect_with_sni` 函数接受主机名和 SNI 名称作为参数,分别用于建立连接和设置 SNI。通过这种方式,可以在客户端模拟连接多个域名并分别设置 SNI。 ### 注意事项 - 客户端必须支持 SNI,否则服务器可能无法正确识别目标域名,导致连接失败或返回默认证书[^1]。 - OpenSSL 版本应为 0.9.8f 或更高,以确保SNI支持[^3]。 - 使用 `s_client` 命令时,若目标服务器未启用 SNI,可省略 `-servername` 参数。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值