]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Fix OSSL_parse_url userinfo scan past authority
author1seal <security@1seal.org>
Mon, 9 Mar 2026 10:48:49 +0000 (11:48 +0100)
committerTomas Mraz <tomas@openssl.org>
Wed, 11 Mar 2026 10:22:46 +0000 (11:22 +0100)
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Norbert Pocs <norbertp@openssl.org>
MergeDate: Wed Mar 11 10:22:54 2026
(Merged from https://github.com/openssl/openssl/pull/30319)

crypto/http/http_lib.c
test/http_test.c

index 54c5c6ec1d8f3aa81a8576fc3b0e8cf49f0040f0..2821c0ec528d906b4745f44f64ca2826b12d6458 100644 (file)
@@ -55,6 +55,7 @@ int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost,
     char **ppath, char **pquery, char **pfrag)
 {
     const char *p, *tmp;
+    const char *authority_end;
     const char *scheme, *scheme_end;
     const char *user, *user_end;
     const char *host, *host_end;
@@ -92,7 +93,10 @@ int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost,
 
     /* parse optional "userinfo@" */
     user = user_end = host = p;
-    host = strchr(p, '@');
+    authority_end = strpbrk(p, "/?#");
+    if (authority_end == NULL)
+        authority_end = p + strlen(p);
+    host = memchr(p, '@', authority_end - p);
     if (host != NULL)
         user_end = host++;
     else
index e7a402dae61559aeb493b19dda80f32e29191099..c7e4630d93f854161fdc9fd2388855a6ee065f91 100644 (file)
@@ -331,6 +331,18 @@ static int test_http_url_path_query_ok(const char *url, const char *exp_path_qu)
     return res;
 }
 
+static int test_http_url_host_ok(const char *url, const char *exp_host)
+{
+    char *host;
+    int res;
+
+    res = TEST_true(OSSL_HTTP_parse_url(url, NULL, NULL, &host, NULL, NULL,
+              NULL, NULL, NULL))
+        && TEST_str_eq(host, exp_host);
+    OPENSSL_free(host);
+    return res;
+}
+
 static int test_http_url_dns(void)
 {
     return test_http_url_ok("host:65535/path", 0, "host", "65535", "/path");
@@ -358,6 +370,13 @@ static int test_http_url_userinfo_query_fragment(void)
     return test_http_url_ok("user:pass@host/p?q#fr", 0, "host", "80", "/p");
 }
 
+static int test_http_url_at_sign_outside_authority(void)
+{
+    return test_http_url_host_ok("http://host/p@attacker.test", "host")
+        && test_http_url_host_ok("http://host/p?q=@attacker.test", "host")
+        && test_http_url_host_ok("http://host/p?q#fr@attacker.test", "host");
+}
+
 static int test_http_url_ipv4(void)
 {
     return test_http_url_ok("https://1.2.3.4/p/q", 1, "1.2.3.4", "443", "/p/q");
@@ -576,6 +595,7 @@ int setup_tests(void)
     ADD_TEST(test_http_url_timestamp);
     ADD_TEST(test_http_url_path_query);
     ADD_TEST(test_http_url_userinfo_query_fragment);
+    ADD_TEST(test_http_url_at_sign_outside_authority);
     ADD_TEST(test_http_url_ipv4);
     ADD_TEST(test_http_url_ipv6);
     ADD_TEST(test_http_url_invalid_prefix);