freenginx-1.27.6 changes draft

2025-04-14 Thread Maxim Dounin


Hello!

Below are CHANGES draft for the upcoming freenginx release,
1.27.6.  Review and comments are welcome.


Changes with freenginx 1.27.615 Apr 2025

*) Workaround: the X25519MLKEM768 group name was not shown in the
   $ssl_curve and $ssl_curves variables when using OpenSSL 3.5.

*) Bugfix: a segmentation fault might occur in a worker process if the
   "proxy_ssl_password_file" directive was used along with variables in
   the "proxy_ssl_certificate" or "proxy_ssl_certificate_key"
   directives; the bug had appeared in 1.23.1.


Изменения в freenginx 1.27.6  15.04.2025

*) Изменение: при использовании OpenSSL 3.5 в переменных $ssl_curve и
   $ssl_curves не отображалось название группы X25519MLKEM768.

*) Исправление: в рабочем процессе мог произойти segmentation fault,
   если использовалась директива proxy_ssl_password_file, а в директивах
   proxy_ssl_certificate или proxy_ssl_certificate_key использовались
   переменные; ошибка появилась в 1.23.1.


-- 
Maxim Dounin
http://mdounin.ru/


[nginx] Upstream: fixed SSL certificate password prompt in compl...

2025-04-14 Thread Maxim Dounin
details:   http://freenginx.org/hg/nginx/rev/1fc37359eb2b
branches:  
changeset: 9344:1fc37359eb2b
user:  Maxim Dounin 
date:  Tue Apr 15 02:20:14 2025 +0300
description:
Upstream: fixed SSL certificate password prompt in complex configs.

Variables support in certificates introduced in 7833:3ab8e1e2f0f7 (1.21.0)
inadvertently broke password prompt for static SSL certificates, such
as in the following configuration:

location / {
proxy_ssl_certificate $foo.crt;
proxy_ssl_certificate_key $foo.key;
proxy_pass https://u;

location /static/ {
proxy_ssl_certificate static.crt;
proxy_ssl_certificate_key static.key;
proxy_pass https://u;
}
}

Fix is to restore the conf->ssl_passwords field as previously used for
initial password reading and configuration inheritance, and only use the
conf->upstream.ssl_passwords field for passwords preserved for run time
usage.

diffstat:

 src/http/modules/ngx_http_grpc_module.c  |  23 ---
 src/http/modules/ngx_http_proxy_module.c |  23 ---
 src/http/modules/ngx_http_uwsgi_module.c |  23 ---
 3 files changed, 36 insertions(+), 33 deletions(-)

diffs (261 lines):

diff --git a/src/http/modules/ngx_http_grpc_module.c 
b/src/http/modules/ngx_http_grpc_module.c
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -37,6 +37,7 @@ typedef struct {
 ngx_uint_t ssl_verify_depth;
 ngx_str_t  ssl_trusted_certificate;
 ngx_str_t  ssl_crl;
+ngx_array_t   *ssl_passwords;
 ngx_array_t   *ssl_conf_commands;
 #endif
 } ngx_http_grpc_loc_conf_t;
@@ -4383,7 +4384,7 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t
 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_passwords = NGX_CONF_UNSET_PTR;
+conf->ssl_passwords = NGX_CONF_UNSET_PTR;
 conf->ssl_conf_commands = NGX_CONF_UNSET_PTR;
 #endif
 
@@ -4496,8 +4497,8 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t 
   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_passwords,
-  prev->upstream.ssl_passwords, NULL);
+ngx_conf_merge_ptr_value(conf->ssl_passwords,
+  prev->ssl_passwords, NULL);
 
 ngx_conf_merge_ptr_value(conf->ssl_conf_commands,
   prev->ssl_conf_commands, NULL);
@@ -4853,15 +4854,15 @@ ngx_http_grpc_ssl_password_file(ngx_conf
 
 ngx_str_t  *value;
 
-if (glcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) {
+if (glcf->ssl_passwords != NGX_CONF_UNSET_PTR) {
 return "is duplicate";
 }
 
 value = cf->args->elts;
 
-glcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]);
-
-if (glcf->upstream.ssl_passwords == NULL) {
+glcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]);
+
+if (glcf->ssl_passwords == NULL) {
 return NGX_CONF_ERROR;
 }
 
