From 4f28cbd41827bf2d57ef1f45539b2b276212e292 Mon Sep 17 00:00:00 2001
From: Michael Rodler <mrodler@amazon.de>
Date: Fri, 9 Jun 2023 15:00:02 +0200
Subject: [PATCH] early reject URI authority if too many ":" chars

Signed-off-by: Michael Rodler <mrodler@amazon.de>
---
 src/uri/authority.rs | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/uri/authority.rs b/src/uri/authority.rs
index 0f701e5f..f41ddd19 100644
--- a/src/uri/authority.rs
+++ b/src/uri/authority.rs
@@ -69,12 +69,13 @@ impl Authority {
     // Postcondition: for all Ok() returns, s[..ret.unwrap()] is valid UTF-8 where
     // ret is the return value.
     pub(super) fn parse(s: &[u8]) -> Result<usize, InvalidUri> {
-        let mut colon_cnt = 0;
+        let mut colon_cnt = 0u32;
         let mut start_bracket = false;
         let mut end_bracket = false;
         let mut has_percent = false;
         let mut end = s.len();
         let mut at_sign_pos = None;
+        const MAX_COLONS: u32 = 8; // e.g., [FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80
 
         // Among other things, this loop checks that every byte in s up to the
         // first '/', '?', or '#' is a valid URI character (or in some contexts,
@@ -87,6 +88,9 @@ impl Authority {
                     break;
                 }
                 b':' => {
+                    if colon_cnt >= MAX_COLONS {
+                        return Err(ErrorKind::InvalidAuthority.into());
+                    }
                     colon_cnt += 1;
                 }
                 b'[' => {
@@ -644,6 +648,12 @@ mod tests {
         assert_eq!(result, authority_str);
     }
 
+    #[test]
+    fn reject_obviously_invalid_ipv6_address() {
+        let err = Authority::parse_non_empty(b"[0:1:2:3:4:5:6:7:8:9:10:11:12:13:14]").unwrap_err();
+        assert_eq!(err.0, ErrorKind::InvalidAuthority);
+    }
+
     #[test]
     fn rejects_percent_outside_ipv6_address() {
         let err = Authority::parse_non_empty(b"1234%20[fe80::1:2:3:4]").unwrap_err();