Skip to content

feature: lua_ssl_key_log directive #376

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ behavior.
* [lua_ssl_certificate_key](https://github.com/openresty/lua-nginx-module#lua_ssl_certificate_key)
* [lua_ssl_trusted_certificate](https://github.com/openresty/lua-nginx-module#lua_ssl_trusted_certificate)
* [lua_ssl_verify_depth](https://github.com/openresty/lua-nginx-module#lua_ssl_verify_depth)
* [lua_ssl_key_log](https://github.com/openresty/lua-nginx-module#lua_ssl_key_log)
* [lua_ssl_conf_command](https://github.com/openresty/lua-nginx-module#lua_ssl_conf_command)
* [lua_check_client_abort](https://github.com/openresty/lua-nginx-module#lua_check_client_abort)
* [lua_max_pending_timers](https://github.com/openresty/lua-nginx-module#lua_max_pending_timers)
Expand Down
1 change: 1 addition & 0 deletions src/ngx_stream_lua_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ struct ngx_stream_lua_srv_conf_s {
ngx_uint_t ssl_verify_depth;
ngx_str_t ssl_trusted_certificate;
ngx_str_t ssl_crl;
ngx_str_t ssl_key_log;
#if (nginx_version >= 1019004)
ngx_array_t *ssl_conf_commands;
#endif
Expand Down
114 changes: 114 additions & 0 deletions src/ngx_stream_lua_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ static char *ngx_stream_lua_lowat_check(ngx_conf_t *cf, void *post, void *data);
#if (NGX_STREAM_SSL)
static ngx_int_t ngx_stream_lua_set_ssl(ngx_conf_t *cf,
ngx_stream_lua_loc_conf_t *llcf);
static void key_log_callback(const ngx_ssl_conn_t *ssl_conn,
const char *line);
static void ngx_stream_lua_ssl_cleanup_key_log(void *data);
static ngx_int_t ngx_stream_lua_ssl_key_log(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *file);
#if (nginx_version >= 1019004)
static char *ngx_stream_lua_ssl_conf_command_check(ngx_conf_t *cf, void *post,
void *data);
Expand Down Expand Up @@ -453,6 +458,13 @@ static ngx_command_t ngx_stream_lua_cmds[] = {
offsetof(ngx_stream_lua_srv_conf_t, ssl_crl),
NULL },

{ ngx_string("lua_ssl_key_log"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_STREAM_SRV_CONF_OFFSET,
offsetof(ngx_stream_lua_srv_conf_t, ssl_key_log),
NULL },

#if (nginx_version >= 1019004)
{ ngx_string("lua_ssl_conf_command"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2,
Expand Down Expand Up @@ -975,6 +987,7 @@ ngx_stream_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
prev->ssl_trusted_certificate, "");
ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
ngx_conf_merge_str_value(conf->ssl_key_log, prev->ssl_key_log, "");
#if (nginx_version >= 1019004)
ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands,
NULL);
Expand Down Expand Up @@ -1105,6 +1118,12 @@ ngx_stream_lua_set_ssl(ngx_conf_t *cf, ngx_stream_lua_srv_conf_t *lscf)
return NGX_ERROR;
}

if (ngx_stream_lua_ssl_key_log(cf, lscf->ssl, &lscf->ssl_key_log)
!= NGX_OK)
{
return NGX_ERROR;
}

#if (nginx_version >= 1019004)
if (ngx_ssl_conf_commands(cf, lscf->ssl, lscf->ssl_conf_commands)
!= NGX_OK)
Expand All @@ -1117,6 +1136,101 @@ ngx_stream_lua_set_ssl(ngx_conf_t *cf, ngx_stream_lua_srv_conf_t *lscf)
}


static void
key_log_callback(const ngx_ssl_conn_t *ssl_conn, const char *line)
{
ngx_stream_lua_ssl_key_log_t *ssl_key_log;
ngx_connection_t *c;

ssl_key_log = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn),
ngx_stream_lua_ssl_key_log_index);
if (ssl_key_log == NULL) {
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
ngx_ssl_error(NGX_LOG_DEBUG, c->log, 0, "get ssl key log failed");

return;
}

(void) ngx_write_fd(ssl_key_log->fd, (void *) line, ngx_strlen(line));
(void) ngx_write_fd(ssl_key_log->fd, (void *) "\n", 1);
}


static void
ngx_stream_lua_ssl_cleanup_key_log(void *data)
{
ngx_stream_lua_ssl_key_log_t *ssl_key_log = data;

if (ngx_close_file(ssl_key_log->fd) == NGX_FILE_ERROR) {
ngx_ssl_error(NGX_LOG_ALERT, ssl_key_log->ssl->log, 0,
ngx_close_file_n "(\"%V\") failed", ssl_key_log->name);
}
}


static ngx_int_t
ngx_stream_lua_ssl_key_log(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
{
ngx_fd_t fd;
ngx_stream_lua_ssl_key_log_t *ssl_key_log;
ngx_pool_cleanup_t *cln;

if (!file->len) {
return NGX_OK;
}

if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
return NGX_ERROR;
}

if (ngx_stream_lua_ssl_init(cf->log) != NGX_OK) {
return NGX_ERROR;
}

/*
* append so that existing keylog file contents can be preserved
*/
fd = ngx_open_file(file->data, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN,
NGX_FILE_DEFAULT_ACCESS);
if (fd == NGX_INVALID_FILE) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, ngx_open_file_n
"(\"%V\") failed", file);
return NGX_ERROR;
}

ssl_key_log = ngx_palloc(cf->pool, sizeof(ngx_stream_lua_ssl_key_log_t));
if (ssl_key_log == NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "ngx_pcalloc() failed");
return NGX_ERROR;
}

ssl_key_log->ssl = ssl;
ssl_key_log->fd = fd;
ssl_key_log->name = *file;

if (SSL_CTX_set_ex_data(ssl->ctx, ngx_stream_lua_ssl_key_log_index,
ssl_key_log) == 0)
{
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"SSL_CTX_set_ex_data() failed");
return NGX_ERROR;
}

cln = ngx_pool_cleanup_add(cf->pool, 0);
if (cln == NULL) {
ngx_stream_lua_ssl_cleanup_key_log(ssl_key_log);
return NGX_ERROR;
}

cln->handler = ngx_stream_lua_ssl_cleanup_key_log;
cln->data = ssl_key_log;

SSL_CTX_set_keylog_callback(ssl->ctx, key_log_callback);

return NGX_OK;
}


#if (nginx_version >= 1019004)
static char *
ngx_stream_lua_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data)
Expand Down
14 changes: 14 additions & 0 deletions src/ngx_stream_lua_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@


