From 210d8f3cba65795c1f079b277a260af5934a4b1b Mon Sep 17 00:00:00 2001 From: ZachChuba <49295341+zachchuba@users.noreply.github.com> Date: Fri, 13 Dec 2024 09:52:54 -0500 Subject: [PATCH 1/2] Validate that hostname is ascii in OkHostnameVerifier.java Sec vuln fix --- .../okhttp/internal/OkHostnameVerifier.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/OkHostnameVerifier.java b/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/OkHostnameVerifier.java index 34bb56ee2d6..0efa386263b 100644 --- a/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/OkHostnameVerifier.java +++ b/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/OkHostnameVerifier.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Locale; import java.util.regex.Pattern; +import java.nio.charset.StandardCharsets; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; @@ -63,6 +64,9 @@ private OkHostnameVerifier() { @Override public boolean verify(String host, SSLSession session) { + if (!isAscii(host)) { + return false; + } try { Certificate[] certificates = session.getPeerCertificates(); return verify(host, (X509Certificate) certificates[0]); @@ -98,7 +102,7 @@ private boolean verifyIpAddress(String ipAddress, X509Certificate certificate) { * Returns true if {@code certificate} matches {@code hostName}. */ private boolean verifyHostName(String hostName, X509Certificate certificate) { - hostName = hostName.toLowerCase(Locale.US); + hostName = asciiToLowercase(hostName); boolean hasDns = false; List altNames = getSubjectAltNames(certificate, ALT_DNS_NAME); for (int i = 0, size = altNames.size(); i < size; i++) { @@ -198,7 +202,7 @@ private boolean verifyHostName(String hostName, String pattern) { } // hostName and pattern are now absolute domain names. - pattern = pattern.toLowerCase(Locale.US); + pattern = asciiToLowercase(pattern); // hostName and pattern are now in lower case -- domain names are case-insensitive. if (!pattern.contains("*")) { @@ -254,4 +258,22 @@ private boolean verifyHostName(String hostName, String pattern) { // hostName matches pattern return true; } + + /** + * Normalize the input to lowercase, if it is an ASCII string. + * Avoid unicode characters like \u1E0E from returning lowercased ascii + * that could match real hostnames. + */ + private static String asciiToLowercase(String input) { + if (isAscii(input)) { + return input.toLowerCase(Locale.US); + } else { + return input; + } + } + + private static boolean isAscii(String input) { + // Only ASCII characters are 1 byte in UTF-8. + return input.getBytes(StandardCharsets.UTF_8).length == input.length(); + } } From be38e8bb178ac2a11a4d527f7f42ce7ef9c5473d Mon Sep 17 00:00:00 2001 From: Zach Chuba Date: Mon, 16 Dec 2024 11:33:49 -0500 Subject: [PATCH 2/2] Validate that hostname is ascii in OkHostnameVerifier.java Sec vuln fix --- .../okhttp/internal/OkHostnameVerifier.java | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/OkHostnameVerifier.java b/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/OkHostnameVerifier.java index 0efa386263b..f6efb2d90e7 100644 --- a/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/OkHostnameVerifier.java +++ b/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/OkHostnameVerifier.java @@ -34,6 +34,8 @@ import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; import javax.security.auth.x500.X500Principal; +import com.google.common.base.Utf8; +import com.google.common.base.Ascii; /** * A HostnameVerifier consistent with altNames = getSubjectAltNames(certificate, ALT_DNS_NAME); for (int i = 0, size = altNames.size(); i < size; i++) { @@ -202,7 +204,7 @@ private boolean verifyHostName(String hostName, String pattern) { } // hostName and pattern are now absolute domain names. - pattern = asciiToLowercase(pattern); + pattern = Ascii.toLowerCase(pattern); // hostName and pattern are now in lower case -- domain names are case-insensitive. if (!pattern.contains("*")) { @@ -260,20 +262,11 @@ private boolean verifyHostName(String hostName, String pattern) { } /** - * Normalize the input to lowercase, if it is an ASCII string. - * Avoid unicode characters like \u1E0E from returning lowercased ascii - * that could match real hostnames. + * Returns true if {@code input} is an ASCII string. + * @param input the string to check. */ - private static String asciiToLowercase(String input) { - if (isAscii(input)) { - return input.toLowerCase(Locale.US); - } else { - return input; - } - } - private static boolean isAscii(String input) { // Only ASCII characters are 1 byte in UTF-8. - return input.getBytes(StandardCharsets.UTF_8).length == input.length(); + return Utf8.encodedLength(input) == input.length(); } }