OpenSSL是否允许每个进程多个SSL_CTX,一个SSL_CTX用于服务器会话,另一个SSL_CTX用于客户端会话?

时间:2014-12-25 18:17:22

标签: openssl client server simultaneous

我有一个Linux进程需要充当SSL服务器(接受和服务来自其他客户端的连接),但还需要 - 在同一个进程中 - 启动与其他SSL服务器的客户端会话。

我打算使用两个SSL_CTX_new()函数调用创建两个单独的SSL_CTX句柄,一个调用服务器方法,另一个调用客户端方法。是否支持在单个进程中双重使用OpenSSL?我希望OpenSSL使用SSL_CTX句柄 - 并且不依赖于全局或静态局部变量 - 来创建和服务新会话可能需要的所有上下文信息。这是一个很好的假设吗?

2 个答案:

答案 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_nameSSL_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_methodSSLv23_server_method)是一些函数指针,用于看不见结构中的connectaccept等函数。客户致电connect,服务器致电accept

相反,只需使用通用SSLv23_method,一切都会好的。您仍然需要使用SSL_CTX_set_options调整上下文,因为SSL_CTX_new提供的默认上下文包括弱/受伤/损坏的协议和密码。

OpenSSL的wiki页面SSL/TLS Client向您展示如何调整SSL_CTX对象。它执行以下操作,客户端和服务器都可以使用它:

  • 禁用SSLv2
  • 禁用SSLv3
  • 禁用压缩
  • 禁用匿名协议
  • 使用“强”密码

使用像"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。如果你的应用程序没有使用线程,你根本不需要这样的设置。