Nginx with TLS 1.3(OpenSSL)
文章目录
2018年8月,TLS 1.3的最终版本RFC 8446终于发布了,我这种菜鸡出于好奇试着安装了OpenSSL 1.1.1来开启TLS 1.3的支持。但是最近几天我发现,使用TLS 1.3的时候,不管怎么设置Nginx里的
ssl_ciphers
中的密码套件的顺序,最终采用的密码套件总是
TLS_AES_256_GCM_SHA384
,就算直接指明使用AES128也无济于事,虽然并不是什么大的问题,但是在一个伪完美主义者眼中,总感觉像是残废了一般(果然强迫症发作就没法治)。
在网上搜索了一番,并没有人对于这个问题进行过探究,能够任意选择密码套件的貌似只有Google的具有等效密码组功能的BoringSSL,于是又查看了 OpenSSL Wiki ,在Ciphersuites一章里有这样一段:
Applications should use the SSL_CTX_set_ciphersuites() or SSL_set_ciphersuites() functions to configure TLSv1.3 ciphersuites. Note that the functions SSL_CTX_get_ciphers() and SSL_get_ciphers() will return the full list of ciphersuites that have been configured for both TLSv1.2 and below and TLSv1.3.
For the OpenSSL command line applications there is a new “-ciphersuites” option to configure the TLSv1.3 ciphersuite list. This is just a simple colon (":") separated list of TLSv1.3 ciphersuite names in preference order. Note that you cannot use the special characters such as “+”, “!", “-” etc, that you can for defining TLSv1.2 ciphersuites. In practice this is not likely to be a problem because there are only a very small number of TLSv1.3 ciphersuites.
For example:
$ openssl s_server -cert mycert.pem -key mykey.pem -cipher ECDHE -ciphersuites “TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256”
This will configure OpenSSL to use any ECDHE based ciphersuites for TLSv1.2 and below. For TLSv1.3 the TLS_AES_256_GCM_SHA384 and TLS_CHACHA20_POLY1305_SHA256 ciphersuites will be available.
提到了设置TLS 1.3密码套件时应该使用
SSL_CTX_set_ciphersuites()
,而TLS 1.2及以下版本使用的是
SSL_CTX_set_cipher_list()
,入口并不一样。
知道了这一点之后就可以试着修♂改Nginx里的设置密码套件的代码了,可以从src/http/modules/ngx_http_ssl_module.c处入手,找到
ngx_http_ssl_merge_srv_conf()
中设置证书、私钥和密码套件的部分:
|
|
conf->ciphers
就是配置文件中
ssl_ciphers
一项后面跟的值对应的
ngx_str_t
结构体。后面的
ngx_ssl_ciphers()
函数内部即为对OpenSSL的SSL设置函数的调用:
|
|
我的
破坏性
修改方案是将配置文件中的密码套件用
'|'
分成两部分,TLS 1.3的放在前面。除了http,mail、stream以及http_grpc中的SSL设置也最终会调用位于src/event/ngx_event_openssl.c中的
ngx_ssl_ciphers()
,因此可以修改里面的代码,将参数分成两部分,分别调用对应的设置函数,修改后的patch如下:
|
|
重新编译后,在Nginx的配置文件中将
ssl_ciphers
的设置改成了下面这样(用
'|'
把密码套件分成了两部分):
|
|
最后用Chromium访问一下试试:
可以看到使用的密码套件已经变成了设置的第一项
TLS_AES_128_GCM_SHA256
。
warning
鉴于本人的代码能力实在有限… 将来如果服务器运行出了偏差我不负责的,明白吗。
相关代码的patch已经上传至 Github Gist 。欢迎提出意见和建议。