From 8b5dcfaad1970f4f8be9ceb22c9a6d9442b27f76 Mon Sep 17 00:00:00 2001 From: spacewander Date: Fri, 4 Nov 2022 13:39:25 +0800 Subject: [PATCH 1/2] feat: add GM C API enable/disable ntls Signed-off-by: spacewander --- lib/resty/apisix/ssl.lua | 21 ++++ patch/1.21.4/nginx-enable_ntls.patch | 19 ++- src/ngx_http_apisix_module.c | 49 +++++++- src/ngx_http_apisix_module.h | 2 + t/gm.t | 175 ++++++++++++++++++++++++--- 5 files changed, 245 insertions(+), 21 deletions(-) diff --git a/lib/resty/apisix/ssl.lua b/lib/resty/apisix/ssl.lua index dd75279..89fdcc1 100644 --- a/lib/resty/apisix/ssl.lua +++ b/lib/resty/apisix/ssl.lua @@ -14,6 +14,7 @@ ffi.cdef[[ typedef intptr_t ngx_flag_t; int ngx_http_apisix_set_gm_cert(void *r, void *cdata, char **err, ngx_flag_t type); int ngx_http_apisix_set_gm_priv_key(void *r, void *cdata, char **err, ngx_flag_t type); + int ngx_http_apisix_enable_ntls(void *r, int enabled); ]] @@ -62,4 +63,24 @@ function _M.set_gm_priv_key(enc_pkey, sign_pkey) end +function _M.enable_ntls() + local r = get_request() + if not r then + error("no request found") + end + + C.ngx_http_apisix_enable_ntls(r, 1) +end + + +function _M.disable_ntls() + local r = get_request() + if not r then + error("no request found") + end + + C.ngx_http_apisix_enable_ntls(r, 0) +end + + return _M diff --git a/patch/1.21.4/nginx-enable_ntls.patch b/patch/1.21.4/nginx-enable_ntls.patch index 04d32bb..641e243 100644 --- a/patch/1.21.4/nginx-enable_ntls.patch +++ b/patch/1.21.4/nginx-enable_ntls.patch @@ -1,14 +1,25 @@ diff --git src/http/ngx_http_request.c src/http/ngx_http_request.c -index 013b715..a729693 100644 +index 013b715..96be553 100644 --- src/http/ngx_http_request.c +++ src/http/ngx_http_request.c -@@ -754,6 +754,11 @@ ngx_http_ssl_handshake(ngx_event_t *rev) +@@ -8,6 +8,9 @@ + #include + #include + #include ++#if (NGX_HTTP_APISIX) ++#include ++#endif + + + static void ngx_http_wait_request_handler(ngx_event_t *ev); +@@ -754,6 +757,12 @@ ngx_http_ssl_handshake(ngx_event_t *rev) return; } +#if (TONGSUO_VERSION_NUMBER && NGX_HTTP_APISIX) -+ // FIXME: add option later -+ SSL_enable_ntls(c->ssl->connection); ++ if (ngx_http_apisix_is_ntls_enabled(hc->conf_ctx)) { ++ SSL_enable_ntls(c->ssl->connection); ++ } +#endif + ngx_reusable_connection(c, 0); diff --git a/src/ngx_http_apisix_module.c b/src/ngx_http_apisix_module.c index 1185c9c..024e5ea 100644 --- a/src/ngx_http_apisix_module.c +++ b/src/ngx_http_apisix_module.c @@ -9,12 +9,18 @@ #define NGX_HTTP_APISIX_SSL_SIGN 2 +typedef struct { + ngx_flag_t enable_ntls; +} ngx_http_apisix_main_conf_t; + + static ngx_str_t remote_addr = ngx_string("remote_addr"); static ngx_str_t remote_port = ngx_string("remote_port"); static ngx_str_t realip_remote_addr = ngx_string("realip_remote_addr"); static ngx_str_t realip_remote_port = ngx_string("realip_remote_port"); +static void *ngx_http_apisix_create_main_conf(ngx_conf_t *cf); static void *ngx_http_apisix_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_apisix_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); @@ -36,7 +42,7 @@ static ngx_http_module_t ngx_http_apisix_module_ctx = { NULL, /* preconfiguration */ NULL, /* postconfiguration */ - NULL, /* create main configuration */ + ngx_http_apisix_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ @@ -63,6 +69,26 @@ ngx_module_t ngx_http_apisix_module = { }; +static void * +ngx_http_apisix_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_apisix_main_conf_t *acf; + + acf = ngx_pcalloc(cf->pool, sizeof(ngx_http_apisix_main_conf_t)); + if (acf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * acf->enable_ntls = 0; + */ + + return acf; +} + + static void * ngx_http_apisix_create_loc_conf(ngx_conf_t *cf) { @@ -778,3 +804,24 @@ ngx_http_apisix_set_gm_priv_key(ngx_http_request_t *r, #endif } + + +int +ngx_http_apisix_enable_ntls(ngx_http_request_t *r, int enabled) +{ + ngx_http_apisix_main_conf_t *acf; + + acf = ngx_http_get_module_main_conf(r, ngx_http_apisix_module); + acf->enable_ntls = enabled; + return NGX_OK; +} + + +ngx_flag_t +ngx_http_apisix_is_ntls_enabled(ngx_http_conf_ctx_t *conf_ctx) +{ + ngx_http_apisix_main_conf_t *acf; + + acf = ngx_http_get_module_main_conf(conf_ctx, ngx_http_apisix_module); + return acf->enable_ntls; +} diff --git a/src/ngx_http_apisix_module.h b/src/ngx_http_apisix_module.h index 68bd25b..a363e8f 100644 --- a/src/ngx_http_apisix_module.h +++ b/src/ngx_http_apisix_module.h @@ -55,5 +55,7 @@ void ngx_http_apisix_mark_request_header_set(ngx_http_request_t *r); ngx_int_t ngx_http_apisix_is_header_filter_by_lua_skipped(ngx_http_request_t *r); ngx_int_t ngx_http_apisix_is_body_filter_by_lua_skipped(ngx_http_request_t *r); +ngx_flag_t ngx_http_apisix_is_ntls_enabled(ngx_http_conf_ctx_t *conf_ctx); + #endif /* _NGX_HTTP_APISIX_H_INCLUDED_ */ diff --git a/t/gm.t b/t/gm.t index 0dff617..8b5183e 100644 --- a/t/gm.t +++ b/t/gm.t @@ -8,17 +8,13 @@ if ($openssl_version !~ m/Tongsuo/) { plan 'no_plan'; } -run_tests(); - -__DATA__ +add_block_preprocessor(sub { + my ($block) = @_; -=== TEST 1: gm handshake ---- http_config - lua_shared_dict done 16k; - server { - listen 1994 ssl; - server_name test.com; - ssl_certificate_by_lua_block { + my $http_config = $block->http_config // ''; + $http_config .= <<_EOC_; + init_by_lua_block { + function set_gm_cert_and_key() local ngx_ssl = require "ngx.ssl" local ssl = require "resty.apisix.ssl" @@ -75,7 +71,39 @@ __DATA__ ngx.log(ngx.ERR, "failed to set private key: ", err) return end + end + + function handshake() + local req = "'GET / HTTP/1.0\\r\\nHost: test.com\\r\\nConnection: close\\r\\n\\r\\n'" + local cmd = "./openssl s_client -connect 127.0.0.1:1994 " .. + "-cipher ECDHE-SM2-WITH-SM4-SM3 -enable_ntls -ntls -verifyCAfile " .. + "t/certs/gm_ca.crt -sign_cert t/certs/client_sign.crt -sign_key t/certs/client_sign.key " .. + "-enc_cert t/certs/client_enc.crt -enc_key t/certs/client_enc.key" + return io.popen("echo -n " .. req .. " | timeout 3s " .. cmd) + end + } +_EOC_ + + $block->set_value("http_config", $http_config); +}); + +run_tests(); + +__DATA__ +=== TEST 1: gm handshake +--- http_config + init_worker_by_lua_block { + local ssl = require "resty.apisix.ssl" + ssl.enable_ntls() + } + + lua_shared_dict done 16k; + server { + listen 1994 ssl; + server_name test.com; + ssl_certificate_by_lua_block { + set_gm_cert_and_key() } ssl_certificate ../../certs/apisix.crt; ssl_certificate_key ../../certs/apisix.key; @@ -93,12 +121,7 @@ __DATA__ location /t { content_by_lua_block { ngx.shared.done:delete("handshake") - local req = "'GET / HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n'" - local cmd = "./openssl s_client -connect 127.0.0.1:1994 " .. - "-cipher ECDHE-SM2-WITH-SM4-SM3 -enable_ntls -ntls -verifyCAfile " .. - "t/certs/gm_ca.crt -sign_cert t/certs/client_sign.crt -sign_key t/certs/client_sign.key " .. - "-enc_cert t/certs/client_enc.crt -enc_key t/certs/client_enc.key" - local f, err = io.popen("echo -n " .. req .. " | timeout 3s " .. cmd) + local f, err = handshake() if not f then ngx.say(err) return @@ -128,3 +151,123 @@ New, NTLSv1.1, Cipher is ECDHE-SM2-SM4-CBC-SM3 [error] [alert] [emerg] + + + +=== TEST 2: gm handshake without ntls enable +--- http_config + lua_shared_dict done 16k; + server { + listen 1994 ssl; + server_name test.com; + ssl_certificate_by_lua_block { + set_gm_cert_and_key() + } + ssl_certificate ../../certs/apisix.crt; + ssl_certificate_key ../../certs/apisix.key; + + server_tokens off; + location / { + content_by_lua_block { + ngx.shared.done:set("handshake", true) + } + } + } +--- config + server_tokens off; + + location /t { + content_by_lua_block { + ngx.shared.done:delete("handshake") + local f, err = handshake() + if not f then + ngx.say(err) + return + end + + local step = 0.001 + while step < 1 do + ngx.sleep(step) + step = step * 2 + + if ngx.shared.done:get("handshake") then + local out = f:read('*a') + ngx.log(ngx.INFO, out) + ngx.say("ok") + f:close() + return + end + end + } + } + +--- error_log +SSL_do_handshake() failed +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 3: gm handshake, then disable ntls +--- http_config + init_worker_by_lua_block { + local ssl = require "resty.apisix.ssl" + ssl.enable_ntls() + } + + lua_shared_dict done 16k; + server { + listen 1994 ssl; + server_name test.com; + ssl_certificate_by_lua_block { + set_gm_cert_and_key() + } + ssl_certificate ../../certs/apisix.crt; + ssl_certificate_key ../../certs/apisix.key; + + server_tokens off; + location / { + content_by_lua_block { + ngx.shared.done:set("handshake", true) + } + } + } +--- config + server_tokens off; + + location /t { + content_by_lua_block { + local ssl = require "resty.apisix.ssl" + ssl.disable_ntls() + + ngx.shared.done:delete("handshake") + local f, err = handshake() + if not f then + ngx.say(err) + return + end + + local step = 0.001 + while step < 2 do + ngx.sleep(step) + step = step * 2 + + if ngx.shared.done:get("handshake") then + local out = f:read('*a') + ngx.log(ngx.INFO, out) + ngx.say("ok") + f:close() + return + end + end + } + } + +--- error_log +SSL_do_handshake() failed +--- no_error_log +[error] +[alert] +[emerg] From 146c2bf04caeb7608a5067fb9c91eaa3e113c70a Mon Sep 17 00:00:00 2001 From: spacewander Date: Fri, 4 Nov 2022 16:42:53 +0800 Subject: [PATCH 2/2] test Signed-off-by: spacewander --- t/gm.t | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/t/gm.t b/t/gm.t index 8b5183e..c5a3d69 100644 --- a/t/gm.t +++ b/t/gm.t @@ -271,3 +271,101 @@ SSL_do_handshake() failed [error] [alert] [emerg] + + + +=== TEST 4: regular handshake with gm enabled +--- http_config + init_worker_by_lua_block { + local ssl = require "resty.apisix.ssl" + ssl.enable_ntls() + } + + lua_shared_dict done 16k; + server { + listen 1994 ssl; + server_name test.com; + ssl_certificate_by_lua_block { + local ngx_ssl = require "ngx.ssl" + + ngx_ssl.clear_certs() + + local f = assert(io.open("t/certs/test.crt")) + local cert = f:read("*a") + f:close() + + local cert, err = ngx_ssl.parse_pem_cert(cert) + if not cert then + ngx.log(ngx.ERR, "failed to parse pem cert: ", err) + return + end + + local ok, err = ngx_ssl.set_cert(cert) + if not ok then + ngx.log(ngx.ERR, "failed to set cert: ", err) + return + end + + local f = assert(io.open("t/certs/test.key")) + local pkey_data = f:read("*a") + f:close() + + local pkey, err = ngx_ssl.parse_pem_priv_key(pkey_data) + if not pkey then + ngx.log(ngx.ERR, "failed to parse pem key: ", err) + return + end + + local ok, err = ngx_ssl.set_priv_key(pkey) + if not ok then + ngx.log(ngx.ERR, "failed to set private key: ", err) + return + end + } + ssl_certificate ../../certs/apisix.crt; + ssl_certificate_key ../../certs/apisix.key; + + server_tokens off; + location / { + content_by_lua_block { + ngx.shared.done:set("handshake", true) + } + } + } +--- config + server_tokens off; + + location /t { + content_by_lua_block { + ngx.shared.done:delete("handshake") + local req = "'GET / HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n'" + local f, err = io.popen("echo -n " .. req .. " | timeout 3s openssl s_client -connect 127.0.0.1:1994") + if not f then + ngx.say(err) + return + end + + local step = 0.001 + while step < 2 do + ngx.sleep(step) + step = step * 2 + + if ngx.shared.done:get("handshake") then + local out = f:read('*a') + ngx.log(ngx.INFO, out) + ngx.say("ok") + f:close() + return + end + end + + ngx.log(ngx.ERR, "openssl client handshake timeout") + } + } + +--- error_log +New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384 +--- no_error_log +[error] +[alert] +[emerg]