]> git.kaiwu.me - nginx.git/commitdiff
SSL: encrypted certificate keys are exempt from object cache.
authorSergey Kandaurov <pluknet@nginx.com>
Wed, 18 Dec 2024 16:09:58 +0000 (20:09 +0400)
committerpluknet <pluknet@nginx.com>
Fri, 17 Jan 2025 00:37:46 +0000 (04:37 +0400)
SSL object cache, as previously introduced in 1.27.2, did not take
into account encrypted certificate keys that might be unexpectedly
fetched from the cache regardless of the matching passphrase.  To
avoid this, caching of encrypted certificate keys is now disabled
based on the passphrase callback invocation.

A notable exception is encrypted certificate keys configured without
ssl_password_file.  They are loaded once resulting in the passphrase
prompt on startup and reused in other contexts as applicable.

src/event/ngx_event_openssl_cache.c

index 9d19627591024cae225c8e67ae706c9160e04bc0..c79f77456ab651b9489d795328845646e8be3760 100644 (file)
@@ -13,6 +13,8 @@
 #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)
@@ -61,6 +63,12 @@ typedef struct {
 } ngx_ssl_cache_t;
 
 
+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,
@@ -228,9 +236,10 @@ ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err,
     }
 
     if (value == NULL) {
-        value = type->create(&id, err, data);
-        if (value == NULL) {
-            return NULL;
+        value = type->create(&id, err, &data);
+
+        if (value == NULL || data == NGX_SSL_CACHE_DISABLED) {
+            return value;
         }
     }
 
@@ -269,7 +278,7 @@ ngx_ssl_cache_connection_fetch(ngx_pool_t *pool, ngx_uint_t index, char **err,
         return NULL;
     }
 
-    return ngx_ssl_cache_types[index].create(&id, err, data);
+    return ngx_ssl_cache_types[index].create(&id, err, &data);
 }
 
 
@@ -472,13 +481,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) {
 
@@ -531,12 +540,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;
@@ -552,7 +565,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;
         }
 
@@ -561,6 +574,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;
@@ -571,7 +588,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,
@@ -580,6 +599,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;
     }