Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions lib/ngx/ssl/clienthello.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ local ngx_lua_ffi_ssl_get_client_hello_ext
local ngx_lua_ffi_ssl_set_protocols
local ngx_lua_ffi_ssl_get_client_hello_ext_present
local ngx_lua_ffi_ssl_get_client_hello_ciphers
local ngx_lua_ffi_ssl_set_ciphers


if subsystem == 'http' then
Expand All @@ -52,6 +53,9 @@ if subsystem == 'http' then
int ngx_http_lua_ffi_ssl_get_client_hello_ciphers(ngx_http_request_t *r,
unsigned short *ciphers, size_t ciphers_len, char **err);
/* Undefined for the stream subsystem */
int ngx_http_lua_ffi_ssl_set_ciphers(ngx_http_request_t *r,
const char *ciphers, const char *ciphersuites, char **err);
/* Undefined for the stream subsystem */
]]

ngx_lua_ffi_ssl_get_client_hello_server_name =
Expand All @@ -63,6 +67,7 @@ if subsystem == 'http' then
C.ngx_http_lua_ffi_ssl_get_client_hello_ext_present
ngx_lua_ffi_ssl_get_client_hello_ciphers =
C.ngx_http_lua_ffi_ssl_get_client_hello_ciphers
ngx_lua_ffi_ssl_set_ciphers = C.ngx_http_lua_ffi_ssl_set_ciphers



Expand Down Expand Up @@ -338,4 +343,34 @@ function _M.set_protocols(protocols)
return nil, ffi_str(errmsg[0])
end


-- return ok, err
-- on failure the connection's cipher list, ciphersuites and error queue
-- are left untouched, so the handshake proceeds on the server defaults
function _M.set_ciphers(ciphers, ciphersuites)
local r = get_request()
if not r then
error("no request found")
end

if ngx_phase() ~= "ssl_client_hello" then
error("API disabled in the current context")
end

if ciphers ~= nil and type(ciphers) ~= "string" then
error("ciphers must be a string")
end

if ciphersuites ~= nil and type(ciphersuites) ~= "string" then
error("ciphersuites must be a string")
end

local rc = ngx_lua_ffi_ssl_set_ciphers(r, ciphers, ciphersuites, errmsg)
if rc == FFI_OK then
return true
end

return nil, ffi_str(errmsg[0])
end

return _M
45 changes: 45 additions & 0 deletions lib/ngx/ssl/clienthello.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Table of Contents
* [get_client_hello_ext_present](#get_client_hello_ext_present)
* [get_client_hello_ext](#get_client_hello_ext)
* [set_protocols](#set_protocols)
* [set_ciphers](#set_ciphers)
* [Community](#community)
* [English Mailing List](#english-mailing-list)
* [Chinese Mailing List](#chinese-mailing-list)
Expand Down Expand Up @@ -294,6 +295,50 @@ Example: `ssl_clt.set_protocols({"TLSv1.1", "TLSv1.2", "TLSv1.3"})`

[Back to TOC](#table-of-contents)

set_ciphers
----------------------
**syntax:** *ok, err = ssl_clt.set_ciphers(ciphers, ciphersuites?)*

**context:** *ssl_client_hello_by_lua**

Sets the cipher list used by the current downstream SSL connection, e.g. keyed on the client hello server name.

The `ciphers` string configures the TLS <= 1.2 cipher list in the OpenSSL cipher list format (see [ciphers(1)](https://docs.openssl.org/master/man1/openssl-ciphers/)), like the `ssl_ciphers` nginx directive. The optional `ciphersuites` string configures the TLS 1.3 ciphersuites, a colon-separated list like `TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256`, like the `ssl_conf_command Ciphersuites` nginx directive. Either argument may be `nil` to leave that part of the configuration unchanged.

Returns `true` on success, or a `nil` value and a string describing the error otherwise.

On failure the connection's SSL object is left exactly as it was -- cipher list, ciphersuites, and error queue all untouched -- so the handshake proceeds with whatever the connection already had, which is the default list inherited from the server block (`ssl_ciphers`/`ssl_conf_command`). Both strings are validated before either is applied, because a failed `SSL_set_cipher_list()` would otherwise still install the parsed list on the connection and leave the error queue dirty, aborting the handshake.

Considering it is meaningless to set the cipher list after the cipher is negotiated,
so this function may only be called in the context of [ssl_client_hello_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_client_hello_by_lua_block).

This function requires OpenSSL 1.1.1 or later.

Example:

```nginx
# nginx.conf
server {
listen 443 ssl;
server_name test.com;
ssl_client_hello_by_lua_block {
local ssl_clt = require "ngx.ssl.clienthello"
local name = ssl_clt.get_client_hello_server_name()
if name == "legacy.test.com" then
local ok, err = ssl_clt.set_ciphers("HIGH:!aNULL:!MD5")
if not ok then
ngx.log(ngx.ERR, "failed to set ciphers: ", err)
-- the handshake continues on the default ssl_ciphers
end
end
}
ssl_certificate test.crt;
ssl_certificate_key test.key;
}
```

[Back to TOC](#table-of-contents)

Community
=========

Expand Down
Loading
Loading