From ed1d8201c7c2fbae762b8a2f7021cbf2e579a841 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Thu, 19 Jan 2017 22:03:25 +0000 Subject: [PATCH] feature: ssl: add FFI function to set SSL ciphers --- src/ngx_http_lua_ssl_certby.c | 27 ++++++++ t/140-ssl-c-api.t | 124 +++++++++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 84e309316a..ac83802745 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -1236,6 +1236,33 @@ ngx_http_lua_ffi_set_priv_key(ngx_http_request_t *r, } +int +ngx_http_lua_ffi_ssl_set_ciphers(ngx_http_request_t *r, const char *ciphers, + char **err) +{ + ngx_ssl_conn_t *ssl_conn; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + if (!SSL_set_cipher_list(ssl_conn, ciphers)) { + *err = "SSL_set_cipher_list() failed"; + ERR_clear_error(); + return NGX_ERROR; + } + + return NGX_OK; +} + + #endif /* NGX_LUA_NO_FFI_API */ diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index 854ff30aad..8960faa677 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -11,7 +11,7 @@ my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); } else { - plan tests => repeat_each() * (blocks() * 5 + 1); + plan tests => repeat_each() * (blocks() * 5 + 2); } $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -62,6 +62,9 @@ ffi.cdef[[ void ngx_http_lua_ffi_free_priv_key(void *cdata); int ngx_http_lua_ffi_ssl_clear_certs(void *r, char **err); + + int ngx_http_lua_ffi_ssl_set_ciphers(void *r, const char *ciphers, + char **err); ]] _EOC_ } @@ -811,3 +814,122 @@ lua ssl server name: "test.com" --- no_error_log [error] [alert] + + + +=== TEST 6: set ciphers +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate ../../cert/test_ecdsa.crt; + ssl_certificate_key ../../cert/test_ecdsa.key; + + ssl_ciphers AES128; + + ssl_certificate_by_lua_block { + collectgarbage() + + local ffi = require "ffi" + require "defines" + + local errmsg = ffi.new("char *[1]") + + local r = getfenv(0).__ngx_req + if not r then + ngx.log(ngx.ERR, "no request found") + return + end + + local rc = ffi.C.ngx_http_lua_ffi_ssl_set_ciphers(r, "AES256", errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set ciphers: ", + ffi.string(errmsg[0])) + return + end + } + + 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; + lua_ssl_ciphers AES256; + lua_ssl_trusted_certificate ../../cert/test_ecdsa.crt; + + location /t { + 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", true) + 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" +cipher: "ECDHE-ECDSA-AES256-GCM-SHA384 + +--- no_error_log +[error] +[alert]