From cb078a3968e000ed876c29d2f1abe74d0ddbbff9 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Thu, 29 May 2025 17:49:48 +0400 Subject: [PATCH] SSL: fixed "key values mismatch" with object cache inheritance. In rare cases, it was possible to get into this error state on reload with improperly updated file timestamps for certificate and key pairs. The fix is to retry on X509_R_KEY_VALUES_MISMATCH, similar to 5d5d9adcc. --- src/event/ngx_event_openssl.c | 28 +++++++++++++++++++++++++--- src/event/ngx_event_openssl_cache.c | 13 +++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index a7b389444..00bab4c57 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -444,10 +444,17 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, { char *err; X509 *x509, **elm; + u_long n; EVP_PKEY *pkey; + ngx_uint_t mask; STACK_OF(X509) *chain; - chain = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_CERT, &err, cert, NULL); + mask = 0; + +retry: + + chain = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_CERT | mask, + &err, cert, NULL); if (chain == NULL) { if (err != NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, @@ -537,7 +544,8 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, } #endif - pkey = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_PKEY, &err, key, passwords); + pkey = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_PKEY | mask, + &err, key, passwords); if (pkey == NULL) { if (err != NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, @@ -549,9 +557,23 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, } if (SSL_CTX_use_PrivateKey(ssl->ctx, 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_EMERG, ssl->log, 0, "SSL_CTX_use_PrivateKey(\"%s\") failed", key->data); - EVP_PKEY_free(pkey); return NGX_ERROR; } diff --git a/src/event/ngx_event_openssl_cache.c b/src/event/ngx_event_openssl_cache.c index 18efc73d0..277464609 100644 --- a/src/event/ngx_event_openssl_cache.c +++ b/src/event/ngx_event_openssl_cache.c @@ -193,6 +193,7 @@ ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err, time_t mtime; uint32_t hash; ngx_int_t rc; + ngx_uint_t invalidate; ngx_file_uniq_t uniq; ngx_file_info_t fi; ngx_ssl_cache_t *cache, *old_cache; @@ -202,6 +203,9 @@ ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err, *err = NULL; + invalidate = index & NGX_SSL_CACHE_INVALIDATE; + index &= ~NGX_SSL_CACHE_INVALIDATE; + if (ngx_ssl_cache_init_key(cf->pool, index, path, &id) != NGX_OK) { return NULL; } @@ -215,7 +219,12 @@ ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err, cn = ngx_ssl_cache_lookup(cache, type, &id, hash); if (cn != NULL) { - return type->ref(err, cn->value); + if (!invalidate || id.type != NGX_SSL_CACHE_PATH) { + return type->ref(err, cn->value); + } + + type->free(cn->value); + ngx_rbtree_delete(&cache->rbtree, &cn->node); } value = NULL; @@ -236,7 +245,7 @@ ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err, old_cache = ngx_ssl_cache_get_old_conf(cf->cycle); - if (old_cache && old_cache->inheritable) { + if (old_cache && old_cache->inheritable && !invalidate) { cn = ngx_ssl_cache_lookup(old_cache, type, &id, hash); if (cn != NULL) {