diff options
| author | Sergey Kandaurov <pluknet@nginx.com> | 2025-01-08 17:50:33 +0400 |
|---|---|---|
| committer | pluknet <pluknet@nginx.com> | 2025-01-17 04:37:46 +0400 |
| commit | 5d5d9adccfeaff7d5926737ee5dfa43937fe5899 (patch) | |
| tree | dffc4e214497ad560eb317e97be59ac6eac3fac3 /src/event/ngx_event_openssl.c | |
| parent | 454ad0ef33a347eba1a62d18c8fc0498f4dcfd64 (diff) | |
| download | nginx-5d5d9adccfeaff7d5926737ee5dfa43937fe5899.tar.gz nginx-5d5d9adccfeaff7d5926737ee5dfa43937fe5899.tar.bz2 | |
SSL: avoid using mismatched certificate/key cached pairs.
This can happen with certificates and certificate keys specified
with variables due to partial cache update in various scenarios:
- cache expiration with only one element of pair evicted
- on-disk update with non-cacheable encrypted keys
- non-atomic on-disk update
The fix is to retry with fresh data on X509_R_KEY_VALUES_MISMATCH.
Diffstat (limited to 'src/event/ngx_event_openssl.c')
| -rw-r--r-- | src/event/ngx_event_openssl.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 8963c8124..0681ca3a2 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -567,10 +567,17 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, { char *err; X509 *x509; + u_long n; EVP_PKEY *pkey; + ngx_uint_t mask; STACK_OF(X509) *chain; - chain = ngx_ssl_cache_connection_fetch(cache, pool, NGX_SSL_CACHE_CERT, + 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) { @@ -611,7 +618,8 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, #endif - pkey = ngx_ssl_cache_connection_fetch(cache, pool, NGX_SSL_CACHE_PKEY, + pkey = ngx_ssl_cache_connection_fetch(cache, pool, + NGX_SSL_CACHE_PKEY | mask, &err, key, passwords); if (pkey == NULL) { if (err != NULL) { @@ -624,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; } |
