diff --git a/.travis.yml b/.travis.yml index 335ae71ee6..0dfcc381ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -88,7 +88,7 @@ install: - git clone https://github.com/openresty/rds-json-nginx-module.git ../rds-json-nginx-module - git clone https://github.com/openresty/srcache-nginx-module.git ../srcache-nginx-module - git clone https://github.com/openresty/redis2-nginx-module.git ../redis2-nginx-module - - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core + - git clone -b feat/cosocket_tlshandshake https://github.com/dndx/lua-resty-core.git ../lua-resty-core - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache - git clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql - git clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string diff --git a/README.markdown b/README.markdown index 4e0b979879..7f0ac24cb1 100644 --- a/README.markdown +++ b/README.markdown @@ -977,7 +977,6 @@ TODO * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). -* cosocket: add client SSL certificate support. [Back to TOC](#table-of-contents) @@ -3594,6 +3593,7 @@ Nginx API for Lua * [ngx.socket.stream](#ngxsocketstream) * [ngx.socket.tcp](#ngxsockettcp) * [tcpsock:connect](#tcpsockconnect) +* [tcpsock:setclientcert](#tcpsocksetclientcert) * [tcpsock:sslhandshake](#tcpsocksslhandshake) * [tcpsock:send](#tcpsocksend) * [tcpsock:receive](#tcpsockreceive) @@ -7565,6 +7565,7 @@ ngx.socket.tcp Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: * [connect](#tcpsockconnect) +* [setclientcert](#tcpsocksetclientcert) * [sslhandshake](#tcpsocksslhandshake) * [send](#tcpsocksend) * [receive](#tcpsockreceive) @@ -7724,6 +7725,31 @@ This method was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) +tcpsock:setclientcert +-------------------- + +**syntax:** *ok, err = tcpsock:setclientcert(cert, pkey)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua** + +Set client certificate chain and corresponding private key to the TCP socket object. +The certificate chain and private key provided will be used later by the [tcpsock:sslhandshake](#tcpsocksslhandshake) method. + +* `cert` specify a client certificate chain cdata object that will be used while handshaking with +remote server. These objects can be created using [ngx.ssl.parse\_pem\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert) +function provided by lua-resty-core. Note that specifying the `cert` option requires +corresponding `pkey` be provided too. See below. +* `pkey` specify a private key corresponds to the `cert` option above. +These objects can be created using [ngx.ssl.parse\_pem\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_priv_key) +function provided by lua-resty-core. + +If both of `cert` and `pkey` are `nil`, this method will clear any existing client certificate and private key +that was previously set on the cosocket object. + +This method was first introduced in the `v0.10.22` release. + +[Back to TOC](#nginx-api-for-lua) + tcpsock:sslhandshake -------------------- diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index ceaf4ff175..72549ca41e 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -22,7 +22,9 @@ static int ngx_http_lua_socket_tcp(lua_State *L); static int ngx_http_lua_socket_tcp_connect(lua_State *L); #if (NGX_HTTP_SSL) -static int ngx_http_lua_socket_tcp_sslhandshake(lua_State *L); +static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c); +static int ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); #endif static int ngx_http_lua_socket_tcp_receive(lua_State *L); static int ngx_http_lua_socket_tcp_receiveany(lua_State *L); @@ -149,12 +151,6 @@ static void ngx_http_lua_socket_shutdown_pool_helper( ngx_http_lua_socket_pool_t *spool); static int ngx_http_lua_socket_prepare_error_retvals(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L, ngx_uint_t ft_type); -#if (NGX_HTTP_SSL) -static int ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, - ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); -static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c); -static int ngx_http_lua_ssl_free_session(lua_State *L); -#endif static void ngx_http_lua_socket_tcp_close_connection(ngx_connection_t *c); @@ -164,6 +160,8 @@ enum { SOCKET_CONNECT_TIMEOUT_INDEX = 2, SOCKET_SEND_TIMEOUT_INDEX = 4, SOCKET_READ_TIMEOUT_INDEX = 5, + SOCKET_CLIENT_CERT_INDEX = 6 , + SOCKET_CLIENT_PKEY_INDEX = 7 , }; @@ -222,9 +220,6 @@ static char ngx_http_lua_upstream_udata_metatable_key; static char ngx_http_lua_downstream_udata_metatable_key; static char ngx_http_lua_pool_udata_metatable_key; static char ngx_http_lua_pattern_udata_metatable_key; -#if (NGX_HTTP_SSL) -static char ngx_http_lua_ssl_session_metatable_key; -#endif #define ngx_http_lua_tcp_socket_metatable_literal_key "__tcp_cosocket_mt" @@ -319,18 +314,11 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* {{{tcp object metatable */ lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( tcp_socket_metatable_key)); - lua_createtable(L, 0 /* narr */, 14 /* nrec */); + lua_createtable(L, 0 /* narr */, 15 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect); lua_setfield(L, -2, "connect"); -#if (NGX_HTTP_SSL) - - lua_pushcfunction(L, ngx_http_lua_socket_tcp_sslhandshake); - lua_setfield(L, -2, "sslhandshake"); - -#endif - lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); lua_setfield(L, -2, "receive"); @@ -404,19 +392,6 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "__gc"); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ - -#if (NGX_HTTP_SSL) - - /* {{{ssl session userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - ssl_session_metatable_key)); - lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ - lua_pushcfunction(L, ngx_http_lua_ssl_free_session); - lua_setfield(L, -2, "__gc"); - lua_rawset(L, LUA_REGISTRYINDEX); - /* }}} */ - -#endif } @@ -451,7 +426,7 @@ ngx_http_lua_socket_tcp(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE); - lua_createtable(L, 5 /* narr */, 1 /* nrec */); + lua_createtable(L, 7 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( tcp_socket_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); @@ -1559,64 +1534,73 @@ ngx_http_lua_socket_conn_error_retval_handler(ngx_http_request_t *r, #if (NGX_HTTP_SSL) -static int -ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) +static const char * +ngx_http_lua_socket_tcp_check_busy(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, unsigned int ops) { - int n, top; - ngx_int_t rc; - ngx_str_t name = ngx_null_string; - ngx_connection_t *c; - ngx_ssl_session_t **psession; - ngx_http_request_t *r; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; - - ngx_http_lua_socket_tcp_upstream_t *u; - - /* Lua function arguments: self [,session] [,host] [,verify] - [,send_status_req] */ + if ((ops & SOCKET_OP_CONNECT) && u->conn_waiting) { + return "socket busy connecting"; + } - n = lua_gettop(L); - if (n < 1 || n > 5) { - return luaL_error(L, "ngx.socket sslhandshake: expecting 1 ~ 5 " - "arguments (including the object), but seen %d", n); + if ((ops & SOCKET_OP_READ) && u->read_waiting) { + return "socket busy reading"; } - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request found"); + if ((ops & SOCKET_OP_WRITE) + && (u->write_waiting + || (u->raw_downstream + && (r->connection->buffered & NGX_HTTP_LOWLEVEL_BUFFERED)))) + { + return "socket busy writing"; } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket ssl handshake"); + return NULL; +} - luaL_checktype(L, 1, LUA_TTABLE); - lua_rawgeti(L, 1, SOCKET_CTX_INDEX); - u = lua_touserdata(L, -1); +int +ngx_http_lua_ffi_socket_tcp_sslhandshake(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_ssl_session_t *sess, + int enable_session_reuse, ngx_str_t *server_name, int verify, + int ocsp_status_req, STACK_OF(X509) *chain, EVP_PKEY *pkey, + const char **errmsg) +{ + ngx_int_t rc, i; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + const char *busy_msg; + ngx_ssl_conn_t *ssl_conn; + X509 *x509; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket ssl handshake"); if (u == NULL || u->peer.connection == NULL || u->read_closed || u->write_closed) { - lua_pushnil(L); - lua_pushliteral(L, "closed"); - return 2; + *errmsg = "closed"; + return NGX_ERROR; } if (u->request != r) { - return luaL_error(L, "bad request"); + *errmsg = "bad request"; + return NGX_ERROR; } - ngx_http_lua_socket_check_busy_connecting(r, u, L); - ngx_http_lua_socket_check_busy_reading(r, u, L); - ngx_http_lua_socket_check_busy_writing(r, u, L); + busy_msg = ngx_http_lua_socket_tcp_check_busy(r, u, SOCKET_OP_CONNECT + | SOCKET_OP_READ + | SOCKET_OP_WRITE); + if (busy_msg != NULL) { + *errmsg = busy_msg; + return NGX_ERROR; + } if (u->raw_downstream || u->body_downstream) { - lua_pushnil(L); - lua_pushliteral(L, "not supported for downstream"); - return 2; + *errmsg = "not supported for downstream sockets"; + return NGX_ERROR; } c = u->peer.connection; @@ -1624,122 +1608,140 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) u->ssl_session_reuse = 1; if (c->ssl && c->ssl->handshaked) { - switch (lua_type(L, 2)) { - case LUA_TUSERDATA: - lua_pushvalue(L, 2); - break; + if (sess != NULL) { + return NGX_DONE; + } - case LUA_TBOOLEAN: - if (!lua_toboolean(L, 2)) { - /* avoid generating the ssl session */ - lua_pushboolean(L, 1); - break; - } - /* fall through */ + u->ssl_session_reuse = enable_session_reuse; - default: - ngx_http_lua_ssl_handshake_retval_handler(r, u, L); - break; - } + (void) ngx_http_lua_ssl_handshake_retval_handler(r, u, NULL); - return 1; + return NGX_OK; } if (ngx_ssl_create_connection(u->conf->ssl, c, NGX_SSL_BUFFER|NGX_SSL_CLIENT) != NGX_OK) { - lua_pushnil(L); - lua_pushliteral(L, "failed to create ssl connection"); - return 2; + *errmsg = "failed to create ssl connection"; + return NGX_ERROR; } + ssl_conn = c->ssl->connection; + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - return luaL_error(L, "no ctx found"); + return NGX_HTTP_LUA_FFI_NO_REQ_CTX; } coctx = ctx->cur_co_ctx; c->sendfile = 0; - if (n >= 2) { - if (lua_type(L, 2) == LUA_TBOOLEAN) { - u->ssl_session_reuse = lua_toboolean(L, 2); + if (sess != NULL) { + if (ngx_ssl_set_session(c, sess) != NGX_OK) { + *errmsg = "ssl set session failed"; + return NGX_ERROR; + } - } else { - psession = lua_touserdata(L, 2); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua ssl set session: %p", sess); - if (psession != NULL && *psession != NULL) { - if (ngx_ssl_set_session(c, *psession) != NGX_OK) { - lua_pushnil(L); - lua_pushliteral(L, "lua ssl set session failed"); - return 2; - } + } else { + u->ssl_session_reuse = enable_session_reuse; + } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua ssl set session: %p", *psession); - } + if (chain != NULL) { + ngx_http_lua_assert(pkey != NULL); /* ensured by resty.core */ + + if (sk_X509_num(chain) < 1) { + ERR_clear_error(); + *errmsg = "invalid client certificate chain"; + return NGX_ERROR; } - if (n >= 3) { - name.data = (u_char *) lua_tolstring(L, 3, &name.len); + x509 = sk_X509_value(chain, 0); + if (x509 == NULL) { + ERR_clear_error(); + *errmsg = "ssl fetch client certificate from chain failed"; + return NGX_ERROR; + } - if (name.data) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua ssl server name: \"%*s\"", name.len, - name.data); + if (SSL_use_certificate(ssl_conn, x509) == 0) { + ERR_clear_error(); + *errmsg = "ssl set client certificate failed"; + return NGX_ERROR; + } -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + /* read rest of the chain */ - if (SSL_set_tlsext_host_name(c->ssl->connection, - (char *) name.data) - == 0) - { - lua_pushnil(L); - lua_pushliteral(L, "SSL_set_tlsext_host_name failed"); - return 2; - } + for (i = 1; i < sk_X509_num(chain); i++) { + x509 = sk_X509_value(chain, i); + if (x509 == NULL) { + ERR_clear_error(); + *errmsg = "ssl fetch client intermediate certificate from " + "chain failed"; + return NGX_ERROR; + } -#else + if (SSL_add1_chain_cert(ssl_conn, x509) == 0) { + ERR_clear_error(); + *errmsg = "ssl set client intermediate certificate failed"; + return NGX_ERROR; + } + } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua socket SNI disabled because the current " - "version of OpenSSL lacks the support"); + if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) { + ERR_clear_error(); + *errmsg = "ssl set client private key failed"; + return NGX_ERROR; + } + } + if (server_name != NULL && server_name->data != NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua ssl server name: \"%V\"", server_name); + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + if (SSL_set_tlsext_host_name(c->ssl->connection, + (char *) server_name->data) + == 0) + { + *errmsg = "SSL_set_tlsext_host_name failed"; + return NGX_ERROR; + } + +#else + *errmsg = "no TLS extension support"; + return NGX_ERROR; #endif - } + } - if (n >= 4) { - u->ssl_verify = lua_toboolean(L, 4); + u->ssl_verify = verify; - if (n >= 5) { - if (lua_toboolean(L, 5)) { + if (ocsp_status_req) { #ifdef NGX_HTTP_LUA_USE_OCSP - SSL_set_tlsext_status_type(c->ssl->connection, - TLSEXT_STATUSTYPE_ocsp); + SSL_set_tlsext_status_type(c->ssl->connection, + TLSEXT_STATUSTYPE_ocsp); + #else - return luaL_error(L, "no OCSP support"); + *errmsg = "no OCSP support"; + return NGX_ERROR; #endif - } - } - } - } } - dd("found sni name: %.*s %p", (int) name.len, name.data, name.data); - - if (name.len == 0) { + if (server_name->len == 0) { u->ssl_name.len = 0; } else { if (u->ssl_name.data) { /* buffer already allocated */ - if (u->ssl_name.len >= name.len) { + if (u->ssl_name.len >= server_name->len) { /* reuse it */ - ngx_memcpy(u->ssl_name.data, name.data, name.len); - u->ssl_name.len = name.len; + ngx_memcpy(u->ssl_name.data, server_name->data, + server_name->len); + u->ssl_name.len = server_name->len; } else { ngx_free(u->ssl_name.data); @@ -1750,17 +1752,15 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) new_ssl_name: - u->ssl_name.data = ngx_alloc(name.len, ngx_cycle->log); + u->ssl_name.data = ngx_alloc(server_name->len, ngx_cycle->log); if (u->ssl_name.data == NULL) { u->ssl_name.len = 0; - - lua_pushnil(L); - lua_pushliteral(L, "no memory"); - return 2; + *errmsg = "no memory"; + return NGX_ERROR; } - ngx_memcpy(u->ssl_name.data, name.data, name.len); - u->ssl_name.len = name.len; + ngx_memcpy(u->ssl_name.data, server_name->data, server_name->len); + u->ssl_name.len = server_name->len; } } @@ -1774,7 +1774,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) rc = ngx_ssl_handshake(c); - dd("ngx_ssl_handshake returned %d", (int) rc); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "ngx_ssl_handshake returned: %d", rc); if (rc == NGX_AGAIN) { if (c->write->timer_set) { @@ -1799,21 +1800,24 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) r->write_event_handler = ngx_http_core_run_phases; } - return lua_yield(L, 0); + return NGX_AGAIN; } - top = lua_gettop(L); ngx_http_lua_ssl_handshake_handler(c); - return lua_gettop(L) - top; + + if (rc == NGX_ERROR) { + *errmsg = u->error_ret; + return NGX_ERROR; + } + + return NGX_OK; } static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) { - const char *err; int waiting; - lua_State *L; ngx_int_t rc; ngx_connection_t *dc; /* downstream connection */ ngx_http_request_t *r; @@ -1836,11 +1840,9 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) waiting = u->conn_waiting; dc = r->connection; - L = u->write_co_ctx->co; if (c->read->timedout) { - lua_pushnil(L); - lua_pushliteral(L, "timeout"); + u->error_ret = "timeout"; goto failed; } @@ -1849,19 +1851,18 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) } if (c->ssl->handshaked) { - if (u->ssl_verify) { rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK) { - lua_pushnil(L); - err = lua_pushfstring(L, "%d: %s", (int) rc, - X509_verify_cert_error_string(rc)); + u->error_ret = X509_verify_cert_error_string(rc); + u->openssl_error_code_ret = rc; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_socket_errors) { ngx_log_error(NGX_LOG_ERR, dc->log, 0, "lua ssl " - "certificate verify error: (%s)", err); + "certificate verify error: (%d: %s)", + rc, u->error_ret); } goto failed; @@ -1872,8 +1873,7 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) if (u->ssl_name.len && ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) { - lua_pushnil(L); - lua_pushliteral(L, "certificate host mismatch"); + u->error_ret = "certificate host mismatch"; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_socket_errors) { @@ -1892,7 +1892,7 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) ngx_http_lua_socket_handle_conn_success(r, u); } else { - (void) ngx_http_lua_ssl_handshake_retval_handler(r, u, L); + (void) ngx_http_lua_ssl_handshake_retval_handler(r, u, NULL); } if (waiting) { @@ -1902,60 +1902,83 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) return; } - lua_pushnil(L); - lua_pushliteral(L, "handshake failed"); + u->error_ret = "handshake failed"; failed: if (waiting) { u->write_prepare_retvals = - ngx_http_lua_socket_conn_error_retval_handler; - ngx_http_lua_socket_handle_conn_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_SSL); + ngx_http_lua_socket_conn_error_retval_handler; + ngx_http_lua_socket_handle_conn_error(r, u, NGX_HTTP_LUA_SOCKET_FT_SSL); ngx_http_run_posted_requests(dc); } else { - (void) ngx_http_lua_socket_conn_error_retval_handler(r, u, L); + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_SSL; + + (void) ngx_http_lua_socket_conn_error_retval_handler(r, u, NULL); } } +int +ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_ssl_session_t **sess, + const char **errmsg, int *openssl_error_code) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua cosocket get SSL handshake result for upstream: %p", u); + + if (u->error_ret != NULL) { + *errmsg = u->error_ret; + *openssl_error_code = u->openssl_error_code_ret; + + return NGX_ERROR; + } + + *sess = u->ssl_session_ret; + + return NGX_OK; +} + + static int ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) { ngx_connection_t *c; - ngx_ssl_session_t *ssl_session, **ud; + ngx_ssl_session_t *ssl_session; if (!u->ssl_session_reuse) { - lua_pushboolean(L, 1); - return 1; + return 0; } - ud = lua_newuserdata(L, sizeof(ngx_ssl_session_t *)); - c = u->peer.connection; ssl_session = ngx_ssl_get_session(c); if (ssl_session == NULL) { - *ud = NULL; + u->ssl_session_ret = NULL; } else { - *ud = ssl_session; + u->ssl_session_ret = ssl_session; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua ssl save session: %p", ssl_session); - - /* set up the __gc metamethod */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - ssl_session_metatable_key)); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); } - return 1; + return 0; } + +void +ngx_http_lua_ffi_ssl_free_session(ngx_ssl_session_t *sess) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua ssl free session: %p", sess); + + ngx_ssl_free_session(sess); +} + + #endif /* NGX_HTTP_SSL */ @@ -2008,12 +2031,14 @@ ngx_http_lua_socket_prepare_error_retvals(ngx_http_request_t *r, u_char errstr[NGX_MAX_ERROR_STR]; u_char *p; - if (ft_type & (NGX_HTTP_LUA_SOCKET_FT_RESOLVER - | NGX_HTTP_LUA_SOCKET_FT_SSL)) - { + if (ft_type & NGX_HTTP_LUA_SOCKET_FT_RESOLVER) { return 2; } + if (ft_type & NGX_HTTP_LUA_SOCKET_FT_SSL) { + return 0; + } + lua_pushnil(L); if (ft_type & NGX_HTTP_LUA_SOCKET_FT_TIMEOUT) { @@ -6105,27 +6130,6 @@ ngx_http_lua_coctx_cleanup(void *data) } -#if (NGX_HTTP_SSL) - -static int -ngx_http_lua_ssl_free_session(lua_State *L) -{ - ngx_ssl_session_t **psession; - - psession = lua_touserdata(L, 1); - if (psession && *psession != NULL) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua ssl free session: %p", *psession); - - ngx_ssl_free_session(*psession); - } - - return 0; -} - -#endif /* NGX_HTTP_SSL */ - - void ngx_http_lua_cleanup_conn_pools(lua_State *L) { diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index a0a5a5181a..ee9411bc8d 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -120,6 +120,9 @@ struct ngx_http_lua_socket_tcp_upstream_s { #if (NGX_HTTP_SSL) ngx_str_t ssl_name; + ngx_ssl_session_t *ssl_session_ret; + const char *error_ret; + int openssl_error_code_ret; #endif unsigned ft_type:16; diff --git a/t/062-count.t b/t/062-count.t index 104126281a..d977909bb6 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -459,7 +459,7 @@ worker: 4 --- request GET /test --- response_body -n = 14 +n = 15 --- no_error_log [error] diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index c26f0cec53..cbbd679468 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -106,7 +106,7 @@ __DATA__ GET /t --- response_body_like chop \Aconnected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 59 bytes. received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil @@ -190,7 +190,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 53 bytes. received: HTTP/1.1 201 Created close: 1 nil @@ -271,7 +271,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 58 bytes. received: HTTP/1.1 302 Moved Temporarily close: 1 nil @@ -355,12 +355,12 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 200 OK close: 1 nil connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -603,7 +603,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 80 bytes. received: HTTP/1.1 404 Not Found close: 1 nil @@ -688,7 +688,7 @@ $::DSTRootCertificate" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 58 bytes. received: HTTP/1.1 302 Moved Temporarily close: 1 nil @@ -1008,7 +1008,7 @@ $::DSTRootCertificate" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 58 bytes. received: HTTP/1.1 302 Moved Temporarily close: 1 nil @@ -1087,7 +1087,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 58 bytes. received: HTTP/1.1 302 Moved Temporarily close: 1 nil @@ -1179,7 +1179,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 53 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -1269,7 +1269,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 53 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -1418,13 +1418,13 @@ $::DSTRootCertificate" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil --- log_level: debug @@ -1494,13 +1494,13 @@ $::DSTRootCertificate" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil --- log_level: debug @@ -1637,7 +1637,7 @@ attempt to call method 'sslhandshake' (a nil value) GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1742,7 +1742,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2031,8 +2031,8 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata -ssl handshake: userdata +ssl handshake: cdata +ssl handshake: cdata sent http request: 58 bytes. received: HTTP/1.1 302 Moved Temporarily close: 1 nil @@ -2232,7 +2232,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- user_files eval ">>> test.key @@ -2405,7 +2405,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2529,7 +2529,7 @@ SSL reused session -=== TEST 31: handshake, too many arguments +=== TEST 31: handshake, too few arguments --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -2633,7 +2633,7 @@ qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including t GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 53 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -2726,7 +2726,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 53 bytes. received: HTTP/1.1 200 OK close: 1 nil diff --git a/t/139-ssl-cert-by.t b/t/139-ssl-cert-by.t index 502e0ac184..2180466907 100644 --- a/t/139-ssl-cert-by.t +++ b/t/139-ssl-cert-by.t @@ -100,7 +100,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -209,7 +209,7 @@ ssl_certificate_by_lua\(nginx.conf:28\):1: ssl cert by lua is running!,/ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -314,7 +314,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1\d)\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -432,7 +432,7 @@ my timer run! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -924,7 +924,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- error_log lua ssl server name: "test.com" @@ -1137,7 +1137,7 @@ print("ssl cert by lua is running!") GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1248,7 +1248,7 @@ a.lua:1: ssl cert by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1372,7 +1372,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1468,7 +1468,7 @@ GitHub openresty/lua-resty-core#42 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1566,7 +1566,7 @@ github issue #723 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1668,7 +1668,7 @@ ssl_certificate_by_lua:1: ssl cert by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 59 bytes. received: HTTP/1.1 200 OK received: Server: nginx @@ -1963,7 +1963,7 @@ qr/\[info\] .*? SSL_do_handshake\(\) failed\b/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2063,7 +2063,7 @@ client ip: 127.0.0.1 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2221,7 +2221,7 @@ qr/elapsed in ssl_certificate_by_lua\*: 0\.(?:09|1\d)\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- no_error_log [error] [alert] @@ -2311,7 +2311,7 @@ ssl handshake: userdata GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- no_error_log [error] [alert] diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index 31a6e2f434..5b2ae018fe 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -217,7 +217,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -371,7 +371,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -499,7 +499,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -650,7 +650,7 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -800,7 +800,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1182,7 +1182,7 @@ client certificate subject: nil GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1306,7 +1306,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t index 6769a336bc..61598732be 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -77,7 +77,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -152,7 +152,7 @@ ssl_session_store_by_lua\(nginx\.conf:25\):1: ssl session store by lua is runnin GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -227,7 +227,7 @@ API disabled in the context of ssl_session_store_by_lua* GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -319,7 +319,7 @@ my timer run! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -390,7 +390,7 @@ API disabled in the context of ssl_session_store_by_lua* GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -462,7 +462,7 @@ ngx.exit does not yield and the error code is eaten. GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -532,7 +532,7 @@ ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -600,7 +600,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -671,7 +671,7 @@ get_phase: ssl_session_store GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log eval @@ -744,7 +744,7 @@ print("ssl store session by lua is running!") GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -820,7 +820,7 @@ a.lua:1: ssl store session by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- no_error_log @@ -891,7 +891,7 @@ qr/\[emerg\] .*? "ssl_session_store_by_lua_block" directive is not allowed here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -955,7 +955,7 @@ ssl_session_store_by_lua(nginx.conf:25):1: ssl session store by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log eval qr/ssl_session_store_by_lua\*: skipped since TLS version >= 1\.3 \(\d+\)/ diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t index 0e90c23665..8c5174dd94 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -80,7 +80,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval: qr/ssl_session_fetch_by_lua\(nginx\.conf:\d+\):.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ @@ -180,7 +180,7 @@ ssl_session_fetch_by_lua\(nginx\.conf:25\):1: ssl fetch sess by lua is running!, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -264,7 +264,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -365,7 +365,7 @@ qr/my timer run!/s GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -446,7 +446,7 @@ qr/received memc reply: OK/s GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -527,7 +527,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -609,7 +609,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -690,7 +690,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -773,7 +773,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -853,7 +853,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -939,7 +939,7 @@ qr/get_phase: ssl_session_fetch/s GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -1025,7 +1025,7 @@ print("ssl fetch sess by lua is running!") GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -1109,7 +1109,7 @@ qr/\S+:\d+: ssl fetch sess by lua is running!/s GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -1285,7 +1285,7 @@ GET /t GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- no_error_log [warn] @@ -1346,7 +1346,7 @@ close: 1 nil GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval: qr/ssl_session_fetch_by_lua\(nginx\.conf:\d+\):.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ --- grep_error_log_out eval @@ -1444,7 +1444,7 @@ ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is run GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval qr/elapsed in ssl_session_fetch_by_lua\*: 0\.(?:09|1[01])\d+,/, @@ -1537,7 +1537,7 @@ qr/elapsed in ssl_session_fetch_by_lua\*: 0\.(?:09|1[01])\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval: qr/received memc reply of \d+ bytes/ --- grep_error_log_out eval @@ -1632,7 +1632,7 @@ close: 1 nil GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval: qr/uthread: [^.,]+/ --- grep_error_log_out eval @@ -1732,7 +1732,7 @@ uthread: failed to kill: already waited or killed GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval: qr/uthread: [^.,]+/ --- grep_error_log_out eval diff --git a/t/155-tls13.t b/t/155-tls13.t index 9f7cf86d2e..4e684cd335 100644 --- a/t/155-tls13.t +++ b/t/155-tls13.t @@ -91,7 +91,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- user_files eval ">>> test.key diff --git a/t/162-socket-tls-handshake.t b/t/162-socket-tls-handshake.t new file mode 100644 index 0000000000..c4076af042 --- /dev/null +++ b/t/162-socket-tls-handshake.t @@ -0,0 +1,376 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * 43; + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; + +log_level 'debug'; + +no_long_string(); +#no_diff(); + +sub read_file { + my $infile = shift; + open my $in, $infile + or die "cannot open $infile for reading: $!"; + my $cert = do { local $/; <$in> }; + close $in; + $cert; +} + +our $MTLSCA = read_file("t/cert/mtls_ca.crt"); +our $MTLSClient = read_file("t/cert/mtls_client.crt"); +our $MTLSClientKey = read_file("t/cert/mtls_client.key"); +our $MTLSServer = read_file("t/cert/mtls_server.crt"); +our $MTLSServerKey = read_file("t/cert/mtls_server.key"); + +our $HtmlDir = html_dir; + +our $mtls_http_config = <<"_EOC_"; +server { + listen unix:$::HtmlDir/mtls.sock ssl; + + ssl_certificate $::HtmlDir/mtls_server.crt; + ssl_certificate_key $::HtmlDir/mtls_server.key; + ssl_client_certificate $::HtmlDir/mtls_ca.crt; + ssl_verify_client on; + server_tokens off; + + location / { + return 200 "hello, \$ssl_client_s_dn"; + } +} +_EOC_ + +our $mtls_user_files = <<"_EOC_"; +>>> mtls_server.key +$::MTLSServerKey +>>> mtls_server.crt +$::MTLSServer +>>> mtls_ca.crt +$::MTLSCA +>>> mtls_client.key +$::MTLSClientKey +>>> mtls_client.crt +$::MTLSClient +_EOC_ + +run_tests(); + +__DATA__ + +=== TEST 1: sanity: www.google.com +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER ipv6=off; + + location /t { + content_by_lua_block { + -- avoid flushing google in "check leak" testing mode: + local counter = package.loaded.counter + if not counter then + counter = 1 + elseif counter >= 2 then + return ngx.exit(503) + else + counter = counter + 1 + end + + package.loaded.counter = counter + + do + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + local ok, err = sock:connect("www.google.com", 443) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake() + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET / HTTP/1.1\r\nHost: www.google.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.") + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive response status line: ", err) + return + end + + ngx.say("received: ", line) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + + collectgarbage() + } + } +--- request +GET /t +--- response_body_like chop +\Aconnected: 1 +ssl handshake: cdata +sent http request: 59 bytes. +received: HTTP/1.1 (?:200 OK|302 Found) +close: 1 nil +\z +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ +--- grep_error_log_out eval +qr/^lua ssl save session: ([0-9A-F]+) +lua ssl free session: ([0-9A-F]+) +$/ +--- no_error_log +lua ssl server name: +SSL reused session +[error] +[alert] +--- timeout: 5 + + + +=== TEST 2: mutual TLS handshake, upstream is not accessible without client certs +--- http_config eval: $::mtls_http_config +--- config eval +" + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = sock:connect('unix:$::HtmlDir/mtls.sock') + if not ok then + ngx.say('failed to connect: ', err) + end + + assert(sock:sslhandshake()) + + ngx.say('connected: ', ok) + + local req = 'GET /\\r\\n' + + local bytes, err = sock:send(req) + if not bytes then + ngx.say('failed to send request: ', err) + return + end + + ngx.say('request sent: ', bytes) + + ngx.say(sock:receive('*a')) + + assert(sock:close()) + } + } +" +--- user_files eval: $::mtls_user_files +--- request +GET /t +--- response_body_like: 400 No required SSL certificate was sent +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + +=== TEST 3: mutual TLS handshake, upstream is accessible with client certs +--- http_config eval: $::mtls_http_config +--- config eval +" + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = sock:connect('unix:$::HtmlDir/mtls.sock') + if not ok then + ngx.say('failed to connect: ', err) + end + + local f = assert(io.open('$::HtmlDir/mtls_client.crt')) + local cert_data = f:read('*a') + f:close() + + f = assert(io.open('$::HtmlDir/mtls_client.key')) + local key_data = f:read('*a') + f:close() + + local ssl = require('ngx.ssl') + + local chain = assert(ssl.parse_pem_cert(cert_data)) + local priv = assert(ssl.parse_pem_priv_key(key_data)) + + sock:setclientcert(chain, priv) + + assert(sock:sslhandshake()) + + ngx.say('connected: ', ok) + + local req = 'GET /\\r\\n' + + local bytes, err = sock:send(req) + if not bytes then + ngx.say('failed to send request: ', err) + return + end + + ngx.say('request sent: ', bytes) + + ngx.say(sock:receive('*a')) + + assert(sock:close()) + } + } +" +--- user_files eval: $::mtls_user_files +--- request +GET /t +--- response_body +connected: 1 +request sent: 7 +hello, CN=foo@example.com,O=OpenResty,ST=California,C=US +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + +=== TEST 4: incorrect type of client cert +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + + local ok, err = sock:setclientcert("doesnt", "work") + if not ok then + ngx.say('failed to setclientcert: ', err) + return + end + + assert(sock:close()) + } + } +--- request +GET /t +--- response_body +failed to setclientcert: bad cert arg: cdata expected, got string +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + +=== TEST 5: incorrect type of client key +--- config eval +" + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + + local f = assert(io.open('$::HtmlDir/mtls_client.crt')) + local cert_data = f:read('*a') + f:close() + + local ssl = require('ngx.ssl') + + local chain = assert(ssl.parse_pem_cert(cert_data)) + + local ok, err = sock:setclientcert(chain, 'work') + if not ok then + ngx.say('failed to setclientcert: ', err) + return + end + + assert(sock:close()) + } + } +" +--- user_files eval: $::mtls_user_files +--- request +GET /t +--- response_body +failed to setclientcert: bad pkey arg: cdata expected, got string +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + +=== TEST 6: missing client cert +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + + local ok, err = sock:setclientcert(nil, "work") + if not ok then + ngx.say('failed to setclientcert: ', err) + return + end + + assert(sock:close()) + } + } +--- request +GET /t +--- response_body +failed to setclientcert: client certificate must be supplied with corresponding private key +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + +=== TEST 7: missing private key +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + + local ok, err = sock:setclientcert('doesnt', nil) + if not ok then + ngx.say('failed to setclientcert: ', err) + return + end + + assert(sock:close()) + } + } +--- request +GET /t +--- response_body +failed to setclientcert: client certificate must be supplied with corresponding private key +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index 79787f63a0..da021300af 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -100,7 +100,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -209,7 +209,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua is running!,/ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -314,7 +314,7 @@ qr/elapsed in ssl client hello by lua: 0.(?:09|1\d)\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -432,7 +432,7 @@ my timer run! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -924,7 +924,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- error_log lua ssl server name: "test.com" @@ -1135,7 +1135,7 @@ print("ssl client hello by lua is running!") GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1246,7 +1246,7 @@ a.lua:1: ssl client hello by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1370,7 +1370,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1466,7 +1466,7 @@ GitHub openresty/lua-resty-core#42 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1561,7 +1561,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1817,7 +1817,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2005,7 +2005,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 57 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2103,7 +2103,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua in server2 is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2208,7 +2208,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2308,7 +2308,7 @@ client ip: 127.0.0.1 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2465,7 +2465,7 @@ qr/elapsed in ssl_client_hello_by_lua\*: 0\.(?:09|1\d)\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- no_error_log [error] [alert] @@ -2555,7 +2555,7 @@ ssl handshake: userdata GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- no_error_log [error] [alert] diff --git a/t/cert/mtls_ca.crt b/t/cert/mtls_ca.crt new file mode 100644 index 0000000000..1fe7e1f985 --- /dev/null +++ b/t/cert/mtls_ca.crt @@ -0,0 +1,78 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 32:ed:21:56:d8:4e:aa:03:89:a9:4a:a4:e2:85:2d:8a:3b:2b:89:22 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA + Validity + Not Before: Mar 13 15:49:00 2022 GMT + Not After : Mar 8 15:49:00 2042 GMT + Subject: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:e6:37:d2:c6:17:36:c7:b2:7f:7d:cf:d0:62:87: + 99:d9:21:b8:de:ff:d8:e2:3a:1c:68:90:8f:ce:17: + 68:22:b0:60:30:cc:29:e8:34:ee:ff:b2:25:de:6e: + 1a:d4:df:10:19:11:4b:40:61:d3:a9:4d:80:ed:97: + 81:4e:c5:74:e8:4d:63:e3:5f:21:bc:5a:6e:22:a0: + 17:91:c1:cb:25:53:9b:9d:4e:e1:51:5b:f6:52:e7: + 0a:27:f6:16:c2:31:cb:6c:47:f4:89:51:15:cc:06: + be:31:3e:1c:ea:ee:81:9b:c4:97:96:fd:e5:1c:95: + 9e:c0:65:cd:a9:9a:cb:68:67:f2:62:a0:21:eb:5a: + c5:a1:92:ed:32:41:28:f9:47:34:eb:44:ae:d6:e7: + 76:71:11:98:c9:2e:ce:6c:7c:10:1b:c7:4c:c3:14: + 89:4e:d9:4c:d9:c7:43:e9:3c:29:ca:62:a9:91:b3: + 87:e7:d7:b4:18:ab:65:f9:6b:ed:82:ca:a1:36:35: + 18:05:cb:5c:24:26:13:13:f8:99:ac:99:be:9b:a6: + 73:df:0d:16:95:b1:dc:be:fe:7a:c2:b6:dc:c8:93: + cf:10:e0:29:03:0e:28:78:18:84:ee:14:92:ab:be: + 5a:a0:14:a2:4a:2f:d3:d0:b8:0e:00:d2:5a:cd:e4: + bd:a1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + F0:D7:4B:14:73:E1:67:00:6B:54:B4:19:20:76:12:9F:9D:8E:C8:09 + Signature Algorithm: sha256WithRSAEncryption + 6d:52:21:6d:6e:8c:e5:4a:28:07:65:6d:d8:7c:23:2e:c6:c1: + d0:ec:27:b3:b0:c3:d3:e8:fa:72:b9:de:32:4e:ff:97:8d:86: + a9:6d:b3:a9:b4:2d:77:ca:28:97:6a:3d:7b:a2:15:ed:34:dc: + 72:9f:6f:e7:01:0c:d3:28:6a:80:1b:50:09:fd:d7:2c:d8:92: + d5:10:c4:73:15:20:7d:99:dc:de:30:7b:3c:6e:e9:66:b2:0e: + 4e:1a:c1:51:57:6e:5b:b0:a9:f6:ff:0b:8f:07:67:31:40:5b: + 11:a9:06:d3:d3:76:c5:d2:56:95:9a:9e:4a:16:44:4b:32:e5: + af:dd:4b:4d:5d:57:b8:85:69:36:93:2a:c6:0c:8f:e1:42:35: + be:8e:f3:e7:35:d3:2c:3a:03:31:40:75:8e:e8:dd:57:35:20: + 5e:18:a9:76:ce:85:be:7e:3a:cf:6e:08:58:5b:47:d5:e9:c4: + ec:0e:e9:8e:3c:2d:5c:7b:59:20:5b:24:92:a0:e0:1e:a3:5a: + 67:d8:ff:7f:a5:82:f1:df:db:05:65:79:88:b1:3c:e6:01:d1: + 5a:c7:d2:6e:9a:e6:a2:da:4a:c7:19:78:d9:14:71:6e:1f:70: + f3:41:e5:b3:78:31:d5:22:0e:7c:1a:b2:43:d9:86:ff:53:ea: + 2b:ba:d2:27 +-----BEGIN CERTIFICATE----- +MIIDhDCCAmygAwIBAgIUMu0hVthOqgOJqUqk4oUtijsriSIwDQYJKoZIhvcNAQEL +BQAwWjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAoT +CU9wZW5SZXN0eTEiMCAGA1UEAxMZT3BlblJlc3R5IFRlc3RpbmcgUm9vdCBDQTAe +Fw0yMjAzMTMxNTQ5MDBaFw00MjAzMDgxNTQ5MDBaMFoxCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQKEwlPcGVuUmVzdHkxIjAgBgNVBAMT +GU9wZW5SZXN0eSBUZXN0aW5nIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDmN9LGFzbHsn99z9Bih5nZIbje/9jiOhxokI/OF2gisGAwzCno +NO7/siXebhrU3xAZEUtAYdOpTYDtl4FOxXToTWPjXyG8Wm4ioBeRwcslU5udTuFR +W/ZS5won9hbCMctsR/SJURXMBr4xPhzq7oGbxJeW/eUclZ7AZc2pmstoZ/JioCHr +WsWhku0yQSj5RzTrRK7W53ZxEZjJLs5sfBAbx0zDFIlO2UzZx0PpPCnKYqmRs4fn +17QYq2X5a+2CyqE2NRgFy1wkJhMT+Jmsmb6bpnPfDRaVsdy+/nrCttzIk88Q4CkD +Dih4GITuFJKrvlqgFKJKL9PQuA4A0lrN5L2hAgMBAAGjQjBAMA4GA1UdDwEB/wQE +AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTw10sUc+FnAGtUtBkgdhKf +nY7ICTANBgkqhkiG9w0BAQsFAAOCAQEAbVIhbW6M5UooB2Vt2HwjLsbB0Owns7DD +0+j6crneMk7/l42GqW2zqbQtd8ool2o9e6IV7TTccp9v5wEM0yhqgBtQCf3XLNiS +1RDEcxUgfZnc3jB7PG7pZrIOThrBUVduW7Cp9v8LjwdnMUBbEakG09N2xdJWlZqe +ShZESzLlr91LTV1XuIVpNpMqxgyP4UI1vo7z5zXTLDoDMUB1jujdVzUgXhipds6F +vn46z24IWFtH1enE7A7pjjwtXHtZIFskkqDgHqNaZ9j/f6WC8d/bBWV5iLE85gHR +WsfSbprmotpKxxl42RRxbh9w80Hls3gx1SIOfBqyQ9mG/1PqK7rSJw== +-----END CERTIFICATE----- diff --git a/t/cert/mtls_ca.key b/t/cert/mtls_ca.key new file mode 100644 index 0000000000..d39b42f9d9 --- /dev/null +++ b/t/cert/mtls_ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA5jfSxhc2x7J/fc/QYoeZ2SG43v/Y4jocaJCPzhdoIrBgMMwp +6DTu/7Il3m4a1N8QGRFLQGHTqU2A7ZeBTsV06E1j418hvFpuIqAXkcHLJVObnU7h +UVv2UucKJ/YWwjHLbEf0iVEVzAa+MT4c6u6Bm8SXlv3lHJWewGXNqZrLaGfyYqAh +61rFoZLtMkEo+Uc060Su1ud2cRGYyS7ObHwQG8dMwxSJTtlM2cdD6TwpymKpkbOH +59e0GKtl+WvtgsqhNjUYBctcJCYTE/iZrJm+m6Zz3w0WlbHcvv56wrbcyJPPEOAp +Aw4oeBiE7hSSq75aoBSiSi/T0LgOANJazeS9oQIDAQABAoIBAQDhH9+uNE8uUv/X +MNvvLfklWpOlBf25o+fZ3NuzRjJgEafOsCee2fyI8FWVwIfeeE8OpFm5GLDZk1+r +dwdM10xuSheO5Z1gyfF/TJwfvamA09SNrPArFkm3YhUNZNl2hykMtwSLL06oWEOu +dbXjit4VS9aNIbTlEe7O5/6Ih0W3zmr1yvUua2swmAZMx3GFA4kbjZZ9vDs27sdu +K+VY3DYRbq1HkiNFT0otfke5bObFBCG7Yp8JLyhYaIkGYFoBXuZ6JNY8EuU2+YyP +6r40tJ7StR1Q6eZJh9/1leaYGZLCh5oFyKpilTuxHbRbr5A28RJKjKvPsdDgTtQn +yHGg70FRAoGBAOhC3TQlFcT2WCCZHHql9JEEHnHVBWnL3Jg7VJuL1i6pEIz7qQkW +AtBEIY/nnTcVNfJ6eXznYtutYvvRSgQTUsBNRoj3s1z9wKOo4uw4LoIUXDEmHCr+ +49DiQyIO21SNMHA+dVxvGRDDjLI9Uc+Scb64QOodoX75HLRZG++24mtdAoGBAP2/ +gCjga2p8Jx9UnhIcrEIIGANyxEQeBdhF56Nt9CJy/Iwi3a6qQ/GkbeoDm5FhXnXo +xcBaHyv2lwi4uO/hONY8eRnYxAWMwAKMZe6VnU1hWI2Ytkh+OcMPMh7NIGQf6X1o +JZrBtnTms060TuuDjLeIlaubDR/xDrMWTMKjKbsVAoGAVLuYAZ8J6xpIGlRhbGlA +6OrMxJCHcgpahvsWKc0BLXKmRBjHmTX7fslsSRihZWgKj1SZH7U2fpgpxV6cFxKJ +nPhUJEHhoKo+bjZ92tnANdqBq7iQjCsDJ8Bz52fuIlGD+1795+PsDA6bNKdkQkrV +zlNf80kuEqmFDFJ5+6EHx00CgYAf+jkpbZa71aeMgDpnZ+uhaqm0DYuEVhBAgBa/ +9sRUbw86jc5IC7cCRcmAOzIosQ+ZZls9cV4KSUohVD4iJMzn2rkcM8AIPwOXjp/t +4DbxoHnrZjpaimW3Gjwju5AAbjEbl7tddFoNA2HHYlurvGlIW9MYzDJsOxGyKfZE +dRF2PQKBgQDUKNHgDYEjLJ99S5Fm5zN/64bKzzDtktGdqOxik5pBKcs/BvOdLM0i +eCjGz/3qrEoenFIBwF/IRz3ug90Zr8bWOu6DudReflAKI/N13dZ2gOTAfaX4ljJF +w0ohSi6xs+mu1GmtipGtNxHi/J3na2BeSnSRFSUg6Zd+oh8BZQKmNg== +-----END RSA PRIVATE KEY----- diff --git a/t/cert/mtls_cert_gen/.gitignore b/t/cert/mtls_cert_gen/.gitignore new file mode 100644 index 0000000000..f375caaefe --- /dev/null +++ b/t/cert/mtls_cert_gen/.gitignore @@ -0,0 +1,4 @@ +*.pem +*.csr +cfssl +cfssljson diff --git a/t/cert/mtls_cert_gen/generate.sh b/t/cert/mtls_cert_gen/generate.sh new file mode 100755 index 0000000000..46625fdd07 --- /dev/null +++ b/t/cert/mtls_cert_gen/generate.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +rm *.pem *.csr cfssl cfssljson + +wget -O cfssl https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64 +wget -O cfssljson https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64 +chmod +x cfssl cfssljson + +./cfssl gencert -initca -config profile.json mtls_ca.json | ./cfssljson -bare mtls_ca + +./cfssl gencert -ca mtls_ca.pem -ca-key mtls_ca-key.pem -config profile.json -profile=client mtls_client.json | ./cfssljson -bare mtls_client +./cfssl gencert -ca mtls_ca.pem -ca-key mtls_ca-key.pem -config profile.json -profile=server mtls_server.json | ./cfssljson -bare mtls_server + +openssl x509 -in mtls_ca.pem -text > ../mtls_ca.crt +mv mtls_ca-key.pem ../mtls_ca.key + +openssl x509 -in mtls_client.pem -text > ../mtls_client.crt +mv mtls_client-key.pem ../mtls_client.key + +openssl x509 -in mtls_server.pem -text > ../mtls_server.crt +mv mtls_server-key.pem ../mtls_server.key + +rm *.pem *.csr cfssl cfssljson diff --git a/t/cert/mtls_cert_gen/mtls_ca.json b/t/cert/mtls_cert_gen/mtls_ca.json new file mode 100644 index 0000000000..0a4a7ab139 --- /dev/null +++ b/t/cert/mtls_cert_gen/mtls_ca.json @@ -0,0 +1,18 @@ +{ + "CA": { + "expiry": "175200h", + "pathlen": 0 + }, + "CN": "OpenResty Testing Root CA", + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "C": "US", + "O": "OpenResty", + "ST": "California" + } + ] +} diff --git a/t/cert/mtls_cert_gen/mtls_client.json b/t/cert/mtls_cert_gen/mtls_client.json new file mode 100644 index 0000000000..4d59f47a5b --- /dev/null +++ b/t/cert/mtls_cert_gen/mtls_client.json @@ -0,0 +1,18 @@ +{ + "CN": "foo@example.com", + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "C": "US", + "O": "OpenResty", + "ST": "California" + } + ], + "hosts": [ + "foo@example.com", + "bar@example.com" + ] +} diff --git a/t/cert/mtls_cert_gen/mtls_server.json b/t/cert/mtls_cert_gen/mtls_server.json new file mode 100644 index 0000000000..655af54ef8 --- /dev/null +++ b/t/cert/mtls_cert_gen/mtls_server.json @@ -0,0 +1,17 @@ +{ + "CN": "example.com", + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "C": "US", + "O": "OpenResty", + "ST": "California" + } + ], + "hosts": [ + "example.com" + ] +} diff --git a/t/cert/mtls_cert_gen/profile.json b/t/cert/mtls_cert_gen/profile.json new file mode 100644 index 0000000000..d3b6ab16cb --- /dev/null +++ b/t/cert/mtls_cert_gen/profile.json @@ -0,0 +1,27 @@ +{ + "signing": { + "default": { + "expiry": "175200h" + }, + "profiles": { + "server": { + "usages": [ + "signing", + "digital signing", + "key encipherment", + "server auth" + ], + "expiry": "175199h" + }, + "client": { + "usages": [ + "signing", + "digital signature", + "key encipherment", + "client auth" + ], + "expiry": "175199h" + } + } + } +} diff --git a/t/cert/mtls_client.crt b/t/cert/mtls_client.crt new file mode 100644 index 0000000000..dd0efdf7f8 --- /dev/null +++ b/t/cert/mtls_client.crt @@ -0,0 +1,87 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 19:0a:a3:a8:9c:d4:0f:dc:c6:fa:23:7b:f8:fc:bd:f4:73:4e:7e:b1 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA + Validity + Not Before: Mar 13 15:49:00 2022 GMT + Not After : Mar 8 14:49:00 2042 GMT + Subject: C = US, ST = California, O = OpenResty, CN = foo@example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:be:5b:09:4c:94:71:d3:82:54:4a:42:6a:76:aa: + 34:5d:28:d9:45:e6:44:9a:74:9f:a6:e6:78:49:9e: + c6:20:75:32:5f:92:3b:ec:6e:4b:7b:b0:75:1c:75: + 09:00:05:77:d6:59:ca:55:5b:13:b6:76:3a:c6:18: + dc:37:6a:20:93:e6:26:56:5d:0b:96:8c:01:f2:96: + 38:08:08:36:a2:64:12:21:a0:8d:48:cd:9a:26:78: + 92:29:b6:63:eb:14:d9:b6:e5:87:f7:d5:55:a4:cc: + 53:1c:a3:7c:b8:bd:ad:7c:a4:d4:86:1f:a7:1c:43: + c5:1a:b5:f1:03:bd:fe:19:98:1d:b7:13:2b:93:a2: + 2a:0e:21:7e:42:a9:bb:28:69:49:59:e7:89:0e:7d: + 5a:ce:fb:d4:0c:20:6a:e1:db:b2:6a:e5:a7:55:e0: + d0:58:4a:e2:08:78:82:b9:06:0c:65:f9:24:06:e6: + 8a:13:b2:9a:ef:1b:4a:b2:3a:b4:98:7f:dd:3c:0e: + 85:0b:a6:c6:47:2f:63:c2:73:52:41:db:7c:06:c3: + 2a:b5:2d:d1:e1:30:d5:c4:79:c9:b9:35:68:46:ad: + c4:45:57:ea:11:88:27:37:ed:ac:49:2d:c4:d6:c6: + a6:74:8d:d3:bc:e0:d9:69:25:0c:0c:b0:e3:b7:cb: + 8d:99 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 22:70:5E:30:8C:4D:66:39:E7:60:C9:29:A2:ED:95:32:34:63:5C:C0 + X509v3 Authority Key Identifier: + keyid:F0:D7:4B:14:73:E1:67:00:6B:54:B4:19:20:76:12:9F:9D:8E:C8:09 + + X509v3 Subject Alternative Name: + email:foo@example.com, email:bar@example.com + Signature Algorithm: sha256WithRSAEncryption + 96:e7:2a:fc:2a:56:16:80:e2:d3:79:0c:46:db:c3:88:ab:d3: + ef:39:66:4b:a9:ab:6c:0e:30:08:07:7c:fc:03:6c:f7:dd:fb: + 3e:a8:c8:68:28:ab:4e:73:97:80:27:5d:c5:9d:52:00:aa:08: + 25:c8:f9:dc:df:64:73:a4:58:5b:bd:5f:1a:53:a4:33:a3:b1: + 45:38:2d:be:d7:f3:a4:c4:f4:7a:07:71:44:f1:a2:65:02:e4: + 71:84:01:b5:83:4b:de:83:b5:ad:ac:b9:3c:17:42:0c:9a:7d: + eb:7f:ab:26:dd:9b:3a:fd:95:37:55:cc:01:c3:3f:20:df:e5: + ed:49:51:7a:42:ea:f3:8a:3f:da:6e:c1:1a:11:b9:45:4d:6e: + c9:21:f4:e3:4f:31:72:5b:bb:01:92:b6:7f:f1:8a:9e:6c:d0: + 7f:96:d7:eb:29:09:53:38:26:41:00:f2:33:04:77:bd:a9:ee: + 60:9e:06:b7:7d:26:ae:1c:4f:56:bd:a5:b6:50:40:be:be:84: + 2a:54:21:59:47:7d:a5:1e:63:6d:28:36:4d:a6:e4:62:69:9b: + 9b:fa:2b:48:e8:64:d7:14:f4:62:a2:26:17:a5:05:58:4a:38: + d2:44:e7:33:90:b9:c1:8c:85:02:99:b8:03:1a:03:d2:cf:ac: + a5:6b:44:98 +-----BEGIN CERTIFICATE----- +MIID3DCCAsSgAwIBAgIUGQqjqJzUD9zG+iN7+Py99HNOfrEwDQYJKoZIhvcNAQEL +BQAwWjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAoT +CU9wZW5SZXN0eTEiMCAGA1UEAxMZT3BlblJlc3R5IFRlc3RpbmcgUm9vdCBDQTAe +Fw0yMjAzMTMxNTQ5MDBaFw00MjAzMDgxNDQ5MDBaMFAxCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQKEwlPcGVuUmVzdHkxGDAWBgNVBAMM +D2Zvb0BleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AL5bCUyUcdOCVEpCanaqNF0o2UXmRJp0n6bmeEmexiB1Ml+SO+xuS3uwdRx1CQAF +d9ZZylVbE7Z2OsYY3DdqIJPmJlZdC5aMAfKWOAgINqJkEiGgjUjNmiZ4kim2Y+sU +2bblh/fVVaTMUxyjfLi9rXyk1IYfpxxDxRq18QO9/hmYHbcTK5OiKg4hfkKpuyhp +SVnniQ59Ws771AwgauHbsmrlp1Xg0FhK4gh4grkGDGX5JAbmihOymu8bSrI6tJh/ +3TwOhQumxkcvY8JzUkHbfAbDKrUt0eEw1cR5ybk1aEatxEVX6hGIJzftrEktxNbG +pnSN07zg2WklDAyw47fLjZkCAwEAAaOBozCBoDAOBgNVHQ8BAf8EBAMCBaAwEwYD +VR0lBAwwCgYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUInBeMIxN +ZjnnYMkpou2VMjRjXMAwHwYDVR0jBBgwFoAU8NdLFHPhZwBrVLQZIHYSn52OyAkw +KwYDVR0RBCQwIoEPZm9vQGV4YW1wbGUuY29tgQ9iYXJAZXhhbXBsZS5jb20wDQYJ +KoZIhvcNAQELBQADggEBAJbnKvwqVhaA4tN5DEbbw4ir0+85Zkupq2wOMAgHfPwD +bPfd+z6oyGgoq05zl4AnXcWdUgCqCCXI+dzfZHOkWFu9XxpTpDOjsUU4Lb7X86TE +9HoHcUTxomUC5HGEAbWDS96Dta2suTwXQgyafet/qybdmzr9lTdVzAHDPyDf5e1J +UXpC6vOKP9puwRoRuUVNbskh9ONPMXJbuwGStn/xip5s0H+W1+spCVM4JkEA8jME +d72p7mCeBrd9Jq4cT1a9pbZQQL6+hCpUIVlHfaUeY20oNk2m5GJpm5v6K0joZNcU +9GKiJhelBVhKONJE5zOQucGMhQKZuAMaA9LPrKVrRJg= +-----END CERTIFICATE----- diff --git a/t/cert/mtls_client.key b/t/cert/mtls_client.key new file mode 100644 index 0000000000..7d77e5506d --- /dev/null +++ b/t/cert/mtls_client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAvlsJTJRx04JUSkJqdqo0XSjZReZEmnSfpuZ4SZ7GIHUyX5I7 +7G5Le7B1HHUJAAV31lnKVVsTtnY6xhjcN2ogk+YmVl0LlowB8pY4CAg2omQSIaCN +SM2aJniSKbZj6xTZtuWH99VVpMxTHKN8uL2tfKTUhh+nHEPFGrXxA73+GZgdtxMr +k6IqDiF+Qqm7KGlJWeeJDn1azvvUDCBq4duyauWnVeDQWEriCHiCuQYMZfkkBuaK +E7Ka7xtKsjq0mH/dPA6FC6bGRy9jwnNSQdt8BsMqtS3R4TDVxHnJuTVoRq3ERVfq +EYgnN+2sSS3E1samdI3TvODZaSUMDLDjt8uNmQIDAQABAoIBACqRsUKu78WdH7x7 +ndNrvMoYmH5JQI5KBmoMoFnWZ/haPSmiSkRVZgwDKi1y/tBCaMpGyjjMZVwolHw4 +kwbRdPeeQHSP2keQh974OQ+SxqUKPAPJI89kK1TvIcCySSYJQ6bjLcT+sGhqSSve +Y8XspR96vQxBh92KSknu5jcwBeMy/eG0mmszzP3y2R0BPztuZdE6dq/KxWQ/R4/P +JG9V1rNkIY+1JZvIICIH1Ehn4UKjiE+FJmyDbDlPKEi7W4CpRnShMLOF4cCFnQLW +RQds3Dj9GcVY+8Q/GLZF0ATjekIyEsKZEgrMAUF5ZSGRpjJQEHX7oseAiQGQxtHT +nj5b1AECgYEAwewXbbd1MqRQ6ohfsQ8j5HSMY6ahvUzs1dZUckr2jw8B98tfi/uj +a6Jq1KZe12+4dfwruRSaYdTsSVuvNiSJOxElY0C1p+lXdprFf7XfoQ6UNtg22jcH +9f8cftnlJoV5whh3YKjqnnnAWUQZ61FTNJ258/t+x0ZgpBJvqBoHwDUCgYEA+0qp +FZ5xS4FLJMc+Xf/hUeXo+04e4OD/se3atYqyuh1ghmQZfRRPOC110HG99H+rzq/x +xPMvRFahkAMyi+/3oIcBEuXvoQyqscIsAhkWD/e9t3Qc9OsWe1hlAgWKZxr6oR2U +KKR1FD7UVecOH+FKCKaL5UpEt4yEigc1NtSlTFUCgYBnV5agrIyzQSex5J0CMWxS +Od362PkGdXEc/8we4F4GnNvSnrm7Uo2jNXmy+zo9mtb1YT43sogXLK4C5e44bz4G +kTuYagqkgdBPb2lihpy3KprHo2+P2JXQfXRFEX9xiN37Fqi/hSUK8R0VNRqO8dbi +ik9nexXzwkiMBxsjvUN2JQKBgFy62FpZ9YTfWVNhEuqtGgCWzrqtwUdKwBBwrVyA +qiNz48Kz/ZPigrlATVF2J5qp4kSLOLRs6OxW65exFl39V2utZgALSbosanDeLk83 +4qRRz3h7KJRYjBtIKz3rvX7+va3mtF2rEmk+Jizs7pFlGWTH0Kf0GBeDiwVEU6bA +IZ9hAoGAQTjnRGMjvyhq0aPYP+mRFiMKSkcL1nyXizYInfAnbfbL/uEODH7D+iMf +kak+UgmeD9ce5d/APmZp3/FzYH/M8ivBgG+MnaI+MLVMhmQdLZyMtbSKKaDpiim7 +DdN1wCXYbur0HlO2t+wemMZPpQu7wybgEOLlIG7Yj/0OWDcal1c= +-----END RSA PRIVATE KEY----- diff --git a/t/cert/mtls_server.crt b/t/cert/mtls_server.crt new file mode 100644 index 0000000000..7cbc2a804b --- /dev/null +++ b/t/cert/mtls_server.crt @@ -0,0 +1,87 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2f:d5:41:13:5a:ff:c7:1c:5b:ce:28:cd:a6:f7:a5:5a:0d:c0:e2:d2 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA + Validity + Not Before: Mar 13 15:49:00 2022 GMT + Not After : Mar 8 14:49:00 2042 GMT + Subject: C = US, ST = California, O = OpenResty, CN = example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d7:03:80:a7:42:7d:06:5a:7b:70:d8:11:96:dd: + 63:35:53:07:28:71:52:05:40:55:83:61:a7:14:ac: + cf:4b:9b:ab:b7:4e:9d:79:e9:13:3d:bc:c3:67:8f: + dd:88:d9:8b:c2:31:aa:b8:28:9e:13:70:db:76:b0: + 12:1c:f8:35:c6:2e:33:9c:b9:04:e3:47:e0:f9:e4: + 7f:a5:55:03:0c:2d:b2:54:17:29:12:dd:61:6e:5c: + 33:9f:e5:8f:8a:2b:41:53:dc:e1:98:49:63:df:e3: + 00:30:2d:1b:bb:f0:8f:cb:04:ec:c9:98:c4:09:5b: + b4:ba:a9:a0:0a:77:d2:42:76:7c:ac:64:c3:97:85: + 50:5d:7d:02:61:2a:00:93:d0:69:5e:87:22:f0:c1: + 1e:53:46:02:40:37:c9:55:77:99:7d:9d:3d:35:14: + 74:84:e3:73:ca:e7:4a:ab:33:98:26:aa:41:4b:b5: + e6:63:7c:a4:1e:25:6a:88:f4:56:d9:2c:63:dd:89: + 19:fa:25:41:44:95:87:40:a7:9b:4e:3a:91:29:32: + 79:66:05:f4:2f:68:2c:06:53:df:4d:60:be:ac:09: + 20:61:9c:6f:1a:a6:07:5a:e7:41:91:9d:36:77:38: + 18:3a:69:7b:67:29:9f:1d:e0:c2:d2:8f:16:5b:14: + e8:e1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 16:07:B5:C2:4C:B5:2D:4F:B8:E9:D6:FA:2F:3F:C0:1B:B6:4F:20:E6 + X509v3 Authority Key Identifier: + keyid:F0:D7:4B:14:73:E1:67:00:6B:54:B4:19:20:76:12:9F:9D:8E:C8:09 + + X509v3 Subject Alternative Name: + DNS:example.com + Signature Algorithm: sha256WithRSAEncryption + d9:c0:c0:d6:8b:44:04:26:b3:98:24:2c:12:82:6d:15:79:92: + 76:c9:77:94:c1:be:8f:8a:18:78:96:04:68:c9:0a:d1:84:c5: + de:cd:ba:b5:a2:3b:d4:0a:70:be:00:49:19:c0:6e:ca:e9:e5: + 8b:b6:e3:a2:39:0d:d8:ee:55:1a:08:73:39:19:d3:07:07:33: + 8c:d8:1b:0f:1b:73:0e:84:72:cf:e6:c1:a1:da:39:aa:c0:2e: + 3d:b9:a6:8f:ec:98:3a:07:58:34:c2:5e:4c:1a:6b:db:ce:51: + 92:25:1d:ba:78:4b:11:b6:f1:69:02:cb:ac:32:bb:80:f9:15: + 91:bf:4e:6a:ab:51:51:7c:7b:1a:72:80:96:eb:0c:fa:56:0e: + f2:87:3c:16:8a:04:aa:8a:9d:0c:d9:e0:c4:2a:20:42:5a:12: + 41:52:30:50:3d:85:f8:07:31:6b:af:a4:d2:44:38:69:ab:88: + 05:d4:5b:68:34:02:dc:99:5a:6c:b7:ea:fc:79:76:fe:68:29: + df:94:22:58:46:f2:40:cb:e1:92:17:d8:1e:3d:fa:a2:56:4f: + ac:3c:3d:ae:f7:90:12:ac:3b:6c:1e:1f:26:48:08:87:9a:0e: + 8d:9d:75:ef:86:1e:63:ac:e9:14:47:ad:3f:4f:10:57:2a:d1: + 95:ec:6f:24 +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIUL9VBE1r/xxxbzijNpvelWg3A4tIwDQYJKoZIhvcNAQEL +BQAwWjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAoT +CU9wZW5SZXN0eTEiMCAGA1UEAxMZT3BlblJlc3R5IFRlc3RpbmcgUm9vdCBDQTAe +Fw0yMjAzMTMxNTQ5MDBaFw00MjAzMDgxNDQ5MDBaMEwxCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQKEwlPcGVuUmVzdHkxFDASBgNVBAMT +C2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1wOA +p0J9Blp7cNgRlt1jNVMHKHFSBUBVg2GnFKzPS5urt06deekTPbzDZ4/diNmLwjGq +uCieE3DbdrASHPg1xi4znLkE40fg+eR/pVUDDC2yVBcpEt1hblwzn+WPiitBU9zh +mElj3+MAMC0bu/CPywTsyZjECVu0uqmgCnfSQnZ8rGTDl4VQXX0CYSoAk9BpXoci +8MEeU0YCQDfJVXeZfZ09NRR0hONzyudKqzOYJqpBS7XmY3ykHiVqiPRW2Sxj3YkZ ++iVBRJWHQKebTjqRKTJ5ZgX0L2gsBlPfTWC+rAkgYZxvGqYHWudBkZ02dzgYOml7 +ZymfHeDC0o8WWxTo4QIDAQABo4GOMIGLMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE +DDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQWB7XCTLUtT7jp +1vovP8Abtk8g5jAfBgNVHSMEGDAWgBTw10sUc+FnAGtUtBkgdhKfnY7ICTAWBgNV +HREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA2cDA1otEBCaz +mCQsEoJtFXmSdsl3lMG+j4oYeJYEaMkK0YTF3s26taI71ApwvgBJGcBuyunli7bj +ojkN2O5VGghzORnTBwczjNgbDxtzDoRyz+bBodo5qsAuPbmmj+yYOgdYNMJeTBpr +285RkiUdunhLEbbxaQLLrDK7gPkVkb9OaqtRUXx7GnKAlusM+lYO8oc8FooEqoqd +DNngxCogQloSQVIwUD2F+Acxa6+k0kQ4aauIBdRbaDQC3JlabLfq/Hl2/mgp35Qi +WEbyQMvhkhfYHj36olZPrDw9rveQEqw7bB4fJkgIh5oOjZ1174YeY6zpFEetP08Q +VyrRlexvJA== +-----END CERTIFICATE----- diff --git a/t/cert/mtls_server.key b/t/cert/mtls_server.key new file mode 100644 index 0000000000..f5b85d18d8 --- /dev/null +++ b/t/cert/mtls_server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA1wOAp0J9Blp7cNgRlt1jNVMHKHFSBUBVg2GnFKzPS5urt06d +eekTPbzDZ4/diNmLwjGquCieE3DbdrASHPg1xi4znLkE40fg+eR/pVUDDC2yVBcp +Et1hblwzn+WPiitBU9zhmElj3+MAMC0bu/CPywTsyZjECVu0uqmgCnfSQnZ8rGTD +l4VQXX0CYSoAk9BpXoci8MEeU0YCQDfJVXeZfZ09NRR0hONzyudKqzOYJqpBS7Xm +Y3ykHiVqiPRW2Sxj3YkZ+iVBRJWHQKebTjqRKTJ5ZgX0L2gsBlPfTWC+rAkgYZxv +GqYHWudBkZ02dzgYOml7ZymfHeDC0o8WWxTo4QIDAQABAoIBAEnmZUiXnJsbbEPr +r5f3vYptYA9xa2xsoTeHz8JWZuUouwtE1PE6v6c/grXMh6rqgpObOH8VTseFyZhw +ibk1Ql48MPcTzG9FnDinZYvwvRxpdFpcn3xhZIRm4kN5xi0KEuj9CPireM1RmxXz +2w1scC+qIKxlejNxNpvVgzE136mBqEFKJzecP+yZuH/A86MQCgwqqa3jSz5ApNg+ +1aJE34cGFieDbAN+9sdqWA3OkRrHoy8EakUf4JEvwX1AwUN832mj+N/LfmcCGMeD +YhzybzlPBV2q2T1+pHIdNT99JVNPkgdTe1903EjnG5oSDGHt2i9MdnNkMsffDWNt +pJiqSHECgYEA2hL6l8Py4oa5AJ2WXriuHRJykAs90K0akftQt4i4lWCbeRhaGh7h +kPgpDS33RkE4SymVVr0c05abMCKabQBwbu4PNCqetCFtfmIQdQCTUbLbXjL8UuD2 +QnF7nbHiwyGBKRMU/F74oX3z7lXLgRtIiyyo5yYgIAQqpz3oJAaXNTUCgYEA/GhE +Ziez8FXVAg3XwwrE3SexRFKv1JqipYE4mr+ouzfpn9yn8mttxbOORiAAEBl3ZPhd +ZUBzLy19fdFZ8RJ0zPsqoZxsd09/XetaBU56C/g9u0fycj1L2elh9rQAlOW0Grus +l8jBh01TGtlg0xobK0zjwdGPcbYkp1IzIqyD9n0CgYEAicBvVyrJ5FnhxwfEkrTq +FycuAtt3Arg2DnzH8geFQaayzv2Y/OMA7Yg0tkSQ7GoKW0A7O31eFjIOeYuCLNSY +MRpjtDov4e0zsx/S8XWZmYP3mjtutBOyuyngQi655TTm18FcAkcjmy9qxOShFj7b +xj5BuzGUHWVEZDxwxUD8hvkCgYBnrcyqyZQ4HImqllUSYNIMpclC71QaWIqGwVWm ++yMsBAOLDvBNu6MTmnXOiEZ+VnecmgiDFr45ms35aI0xYQtpR6JzT/Wd7KG8ynfn +xhyL3iQ9UYhdNKB7mkoLNFUo1FHuyThUALq+AR0p4jDLheWzG5pSeuoZI2Ba+oDW +tVZfYQKBgC5phtERR5LKU5Wkzm+uY2j+Nzh4kuKkdLosB9pUW8VnrwFDLZ+r1CxG +L6CxOZ0AylCMIlrFeUXMa91kLDJYch0NUPHuGBkdIBDXi2kqN7GflTdV3Z8uev20 +uMjErA93yVOWHTR3Wo8WIHy5mdsNRQgGAPw1RVW7rnYIyXJW/mTs +-----END RSA PRIVATE KEY-----