服务于多个域在一个盒子SNI [英] Serving multiple domains in one box with SNI

查看:230
本文介绍了服务于多个域在一个盒子SNI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用了FreeBSD-8.2的OpenSSL 0.9.8q。我有我的系统上3虚拟主机和要实现SNI,以服务为他们的所有3台服务器。

我有3个独立的证书为每个,在我的SSL服务器code我必须以某种方式找出哪些是客户端的请求的域名,并使用基于相应的证书文件。为此,我写了一个名为 get_ssl_servername_cb 功能,并通过它作为回调函数 SSL_CTX_set_tlsext_servername_callback 。这样一来,在回调函数,我可以获取客户端的请求的域名。

但我的问题是,这个回调函数被 SSL_accept 函数的执行后执行,但我必须选择并使用 SSL_new 命令,这是执行 SSL_accept 之前的方式。

所以我的问题是,我该如何使用 SSL_CTX_set_tlsext_servername_callback 功能SNI?


解决方案

  

但我的问题是,这个回调函数被的SSL_accept功能执行后执行,但是我必须选择和使用SSL_new命令,这是SSL_accept执行前路才使用相应的证书。


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

下面是一些例子胳肢使用OpenSSL的的s_client.First 的行为。为了模拟非SNI客户端,使你的 get_ssl_servername_cb 不是的调用,问题:


  • 的OpenSSL的s_client.First -connect本地主机:8443 -ssl3 #SNI添加在使用TLSv1

  • 的OpenSSL的s_client.First -connect本地主机:8443 -tls1 #Windows XP客户端

要模拟SNI客户端,以便您的 get_ssl_servername_cb 的调用,问题:


  • 的OpenSSL的s_client.First -connect本地主机:8443 -tls1 -servername本地主机

