服务于多个域在一个盒子SNI [英] Serving multiple domains in one box with 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。在
< OpenSSL的DIR> /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,
广告 code>和
ARG
未使用的参数。我不知道是什么广告 code>做,因为我不使用它。
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 toSSL_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 usingSSL_new
command, which is way before execution ofSSL_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 yourget_ssl_servername_cb
is not called, issue:
openssl s_client -connect localhost:8443 -ssl3
# SNI added at TLSv1openssl s_client -connect localhost:8443 -tls1
# Windows XP clientTo 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 onlocalhost
):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 withSSL_CTX_set_tlsext_servername_callback
), you examine the server name. One of two situations occur: you already have aSSL_CTX
for the server's name, or you need to create aSSL_CTX
for server's name.Once you fetch the
SSL_CTX
from cache or create a newSSL_CTX
, you then useSSL_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 fors_server.c
(in<openssl dir>/apps/s_server.c
). Follow the trail ofctx2
,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 neededSSL_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 theSSL_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
andarg
are unused parameters. I don't know whatad
does because I don't use it.arg
can be used to pass in a context to the callback. I don't usearg
either, buts_server.c
uses it to print some debug information (thearg
is a pointer to aBIO
s tied tostderr
(and a few others), IIRC).
For completeness,
SSL_CTX
are reference counted and they can be re-used. A newly createdSSL_CTX
has a count of 1, which is delegated to the OpenSSL internal caching mechanism. When you hand theSSL_CTX
to aSSL
object, the count increments to 2. When theSSL
object callsSSL_CTX_free
on theSSL_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屋!