Skip to content

Commit f36b206

Browse files
chensunnyzhuizhuhaomeng
authored andcommitted
feature: add support for ssl.get_req_shared_ssl_ciphers()
1 parent dbdcb7e commit f36b206

File tree

3 files changed

+143
-4
lines changed

3 files changed

+143
-4
lines changed

lib/ngx/ssl.lua

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@ local ffi = require "ffi"
99
local C = ffi.C
1010
local ffi_str = ffi.string
1111
local ffi_gc = ffi.gc
12+
local ffi_copy = ffi.copy
13+
local ffi_sizeof = ffi.sizeof
14+
local ffi_typeof = ffi.typeof
15+
local ffi_new = ffi.new
1216
local get_request = base.get_request
1317
local error = error
1418
local tonumber = tonumber
19+
local format = string.format
20+
local concat = table.concat
1521
local errmsg = base.get_errmsg_ptr()
1622
local get_string_buf = base.get_string_buf
1723
local get_size_ptr = base.get_size_ptr
@@ -43,6 +49,7 @@ local ngx_lua_ffi_ssl_client_random
4349
local ngx_lua_ffi_ssl_export_keying_material
4450
local ngx_lua_ffi_ssl_export_keying_material_early
4551
local ngx_lua_ffi_get_req_ssl_pointer
52+
local ngx_lua_ffi_req_shared_ssl_ciphers
4653

4754

4855
if subsystem == 'http' then
@@ -114,6 +121,15 @@ if subsystem == 'http' then
114121
unsigned char *out, size_t out_size,
115122
const char *label, size_t llen,
116123
const unsigned char *ctx, size_t ctxlen, char **err);
124+
125+
int ngx_http_lua_ffi_req_shared_ssl_ciphers(ngx_http_request_t *r,
126+
unsigned short *ciphers, unsigned short *nciphers,
127+
int filter_grease, char **err);
128+
129+
typedef struct {
130+
uint16_t nciphers;
131+
uint16_t ciphers[?];
132+
} ngx_lua_ssl_ciphers;
117133
]]
118134

119135
ngx_lua_ffi_ssl_set_der_certificate =
@@ -143,6 +159,8 @@ if subsystem == 'http' then
143159
ngx_lua_ffi_ssl_export_keying_material_early =
144160
C.ngx_http_lua_ffi_ssl_export_keying_material_early
145161
ngx_lua_ffi_get_req_ssl_pointer = C.ngx_http_lua_ffi_get_req_ssl_pointer
162+
ngx_lua_ffi_req_shared_ssl_ciphers =
163+
C.ngx_http_lua_ffi_req_shared_ssl_ciphers
146164

