From 42b9781db80034a3500a06600c7e4a580a263cff Mon Sep 17 00:00:00 2001 From: Martin Redolatti Date: Tue, 24 Jun 2025 15:25:15 -0300 Subject: [PATCH 1/4] add support for proxy_connect module --- ngx_http_auth_digest_module.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/ngx_http_auth_digest_module.c b/ngx_http_auth_digest_module.c index a388a9d..e0cb5ae 100644 --- a/ngx_http_auth_digest_module.c +++ b/ngx_http_auth_digest_module.c @@ -640,6 +640,34 @@ ngx_http_auth_digest_verify_hash(ngx_http_request_t *r, ngx_md5_t md5; u_char hash[16]; + // incoming requests with CONNECT method don't set `r->unparsed_uri`, matching + // needs to be done based on server & port +#ifdef NGX_HTTP_PROXY_CONNECT + if (r->method_name.len == 7 && ngx_strncmp(r->method_name.data, "CONNECT", 7) == 0) { + // CONNECT requests don't have `r->unparsed_uri` set, so the URI must be validated + // against server address (& optionally port) + size_t uri_len = 0; + while (uri_len < fields->uri.len && fields->uri.data[uri_len++] != ':'); + if (uri_len < fields->uri.len && fields->uri.data[uri_len] == ':') { + uri_len--; + } + if (!((r->connect_host.len == (uri_len - 1)) && + (ngx_strncmp(r->connect_host.data, fields->uri.data, + uri_len) == 0))) { + return NGX_DECLINED; + } + if (uri_len + 1 < fields->uri.len && fields->uri.data[uri_len + 1] == ':') { + // need to check port as well + uri_len += 2; // skip `:` and position pointer at port + u_char* uri_port = fields->uri.data + uri_len; + size_t uri_port_len = fields->uri.len - uri_len; + if (!((uri_port_len != r->connect_port.len) && + (ngx_strncmp(uri_port, r->connect_port.data, ngx_min(uri_port_len, r->connect_port.len)) == 0))) { + return NGX_DECLINED; + } + } + } else { +#endif // The .net Http library sends the incorrect URI as part of the Authorization // response. Instead of the complete URI including the query parameters it // sends only the basic URI without the query parameters. It also uses this @@ -660,6 +688,9 @@ ngx_http_auth_digest_verify_hash(ngx_http_request_t *r, return NGX_DECLINED; } } +#ifdef NGX_HTTP_PROXY_CONNECT + } +#endif // the hashing scheme: // digest: @@ -839,7 +870,7 @@ ngx_http_auth_digest_verify_hash(ngx_http_request_t *r, // Set the stale value to 1 because the nonce value was not found in // the digest tree, but the computation is valid. fields->stale = 1; - + invalid: // nonce is invalid/expired or client reused an nc value. suspicious... ngx_shmtx_unlock(&shpool->mutex); From 7f8c8ab1bfb4d156f42c93695c85fceae8fdde1b Mon Sep 17 00:00:00 2001 From: Martin Redolatti Date: Tue, 24 Jun 2025 15:32:36 -0300 Subject: [PATCH 2/4] remove extra whitespace --- ngx_http_auth_digest_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngx_http_auth_digest_module.c b/ngx_http_auth_digest_module.c index e0cb5ae..338e8d6 100644 --- a/ngx_http_auth_digest_module.c +++ b/ngx_http_auth_digest_module.c @@ -870,7 +870,7 @@ ngx_http_auth_digest_verify_hash(ngx_http_request_t *r, // Set the stale value to 1 because the nonce value was not found in // the digest tree, but the computation is valid. fields->stale = 1; - + invalid: // nonce is invalid/expired or client reused an nc value. suspicious... ngx_shmtx_unlock(&shpool->mutex); From c9c40d54a1462a84089d84084a38a1073621f8c1 Mon Sep 17 00:00:00 2001 From: Martin Redolatti Date: Tue, 24 Jun 2025 15:34:31 -0300 Subject: [PATCH 3/4] remove duplicate comment --- ngx_http_auth_digest_module.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ngx_http_auth_digest_module.c b/ngx_http_auth_digest_module.c index 338e8d6..bc56ff5 100644 --- a/ngx_http_auth_digest_module.c +++ b/ngx_http_auth_digest_module.c @@ -640,8 +640,6 @@ ngx_http_auth_digest_verify_hash(ngx_http_request_t *r, ngx_md5_t md5; u_char hash[16]; - // incoming requests with CONNECT method don't set `r->unparsed_uri`, matching - // needs to be done based on server & port #ifdef NGX_HTTP_PROXY_CONNECT if (r->method_name.len == 7 && ngx_strncmp(r->method_name.data, "CONNECT", 7) == 0) { // CONNECT requests don't have `r->unparsed_uri` set, so the URI must be validated From e6e0fe85580ba6f9c2c4e2c080001764c5e1c3fd Mon Sep 17 00:00:00 2001 From: Martin Redolatti Date: Wed, 2 Jul 2025 11:43:11 -0300 Subject: [PATCH 4/4] code polishing --- ngx_http_auth_digest_module.c | 51 +++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/ngx_http_auth_digest_module.c b/ngx_http_auth_digest_module.c index bc56ff5..d998765 100644 --- a/ngx_http_auth_digest_module.c +++ b/ngx_http_auth_digest_module.c @@ -641,29 +641,34 @@ ngx_http_auth_digest_verify_hash(ngx_http_request_t *r, u_char hash[16]; #ifdef NGX_HTTP_PROXY_CONNECT - if (r->method_name.len == 7 && ngx_strncmp(r->method_name.data, "CONNECT", 7) == 0) { - // CONNECT requests don't have `r->unparsed_uri` set, so the URI must be validated - // against server address (& optionally port) - size_t uri_len = 0; - while (uri_len < fields->uri.len && fields->uri.data[uri_len++] != ':'); - if (uri_len < fields->uri.len && fields->uri.data[uri_len] == ':') { - uri_len--; - } - if (!((r->connect_host.len == (uri_len - 1)) && - (ngx_strncmp(r->connect_host.data, fields->uri.data, - uri_len) == 0))) { - return NGX_DECLINED; - } - if (uri_len + 1 < fields->uri.len && fields->uri.data[uri_len + 1] == ':') { - // need to check port as well - uri_len += 2; // skip `:` and position pointer at port - u_char* uri_port = fields->uri.data + uri_len; - size_t uri_port_len = fields->uri.len - uri_len; - if (!((uri_port_len != r->connect_port.len) && - (ngx_strncmp(uri_port, r->connect_port.data, ngx_min(uri_port_len, r->connect_port.len)) == 0))) { - return NGX_DECLINED; - } - } + if (r->method == NGX_HTTP_CONNECT) { + // CONNECT requests don't have `r->unparsed_uri` set, so the URI must be validated + // against server address (host & port) + u_char* host_end = memchr(fields->uri.data, ':', fields->uri.len); + if (host_end == NULL) { + // CONNECT requests have no default port, if `:` is not found request is considered malformed + return NGX_DECLINED; + } + + size_t host_len = host_end - fields->uri.data; + if (!((r->connect_host.len == (host_len)) && + (ngx_strncmp(r->connect_host.data, fields->uri.data, + host_len) == 0))) { + return NGX_DECLINED; + } + + u_char* port_start = host_end + 1; + u_char* uri_end = fields->uri.data + fields->uri.len; + if (port_start >= uri_end) { + // Port shold have at least 1 digit + return NGX_DECLINED; + } + + size_t port_len = uri_end - port_start; + if (!((port_len == r->connect_port.len) && + (ngx_strncmp(port_start, r->connect_port.data, ngx_min(port_len, r->connect_port.len)) == 0))) { + return NGX_DECLINED; + } } else { #endif // The .net Http library sends the incorrect URI as part of the Authorization