diff options
author | Andrey Suvorov <a.suvorov@f5.com> | 2021-05-26 11:19:47 -0700 |
---|---|---|
committer | Andrey Suvorov <a.suvorov@f5.com> | 2021-05-26 11:19:47 -0700 |
commit | 3f7ccf142ff4d1a11b807a344bcb1e3cb6c3284b (patch) | |
tree | 0262e65fe3a943ba90d5e377b7b4c9b4faa42096 | |
parent | 3efffddd95e564fe10f59e1de45afc2b551a5cba (diff) | |
download | unit-3f7ccf142ff4d1a11b807a344bcb1e3cb6c3284b.tar.gz unit-3f7ccf142ff4d1a11b807a344bcb1e3cb6c3284b.tar.bz2 |
Enabling SSL_CTX configuration by using SSL_CONF_cmd().
To perform various configuration operations on SSL_CTX, OpenSSL provides
SSL_CONF_cmd(). Specifically, to configure ciphers for a listener,
"CipherString" and "Ciphersuites" file commands are used:
https://www.openssl.org/docs/man1.1.1/man3/SSL_CONF_cmd.html
This feature can be configured in the "tls/conf_commands" section.
-rw-r--r-- | auto/ssltls | 14 | ||||
-rw-r--r-- | docs/changes.xml | 6 | ||||
-rw-r--r-- | src/nxt_conf_validation.c | 46 | ||||
-rw-r--r-- | src/nxt_openssl.c | 114 | ||||
-rw-r--r-- | src/nxt_router.c | 90 | ||||
-rw-r--r-- | src/nxt_tls.h | 6 |
6 files changed, 215 insertions, 61 deletions
diff --git a/auto/ssltls b/auto/ssltls index f034b758..f9363dde 100644 --- a/auto/ssltls +++ b/auto/ssltls @@ -52,6 +52,20 @@ if [ $NXT_OPENSSL = YES ]; then $echo exit 1; fi + + + nxt_feature="OpenSSL SSL_CONF_cmd()" + nxt_feature_name=NXT_HAVE_OPENSSL_CONF_CMD + nxt_feature_run= + nxt_feature_incs= + nxt_feature_libs="$NXT_OPENSSL_LIBS" + nxt_feature_test="#include <openssl/ssl.h> + + int main() { + SSL_CONF_cmd(NULL, NULL, NULL); + return 0; + }" + . auto/feature fi diff --git a/docs/changes.xml b/docs/changes.xml index cbe6269a..2dcaf4dd 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -39,6 +39,12 @@ PHP added to the default MIME type list. <change type="feature"> <para> +arbitrary configuration of TLS connections via OpenSSL commands. +</para> +</change> + +<change type="feature"> +<para> multiple "targets" in Python applications. </para> </change> diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index 14066fb0..06ae2847 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -89,6 +89,10 @@ static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, #if (NXT_TLS) static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); +#if (NXT_HAVE_OPENSSL_CONF_CMD) +static nxt_int_t nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value, void *data); +#endif static nxt_int_t nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, nxt_conf_value_t *value); #endif @@ -363,7 +367,17 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = { { .name = nxt_string("certificate"), .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, + .flags = NXT_CONF_VLDT_REQUIRED, .validator = nxt_conf_vldt_certificate, + }, { + .name = nxt_string("conf_commands"), + .type = NXT_CONF_VLDT_OBJECT, +#if (NXT_HAVE_OPENSSL_CONF_CMD) + .validator = nxt_conf_vldt_object_conf_commands, +#else + .validator = nxt_conf_vldt_unsupported, + .u.string = "conf_commands", +#endif }, NXT_CONF_VLDT_END @@ -1971,6 +1985,38 @@ nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, return NXT_OK; } + +#if (NXT_HAVE_OPENSSL_CONF_CMD) + +static nxt_int_t +nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value, void *data) +{ + uint32_t index; + nxt_int_t ret; + nxt_str_t name; + nxt_conf_value_t *member; + + index = 0; + + for ( ;; ) { + member = nxt_conf_next_object_member(value, &name, &index); + + if (member == NULL) { + break; + } + + ret = nxt_conf_vldt_type(vldt, &name, member, NXT_CONF_VLDT_STRING); + if (ret != NXT_OK) { + return ret; + } + } + + return NXT_OK; +} + +#endif + #endif diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c index af4dc24a..2fd5d1bf 100644 --- a/src/nxt_openssl.c +++ b/src/nxt_openssl.c @@ -5,6 +5,7 @@ */ #include <nxt_main.h> +#include <nxt_conf.h> #include <openssl/ssl.h> #include <openssl/conf.h> #include <openssl/err.h> @@ -42,9 +43,14 @@ static unsigned long nxt_openssl_thread_id(void); static void nxt_openssl_locks_free(void); #endif static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, - nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t last); + nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_conf_value_t *conf_cmds, + nxt_bool_t last); static nxt_int_t nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t single); +#if (NXT_HAVE_OPENSSL_CONF_CMD) +static nxt_int_t nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, + nxt_conf_value_t *value, nxt_mp_t *mp); +#endif static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf, nxt_mp_t *mp); static nxt_int_t nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, @@ -260,7 +266,7 @@ nxt_openssl_locks_free(void) static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf, - nxt_mp_t *mp, nxt_bool_t last) + nxt_mp_t *mp, nxt_conf_value_t *conf_cmds, nxt_bool_t last) { SSL_CTX *ctx; const char *ciphers, *ca_certificate; @@ -320,6 +326,7 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf, goto fail; } */ + ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5"; if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { @@ -329,6 +336,14 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf, goto fail; } +#if (NXT_HAVE_OPENSSL_CONF_CMD) + if (conf_cmds != NULL + && nxt_ssl_conf_commands(task, ctx, conf_cmds, mp) != NXT_OK) + { + goto fail; + } +#endif + SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); if (conf->ca_certificate != NULL) { @@ -484,6 +499,89 @@ clean: } +#if (NXT_HAVE_OPENSSL_CONF_CMD) + +static nxt_int_t +nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, nxt_conf_value_t *conf, + nxt_mp_t *mp) +{ + int ret; + char *zcmd, *zvalue; + uint32_t index; + nxt_str_t cmd, value; + SSL_CONF_CTX *cctx; + nxt_conf_value_t *member; + + cctx = SSL_CONF_CTX_new(); + if (nxt_slow_path(cctx == NULL)) { + nxt_openssl_log_error(task, NXT_LOG_ALERT, + "SSL_CONF_CTX_new() failed"); + return NXT_ERROR; + } + + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE + | SSL_CONF_FLAG_SERVER + | SSL_CONF_FLAG_CERTIFICATE + | SSL_CONF_FLAG_SHOW_ERRORS); + + SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); + + index = 0; + + for ( ;; ) { + member = nxt_conf_next_object_member(conf, &cmd, &index); + if (nxt_slow_path(member == NULL)) { + break; + } + + nxt_conf_get_string(member, &value); + + zcmd = nxt_str_cstrz(mp, &cmd); + zvalue = nxt_str_cstrz(mp, &value); + + if (nxt_slow_path(zcmd == NULL || zvalue == NULL)) { + goto fail; + } + + ret = SSL_CONF_cmd(cctx, zcmd, zvalue); + if (ret == -2) { + nxt_openssl_log_error(task, NXT_LOG_ERR, + "unknown command \"%s\" in " + "\"conf_commands\" option", zcmd); + goto fail; + } + + if (ret <= 0) { + nxt_openssl_log_error(task, NXT_LOG_ERR, + "invalid value \"%s\" for command \"%s\" " + "in \"conf_commands\" option", + zvalue, zcmd); + goto fail; + } + + nxt_debug(task, "SSL_CONF_cmd(\"%s\", \"%s\")", zcmd, zvalue); + } + + if (SSL_CONF_CTX_finish(cctx) != 1) { + nxt_openssl_log_error(task, NXT_LOG_ALERT, + "SSL_CONF_finish() failed"); + goto fail; + } + + SSL_CONF_CTX_free(cctx); + + return NXT_OK; + +fail: + + SSL_CONF_CTX_free(cctx); + + return NXT_ERROR; +} + +#endif + + static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf, nxt_mp_t *mp) @@ -550,7 +648,7 @@ nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf, NULL, 0); if (len <= 0) { nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither " - "Subject Alternative Name nor Common Name", bundle->name); + "Subject Alternative Name nor Common Name", &bundle->name); return NXT_OK; } @@ -629,7 +727,7 @@ nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, if (item->name.length == 0 || item->name.start[0] != '.') { nxt_log(task, NXT_LOG_WARN, "ignored invalid name \"%V\" " "in certificate \"%V\": missing \".\" " - "after wildcard symbol", &str, item->bundle->name); + "after wildcard symbol", &str, &item->bundle->name); return NXT_OK; } } @@ -644,7 +742,7 @@ nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, ret = nxt_lvlhsh_insert(lvlhsh, &lhq); if (nxt_fast_path(ret == NXT_OK)) { nxt_debug(task, "name \"%V\" for certificate \"%V\" is inserted", - &str, item->bundle->name); + &str, &item->bundle->name); return NXT_OK; } @@ -653,7 +751,7 @@ nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, if (old->bundle != item->bundle) { nxt_log(task, NXT_LOG_WARN, "ignored duplicate name \"%V\" " "in certificate \"%V\", identical name appears in \"%V\"", - &str, old->bundle->name, item->bundle->name); + &str, &old->bundle->name, &item->bundle->name); old->bundle = item->bundle; } @@ -730,8 +828,8 @@ nxt_openssl_servername(SSL *s, int *ad, void *arg) if (bundle != NULL) { nxt_debug(c->socket.task, "new tls context found for \"%V\": \"%V\" " - "(old: \"%V\")", &str, bundle->name, - conf->bundle->name); + "(old: \"%V\")", &str, &bundle->name, + &conf->bundle->name); if (bundle != conf->bundle) { if (SSL_set_SSL_CTX(s, bundle->ctx) == NULL) { diff --git a/src/nxt_router.c b/src/nxt_router.c index 122fd523..015ae226 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -41,8 +41,11 @@ typedef struct { #if (NXT_TLS) typedef struct { - nxt_str_t name; - nxt_socket_conf_t *conf; + nxt_str_t name; + nxt_socket_conf_t *socket_conf; + nxt_router_temp_conf_t *temp_conf; + nxt_conf_value_t *conf_cmds; + nxt_bool_t last; nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */ } nxt_router_tlssock_t; @@ -117,12 +120,11 @@ static void nxt_router_listen_socket_ready(nxt_task_t *task, static void nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data); #if (NXT_TLS) -static void nxt_router_tls_rpc_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls, nxt_bool_t last); static void nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data); static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *value, nxt_socket_conf_t *skcf); + nxt_conf_value_t *value, nxt_socket_conf_t *skcf, + nxt_conf_value_t * conf_cmds); #endif static void nxt_router_app_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_app_t *app); @@ -954,8 +956,10 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link); - nxt_router_tls_rpc_create(task, tmcf, tls, - nxt_queue_is_empty(&tmcf->tls)); + tls->last = nxt_queue_is_empty(&tmcf->tls); + + nxt_cert_store_get(task, &tls->name, tmcf->mem_pool, + nxt_router_tls_rpc_handler, tls); return; } #endif @@ -1337,7 +1341,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_router_t *router; nxt_app_joint_t *app_joint; #if (NXT_TLS) - nxt_conf_value_t *certificate; + nxt_conf_value_t *certificate, *conf_cmds; #endif nxt_conf_value_t *conf, *http, *value, *websocket; nxt_conf_value_t *applications, *application; @@ -1358,6 +1362,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, static nxt_str_t access_log_path = nxt_string("/access_log"); #if (NXT_TLS) static nxt_str_t certificate_path = nxt_string("/tls/certificate"); + static nxt_str_t conf_commands_path = nxt_string("/tls/conf_commands"); #endif static nxt_str_t static_path = nxt_string("/settings/http/static"); static nxt_str_t websocket_path = nxt_string("/settings/http/websocket"); @@ -1736,6 +1741,8 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, certificate = nxt_conf_get_path(listener, &certificate_path); if (certificate != NULL) { + conf_cmds = nxt_conf_get_path(listener, &conf_commands_path); + if (nxt_conf_type(certificate) == NXT_CONF_ARRAY) { n = nxt_conf_array_elements_count(certificate); @@ -1744,7 +1751,8 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_assert(value != NULL); - ret = nxt_router_conf_tls_insert(tmcf, value, skcf); + ret = nxt_router_conf_tls_insert(tmcf, value, skcf, + conf_cmds); if (nxt_slow_path(ret != NXT_OK)) { goto fail; } @@ -1752,7 +1760,8 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, } else { /* NXT_CONF_STRING */ - ret = nxt_router_conf_tls_insert(tmcf, certificate, skcf); + ret = nxt_router_conf_tls_insert(tmcf, certificate, skcf, + conf_cmds); if (nxt_slow_path(ret != NXT_OK)) { goto fail; } @@ -1846,25 +1855,20 @@ fail: static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *value, nxt_socket_conf_t *skcf) + nxt_conf_value_t *value, nxt_socket_conf_t *skcf, + nxt_conf_value_t *conf_cmds) { - nxt_mp_t *mp; - nxt_str_t str; nxt_router_tlssock_t *tls; - mp = tmcf->router_conf->mem_pool; - - tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t)); + tls = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_router_tlssock_t)); if (nxt_slow_path(tls == NULL)) { return NXT_ERROR; } - tls->conf = skcf; - nxt_conf_get_string(value, &str); - - if (nxt_slow_path(nxt_str_dup(mp, &tls->name, &str) == NULL)) { - return NXT_ERROR; - } + tls->socket_conf = skcf; + tls->conf_cmds = conf_cmds; + tls->temp_conf = tmcf; + nxt_conf_get_string(value, &tls->name); nxt_queue_insert_tail(&tmcf->tls, &tls->link); @@ -2428,42 +2432,20 @@ nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, #if (NXT_TLS) static void -nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_router_tlssock_t *tls, nxt_bool_t last) -{ - nxt_socket_rpc_t *rpc; - - rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); - if (rpc == NULL) { - nxt_router_conf_error(task, tmcf); - return; - } - - rpc->name = &tls->name; - rpc->socket_conf = tls->conf; - rpc->temp_conf = tmcf; - rpc->last = last; - - nxt_cert_store_get(task, &tls->name, tmcf->mem_pool, - nxt_router_tls_rpc_handler, rpc); -} - - -static void nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) { nxt_mp_t *mp; nxt_int_t ret; nxt_tls_conf_t *tlscf; - nxt_socket_rpc_t *rpc; + nxt_router_tlssock_t *tls; nxt_tls_bundle_conf_t *bundle; nxt_router_temp_conf_t *tmcf; nxt_debug(task, "tls rpc handler"); - rpc = data; - tmcf = rpc->temp_conf; + tls = data; + tmcf = tls->temp_conf; if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { goto fail; @@ -2471,17 +2453,17 @@ nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, mp = tmcf->router_conf->mem_pool; - if (rpc->socket_conf->tls == NULL){ + if (tls->socket_conf->tls == NULL){ tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); if (nxt_slow_path(tlscf == NULL)) { goto fail; } tlscf->no_wait_shutdown = 1; - rpc->socket_conf->tls = tlscf; + tls->socket_conf->tls = tlscf; } else { - tlscf = rpc->socket_conf->tls; + tlscf = tls->socket_conf->tls; } bundle = nxt_mp_get(mp, sizeof(nxt_tls_bundle_conf_t)); @@ -2489,12 +2471,16 @@ nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, goto fail; } - bundle->name = rpc->name; + if (nxt_slow_path(nxt_str_dup(mp, &bundle->name, &tls->name) == NULL)) { + goto fail; + } + bundle->chain_file = msg->fd[0]; bundle->next = tlscf->bundle; tlscf->bundle = bundle; - ret = task->thread->runtime->tls->server_init(task, tlscf, mp, rpc->last); + ret = task->thread->runtime->tls->server_init(task, tlscf, mp, + tls->conf_cmds, tls->last); if (nxt_slow_path(ret != NXT_OK)) { goto fail; } diff --git a/src/nxt_tls.h b/src/nxt_tls.h index 2a29f3ca..63c49ee4 100644 --- a/src/nxt_tls.h +++ b/src/nxt_tls.h @@ -8,6 +8,9 @@ #define _NXT_TLS_H_INCLUDED_ +#include <nxt_conf.h> + + /* * The SSL/TLS libraries lack vector I/O interface yet add noticeable * overhead to each SSL/TLS record so buffering allows to decrease the @@ -32,6 +35,7 @@ typedef struct { nxt_int_t (*server_init)(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_mp_t *mp, + nxt_conf_value_t *conf_cmds, nxt_bool_t last); void (*server_free)(nxt_task_t *task, nxt_tls_conf_t *conf); @@ -49,7 +53,7 @@ struct nxt_tls_bundle_conf_s { void *ctx; nxt_fd_t chain_file; - nxt_str_t *name; + nxt_str_t name; nxt_tls_bundle_conf_t *next; }; |