From 842537ba34ba50fc1e1bb2daf84437dbe454f90c Mon Sep 17 00:00:00 2001 From: Tuure Vartiainen Date: Fri, 28 Jul 2017 13:08:56 +0300 Subject: [PATCH 1/8] feature: ngx.ssl: added new API functions get_psk_identity() and set_psk_key(). doc: added new API functions get_psk_identity() and set_psk_key() to ngx.ssl lib. --- lib/ngx/ssl.lua | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/ngx/ssl.md | 29 +++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/lib/ngx/ssl.lua b/lib/ngx/ssl.lua index 89d42a533..8dae77e22 100644 --- a/lib/ngx/ssl.lua +++ b/lib/ngx/ssl.lua @@ -58,6 +58,15 @@ int ngx_http_lua_ffi_set_priv_key(void *r, void *cdata, char **err); void ngx_http_lua_ffi_free_cert(void *cdata); void ngx_http_lua_ffi_free_priv_key(void *cdata); + +int ngx_http_lua_ffi_ssl_set_psk_key(ngx_http_request_t *r, + const char *key, size_t len, char **err); + +int ngx_http_lua_ffi_ssl_get_psk_identity(ngx_http_request_t *r, + char *buf, char **err); + +int ngx_http_lua_ffi_ssl_get_psk_identity_size(ngx_http_request_t *r, + char **err); ]] @@ -261,6 +270,50 @@ function _M.set_priv_key(priv_key) end +function _M.set_psk_key(psk_key) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_ssl_set_psk_key(r, psk_key, #psk_key, errmsg) + if rc == FFI_OK then + return true + end + + return nil, ffi_str(errmsg[0]) +end + + +-- return psk_identity, err +function _M.get_psk_identity() + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local len = C.ngx_http_lua_ffi_ssl_get_psk_identity_size(r, errmsg) + + if len < 0 then + return nil, ffi_str(errmsg[0]) + end + + if len > 4096 then + return nil, "psk identity too long" + end + + local buf = get_string_buf(len) + + local rc = C.ngx_http_lua_ffi_ssl_get_psk_identity(r, buf, errmsg) + + if rc == FFI_ERROR then + return nil, ffi_str(errmsg[0]) + end + + return ffi_str(buf, len) +end + + do _M.SSL3_VERSION = 0x0300 _M.TLS1_VERSION = 0x0301 diff --git a/lib/ngx/ssl.md b/lib/ngx/ssl.md index fc63c24e9..39e10e707 100644 --- a/lib/ngx/ssl.md +++ b/lib/ngx/ssl.md @@ -23,6 +23,8 @@ Table of Contents * [parse_pem_priv_key](#parse_pem_priv_key) * [set_cert](#set_cert) * [set_priv_key](#set_priv_key) + * [set_psk_key](#set_psk_key) + * [get_psk_identity](#get_psk_identity) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) @@ -396,6 +398,33 @@ This function was first added in version `0.1.7`. [Back to TOC](#table-of-contents) +set_psk_key +------------ +**syntax:** *ok, err = ssl.set_psk_key(psk_key)* + +**context:** *ssl_psk_by_lua** + +Sets the TLS-PSK key for the current SSL connection. + +Returns `true` on success, or a `nil` value and a string describing the error otherwise. + +This function was first added in version `xxx`. + +[Back to TOC](#table-of-contents) + +get_psk_identity +------------ +**syntax:** *identity, err = ssl.get_psk_identity()* + +**context:** *ssl_psk_by_lua** + +Returns a TLS-PSK identity a client sent for the current SSL connection. Returns `nil` and +a string describing the error otherwise. + +This function was first added in version `xxx`. + +[Back to TOC](#table-of-contents) + Community ========= From f6646cc5346b4c1c8765d48e2f30f3af375d7ace Mon Sep 17 00:00:00 2001 From: Tuure Vartiainen Date: Mon, 31 Jul 2017 15:04:40 +0300 Subject: [PATCH 2/8] travis-ci: use ssl-psk branch of lua-nginx-module. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 127725613..cff7fb603 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,7 +60,7 @@ install: - git clone https://github.com/openresty/openresty.git ../openresty - git clone https://github.com/openresty/openresty-devel-utils.git - git clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module - - git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module + - git clone -b ssl-psk https://github.com/vartiait/lua-nginx-module.git ../lua-nginx-module - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx - git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module - git clone https://github.com/openresty/lua-resty-lrucache.git From 54bbb7340c12ddad04b6162b18353852219db1d1 Mon Sep 17 00:00:00 2001 From: Tuure Vartiainen Date: Thu, 5 Oct 2017 01:09:02 +0300 Subject: [PATCH 3/8] tests: added test cases for TLS-PSK upstream and downstream. --- t/ssl-psk.t | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 t/ssl-psk.t diff --git a/t/ssl-psk.t b/t/ssl-psk.t new file mode 100644 index 000000000..680d65d31 --- /dev/null +++ b/t/ssl-psk.t @@ -0,0 +1,257 @@ +# vim:set ft=ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; +use Cwd qw(abs_path realpath cwd); +use File::Basename; + +#worker_connections(10140); +#workers(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 6 + 2); + +our $CWD = cwd(); + +no_long_string(); +#no_diff(); + +$ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$::CWD/lib/?.lua;;"; +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); + +run_tests(); + +__DATA__ + +=== TEST 1: TLS-PSK +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_psk_by_lua_block { + local ssl = require "ngx.ssl" + + local psk_key = "psk_test_key" + + local psk_identity, err = ssl.get_psk_identity() + if not psk_identity then + ngx.log(ngx.ERR, "failed to get psk identity: ", err) + return ngx.ERROR + end + + print("client psk identity: ", psk_identity) + + local ok, err = ssl.set_psk_key(key) + if not ok then + ngx.log(ngx.ERR, "failed to set psk key: ", err) + return ngx.ERROR + end + } + + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + ssl_psk_identity_hint psk_test_identity_hint; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + + location /t { + lua_ssl_ciphers PSK-AES256-CBC-SHA; + lua_ssl_psk_identity psk_test_identity; + lua_ssl_psk_key psk_test_key; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + 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 sess, err = sock:sslhandshake(nil, "test.com", false) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\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 http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +client psk identity: psk_test_identity + +--- no_error_log +[alert] +[emerg] +[error] + + + +=== TEST 2: TLS-PSK mismatching key +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_psk_by_lua_block { + local ssl = require "ngx.ssl" + + local psk_key = "psk_test_key2" + + local psk_identity, err = ssl.get_psk_identity() + if not psk_identity then + ngx.log(ngx.ERR, "failed to get psk identity: ", err) + return ngx.ERROR + end + + print("client psk identity: ", psk_identity) + + local ok, err = ssl.set_psk_key(key) + if not ok then + ngx.log(ngx.ERR, "failed to set psk key: ", err) + return ngx.ERROR + end + } + + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + ssl_psk_identity_hint psk_test_identity_hint; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + + location /t { + lua_ssl_ciphers PSK-AES256-CBC-SHA; + lua_ssl_psk_identity psk_test_identity; + lua_ssl_psk_key psk_test_key; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + 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 sess, err = sock:sslhandshake(nil, "test.com", false) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\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 http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed + +--- error_log +lua ssl server name: "test.com" +client psk identity: psk_test_identity + +--- no_error_log +[alert] +[emerg] +[error] From aea0d2eeaed544cd14e91e213fac37aaded31bda Mon Sep 17 00:00:00 2001 From: Tuure Vartiainen Date: Thu, 5 Oct 2017 01:40:22 +0300 Subject: [PATCH 4/8] bugfix: ngx.ssl: import base.FFI_ERROR. --- lib/ngx/ssl.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ngx/ssl.lua b/lib/ngx/ssl.lua index 8dae77e22..ca82ed607 100644 --- a/lib/ngx/ssl.lua +++ b/lib/ngx/ssl.lua @@ -16,6 +16,7 @@ local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local FFI_DECLINED = base.FFI_DECLINED local FFI_OK = base.FFI_OK +local FFI_ERROR = base.FFI_ERROR ffi.cdef[[ From 40cca9c6149f7a55e1fc556b4f63c06c4a75a9c3 Mon Sep 17 00:00:00 2001 From: Tuure Vartiainen Date: Thu, 5 Oct 2017 02:36:47 +0300 Subject: [PATCH 5/8] tests: Use TLSv1 in TLS-PSK test case. --- t/ssl-psk.t | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/t/ssl-psk.t b/t/ssl-psk.t index 680d65d31..1a270fa62 100644 --- a/t/ssl-psk.t +++ b/t/ssl-psk.t @@ -33,6 +33,9 @@ __DATA__ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; + ssl_protocols TLSv1; + ssl_ciphers PSK; + ssl_psk_by_lua_block { local ssl = require "ngx.ssl" @@ -69,7 +72,7 @@ __DATA__ server_tokens off; location /t { - lua_ssl_ciphers PSK-AES256-CBC-SHA; + lua_ssl_ciphers PSK; lua_ssl_psk_identity psk_test_identity; lua_ssl_psk_key psk_test_key; @@ -153,6 +156,9 @@ client psk identity: psk_test_identity listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; + ssl_protocols TLSv1; + ssl_ciphers PSK; + ssl_psk_by_lua_block { local ssl = require "ngx.ssl" @@ -189,7 +195,7 @@ client psk identity: psk_test_identity server_tokens off; location /t { - lua_ssl_ciphers PSK-AES256-CBC-SHA; + lua_ssl_ciphers PSK; lua_ssl_psk_identity psk_test_identity; lua_ssl_psk_key psk_test_key; From 2623195ac9eb855ca50e49d284c0b1a680e4e550 Mon Sep 17 00:00:00 2001 From: Tuure Vartiainen Date: Thu, 5 Oct 2017 15:33:00 +0300 Subject: [PATCH 6/8] tests: define lua_package_path in ssl-psk.t --- t/ssl-psk.t | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/t/ssl-psk.t b/t/ssl-psk.t index 1a270fa62..8bc6b8f9d 100644 --- a/t/ssl-psk.t +++ b/t/ssl-psk.t @@ -20,15 +20,13 @@ no_long_string(); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$::CWD/lib/?.lua;;"; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); -$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; -$ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); - run_tests(); __DATA__ === TEST 1: TLS-PSK --- http_config + lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH/?.lua;;"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; From ee753ece69fe6de69e845848cedc2efc02357c1c Mon Sep 17 00:00:00 2001 From: Tuure Vartiainen Date: Thu, 5 Oct 2017 16:01:47 +0300 Subject: [PATCH 7/8] tests: fixed a typo and adjusted expected error_log output in ssl-psk.t --- t/ssl-psk.t | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/t/ssl-psk.t b/t/ssl-psk.t index 8bc6b8f9d..32823d63d 100644 --- a/t/ssl-psk.t +++ b/t/ssl-psk.t @@ -47,7 +47,7 @@ __DATA__ print("client psk identity: ", psk_identity) - local ok, err = ssl.set_psk_key(key) + local ok, err = ssl.set_psk_key(psk_key) if not ok then ngx.log(ngx.ERR, "failed to set psk key: ", err) return ngx.ERROR @@ -150,6 +150,7 @@ client psk identity: psk_test_identity === TEST 2: TLS-PSK mismatching key --- http_config + lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH/?.lua;;"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -170,7 +171,7 @@ client psk identity: psk_test_identity print("client psk identity: ", psk_identity) - local ok, err = ssl.set_psk_key(key) + local ok, err = ssl.set_psk_key(psk_key) if not ok then ngx.log(ngx.ERR, "failed to set psk key: ", err) return ngx.ERROR @@ -251,11 +252,13 @@ GET /t connected: 1 failed to do SSL handshake: handshake failed ---- error_log -lua ssl server name: "test.com" -client psk identity: psk_test_identity +--- error_log eval +[ +qr/lua ssl server name: "test.com"/s, +qr/client psk identity: psk_test_identity/s, +qr/\[error\] .*? SSL_do_handshake\(\) failed .*? alert bad record mac/s, +] --- no_error_log [alert] [emerg] -[error] From 6aa46b74b657613c251ef70409089c8362ebf8f9 Mon Sep 17 00:00:00 2001 From: Tuure Vartiainen Date: Mon, 9 Oct 2017 17:43:33 +0300 Subject: [PATCH 8/8] tests: Changed ssl_psk_by_lua* with ssl_certificate_by_lua*. doc: Changed ssl_psk_by_lua* with ssl_certificate_by_lua*. --- lib/ngx/ssl.md | 4 ++-- t/ssl-psk.t | 20 ++++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/ngx/ssl.md b/lib/ngx/ssl.md index 39e10e707..a0573f6d8 100644 --- a/lib/ngx/ssl.md +++ b/lib/ngx/ssl.md @@ -402,7 +402,7 @@ set_psk_key ------------ **syntax:** *ok, err = ssl.set_psk_key(psk_key)* -**context:** *ssl_psk_by_lua** +**context:** *ssl_certificate_by_lua** Sets the TLS-PSK key for the current SSL connection. @@ -416,7 +416,7 @@ get_psk_identity ------------ **syntax:** *identity, err = ssl.get_psk_identity()* -**context:** *ssl_psk_by_lua** +**context:** *ssl_certificate_by_lua** Returns a TLS-PSK identity a client sent for the current SSL connection. Returns `nil` and a string describing the error otherwise. diff --git a/t/ssl-psk.t b/t/ssl-psk.t index 32823d63d..780e5dfa4 100644 --- a/t/ssl-psk.t +++ b/t/ssl-psk.t @@ -34,15 +34,19 @@ __DATA__ ssl_protocols TLSv1; ssl_ciphers PSK; - ssl_psk_by_lua_block { + ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local psk_key = "psk_test_key" local psk_identity, err = ssl.get_psk_identity() if not psk_identity then + if err == "not in psk context" then + -- handler was not called by TLS-PSK callback + return + end ngx.log(ngx.ERR, "failed to get psk identity: ", err) - return ngx.ERROR + return ngx.exit(ngx.ERROR) end print("client psk identity: ", psk_identity) @@ -50,7 +54,7 @@ __DATA__ local ok, err = ssl.set_psk_key(psk_key) if not ok then ngx.log(ngx.ERR, "failed to set psk key: ", err) - return ngx.ERROR + return ngx.exit(ngx.ERROR) end } @@ -158,15 +162,19 @@ client psk identity: psk_test_identity ssl_protocols TLSv1; ssl_ciphers PSK; - ssl_psk_by_lua_block { + ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local psk_key = "psk_test_key2" local psk_identity, err = ssl.get_psk_identity() if not psk_identity then + if err == "not in psk context" then + -- handler was not called by TLS-PSK callback + return + end ngx.log(ngx.ERR, "failed to get psk identity: ", err) - return ngx.ERROR + return ngx.exit(ngx.ERROR) end print("client psk identity: ", psk_identity) @@ -174,7 +182,7 @@ client psk identity: psk_test_identity local ok, err = ssl.set_psk_key(psk_key) if not ok then ngx.log(ngx.ERR, "failed to set psk key: ", err) - return ngx.ERROR + return ngx.exit(ngx.ERROR) end }