diff options
Diffstat (limited to '')
-rw-r--r-- | docs/changes.xml | 7 | ||||
-rw-r--r-- | src/nxt_conf_validation.c | 29 | ||||
-rw-r--r-- | src/nxt_openssl.c | 404 | ||||
-rw-r--r-- | src/nxt_router.c | 123 | ||||
-rw-r--r-- | src/nxt_tls.h | 29 |
5 files changed, 524 insertions, 68 deletions
diff --git a/docs/changes.xml b/docs/changes.xml index 009866bb..cca6bbc4 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -11,6 +11,13 @@ <change type="feature"> <para> +support for multiple certificate bundles on a listener via Server Name +Indication (SNI) TLS extension. +</para> +</change> + +<change type="feature"> +<para> "--mandir" ./configure option to specify the directory for man page installation. </para> </change> diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index 0e6fc135..8c5d1ec7 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -87,6 +87,8 @@ 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); +static nxt_int_t nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value); #endif static nxt_int_t nxt_conf_vldt_action(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); @@ -354,7 +356,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = { { .name = nxt_string("certificate"), - .type = NXT_CONF_VLDT_STRING, + .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, .validator = nxt_conf_vldt_certificate, }, @@ -1827,9 +1829,34 @@ static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data) { + if (nxt_conf_type(value) == NXT_CONF_ARRAY) { + if (nxt_conf_array_elements_count(value) == 0) { + return nxt_conf_vldt_error(vldt, "The \"certificate\" array " + "must contain at least one element."); + } + + return nxt_conf_vldt_array_iterator(vldt, value, + &nxt_conf_vldt_certificate_element); + } + + /* NXT_CONF_STRING */ + + return nxt_conf_vldt_certificate_element(vldt, value); +} + + +static nxt_int_t +nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value) +{ nxt_str_t name; nxt_conf_value_t *cert; + if (nxt_conf_type(value) != NXT_CONF_STRING) { + return nxt_conf_vldt_error(vldt, "The \"certificate\" array must " + "contain only string values."); + } + nxt_conf_get_string(value, &name); cert = nxt_cert_info_get(&name); diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c index 835ca8b2..9b86150f 100644 --- a/src/nxt_openssl.c +++ b/src/nxt_openssl.c @@ -9,17 +9,19 @@ #include <openssl/conf.h> #include <openssl/err.h> #include <openssl/rand.h> +#include <openssl/x509v3.h> typedef struct { - SSL *session; - nxt_conn_t *conn; + SSL *session; + nxt_conn_t *conn; - int ssl_error; - uint8_t times; /* 2 bits */ - uint8_t handshake; /* 1 bit */ + int ssl_error; + uint8_t times; /* 2 bits */ + uint8_t handshake; /* 1 bit */ - nxt_buf_mem_t buffer; + nxt_tls_conf_t *conf; + nxt_buf_mem_t buffer; } nxt_openssl_conn_t; @@ -40,8 +42,18 @@ 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); -static nxt_int_t nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd); + nxt_tls_conf_t *conf, nxt_mp_t *mp, 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); +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, + void *data); +static nxt_int_t nxt_openssl_bundle_hash_insert(nxt_task_t *task, + nxt_lvlhsh_t *lvlhsh, nxt_tls_bundle_hash_item_t *item, nxt_mp_t * mp); +static nxt_int_t nxt_openssl_servername(SSL *s, int *ad, void *arg); +static nxt_tls_bundle_conf_t *nxt_openssl_find_ctx(nxt_tls_conf_t *conf, + nxt_str_t *sn); static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c); @@ -245,12 +257,13 @@ nxt_openssl_locks_free(void) static nxt_int_t -nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) +nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf, + nxt_mp_t *mp, nxt_bool_t last) { - SSL_CTX *ctx; - nxt_fd_t fd; - const char *ciphers, *ca_certificate; - STACK_OF(X509_NAME) *list; + SSL_CTX *ctx; + const char *ciphers, *ca_certificate; + STACK_OF(X509_NAME) *list; + nxt_tls_bundle_conf_t *bundle; ctx = SSL_CTX_new(SSLv23_server_method()); if (ctx == NULL) { @@ -258,8 +271,10 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) return NXT_ERROR; } - conf->ctx = ctx; - conf->conn_init = nxt_openssl_conn_init; + bundle = conf->bundle; + nxt_assert(bundle != NULL); + + bundle->ctx = ctx; #ifdef SSL_OP_NO_RENEGOTIATION /* Renegration is not currently supported. */ @@ -287,11 +302,10 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) #endif - fd = conf->chain_file; - - if (nxt_openssl_chain_file(ctx, fd) != NXT_OK) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "nxt_openssl_chain_file() failed"); + if (nxt_openssl_chain_file(task, ctx, conf, mp, + last && bundle->next == NULL) + != NXT_OK) + { goto fail; } /* @@ -350,6 +364,14 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) SSL_CTX_set_client_CA_list(ctx, list); } + if (last) { + conf->conn_init = nxt_openssl_conn_init; + + if (bundle->next != NULL) { + SSL_CTX_set_tlsext_servername_callback(ctx, nxt_openssl_servername); + } + } + return NXT_OK; fail: @@ -366,22 +388,27 @@ fail: static nxt_int_t -nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd) +nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf, + nxt_mp_t *mp, nxt_bool_t single) { - BIO *bio; - X509 *cert, *ca; - long reason; - EVP_PKEY *key; - nxt_int_t ret; + BIO *bio; + X509 *cert, *ca; + long reason; + EVP_PKEY *key; + nxt_int_t ret; + nxt_tls_bundle_conf_t *bundle; + + ret = NXT_ERROR; + cert = NULL; bio = BIO_new(BIO_s_fd()); if (bio == NULL) { - return NXT_ERROR; + goto end; } - BIO_set_fd(bio, fd, BIO_CLOSE); + bundle = conf->bundle; - ret = NXT_ERROR; + BIO_set_fd(bio, bundle->chain_file, BIO_CLOSE); cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); if (cert == NULL) { @@ -392,6 +419,10 @@ nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd) goto end; } + if (!single && nxt_openssl_cert_get_names(task, cert, conf, mp) != NXT_OK) { + goto clean; + } + for ( ;; ) { ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); @@ -437,17 +468,319 @@ nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd) end: - X509_free(cert); + if (ret != NXT_OK) { + nxt_openssl_log_error(task, NXT_LOG_ALERT, + "nxt_openssl_chain_file() failed"); + } + +clean: + BIO_free(bio); + X509_free(cert); return ret; } +static nxt_uint_t +nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf, + nxt_mp_t *mp) +{ + int len; + nxt_str_t domain, str; + X509_NAME *x509_name; + nxt_uint_t i, n; + GENERAL_NAME *name; + nxt_tls_bundle_conf_t *bundle; + STACK_OF(GENERAL_NAME) *alt_names; + nxt_tls_bundle_hash_item_t *item; + + bundle = conf->bundle; + + alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + + if (alt_names != NULL) { + n = sk_GENERAL_NAME_num(alt_names); + + for (i = 0; i != n; i++) { + name = sk_GENERAL_NAME_value(alt_names, i); + + if (name->type != GEN_DNS) { + continue; + } + + str.length = ASN1_STRING_length(name->d.dNSName); +#if OPENSSL_VERSION_NUMBER > 0x10100000L + str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); +#else + str.start = ASN1_STRING_data(name->d.dNSName); +#endif + + domain.start = nxt_mp_nget(mp, str.length); + if (nxt_slow_path(domain.start == NULL)) { + goto fail; + } + + domain.length = str.length; + nxt_memcpy_lowcase(domain.start, str.start, str.length); + + item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); + if (nxt_slow_path(item == NULL)) { + goto fail; + } + + item->name = domain; + item->bundle = bundle; + + if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, + item, mp) + == NXT_ERROR) + { + goto fail; + } + } + + sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); + + } else { + x509_name = X509_get_subject_name(cert); + len = X509_NAME_get_text_by_NID(x509_name, NID_commonName, + NULL, 0); + if (len <= 0) { + nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither " + "Subject Alternative Name nor Common Name", bundle->name); + return NXT_OK; + } + + domain.start = nxt_mp_nget(mp, len + 1); + if (nxt_slow_path(domain.start == NULL)) { + return NXT_ERROR; + } + + domain.length = X509_NAME_get_text_by_NID(x509_name, NID_commonName, + (char *) domain.start, + len + 1); + nxt_memcpy_lowcase(domain.start, domain.start, domain.length); + + item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); + if (nxt_slow_path(item == NULL)) { + return NXT_ERROR; + } + + item->name = domain; + item->bundle = bundle; + + if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, item, + mp) + == NXT_ERROR) + { + return NXT_ERROR; + } + } + + return NXT_OK; + +fail: + + sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); + + return NXT_ERROR; +} + + +static const nxt_lvlhsh_proto_t nxt_openssl_bundle_hash_proto + nxt_aligned(64) = +{ + NXT_LVLHSH_DEFAULT, + nxt_openssl_bundle_hash_test, + nxt_mp_lvlhsh_alloc, + nxt_mp_lvlhsh_free, +}; + + +static nxt_int_t +nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, void *data) +{ + nxt_tls_bundle_hash_item_t *item; + + item = data; + + return nxt_strstr_eq(&lhq->key, &item->name) ? NXT_OK : NXT_DECLINED; +} + + +static nxt_int_t +nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, + nxt_tls_bundle_hash_item_t *item, nxt_mp_t *mp) +{ + nxt_str_t str; + nxt_int_t ret; + nxt_lvlhsh_query_t lhq; + nxt_tls_bundle_hash_item_t *old; + + str = item->name; + + if (item->name.start[0] == '*') { + item->name.start++; + item->name.length--; + + 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); + return NXT_OK; + } + } + + lhq.pool = mp; + lhq.key = item->name; + lhq.value = item; + lhq.proto = &nxt_openssl_bundle_hash_proto; + lhq.replace = 0; + lhq.key_hash = nxt_murmur_hash2(item->name.start, item->name.length); + + 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); + return NXT_OK; + } + + if (nxt_fast_path(ret == NXT_DECLINED)) { + old = lhq.value; + 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); + + old->bundle = item->bundle; + } + + return NXT_OK; + } + + return NXT_ERROR; +} + + +static nxt_int_t +nxt_openssl_servername(SSL *s, int *ad, void *arg) +{ + nxt_str_t str; + nxt_uint_t i; + nxt_conn_t *c; + const char *servername; + nxt_tls_conf_t *conf; + nxt_openssl_conn_t *tls; + nxt_tls_bundle_conf_t *bundle; + + c = SSL_get_ex_data(s, nxt_openssl_connection_index); + + if (nxt_slow_path(c == NULL)) { + nxt_thread_log_alert("SSL_get_ex_data() failed"); + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); + if (nxt_slow_path(servername == NULL)) { + nxt_log(c->socket.task, NXT_LOG_ALERT, "SSL_get_servername() returned " + "NULL in server name callback"); + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + str.length = nxt_strlen(servername); + if (str.length == 0) { + nxt_debug(c->socket.task, "client sent zero-length server name"); + goto done; + } + + if (servername[0] == '.') { + nxt_debug(c->socket.task, "ignored the server name \"%s\": " + "leading \".\"", servername); + goto done; + } + + nxt_debug(c->socket.task, "tls with servername \"%s\"", servername); + + str.start = nxt_mp_nget(c->mem_pool, str.length); + if (nxt_slow_path(str.start == NULL)) { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + nxt_memcpy_lowcase(str.start, (const u_char *) servername, str.length); + + tls = c->u.tls; + conf = tls->conf; + + bundle = nxt_openssl_find_ctx(conf, &str); + + if (bundle == NULL) { + for (i = 1; i < str.length; i++) { + if (str.start[i] == '.') { + str.start += i; + str.length -= i; + + bundle = nxt_openssl_find_ctx(conf, &str); + break; + } + } + } + + if (bundle != NULL) { + nxt_debug(c->socket.task, "new tls context found for \"%V\": \"%V\" " + "(old: \"%V\")", &str, bundle->name, + conf->bundle->name); + + if (bundle != conf->bundle) { + if (SSL_set_SSL_CTX(s, bundle->ctx) == NULL) { + nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, + "SSL_set_SSL_CTX() failed"); + + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + } + } + +done: + + return SSL_TLSEXT_ERR_OK; +} + + +static nxt_tls_bundle_conf_t * +nxt_openssl_find_ctx(nxt_tls_conf_t *conf, nxt_str_t *sn) +{ + nxt_int_t ret; + nxt_lvlhsh_query_t lhq; + nxt_tls_bundle_hash_item_t *item; + + lhq.key_hash = nxt_murmur_hash2(sn->start, sn->length); + lhq.key = *sn; + lhq.proto = &nxt_openssl_bundle_hash_proto; + + ret = nxt_lvlhsh_find(&conf->bundle_hash, &lhq); + if (ret != NXT_OK) { + return NULL; + } + + item = lhq.value; + + return item->bundle; +} + + static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf) { - SSL_CTX_free(conf->ctx); + nxt_tls_bundle_conf_t *bundle; + + bundle = conf->bundle; + nxt_assert(bundle != NULL); + + do { + SSL_CTX_free(bundle->ctx); + bundle = bundle->next; + } while (bundle != NULL); #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ && OPENSSL_VERSION_NUMBER < 0x1010101fL) @@ -474,7 +807,7 @@ nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) c->u.tls = tls; nxt_buf_mem_set_size(&tls->buffer, conf->buffer_size); - ctx = conf->ctx; + ctx = conf->bundle->ctx; s = SSL_new(ctx); if (s == NULL) { @@ -483,6 +816,8 @@ nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) } tls->session = s; + /* To pass TLS config to the nxt_openssl_servername() callback. */ + tls->conf = conf; tls->conn = c; ret = SSL_set_fd(s, c->socket.fd); @@ -504,6 +839,11 @@ nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) c->sendfile = NXT_CONN_SENDFILE_OFF; nxt_openssl_conn_handshake(task, c, c->socket.data); + /* + * TLS configuration might be destroyed after the TLS connection + * is established. + */ + tls->conf = NULL; return; fail: diff --git a/src/nxt_router.c b/src/nxt_router.c index 4be4197a..0ecaefa1 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -51,8 +51,10 @@ typedef struct { typedef struct { + nxt_str_t *name; nxt_socket_conf_t *socket_conf; nxt_router_temp_conf_t *temp_conf; + nxt_bool_t last; } nxt_socket_rpc_t; @@ -116,9 +118,11 @@ 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_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); #endif static void nxt_router_app_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_app_t *app); @@ -944,14 +948,15 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) } #if (NXT_TLS) - qlk = nxt_queue_first(&tmcf->tls); + qlk = nxt_queue_last(&tmcf->tls); - if (qlk != nxt_queue_tail(&tmcf->tls)) { + if (qlk != nxt_queue_head(&tmcf->tls)) { nxt_queue_remove(qlk); tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link); - nxt_router_tls_rpc_create(task, tmcf, tls); + nxt_router_tls_rpc_create(task, tmcf, tls, + nxt_queue_is_empty(&tmcf->tls)); return; } #endif @@ -990,7 +995,7 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) nxt_router_apps_sort(task, router, tmcf); - nxt_router_apps_hash_use(task, rtcf, 1); + nxt_router_apps_hash_use(task, rtcf, 1); nxt_router_engines_post(router, tmcf); @@ -1332,6 +1337,9 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_port_t *port; nxt_router_t *router; nxt_app_joint_t *app_joint; +#if (NXT_TLS) + nxt_conf_value_t *certificate; +#endif nxt_conf_value_t *conf, *http, *value, *websocket; nxt_conf_value_t *applications, *application; nxt_conf_value_t *listeners, *listener; @@ -1343,9 +1351,6 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_router_app_conf_t apcf; nxt_router_access_log_t *access_log; nxt_router_listener_conf_t lscf; -#if (NXT_TLS) - nxt_router_tlssock_t *tls; -#endif static nxt_str_t http_path = nxt_string("/settings/http"); static nxt_str_t applications_path = nxt_string("/applications"); @@ -1729,20 +1734,30 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, } #if (NXT_TLS) - value = nxt_conf_get_path(listener, &certificate_path); + certificate = nxt_conf_get_path(listener, &certificate_path); - if (value != NULL) { - nxt_conf_get_string(value, &name); + if (certificate != NULL) { + if (nxt_conf_type(certificate) == NXT_CONF_ARRAY) { + n = nxt_conf_array_elements_count(certificate); - tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t)); - if (nxt_slow_path(tls == NULL)) { - goto fail; - } + for (i = 0; i < n; i++) { + value = nxt_conf_get_array_element(certificate, i); - tls->name = name; - tls->conf = skcf; + nxt_assert(value != NULL); - nxt_queue_insert_tail(&tmcf->tls, &tls->link); + ret = nxt_router_conf_tls_insert(tmcf, value, skcf); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + } + + } else { + /* NXT_CONF_STRING */ + ret = nxt_router_conf_tls_insert(tmcf, certificate, skcf); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + } } #endif @@ -1828,6 +1843,38 @@ fail: } +#if (NXT_TLS) + +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_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)); + 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; + } + + nxt_queue_insert_tail(&tmcf->tls, &tls->link); + + return NXT_OK; +} + +#endif + + static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, nxt_conf_value_t *conf) @@ -2383,7 +2430,7 @@ nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, static void nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_router_tlssock_t *tls) + nxt_router_tlssock_t *tls, nxt_bool_t last) { nxt_socket_rpc_t *rpc; @@ -2393,8 +2440,10 @@ nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *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); @@ -2405,11 +2454,12 @@ 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_temp_conf_t *tmcf; + nxt_mp_t *mp; + nxt_int_t ret; + nxt_tls_conf_t *tlscf; + nxt_socket_rpc_t *rpc; + nxt_tls_bundle_conf_t *bundle; + nxt_router_temp_conf_t *tmcf; nxt_debug(task, "tls rpc handler"); @@ -2422,20 +2472,33 @@ nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, mp = tmcf->router_conf->mem_pool; - tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); - if (nxt_slow_path(tlscf == NULL)) { + if (rpc->socket_conf->tls == NULL){ + tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); + if (nxt_slow_path(tlscf == NULL)) { + goto fail; + } + + rpc->socket_conf->tls = tlscf; + + } else { + tlscf = rpc->socket_conf->tls; + } + + bundle = nxt_mp_get(mp, sizeof(nxt_tls_bundle_conf_t)); + if (nxt_slow_path(bundle == NULL)) { goto fail; } - tlscf->chain_file = msg->fd[0]; + bundle->name = rpc->name; + bundle->chain_file = msg->fd[0]; + bundle->next = tlscf->bundle; + tlscf->bundle = bundle; - ret = task->thread->runtime->tls->server_init(task, tlscf); + ret = task->thread->runtime->tls->server_init(task, tlscf, mp, rpc->last); if (nxt_slow_path(ret != NXT_OK)) { goto fail; } - rpc->socket_conf->tls = tlscf; - nxt_work_queue_add(&task->thread->engine->fast_work_queue, nxt_router_conf_apply, task, tmcf, NULL); return; diff --git a/src/nxt_tls.h b/src/nxt_tls.h index d9fcc6a8..c44bfe56 100644 --- a/src/nxt_tls.h +++ b/src/nxt_tls.h @@ -23,28 +23,47 @@ #define NXT_TLS_BUFFER_SIZE 4096 -typedef struct nxt_tls_conf_s nxt_tls_conf_t; - +typedef struct nxt_tls_conf_s nxt_tls_conf_t; +typedef struct nxt_tls_bundle_conf_s nxt_tls_bundle_conf_t; typedef struct { nxt_int_t (*library_init)(nxt_task_t *task); void (*library_free)(nxt_task_t *task); nxt_int_t (*server_init)(nxt_task_t *task, - nxt_tls_conf_t *conf); + nxt_tls_conf_t *conf, nxt_mp_t *mp, + nxt_bool_t last); void (*server_free)(nxt_task_t *task, nxt_tls_conf_t *conf); } nxt_tls_lib_t; -struct nxt_tls_conf_s { +typedef struct { + nxt_tls_bundle_conf_t *bundle; + + nxt_str_t name; +} nxt_tls_bundle_hash_item_t; + + +struct nxt_tls_bundle_conf_s { void *ctx; + + nxt_fd_t chain_file; + nxt_str_t *name; + + nxt_tls_bundle_conf_t *next; +}; + + +struct nxt_tls_conf_s { + nxt_tls_bundle_conf_t *bundle; + nxt_lvlhsh_t bundle_hash; + void (*conn_init)(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c); const nxt_tls_lib_t *lib; - nxt_fd_t chain_file; char *ciphers; char *ca_certificate; |