From d2944a1b31eb032dcf66dcd5cc3b382fb75f3144 Mon Sep 17 00:00:00 2001 From: mengxiangwei Date: Mon, 16 Mar 2026 22:52:09 +0800 Subject: [PATCH 1/2] feat: add server random and master key fetch api --- .vscode/c_cpp_properties.json | 18 + .vscode/launch.json | 13 + .vscode/settings.json | 74 ++ src/ngx_http_lua_ssl_certby.c | 49 + src/ngx_http_lua_ssl_certby.c.orig | 1657 ++++++++++++++++++++++++++++ 5 files changed, 1811 insertions(+) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 src/ngx_http_lua_ssl_certby.c.orig diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000000..9b8a691b01 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "macos-clang-x64", + "includePath": [ + "${workspaceFolder}/**" + ], + "compilerPath": "/usr/local/opt/llvm/bin/clang", + "cStandard": "${default}", + "cppStandard": "${default}", + "intelliSenseMode": "macos-clang-x64", + "compilerArgs": [ + "" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..441df560c7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C/C++ Runner: Debug Session", + "type": "lldb", + "request": "launch", + "args": [], + "cwd": "/Users/xiangwei/Desktop/theweakgod/lua-nginx-module/src", + "program": "/Users/xiangwei/Desktop/theweakgod/lua-nginx-module/src/build/Debug/outDebug" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..f32bf6dadd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,74 @@ +{ + "C_Cpp_Runner.cCompilerPath": "clang", + "C_Cpp_Runner.cppCompilerPath": "clang++", + "C_Cpp_Runner.debuggerPath": "lldb", + "C_Cpp_Runner.cStandard": "", + "C_Cpp_Runner.cppStandard": "", + "C_Cpp_Runner.msvcBatchPath": "", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": false, + "files.associations": { + "*.lua": "lua", + "__hash_table": "c", + "__split_buffer": "c", + "array": "c", + "bitset": "c", + "deque": "c", + "initializer_list": "c", + "queue": "c", + "stack": "c", + "string": "c", + "string_view": "c", + "unordered_map": "c", + "vector": "c" + } +} \ No newline at end of file diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index e0ee69051d..4c555d450d 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -1754,4 +1754,53 @@ ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r, } +int +ngx_http_lua_ffi_ssl_server_random(ngx_http_request_t *r, + unsigned char *out, size_t *outlen, 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; + } + + *outlen = SSL_get_server_random(ssl_conn, out, *outlen); + + return NGX_OK; +} + +int +ngx_http_lua_ffi_ssl_session_master_key(ngx_http_request_t *r, + unsigned char *out, size_t *outlen, char **err) +{ + ngx_ssl_conn_t *ssl_conn; + SSL_SESSION *sess; + + 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; + } + + sess = SSL_get0_session(ssl_conn); + + + *outlen = SSL_SESSION_get_master_key(sess, out, *outlen); + + return NGX_OK; +} + + #endif /* NGX_HTTP_SSL */ diff --git a/src/ngx_http_lua_ssl_certby.c.orig b/src/ngx_http_lua_ssl_certby.c.orig new file mode 100644 index 0000000000..0901f06eab --- /dev/null +++ b/src/ngx_http_lua_ssl_certby.c.orig @@ -0,0 +1,1657 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#if (NGX_HTTP_SSL) + + +#include "ngx_http_lua_cache.h" +#include "ngx_http_lua_initworkerby.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_ssl_module.h" +#include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_ssl_certby.h" +#include "ngx_http_lua_directive.h" +#include "ngx_http_lua_ssl.h" + + +enum { + NGX_HTTP_LUA_ADDR_TYPE_UNIX = 0, + NGX_HTTP_LUA_ADDR_TYPE_INET = 1, + NGX_HTTP_LUA_ADDR_TYPE_INET6 = 2, +}; + + +static void ngx_http_lua_ssl_cert_done(void *data); +static void ngx_http_lua_ssl_cert_aborted(void *data); +static u_char *ngx_http_lua_log_ssl_cert_error(ngx_log_t *log, u_char *buf, + size_t len); +static ngx_int_t ngx_http_lua_ssl_cert_by_chunk(lua_State *L, + ngx_http_request_t *r); + + +ngx_int_t +ngx_http_lua_ssl_cert_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, + lscf->srv.ssl_cert_src.data, + &lscf->srv.ssl_cert_src_ref, + lscf->srv.ssl_cert_src_key); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_cert_by_chunk(L, r); +} + + +ngx_int_t +ngx_http_lua_ssl_cert_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + lscf->srv.ssl_cert_src.data, + lscf->srv.ssl_cert_src.len, + &lscf->srv.ssl_cert_src_ref, + lscf->srv.ssl_cert_src_key, + (const char *) + lscf->srv.ssl_cert_chunkname); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_cert_by_chunk(L, r); +} + + +char * +ngx_http_lua_ssl_cert_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_ssl_cert_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + +char * +ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ +#if OPENSSL_VERSION_NUMBER < 0x1000205fL + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "at least OpenSSL 1.0.2e required but found " + OPENSSL_VERSION_TEXT); + + return NGX_CONF_ERROR; + +#else + + size_t chunkname_len; + u_char *chunkname; + u_char *cache_key = NULL; + u_char *name; + ngx_str_t *value; + ngx_http_lua_srv_conf_t *lscf = conf; + + /* must specify a concrete handler */ + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } + + if (lscf->srv.ssl_cert_handler) { + return "is duplicate"; + } + + if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + lscf->srv.ssl_cert_handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_ssl_cert_handler_file) { + /* Lua code in an external file */ + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, + value[1].len); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + cache_key = ngx_http_lua_gen_file_cache_key(cf, value[1].data, + value[1].len); + if (cache_key == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_cert_src.data = name; + lscf->srv.ssl_cert_src.len = ngx_strlen(name); + + } else { + cache_key = ngx_http_lua_gen_chunk_cache_key(cf, + "ssl_certificate_by_lua", + value[1].data, + value[1].len); + if (cache_key == NULL) { + return NGX_CONF_ERROR; + } + + chunkname = ngx_http_lua_gen_chunk_name(cf, "ssl_certificate_by_lua", + sizeof("ssl_certificate_by_lua") - 1, &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + /* Don't eval nginx variables for inline lua code */ + lscf->srv.ssl_cert_src = value[1]; + lscf->srv.ssl_cert_chunkname = chunkname; + } + + lscf->srv.ssl_cert_src_key = cache_key; + + return NGX_CONF_OK; + +#endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +} + + +int +ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) +{ + lua_State *L; + ngx_int_t rc; + ngx_connection_t *c, *fc; + ngx_http_request_t *r = NULL; + ngx_pool_cleanup_t *cln; + ngx_http_connection_t *hc; + ngx_http_lua_srv_conf_t *lscf; + ngx_http_core_loc_conf_t *clcf; + ngx_http_lua_ssl_ctx_t *cctx; + ngx_http_core_srv_conf_t *cscf; + + c = ngx_ssl_get_connection(ssl_conn); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl cert: connection reusable: %ud", c->reusable); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + + dd("ssl cert handler, cert-ctx=%p", cctx); + + if (cctx && cctx->entered_cert_handler) { + /* not the first time */ + + if (cctx->done) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua_certificate_by_lua: cert cb exit code: %d", + cctx->exit_code); + + dd("lua ssl cert done, finally"); + return cctx->exit_code; + } + + return -1; + } + + dd("first time"); + +#if (nginx_version < 1017009) + ngx_reusable_connection(c, 0); +#endif + + hc = c->data; + + fc = ngx_http_lua_create_fake_connection(NULL); + if (fc == NULL) { + goto failed; + } + + fc->log->handler = ngx_http_lua_log_ssl_cert_error; + fc->log->data = fc; + + fc->addr_text = c->addr_text; + fc->listening = c->listening; + + r = ngx_http_lua_create_fake_request(fc); + if (r == NULL) { + goto failed; + } + + r->main_conf = hc->conf_ctx->main_conf; + r->srv_conf = hc->conf_ctx->srv_conf; + r->loc_conf = hc->conf_ctx->loc_conf; + + fc->log->file = c->log->file; + fc->log->log_level = c->log->log_level; + fc->ssl = c->ssl; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + +#if (nginx_version >= 1009000) + ngx_set_connection_log(fc, clcf->error_log); + +#else + ngx_http_set_connection_log(fc, clcf->error_log); +#endif + + if (cctx == NULL) { + cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t)); + if (cctx == NULL) { + goto failed; /* error */ + } + + cctx->ctx_ref = LUA_NOREF; + } + + cctx->exit_code = 1; /* successful by default */ + cctx->connection = c; + cctx->request = r; + cctx->entered_cert_handler = 1; + cctx->done = 0; + + dd("setting cctx"); + + if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, cctx) + == 0) + { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed"); + goto failed; + } + + lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module); + + /* TODO honor lua_code_cache off */ + L = ngx_http_lua_get_lua_vm(r, NULL); + + c->log->action = "loading SSL certificate by lua"; + + if (lscf->srv.ssl_cert_handler == NULL) { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "no ssl_certificate_by_lua* defined in " + "server %V", &cscf->server_name); + + goto failed; + } + + rc = lscf->srv.ssl_cert_handler(r, lscf, L); + + if (rc >= NGX_OK || rc == NGX_ERROR) { + cctx->done = 1; + + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua_certificate_by_lua: handler return value: %i, " + "cert cb exit code: %d", rc, cctx->exit_code); + + c->log->action = "SSL handshaking"; + return cctx->exit_code; + } + + /* rc == NGX_DONE */ + + cln = ngx_pool_cleanup_add(fc->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->handler = ngx_http_lua_ssl_cert_done; + cln->data = cctx; + + if (cctx->cleanup == NULL) { + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->data = cctx; + cctx->cleanup = &cln->handler; + } + + *cctx->cleanup = ngx_http_lua_ssl_cert_aborted; + + return -1; + +#if 1 +failed: + + if (r && r->pool) { + ngx_http_lua_free_fake_request(r); + } + + if (fc) { + ngx_http_lua_close_fake_connection(fc); + } + + return 0; +#endif +} + + +static void +ngx_http_lua_ssl_cert_done(void *data) +{ + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx = data; + + dd("lua ssl cert done"); + + if (cctx->aborted) { + return; + } + + ngx_http_lua_assert(cctx->done == 0); + + cctx->done = 1; + + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + + c = cctx->connection; + + c->log->action = "SSL handshaking"; + + ngx_post_event(c->write, &ngx_posted_events); +} + + +static void +ngx_http_lua_ssl_cert_aborted(void *data) +{ + ngx_http_lua_ssl_ctx_t *cctx = data; + + dd("lua ssl cert done"); + + if (cctx->done) { + /* completed successfully already */ + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cctx->connection->log, 0, + "lua_certificate_by_lua: cert cb aborted"); + + cctx->aborted = 1; + cctx->request->connection->ssl = NULL; + + ngx_http_lua_finalize_fake_request(cctx->request, NGX_ERROR); +} + + +static u_char * +ngx_http_lua_log_ssl_cert_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_connection_t *c; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + buf = p; + } + + p = ngx_snprintf(buf, len, ", context: ssl_certificate_by_lua*"); + len -= p - buf; + buf = p; + + c = log->data; + + if (c && c->addr_text.len) { + p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text); + len -= p - buf; + buf = p; + } + + if (c && c->listening && c->listening->addr_text.len) { + p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text); + /* len -= p - buf; */ + buf = p; + } + + return buf; +} + + +static ngx_int_t +ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) +{ + int co_ref; + ngx_int_t rc; + lua_State *co; + ngx_http_lua_ctx_t *ctx; + ngx_pool_cleanup_t *cln; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; + } + + } else { + dd("reset ctx"); + ngx_http_lua_reset_ctx(r, L, ctx); + } + + ctx->entered_content_phase = 1; + + /* {{{ new coroutine to handle request */ + co = ngx_http_lua_new_thread(r, L, &co_ref); + + if (co == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua: failed to create new coroutine to handle request"); + + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; + } + + /* move code closure to new coroutine */ + lua_xmove(L, co, 1); + +#ifndef OPENRESTY_LUAJIT + /* set closure's env table to new coroutine's globals table */ + ngx_http_lua_get_globals_table(co); + lua_setfenv(co, -2); +#endif + + /* save nginx request in coroutine globals table */ + ngx_http_lua_set_req(co, r); + + ctx->cur_co_ctx = &ctx->entry_co_ctx; + ctx->cur_co_ctx->co = co; + ctx->cur_co_ctx->co_ref = co_ref; +#ifdef NGX_LUA_USE_ASSERT + ctx->cur_co_ctx->co_top = 1; +#endif + + ngx_http_lua_attach_co_ctx_to_L(co, ctx->cur_co_ctx); + + /* register request cleanup hooks */ + if (ctx->cleanup == NULL) { + cln = ngx_pool_cleanup_add(r->pool, 0); + if (cln == NULL) { + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; + } + + cln->handler = ngx_http_lua_request_cleanup_handler; + cln->data = ctx; + ctx->cleanup = &cln->handler; + } + + ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_CERT; + + rc = ngx_http_lua_run_thread(L, r, ctx, 0); + + if (rc == NGX_ERROR || rc >= NGX_OK) { + /* do nothing */ + + } else if (rc == NGX_AGAIN) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); + + } else if (rc == NGX_DONE) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); + + } else { + rc = NGX_OK; + } + + ngx_http_lua_finalize_request(r, rc); + return rc; +} + + +int +ngx_http_lua_ffi_ssl_get_tls1_version(ngx_http_request_t *r, 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; + } + + dd("tls1 ver: %d", SSL_version(ssl_conn)); + + return SSL_version(ssl_conn); +} + + +int +ngx_http_lua_ffi_ssl_clear_certs(ngx_http_request_t *r, char **err) +{ +#ifdef LIBRESSL_VERSION_NUMBER + + *err = "LibreSSL not supported"; + return NGX_ERROR; + +#else + +# if OPENSSL_VERSION_NUMBER < 0x1000205fL + + *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; + return NGX_ERROR; + +# else + + 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; + } + + SSL_certs_clear(ssl_conn); + return NGX_OK; + +# endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +#endif +} + + +int +ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r, + const char *data, size_t len, char **err) +{ +#ifdef LIBRESSL_VERSION_NUMBER + + *err = "LibreSSL not supported"; + return NGX_ERROR; + +#else + +# if OPENSSL_VERSION_NUMBER < 0x1000205fL + + *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; + return NGX_ERROR; + +# else + + BIO *bio = NULL; + X509 *x509 = NULL; + 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; + } + + bio = BIO_new_mem_buf((char *) data, len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + goto failed; + } + + x509 = d2i_X509_bio(bio, NULL); + if (x509 == NULL) { + *err = "d2i_X509_bio() failed"; + goto failed; + } + + if (SSL_use_certificate(ssl_conn, x509) == 0) { + *err = "SSL_use_certificate() failed"; + goto failed; + } + +#if 0 + if (SSL_set_ex_data(ssl_conn, ngx_ssl_certificate_index, x509) == 0) { + *err = "SSL_set_ex_data() failed"; + goto failed; + } +#endif + + X509_free(x509); + x509 = NULL; + + /* read rest of the chain */ + + while (!BIO_eof(bio)) { + + x509 = d2i_X509_bio(bio, NULL); + if (x509 == NULL) { + *err = "d2i_X509_bio() failed"; + goto failed; + } + + if (SSL_add0_chain_cert(ssl_conn, x509) == 0) { + *err = "SSL_add0_chain_cert() failed"; + goto failed; + } + } + + BIO_free(bio); + + *err = NULL; + return NGX_OK; + +failed: + + if (bio) { + BIO_free(bio); + } + + if (x509) { + X509_free(x509); + } + + ERR_clear_error(); + + return NGX_ERROR; + +# endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +#endif +} + + +int +ngx_http_lua_ffi_ssl_set_der_private_key(ngx_http_request_t *r, + const char *data, size_t len, char **err) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + 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; + } + + bio = BIO_new_mem_buf((char *) data, len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + goto failed; + } + + pkey = d2i_PrivateKey_bio(bio, NULL); + if (pkey == NULL) { + *err = "d2i_PrivateKey_bio() failed"; + goto failed; + } + + if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) { + *err = "SSL_use_PrivateKey() failed"; + goto failed; + } + + EVP_PKEY_free(pkey); + BIO_free(bio); + + return NGX_OK; + +failed: + + if (pkey) { + EVP_PKEY_free(pkey); + } + + if (bio) { + BIO_free(bio); + } + + ERR_clear_error(); + + return NGX_ERROR; +} + + +int +ngx_http_lua_ffi_ssl_raw_server_addr(ngx_http_request_t *r, char **addr, + size_t *addrlen, int *addrtype, char **err) +{ +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un *saun; +#endif + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + 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; + } + + c = ngx_ssl_get_connection(ssl_conn); + + if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { + return 0; + } + + switch (c->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->local_sockaddr; + *addrlen = 16; + *addr = (char *) &sin6->sin6_addr.s6_addr; + *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET6; + + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + saun = (struct sockaddr_un *) c->local_sockaddr; + + /* on Linux sockaddr might not include sun_path at all */ + if (c->local_socklen <= (socklen_t) + offsetof(struct sockaddr_un, sun_path)) + { + *addr = ""; + *addrlen = 0; + + } else { + *addr = saun->sun_path; + *addrlen = ngx_strlen(saun->sun_path); + } + + *addrtype = NGX_HTTP_LUA_ADDR_TYPE_UNIX; + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->local_sockaddr; + *addr = (char *) &sin->sin_addr.s_addr; + *addrlen = 4; + *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET; + break; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_ssl_server_name(ngx_http_request_t *r, char **name, + size_t *namelen, 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; + } + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + + *name = (char *) SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); + + if (*name) { + *namelen = ngx_strlen(*name); + return NGX_OK; + } + + return NGX_DECLINED; + +#else + + *err = "no TLS extension support"; + return NGX_ERROR; + +#endif +} + + +int +ngx_http_lua_ffi_ssl_server_port(ngx_http_request_t *r, + unsigned short *server_port, char **err) +{ + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + + 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; + } + + c = ngx_ssl_get_connection(ssl_conn); + + switch (c->local_sockaddr->sa_family) { + + case AF_UNIX: + *err = "unix domain has no port"; + return NGX_ERROR; + + default: + *server_port = (unsigned short) ngx_inet_get_port(c->local_sockaddr); + return NGX_OK; + } +} + + +int +ngx_http_lua_ffi_ssl_raw_client_addr(ngx_http_request_t *r, char **addr, + size_t *addrlen, int *addrtype, char **err) +{ +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un *saun; +#endif + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + 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; + } + + c = ngx_ssl_get_connection(ssl_conn); + + switch (c->sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->sockaddr; + *addrlen = 16; + *addr = (char *) &sin6->sin6_addr.s6_addr; + *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET6; + + break; +#endif + +# if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + saun = (struct sockaddr_un *)c->sockaddr; + /* on Linux sockaddr might not include sun_path at all */ + if (c->socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)) { + *addr = ""; + *addrlen = 0; + + } else { + *addr = saun->sun_path; + *addrlen = ngx_strlen(saun->sun_path); + } + + *addrtype = NGX_HTTP_LUA_ADDR_TYPE_UNIX; + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->sockaddr; + *addr = (char *) &sin->sin_addr.s_addr; + *addrlen = 4; + *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET; + break; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der, + char **err) +{ + int total, len; + BIO *bio; + X509 *x509; + u_long n; + + bio = BIO_new_mem_buf((char *) pem, (int) pem_len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); + return NGX_ERROR; + } + + x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); + if (x509 == NULL) { + *err = "PEM_read_bio_X509_AUX() failed"; + BIO_free(bio); + ERR_clear_error(); + return NGX_ERROR; + } + + total = i2d_X509(x509, &der); + if (total < 0) { + *err = "i2d_X509() failed"; + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NGX_ERROR; + } + + X509_free(x509); + + /* read rest of the chain */ + + for ( ;; ) { + + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + if (x509 == NULL) { + n = ERR_peek_last_error(); + + if (ERR_GET_LIB(n) == ERR_LIB_PEM + && ERR_GET_REASON(n) == PEM_R_NO_START_LINE) + { + /* end of file */ + ERR_clear_error(); + break; + } + + /* some real error */ + + *err = "PEM_read_bio_X509() failed"; + BIO_free(bio); + ERR_clear_error(); + return NGX_ERROR; + } + + len = i2d_X509(x509, &der); + if (len < 0) { + *err = "i2d_X509() failed"; + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NGX_ERROR; + } + + total += len; + + X509_free(x509); + } + + BIO_free(bio); + + return total; +} + + +int +ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, + const u_char *passphrase, u_char *der, char **err) +{ + int len; + BIO *in; + EVP_PKEY *pkey; + + in = BIO_new_mem_buf((char *) pem, (int) pem_len); + if (in == NULL) { + *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); + return NGX_ERROR; + } + + pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, (void *) passphrase); + if (pkey == NULL) { + BIO_free(in); + *err = "PEM_read_bio_PrivateKey() failed"; + ERR_clear_error(); + return NGX_ERROR; + } + + BIO_free(in); + + len = i2d_PrivateKey(pkey, &der); + if (len < 0) { + EVP_PKEY_free(pkey); + *err = "i2d_PrivateKey() failed"; + ERR_clear_error(); + return NGX_ERROR; + } + + EVP_PKEY_free(pkey); + + return len; +} + + +void * +ngx_http_lua_ffi_parse_pem_cert(const u_char *pem, size_t pem_len, + char **err) +{ + BIO *bio; + X509 *x509; + u_long n; + STACK_OF(X509) *chain; + + bio = BIO_new_mem_buf((char *) pem, (int) pem_len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); + return NULL; + } + + x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); + if (x509 == NULL) { + *err = "PEM_read_bio_X509_AUX() failed"; + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + chain = sk_X509_new_null(); + if (chain == NULL) { + *err = "sk_X509_new_null() failed"; + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + if (sk_X509_push(chain, x509) == 0) { + *err = "sk_X509_push() failed"; + sk_X509_free(chain); + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + /* read rest of the chain */ + + for ( ;; ) { + + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + if (x509 == NULL) { + n = ERR_peek_last_error(); + + if (ERR_GET_LIB(n) == ERR_LIB_PEM + && ERR_GET_REASON(n) == PEM_R_NO_START_LINE) + { + /* end of file */ + ERR_clear_error(); + break; + } + + /* some real error */ + + *err = "PEM_read_bio_X509() failed"; + sk_X509_pop_free(chain, X509_free); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + if (sk_X509_push(chain, x509) == 0) { + *err = "sk_X509_push() failed"; + sk_X509_pop_free(chain, X509_free); + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + } + + BIO_free(bio); + + return chain; +} + + +void * +ngx_http_lua_ffi_parse_der_cert(const char *data, size_t len, + char **err) +{ + BIO *bio; + X509 *x509; + STACK_OF(X509) *chain; + + if (data == NULL || len == 0) { + *err = "invalid argument"; + ERR_clear_error(); + return NULL; + } + + bio = BIO_new_mem_buf((char *) data, len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); + return NULL; + } + + x509 = d2i_X509_bio(bio, NULL); + if (x509 == NULL) { + *err = "d2i_X509_bio() failed"; + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + chain = sk_X509_new_null(); + if (chain == NULL) { + *err = "sk_X509_new_null() failed"; + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + if (sk_X509_push(chain, x509) == 0) { + *err = "sk_X509_push() failed"; + sk_X509_free(chain); + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + /* read rest of the chain */ + + while (!BIO_eof(bio)) { + x509 = d2i_X509_bio(bio, NULL); + if (x509 == NULL) { + *err = "d2i_X509_bio() failed in rest of chain"; + sk_X509_pop_free(chain, X509_free); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + if (sk_X509_push(chain, x509) == 0) { + *err = "sk_X509_push() failed in rest of chain"; + sk_X509_pop_free(chain, X509_free); + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + } + + BIO_free(bio); + + return chain; +} + + +void +ngx_http_lua_ffi_free_cert(void *cdata) +{ + STACK_OF(X509) *chain = cdata; + + sk_X509_pop_free(chain, X509_free); +} + + +void * +ngx_http_lua_ffi_parse_pem_priv_key(const u_char *pem, size_t pem_len, + char **err) +{ + BIO *in; + EVP_PKEY *pkey; + + in = BIO_new_mem_buf((char *) pem, (int) pem_len); + if (in == NULL) { + *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); + return NULL; + } + + pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + if (pkey == NULL) { + *err = "PEM_read_bio_PrivateKey() failed"; + BIO_free(in); + ERR_clear_error(); + return NULL; + } + + BIO_free(in); + + return pkey; +} + + +void * +ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len, + char **err) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + + if (data == NULL || len == 0) { + *err = "invalid argument"; + ERR_clear_error(); + return NULL; + } + + bio = BIO_new_mem_buf((char *) data, len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); + return NULL; + } + + pkey = d2i_PrivateKey_bio(bio, NULL); + if (pkey == NULL) { + *err = "d2i_PrivateKey_bio() failed"; + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + BIO_free(bio); + + return pkey; +} + + +void +ngx_http_lua_ffi_free_priv_key(void *cdata) +{ + EVP_PKEY *pkey = cdata; + + EVP_PKEY_free(pkey); +} + + +int +ngx_http_lua_ffi_set_cert(ngx_http_request_t *r, + void *cdata, char **err) +{ +#ifdef LIBRESSL_VERSION_NUMBER + + *err = "LibreSSL not supported"; + return NGX_ERROR; + +#else + +# if OPENSSL_VERSION_NUMBER < 0x1000205fL + + *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; + return NGX_ERROR; + +# else + +#ifdef OPENSSL_IS_BORINGSSL + size_t i; +#else + int i; +#endif + X509 *x509 = NULL; + ngx_ssl_conn_t *ssl_conn; + STACK_OF(X509) *chain = cdata; + + 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 (sk_X509_num(chain) < 1) { + *err = "invalid certificate chain"; + goto failed; + } + + x509 = sk_X509_value(chain, 0); + if (x509 == NULL) { + *err = "sk_X509_value() failed"; + goto failed; + } + + if (SSL_use_certificate(ssl_conn, x509) == 0) { + *err = "SSL_use_certificate() failed"; + goto failed; + } + + x509 = NULL; + + /* read rest of the chain */ + + for (i = 1; i < sk_X509_num(chain); i++) { + + x509 = sk_X509_value(chain, i); + if (x509 == NULL) { + *err = "sk_X509_value() failed"; + goto failed; + } + + if (SSL_add1_chain_cert(ssl_conn, x509) == 0) { + *err = "SSL_add1_chain_cert() failed"; + goto failed; + } + } + + *err = NULL; + return NGX_OK; + +failed: + + ERR_clear_error(); + + return NGX_ERROR; + +# endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +#endif +} + + +int +ngx_http_lua_ffi_set_priv_key(ngx_http_request_t *r, + void *cdata, char **err) +{ + EVP_PKEY *pkey = NULL; + 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; + } + + pkey = cdata; + if (pkey == NULL) { + *err = "invalid private key failed"; + goto failed; + } + + if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) { + *err = "SSL_use_PrivateKey() failed"; + goto failed; + } + + return NGX_OK; + +failed: + + ERR_clear_error(); + + return NGX_ERROR; +} + + +#ifndef LIBRESSL_VERSION_NUMBER +static int +ngx_http_lua_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) +{ + /* + * we never terminate handshake here and user can later use + * $ssl_client_verify to check verification result. + * + * this is consistent with Nginx behavior. + */ + return 1; +} +#endif + + +int +ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *client_certs, + void *trusted_certs, int depth, char **err) +{ +#ifdef LIBRESSL_VERSION_NUMBER + + *err = "LibreSSL not supported"; + return NGX_ERROR; + +#else + + ngx_http_lua_ctx_t *ctx; + ngx_ssl_conn_t *ssl_conn; + ngx_http_ssl_srv_conf_t *sscf; + STACK_OF(X509) *client_chain = client_certs; + STACK_OF(X509) *trusted_chain = trusted_certs; + STACK_OF(X509_NAME) *name_chain = NULL; + X509 *x509 = NULL; + X509_NAME *subject = NULL; + X509_STORE *ca_store = NULL; +#ifdef OPENSSL_IS_BORINGSSL + size_t i; +#else + int i; +#endif + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + *err = "no request ctx found"; + return NGX_ERROR; + } + + if (!(ctx->context & NGX_HTTP_LUA_CONTEXT_SSL_CERT)) { + *err = "API disabled in the current context"; + return NGX_ERROR; + } + + 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; + } + + /* enable verify */ + + SSL_set_verify(ssl_conn, SSL_VERIFY_PEER, ngx_http_lua_ssl_verify_callback); + + /* set depth */ + + if (depth < 0) { + sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); + if (sscf != NULL) { + depth = sscf->verify_depth; + + } else { + /* same as the default value of ssl_verify_depth */ + depth = 1; + } + } + + SSL_set_verify_depth(ssl_conn, depth); + + /* set CA chain */ + + if (client_chain != NULL || trusted_chain != NULL) { + + ca_store = X509_STORE_new(); + if (ca_store == NULL) { + *err = "X509_STORE_new() failed"; + return NGX_ERROR; + } + + if (client_chain != NULL) { + + /* construct name chain */ + name_chain = sk_X509_NAME_new_null(); + if (name_chain == NULL) { + *err = "sk_X509_NAME_new_null() failed"; + goto failed; + } + + for (i = 0; i < sk_X509_num(client_chain); i++) { + x509 = sk_X509_value(client_chain, i); + if (x509 == NULL) { + *err = "sk_X509_value() failed"; + goto failed; + } + + /* add subject to name chain, which will be sent to client */ + subject = X509_NAME_dup(X509_get_subject_name(x509)); + if (subject == NULL) { + *err = "X509_get_subject_name() failed"; + goto failed; + } + + if (!sk_X509_NAME_push(name_chain, subject)) { + *err = "sk_X509_NAME_push() failed"; + X509_NAME_free(subject); + goto failed; + } + + /* add to trusted CA store */ + if (X509_STORE_add_cert(ca_store, x509) == 0) { + *err = "X509_STORE_add_cert() failed"; + goto failed; + } + } + + /* clean subject name list, and set it for send to client */ + SSL_set_client_CA_list(ssl_conn, name_chain); + } + + if (trusted_chain != NULL) { + for (i = 0; i < sk_X509_num(trusted_chain); i++) { + x509 = sk_X509_value(trusted_chain, i); + if (x509 == NULL) { + *err = "sk_X509_value() failed"; + goto failed; + } + + /* add to trusted CA store */ + if (X509_STORE_add_cert(ca_store, x509) == 0) { + *err = "X509_STORE_add_cert() failed"; + goto failed; + } + } + } + + /* clean ca_store, and store new ca_store */ + if (SSL_set0_verify_cert_store(ssl_conn, ca_store) == 0) { + *err = "SSL_set0_verify_cert_store() failed"; + goto failed; + } + } + + return NGX_OK; + +failed: + + sk_X509_NAME_free(name_chain); + + X509_STORE_free(ca_store); + + return NGX_ERROR; +#endif +} + + +ngx_ssl_conn_t * +ngx_http_lua_ffi_get_req_ssl_pointer(ngx_http_request_t *r) +{ + if (r->connection == NULL || r->connection->ssl == NULL) { + return NULL; + } + + return r->connection->ssl->connection; +} + + +int +ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r, + unsigned char *out, size_t *outlen, 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; + } + + *outlen = SSL_get_client_random(ssl_conn, out, *outlen); + + return NGX_OK; +} + + +#endif /* NGX_HTTP_SSL */ From 3fd83ee7dab40fdfcf147e7d2331275a991b4943 Mon Sep 17 00:00:00 2001 From: theweakgod <1031205858@qq.com> Date: Tue, 17 Mar 2026 16:42:41 +0800 Subject: [PATCH 2/2] feat: add server random and master key fetch api --- .vscode/c_cpp_properties.json | 18 - .vscode/launch.json | 13 - .vscode/settings.json | 74 -- src/ngx_http_lua_ssl_certby.c | 1 + src/ngx_http_lua_ssl_certby.c.orig | 1657 ---------------------------- 5 files changed, 1 insertion(+), 1762 deletions(-) delete mode 100644 .vscode/c_cpp_properties.json delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json delete mode 100644 src/ngx_http_lua_ssl_certby.c.orig diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index 9b8a691b01..0000000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "configurations": [ - { - "name": "macos-clang-x64", - "includePath": [ - "${workspaceFolder}/**" - ], - "compilerPath": "/usr/local/opt/llvm/bin/clang", - "cStandard": "${default}", - "cppStandard": "${default}", - "intelliSenseMode": "macos-clang-x64", - "compilerArgs": [ - "" - ] - } - ], - "version": 4 -} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 441df560c7..0000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "C/C++ Runner: Debug Session", - "type": "lldb", - "request": "launch", - "args": [], - "cwd": "/Users/xiangwei/Desktop/theweakgod/lua-nginx-module/src", - "program": "/Users/xiangwei/Desktop/theweakgod/lua-nginx-module/src/build/Debug/outDebug" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index f32bf6dadd..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "C_Cpp_Runner.cCompilerPath": "clang", - "C_Cpp_Runner.cppCompilerPath": "clang++", - "C_Cpp_Runner.debuggerPath": "lldb", - "C_Cpp_Runner.cStandard": "", - "C_Cpp_Runner.cppStandard": "", - "C_Cpp_Runner.msvcBatchPath": "", - "C_Cpp_Runner.useMsvc": false, - "C_Cpp_Runner.warnings": [ - "-Wall", - "-Wextra", - "-Wpedantic", - "-Wshadow", - "-Wformat=2", - "-Wcast-align", - "-Wconversion", - "-Wsign-conversion", - "-Wnull-dereference" - ], - "C_Cpp_Runner.msvcWarnings": [ - "/W4", - "/permissive-", - "/w14242", - "/w14287", - "/w14296", - "/w14311", - "/w14826", - "/w44062", - "/w44242", - "/w14905", - "/w14906", - "/w14263", - "/w44265", - "/w14928" - ], - "C_Cpp_Runner.enableWarnings": true, - "C_Cpp_Runner.warningsAsError": false, - "C_Cpp_Runner.compilerArgs": [], - "C_Cpp_Runner.linkerArgs": [], - "C_Cpp_Runner.includePaths": [], - "C_Cpp_Runner.includeSearch": [ - "*", - "**/*" - ], - "C_Cpp_Runner.excludeSearch": [ - "**/build", - "**/build/**", - "**/.*", - "**/.*/**", - "**/.vscode", - "**/.vscode/**" - ], - "C_Cpp_Runner.useAddressSanitizer": false, - "C_Cpp_Runner.useUndefinedSanitizer": false, - "C_Cpp_Runner.useLeakSanitizer": false, - "C_Cpp_Runner.showCompilationTime": false, - "C_Cpp_Runner.useLinkTimeOptimization": false, - "C_Cpp_Runner.msvcSecureNoWarnings": false, - "files.associations": { - "*.lua": "lua", - "__hash_table": "c", - "__split_buffer": "c", - "array": "c", - "bitset": "c", - "deque": "c", - "initializer_list": "c", - "queue": "c", - "stack": "c", - "string": "c", - "string_view": "c", - "unordered_map": "c", - "vector": "c" - } -} \ No newline at end of file diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 4c555d450d..ac2bd9a168 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -1776,6 +1776,7 @@ ngx_http_lua_ffi_ssl_server_random(ngx_http_request_t *r, return NGX_OK; } + int ngx_http_lua_ffi_ssl_session_master_key(ngx_http_request_t *r, unsigned char *out, size_t *outlen, char **err) diff --git a/src/ngx_http_lua_ssl_certby.c.orig b/src/ngx_http_lua_ssl_certby.c.orig deleted file mode 100644 index 0901f06eab..0000000000 --- a/src/ngx_http_lua_ssl_certby.c.orig +++ /dev/null @@ -1,1657 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#if (NGX_HTTP_SSL) - - -#include "ngx_http_lua_cache.h" -#include "ngx_http_lua_initworkerby.h" -#include "ngx_http_lua_util.h" -#include "ngx_http_ssl_module.h" -#include "ngx_http_lua_contentby.h" -#include "ngx_http_lua_ssl_certby.h" -#include "ngx_http_lua_directive.h" -#include "ngx_http_lua_ssl.h" - - -enum { - NGX_HTTP_LUA_ADDR_TYPE_UNIX = 0, - NGX_HTTP_LUA_ADDR_TYPE_INET = 1, - NGX_HTTP_LUA_ADDR_TYPE_INET6 = 2, -}; - - -static void ngx_http_lua_ssl_cert_done(void *data); -static void ngx_http_lua_ssl_cert_aborted(void *data); -static u_char *ngx_http_lua_log_ssl_cert_error(ngx_log_t *log, u_char *buf, - size_t len); -static ngx_int_t ngx_http_lua_ssl_cert_by_chunk(lua_State *L, - ngx_http_request_t *r); - - -ngx_int_t -ngx_http_lua_ssl_cert_handler_file(ngx_http_request_t *r, - ngx_http_lua_srv_conf_t *lscf, lua_State *L) -{ - ngx_int_t rc; - - rc = ngx_http_lua_cache_loadfile(r->connection->log, L, - lscf->srv.ssl_cert_src.data, - &lscf->srv.ssl_cert_src_ref, - lscf->srv.ssl_cert_src_key); - if (rc != NGX_OK) { - return rc; - } - - /* make sure we have a valid code chunk */ - ngx_http_lua_assert(lua_isfunction(L, -1)); - - return ngx_http_lua_ssl_cert_by_chunk(L, r); -} - - -ngx_int_t -ngx_http_lua_ssl_cert_handler_inline(ngx_http_request_t *r, - ngx_http_lua_srv_conf_t *lscf, lua_State *L) -{ - ngx_int_t rc; - - rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, - lscf->srv.ssl_cert_src.data, - lscf->srv.ssl_cert_src.len, - &lscf->srv.ssl_cert_src_ref, - lscf->srv.ssl_cert_src_key, - (const char *) - lscf->srv.ssl_cert_chunkname); - if (rc != NGX_OK) { - return rc; - } - - /* make sure we have a valid code chunk */ - ngx_http_lua_assert(lua_isfunction(L, -1)); - - return ngx_http_lua_ssl_cert_by_chunk(L, r); -} - - -char * -ngx_http_lua_ssl_cert_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - char *rv; - ngx_conf_t save; - - save = *cf; - cf->handler = ngx_http_lua_ssl_cert_by_lua; - cf->handler_conf = conf; - - rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); - - *cf = save; - - return rv; -} - - -char * -ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ -#if OPENSSL_VERSION_NUMBER < 0x1000205fL - - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "at least OpenSSL 1.0.2e required but found " - OPENSSL_VERSION_TEXT); - - return NGX_CONF_ERROR; - -#else - - size_t chunkname_len; - u_char *chunkname; - u_char *cache_key = NULL; - u_char *name; - ngx_str_t *value; - ngx_http_lua_srv_conf_t *lscf = conf; - - /* must specify a concrete handler */ - if (cmd->post == NULL) { - return NGX_CONF_ERROR; - } - - if (lscf->srv.ssl_cert_handler) { - return "is duplicate"; - } - - if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) { - return NGX_CONF_ERROR; - } - - value = cf->args->elts; - - lscf->srv.ssl_cert_handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post; - - if (cmd->post == ngx_http_lua_ssl_cert_handler_file) { - /* Lua code in an external file */ - name = ngx_http_lua_rebase_path(cf->pool, value[1].data, - value[1].len); - if (name == NULL) { - return NGX_CONF_ERROR; - } - - cache_key = ngx_http_lua_gen_file_cache_key(cf, value[1].data, - value[1].len); - if (cache_key == NULL) { - return NGX_CONF_ERROR; - } - - lscf->srv.ssl_cert_src.data = name; - lscf->srv.ssl_cert_src.len = ngx_strlen(name); - - } else { - cache_key = ngx_http_lua_gen_chunk_cache_key(cf, - "ssl_certificate_by_lua", - value[1].data, - value[1].len); - if (cache_key == NULL) { - return NGX_CONF_ERROR; - } - - chunkname = ngx_http_lua_gen_chunk_name(cf, "ssl_certificate_by_lua", - sizeof("ssl_certificate_by_lua") - 1, &chunkname_len); - if (chunkname == NULL) { - return NGX_CONF_ERROR; - } - - /* Don't eval nginx variables for inline lua code */ - lscf->srv.ssl_cert_src = value[1]; - lscf->srv.ssl_cert_chunkname = chunkname; - } - - lscf->srv.ssl_cert_src_key = cache_key; - - return NGX_CONF_OK; - -#endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ -} - - -int -ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) -{ - lua_State *L; - ngx_int_t rc; - ngx_connection_t *c, *fc; - ngx_http_request_t *r = NULL; - ngx_pool_cleanup_t *cln; - ngx_http_connection_t *hc; - ngx_http_lua_srv_conf_t *lscf; - ngx_http_core_loc_conf_t *clcf; - ngx_http_lua_ssl_ctx_t *cctx; - ngx_http_core_srv_conf_t *cscf; - - c = ngx_ssl_get_connection(ssl_conn); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "ssl cert: connection reusable: %ud", c->reusable); - - cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); - - dd("ssl cert handler, cert-ctx=%p", cctx); - - if (cctx && cctx->entered_cert_handler) { - /* not the first time */ - - if (cctx->done) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua_certificate_by_lua: cert cb exit code: %d", - cctx->exit_code); - - dd("lua ssl cert done, finally"); - return cctx->exit_code; - } - - return -1; - } - - dd("first time"); - -#if (nginx_version < 1017009) - ngx_reusable_connection(c, 0); -#endif - - hc = c->data; - - fc = ngx_http_lua_create_fake_connection(NULL); - if (fc == NULL) { - goto failed; - } - - fc->log->handler = ngx_http_lua_log_ssl_cert_error; - fc->log->data = fc; - - fc->addr_text = c->addr_text; - fc->listening = c->listening; - - r = ngx_http_lua_create_fake_request(fc); - if (r == NULL) { - goto failed; - } - - r->main_conf = hc->conf_ctx->main_conf; - r->srv_conf = hc->conf_ctx->srv_conf; - r->loc_conf = hc->conf_ctx->loc_conf; - - fc->log->file = c->log->file; - fc->log->log_level = c->log->log_level; - fc->ssl = c->ssl; - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - -#if (nginx_version >= 1009000) - ngx_set_connection_log(fc, clcf->error_log); - -#else - ngx_http_set_connection_log(fc, clcf->error_log); -#endif - - if (cctx == NULL) { - cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t)); - if (cctx == NULL) { - goto failed; /* error */ - } - - cctx->ctx_ref = LUA_NOREF; - } - - cctx->exit_code = 1; /* successful by default */ - cctx->connection = c; - cctx->request = r; - cctx->entered_cert_handler = 1; - cctx->done = 0; - - dd("setting cctx"); - - if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, cctx) - == 0) - { - ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed"); - goto failed; - } - - lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module); - - /* TODO honor lua_code_cache off */ - L = ngx_http_lua_get_lua_vm(r, NULL); - - c->log->action = "loading SSL certificate by lua"; - - if (lscf->srv.ssl_cert_handler == NULL) { - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "no ssl_certificate_by_lua* defined in " - "server %V", &cscf->server_name); - - goto failed; - } - - rc = lscf->srv.ssl_cert_handler(r, lscf, L); - - if (rc >= NGX_OK || rc == NGX_ERROR) { - cctx->done = 1; - - if (cctx->cleanup) { - *cctx->cleanup = NULL; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua_certificate_by_lua: handler return value: %i, " - "cert cb exit code: %d", rc, cctx->exit_code); - - c->log->action = "SSL handshaking"; - return cctx->exit_code; - } - - /* rc == NGX_DONE */ - - cln = ngx_pool_cleanup_add(fc->pool, 0); - if (cln == NULL) { - goto failed; - } - - cln->handler = ngx_http_lua_ssl_cert_done; - cln->data = cctx; - - if (cctx->cleanup == NULL) { - cln = ngx_pool_cleanup_add(c->pool, 0); - if (cln == NULL) { - goto failed; - } - - cln->data = cctx; - cctx->cleanup = &cln->handler; - } - - *cctx->cleanup = ngx_http_lua_ssl_cert_aborted; - - return -1; - -#if 1 -failed: - - if (r && r->pool) { - ngx_http_lua_free_fake_request(r); - } - - if (fc) { - ngx_http_lua_close_fake_connection(fc); - } - - return 0; -#endif -} - - -static void -ngx_http_lua_ssl_cert_done(void *data) -{ - ngx_connection_t *c; - ngx_http_lua_ssl_ctx_t *cctx = data; - - dd("lua ssl cert done"); - - if (cctx->aborted) { - return; - } - - ngx_http_lua_assert(cctx->done == 0); - - cctx->done = 1; - - if (cctx->cleanup) { - *cctx->cleanup = NULL; - } - - c = cctx->connection; - - c->log->action = "SSL handshaking"; - - ngx_post_event(c->write, &ngx_posted_events); -} - - -static void -ngx_http_lua_ssl_cert_aborted(void *data) -{ - ngx_http_lua_ssl_ctx_t *cctx = data; - - dd("lua ssl cert done"); - - if (cctx->done) { - /* completed successfully already */ - return; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cctx->connection->log, 0, - "lua_certificate_by_lua: cert cb aborted"); - - cctx->aborted = 1; - cctx->request->connection->ssl = NULL; - - ngx_http_lua_finalize_fake_request(cctx->request, NGX_ERROR); -} - - -static u_char * -ngx_http_lua_log_ssl_cert_error(ngx_log_t *log, u_char *buf, size_t len) -{ - u_char *p; - ngx_connection_t *c; - - if (log->action) { - p = ngx_snprintf(buf, len, " while %s", log->action); - len -= p - buf; - buf = p; - } - - p = ngx_snprintf(buf, len, ", context: ssl_certificate_by_lua*"); - len -= p - buf; - buf = p; - - c = log->data; - - if (c && c->addr_text.len) { - p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text); - len -= p - buf; - buf = p; - } - - if (c && c->listening && c->listening->addr_text.len) { - p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text); - /* len -= p - buf; */ - buf = p; - } - - return buf; -} - - -static ngx_int_t -ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) -{ - int co_ref; - ngx_int_t rc; - lua_State *co; - ngx_http_lua_ctx_t *ctx; - ngx_pool_cleanup_t *cln; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - - if (ctx == NULL) { - ctx = ngx_http_lua_create_ctx(r); - if (ctx == NULL) { - rc = NGX_ERROR; - ngx_http_lua_finalize_request(r, rc); - return rc; - } - - } else { - dd("reset ctx"); - ngx_http_lua_reset_ctx(r, L, ctx); - } - - ctx->entered_content_phase = 1; - - /* {{{ new coroutine to handle request */ - co = ngx_http_lua_new_thread(r, L, &co_ref); - - if (co == NULL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "lua: failed to create new coroutine to handle request"); - - rc = NGX_ERROR; - ngx_http_lua_finalize_request(r, rc); - return rc; - } - - /* move code closure to new coroutine */ - lua_xmove(L, co, 1); - -#ifndef OPENRESTY_LUAJIT - /* set closure's env table to new coroutine's globals table */ - ngx_http_lua_get_globals_table(co); - lua_setfenv(co, -2); -#endif - - /* save nginx request in coroutine globals table */ - ngx_http_lua_set_req(co, r); - - ctx->cur_co_ctx = &ctx->entry_co_ctx; - ctx->cur_co_ctx->co = co; - ctx->cur_co_ctx->co_ref = co_ref; -#ifdef NGX_LUA_USE_ASSERT - ctx->cur_co_ctx->co_top = 1; -#endif - - ngx_http_lua_attach_co_ctx_to_L(co, ctx->cur_co_ctx); - - /* register request cleanup hooks */ - if (ctx->cleanup == NULL) { - cln = ngx_pool_cleanup_add(r->pool, 0); - if (cln == NULL) { - rc = NGX_ERROR; - ngx_http_lua_finalize_request(r, rc); - return rc; - } - - cln->handler = ngx_http_lua_request_cleanup_handler; - cln->data = ctx; - ctx->cleanup = &cln->handler; - } - - ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_CERT; - - rc = ngx_http_lua_run_thread(L, r, ctx, 0); - - if (rc == NGX_ERROR || rc >= NGX_OK) { - /* do nothing */ - - } else if (rc == NGX_AGAIN) { - rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); - - } else if (rc == NGX_DONE) { - rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); - - } else { - rc = NGX_OK; - } - - ngx_http_lua_finalize_request(r, rc); - return rc; -} - - -int -ngx_http_lua_ffi_ssl_get_tls1_version(ngx_http_request_t *r, 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; - } - - dd("tls1 ver: %d", SSL_version(ssl_conn)); - - return SSL_version(ssl_conn); -} - - -int -ngx_http_lua_ffi_ssl_clear_certs(ngx_http_request_t *r, char **err) -{ -#ifdef LIBRESSL_VERSION_NUMBER - - *err = "LibreSSL not supported"; - return NGX_ERROR; - -#else - -# if OPENSSL_VERSION_NUMBER < 0x1000205fL - - *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; - return NGX_ERROR; - -# else - - 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; - } - - SSL_certs_clear(ssl_conn); - return NGX_OK; - -# endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ -#endif -} - - -int -ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r, - const char *data, size_t len, char **err) -{ -#ifdef LIBRESSL_VERSION_NUMBER - - *err = "LibreSSL not supported"; - return NGX_ERROR; - -#else - -# if OPENSSL_VERSION_NUMBER < 0x1000205fL - - *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; - return NGX_ERROR; - -# else - - BIO *bio = NULL; - X509 *x509 = NULL; - 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; - } - - bio = BIO_new_mem_buf((char *) data, len); - if (bio == NULL) { - *err = "BIO_new_mem_buf() failed"; - goto failed; - } - - x509 = d2i_X509_bio(bio, NULL); - if (x509 == NULL) { - *err = "d2i_X509_bio() failed"; - goto failed; - } - - if (SSL_use_certificate(ssl_conn, x509) == 0) { - *err = "SSL_use_certificate() failed"; - goto failed; - } - -#if 0 - if (SSL_set_ex_data(ssl_conn, ngx_ssl_certificate_index, x509) == 0) { - *err = "SSL_set_ex_data() failed"; - goto failed; - } -#endif - - X509_free(x509); - x509 = NULL; - - /* read rest of the chain */ - - while (!BIO_eof(bio)) { - - x509 = d2i_X509_bio(bio, NULL); - if (x509 == NULL) { - *err = "d2i_X509_bio() failed"; - goto failed; - } - - if (SSL_add0_chain_cert(ssl_conn, x509) == 0) { - *err = "SSL_add0_chain_cert() failed"; - goto failed; - } - } - - BIO_free(bio); - - *err = NULL; - return NGX_OK; - -failed: - - if (bio) { - BIO_free(bio); - } - - if (x509) { - X509_free(x509); - } - - ERR_clear_error(); - - return NGX_ERROR; - -# endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ -#endif -} - - -int -ngx_http_lua_ffi_ssl_set_der_private_key(ngx_http_request_t *r, - const char *data, size_t len, char **err) -{ - BIO *bio = NULL; - EVP_PKEY *pkey = NULL; - 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; - } - - bio = BIO_new_mem_buf((char *) data, len); - if (bio == NULL) { - *err = "BIO_new_mem_buf() failed"; - goto failed; - } - - pkey = d2i_PrivateKey_bio(bio, NULL); - if (pkey == NULL) { - *err = "d2i_PrivateKey_bio() failed"; - goto failed; - } - - if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) { - *err = "SSL_use_PrivateKey() failed"; - goto failed; - } - - EVP_PKEY_free(pkey); - BIO_free(bio); - - return NGX_OK; - -failed: - - if (pkey) { - EVP_PKEY_free(pkey); - } - - if (bio) { - BIO_free(bio); - } - - ERR_clear_error(); - - return NGX_ERROR; -} - - -int -ngx_http_lua_ffi_ssl_raw_server_addr(ngx_http_request_t *r, char **addr, - size_t *addrlen, int *addrtype, char **err) -{ -#if (NGX_HAVE_UNIX_DOMAIN) - struct sockaddr_un *saun; -#endif - ngx_ssl_conn_t *ssl_conn; - ngx_connection_t *c; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif - - 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; - } - - c = ngx_ssl_get_connection(ssl_conn); - - if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { - return 0; - } - - switch (c->local_sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) c->local_sockaddr; - *addrlen = 16; - *addr = (char *) &sin6->sin6_addr.s6_addr; - *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET6; - - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - saun = (struct sockaddr_un *) c->local_sockaddr; - - /* on Linux sockaddr might not include sun_path at all */ - if (c->local_socklen <= (socklen_t) - offsetof(struct sockaddr_un, sun_path)) - { - *addr = ""; - *addrlen = 0; - - } else { - *addr = saun->sun_path; - *addrlen = ngx_strlen(saun->sun_path); - } - - *addrtype = NGX_HTTP_LUA_ADDR_TYPE_UNIX; - break; -#endif - - default: /* AF_INET */ - sin = (struct sockaddr_in *) c->local_sockaddr; - *addr = (char *) &sin->sin_addr.s_addr; - *addrlen = 4; - *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET; - break; - } - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_ssl_server_name(ngx_http_request_t *r, char **name, - size_t *namelen, 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; - } - -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - - *name = (char *) SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); - - if (*name) { - *namelen = ngx_strlen(*name); - return NGX_OK; - } - - return NGX_DECLINED; - -#else - - *err = "no TLS extension support"; - return NGX_ERROR; - -#endif -} - - -int -ngx_http_lua_ffi_ssl_server_port(ngx_http_request_t *r, - unsigned short *server_port, char **err) -{ - ngx_ssl_conn_t *ssl_conn; - ngx_connection_t *c; - - 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; - } - - c = ngx_ssl_get_connection(ssl_conn); - - switch (c->local_sockaddr->sa_family) { - - case AF_UNIX: - *err = "unix domain has no port"; - return NGX_ERROR; - - default: - *server_port = (unsigned short) ngx_inet_get_port(c->local_sockaddr); - return NGX_OK; - } -} - - -int -ngx_http_lua_ffi_ssl_raw_client_addr(ngx_http_request_t *r, char **addr, - size_t *addrlen, int *addrtype, char **err) -{ -#if (NGX_HAVE_UNIX_DOMAIN) - struct sockaddr_un *saun; -#endif - ngx_ssl_conn_t *ssl_conn; - ngx_connection_t *c; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif - - 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; - } - - c = ngx_ssl_get_connection(ssl_conn); - - switch (c->sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) c->sockaddr; - *addrlen = 16; - *addr = (char *) &sin6->sin6_addr.s6_addr; - *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET6; - - break; -#endif - -# if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - saun = (struct sockaddr_un *)c->sockaddr; - /* on Linux sockaddr might not include sun_path at all */ - if (c->socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)) { - *addr = ""; - *addrlen = 0; - - } else { - *addr = saun->sun_path; - *addrlen = ngx_strlen(saun->sun_path); - } - - *addrtype = NGX_HTTP_LUA_ADDR_TYPE_UNIX; - break; -#endif - - default: /* AF_INET */ - sin = (struct sockaddr_in *) c->sockaddr; - *addr = (char *) &sin->sin_addr.s_addr; - *addrlen = 4; - *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET; - break; - } - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der, - char **err) -{ - int total, len; - BIO *bio; - X509 *x509; - u_long n; - - bio = BIO_new_mem_buf((char *) pem, (int) pem_len); - if (bio == NULL) { - *err = "BIO_new_mem_buf() failed"; - ERR_clear_error(); - return NGX_ERROR; - } - - x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); - if (x509 == NULL) { - *err = "PEM_read_bio_X509_AUX() failed"; - BIO_free(bio); - ERR_clear_error(); - return NGX_ERROR; - } - - total = i2d_X509(x509, &der); - if (total < 0) { - *err = "i2d_X509() failed"; - X509_free(x509); - BIO_free(bio); - ERR_clear_error(); - return NGX_ERROR; - } - - X509_free(x509); - - /* read rest of the chain */ - - for ( ;; ) { - - x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); - if (x509 == NULL) { - n = ERR_peek_last_error(); - - if (ERR_GET_LIB(n) == ERR_LIB_PEM - && ERR_GET_REASON(n) == PEM_R_NO_START_LINE) - { - /* end of file */ - ERR_clear_error(); - break; - } - - /* some real error */ - - *err = "PEM_read_bio_X509() failed"; - BIO_free(bio); - ERR_clear_error(); - return NGX_ERROR; - } - - len = i2d_X509(x509, &der); - if (len < 0) { - *err = "i2d_X509() failed"; - X509_free(x509); - BIO_free(bio); - ERR_clear_error(); - return NGX_ERROR; - } - - total += len; - - X509_free(x509); - } - - BIO_free(bio); - - return total; -} - - -int -ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, - const u_char *passphrase, u_char *der, char **err) -{ - int len; - BIO *in; - EVP_PKEY *pkey; - - in = BIO_new_mem_buf((char *) pem, (int) pem_len); - if (in == NULL) { - *err = "BIO_new_mem_buf() failed"; - ERR_clear_error(); - return NGX_ERROR; - } - - pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, (void *) passphrase); - if (pkey == NULL) { - BIO_free(in); - *err = "PEM_read_bio_PrivateKey() failed"; - ERR_clear_error(); - return NGX_ERROR; - } - - BIO_free(in); - - len = i2d_PrivateKey(pkey, &der); - if (len < 0) { - EVP_PKEY_free(pkey); - *err = "i2d_PrivateKey() failed"; - ERR_clear_error(); - return NGX_ERROR; - } - - EVP_PKEY_free(pkey); - - return len; -} - - -void * -ngx_http_lua_ffi_parse_pem_cert(const u_char *pem, size_t pem_len, - char **err) -{ - BIO *bio; - X509 *x509; - u_long n; - STACK_OF(X509) *chain; - - bio = BIO_new_mem_buf((char *) pem, (int) pem_len); - if (bio == NULL) { - *err = "BIO_new_mem_buf() failed"; - ERR_clear_error(); - return NULL; - } - - x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); - if (x509 == NULL) { - *err = "PEM_read_bio_X509_AUX() failed"; - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - - chain = sk_X509_new_null(); - if (chain == NULL) { - *err = "sk_X509_new_null() failed"; - X509_free(x509); - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - - if (sk_X509_push(chain, x509) == 0) { - *err = "sk_X509_push() failed"; - sk_X509_free(chain); - X509_free(x509); - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - - /* read rest of the chain */ - - for ( ;; ) { - - x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); - if (x509 == NULL) { - n = ERR_peek_last_error(); - - if (ERR_GET_LIB(n) == ERR_LIB_PEM - && ERR_GET_REASON(n) == PEM_R_NO_START_LINE) - { - /* end of file */ - ERR_clear_error(); - break; - } - - /* some real error */ - - *err = "PEM_read_bio_X509() failed"; - sk_X509_pop_free(chain, X509_free); - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - - if (sk_X509_push(chain, x509) == 0) { - *err = "sk_X509_push() failed"; - sk_X509_pop_free(chain, X509_free); - X509_free(x509); - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - } - - BIO_free(bio); - - return chain; -} - - -void * -ngx_http_lua_ffi_parse_der_cert(const char *data, size_t len, - char **err) -{ - BIO *bio; - X509 *x509; - STACK_OF(X509) *chain; - - if (data == NULL || len == 0) { - *err = "invalid argument"; - ERR_clear_error(); - return NULL; - } - - bio = BIO_new_mem_buf((char *) data, len); - if (bio == NULL) { - *err = "BIO_new_mem_buf() failed"; - ERR_clear_error(); - return NULL; - } - - x509 = d2i_X509_bio(bio, NULL); - if (x509 == NULL) { - *err = "d2i_X509_bio() failed"; - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - - chain = sk_X509_new_null(); - if (chain == NULL) { - *err = "sk_X509_new_null() failed"; - X509_free(x509); - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - - if (sk_X509_push(chain, x509) == 0) { - *err = "sk_X509_push() failed"; - sk_X509_free(chain); - X509_free(x509); - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - - /* read rest of the chain */ - - while (!BIO_eof(bio)) { - x509 = d2i_X509_bio(bio, NULL); - if (x509 == NULL) { - *err = "d2i_X509_bio() failed in rest of chain"; - sk_X509_pop_free(chain, X509_free); - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - - if (sk_X509_push(chain, x509) == 0) { - *err = "sk_X509_push() failed in rest of chain"; - sk_X509_pop_free(chain, X509_free); - X509_free(x509); - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - } - - BIO_free(bio); - - return chain; -} - - -void -ngx_http_lua_ffi_free_cert(void *cdata) -{ - STACK_OF(X509) *chain = cdata; - - sk_X509_pop_free(chain, X509_free); -} - - -void * -ngx_http_lua_ffi_parse_pem_priv_key(const u_char *pem, size_t pem_len, - char **err) -{ - BIO *in; - EVP_PKEY *pkey; - - in = BIO_new_mem_buf((char *) pem, (int) pem_len); - if (in == NULL) { - *err = "BIO_new_mem_buf() failed"; - ERR_clear_error(); - return NULL; - } - - pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); - if (pkey == NULL) { - *err = "PEM_read_bio_PrivateKey() failed"; - BIO_free(in); - ERR_clear_error(); - return NULL; - } - - BIO_free(in); - - return pkey; -} - - -void * -ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len, - char **err) -{ - BIO *bio = NULL; - EVP_PKEY *pkey = NULL; - - if (data == NULL || len == 0) { - *err = "invalid argument"; - ERR_clear_error(); - return NULL; - } - - bio = BIO_new_mem_buf((char *) data, len); - if (bio == NULL) { - *err = "BIO_new_mem_buf() failed"; - ERR_clear_error(); - return NULL; - } - - pkey = d2i_PrivateKey_bio(bio, NULL); - if (pkey == NULL) { - *err = "d2i_PrivateKey_bio() failed"; - BIO_free(bio); - ERR_clear_error(); - return NULL; - } - - BIO_free(bio); - - return pkey; -} - - -void -ngx_http_lua_ffi_free_priv_key(void *cdata) -{ - EVP_PKEY *pkey = cdata; - - EVP_PKEY_free(pkey); -} - - -int -ngx_http_lua_ffi_set_cert(ngx_http_request_t *r, - void *cdata, char **err) -{ -#ifdef LIBRESSL_VERSION_NUMBER - - *err = "LibreSSL not supported"; - return NGX_ERROR; - -#else - -# if OPENSSL_VERSION_NUMBER < 0x1000205fL - - *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; - return NGX_ERROR; - -# else - -#ifdef OPENSSL_IS_BORINGSSL - size_t i; -#else - int i; -#endif - X509 *x509 = NULL; - ngx_ssl_conn_t *ssl_conn; - STACK_OF(X509) *chain = cdata; - - 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 (sk_X509_num(chain) < 1) { - *err = "invalid certificate chain"; - goto failed; - } - - x509 = sk_X509_value(chain, 0); - if (x509 == NULL) { - *err = "sk_X509_value() failed"; - goto failed; - } - - if (SSL_use_certificate(ssl_conn, x509) == 0) { - *err = "SSL_use_certificate() failed"; - goto failed; - } - - x509 = NULL; - - /* read rest of the chain */ - - for (i = 1; i < sk_X509_num(chain); i++) { - - x509 = sk_X509_value(chain, i); - if (x509 == NULL) { - *err = "sk_X509_value() failed"; - goto failed; - } - - if (SSL_add1_chain_cert(ssl_conn, x509) == 0) { - *err = "SSL_add1_chain_cert() failed"; - goto failed; - } - } - - *err = NULL; - return NGX_OK; - -failed: - - ERR_clear_error(); - - return NGX_ERROR; - -# endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ -#endif -} - - -int -ngx_http_lua_ffi_set_priv_key(ngx_http_request_t *r, - void *cdata, char **err) -{ - EVP_PKEY *pkey = NULL; - 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; - } - - pkey = cdata; - if (pkey == NULL) { - *err = "invalid private key failed"; - goto failed; - } - - if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) { - *err = "SSL_use_PrivateKey() failed"; - goto failed; - } - - return NGX_OK; - -failed: - - ERR_clear_error(); - - return NGX_ERROR; -} - - -#ifndef LIBRESSL_VERSION_NUMBER -static int -ngx_http_lua_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) -{ - /* - * we never terminate handshake here and user can later use - * $ssl_client_verify to check verification result. - * - * this is consistent with Nginx behavior. - */ - return 1; -} -#endif - - -int -ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *client_certs, - void *trusted_certs, int depth, char **err) -{ -#ifdef LIBRESSL_VERSION_NUMBER - - *err = "LibreSSL not supported"; - return NGX_ERROR; - -#else - - ngx_http_lua_ctx_t *ctx; - ngx_ssl_conn_t *ssl_conn; - ngx_http_ssl_srv_conf_t *sscf; - STACK_OF(X509) *client_chain = client_certs; - STACK_OF(X509) *trusted_chain = trusted_certs; - STACK_OF(X509_NAME) *name_chain = NULL; - X509 *x509 = NULL; - X509_NAME *subject = NULL; - X509_STORE *ca_store = NULL; -#ifdef OPENSSL_IS_BORINGSSL - size_t i; -#else - int i; -#endif - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - *err = "no request ctx found"; - return NGX_ERROR; - } - - if (!(ctx->context & NGX_HTTP_LUA_CONTEXT_SSL_CERT)) { - *err = "API disabled in the current context"; - return NGX_ERROR; - } - - 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; - } - - /* enable verify */ - - SSL_set_verify(ssl_conn, SSL_VERIFY_PEER, ngx_http_lua_ssl_verify_callback); - - /* set depth */ - - if (depth < 0) { - sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - if (sscf != NULL) { - depth = sscf->verify_depth; - - } else { - /* same as the default value of ssl_verify_depth */ - depth = 1; - } - } - - SSL_set_verify_depth(ssl_conn, depth); - - /* set CA chain */ - - if (client_chain != NULL || trusted_chain != NULL) { - - ca_store = X509_STORE_new(); - if (ca_store == NULL) { - *err = "X509_STORE_new() failed"; - return NGX_ERROR; - } - - if (client_chain != NULL) { - - /* construct name chain */ - name_chain = sk_X509_NAME_new_null(); - if (name_chain == NULL) { - *err = "sk_X509_NAME_new_null() failed"; - goto failed; - } - - for (i = 0; i < sk_X509_num(client_chain); i++) { - x509 = sk_X509_value(client_chain, i); - if (x509 == NULL) { - *err = "sk_X509_value() failed"; - goto failed; - } - - /* add subject to name chain, which will be sent to client */ - subject = X509_NAME_dup(X509_get_subject_name(x509)); - if (subject == NULL) { - *err = "X509_get_subject_name() failed"; - goto failed; - } - - if (!sk_X509_NAME_push(name_chain, subject)) { - *err = "sk_X509_NAME_push() failed"; - X509_NAME_free(subject); - goto failed; - } - - /* add to trusted CA store */ - if (X509_STORE_add_cert(ca_store, x509) == 0) { - *err = "X509_STORE_add_cert() failed"; - goto failed; - } - } - - /* clean subject name list, and set it for send to client */ - SSL_set_client_CA_list(ssl_conn, name_chain); - } - - if (trusted_chain != NULL) { - for (i = 0; i < sk_X509_num(trusted_chain); i++) { - x509 = sk_X509_value(trusted_chain, i); - if (x509 == NULL) { - *err = "sk_X509_value() failed"; - goto failed; - } - - /* add to trusted CA store */ - if (X509_STORE_add_cert(ca_store, x509) == 0) { - *err = "X509_STORE_add_cert() failed"; - goto failed; - } - } - } - - /* clean ca_store, and store new ca_store */ - if (SSL_set0_verify_cert_store(ssl_conn, ca_store) == 0) { - *err = "SSL_set0_verify_cert_store() failed"; - goto failed; - } - } - - return NGX_OK; - -failed: - - sk_X509_NAME_free(name_chain); - - X509_STORE_free(ca_store); - - return NGX_ERROR; -#endif -} - - -ngx_ssl_conn_t * -ngx_http_lua_ffi_get_req_ssl_pointer(ngx_http_request_t *r) -{ - if (r->connection == NULL || r->connection->ssl == NULL) { - return NULL; - } - - return r->connection->ssl->connection; -} - - -int -ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r, - unsigned char *out, size_t *outlen, 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; - } - - *outlen = SSL_get_client_random(ssl_conn, out, *outlen); - - return NGX_OK; -} - - -#endif /* NGX_HTTP_SSL */