147165
elseif subsystem == 'stream' then
148166
ffi.cdef[[
@@ -237,6 +255,37 @@ local charpp = ffi.new("char*[1]")
237255
local intp = ffi.new("int[1]")
238256
local ushortp = ffi.new("unsigned short[1]")
239257

258+
do
259+
local ciphers_buf = ffi_new("uint16_t [?]", 256)
260+
261+
function _M.get_req_shared_ssl_ciphers(filter_grease)
262+
local r = get_request()
263+
if not r then
264+
error("no request found")
265+
end
266+
267+
if filter_grease == nil then
268+
filter_grease = true -- Default to filter GREASE
269+
end
270+
271+
ciphers_buf[0] = 255 -- Set max number of ciphers we can hold
272+
local filter_flag = filter_grease and 1 or 0
273+
local rc = ngx_lua_ffi_req_shared_ssl_ciphers(r, ciphers_buf + 1,
274+
ciphers_buf, filter_flag,
275+
errmsg)
276+
if rc ~= FFI_OK then
277+
return nil, ffi_str(errmsg[0])
278+
end
279+
280+
-- Build result table
281+
local result = {}
282+
for i = 1, ciphers_buf[0] do
283+
result[i] = tonumber(ciphers_buf[i])
284+
end
285+
286+
return result
287+
end
288+
end
240289

241290
function _M.clear_certs()
242291
local r = get_request()

lib/ngx/ssl.md

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Table of Contents
3232
* [set_priv_key](#set_priv_key)
3333
* [verify_client](#verify_client)
3434
* [get_client_random](#get_client_random)
35+
* [get_shared_ssl_ciphers](#get_shared_ssl_ciphers)
3536
* [get_req_ssl_pointer](#get_req_ssl_pointer)
3637
* [Community](#community)
3738
* [English Mailing List](#english-mailing-list)
@@ -650,7 +651,6 @@ This function can be called in any context where downstream https is used, but i
650651

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

653-
654654
get_req_ssl_pointer
655655
------------
656656
**syntax:** *ssl_ptr, err = ssl.get_req_ssl_pointer()*
@@ -668,6 +668,39 @@ This function was first added in version `0.1.16`.
668668

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

671+
get_req_shared_ssl_ciphers
672+
-----------
673+
**syntax:** *ciphers = ssl.get_req_shared_ssl_ciphers(filter_grease?)*
674+
675+
**context:** *any*
676+
677+
Returns an array of cipher IDs that are supported by both the server and client for the current SSL connection.
678+
679+
The optional argument `filter_grease` defaults to `true`. Set it to `false` explicitly if you want to include GREASE cipher values in the results.
680+
681+
Example usage:
682+
683+
```lua
684+
local ciphers, err = ssl.get_req_shared_ssl_ciphers()
685+
if ciphers then
686+
for i, cipher in ipairs(ciphers) do
687+
ngx.log(ngx.INFO, "Cipher: ", cipher)
688+
end
689+
else
690+
ngx.log(ngx.ERR, err)
691+
end
692+
```
693+
694+
GREASE (Generate Random Extensions And Sustain Extensibility) cipher values are automatically filtered out from the results.
695+
696+
Returns `nil` and an error string on failure.
697+
698+
This function can be called in any context where downstream https is used.
699+
700+
This function was first added in version `0.1.29`.
701+
702+
[Back to TOC](#table-of-contents)
703+
671704
Community
672705
=========
673706

t/ssl.t

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use t::TestCore;
88

99
repeat_each(2);
1010

11-
plan tests => repeat_each() * (blocks() * 6 - 1);
11+
plan tests => repeat_each() * (blocks() * 6 );
1212

1313
no_long_string();
1414
#no_diff();
@@ -110,8 +110,7 @@ failed to do SSL handshake: handshake failed
110110
111111
--- error_log eval
112112
['lua ssl server name: "test.com"',
113-
qr/routines::no suitable signature algorithm|sslv3 alert handshake failure|routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE:SSL alert number 40/]
114-
113+
qr/sslv3 alert handshake failure|SSL alert number 40/]
115114
--- no_error_log
116115
[alert]
117116
[emerg]
@@ -3419,3 +3418,61 @@ SUCCESS
34193418
[error]
34203419
[alert]
34213420
[emerg]
3421+
3422+
3423+
3424+
=== TEST 35: get shared SSL ciphers
3425+
--- http_config
3426+
lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH";
3427+
server {
3428+
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
3429+
server_name test.com;
3430+
ssl_protocols TLSv1.2;
3431+
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384;
3432+
3433+
ssl_certificate_by_lua_block {
3434+
local ssl = require "ngx.ssl"
3435+
local ciphers, err = ssl.get_req_shared_ssl_ciphers()
3436+
if not err and ciphers then
3437+
ngx.log(ngx.INFO, "shared ciphers count: ", #ciphers)
3438+
local count = 0
3439+
for i, cipher_id in ipairs(ciphers) do
3440+
count = count + 1
3441+
ngx.log(ngx.INFO, string.format("%d: SHARED_CIPHER 0x%04x", i, cipher_id))
3442+
if count >= 3 then -- log only first 3 to avoid too much output
3443+
break
3444+
end
3445+
end
3446+
else
3447+
ngx.log(ngx.ERR, "failed to get shared ciphers: ", err)
3448+
end
3449+
}
3450+
ssl_certificate ../../cert/test.crt;
3451+
ssl_certificate_key ../../cert/test.key;
3452+
3453+
server_tokens off;
3454+
location /foo {
3455+
default_type 'text/plain';
3456+
content_by_lua_block {ngx.status = 200 ngx.say("foo") ngx.exit(200)}
3457+
more_clear_headers Date;
3458+
}
3459+
}
3460+
--- config
3461+
location /t {
3462+
proxy_ssl_protocols TLSv1.2;
3463+
proxy_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256;
3464+
proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock:/foo;
3465+
proxy_ssl_session_reuse off;
3466+
}
3467+
3468+
--- request
3469+
GET /t
3470+
--- response_body
3471+
foo
3472+
--- error_log eval
3473+
[qr/shared ciphers count: \d+/,
3474+
qr/1: SHARED_CIPHER 0x/]
3475+
--- no_error_log
3476+
[alert]
3477+
[crit]
3478+
[error]

0 commit comments

Comments
 (0)