Skip to content

Commit 9aed90f

Browse files
authored
feature: add lua_ssl_key_log directive.
1 parent 25ebf20 commit 9aed90f

File tree

7 files changed

+264
-0
lines changed

7 files changed

+264
-0
lines changed

README.markdown

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,7 @@ Directives
11861186
* [lua_ssl_certificate_key](#lua_ssl_certificate_key)
11871187
* [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate)
11881188
* [lua_ssl_verify_depth](#lua_ssl_verify_depth)
1189+
* [lua_ssl_key_log](#lua_ssl_key_log)
11891190
* [lua_ssl_conf_command](#lua_ssl_conf_command)
11901191
* [lua_http10_buffering](#lua_http10_buffering)
11911192
* [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone)
@@ -3447,6 +3448,19 @@ See also [lua_ssl_certificate](#lua_ssl_certificate), [lua_ssl_certificate_key](
34473448

34483449
[Back to TOC](#directives)
34493450

3451+
lua_ssl_key_log
3452+
---------------
3453+
3454+
**syntax:** *lua_ssl_key_log <file>*
3455+
3456+
**default:** *none*
3457+
3458+
**context:** *http, server, location*
3459+
3460+
Enables logging of client connection SSL keys in the [tcpsock:sslhandshake](#tcpsocksslhandshake) method and specifies the path to the key log file. Keys are logged in the SSLKEYLOGFILE format compatible with Wireshark.
3461+
3462+
[Back to TOC](#directives)
3463+
34503464
lua_ssl_conf_command
34513465
--------------------
34523466

doc/HttpLuaModule.wiki

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2925,6 +2925,16 @@ This directive was first introduced in the <code>v0.9.11</code> release.
29252925
29262926
See also [[#lua_ssl_certificate|lua_ssl_certificate]], [[#lua_ssl_certificate_key|lua_ssl_certificate_key]] and [[#lua_ssl_trusted_certificate|lua_ssl_trusted_certificate]].
29272927
2928+
== lua_ssl_key_log ==
2929+
2930+
'''syntax:''' ''lua_ssl_key_log <file>''
2931+
2932+
'''default:''' ''none''
2933+
2934+
'''context:''' ''http, server, location''
2935+
2936+
Enables logging of client connection SSL keys in the [[#tcpsock:sslhandshake|tcpsock:sslhandshake]] method and specifies the path to the key log file. Keys are logged in the SSLKEYLOGFILE format compatible with Wireshark.
2937+
29282938
== lua_ssl_conf_command ==
29292939
29302940
'''syntax:''' ''lua_ssl_conf_command <command>''

src/ngx_http_lua_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ typedef struct {
379379
ngx_uint_t ssl_verify_depth;
380380
ngx_str_t ssl_trusted_certificate;
381381
ngx_str_t ssl_crl;
382+
ngx_str_t ssl_key_log;
382383
#if (nginx_version >= 1019004)
383384
ngx_array_t *ssl_conf_commands;
384385
#endif

src/ngx_http_lua_module.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ static ngx_int_t ngx_http_lua_merge_ssl(ngx_conf_t *cf,
5454
ngx_http_lua_loc_conf_t *conf, ngx_http_lua_loc_conf_t *prev);
5555
static ngx_int_t ngx_http_lua_set_ssl(ngx_conf_t *cf,
5656
ngx_http_lua_loc_conf_t *llcf);
57+
static void key_log_callback(const ngx_ssl_conn_t *ssl_conn,
58+
const char *line);
59+
static void ngx_http_lua_ssl_cleanup_key_log(void *data);
60+
static ngx_int_t ngx_http_lua_ssl_key_log(ngx_conf_t *cf, ngx_ssl_t *ssl,
61+
ngx_str_t *file);
5762
#if (nginx_version >= 1019004)
5863
static char *ngx_http_lua_ssl_conf_command_check(ngx_conf_t *cf, void *post,
5964
void *data);
@@ -690,6 +695,13 @@ static ngx_command_t ngx_http_lua_cmds[] = {
690695
offsetof(ngx_http_lua_loc_conf_t, ssl_crl),
691696
NULL },
692697

698+
{ ngx_string("lua_ssl_key_log"),
699+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
700+
ngx_conf_set_str_slot,
701+
NGX_HTTP_LOC_CONF_OFFSET,
702+
offsetof(ngx_http_lua_loc_conf_t, ssl_key_log),
703+
NULL },
704+
693705
#if (nginx_version >= 1019004)
694706
{ ngx_string("lua_ssl_conf_command"),
695707
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
@@ -1433,6 +1445,7 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf)
14331445
* conf->ssl_ciphers = { 0, NULL };
14341446
* conf->ssl_trusted_certificate = { 0, NULL };
14351447
* conf->ssl_crl = { 0, NULL };
1448+
* conf->ssl_key_log = { 0, NULL };
14361449
*/
14371450

14381451
conf->force_read_body = NGX_CONF_UNSET;
@@ -1553,6 +1566,7 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
15531566
ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
15541567
prev->ssl_trusted_certificate, "");
15551568
ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
1569+
ngx_conf_merge_str_value(conf->ssl_key_log, prev->ssl_key_log, "");
15561570

15571571
#if (nginx_version >= 1019004)
15581572
ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands,
@@ -1616,6 +1630,7 @@ ngx_http_lua_merge_ssl(ngx_conf_t *cf,
16161630
&& conf->ssl_certificate_keys == NGX_CONF_UNSET_PTR
16171631
&& conf->ssl_trusted_certificate.data == NULL
16181632
&& conf->ssl_crl.data == NULL
1633+
&& conf->ssl_key_log.data == NULL
16191634
#if (nginx_version >= 1019004)
16201635
&& conf->ssl_conf_commands == NGX_CONF_UNSET_PTR
16211636
#endif
@@ -1723,6 +1738,12 @@ ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf)
17231738
return NGX_ERROR;
17241739
}
17251740

1741+
if (ngx_http_lua_ssl_key_log(cf, llcf->ssl, &llcf->ssl_key_log)
1742+
!= NGX_OK)
1743+
{
1744+
return NGX_ERROR;
1745+
}
1746+
17261747
#if (nginx_version >= 1019004)
17271748
if (ngx_ssl_conf_commands(cf, llcf->ssl, llcf->ssl_conf_commands)
17281749
!= NGX_OK)
@@ -1734,6 +1755,102 @@ ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf)
17341755
return NGX_OK;
17351756
}
17361757

1758+
1759+
static void
1760+
key_log_callback(const ngx_ssl_conn_t *ssl_conn, const char *line)
1761+
{
1762+
ngx_http_lua_ssl_key_log_t *ssl_key_log;
1763+
ngx_connection_t *c;
1764+
1765+
ssl_key_log = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn),
1766+
ngx_http_lua_ssl_key_log_index);
1767+
if (ssl_key_log == NULL) {
1768+
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
1769+
ngx_ssl_error(NGX_LOG_DEBUG, c->log, 0, "get ssl key log failed");
1770+
1771+
return;
1772+
}
1773+
1774+
(void) ngx_write_fd(ssl_key_log->fd, (void *) line, ngx_strlen(line));
1775+
(void) ngx_write_fd(ssl_key_log->fd, (void *) "\n", 1);
1776+
}
1777+
1778+
1779+
static void
1780+
ngx_http_lua_ssl_cleanup_key_log(void *data)
1781+
{
1782+
ngx_http_lua_ssl_key_log_t *ssl_key_log = data;
1783+
1784+
if (ngx_close_file(ssl_key_log->fd) == NGX_FILE_ERROR) {
1785+
ngx_ssl_error(NGX_LOG_ALERT, ssl_key_log->ssl->log, 0,
1786+
ngx_close_file_n "(\"%V\") failed", ssl_key_log->name);
1787+
}
1788+
}
1789+
1790+
1791+
static ngx_int_t
1792+
ngx_http_lua_ssl_key_log(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
1793+
{
1794+
ngx_fd_t fd;
1795+
ngx_http_lua_ssl_key_log_t *ssl_key_log;
1796+
ngx_pool_cleanup_t *cln;
1797+
1798+
if (!file->len) {
1799+
return NGX_OK;
1800+
}
1801+
1802+
if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
1803+
return NGX_ERROR;
1804+
}
1805+
1806+
if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) {
1807+
return NGX_ERROR;
1808+
}
1809+
1810+
/*
1811+
* append so that existing keylog file contents can be preserved
1812+
*/
1813+
fd = ngx_open_file(file->data, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN,
1814+
NGX_FILE_DEFAULT_ACCESS);
1815+
if (fd == NGX_INVALID_FILE) {
1816+
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, ngx_open_file_n
1817+
"(\"%V\") failed", file);
1818+
return NGX_ERROR;
1819+
}
1820+
1821+
ssl_key_log = ngx_palloc(cf->pool, sizeof(ngx_http_lua_ssl_key_log_t));
1822+
if (ssl_key_log == NULL) {
1823+
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "ngx_pcalloc() failed");
1824+
return NGX_ERROR;
1825+
}
1826+
1827+
ssl_key_log->ssl = ssl;
1828+
ssl_key_log->fd = fd;
1829+
ssl_key_log->name = *file;
1830+
1831+
if (SSL_CTX_set_ex_data(ssl->ctx, ngx_http_lua_ssl_key_log_index,
1832+
ssl_key_log) == 0)
1833+
{
1834+
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
1835+
"SSL_CTX_set_ex_data() failed");
1836+
return NGX_ERROR;
1837+
}
1838+
1839+
cln = ngx_pool_cleanup_add(cf->pool, 0);
1840+
if (cln == NULL) {
1841+
ngx_http_lua_ssl_cleanup_key_log(ssl_key_log);
1842+
return NGX_ERROR;
1843+
}
1844+
1845+
cln->handler = ngx_http_lua_ssl_cleanup_key_log;
1846+
cln->data = ssl_key_log;
1847+
1848+
SSL_CTX_set_keylog_callback(ssl->ctx, key_log_callback);
1849+
1850+
return NGX_OK;
1851+
}
1852+
1853+
17371854
#if (nginx_version >= 1019004)
17381855
static char *
17391856
ngx_http_lua_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data)

src/ngx_http_lua_ssl.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515

1616
int ngx_http_lua_ssl_ctx_index = -1;
17+
int ngx_http_lua_ssl_key_log_index = -1;
1718

1819

1920
ngx_int_t
@@ -30,6 +31,17 @@ ngx_http_lua_ssl_init(ngx_log_t *log)
3031
}
3132
}
3233

34+
if (ngx_http_lua_ssl_key_log_index == -1) {
35+
ngx_http_lua_ssl_key_log_index = SSL_get_ex_new_index(0, NULL, NULL,
36+
NULL, NULL);
37+
38+
if (ngx_http_lua_ssl_key_log_index == -1) {
39+
ngx_ssl_error(NGX_LOG_ALERT, log, 0,
40+
"lua: SSL_get_ex_new_index() for key log failed");
41+
return NGX_ERROR;
42+
}
43+
}
44+
3345
return NGX_OK;
3446
}
3547

