From b923e54743b26c29e71703fa5de4a53bef970079 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Mon, 6 May 2013 13:17:38 -0700 Subject: NativeCrypto: remove dep on Android host verifier DefaultHostnameVerifier on Android actually does something, but it doesn't do anything on other JVMs. Copy out the method we need instead of relying on the implementation in Android's libcore. Change-Id: Ic623c366cbba957597021786045094de3cba82d7 --- .../main/java/org/conscrypt/CertPinManager.java | 51 ++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) (limited to 'crypto') diff --git a/crypto/src/main/java/org/conscrypt/CertPinManager.java b/crypto/src/main/java/org/conscrypt/CertPinManager.java index df0cb8f..22578fc 100644 --- a/crypto/src/main/java/org/conscrypt/CertPinManager.java +++ b/crypto/src/main/java/org/conscrypt/CertPinManager.java @@ -22,8 +22,8 @@ import java.io.IOException; import java.security.cert.X509Certificate; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; -import javax.net.ssl.DefaultHostnameVerifier; import libcore.io.IoUtils; import libcore.util.BasicLruCache; @@ -36,7 +36,6 @@ public class CertPinManager { private final Map entries = new HashMap(); private final BasicLruCache hostnameCache = new BasicLruCache(10); - private final DefaultHostnameVerifier verifier = new DefaultHostnameVerifier(); private boolean initialized = false; private static final boolean DEBUG = false; @@ -166,13 +165,59 @@ public class CertPinManager { continue; } // now verify that the CN matches at all - if (verifier.verifyHostName(hostname, cn)) { + if (isHostnameMatchedBy(hostname, cn)) { bestMatch = cn; } } return bestMatch; } + /** + * Returns true if {@code hostName} matches the name or pattern {@code cn}. + * + * @param hostName lowercase host name. + * @param cn certificate host name. May include wildcards like + * {@code *.android.com}. + */ + private static boolean isHostnameMatchedBy(String hostName, String cn) { + if (hostName == null || hostName.isEmpty() || cn == null || cn.isEmpty()) { + return false; + } + + cn = cn.toLowerCase(Locale.US); + + if (!cn.contains("*")) { + return hostName.equals(cn); + } + + if (cn.startsWith("*.") && hostName.regionMatches(0, cn, 2, cn.length() - 2)) { + return true; // "*.foo.com" matches "foo.com" + } + + int asterisk = cn.indexOf('*'); + int dot = cn.indexOf('.'); + if (asterisk > dot) { + return false; // malformed; wildcard must be in the first part of + // the cn + } + + if (!hostName.regionMatches(0, cn, 0, asterisk)) { + return false; // prefix before '*' doesn't match + } + + int suffixLength = cn.length() - (asterisk + 1); + int suffixStart = hostName.length() - suffixLength; + if (hostName.indexOf('.', asterisk) < suffixStart) { + return false; // wildcard '*' can't match a '.' + } + + if (!hostName.regionMatches(suffixStart, cn, asterisk + 1, suffixLength)) { + return false; // suffix after '*' doesn't match + } + + return true; + } + private static void log(String s, Exception e) { if (DEBUG) { System.out.println("PINFILE: " + s); -- cgit v1.1