fix security issue with okhttp (#11749)

* Validate that hostname is ascii in OkHostnameVerifier.java
This commit is contained in:
ZachChuba 2024-12-16 16:31:36 -05:00 committed by Eric Anderson
parent 112dccbb6a
commit 05d9628e86
1 changed files with 18 additions and 3 deletions

View File

@ -29,10 +29,13 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.nio.charset.StandardCharsets;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSession;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
import com.google.common.base.Utf8;
import com.google.common.base.Ascii;
/** /**
* A HostnameVerifier consistent with <a * A HostnameVerifier consistent with <a
@ -63,6 +66,9 @@ public final class OkHostnameVerifier implements HostnameVerifier {
@Override @Override
public boolean verify(String host, SSLSession session) { public boolean verify(String host, SSLSession session) {
if (!isAscii(host)) {
return false;
}
try { try {
Certificate[] certificates = session.getPeerCertificates(); Certificate[] certificates = session.getPeerCertificates();
return verify(host, (X509Certificate) certificates[0]); return verify(host, (X509Certificate) certificates[0]);
@ -71,7 +77,7 @@ public final class OkHostnameVerifier implements HostnameVerifier {
} }
} }
public boolean verify(String host, X509Certificate certificate) { private boolean verify(String host, X509Certificate certificate) {
return verifyAsIpAddress(host) return verifyAsIpAddress(host)
? verifyIpAddress(host, certificate) ? verifyIpAddress(host, certificate)
: verifyHostName(host, certificate); : verifyHostName(host, certificate);
@ -98,7 +104,7 @@ public final class OkHostnameVerifier implements HostnameVerifier {
* Returns true if {@code certificate} matches {@code hostName}. * Returns true if {@code certificate} matches {@code hostName}.
*/ */
private boolean verifyHostName(String hostName, X509Certificate certificate) { private boolean verifyHostName(String hostName, X509Certificate certificate) {
hostName = hostName.toLowerCase(Locale.US); hostName = Ascii.toLowerCase(hostName);
boolean hasDns = false; boolean hasDns = false;
List<String> altNames = getSubjectAltNames(certificate, ALT_DNS_NAME); List<String> altNames = getSubjectAltNames(certificate, ALT_DNS_NAME);
for (int i = 0, size = altNames.size(); i < size; i++) { for (int i = 0, size = altNames.size(); i < size; i++) {
@ -198,7 +204,7 @@ public final class OkHostnameVerifier implements HostnameVerifier {
} }
// hostName and pattern are now absolute domain names. // hostName and pattern are now absolute domain names.
pattern = pattern.toLowerCase(Locale.US); pattern = Ascii.toLowerCase(pattern);
// hostName and pattern are now in lower case -- domain names are case-insensitive. // hostName and pattern are now in lower case -- domain names are case-insensitive.
if (!pattern.contains("*")) { if (!pattern.contains("*")) {
@ -254,4 +260,13 @@ public final class OkHostnameVerifier implements HostnameVerifier {
// hostName matches pattern // hostName matches pattern
return true; return true;
} }
/**
* Returns true if {@code input} is an ASCII string.
* @param input the string to check.
*/
private static boolean isAscii(String input) {
// Only ASCII characters are 1 byte in UTF-8.
return Utf8.encodedLength(input) == input.length();
}
} }