summaryrefslogtreecommitdiffstats
path: root/luni
diff options
context:
space:
mode:
Diffstat (limited to 'luni')
-rwxr-xr-xluni/src/main/files/README.cacerts2
-rw-r--r--luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java202
-rw-r--r--luni/src/main/java/javax/net/ssl/HttpsURLConnection.java11
-rw-r--r--luni/src/test/java/libcore/java/util/OldTimeZoneTest.java14
-rw-r--r--luni/src/test/java/libcore/java/util/TimeZoneTest.java6
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java71
6 files changed, 76 insertions, 230 deletions
diff --git a/luni/src/main/files/README.cacerts b/luni/src/main/files/README.cacerts
index e905a68..ca5c570 100755
--- a/luni/src/main/files/README.cacerts
+++ b/luni/src/main/files/README.cacerts
@@ -1,7 +1,7 @@
The filenames in the cacerts directory are in the format of <hash>.<n>
where "hash" is the subject hash produced by:
- openssl x509 -subject_hash -in filename
+ openssl x509 -subject_hash_old -in filename
and the "n" is a unique integer identifier starting at 0 to deal
with collisions. See OpenSSL's c_rehash manpage for details.
diff --git a/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java b/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
deleted file mode 100644
index e513cf2..0000000
--- a/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.net.ssl;
-
-import java.net.InetAddress;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateParsingException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import javax.security.auth.x500.X500Principal;
-
-/**
- * A HostnameVerifier consistent with <a
- * href="http://www.ietf.org/rfc/rfc2818.txt">RFC 2818</a>.
- *
- * @hide accessible via HttpsURLConnection.getDefaultHostnameVerifier()
- */
-public final class DefaultHostnameVerifier implements HostnameVerifier {
- private static final int ALT_DNS_NAME = 2;
- private static final int ALT_IPA_NAME = 7;
-
- @Override
- public final boolean verify(String host, SSLSession session) {
- try {
- Certificate[] certificates = session.getPeerCertificates();
- return verify(host, (X509Certificate) certificates[0]);
- } catch (SSLException e) {
- return false;
- }
- }
-
- private boolean verify(String host, X509Certificate certificate) {
- return InetAddress.isNumeric(host)
- ? verifyIpAddress(host, certificate)
- : verifyHostName(host, certificate);
- }
-
- /**
- * Returns true if {@code certificate} matches {@code ipAddress}.
- */
- private boolean verifyIpAddress(String ipAddress, X509Certificate certificate) {
- for (String altName : getSubjectAltNames(certificate, ALT_IPA_NAME)) {
- if (ipAddress.equalsIgnoreCase(altName)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if {@code certificate} matches {@code hostName}.
- */
- private boolean verifyHostName(String hostName, X509Certificate certificate) {
- hostName = hostName.toLowerCase(Locale.US);
- boolean hasDns = false;
- for (String altName : getSubjectAltNames(certificate, ALT_DNS_NAME)) {
- hasDns = true;
- if (verifyHostName(hostName, altName)) {
- return true;
- }
- }
-
- if (!hasDns) {
- X500Principal principal = certificate.getSubjectX500Principal();
- // RFC 2818 advises using the most specific name for matching.
- String cn = new DistinguishedNameParser(principal).findMostSpecific("cn");
- if (cn != null) {
- return verifyHostName(hostName, cn);
- }
- }
-
- return false;
- }
-
- private List<String> getSubjectAltNames(X509Certificate certificate, int type) {
- List<String> result = new ArrayList<String>();
- try {
- Collection<?> subjectAltNames = certificate.getSubjectAlternativeNames();
- if (subjectAltNames == null) {
- return Collections.emptyList();
- }
- for (Object subjectAltName : subjectAltNames) {
- List<?> entry = (List<?>) subjectAltName;
- if (entry == null || entry.size() < 2) {
- continue;
- }
- Integer altNameType = (Integer) entry.get(0);
- if (altNameType == null) {
- continue;
- }
- if (altNameType == type) {
- String altName = (String) entry.get(1);
- if (altName != null) {
- result.add(altName);
- }
- }
- }
- return result;
- } catch (CertificateParsingException e) {
- return Collections.emptyList();
- }
- }
-
- /**
- * 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 boolean verifyHostName(String hostName, String cn) {
- if (hostName == null || hostName.isEmpty() || cn == null || cn.isEmpty()) {
- return false;
- }
-
- if (hostName.endsWith(".") && !cn.endsWith(".")) {
- // "www.android.com." matches "www.android.com"
- // This is needed because server certificates do not normally contain absolute names
- // or patterns. Connections via absolute hostnames should be supported and even
- // preferred over those via relative hostnames, to avoid DNS suffixes being appended.
- cn += '.';
- }
-
- cn = cn.toLowerCase(Locale.US);
-
- if (!cn.contains("*")) {
- return hostName.equals(cn);
- }
-
- if (!containsAtLeastTwoDomainNameLabelsExcludingRoot(cn)) {
- return false; // reject matches where the wildcard pattern consists of only one label.
- }
-
- 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;
- }
-
- /**
- * Checks whether the provided hostname consists of at least two domain name labels, excluding
- * the root label.
- *
- * <p>For example, this method returns {@code true} for {@code www.android.com} and
- * {@code foo.com} and {@code foo.com.}, and returns {@code false} for {@code foo} and
- * {@code foo.}.
- */
- private static boolean containsAtLeastTwoDomainNameLabelsExcludingRoot(String hostname) {
- int delimiterIndex = hostname.indexOf('.');
- if (delimiterIndex == -1) {
- // No delimiters -- only one label
- return false;
- }
- if (delimiterIndex == hostname.length() - 1) {
- // Only one delimiter at the every end of the hostname -- this is an absolute hostname
- // consisting of one label
- return false;
- }
- // At least two labels
- return true;
- }
-}
diff --git a/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java b/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java
index ab86a9b..1bd48fd 100644
--- a/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java
+++ b/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java
@@ -109,7 +109,16 @@ public abstract class HttpsURLConnection extends HttpURLConnection {
* it.
*/
private static class NoPreloadHolder {
- public static HostnameVerifier defaultHostnameVerifier = new DefaultHostnameVerifier();
+ public static HostnameVerifier defaultHostnameVerifier;
+ static {
+ try {
+ defaultHostnameVerifier = (HostnameVerifier)
+ Class.forName("com.android.okhttp.internal.tls.OkHostnameVerifier")
+ .getField("INSTANCE").get(null);
+ } catch (Exception e) {
+ throw new AssertionError("Failed to obtain okhttp HostnameVerifier", e);
+ }
+ }
public static SSLSocketFactory defaultSSLSocketFactory = (SSLSocketFactory) SSLSocketFactory
.getDefault();
diff --git a/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java b/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
index ecf2e5f..7a5fc4a 100644
--- a/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
@@ -108,7 +108,7 @@ public class OldTimeZoneTest extends TestCase {
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
assertEquals("Pacific Daylight Time", tz.getDisplayName(true, TimeZone.LONG, Locale.US));
assertEquals("Pacific Standard Time", tz.getDisplayName(false, TimeZone.LONG, Locale.UK));
- assertEquals("heure avanc\u00e9e du Pacifique",
+ assertEquals("heure d’été du Pacifique",
tz.getDisplayName(true, TimeZone.LONG, Locale.FRANCE));
assertEquals("heure normale du Pacifique nord-américain",
tz.getDisplayName(false, TimeZone.LONG, Locale.FRANCE));
@@ -123,18 +123,6 @@ public class OldTimeZoneTest extends TestCase {
assertEquals("GMT-07:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.FRANCE));
assertEquals("GMT-08:00", tz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
assertEquals("GMT-07:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
-
- // The RI behavior mentioned above does not appear to be because "PST" is a legacy
- // three-character timezone supported by the RI: it happens for "Asia/Tehran"/"IRST" too
- // (IRST is not a legacy code). The RI may just use a different dataset that has "PST" /
- // "IRST" as valid translations (even for scripts like Chinese).
- TimeZone iranTz = TimeZone.getTimeZone("Asia/Tehran");
- assertEquals("Iran Summer Time", iranTz.getDisplayName(true, TimeZone.LONG, Locale.UK));
- assertEquals("Iran Daylight Time", iranTz.getDisplayName(true, TimeZone.LONG, Locale.US));
- assertEquals("Iran Standard Time", iranTz.getDisplayName(false, TimeZone.LONG, Locale.UK));
- assertEquals("Iran Standard Time", iranTz.getDisplayName(false, TimeZone.LONG, Locale.US));
- assertEquals("GMT+03:30", iranTz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
- assertEquals("GMT+04:30", iranTz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
}
public void test_getID() {
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index aadb9df..96ad2ed 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -73,6 +73,12 @@ public class TimeZoneTest extends TestCase {
assertFalse(tz.inDaylightTime(date));
}
+ public void testGetDisplayNameShort_nonHourOffsets() {
+ TimeZone iranTz = TimeZone.getTimeZone("Asia/Tehran");
+ assertEquals("GMT+03:30", iranTz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
+ assertEquals("GMT+04:30", iranTz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
+ }
+
public void testPreHistoricOffsets() throws Exception {
// "Africa/Bissau" has just a few transitions and hasn't changed in a long time.
// 1912-01-01 00:02:19-0100 ... 1912-01-01 00:02:20-0100
diff --git a/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java b/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
index 9e4b804..1a24667 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
@@ -124,25 +124,70 @@ public final class DefaultHostnameVerifierTest extends TestCase {
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
}
- public void testWildcardMatchesWildcardSuffix() {
- assertTrue(verifyWithDomainNamePattern("b.c.d", "*.b.c.d"));
- assertTrue(verifyWithDomainNamePattern("imap.google.com", "*.imap.google.com"));
+ public void testWildcardsRejectedForIpAddress() {
+ assertFalse(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("cn=*.2.3.4")));
+ assertFalse(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("cn=*.2.3.4")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "*.2.3.4")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*.2.3.4")));
+ assertFalse(verifyWithServerCertificate(
+ "2001:1234::1", new StubX509Certificate("cn=*:1234::1")));
+ assertFalse(verifyWithServerCertificate(
+ "2001:1234::1", new StubX509Certificate("cn=*:1234::1")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "*:1234::1")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*:1234::1")));
+ }
+
+ public void testNullParameters() {
+ // Confirm that neither of the parameters used later in the test cause the verifier to blow
+ // up
+ String hostname = "www.example.com";
+ StubSSLSession session = new StubSSLSession();
+ session.peerCertificates =
+ new Certificate[] {new StubX509Certificate("cn=www.example.com")};
+ verifier.verify(hostname, session);
+
+ try {
+ verifier.verify(hostname, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ verifier.verify(null, session);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testInvalidDomainNames() {
+ assertFalse(verifyWithDomainNamePattern("", ""));
+ assertFalse(verifyWithDomainNamePattern(".test.example.com", ".test.example.com"));
+ assertFalse(verifyWithDomainNamePattern("ex*ample.com", "ex*ample.com"));
+ assertFalse(verifyWithDomainNamePattern("example.com..", "example.com."));
+ assertFalse(verifyWithDomainNamePattern("example.com.", "example.com.."));
}
- public void testWildcardMatchingSubstring() {
- assertTrue(verifyWithDomainNamePattern("b.c.d", "b*.c.d"));
- assertTrue(verifyWithDomainNamePattern("imap.google.com", "ima*.google.com"));
+ public void testWildcardCharacterMustBeLeftMostLabelOnly() {
+ assertFalse(verifyWithDomainNamePattern("test.www.example.com", "test.*.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "www.*.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "www.example.*"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "*www.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "*w.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "w*w.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "w*.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "www*.example.com"));
}
- public void testWildcardMatchingEmptySubstring() {
- assertTrue(verifyWithDomainNamePattern("imap.google.com", "imap*.google.com"));
+ public void testWildcardCannotMatchEmptyLabel() {
+ assertFalse(verifyWithDomainNamePattern("example.com", "*.example.com"));
+ assertFalse(verifyWithDomainNamePattern(".example.com", "*.example.com"));
}
- public void testWildcardMatchesChildDomain() {
- assertFalse(verifyWithDomainNamePattern("a.b.c.d", "*.c.d"));
+ public void testWildcardCannotMatchChildDomain() {
+ assertFalse(verifyWithDomainNamePattern("sub.www.example.com", "*.example.com"));
}
- public void testWildcardsRejectedForSingleLabelPatterns() {
+ public void testWildcardRejectedForSingleLabelPatterns() {
assertFalse(verifyWithDomainNamePattern("d", "*"));
assertFalse(verifyWithDomainNamePattern("d.", "*."));
assertFalse(verifyWithDomainNamePattern("d", "d*"));
@@ -167,7 +212,7 @@ public final class DefaultHostnameVerifierTest extends TestCase {
assertFalse(verifyWithDomainNamePattern("imap.google.com", "ix*.google.com"));
assertTrue(verifyWithDomainNamePattern("imap.google.com", "iMap.Google.Com"));
assertTrue(verifyWithDomainNamePattern("weird", "weird"));
- assertFalse(verifyWithDomainNamePattern("weird", "weird."));
+ assertTrue(verifyWithDomainNamePattern("weird", "weird."));
// Wildcards rejected for domain names consisting of fewer than two labels (excluding root).
assertFalse(verifyWithDomainNamePattern("weird", "weird*"));
@@ -364,7 +409,7 @@ public final class DefaultHostnameVerifierTest extends TestCase {
// Verify using a certificate where the pattern is in the CN
session.peerCertificates = new Certificate[] {
- new StubX509Certificate("cn=" + pattern)
+ new StubX509Certificate("cn=\"" + pattern + "\"")
};
boolean resultWhenPatternInCn = verifier.verify(hostname, session);