From da24305046c7d302dae56d66eb7f91ae85c1ba6e Mon Sep 17 00:00:00 2001 From: Hakase Date: Fri, 31 Jan 2025 05:19:13 +0900 Subject: [PATCH] Latest update - GitHub 57d54fd92 --- auto/lib/libatomic/conf | 4 +- auto/lib/libatomic/make | 11 +- misc/GNUmakefile | 3 + src/core/ngx_core.h | 1 + src/event/ngx_event_openssl.c | 35 +- src/event/ngx_event_openssl.h | 13 +- src/event/ngx_event_openssl_cache.c | 421 ++++++++++++++++-- src/event/quic/ngx_event_quic_output.c | 4 +- src/http/modules/ngx_http_grpc_module.c | 106 +++++ src/http/modules/ngx_http_proxy_module.c | 106 +++++ .../modules/ngx_http_slice_filter_module.c | 4 +- src/http/modules/ngx_http_ssl_module.c | 106 +++++ src/http/modules/ngx_http_ssl_module.h | 2 + src/http/modules/ngx_http_uwsgi_module.c | 106 +++++ src/http/ngx_http_request.c | 1 + src/http/ngx_http_upstream.c | 1 + src/http/ngx_http_upstream.h | 1 + src/stream/ngx_stream_proxy_module.c | 109 +++++ src/stream/ngx_stream_ssl_module.c | 107 +++++ src/stream/ngx_stream_ssl_module.h | 66 +-- 20 files changed, 1120 insertions(+), 87 deletions(-) diff --git a/auto/lib/libatomic/conf b/auto/lib/libatomic/conf index 8c8cb43..dfdc1a6 100644 --- a/auto/lib/libatomic/conf +++ b/auto/lib/libatomic/conf @@ -7,8 +7,8 @@ if [ $NGX_LIBATOMIC != YES ]; then have=NGX_HAVE_LIBATOMIC . auto/have CORE_INCS="$CORE_INCS $NGX_LIBATOMIC/src" - LINK_DEPS="$LINK_DEPS $NGX_LIBATOMIC/src/libatomic_ops.a" - CORE_LIBS="$CORE_LIBS $NGX_LIBATOMIC/src/libatomic_ops.a" + LINK_DEPS="$LINK_DEPS $NGX_LIBATOMIC/build/lib/libatomic_ops.a" + CORE_LIBS="$CORE_LIBS $NGX_LIBATOMIC/build/lib/libatomic_ops.a" else diff --git a/auto/lib/libatomic/make b/auto/lib/libatomic/make index c90318e..530c746 100644 --- a/auto/lib/libatomic/make +++ b/auto/lib/libatomic/make @@ -3,14 +3,19 @@ # Copyright (C) Nginx, Inc. + case $NGX_LIBATOMIC in + /*) ngx_prefix="$NGX_LIBATOMIC/build" ;; + *) ngx_prefix="$PWD/$NGX_LIBATOMIC/build" ;; + esac + cat << END >> $NGX_MAKEFILE -$NGX_LIBATOMIC/src/libatomic_ops.a: $NGX_LIBATOMIC/Makefile - cd $NGX_LIBATOMIC && \$(MAKE) +$NGX_LIBATOMIC/build/lib/libatomic_ops.a: $NGX_LIBATOMIC/Makefile + cd $NGX_LIBATOMIC && \$(MAKE) && \$(MAKE) install $NGX_LIBATOMIC/Makefile: $NGX_MAKEFILE cd $NGX_LIBATOMIC \\ && if [ -f Makefile ]; then \$(MAKE) distclean; fi \\ - && ./configure + && ./configure --prefix=$ngx_prefix END diff --git a/misc/GNUmakefile b/misc/GNUmakefile index e18a86a..b7e76b9 100644 --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -93,6 +93,9 @@ zip: export mv $(TEMP)/$(NGINX)/LICENSE $(TEMP)/$(NGINX)/docs.new mv $(TEMP)/$(NGINX)/README.md $(TEMP)/$(NGINX)/docs.new + mv $(TEMP)/$(NGINX)/CODE_OF_CONDUCT.md $(TEMP)/$(NGINX)/docs.new + mv $(TEMP)/$(NGINX)/CONTRIBUTING.md $(TEMP)/$(NGINX)/docs.new + mv $(TEMP)/$(NGINX)/SECURITY.md $(TEMP)/$(NGINX)/docs.new mv $(TEMP)/$(NGINX)/docs/html $(TEMP)/$(NGINX) rm -r $(TEMP)/$(NGINX)/docs diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index 88db7dc..02890b8 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -26,6 +26,7 @@ typedef struct ngx_event_aio_s ngx_event_aio_t; typedef struct ngx_connection_s ngx_connection_t; typedef struct ngx_thread_task_s ngx_thread_task_t; typedef struct ngx_ssl_s ngx_ssl_t; +typedef struct ngx_ssl_cache_s ngx_ssl_cache_t; typedef struct ngx_proxy_protocol_s ngx_proxy_protocol_t; typedef struct ngx_quic_stream_s ngx_quic_stream_t; typedef struct ngx_ssl_connection_s ngx_ssl_connection_t; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 8fa1592..3735715 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -562,15 +562,23 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, - ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords) + ngx_str_t *cert, ngx_str_t *key, ngx_ssl_cache_t *cache, + ngx_array_t *passwords) { char *err; X509 *x509; + u_long n; EVP_PKEY *pkey; + ngx_uint_t mask; STACK_OF(X509) *chain; - chain = ngx_ssl_cache_connection_fetch(pool, NGX_SSL_CACHE_CERT, &err, - cert, NULL); + mask = 0; + +retry: + + chain = ngx_ssl_cache_connection_fetch(cache, pool, + NGX_SSL_CACHE_CERT | mask, + &err, cert, NULL); if (chain == NULL) { if (err != NULL) { ngx_ssl_error(NGX_LOG_ERR, c->log, 0, @@ -610,8 +618,9 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, #endif - pkey = ngx_ssl_cache_connection_fetch(pool, NGX_SSL_CACHE_PKEY, &err, - key, passwords); + pkey = ngx_ssl_cache_connection_fetch(cache, pool, + NGX_SSL_CACHE_PKEY | mask, + &err, key, passwords); if (pkey == NULL) { if (err != NULL) { ngx_ssl_error(NGX_LOG_ERR, c->log, 0, @@ -623,9 +632,23 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, } if (SSL_use_PrivateKey(c->ssl->connection, pkey) == 0) { + EVP_PKEY_free(pkey); + + /* there can be mismatched pairs on uneven cache update */ + + n = ERR_peek_last_error(); + + if (ERR_GET_LIB(n) == ERR_LIB_X509 + && ERR_GET_REASON(n) == X509_R_KEY_VALUES_MISMATCH + && mask == 0) + { + ERR_clear_error(); + mask = NGX_SSL_CACHE_INVALIDATE; + goto retry; + } + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_use_PrivateKey(\"%s\") failed", key->data); - EVP_PKEY_free(pkey); return NGX_ERROR; } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index ec6e270..22d22fa 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -83,7 +83,7 @@ #endif -typedef struct ngx_ssl_ocsp_s ngx_ssl_ocsp_t; +typedef struct ngx_ssl_ocsp_s ngx_ssl_ocsp_t; typedef struct { @@ -219,6 +219,8 @@ typedef struct { #define NGX_SSL_CACHE_CRL 2 #define NGX_SSL_CACHE_CA 3 +#define NGX_SSL_CACHE_INVALIDATE 0x80000000 + ngx_int_t ngx_ssl_init(ngx_log_t *log); ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data); @@ -228,7 +230,8 @@ ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); ngx_int_t ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, - ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); + ngx_str_t *cert, ngx_str_t *key, ngx_ssl_cache_t *cache, + ngx_array_t *passwords); ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, ngx_uint_t prefer_server_ciphers); @@ -251,10 +254,12 @@ ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s); void ngx_ssl_ocsp_cleanup(ngx_connection_t *c); ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data); +ngx_ssl_cache_t *ngx_ssl_cache_init(ngx_pool_t *pool, ngx_uint_t max, + time_t valid, time_t inactive); void *ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err, ngx_str_t *path, void *data); -void *ngx_ssl_cache_connection_fetch(ngx_pool_t *pool, ngx_uint_t index, - char **err, ngx_str_t *path, void *data); +void *ngx_ssl_cache_connection_fetch(ngx_ssl_cache_t *cache, ngx_pool_t *pool, + ngx_uint_t index, char **err, ngx_str_t *path, void *data); ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf, diff --git a/src/event/ngx_event_openssl_cache.c b/src/event/ngx_event_openssl_cache.c index 8829e28..d62b4c4 100644 --- a/src/event/ngx_event_openssl_cache.c +++ b/src/event/ngx_event_openssl_cache.c @@ -13,6 +13,16 @@ #define NGX_SSL_CACHE_DATA 1 #define NGX_SSL_CACHE_ENGINE 2 +#define NGX_SSL_CACHE_DISABLED (ngx_array_t *) (uintptr_t) -1 + + +#define ngx_ssl_cache_get_conf(cycle) \ + (ngx_ssl_cache_t *) ngx_get_conf(cycle->conf_ctx, ngx_openssl_cache_module) + +#define ngx_ssl_cache_get_old_conf(cycle) \ + cycle->old_cycle->conf_ctx ? ngx_ssl_cache_get_conf(cycle->old_cycle) \ + : NULL + typedef struct { unsigned type:2; @@ -36,22 +46,45 @@ typedef struct { typedef struct { ngx_rbtree_node_t node; + ngx_queue_t queue; ngx_ssl_cache_key_t id; ngx_ssl_cache_type_t *type; void *value; + + time_t created; + time_t accessed; + + time_t mtime; + ngx_file_uniq_t uniq; } ngx_ssl_cache_node_t; -typedef struct { +struct ngx_ssl_cache_s { ngx_rbtree_t rbtree; ngx_rbtree_node_t sentinel; -} ngx_ssl_cache_t; + ngx_queue_t expire_queue; + + ngx_flag_t inheritable; + + ngx_uint_t current; + ngx_uint_t max; + time_t valid; + time_t inactive; +}; + + +typedef struct { + ngx_str_t *pwd; + unsigned encrypted:1; +} ngx_ssl_cache_pwd_t; static ngx_int_t ngx_ssl_cache_init_key(ngx_pool_t *pool, ngx_uint_t index, ngx_str_t *path, ngx_ssl_cache_key_t *id); static ngx_ssl_cache_node_t *ngx_ssl_cache_lookup(ngx_ssl_cache_t *cache, ngx_ssl_cache_type_t *type, ngx_ssl_cache_key_t *id, uint32_t hash); +static void ngx_ssl_cache_expire(ngx_ssl_cache_t *cache, ngx_uint_t n, + ngx_log_t *log); static void *ngx_ssl_cache_cert_create(ngx_ssl_cache_key_t *id, char **err, void *data); @@ -76,22 +109,38 @@ static void *ngx_ssl_cache_ca_create(ngx_ssl_cache_key_t *id, char **err, static BIO *ngx_ssl_cache_create_bio(ngx_ssl_cache_key_t *id, char **err); static void *ngx_openssl_cache_create_conf(ngx_cycle_t *cycle); +static char *ngx_openssl_cache_init_conf(ngx_cycle_t *cycle, void *conf); static void ngx_ssl_cache_cleanup(void *data); static void ngx_ssl_cache_node_insert(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +static void ngx_ssl_cache_node_free(ngx_rbtree_t *rbtree, + ngx_ssl_cache_node_t *cn); + + +static ngx_command_t ngx_openssl_cache_commands[] = { + + { ngx_string("ssl_object_cache_inheritable"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + 0, + offsetof(ngx_ssl_cache_t, inheritable), + NULL }, + + ngx_null_command +}; static ngx_core_module_t ngx_openssl_cache_module_ctx = { ngx_string("openssl_cache"), ngx_openssl_cache_create_conf, - NULL + ngx_openssl_cache_init_conf }; ngx_module_t ngx_openssl_cache_module = { NGX_MODULE_V1, &ngx_openssl_cache_module_ctx, /* module context */ - NULL, /* module directives */ + ngx_openssl_cache_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ @@ -132,8 +181,13 @@ void * ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err, ngx_str_t *path, void *data) { + void *value; + time_t mtime; uint32_t hash; - ngx_ssl_cache_t *cache; + ngx_int_t rc; + ngx_file_uniq_t uniq; + ngx_file_info_t fi; + ngx_ssl_cache_t *cache, *old_cache; ngx_ssl_cache_key_t id; ngx_ssl_cache_type_t *type; ngx_ssl_cache_node_t *cn; @@ -151,12 +205,61 @@ ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err, hash = ngx_murmur_hash2(id.data, id.len); cn = ngx_ssl_cache_lookup(cache, type, &id, hash); + if (cn != NULL) { return type->ref(err, cn->value); } + value = NULL; + + if (id.type == NGX_SSL_CACHE_PATH + && (rc = ngx_file_info(id.data, &fi)) != NGX_FILE_ERROR) + { + mtime = ngx_file_mtime(&fi); + uniq = ngx_file_uniq(&fi); + + } else { + rc = NGX_FILE_ERROR; + mtime = 0; + uniq = 0; + } + + /* try to use a reference from the old cycle */ + + old_cache = ngx_ssl_cache_get_old_conf(cf->cycle); + + if (old_cache && old_cache->inheritable) { + cn = ngx_ssl_cache_lookup(old_cache, type, &id, hash); + + if (cn != NULL) { + switch (id.type) { + + case NGX_SSL_CACHE_DATA: + value = type->ref(err, cn->value); + break; + + default: + if (rc != NGX_FILE_ERROR + && uniq == cn->uniq && mtime == cn->mtime) + { + value = type->ref(err, cn->value); + } + break; + } + } + } + + if (value == NULL) { + value = type->create(&id, err, &data); + + if (value == NULL || data == NGX_SSL_CACHE_DISABLED) { + return value; + } + } + cn = ngx_palloc(cf->pool, sizeof(ngx_ssl_cache_node_t) + id.len + 1); if (cn == NULL) { + type->free(value); return NULL; } @@ -165,13 +268,13 @@ ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err, cn->id.len = id.len; cn->id.type = id.type; cn->type = type; + cn->value = value; + cn->mtime = mtime; + cn->uniq = uniq; ngx_cpystrn(cn->id.data, id.data, id.len + 1); - cn->value = type->create(&id, err, data); - if (cn->value == NULL) { - return NULL; - } + ngx_queue_init(&cn->queue); ngx_rbtree_insert(&cache->rbtree, &cn->node); @@ -180,18 +283,150 @@ ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err, void * -ngx_ssl_cache_connection_fetch(ngx_pool_t *pool, ngx_uint_t index, char **err, - ngx_str_t *path, void *data) +ngx_ssl_cache_connection_fetch(ngx_ssl_cache_t *cache, ngx_pool_t *pool, + ngx_uint_t index, char **err, ngx_str_t *path, void *data) { - ngx_ssl_cache_key_t id; + void *value; + time_t now; + uint32_t hash; + ngx_uint_t invalidate; + ngx_file_info_t fi; + ngx_ssl_cache_key_t id; + ngx_ssl_cache_type_t *type; + ngx_ssl_cache_node_t *cn; *err = NULL; + invalidate = index & NGX_SSL_CACHE_INVALIDATE; + index &= ~NGX_SSL_CACHE_INVALIDATE; + if (ngx_ssl_cache_init_key(pool, index, path, &id) != NGX_OK) { return NULL; } - return ngx_ssl_cache_types[index].create(&id, err, data); + type = &ngx_ssl_cache_types[index]; + + if (cache == NULL) { + return type->create(&id, err, &data); + } + + now = ngx_time(); + + hash = ngx_murmur_hash2(id.data, id.len); + + cn = ngx_ssl_cache_lookup(cache, type, &id, hash); + + if (cn != NULL) { + ngx_queue_remove(&cn->queue); + + if (id.type == NGX_SSL_CACHE_DATA) { + goto found; + } + + if (!invalidate && now - cn->created <= cache->valid) { + goto found; + } + + switch (id.type) { + + case NGX_SSL_CACHE_PATH: + + if (ngx_file_info(id.data, &fi) != NGX_FILE_ERROR) { + + if (!invalidate + && ngx_file_uniq(&fi) == cn->uniq + && ngx_file_mtime(&fi) == cn->mtime) + { + break; + } + + cn->mtime = ngx_file_mtime(&fi); + cn->uniq = ngx_file_uniq(&fi); + + } else { + cn->mtime = 0; + cn->uniq = 0; + } + + /* fall through */ + + default: + ngx_log_debug1(NGX_LOG_DEBUG_CORE, pool->log, 0, + "update cached ssl object: %s", cn->id.data); + + type->free(cn->value); + + value = type->create(&id, err, &data); + + if (value == NULL || data == NGX_SSL_CACHE_DISABLED) { + ngx_rbtree_delete(&cache->rbtree, &cn->node); + + cache->current--; + + ngx_free(cn); + + return value; + } + + cn->value = value; + } + + cn->created = now; + + goto found; + } + + value = type->create(&id, err, &data); + + if (value == NULL || data == NGX_SSL_CACHE_DISABLED) { + return value; + } + + cn = ngx_alloc(sizeof(ngx_ssl_cache_node_t) + id.len + 1, pool->log); + if (cn == NULL) { + type->free(value); + return NULL; + } + + cn->node.key = hash; + cn->id.data = (u_char *)(cn + 1); + cn->id.len = id.len; + cn->id.type = id.type; + cn->type = type; + cn->value = value; + cn->created = now; + + ngx_cpystrn(cn->id.data, id.data, id.len + 1); + + if (id.type == NGX_SSL_CACHE_PATH) { + + if (ngx_file_info(id.data, &fi) != NGX_FILE_ERROR) { + cn->mtime = ngx_file_mtime(&fi); + cn->uniq = ngx_file_uniq(&fi); + + } else { + cn->mtime = 0; + cn->uniq = 0; + } + } + + ngx_ssl_cache_expire(cache, 1, pool->log); + + if (cache->current >= cache->max) { + ngx_ssl_cache_expire(cache, 0, pool->log); + } + + ngx_rbtree_insert(&cache->rbtree, &cn->node); + + cache->current++; + +found: + + cn->accessed = now; + + ngx_queue_insert_head(&cache->expire_queue, &cn->queue); + + return type->ref(err, cn->value); } @@ -278,6 +513,37 @@ ngx_ssl_cache_lookup(ngx_ssl_cache_t *cache, ngx_ssl_cache_type_t *type, } +static void +ngx_ssl_cache_expire(ngx_ssl_cache_t *cache, ngx_uint_t n, + ngx_log_t *log) +{ + time_t now; + ngx_queue_t *q; + ngx_ssl_cache_node_t *cn; + + now = ngx_time(); + + while (n < 3) { + + if (ngx_queue_empty(&cache->expire_queue)) { + return; + } + + q = ngx_queue_last(&cache->expire_queue); + + cn = ngx_queue_data(q, ngx_ssl_cache_node_t, queue); + + if (n++ != 0 && now - cn->accessed <= cache->inactive) { + return; + } + + ngx_ssl_cache_node_free(&cache->rbtree, cn); + + cache->current--; + } +} + + static void * ngx_ssl_cache_cert_create(ngx_ssl_cache_key_t *id, char **err, void *data) { @@ -394,13 +660,13 @@ ngx_ssl_cache_cert_ref(char **err, void *data) static void * ngx_ssl_cache_pkey_create(ngx_ssl_cache_key_t *id, char **err, void *data) { - ngx_array_t *passwords = data; + ngx_array_t **passwords = data; - BIO *bio; - EVP_PKEY *pkey; - ngx_str_t *pwd; - ngx_uint_t tries; - pem_password_cb *cb; + BIO *bio; + EVP_PKEY *pkey; + ngx_uint_t tries; + pem_password_cb *cb; + ngx_ssl_cache_pwd_t cb_data, *pwd; if (id->type == NGX_SSL_CACHE_ENGINE) { @@ -453,12 +719,16 @@ ngx_ssl_cache_pkey_create(ngx_ssl_cache_key_t *id, char **err, void *data) return NULL; } - if (passwords) { - tries = passwords->nelts; - pwd = passwords->elts; + cb_data.encrypted = 0; + + if (*passwords) { + cb_data.pwd = (*passwords)->elts; + tries = (*passwords)->nelts; + pwd = &cb_data; cb = ngx_ssl_cache_pkey_password_callback; } else { + cb_data.pwd = NULL; tries = 1; pwd = NULL; cb = NULL; @@ -474,7 +744,7 @@ ngx_ssl_cache_pkey_create(ngx_ssl_cache_key_t *id, char **err, void *data) if (tries-- > 1) { ERR_clear_error(); (void) BIO_reset(bio); - pwd++; + cb_data.pwd++; continue; } @@ -483,6 +753,10 @@ ngx_ssl_cache_pkey_create(ngx_ssl_cache_key_t *id, char **err, void *data) return NULL; } + if (cb_data.encrypted) { + *passwords = NGX_SSL_CACHE_DISABLED; + } + BIO_free(bio); return pkey; @@ -493,7 +767,9 @@ static int ngx_ssl_cache_pkey_password_callback(char *buf, int size, int rwflag, void *userdata) { - ngx_str_t *pwd = userdata; + ngx_ssl_cache_pwd_t *data = userdata; + + ngx_str_t *pwd; if (rwflag) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, @@ -502,6 +778,10 @@ ngx_ssl_cache_pkey_password_callback(char *buf, int size, int rwflag, return 0; } + data->encrypted = 1; + + pwd = data->pwd; + if (pwd == NULL) { return 0; } @@ -721,15 +1001,52 @@ ngx_ssl_cache_create_bio(ngx_ssl_cache_key_t *id, char **err) static void * ngx_openssl_cache_create_conf(ngx_cycle_t *cycle) { - ngx_ssl_cache_t *cache; - ngx_pool_cleanup_t *cln; + ngx_ssl_cache_t *cache; - cache = ngx_pcalloc(cycle->pool, sizeof(ngx_ssl_cache_t)); + cache = ngx_ssl_cache_init(cycle->pool, 0, 0, 0); if (cache == NULL) { return NULL; } - cln = ngx_pool_cleanup_add(cycle->pool, 0); + cache->inheritable = NGX_CONF_UNSET; + + return cache; +} + + +static char * +ngx_openssl_cache_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_ssl_cache_t *cache = conf; + + ngx_conf_init_value(cache->inheritable, 1); + + return NGX_CONF_OK; +} + + +ngx_ssl_cache_t * +ngx_ssl_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t valid, + time_t inactive) +{ + ngx_ssl_cache_t *cache; + ngx_pool_cleanup_t *cln; + + cache = ngx_pcalloc(pool, sizeof(ngx_ssl_cache_t)); + if (cache == NULL) { + return NULL; + } + + ngx_rbtree_init(&cache->rbtree, &cache->sentinel, + ngx_ssl_cache_node_insert); + + ngx_queue_init(&cache->expire_queue); + + cache->max = max; + cache->valid = valid; + cache->inactive = inactive; + + cln = ngx_pool_cleanup_add(pool, 0); if (cln == NULL) { return NULL; } @@ -737,9 +1054,6 @@ ngx_openssl_cache_create_conf(ngx_cycle_t *cycle) cln->handler = ngx_ssl_cache_cleanup; cln->data = cache; - ngx_rbtree_init(&cache->rbtree, &cache->sentinel, - ngx_ssl_cache_node_insert); - return cache; } @@ -759,12 +1073,47 @@ ngx_ssl_cache_cleanup(void *data) return; } - for (node = ngx_rbtree_min(tree->root, tree->sentinel); - node; - node = ngx_rbtree_next(tree, node)) - { + node = ngx_rbtree_min(tree->root, tree->sentinel); + + while (node != NULL) { cn = ngx_rbtree_data(node, ngx_ssl_cache_node_t, node); - cn->type->free(cn->value); + node = ngx_rbtree_next(tree, node); + + ngx_ssl_cache_node_free(tree, cn); + + if (cache->max) { + cache->current--; + } + } + + if (cache->current) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "%ui items still left in ssl cache", + cache->current); + } + + if (!ngx_queue_empty(&cache->expire_queue)) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "queue still is not empty in ssl cache"); + + } +} + + +static void +ngx_ssl_cache_node_free(ngx_rbtree_t *rbtree, ngx_ssl_cache_node_t *cn) +{ + cn->type->free(cn->value); + + ngx_rbtree_delete(rbtree, &cn->node); + + if (!ngx_queue_empty(&cn->queue)) { + ngx_queue_remove(&cn->queue); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "delete cached ssl object: %s", cn->id.data); + + ngx_free(cn); } } diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c index ce6aaab..f087e2b 100644 --- a/src/event/quic/ngx_event_quic_output.c +++ b/src/event/quic/ngx_event_quic_output.c @@ -411,7 +411,7 @@ ngx_quic_send_segments(ngx_connection_t *c, u_char *buf, size_t len, ngx_memzero(msg_control, sizeof(msg_control)); iov.iov_len = len; - iov.iov_base = buf; + iov.iov_base = (void *) buf; msg.msg_iov = &iov; msg.msg_iovlen = 1; @@ -699,7 +699,7 @@ ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len, ngx_memzero(&msg, sizeof(struct msghdr)); iov.iov_len = len; - iov.iov_base = buf; + iov.iov_base = (void *) buf; msg.msg_iov = &iov; msg.msg_iovlen = 1; diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 3267204..8e246c3 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -205,6 +205,8 @@ static char *ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #if (NGX_HTTP_SSL) +static char *ngx_http_grpc_ssl_certificate_cache(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); static char *ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post, @@ -437,6 +439,13 @@ static ngx_command_t ngx_http_grpc_commands[] = { offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_certificate_key), NULL }, + { ngx_string("grpc_ssl_certificate_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, + ngx_http_grpc_ssl_certificate_cache, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("grpc_ssl_password_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_grpc_ssl_password_file, @@ -4386,6 +4395,7 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR; conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate_cache = NGX_CONF_UNSET_PTR; conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -4497,6 +4507,8 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.ssl_certificate, NULL); ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_cache, + prev->upstream.ssl_certificate_cache, NULL); ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, prev->upstream.ssl_passwords, NULL); @@ -4847,6 +4859,100 @@ ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HTTP_SSL) +static char * +ngx_http_grpc_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_grpc_loc_conf_t *plcf = conf; + + time_t inactive, valid; + ngx_str_t *value, s; + ngx_int_t max; + ngx_uint_t i; + + if (plcf->upstream.ssl_certificate_cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + max = 0; + inactive = 10; + valid = 60; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "max=", 4) == 0) { + + max = ngx_atoi(value[i].data + 4, value[i].len - 4); + if (max <= 0) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + inactive = ngx_parse_time(&s, 1); + if (inactive == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "valid=", 6) == 0) { + + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + valid = ngx_parse_time(&s, 1); + if (valid == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strcmp(value[i].data, "off") == 0) { + + plcf->upstream.ssl_certificate_cache = NULL; + + continue; + } + + failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (plcf->upstream.ssl_certificate_cache == NULL) { + return NGX_CONF_OK; + } + + if (max == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"grpc_ssl_certificate_cache\" must have " + "the \"max\" parameter"); + return NGX_CONF_ERROR; + } + + plcf->upstream.ssl_certificate_cache = ngx_ssl_cache_init(cf->pool, max, + valid, inactive); + if (plcf->upstream.ssl_certificate_cache == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static char * ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 9d776f6..877d64c 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -222,6 +222,8 @@ static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #endif #if (NGX_HTTP_SSL) +static char *ngx_http_proxy_ssl_certificate_cache(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); static char *ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #endif @@ -764,6 +766,13 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate_key), NULL }, + { ngx_string("proxy_ssl_certificate_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, + ngx_http_proxy_ssl_certificate_cache, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("proxy_ssl_password_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_proxy_ssl_password_file, @@ -3407,6 +3416,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.ssl_verify = NGX_CONF_UNSET; conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR; conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate_cache = NGX_CONF_UNSET_PTR; conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; @@ -3755,6 +3765,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.ssl_certificate, NULL); ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_cache, + prev->upstream.ssl_certificate_cache, NULL); ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, prev->upstream.ssl_passwords, NULL); @@ -4865,6 +4877,100 @@ ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HTTP_SSL) +static char * +ngx_http_proxy_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_proxy_loc_conf_t *plcf = conf; + + time_t inactive, valid; + ngx_str_t *value, s; + ngx_int_t max; + ngx_uint_t i; + + if (plcf->upstream.ssl_certificate_cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + max = 0; + inactive = 10; + valid = 60; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "max=", 4) == 0) { + + max = ngx_atoi(value[i].data + 4, value[i].len - 4); + if (max <= 0) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + inactive = ngx_parse_time(&s, 1); + if (inactive == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "valid=", 6) == 0) { + + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + valid = ngx_parse_time(&s, 1); + if (valid == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strcmp(value[i].data, "off") == 0) { + + plcf->upstream.ssl_certificate_cache = NULL; + + continue; + } + + failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (plcf->upstream.ssl_certificate_cache == NULL) { + return NGX_CONF_OK; + } + + if (max == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_ssl_certificate_cache\" must have " + "the \"max\" parameter"); + return NGX_CONF_ERROR; + } + + plcf->upstream.ssl_certificate_cache = ngx_ssl_cache_init(cf->pool, max, + valid, inactive); + if (plcf->upstream.ssl_certificate_cache == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static char * ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/modules/ngx_http_slice_filter_module.c b/src/http/modules/ngx_http_slice_filter_module.c index 186380a..3b0bef6 100644 --- a/src/http/modules/ngx_http_slice_filter_module.c +++ b/src/http/modules/ngx_http_slice_filter_module.c @@ -165,8 +165,8 @@ ngx_http_slice_header_filter(ngx_http_request_t *r) if (cr.start != ctx->start || cr.end != end) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unexpected range in slice response: %O-%O", - cr.start, cr.end); + "unexpected range in slice response: %O-%O, " + "expected: %O-%O", cr.start, cr.end, ctx->start, end); return NGX_ERROR; } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 06d390f..14e9b07 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -43,6 +43,8 @@ static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, static ngx_int_t ngx_http_ssl_compile_certificates(ngx_conf_t *cf, ngx_http_ssl_srv_conf_t *conf); +static char *ngx_http_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, @@ -108,6 +110,13 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, certificate_keys), NULL }, + { ngx_string("ssl_certificate_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE123, + ngx_http_ssl_certificate_cache, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("ssl_password_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_http_ssl_password_file, @@ -654,6 +663,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) sscf->verify_depth = NGX_CONF_UNSET_UINT; sscf->certificates = NGX_CONF_UNSET_PTR; sscf->certificate_keys = NGX_CONF_UNSET_PTR; + sscf->certificate_cache = NGX_CONF_UNSET_PTR; sscf->passwords = NGX_CONF_UNSET_PTR; sscf->conf_commands = NGX_CONF_UNSET_PTR; sscf->builtin_session_cache = NGX_CONF_UNSET; @@ -704,6 +714,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys, NULL); + ngx_conf_merge_ptr_value(conf->certificate_cache, prev->certificate_cache, + NULL); + ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); @@ -1056,6 +1069,99 @@ found: } +static char * +ngx_http_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_ssl_srv_conf_t *sscf = conf; + + time_t inactive, valid; + ngx_str_t *value, s; + ngx_int_t max; + ngx_uint_t i; + + if (sscf->certificate_cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + max = 0; + inactive = 10; + valid = 60; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "max=", 4) == 0) { + + max = ngx_atoi(value[i].data + 4, value[i].len - 4); + if (max <= 0) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + inactive = ngx_parse_time(&s, 1); + if (inactive == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "valid=", 6) == 0) { + + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + valid = ngx_parse_time(&s, 1); + if (valid == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strcmp(value[i].data, "off") == 0) { + + sscf->certificate_cache = NULL; + + continue; + } + + failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (sscf->certificate_cache == NULL) { + return NGX_CONF_OK; + } + + if (max == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"ssl_certificate_cache\" must have " + "the \"max\" parameter"); + return NGX_CONF_ERROR; + } + + sscf->certificate_cache = ngx_ssl_cache_init(cf->pool, max, valid, + inactive); + if (sscf->certificate_cache == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static char * ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index 1d7e63e..08b0e11 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -38,6 +38,8 @@ typedef struct { ngx_array_t *certificate_values; ngx_array_t *certificate_key_values; + ngx_ssl_cache_t *certificate_cache; + ngx_str_t dhparam; ngx_str_t ecdh_curve; ngx_str_t client_certificate; diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 7988cc5..14aae5b 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -92,6 +92,8 @@ static char *ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, #endif #if (NGX_HTTP_SSL) +static char *ngx_http_uwsgi_ssl_certificate_cache(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); static char *ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_uwsgi_ssl_conf_command_check(ngx_conf_t *cf, void *post, @@ -559,6 +561,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_certificate_key), NULL }, + { ngx_string("uwsgi_ssl_certificate_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, + ngx_http_uwsgi_ssl_certificate_cache, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("uwsgi_ssl_password_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_uwsgi_ssl_password_file, @@ -1590,6 +1599,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR; conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate_cache = NGX_CONF_UNSET_PTR; conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -1921,6 +1931,8 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.ssl_certificate, NULL); ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_cache, + prev->upstream.ssl_certificate_cache, NULL); ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, prev->upstream.ssl_passwords, NULL); @@ -2455,6 +2467,100 @@ ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HTTP_SSL) +static char * +ngx_http_uwsgi_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_uwsgi_loc_conf_t *plcf = conf; + + time_t inactive, valid; + ngx_str_t *value, s; + ngx_int_t max; + ngx_uint_t i; + + if (plcf->upstream.ssl_certificate_cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + max = 0; + inactive = 10; + valid = 60; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "max=", 4) == 0) { + + max = ngx_atoi(value[i].data + 4, value[i].len - 4); + if (max <= 0) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + inactive = ngx_parse_time(&s, 1); + if (inactive == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "valid=", 6) == 0) { + + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + valid = ngx_parse_time(&s, 1); + if (valid == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strcmp(value[i].data, "off") == 0) { + + plcf->upstream.ssl_certificate_cache = NULL; + + continue; + } + + failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (plcf->upstream.ssl_certificate_cache == NULL) { + return NGX_CONF_OK; + } + + if (max == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"uwsgi_ssl_certificate_cache\" must have " + "the \"max\" parameter"); + return NGX_CONF_ERROR; + } + + plcf->upstream.ssl_certificate_cache = ngx_ssl_cache_init(cf->pool, max, + valid, inactive); + if (plcf->upstream.ssl_certificate_cache == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static char * ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 3cca57c..f44c9e7 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1054,6 +1054,7 @@ ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) "ssl key: \"%s\"", key.data); if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key, + sscf->certificate_cache, sscf->passwords) != NGX_OK) { diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index d95662c..77dc032 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -2019,6 +2019,7 @@ ngx_http_upstream_ssl_certificate(ngx_http_request_t *r, "http upstream ssl key: \"%s\"", key.data); if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key, + u->conf->ssl_certificate_cache, u->conf->ssl_passwords) != NGX_OK) { diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index eeb9b22..d48de57 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -245,6 +245,7 @@ typedef struct { ngx_http_complex_value_t *ssl_certificate; ngx_http_complex_value_t *ssl_certificate_key; + ngx_ssl_cache_t *ssl_certificate_cache; ngx_array_t *ssl_passwords; #endif diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index e978056..7f8bfc4 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -49,6 +49,7 @@ typedef struct { ngx_str_t ssl_crl; ngx_stream_complex_value_t *ssl_certificate; ngx_stream_complex_value_t *ssl_certificate_key; + ngx_ssl_cache_t *ssl_certificate_cache; ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; @@ -94,6 +95,8 @@ static char *ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, #if (NGX_STREAM_SSL) static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s); +static char *ngx_stream_proxy_ssl_certificate_cache(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); static char *ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, @@ -341,6 +344,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate_key), NULL }, + { ngx_string("proxy_ssl_certificate_cache"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE123, + ngx_stream_proxy_ssl_certificate_cache, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("proxy_ssl_password_file"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_stream_proxy_ssl_password_file, @@ -1029,6 +1039,100 @@ ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) } +static char * +ngx_stream_proxy_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_stream_proxy_srv_conf_t *pscf = conf; + + time_t inactive, valid; + ngx_str_t *value, s; + ngx_int_t max; + ngx_uint_t i; + + if (pscf->ssl_certificate_cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + max = 0; + inactive = 10; + valid = 60; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "max=", 4) == 0) { + + max = ngx_atoi(value[i].data + 4, value[i].len - 4); + if (max <= 0) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + inactive = ngx_parse_time(&s, 1); + if (inactive == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "valid=", 6) == 0) { + + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + valid = ngx_parse_time(&s, 1); + if (valid == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strcmp(value[i].data, "off") == 0) { + + pscf->ssl_certificate_cache = NULL; + + continue; + } + + failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (pscf->ssl_certificate_cache == NULL) { + return NGX_CONF_OK; + } + + if (max == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_ssl_certificate_cache\" must have " + "the \"max\" parameter"); + return NGX_CONF_ERROR; + } + + pscf->ssl_certificate_cache = ngx_ssl_cache_init(cf->pool, max, valid, + inactive); + if (pscf->ssl_certificate_cache == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static char * ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) @@ -1325,6 +1429,7 @@ ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s) "stream upstream ssl key: \"%s\"", key.data); if (ngx_ssl_connection_certificate(c, c->pool, &cert, &key, + pscf->ssl_certificate_cache, pscf->ssl_passwords) != NGX_OK) { @@ -2120,6 +2225,7 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; conf->ssl_certificate = NGX_CONF_UNSET_PTR; conf->ssl_certificate_key = NGX_CONF_UNSET_PTR; + conf->ssl_certificate_cache = NGX_CONF_UNSET_PTR; conf->ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -2206,6 +2312,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->ssl_certificate_key, prev->ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->ssl_certificate_cache, + prev->ssl_certificate_cache, NULL); + ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); ngx_conf_merge_ptr_value(conf->ssl_conf_commands, diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 7d5eb90..74d1e77 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -47,6 +47,8 @@ static char *ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, static ngx_int_t ngx_stream_ssl_compile_certificates(ngx_conf_t *cf, ngx_stream_ssl_srv_conf_t *conf); +static char *ngx_stream_ssl_certificate_cache(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, @@ -117,6 +119,13 @@ static ngx_command_t ngx_stream_ssl_commands[] = { offsetof(ngx_stream_ssl_srv_conf_t, certificate_keys), NULL }, + { ngx_string("ssl_certificate_cache"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE123, + ngx_stream_ssl_certificate_cache, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("ssl_password_file"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_stream_ssl_password_file, @@ -718,6 +727,7 @@ ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) "ssl key: \"%s\"", key.data); if (ngx_ssl_connection_certificate(c, c->pool, &cert, &key, + sscf->certificate_cache, sscf->passwords) != NGX_OK) { @@ -844,6 +854,7 @@ ngx_stream_ssl_create_srv_conf(ngx_conf_t *cf) sscf->handshake_timeout = NGX_CONF_UNSET_MSEC; sscf->certificates = NGX_CONF_UNSET_PTR; sscf->certificate_keys = NGX_CONF_UNSET_PTR; + sscf->certificate_cache = NGX_CONF_UNSET_PTR; sscf->passwords = NGX_CONF_UNSET_PTR; sscf->conf_commands = NGX_CONF_UNSET_PTR; sscf->prefer_server_ciphers = NGX_CONF_UNSET; @@ -892,6 +903,9 @@ ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys, NULL); + ngx_conf_merge_ptr_value(conf->certificate_cache, prev->certificate_cache, + NULL); + ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); @@ -1198,6 +1212,99 @@ found: } +static char * +ngx_stream_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_ssl_srv_conf_t *sscf = conf; + + time_t inactive, valid; + ngx_str_t *value, s; + ngx_int_t max; + ngx_uint_t i; + + if (sscf->certificate_cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + max = 0; + inactive = 10; + valid = 60; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "max=", 4) == 0) { + + max = ngx_atoi(value[i].data + 4, value[i].len - 4); + if (max <= 0) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + inactive = ngx_parse_time(&s, 1); + if (inactive == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "valid=", 6) == 0) { + + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + valid = ngx_parse_time(&s, 1); + if (valid == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strcmp(value[i].data, "off") == 0) { + + sscf->certificate_cache = NULL; + + continue; + } + + failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (sscf->certificate_cache == NULL) { + return NGX_CONF_OK; + } + + if (max == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"ssl_certificate_cache\" must have " + "the \"max\" parameter"); + return NGX_CONF_ERROR; + } + + sscf->certificate_cache = ngx_ssl_cache_init(cf->pool, max, valid, + inactive); + if (sscf->certificate_cache == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static char * ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h index e676942..ffa03a6 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h @@ -15,53 +15,55 @@ typedef struct { - ngx_msec_t handshake_timeout; + ngx_msec_t handshake_timeout; - ngx_flag_t prefer_server_ciphers; - ngx_flag_t reject_handshake; + ngx_flag_t prefer_server_ciphers; + ngx_flag_t reject_handshake; - ngx_ssl_t ssl; + ngx_ssl_t ssl; - ngx_uint_t protocols; + ngx_uint_t protocols; - ngx_uint_t verify; - ngx_uint_t verify_depth; + ngx_uint_t verify; + ngx_uint_t verify_depth; - ssize_t builtin_session_cache; + ssize_t builtin_session_cache; - time_t session_timeout; + time_t session_timeout; - ngx_array_t *certificates; - ngx_array_t *certificate_keys; + ngx_array_t *certificates; + ngx_array_t *certificate_keys; - ngx_array_t *certificate_values; - ngx_array_t *certificate_key_values; + ngx_array_t *certificate_values; + ngx_array_t *certificate_key_values; - ngx_str_t dhparam; - ngx_str_t ecdh_curve; - ngx_str_t client_certificate; - ngx_str_t trusted_certificate; - ngx_str_t crl; - ngx_str_t alpn; + ngx_ssl_cache_t *certificate_cache; - ngx_str_t ciphers; + ngx_str_t dhparam; + ngx_str_t ecdh_curve; + ngx_str_t client_certificate; + ngx_str_t trusted_certificate; + ngx_str_t crl; + ngx_str_t alpn; - ngx_array_t *passwords; - ngx_array_t *conf_commands; + ngx_str_t ciphers; - ngx_shm_zone_t *shm_zone; + ngx_array_t *passwords; + ngx_array_t *conf_commands; - ngx_flag_t session_tickets; - ngx_array_t *session_ticket_keys; + ngx_shm_zone_t *shm_zone; - ngx_uint_t ocsp; - ngx_str_t ocsp_responder; - ngx_shm_zone_t *ocsp_cache_zone; + ngx_flag_t session_tickets; + ngx_array_t *session_ticket_keys; - ngx_flag_t stapling; - ngx_flag_t stapling_verify; - ngx_str_t stapling_file; - ngx_str_t stapling_responder; + ngx_uint_t ocsp; + ngx_str_t ocsp_responder; + ngx_shm_zone_t *ocsp_cache_zone; + + ngx_flag_t stapling; + ngx_flag_t stapling_verify; + ngx_str_t stapling_file; + ngx_str_t stapling_responder; } ngx_stream_ssl_srv_conf_t;