@@ -4890,7 +4891,7 @@ ngx_http_grpc_merge_ssl(ngx_conf_t *cf, 
 && conf->ssl_ciphers.data == NULL
 && conf->upstream.ssl_certificate == NGX_CONF_UNSET_PTR
 && conf->upstream.ssl_certificate_key == NGX_CONF_UNSET_PTR
-&& conf->upstream.ssl_passwords == NGX_CONF_UNSET_PTR
+&& conf->ssl_passwords == NGX_CONF_UNSET_PTR
 && conf->upstream.ssl_verify == NGX_CONF_UNSET
 && conf->ssl_verify_depth == NGX_CONF_UNSET_UINT
 && conf->ssl_trusted_certificate.data == NULL
@@ -4942,7 +4943,7 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ng
 || glcf->upstream.ssl_certificate_key->lengths))
 {
 glcf->upstream.ssl_passwords =
-  ngx_ssl_preserve_passwords(cf, glcf->upstream.ssl_passwords);
+  ngx_ssl_preserve_passwords(cf, glcf->ssl_passwords);
 if (glcf->upstream.ssl_passwords == NULL) {
 return NGX_ERROR;
 }
@@ -4987,7 +4988,7 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ng
 || glcf->upstream.ssl_certificate_key->lengths)
 {
 glcf->upstream.ssl_passwords =
-  ngx_ssl_preserve_passwords(cf, glcf->upstream.ssl_passwords);
+  ngx_ssl_preserve_passwords(cf, glcf->ssl_passwords);
 if (glcf->upstream.ssl_passwords == NULL) {
 return NGX_ERROR;
 }
@@ -4996,7 +4997,7 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ng
 if (ngx_ssl_certificate(cf, glcf->upstream.ssl,
 &glcf->upstream.ssl_certificate->value,
 

[nginx] Version bump.

2025-04-14 Thread Maxim Dounin
details:   http://freenginx.org/hg/nginx/rev/aeaee7ffdb78
branches:  
changeset: 9342:aeaee7ffdb78
user:  Maxim Dounin 
date:  Tue Apr 15 02:19:07 2025 +0300
description:
Version bump.

diffstat:

 src/core/nginx.h |  4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diffs (14 lines):

diff --git a/src/core/nginx.h b/src/core/nginx.h
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version  1027005
-#define NGINX_VERSION  "1.27.5"
+#define nginx_version  1027006
+#define NGINX_VERSION  "1.27.6"
 
 #define NGINX_NAME "freenginx"
 #define NGINX_VER  NGINX_NAME "/" NGINX_VERSION


[nginx] Upstream: fixed passwords usage for certificates with va...

2025-04-14 Thread Maxim Dounin
details:   http://freenginx.org/hg/nginx/rev/4f20c52c5f1b
branches:  
changeset: 9343:4f20c52c5f1b
user:  Maxim Dounin 
date:  Tue Apr 15 02:20:08 2025 +0300
description:
Upstream: fixed passwords usage for certificates with variables.

SSL certificate passwords are stored separately from the SSL context
created for SSL proxying, yet modified when the context is created
if certificates with variables are used (to ensure passwords will be
available at run time).  Optimizations introduced in 8053:9d98d524bd02
(1.23.1) did not take this into account, and might end up using at run
time passwords which weren't preserved to be usable at run time, such as
in the following configuration:

server {
proxy_ssl_certificate $crt;
proxy_ssl_certificate_key $key;
proxy_ssl_password_file foo;

location /1/ {
proxy_pass https://u;
}

location /2/ {
proxy_pass https://u;
}
}

Fix is to preserve passwords if needed when using an inherited SSL
context.

diffstat:

 src/http/modules/ngx_http_grpc_module.c  |  13 +
 src/http/modules/ngx_http_proxy_module.c |  13 +
 src/http/modules/ngx_http_uwsgi_module.c |  13 +
 3 files changed, 39 insertions(+), 0 deletions(-)

diffs (69 lines):

diff --git a/src/http/modules/ngx_http_grpc_module.c 
b/src/http/modules/ngx_http_grpc_module.c
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -4935,6 +4935,19 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ng
 ngx_pool_cleanup_t  *cln;
 
 if (glcf->upstream.ssl->ctx) {
+
+if (glcf->upstream.ssl_certificate
+&& glcf->upstream.ssl_certificate->value.len
+&& (glcf->upstream.ssl_certificate->lengths
+|| glcf->upstream.ssl_certificate_key->lengths))
+{
+glcf->upstream.ssl_passwords =
+  ngx_ssl_preserve_passwords(cf, glcf->upstream.ssl_passwords);
+if (glcf->upstream.ssl_passwords == NULL) {
+return NGX_ERROR;
+}
+}
+
 return NGX_OK;
 }
 
diff --git a/src/http/modules/ngx_http_proxy_module.c 
b/src/http/modules/ngx_http_proxy_module.c
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -4987,6 +4987,19 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, n
 ngx_pool_cleanup_t  *cln;
 
 if (plcf->upstream.ssl->ctx) {
+
+if (plcf->upstream.ssl_certificate
+&& plcf->upstream.ssl_certificate->value.len
+&& (plcf->upstream.ssl_certificate->lengths
+|| plcf->upstream.ssl_certificate_key->lengths))
+{
+plcf->upstream.ssl_passwords =
+  ngx_ssl_preserve_passwords(cf, plcf->upstream.ssl_passwords);
+if (plcf->upstream.ssl_passwords == NULL) {
+return NGX_ERROR;
+}
+}
+
 return NGX_OK;
 }
 
diff --git a/src/http/modules/ngx_http_uwsgi_module.c 
b/src/http/modules/ngx_http_uwsgi_module.c
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -2519,6 +2519,19 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, n
 ngx_pool_cleanup_t  *cln;
 
 if (uwcf->upstream.ssl->ctx) {
+
+if (uwcf->upstream.ssl_certificate
+&& uwcf->upstream.ssl_certificate->value.len
+&& (uwcf->upstream.ssl_certificate->lengths
+|| uwcf->upstream.ssl_certificate_key->lengths))
+{
+uwcf->upstream.ssl_passwords =
+  ngx_ssl_preserve_passwords(cf, uwcf->upstream.ssl_passwords);
+if (uwcf->upstream.ssl_passwords == NULL) {
+return NGX_ERROR;
+}
+}
+
 return NGX_OK;
 }
 


[nginx-tests] Tests: tests for proxy_ssl_password_file issue.

2025-04-14 Thread Maxim Dounin
details:   http://freenginx.org/hg/nginx-tests/rev/0a913a10945b
branches:  
changeset: 2007:0a913a10945b
user:  Maxim Dounin 
date:  Sun Apr 13 05:13:42 2025 +0300
description:
Tests: tests for proxy_ssl_password_file issue.

diffstat:

 proxy_ssl_certificate_vars.t |  27 ++-
 1 files changed, 26 insertions(+), 1 deletions(-)

diffs (49 lines):

diff --git a/proxy_ssl_certificate_vars.t b/proxy_ssl_certificate_vars.t
--- a/proxy_ssl_certificate_vars.t
+++ b/proxy_ssl_certificate_vars.t
@@ -61,6 +61,20 @@ http {
 proxy_ssl_certificate $arg_cert;
 proxy_ssl_certificate_key $arg_cert;
 }
+
+location /complex/ {
+proxy_ssl_certificate $arg_cert.example.com.crt;
+proxy_ssl_certificate_key $arg_cert.example.com.key;
+proxy_ssl_password_file password;
+
+location /complex/1 {
+proxy_pass https://127.0.0.1:8082/;
+}
+
+location /complex/2 {
+proxy_pass https://127.0.0.1:8082/;
+}
+}
 }
 
 server {
@@ -133,7 +147,7 @@ sleep 1 if $^O eq 'MSWin32';
 $t->write_file('password', '3.example.com');
 $t->write_file('index.html', '');
 
-$t->run()->plan(4);
+$t->run()->plan(6);
 
 ###
 
@@ -146,4 +160,15 @@ like(http_get('/encrypted?cert=3'),
 like(http_get('/none'),
qr/X-Verify: NONE/ms, 'variable - no certificate');
 
+like(http_get('/complex/1?cert=3'),
+   qr/X-Verify: SUCCESS/ms, 'variable - inherited encrypted key 1st');
+
+SKIP: {
+skip 'leaves coredump', 1 unless $t->has_version('1.27.6')
+   or $ENV{TEST_NGINX_UNSAFE};
+
+like(http_get('/complex/2?cert=3'),
+   qr/X-Verify: SUCCESS/ms, 'variable - inherited encrypted key 2nd');
+}
+
 ###


[nginx] SSL: improved handling of $ssl_curve and $ssl_curves var...

2025-04-14 Thread Maxim Dounin
details:   http://freenginx.org/hg/nginx/rev/22e6a225f605
branches:  
changeset: 9341:22e6a225f605
user:  Maxim Dounin 
date:  Tue Apr 15 02:09:29 2025 +0300
description:
SSL: improved handling of $ssl_curve and $ssl_curves variables.

Now both $ssl_curve and $ssl_curves try to use SSL_group_to_name()
if available and no NID is found.  Notably, this makes it possible to
see the name of the X25519MLKEM768 group as supported by OpenSSL 3.5.0.

diffstat:

 src/event/ngx_event_openssl.c |  72 --
 1 files changed, 61 insertions(+), 11 deletions(-)

diffs (108 lines):

diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -5270,6 +5270,26 @@ ngx_ssl_get_curve(ngx_connection_t *c, n
 return NGX_OK;
 }
 
+#if OPENSSL_VERSION_NUMBER >= 0x3000L
+{
+u_char  *name;
+
+name = (u_char *) SSL_group_to_name(c->ssl->connection, nid);
+
+if (name) {
+s->len = ngx_strlen(name);
+
+s->data = ngx_pnalloc(pool, s->len);
+if (s->data == NULL) {
+return NGX_ERROR;
+}
+
+ngx_memcpy(s->data, name, s->len);
+return NGX_OK;
+}
+}
+#endif
+
 s->len = sizeof("0x") - 1;
 
 s->data = ngx_pnalloc(pool, s->len);
@@ -5292,10 +5312,13 @@ ngx_ssl_get_curve(ngx_connection_t *c, n
 ngx_int_t
 ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
 {
-#ifdef SSL_CTRL_GET_CURVES
+#ifdef SSL_get1_curves
 
 int *curves, n, i, nid;
 u_char  *p;
+#if OPENSSL_VERSION_NUMBER >= 0x3000L
+u_char  *name;
+#endif
 size_t   len;
 
 n = SSL_get1_curves(c->ssl->connection, NULL);
@@ -5316,12 +5339,25 @@ ngx_ssl_get_curves(ngx_connection_t *c, 
 for (i = 0; i < n; i++) {
 nid = curves[i];
 
-if (nid & TLSEXT_nid_unknown) {
-len += sizeof("0x") - 1;
-
-} else {
+if ((nid & TLSEXT_nid_unknown) == 0) {
 len += ngx_strlen(OBJ_nid2sn(nid));
-}
+goto next_length;
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x3000L
+
+name = (u_char *) SSL_group_to_name(c->ssl->connection, nid);
+
+if (name) {
+len += ngx_strlen(name);
+goto next_length;
+}
+
+#endif
+
+len += sizeof("0x") - 1;
+
+next_length:
 
 len += sizeof(":") - 1;
 }
@@ -5336,12 +5372,26 @@ ngx_ssl_get_curves(ngx_connection_t *c, 
 for (i = 0; i < n; i++) {
 nid = curves[i];
 
-if (nid & TLSEXT_nid_unknown) {
-p = ngx_sprintf(p, "0x%04xd", nid & 0x);
-
-} else {
+if ((nid & TLSEXT_nid_unknown) == 0) {
 p = ngx_sprintf(p, "%s", OBJ_nid2sn(nid));
-}
+goto next_value;
+
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x3000L
+
+name = (u_char *) SSL_group_to_name(c->ssl->connection, nid);
+
+if (name) {
+p = ngx_sprintf(p, "%s", name);
+goto next_value;
+}
+
+#endif
+
+p = ngx_sprintf(p, "0x%04xd", nid & 0x);
+
+next_value:
 
 *p++ = ':';
 }