Reverted to simple wildcard matching
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1622696 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2466424d5d
commit
9e83772d35
|
@ -177,20 +177,46 @@ public abstract class AbstractVerifier implements X509HostnameVerifier {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean matchIdentity(final String host, final String identity, final boolean strictWithSubDomains) {
|
||||
return strictWithSubDomains ?
|
||||
DefaultHostnameVerifier.matchIdentityStrict(host, identity) :
|
||||
DefaultHostnameVerifier.matchIdentity(host, identity);
|
||||
private static boolean matchIdentity(final String host, final String identity, final boolean strict) {
|
||||
if (host == null) {
|
||||
return false;
|
||||
}
|
||||
final String normalizedHost = host.toLowerCase(Locale.ROOT);
|
||||
final String normalizedIdentity = identity.toLowerCase(Locale.ROOT);
|
||||
// The CN better have at least two dots if it wants wildcard
|
||||
// action. It also can't be [*.co.uk] or [*.co.jp] or
|
||||
// [*.org.uk], etc...
|
||||
final String parts[] = normalizedIdentity.split("\\.");
|
||||
final boolean doWildcard = parts.length >= 3 && parts[0].endsWith("*") &&
|
||||
(!strict || validCountryWildcard(parts));
|
||||
if (doWildcard) {
|
||||
boolean match;
|
||||
final String firstpart = parts[0];
|
||||
if (firstpart.length() > 1) { // e.g. server*
|
||||
final String prefix = firstpart.substring(0, firstpart.length() - 1); // e.g. server
|
||||
final String suffix = normalizedIdentity.substring(firstpart.length()); // skip wildcard part from cn
|
||||
final String hostSuffix = normalizedHost.substring(prefix.length()); // skip wildcard part from normalizedHost
|
||||
match = normalizedHost.startsWith(prefix) && hostSuffix.endsWith(suffix);
|
||||
} else {
|
||||
match = normalizedHost.endsWith(normalizedIdentity.substring(1));
|
||||
}
|
||||
return match && (!strict || countDots(normalizedHost) == countDots(normalizedIdentity));
|
||||
} else {
|
||||
return normalizedHost.equals(normalizedIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean acceptableCountryWildcard(final String cn) {
|
||||
final String parts[] = cn.split("\\.");
|
||||
private static boolean validCountryWildcard(final String parts[]) {
|
||||
if (parts.length != 3 || parts[2].length() != 2) {
|
||||
return true; // it's not an attempt to wildcard a 2TLD within a country code
|
||||
}
|
||||
return Arrays.binarySearch(BAD_COUNTRY_2LDS, parts[1]) < 0;
|
||||
}
|
||||
|
||||
public static boolean acceptableCountryWildcard(final String cn) {
|
||||
return validCountryWildcard(cn.split("\\."));
|
||||
}
|
||||
|
||||
public static String[] getCNs(final X509Certificate cert) {
|
||||
final String subjectPrincipal = cert.getSubjectX500Principal().toString();
|
||||
try {
|
||||
|
|
|
@ -35,9 +35,9 @@ import java.security.cert.X509Certificate;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import javax.naming.InvalidNameException;
|
||||
import javax.naming.NamingException;
|
||||
|
@ -63,11 +63,6 @@ import org.apache.http.conn.util.InetAddressUtils;
|
|||
@Immutable
|
||||
public final class DefaultHostnameVerifier implements HostnameVerifier {
|
||||
|
||||
public static final DefaultHostnameVerifier INSTANCE = new DefaultHostnameVerifier();
|
||||
|
||||
private final static Pattern WILDCARD_PATTERN = Pattern.compile(
|
||||
"^[a-z0-9\\-\\*]+(\\.[a-z0-9\\-]+){2,}$",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
/**
|
||||
* This contains a list of 2nd-level domains that aren't allowed to
|
||||
* have wildcards when combined with country-codes.
|
||||
|
@ -155,9 +150,11 @@ public final class DefaultHostnameVerifier implements HostnameVerifier {
|
|||
}
|
||||
|
||||
static void matchDNSName(final String host, final List<String> subjectAlts) throws SSLException {
|
||||
final String normalizedHost = host.toLowerCase(Locale.ROOT);
|
||||
for (int i = 0; i < subjectAlts.size(); i++) {
|
||||
final String subjectAlt = subjectAlts.get(i);
|
||||
if (matchIdentityStrict(host, subjectAlt)) {
|
||||
final String normalizedSubjectAlt = subjectAlt.toLowerCase(Locale.ROOT);
|
||||
if (matchIdentityStrict(normalizedHost, normalizedSubjectAlt)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -176,34 +173,31 @@ public final class DefaultHostnameVerifier implements HostnameVerifier {
|
|||
if (host == null) {
|
||||
return false;
|
||||
}
|
||||
// The CN better have at least two dots if it wants wildcard
|
||||
// action. It also can't be [*.co.uk] or [*.co.jp] or
|
||||
// [*.org.uk], etc...
|
||||
if (identity.contains("*") && WILDCARD_PATTERN.matcher(identity).matches()) {
|
||||
// RFC 2818, 3.1. Server Identity
|
||||
// "...Names may contain the wildcard
|
||||
// character * which is considered to match any single domain name
|
||||
// component or component fragment..."
|
||||
// Based on this statement presuming only singular wildcard is legal
|
||||
final int asteriskIdx = identity.indexOf('*');
|
||||
if (asteriskIdx != -1) {
|
||||
if (!strict || !BAD_COUNTRY_WILDCARD_PATTERN.matcher(identity).matches()) {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
buf.append("^");
|
||||
for (int i = 0; i < identity.length(); i++) {
|
||||
final char ch = identity.charAt(i);
|
||||
if (ch == '.') {
|
||||
buf.append("\\.");
|
||||
} else if (ch == '*') {
|
||||
if (strict) {
|
||||
buf.append("[a-z0-9\\-]*");
|
||||
} else {
|
||||
buf.append(".*");
|
||||
}
|
||||
} else {
|
||||
buf.append(ch);
|
||||
final String prefix = identity.substring(0, asteriskIdx);
|
||||
final String suffix = identity.substring(asteriskIdx + 1);
|
||||
if (!prefix.isEmpty() && !host.startsWith(prefix)) {
|
||||
return false;
|
||||
}
|
||||
if (!suffix.isEmpty() && !host.endsWith(suffix)) {
|
||||
return false;
|
||||
}
|
||||
// Additional sanity checks on content selected by wildcard can be done here
|
||||
if (strict) {
|
||||
final String remainder = host.substring(
|
||||
prefix.length(), host.length() - suffix.length());
|
||||
if (remainder.contains(".")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
buf.append("$");
|
||||
try {
|
||||
final Pattern identityPattern = Pattern.compile(buf.toString(), Pattern.CASE_INSENSITIVE);
|
||||
return identityPattern.matcher(host).matches();
|
||||
} catch (PatternSyntaxException ignore) {
|
||||
// do simple match
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return host.equalsIgnoreCase(identity);
|
||||
|
|
|
@ -148,7 +148,7 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
|
|||
* @since 4.4
|
||||
*/
|
||||
public static HostnameVerifier getDefaultHostnameVerifier() {
|
||||
return DefaultHostnameVerifier.INSTANCE;
|
||||
return new DefaultHostnameVerifier();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,7 +48,7 @@ public class TestDefaultHostnameVerifier {
|
|||
|
||||
@Before
|
||||
public void setup() {
|
||||
impl = DefaultHostnameVerifier.INSTANCE;
|
||||
impl = new DefaultHostnameVerifier();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -113,7 +113,7 @@ public class TestDefaultHostnameVerifier {
|
|||
x509 = (X509Certificate) cf.generateCertificate(in);
|
||||
exceptionPlease(impl, "foo.com", x509);
|
||||
impl.verify("www.foo.com", x509);
|
||||
exceptionPlease(impl, "\u82b1\u5b50.foo.com", x509);
|
||||
impl.verify("\u82b1\u5b50.foo.com", x509);
|
||||
exceptionPlease(impl, "a.b.foo.com", x509);
|
||||
|
||||
in = new ByteArrayInputStream(CertificatesToPlayWith.X509_WILD_CO_JP);
|
||||
|
@ -134,7 +134,7 @@ public class TestDefaultHostnameVerifier {
|
|||
// try the bar.com variations
|
||||
exceptionPlease(impl, "bar.com", x509);
|
||||
impl.verify("www.bar.com", x509);
|
||||
exceptionPlease(impl, "\u82b1\u5b50.bar.com", x509);
|
||||
impl.verify("\u82b1\u5b50.bar.com", x509);
|
||||
exceptionPlease(impl, "a.b.bar.com", x509);
|
||||
|
||||
in = new ByteArrayInputStream(CertificatesToPlayWith.X509_MULTIPLE_VALUE_AVA);
|
||||
|
@ -191,13 +191,6 @@ public class TestDefaultHostnameVerifier {
|
|||
Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.b.c", "*.b.c"));
|
||||
Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "*.b.c"));
|
||||
|
||||
Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.B.c", "*.b.c"));
|
||||
Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.B.c", "*.b.c"));
|
||||
|
||||
Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.b.C", "*.B.c"));
|
||||
Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.b.C", "*.B.c"));
|
||||
|
||||
|
||||
Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("s.a.b.c", "*.b.c"));
|
||||
Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.b.c", "*.b.c")); // subdomain not OK
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ public class TestHostnameVerifier {
|
|||
DEFAULT.verify("www.foo.com", x509);
|
||||
STRICT.verify("www.foo.com", x509);
|
||||
DEFAULT.verify("\u82b1\u5b50.foo.com", x509);
|
||||
exceptionPlease(STRICT, "\u82b1\u5b50.foo.com", x509);
|
||||
STRICT.verify("\u82b1\u5b50.foo.com", x509);
|
||||
DEFAULT.verify("a.b.foo.com", x509);
|
||||
exceptionPlease(STRICT, "a.b.foo.com", x509);
|
||||
|
||||
|
@ -171,7 +171,7 @@ public class TestHostnameVerifier {
|
|||
DEFAULT.verify("www.bar.com", x509);
|
||||
STRICT.verify("www.bar.com", x509);
|
||||
DEFAULT.verify("\u82b1\u5b50.bar.com", x509);
|
||||
exceptionPlease(STRICT, "\u82b1\u5b50.bar.com", x509);
|
||||
STRICT.verify("\u82b1\u5b50.bar.com", x509);
|
||||
DEFAULT.verify("a.b.bar.com", x509);
|
||||
exceptionPlease(STRICT, "a.b.bar.com", x509);
|
||||
|
||||
|
|
Loading…
Reference in New Issue