Tue, 25 Aug 2020 09:23:47 +0300
8245472: Backport JDK-8038893 to JDK8
Reviewed-by: mbalao
1.1 --- a/src/share/classes/java/net/SocketPermission.java Tue Aug 25 08:41:48 2020 +0300 1.2 +++ b/src/share/classes/java/net/SocketPermission.java Tue Aug 25 09:23:47 2020 +0300 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -43,8 +43,8 @@ 1.11 import java.io.ObjectInputStream; 1.12 import java.io.IOException; 1.13 import sun.net.util.IPAddressUtil; 1.14 -import sun.net.RegisteredDomain; 1.15 import sun.net.PortConfig; 1.16 +import sun.security.util.RegisteredDomain; 1.17 import sun.security.util.SecurityConstants; 1.18 import sun.security.util.Debug; 1.19 1.20 @@ -677,13 +677,18 @@ 1.21 String a = cname.toLowerCase(); 1.22 String b = hname.toLowerCase(); 1.23 if (a.startsWith(b) && 1.24 - ((a.length() == b.length()) || (a.charAt(b.length()) == '.'))) 1.25 + ((a.length() == b.length()) || (a.charAt(b.length()) == '.'))) { 1.26 return true; 1.27 + } 1.28 if (cdomain == null) { 1.29 - cdomain = RegisteredDomain.getRegisteredDomain(a); 1.30 + cdomain = RegisteredDomain.from(a) 1.31 + .map(RegisteredDomain::name) 1.32 + .orElse(a); 1.33 } 1.34 if (hdomain == null) { 1.35 - hdomain = RegisteredDomain.getRegisteredDomain(b); 1.36 + hdomain = RegisteredDomain.from(b) 1.37 + .map(RegisteredDomain::name) 1.38 + .orElse(b); 1.39 } 1.40 1.41 return cdomain.length() != 0 && hdomain.length() != 0
2.1 --- a/src/share/classes/sun/net/RegisteredDomain.java Tue Aug 25 08:41:48 2020 +0300 2.2 +++ b/src/share/classes/sun/net/RegisteredDomain.java Tue Aug 25 09:23:47 2020 +0300 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -32,6 +32,10 @@ 2.11 import java.util.Set; 2.12 2.13 /* 2.14 + * WARNING: This class may contain out-of-date information. It should be 2.15 + * updated or replaced with an appropriate implementation. See 2.16 + * sun.security.util.RegisteredDomain for more information. 2.17 + * 2.18 * The naming tables listed below were gathered from publicly available data such as 2.19 * the subdomain registration websites listed for each top-level domain by the Internet 2.20 * Assigned Numbers Authority and the website of the Internet Corporation for Assigned Names 2.21 @@ -696,6 +700,36 @@ 2.22 top3Map.put("tr", new HashSet<String>(Arrays.asList("gov.nc.tr"))); 2.23 } 2.24 2.25 + /** 2.26 + * Returns a {@code sun.security.util.RegisteredDomain} representing the 2.27 + * registered part of the specified domain. 2.28 + * 2.29 + * @param domain the domain name 2.30 + * @return a {@code sun.security.util.RegisteredDomain} or null 2.31 + * if the domain is unknown or not registerable 2.32 + * @throws NullPointerException if domain is null 2.33 + */ 2.34 + public static sun.security.util.RegisteredDomain registeredDomain(String domain) { 2.35 + String name = getRegisteredDomain(domain); 2.36 + if (name.equals(domain)) { 2.37 + return null; 2.38 + } 2.39 + return new sun.security.util.RegisteredDomain() { 2.40 + private String rname = name; 2.41 + @Override 2.42 + public String name() { 2.43 + return rname; 2.44 + } 2.45 + @Override 2.46 + public sun.security.util.RegisteredDomain.Type type() { 2.47 + return sun.security.util.RegisteredDomain.Type.ICANN; 2.48 + } 2.49 + @Override 2.50 + public String publicSuffix() { 2.51 + return rname.substring(rname.indexOf(".") + 1); 2.52 + } 2.53 + }; 2.54 + } 2.55 2.56 /* 2.57 * Return the registered part of a qualified domain
3.1 --- a/src/share/classes/sun/security/util/HostnameChecker.java Tue Aug 25 08:41:48 2020 +0300 3.2 +++ b/src/share/classes/sun/security/util/HostnameChecker.java Tue Aug 25 09:23:47 2020 +0300 3.3 @@ -41,6 +41,7 @@ 3.4 import sun.security.x509.X500Name; 3.5 3.6 import sun.net.util.IPAddressUtil; 3.7 +import sun.security.ssl.SSLLogger; 3.8 3.9 /** 3.10 * Class to check hostnames against the names specified in a certificate as 3.11 @@ -86,18 +87,27 @@ 3.12 /** 3.13 * Perform the check. 3.14 * 3.15 - * @exception CertificateException if the name does not match any of 3.16 - * the names specified in the certificate 3.17 + * @param expectedName the expected host name or ip address 3.18 + * @param cert the certificate to check against 3.19 + * @param chainsToPublicCA true if the certificate chains to a public 3.20 + * root CA (as pre-installed in the cacerts file) 3.21 + * @throws CertificateException if the name does not match any of 3.22 + * the names specified in the certificate 3.23 */ 3.24 - public void match(String expectedName, X509Certificate cert) 3.25 - throws CertificateException { 3.26 + public void match(String expectedName, X509Certificate cert, 3.27 + boolean chainsToPublicCA) throws CertificateException { 3.28 if (isIpAddress(expectedName)) { 3.29 matchIP(expectedName, cert); 3.30 } else { 3.31 - matchDNS(expectedName, cert); 3.32 + matchDNS(expectedName, cert, chainsToPublicCA); 3.33 } 3.34 } 3.35 3.36 + public void match(String expectedName, X509Certificate cert) 3.37 + throws CertificateException { 3.38 + match(expectedName, cert, false); 3.39 + } 3.40 + 3.41 /** 3.42 * Perform the check for Kerberos. 3.43 */ 3.44 @@ -182,11 +192,12 @@ 3.45 * Certification Authorities are encouraged to use the dNSName instead. 3.46 * 3.47 * Matching is performed using the matching rules specified by 3.48 - * [RFC2459]. If more than one identity of a given type is present in 3.49 + * [RFC5280]. If more than one identity of a given type is present in 3.50 * the certificate (e.g., more than one dNSName name, a match in any one 3.51 * of the set is considered acceptable.) 3.52 */ 3.53 - private void matchDNS(String expectedName, X509Certificate cert) 3.54 + private void matchDNS(String expectedName, X509Certificate cert, 3.55 + boolean chainsToPublicCA) 3.56 throws CertificateException { 3.57 // Check that the expected name is a valid domain name. 3.58 try { 3.59 @@ -204,7 +215,7 @@ 3.60 if (((Integer)next.get(0)).intValue() == ALTNAME_DNS) { 3.61 foundDNS = true; 3.62 String dnsName = (String)next.get(1); 3.63 - if (isMatched(expectedName, dnsName)) { 3.64 + if (isMatched(expectedName, dnsName, chainsToPublicCA)) { 3.65 return; 3.66 } 3.67 } 3.68 @@ -226,7 +237,8 @@ 3.69 throw new CertificateException("Not a formal name " 3.70 + cname); 3.71 } 3.72 - if (isMatched(expectedName, cname)) { 3.73 + if (isMatched(expectedName, cname, 3.74 + chainsToPublicCA)) { 3.75 return; 3.76 } 3.77 } catch (IOException e) { 3.78 @@ -271,7 +283,11 @@ 3.79 * The <code>name</code> parameter should represent a DNS name. The 3.80 * <code>template</code> parameter may contain the wildcard character '*'. 3.81 */ 3.82 - private boolean isMatched(String name, String template) { 3.83 + private boolean isMatched(String name, String template, 3.84 + boolean chainsToPublicCA) { 3.85 + if (hasIllegalWildcard(name, template, chainsToPublicCA)) { 3.86 + return false; 3.87 + } 3.88 // check the validity of the domain name template. 3.89 try { 3.90 // Replacing wildcard character '*' with 'z' so as to check 3.91 @@ -293,6 +309,64 @@ 3.92 } 3.93 } 3.94 3.95 + /** 3.96 + * Returns true if the template contains an illegal wildcard character. 3.97 + */ 3.98 + private static boolean hasIllegalWildcard(String domain, String template, 3.99 + boolean chainsToPublicCA) { 3.100 + // not ok if it is a single wildcard character or "*." 3.101 + if (template.equals("*") || template.equals("*.")) { 3.102 + if (SSLLogger.isOn) { 3.103 + SSLLogger.fine( 3.104 + "Certificate domain name has illegal single " + 3.105 + "wildcard character: " + template); 3.106 + } 3.107 + return true; 3.108 + } 3.109 + 3.110 + int lastWildcardIndex = template.lastIndexOf("*"); 3.111 + 3.112 + // ok if it has no wildcard character 3.113 + if (lastWildcardIndex == -1) { 3.114 + return false; 3.115 + } 3.116 + 3.117 + String afterWildcard = template.substring(lastWildcardIndex); 3.118 + int firstDotIndex = afterWildcard.indexOf("."); 3.119 + 3.120 + // not ok if there is no dot after wildcard (ex: "*com") 3.121 + if (firstDotIndex == -1) { 3.122 + if (SSLLogger.isOn) { 3.123 + SSLLogger.fine( 3.124 + "Certificate domain name has illegal wildcard, " + 3.125 + "no dot after wildcard character: " + template); 3.126 + } 3.127 + return true; 3.128 + } 3.129 + 3.130 + // If the wildcarded domain is a top-level domain under which names 3.131 + // can be registered, then a wildcard is not allowed. 3.132 + 3.133 + if (!chainsToPublicCA) { 3.134 + return false; // skip check for non-public certificates 3.135 + } 3.136 + Optional<RegisteredDomain> rd = RegisteredDomain.from(domain) 3.137 + .filter(d -> d.type() == RegisteredDomain.Type.ICANN); 3.138 + 3.139 + if (rd.isPresent()) { 3.140 + String wDomain = afterWildcard.substring(firstDotIndex + 1); 3.141 + if (rd.get().publicSuffix().equalsIgnoreCase(wDomain)) { 3.142 + if (SSLLogger.isOn) { 3.143 + SSLLogger.fine( 3.144 + "Certificate domain name has illegal " + 3.145 + "wildcard for public suffix: " + template); 3.146 + } 3.147 + return true; 3.148 + } 3.149 + } 3.150 + 3.151 + return false; 3.152 + } 3.153 3.154 /** 3.155 * Returns true if name matches against template.<p>
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/share/classes/sun/security/util/RegisteredDomain.java Tue Aug 25 09:23:47 2020 +0300 4.3 @@ -0,0 +1,93 @@ 4.4 +/* 4.5 + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.7 + * 4.8 + * This code is free software; you can redistribute it and/or modify it 4.9 + * under the terms of the GNU General Public License version 2 only, as 4.10 + * published by the Free Software Foundation. Oracle designates this 4.11 + * particular file as subject to the "Classpath" exception as provided 4.12 + * by Oracle in the LICENSE file that accompanied this code. 4.13 + * 4.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 4.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 4.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 4.17 + * version 2 for more details (a copy is included in the LICENSE file that 4.18 + * accompanied this code). 4.19 + * 4.20 + * You should have received a copy of the GNU General Public License version 4.21 + * 2 along with this work; if not, write to the Free Software Foundation, 4.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 4.23 + * 4.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 4.25 + * or visit www.oracle.com if you need additional information or have any 4.26 + * questions. 4.27 + */ 4.28 + 4.29 +package sun.security.util; 4.30 + 4.31 +import java.util.Optional; 4.32 + 4.33 +/** 4.34 + * A domain that is registered under a "public suffix". The public suffix is 4.35 + * a top-level domain under which names can be registered. For example, 4.36 + * "com" and "co.uk" are public suffixes, and "example.com" and "example.co.uk" 4.37 + * are registered domains. 4.38 + * <p> 4.39 + * The primary purpose of this class is to determine if domains are safe to 4.40 + * use in various use-cases. 4.41 + */ 4.42 +public interface RegisteredDomain { 4.43 + 4.44 + public enum Type { 4.45 + /** 4.46 + * An ICANN registered domain. 4.47 + */ 4.48 + ICANN, 4.49 + /** 4.50 + * A private registered domain. 4.51 + */ 4.52 + PRIVATE 4.53 + } 4.54 + 4.55 + /** 4.56 + * Returns the name of the registered domain. 4.57 + * 4.58 + * @return the name of the registered domain 4.59 + */ 4.60 + String name(); 4.61 + 4.62 + /** 4.63 + * Returns the type of the registered domain. 4.64 + * 4.65 + * @return the type of the registered domain 4.66 + */ 4.67 + Type type(); 4.68 + 4.69 + /** 4.70 + * Returns the public suffix of the registered domain. 4.71 + * 4.72 + * @return the public suffix of the registered domain 4.73 + */ 4.74 + String publicSuffix(); 4.75 + 4.76 + /** 4.77 + * Returns an {@code Optional<RegisteredDomain>} representing the 4.78 + * registered part of the specified domain. 4.79 + * 4.80 + * {@implNote} 4.81 + * The default implementation is based on the legacy 4.82 + * {@code sun.net.RegisteredDomain} class which is no longer maintained. 4.83 + * It should be updated or replaced with an appropriate implementation. 4.84 + * 4.85 + * @param domain the domain name 4.86 + * @return an {@code Optional<RegisteredDomain>}; the {@code Optional} is 4.87 + * empty if the domain is unknown or not registerable 4.88 + * @throws NullPointerException if domain is null 4.89 + */ 4.90 + public static Optional<RegisteredDomain> from(String domain) { 4.91 + if (domain == null) { 4.92 + throw new NullPointerException(); 4.93 + } 4.94 + return Optional.ofNullable(sun.net.RegisteredDomain.registeredDomain(domain)); 4.95 + } 4.96 +}