您也可以通过添加 -CAfile 避免证书验证错误。这是从我的测试脚本之一(用于测试DSS / DSA证书上的本地主机

  printf的GET / HTTP / 1.1 \\ r \\ n \\ r \\ n|在/ usr /本地/ SSL /斌/ OpenSSL的的s_client.First \\
    -connect本地主机:8443 -tls1 -servername本地主机\\
    -CAfile PKI /签约-DSS-cert.pem



  

所以我的问题是,我怎么能使用SSL_CTX_set_tlsext_servername_callback功能SNI?


请参阅OpenSSL的源$ C ​​$ c。在&LT; OpenSSL的DIR&GT; /apps/s_server.c ;或见<一个href=\"http://stackoverflow.com/questions/5113333/how-to-implement-server-name-indicationsni-on-openssl-in-c-or-c\">How实现服务器名称指示(SNI)OpenSSL的C或C ++?。

在你的 get_ssl_servername_cb (设置为 SSL_CTX_set_tlsext_servername_callback ),您检查服务器名称。其中的两种情况发生:你已经有一个 SSL_CTX 服务器的名称,或者您需要创建一个 SSL_CTX 的服务器的名称。

一旦你取 SSL_CTX 从高速缓存或创建一个新的 SSL_CTX ,你再使用 SSL_set_SSL_CTX 来在上下文切换。有在OpenSSL的源文件中的新的上下文交换的一个例子。见code为 s_server.c (在&LT; OpenSSL的DIR&GT; /apps/s_server.c ) 。按照 ctx2

的踪迹

下面是它看起来像我的项目之一。 IsDomainInDefaultCert 确定请求的服务器名称由默认的服务器证书提供的。如果不是, GetServerContext 获取所需的 SSL_CTX GetServerContext 拉证书所需的出应用程序级缓存;或者创建它,并把它在应用程序级高速缓存( GetServerContext 也断言的 SSL_CTX 这样一个引用计数OpenSSL库不会从应用程序中)将其删除。

 静态INT ServerNameCallback(SSL * SSL,为int *广告,无效* ARG)
{
    未使用(广告);
    未使用(ARG);    ASSERT(SSL);
    如果(SSL == NULL)
        返回SSL_TLSEXT_ERR_NOACK;    为const char *服务器名= SSL_get_servername(SSL,TLSEXT_NAMETYPE_host_name);
    ASSERT(服务器和放大器;&安培;服务器名[0]);
    如果(!服务器名||服务器名称[0] =='\\ 0')
        返回SSL_TLSEXT_ERR_NOACK;    / *是否默认证书已经处理这个域名? * /
    如果(IsDomainInDefCert(服务器名))
        返回SSL_TLSEXT_ERR_OK;    / *需要一个新的证书,此域* /
    SSL_CTX * CTX = GetServerContext(服务器名);
    ASSERT(CTX!= NULL);
    如果(CTX == NULL)
        返回SSL_TLSEXT_ERR_NOACK;    / *无用的返回值* /
    SSL_CTX * V = SSL_set_SSL_CTX(SSL,CTX);
    ASSERT(V == CTX);
    如果(V!= CTX)
        返回SSL_TLSEXT_ERR_NOACK;    返回SSL_TLSEXT_ERR_OK;
}

在上面的code,广告 ARG 未使用的参数。我不知道是什么广告做,因为我不使用它。 ARG 可用于在上下文中回调传递。我不使用 ARG 下去,但 s_server.c 用它来打印一些调试信息( ARG 是一个指向一个 BIO 取值绑标准错误(和其他少数),IIRC)。


有关完整性, SSL_CTX 是参考计数,它们可以被重新使用。新创建 SSL_CTX 具有1的数,这是委托给OpenSSL的内部缓存机制。当你的手在 SSL_CTX SSL 对象,计数增量2.当 SSL 对象调用 SSL_CTX_free SSL_CTX ,该函数将递减引用计数。如果上下文是过期及基准计为1,则OpenSSL库将从它的内部高速缓存中删除。

I'm using OpenSSL 0.9.8q in FreeBSD-8.2. I have 3 virtual hosts on my system and want to implement SNI to serve for all 3 of them in one server.

I have 3 separate certificates one for each, and in my ssl-server code I have to somehow find out what is the domain-name of client's request, and use the appropriate certificate file based on that. For this I wrote a function named get_ssl_servername_cb and passed it as callback function to SSL_CTX_set_tlsext_servername_callback. This way, in callback function I can get the the domain-name of the client's request.

But my problem is, this callback function is being executed after execution of SSL_accept function, but I have to choose and use the appropriate certificate before using SSL_new command, which is way before execution of SSL_accept.

So my question is, how can I use SSL_CTX_set_tlsext_servername_callback function for SNI?

解决方案

but my problem is, this callback function is being executed after execution of "SSL_accept" function, but I have to choose and use the appropriate certificate before using "SSL_new" command, which is way before execution of SSL_accept.

When you start your server, you provide a default SSL_CTX. This is used for non-SNI clients, like SSLv3 clients and TLS clients that don't utilize SNI (like Windows XP). This is needed because the callback is not invoked in this situation.

Here are some examples to tickle the behavior using OpenSSL's s_client. To simulate a non-SNI client so that your get_ssl_servername_cb is not called, issue:

  • openssl s_client -connect localhost:8443 -ssl3 # SNI added at TLSv1
  • openssl s_client -connect localhost:8443 -tls1 # Windows XP client

To simulate a SNI client so that your get_ssl_servername_cb is called, issue:

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

You can also avoid the certificate verification errors by adding -CAfile. This is from one of my test scripts (for testing DSS/DSA certificates on localhost):

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 


so my question is, how can I use "SSL_CTX_set_tlsext_servername_callback" function for SNI?

See the OpenSSL source code at <openssl dir>/apps/s_server.c; or see How to implement Server Name Indication(SNI) on OpenSSL in C or C++?.

In your get_ssl_servername_cb (set with SSL_CTX_set_tlsext_servername_callback), you examine the server name. One of two situations occur: you already have a SSL_CTX for the server's name, or you need to create a SSL_CTX for server's name.

Once you fetch the SSL_CTX from cache or create a new SSL_CTX, you then use SSL_set_SSL_CTX to swap in the context. There's an example of swapping in the new context in the OpenSSL source files. See the code for s_server.c (in <openssl dir>/apps/s_server.c). Follow the trail of ctx2,

Here's what it looks like in one of my projects. IsDomainInDefaultCert determines if the requested server name is provided by the default server certificate. If not, GetServerContext fetches the needed SSL_CTX. GetServerContext pulls the needed certificate out of an app-level cache; or creates it and puts it in the app-level cache (GetServerContext also asserts one reference count on the SSL_CTX so the OpenSSL library does not delete it from under the app).

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;
}

In the code above, ad and arg are unused parameters. I don't know what ad does because I don't use it. arg can be used to pass in a context to the callback. I don't use arg either, but s_server.c uses it to print some debug information (the arg is a pointer to a BIOs tied to stderr (and a few others), IIRC).


For completeness, SSL_CTX are reference counted and they can be re-used. A newly created SSL_CTX has a count of 1, which is delegated to the OpenSSL internal caching mechanism. When you hand the SSL_CTX to a SSL object, the count increments to 2. When the SSL object calls SSL_CTX_free on the SSL_CTX, the function will decrement the reference count. If the context is expired and the reference count is 1, then the OpenSSL library will delete it from its internal cache.

这篇关于服务于多个域在一个盒子SNI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