首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用SNI在一个框中服务多个域

问使用SNI在一个框中服务多个域
EN

Stack Overflow用户
提问于 2014-03-13 08:48:18
回答 1查看 4.6K关注 0票数 7

我在FreeBSD8.2中使用OpenSSL 0.9.8q。我的系统上有3台虚拟主机,并希望实现SNI,以便在一台服务器中为所有3台主机提供服务。

我有三个独立的证书,每个证书一个,在我的ssl服务器代码中,我必须以某种方式找出客户机请求的域名,并在此基础上使用适当的证书文件。为此,我编写了一个名为get_ssl_servername_cb的函数,并将其作为回调函数传递给SSL_CTX_set_tlsext_servername_callback。这样,在回调函数中,我可以获得客户请求的域名。

但是我的问题是,这个回调函数是在执行SSL_accept函数之后执行的,但是在使用SSL_new命令之前,必须选择和使用适当的证书,这是在执行SSL_accept之前。

所以我的问题是,如何使用SSL_CTX_set_tlsext_servername_callback函数进行SNI?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-03-13 10:29:42

但是我的问题是,这个回调函数是在执行" SSL_accept“函数之后执行的,但是在使用"SSL_new”命令之前,必须选择和使用适当的证书,这是在执行SSL_accept之前。

启动服务器时,提供默认的SSL_CTX。这用于非SNI客户端,如不使用SNI(如Windows )的SSLv3客户端和TLS客户端。这是需要的,因为在这种情况下不调用回调。

下面是一些使用OpenSSL的s_client来挠痒行为的示例。若要模拟非SNI客户端以避免调用get_ssl_servername_cb,请发出以下命令:

  • openssl s_client -connect localhost:8443 -ssl3 # SNI在TLSv1上添加
  • openssl s_client -connect localhost:8443 -tls1 # Windows客户端

若要模拟SNI客户端以便调用get_ssl_servername_cb,请发出以下命令:

  • openssl s_client -connect localhost:8443 -tls1 -servername localhost

还可以通过添加-CAfile来避免证书验证错误。这是我的一个测试脚本(用于在localhost上测试DSS/DSA证书):

代码语言:javascript
复制
printf "GET / HTTP/1.1\r\n\r\n" | /usr/local/ssl/bin/openssl s_client \
    -connect localhost:8443 -tls1 -servername localhost \
    -CAfile pki/signing-dss-cert.pem 

因此,我的问题是,我如何使用"SSL_CTX_set_tlsext_servername_callback“函数的SNI?

请参阅<openssl dir>/apps/s_server.c上的<openssl dir>/apps/s_server.c源代码;或参见How to implement Server Name Indication(SNI) on OpenSSL in C or C++?。

在get_ssl_servername_cb (用SSL_CTX_set_tlsext_servername_callback设置)中,检查服务器名。出现两种情况之一:您已经为服务器名称创建了一个SSL_CTX,或者您需要为服务器的名称创建一个SSL_CTX。

从缓存中获取SSL_CTX或创建新的SSL_CTX之后,就可以在上下文中使用SSL_set_SSL_CTX进行交换了。在OpenSSL源文件中的新上下文中有一个交换的例子。请参阅s_server.c的代码(在<openssl dir>/apps/s_server.c中)。沿着ctx2的轨迹,

这是我的一个项目中的样子。IsDomainInDefaultCert确定请求的服务器名称是否由默认服务器证书提供。如果不是,GetServerContext将获取所需的SSL_CTX。GetServerContext从应用程序级缓存中提取所需的证书;或者创建它,并将其放入应用级缓存(GetServerContext还在SSL_CTX上断言一个引用计数,这样OpenSSL库就不会从应用程序下删除它)。

代码语言:javascript
复制
static int ServerNameCallback(SSL *ssl, int *ad, void *arg)
{
    UNUSED(ad);
    UNUSED(arg);

    ASSERT(ssl);
    if (ssl == NULL)
        return SSL_TLSEXT_ERR_NOACK;

    const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
    ASSERT(servername && servername[0]);
    if (!servername || servername[0] == '\0')
        return SSL_TLSEXT_ERR_NOACK;

    /* Does the default cert already handle this domain? */
    if (IsDomainInDefCert(servername))
        return SSL_TLSEXT_ERR_OK;

    /* Need a new certificate for this domain */
    SSL_CTX* ctx = GetServerContext(servername);
    ASSERT(ctx != NULL);
    if (ctx == NULL)
        return SSL_TLSEXT_ERR_NOACK;   

    /* Useless return value */
    SSL_CTX* v = SSL_set_SSL_CTX(ssl, ctx);
    ASSERT(v == ctx);
    if (v != ctx)   
        return SSL_TLSEXT_ERR_NOACK;

    return SSL_TLSEXT_ERR_OK;
}

在上面的代码中,ad和arg是未使用的参数。我不知道ad做什么,因为我不使用它。可以使用arg将上下文传递给回调。我也不使用arg,但s_server.c使用它打印一些调试信息( arg是指向绑定到stderr (以及其他几个)的BIO的指针)。

为了完整性,SSL_CTX是参考计数,它们可以重复使用.新创建的SSL_CTX的计数为1,它被委托给OpenSSL内部缓存机制。当您将SSL_CTX传递给SSL对象时,计数增加到2。当SSL对象在SSL_CTX上调用SSL_CTX_free时,该函数将减少引用计数。如果上下文过期且引用计数为1,则OpenSSL库将从其内部缓存中删除它。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22373332

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档