From e91d17bdd729aba165c2e30dbfa169dc6c316fcc Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 22 Apr 2021 18:25:48 +0200 Subject: [PATCH 1/6] Fix #67792: HTTP Authorization schemes are treated as case-sensitive --- main/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/main.c b/main/main.c index 3450b4197f3d9..9ee5c978578af 100644 --- a/main/main.c +++ b/main/main.c @@ -2713,7 +2713,7 @@ PHPAPI int php_handle_auth_data(const char *auth) { int ret = -1; - if (auth && auth[0] != '\0' && strncmp(auth, "Basic ", 6) == 0) { + if (auth && auth[0] != '\0' && strncasecmp(auth, "Basic ", 6) == 0) { char *pass; zend_string *user; @@ -2736,7 +2736,7 @@ PHPAPI int php_handle_auth_data(const char *auth) SG(request_info).auth_digest = NULL; } - if (ret == -1 && auth && auth[0] != '\0' && strncmp(auth, "Digest ", 7) == 0) { + if (ret == -1 && auth && auth[0] != '\0' && strncasecmp(auth, "Digest ", 7) == 0) { SG(request_info).auth_digest = estrdup(auth + 7); ret = 0; } From f18e7eed576ddd0165c43f7be622103a551199bb Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 23 Apr 2021 10:40:37 +0200 Subject: [PATCH 2/6] Use zend_binary_strcasecmp() to avoid any locale issues --- main/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main/main.c b/main/main.c index 9ee5c978578af..5b9ac2c738ce9 100644 --- a/main/main.c +++ b/main/main.c @@ -2712,12 +2712,13 @@ PHPAPI void php_handle_aborted_connection(void) PHPAPI int php_handle_auth_data(const char *auth) { int ret = -1; + size_t auth_len = strlen(auth); - if (auth && auth[0] != '\0' && strncasecmp(auth, "Basic ", 6) == 0) { + if (auth && auth[0] != '\0' && zend_binary_strcasecmp(auth, auth_len, "Basic ", 6) == 0) { char *pass; zend_string *user; - user = php_base64_decode((const unsigned char*)auth + 6, strlen(auth) - 6); + user = php_base64_decode((const unsigned char*)auth + 6, auth_len - 6); if (user) { pass = strchr(ZSTR_VAL(user), ':'); if (pass) { @@ -2736,7 +2737,7 @@ PHPAPI int php_handle_auth_data(const char *auth) SG(request_info).auth_digest = NULL; } - if (ret == -1 && auth && auth[0] != '\0' && strncasecmp(auth, "Digest ", 7) == 0) { + if (ret == -1 && auth && auth[0] != '\0' && zend_binary_strcasecmp(auth, auth_len, "Digest ", 7) == 0) { SG(request_info).auth_digest = estrdup(auth + 7); ret = 0; } From dba98e757c1bba5a6140189191c8e4eb7c906b5a Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 23 Apr 2021 12:35:57 +0200 Subject: [PATCH 3/6] Inline strlen() calls --- main/main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/main/main.c b/main/main.c index 5b9ac2c738ce9..0e1ca3ea52a78 100644 --- a/main/main.c +++ b/main/main.c @@ -2712,13 +2712,12 @@ PHPAPI void php_handle_aborted_connection(void) PHPAPI int php_handle_auth_data(const char *auth) { int ret = -1; - size_t auth_len = strlen(auth); - if (auth && auth[0] != '\0' && zend_binary_strcasecmp(auth, auth_len, "Basic ", 6) == 0) { + if (auth && auth[0] != '\0' && zend_binary_strcasecmp(auth, strlen(auth), "Basic ", 6) == 0) { char *pass; zend_string *user; - user = php_base64_decode((const unsigned char*)auth + 6, auth_len - 6); + user = php_base64_decode((const unsigned char*)auth + 6, strlen(auth) - 6); if (user) { pass = strchr(ZSTR_VAL(user), ':'); if (pass) { @@ -2737,7 +2736,7 @@ PHPAPI int php_handle_auth_data(const char *auth) SG(request_info).auth_digest = NULL; } - if (ret == -1 && auth && auth[0] != '\0' && zend_binary_strcasecmp(auth, auth_len, "Digest ", 7) == 0) { + if (ret == -1 && auth && auth[0] != '\0' && zend_binary_strcasecmp(auth, strlen(auth), "Digest ", 7) == 0) { SG(request_info).auth_digest = estrdup(auth + 7); ret = 0; } From 7b7b7427397dbb49d67e843942620ab7d93e237c Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 23 Apr 2021 13:44:59 +0200 Subject: [PATCH 4/6] Use the proper zend_binary_strncasecmp() instead --- main/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/main.c b/main/main.c index 0e1ca3ea52a78..9ca3d77b2a8c0 100644 --- a/main/main.c +++ b/main/main.c @@ -2713,7 +2713,7 @@ PHPAPI int php_handle_auth_data(const char *auth) { int ret = -1; - if (auth && auth[0] != '\0' && zend_binary_strcasecmp(auth, strlen(auth), "Basic ", 6) == 0) { + if (auth && auth[0] != '\0' && zend_binary_strncasecmp(auth, strlen(auth), "Basic ", 6, 6) == 0) { char *pass; zend_string *user; @@ -2736,7 +2736,7 @@ PHPAPI int php_handle_auth_data(const char *auth) SG(request_info).auth_digest = NULL; } - if (ret == -1 && auth && auth[0] != '\0' && zend_binary_strcasecmp(auth, strlen(auth), "Digest ", 7) == 0) { + if (ret == -1 && auth && auth[0] != '\0' && zend_binary_strncasecmp(auth, strlen(auth), "Digest ", 7, 7) == 0) { SG(request_info).auth_digest = estrdup(auth + 7); ret = 0; } From de5f79995f125b1138a7b492f61a16e86e9d7333 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 23 Apr 2021 14:32:48 +0200 Subject: [PATCH 5/6] Refactor * call strlen(auth) only once * use sizeof() instead of magic numbers --- main/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main/main.c b/main/main.c index 9ca3d77b2a8c0..b17bbd7fe7b0a 100644 --- a/main/main.c +++ b/main/main.c @@ -2712,12 +2712,13 @@ PHPAPI void php_handle_aborted_connection(void) PHPAPI int php_handle_auth_data(const char *auth) { int ret = -1; + size_t auth_len = auth != NULL ? strlen(auth) : 0; - if (auth && auth[0] != '\0' && zend_binary_strncasecmp(auth, strlen(auth), "Basic ", 6, 6) == 0) { + if (auth && auth_len > 0 && zend_binary_strncasecmp(auth, auth_len, "Basic ", sizeof("Basic ")-1, sizeof("Basic ")-1) == 0) { char *pass; zend_string *user; - user = php_base64_decode((const unsigned char*)auth + 6, strlen(auth) - 6); + user = php_base64_decode((const unsigned char*)auth + 6, auth_len - 6); if (user) { pass = strchr(ZSTR_VAL(user), ':'); if (pass) { @@ -2736,7 +2737,7 @@ PHPAPI int php_handle_auth_data(const char *auth) SG(request_info).auth_digest = NULL; } - if (ret == -1 && auth && auth[0] != '\0' && zend_binary_strncasecmp(auth, strlen(auth), "Digest ", 7, 7) == 0) { + if (ret == -1 && auth && auth_len > 0 && zend_binary_strncasecmp(auth, auth_len, "Digest ", sizeof("Digest ")-1, sizeof("Digest ")-1) == 0) { SG(request_info).auth_digest = estrdup(auth + 7); ret = 0; } From 83e4cbe2cbf735eb18ae05d9d667af9f3f1440fe Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 23 Apr 2021 14:38:51 +0200 Subject: [PATCH 6/6] Add test case for Digest authentication --- sapi/cli/tests/php_cli_server_021.phpt | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 sapi/cli/tests/php_cli_server_021.phpt diff --git a/sapi/cli/tests/php_cli_server_021.phpt b/sapi/cli/tests/php_cli_server_021.phpt new file mode 100644 index 0000000000000..66ad4b225c919 --- /dev/null +++ b/sapi/cli/tests/php_cli_server_021.phpt @@ -0,0 +1,39 @@ +--TEST-- +Digest Authentication +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +HTTP/1.1 200 OK +Host: %s +Date: %s +Connection: close +X-Powered-By: PHP/%s +Content-type: text/html; charset=UTF-8 + +NULL +NULL +string(242) "username="Mufasa", realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/dir/index.html", qop=auth, nc=00000001, cnonce="0a4f113b", response="6629fae49393a05397450978507c4ef1", opaque="5ccc069c403ebaf9f0171e9517f40e41""