aboutsummaryrefslogtreecommitdiffstats
path: root/okhttp
diff options
context:
space:
mode:
authorAlex Klyubin <klyubin@google.com>2014-12-02 12:51:25 -0800
committerAlex Klyubin <klyubin@google.com>2014-12-04 09:27:14 -0800
commit57592013ea5a8d2aeb9842aa6e463d89fa6fa250 (patch)
tree4a4998305ba4571aaf06b498256d53c8fd446b14 /okhttp
parentfadae63ef6b2d35eec5c11700a340304a1fd0251 (diff)
downloadandroid_external_okhttp-57592013ea5a8d2aeb9842aa6e463d89fa6fa250.tar.gz
android_external_okhttp-57592013ea5a8d2aeb9842aa6e463d89fa6fa250.tar.bz2
android_external_okhttp-57592013ea5a8d2aeb9842aa6e463d89fa6fa250.zip
Strict, modern HostnameVerifier.
This brings OkHostnameVerifier up to date with the intersection of RFC 2818 and Baseline Requirements, and adds support for absolute domain names. The changes are: * Absolute domain names are supported. All presented hostnames are treated as absolute domain names. All domain names in server certificates are treated as absolute domain names as well. * Wildcard character (*) is permitted only in the left-most domain name label and must be the only character in that label. For example, *.example.com is permitted, while *a.example.com, a*.example.com, a*b.example.com, a.*.example.com are not permitted. * Wildcard character (*) must match exactly one domain name label. For example, *.example.com matches www.example.com, but does not match example.com or www.test.example.com. * Wildcard pattern cannot mach single-label domain names: * and *. patterns are rejected. Bug: 18432707 Bug: 17482685 Bug: 17548724 Bug: 17552202 Bug: 17552202 Change-Id: I560121f388568d0513a0cee22250b6fc59424b30
Diffstat (limited to 'okhttp')
-rw-r--r--okhttp/src/main/java/com/squareup/okhttp/internal/tls/OkHostnameVerifier.java98
1 files changed, 74 insertions, 24 deletions
diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/tls/OkHostnameVerifier.java b/okhttp/src/main/java/com/squareup/okhttp/internal/tls/OkHostnameVerifier.java
index 326872a..10dbd93 100644
--- a/okhttp/src/main/java/com/squareup/okhttp/internal/tls/OkHostnameVerifier.java
+++ b/okhttp/src/main/java/com/squareup/okhttp/internal/tls/OkHostnameVerifier.java
@@ -58,6 +58,7 @@ public final class OkHostnameVerifier implements HostnameVerifier {
private OkHostnameVerifier() {
}
+ @Override
public boolean verify(String host, SSLSession session) {
try {
Certificate[] certificates = session.getPeerCertificates();
@@ -144,48 +145,97 @@ public final class OkHostnameVerifier implements HostnameVerifier {
}
/**
- * Returns true if {@code hostName} matches the name or pattern {@code cn}.
+ * Returns {@code true} iff {@code hostName} matches the domain name {@code pattern}.
*
- * @param hostName lowercase host name.
- * @param cn certificate host name. May include wildcards like
- * {@code *.android.com}.
+ * @param hostName lower-case host name.
+ * @param pattern domain name pattern from certificate. May be a wildcard pattern such as
+ * {@code *.android.com}.
*/
- public boolean verifyHostName(String hostName, String cn) {
+ private boolean verifyHostName(String hostName, String pattern) {
+ // Basic sanity checks
// Check length == 0 instead of .isEmpty() to support Java 5.
- if (hostName == null || hostName.length() == 0 || cn == null || cn.length() == 0) {
+ if ((hostName == null) || (hostName.length() == 0) || (hostName.startsWith("."))
+ || (hostName.endsWith(".."))) {
+ // Invalid domain name
+ return false;
+ }
+ if ((pattern == null) || (pattern.length() == 0) || (pattern.startsWith("."))
+ || (pattern.endsWith(".."))) {
+ // Invalid pattern/domain name
return false;
}
- cn = cn.toLowerCase(Locale.US);
-
- if (!cn.contains("*")) {
- return hostName.equals(cn);
+ // Normalize hostName and pattern by turning them into absolute domain names if they are not
+ // yet absolute. This is needed because server certificates do not normally contain absolute
+ // names or patterns, but they should be treated as absolute. At the same time, any hostName
+ // presented to this method should also be treated as absolute for the purposes of matching
+ // to the server certificate.
+ // www.android.com matches www.android.com
+ // www.android.com matches www.android.com.
+ // www.android.com. matches www.android.com.
+ // www.android.com. matches www.android.com
+ if (!hostName.endsWith(".")) {
+ hostName += '.';
}
+ if (!pattern.endsWith(".")) {
+ pattern += '.';
+ }
+ // hostName and pattern are now absolute domain names.
+
+ pattern = pattern.toLowerCase(Locale.US);
+ // hostName and pattern are now in lower case -- domain names are case-insensitive.
- if (cn.startsWith("*.") && hostName.regionMatches(0, cn, 2, cn.length() - 2)) {
- return true; // "*.foo.com" matches "foo.com"
+ if (!pattern.contains("*")) {
+ // Not a wildcard pattern -- hostName and pattern must match exactly.
+ return hostName.equals(pattern);
+ }
+ // Wildcard pattern
+
+ // WILDCARD PATTERN RULES:
+ // 1. Asterisk (*) is only permitted in the left-most domain name label and must be the
+ // only character in that label (i.e., must match the whole left-most label).
+ // For example, *.example.com is permitted, while *a.example.com, a*.example.com,
+ // a*b.example.com, a.*.example.com are not permitted.
+ // 2. Asterisk (*) cannot match across domain name labels.
+ // For example, *.example.com matches test.example.com but does not match
+ // sub.test.example.com.
+ // 3. Wildcard patterns for single-label domain names are not permitted.
+
+ if ((!pattern.startsWith("*.")) || (pattern.indexOf('*', 1) != -1)) {
+ // Asterisk (*) is only permitted in the left-most domain name label and must be the only
+ // character in that label
+ return false;
}
- int asterisk = cn.indexOf('*');
- int dot = cn.indexOf('.');
- if (asterisk > dot) {
- return false; // malformed; wildcard must be in the first part of the cn
+ // Optimization: check whether hostName is too short to match the pattern. hostName must be at
+ // least as long as the pattern because asterisk must match the whole left-most label and
+ // hostName starts with a non-empty label. Thus, asterisk has to match one or more characters.
+ if (hostName.length() < pattern.length()) {
+ // hostName too short to match the pattern.
+ return false;
}
- if (!hostName.regionMatches(0, cn, 0, asterisk)) {
- return false; // prefix before '*' doesn't match
+ if ("*.".equals(pattern)) {
+ // Wildcard pattern for single-label domain name -- not permitted.
+ return false;
}
- int suffixLength = cn.length() - (asterisk + 1);
- int suffixStart = hostName.length() - suffixLength;
- if (hostName.indexOf('.', asterisk) < suffixStart) {
- return false; // wildcard '*' can't match a '.'
+ // hostName must end with the region of pattern following the asterisk.
+ String suffix = pattern.substring(1);
+ if (!hostName.endsWith(suffix)) {
+ // hostName does not end with the suffix
+ return false;
}
- if (!hostName.regionMatches(suffixStart, cn, asterisk + 1, suffixLength)) {
- return false; // suffix after '*' doesn't match
+ // Check that asterisk did not match across domain name labels.
+ int suffixStartIndexInHostName = hostName.length() - suffix.length();
+ if ((suffixStartIndexInHostName > 0)
+ && (hostName.lastIndexOf('.', suffixStartIndexInHostName - 1) != -1)) {
+ // Asterisk is matching across domain name labels -- not permitted.
+ return false;
}
+ // hostName matches pattern
return true;
}
}