我有一个Linux进程需要充当SSL服务器(接受和服务来自其他客户端的连接),但还需要 - 在同一个进程中 - 启动与其他SSL服务器的客户端会话。
我打算使用两个SSL_CTX_new()函数调用创建两个单独的SSL_CTX句柄,一个调用服务器方法,另一个调用客户端方法。是否支持在单个进程中双重使用OpenSSL?我希望OpenSSL使用SSL_CTX句柄 - 并且不依赖于全局或静态局部变量 - 来创建和服务新会话可能需要的所有上下文信息。这是一个很好的假设吗?
答案 0 :(得分:6)
OpenSSL是否允许每个进程多个SSL_CTX,一个SSL_CTX用于服务器会话......
是的,这很常见。使用服务器名称指示时很常见。对于SNI,您有一个默认的SSL_CTX
,然后是每个服务器的SSL_CTX
。然后,如果客户端在其SSL_CTX
中包含服务器名称扩展名,则返回SNI回调中的默认SSL_CTX
或专用ClientHello
。
SSL_CTX
被库引用计数,因此在SSL_CTX_free
次调用之一中引用计数降至0之前,它们不会被真正释放。
以下是关于SNI的一些相关问题,如果感兴趣的话:
第一个甚至为您提供回调代码。 GetServerContext
根据服务器名称返回新的(或现有的)上下文:
/* Need a new certificate for this domain */
SSL_CTX* ctx = GetServerContext(servername);
if(ctx == NULL) handleFailure();
...
/* Set new context */
SSL_CTX* v = SSL_set_SSL_CTX(ssl, ctx);
OpenSSL是否允许每个进程多个SSL_CTX,...其他SSL_CTX用于客户端会话?
是的,但通常不使用它。客户端不通常会像服务器那样更改其SSL_CTX
。
如果客户端连接到多个服务器,通常使用SSL_CTX_set_options
设置通道参数,并将其用于每个服务器的连接(甚至是不同的服务器)。参数可以是协议(TLS 1.1,TLS 1.2),密码套件(删除匿名密码套件)和压缩等。有关详细信息,请参阅下面围绕SSL/TLS Client的讨论。
客户端确实需要设置服务器的主机名,但这是使用SSL*
而不是SSL_set_tlsext_host_name
在SSL_CTX*
上完成的。
或者,如果您使用的是BIO
,它会是这样的。请注意,BIO
有效地包裹了SSL*
,因此您不会修改SSL_CTX*
:
BIO* web = BIO_new_ssl_connect(ctx);
if(web == NULL) handleFailure();
res = BIO_set_conn_hostname(web, HOST_NAME ":" HOST_PORT);
if(res != 1) handleFailure();
...一个用服务器方法调用,另一个用客户端方法调用
不需要。它们之间的唯一区别(如SSLv23_client_method
和SSLv23_server_method
)是一些函数指针,用于看不见结构中的connect
和accept
等函数。客户致电connect
,服务器致电accept
。
相反,只需使用通用SSLv23_method
,一切都会好的。您仍然需要使用SSL_CTX_set_options
调整上下文,因为SSL_CTX_new
提供的默认上下文包括弱/受伤/损坏的协议和密码。
OpenSSL的wiki页面SSL/TLS Client向您展示如何调整SSL_CTX
对象。它执行以下操作,客户端和服务器都可以使用它:
使用像"HIGH: ... : !SRP:!PSK"
这样的自定义密码列表可以删除许多弱/受损密码,并删除服务器可能不支持的一堆密码套件(因此客户端没有理由通告它们)。 SRP是Thomas Wu的安全远程密码,PSK是预共享密钥。 IANA reserves 87 cipher suites基于它们,因此它在ClientHello
中保存了近180个字节。
是否支持在单个进程中双重使用OpenSSL?
是
嗯,那里你运气不好。有很多全局变量,其中一些是动态分配的,其中一些不会被释放。我希望OpenSSL使用SSL_CTX句柄 - 并且不依赖于全局或静态局部变量
如果您使用的是Java或C#,则每次加载/卸载共享对象时都会泄露它们。因此,您的Java或C#程序会随着时间的推移积累越来越多的内存。 OpenSSL开发人员并不觉得自己值得花时间。例如,请参阅OpenSSL邮件列表中的Small memory leak on multithreaded server。
答案 1 :(得分:1)
根据我的经验:只要您正确初始化OpenSSL库,就可以自由创建多个上下文。我已经在同一个应用程序中使用了两个不同的上下文,在设置了线程锁之后没有任何问题,如OpenSSL手册页中所述:http://www.openssl.org/docs/crypto/threads.html。如果你的应用程序没有使用线程,你根本不需要这样的设置。