src/ngx_http_lua_ssl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,18 @@ typedef struct {
4141
} ngx_http_lua_ssl_ctx_t;
4242

4343

44+
typedef struct {
45+
ngx_ssl_t *ssl;
46+
ngx_fd_t fd;
47+
ngx_str_t name;
48+
} ngx_http_lua_ssl_key_log_t;
49+
50+
4451
ngx_int_t ngx_http_lua_ssl_init(ngx_log_t *log);
4552

4653

4754
extern int ngx_http_lua_ssl_ctx_index;
55+
extern int ngx_http_lua_ssl_key_log_index;
4856

4957

5058
#endif

t/129-ssl-socket.t

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2944,3 +2944,105 @@ SSL reused session
29442944
[alert]
29452945
[emerg]
29462946
--- timeout: 10
2947+
2948+
2949+
2950+
=== TEST 35: lua_ssl_key_log directive
2951+
--- skip_openssl: 8: < 1.1.1
2952+
--- http_config
2953+
server {
2954+
listen $TEST_NGINX_SERVER_SSL_PORT ssl;
2955+
server_name test.com;
2956+
ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt;
2957+
ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key;
2958+
ssl_protocols TLSv1.3;
2959+
2960+
location / {
2961+
content_by_lua_block {
2962+
ngx.exit(200)
2963+
}
2964+
}
2965+
}
2966+
--- config
2967+
server_tokens off;
2968+
lua_ssl_protocols TLSv1.3;
2969+
lua_ssl_key_log sslkey.log;
2970+
2971+
location /t {
2972+
content_by_lua_block {
2973+
local sock = ngx.socket.tcp()
2974+
sock:settimeout(2000)
2975+
2976+
do
2977+
local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT)
2978+
if not ok then
2979+
ngx.say("failed to connect: ", err)
2980+
return
2981+
end
2982+
2983+
ngx.say("connected: ", ok)
2984+
2985+
local session, err = sock:sslhandshake(nil, "test.com")
2986+
if not session then
2987+
ngx.say("failed to do SSL handshake: ", err)
2988+
return
2989+
end
2990+
2991+
ngx.say("ssl handshake: ", type(session))
2992+
2993+
local req = "GET / HTTP/1.1\r\nHost: test.com\r\nConnection: close\r\n\r\n"
2994+
local bytes, err = sock:send(req)
2995+
if not bytes then
2996+
ngx.say("failed to send http request: ", err)
2997+
return
2998+
end
2999+
3000+
ngx.say("sent http request: ", bytes, " bytes.")
3001+
3002+
local line, err = sock:receive()
3003+
if not line then
3004+
ngx.say("failed to receive response status line: ", err)
3005+
return
3006+
end
3007+
3008+
ngx.say("received: ", line)
3009+
3010+
local ok, err = sock:close()
3011+
ngx.say("close: ", ok, " ", err)
3012+
3013+
local f, err = io.open("$TEST_NGINX_SERVER_ROOT/conf/sslkey.log", "r")
3014+
if not f then
3015+
ngx.log(ngx.ERR, "failed to open sslkey.log: ", err)
3016+
return
3017+
end
3018+
3019+
local key_log = f:read("*a")
3020+
ngx.say(key_log)
3021+
f:close()
3022+
end -- do
3023+
collectgarbage()
3024+
}
3025+
}
3026+
--- request
3027+
GET /t
3028+
--- response_body_like
3029+
connected: 1
3030+
ssl handshake: cdata
3031+
sent http request: 53 bytes.
3032+
received: HTTP/1.1 200 OK
3033+
close: 1 nil
3034+
SERVER_HANDSHAKE_TRAFFIC_SECRET [0-9a-z\s]+
3035+
EXPORTER_SECRET [0-9a-z\s]+
3036+
SERVER_TRAFFIC_SECRET_0 [0-9a-z\s]+
3037+
CLIENT_HANDSHAKE_TRAFFIC_SECRET [0-9a-z\s]+
3038+
CLIENT_TRAFFIC_SECRET_0 [0-9a-z\s]+
3039+
3040+
--- log_level: debug
3041+
--- error_log eval
3042+
['lua ssl server name: "test.com"',
3043+
qr/SSL: TLSv1.3, cipher: "TLS_AES_256_GCM_SHA384 TLSv1.3/]
3044+
--- no_error_log
3045+
SSL reused session
3046+
[error]
3047+
[alert]
3048+
--- timeout: 10

0 commit comments

Comments
 (0)