int ngx_stream_lua_ssl_ctx_index = -1;
int ngx_stream_lua_ssl_key_log_index = -1;


ngx_int_t
Expand All @@ -40,6 +41,19 @@ ngx_stream_lua_ssl_init(ngx_log_t *log)
}
}

if (ngx_stream_lua_ssl_key_log_index == -1) {
ngx_stream_lua_ssl_key_log_index = SSL_get_ex_new_index(0, NULL,
NULL,
NULL,
NULL);

if (ngx_stream_lua_ssl_key_log_index == -1) {
ngx_ssl_error(NGX_LOG_ALERT, log, 0,
"lua: SSL_get_ex_new_index() for key log failed");
return NGX_ERROR;
}
}

return NGX_OK;
}

Expand Down
8 changes: 8 additions & 0 deletions src/ngx_stream_lua_ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,18 @@ typedef struct {
} ngx_stream_lua_ssl_ctx_t;


typedef struct {
ngx_ssl_t *ssl;
ngx_fd_t fd;
ngx_str_t name;
} ngx_stream_lua_ssl_key_log_t;


ngx_int_t ngx_stream_lua_ssl_init(ngx_log_t *log);


extern int ngx_stream_lua_ssl_ctx_index;
extern int ngx_stream_lua_ssl_key_log_index;


#endif
Expand Down
105 changes: 105 additions & 0 deletions t/129-ssl-socket.t
Original file line number Diff line number Diff line change
Expand Up @@ -3012,3 +3012,108 @@ handshake rejected while SSL handshaking
[crit]
--- timeout: 5
--- skip_nginx: 7: < 1.25.4



=== TEST 37: lua_ssl_key_log directive
--- skip_openssl: 8: < 1.1.1
--- http_config
server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
server_name test.com;
ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt;
ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key;
ssl_protocols TLSv1.3;

location / {
content_by_lua_block {
ngx.exit(200)
}
}
}
--- stream_server_config
lua_ssl_protocols TLSv1.3;
lua_ssl_key_log sslkey.log;

content_by_lua_block {
local sock = ngx.socket.tcp()
sock:settimeout(2000)

do
local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
if not ok then
ngx.say("failed to connect: ", err)
return
end

ngx.say("connected: ", ok)

local session, err = sock:sslhandshake(nil, "test.com")
if not session then
ngx.say("failed to do SSL handshake: ", err)
return
end

ngx.say("ssl handshake: ", type(session))

local req = "GET / HTTP/1.1\r\nHost: test.com\r\nConnection: close\r\n\r\n"
local bytes, err = sock:send(req)
if not bytes then
ngx.say("failed to send stream request: ", err)
return
end

ngx.say("sent stream request: ", bytes, " bytes.")

local line, err = sock:receive()
if not line then
ngx.say("failed to recieve response status line: ", err)
return
end

ngx.say("received: ", line)

local ok, err = sock:close()
ngx.say("close: ", ok, " ", err)

local f, err = io.open("$TEST_NGINX_SERVER_ROOT/conf/sslkey.log", "r")
if not f then
ngx.log(ngx.ERR, "failed to open sslkey.log: ", err)
return
end

local key_log = f:read("*a")
ngx.say(key_log)
f:close()
end -- do
collectgarbage()
}

--- stream_response_like
connected: 1
ssl handshake: userdata
sent stream request: 53 bytes.
received: HTTP/1.1 200 OK
close: 1 nil
SERVER_HANDSHAKE_TRAFFIC_SECRET [0-9a-z\s]+
EXPORTER_SECRET [0-9a-z\s]+
SERVER_TRAFFIC_SECRET_0 [0-9a-z\s]+
CLIENT_HANDSHAKE_TRAFFIC_SECRET [0-9a-z\s]+
CLIENT_TRAFFIC_SECRET_0 [0-9a-z\s]+

--- log_level: debug
--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/
--- grep_error_log_out eval
qr/^lua ssl save session: ([0-9A-F]+)
lua ssl free session: ([0-9A-F]+)
$/
--- error_log eval
[
'lua ssl server name: "test.com"',
qr/SSL: TLSv1.3, cipher: "(TLS_AES_256_GCM_SHA384 TLSv1.3|TLS_AES_128_GCM_SHA256 Kx=GENERIC Au=GENERIC Enc=AESGCM\(128\) Mac=AEAD)/,
]
--- no_error_log
SSL reused session
[error]
[alert]
--- timeout: 10