8038893: Recertify certificate matching
Reviewed-by: xuelei, jdn, erikj, asmotrak
This commit is contained in:
parent
240fd78fc1
commit
2cef018734
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,11 +30,19 @@ include MakeBase.gmk
|
|||||||
include JavaCompilation.gmk
|
include JavaCompilation.gmk
|
||||||
include SetupJavaCompilers.gmk
|
include SetupJavaCompilers.gmk
|
||||||
|
|
||||||
|
$(eval $(call IncludeCustomExtension, jdk, CompileTools.gmk))
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
# Use += to be able to add to this from a custom extension
|
||||||
|
BUILD_TOOLS_SRC_DIRS += \
|
||||||
|
$(JDK_TOPDIR)/make/src/classes \
|
||||||
|
$(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes \
|
||||||
|
#
|
||||||
|
|
||||||
$(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \
|
$(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \
|
||||||
SETUP := GENERATE_OLDBYTECODE, \
|
SETUP := GENERATE_OLDBYTECODE, \
|
||||||
SRC := $(JDK_TOPDIR)/make/src/classes $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes, \
|
SRC := $(BUILD_TOOLS_SRC_DIRS), \
|
||||||
EXCLUDES := build/tools/deps \
|
EXCLUDES := build/tools/deps \
|
||||||
build/tools/jigsaw, \
|
build/tools/jigsaw, \
|
||||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes))
|
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -28,6 +28,9 @@ _TOOLS_GMK := 1
|
|||||||
|
|
||||||
include JavaCompilation.gmk
|
include JavaCompilation.gmk
|
||||||
|
|
||||||
|
# Hook to include the corresponding custom file, if present.
|
||||||
|
$(eval $(call IncludeCustomExtension, jdk, Tools.gmk))
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# To avoid reevaluating the compilation setup for the tools each time this file
|
# To avoid reevaluating the compilation setup for the tools each time this file
|
||||||
# is included, the actual compilation is handled by CompileTools.gmk. The
|
# is included, the actual compilation is handled by CompileTools.gmk. The
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -44,8 +44,8 @@ import java.util.StringJoiner;
|
|||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.ConcurrentSkipListMap;
|
import java.util.concurrent.ConcurrentSkipListMap;
|
||||||
import sun.net.util.IPAddressUtil;
|
import sun.net.util.IPAddressUtil;
|
||||||
import sun.net.RegisteredDomain;
|
|
||||||
import sun.net.PortConfig;
|
import sun.net.PortConfig;
|
||||||
|
import sun.security.util.RegisteredDomain;
|
||||||
import sun.security.util.SecurityConstants;
|
import sun.security.util.SecurityConstants;
|
||||||
import sun.security.util.Debug;
|
import sun.security.util.Debug;
|
||||||
|
|
||||||
@ -678,13 +678,18 @@ public final class SocketPermission extends Permission
|
|||||||
String a = cname.toLowerCase();
|
String a = cname.toLowerCase();
|
||||||
String b = hname.toLowerCase();
|
String b = hname.toLowerCase();
|
||||||
if (a.startsWith(b) &&
|
if (a.startsWith(b) &&
|
||||||
((a.length() == b.length()) || (a.charAt(b.length()) == '.')))
|
((a.length() == b.length()) || (a.charAt(b.length()) == '.'))) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (cdomain == null) {
|
if (cdomain == null) {
|
||||||
cdomain = RegisteredDomain.getRegisteredDomain(a);
|
cdomain = RegisteredDomain.from(a)
|
||||||
|
.map(RegisteredDomain::name)
|
||||||
|
.orElse(a);
|
||||||
}
|
}
|
||||||
if (hdomain == null) {
|
if (hdomain == null) {
|
||||||
hdomain = RegisteredDomain.getRegisteredDomain(b);
|
hdomain = RegisteredDomain.from(b)
|
||||||
|
.map(RegisteredDomain::name)
|
||||||
|
.orElse(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cdomain.length() != 0 && hdomain.length() != 0
|
return cdomain.length() != 0 && hdomain.length() != 0
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -32,6 +32,10 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* WARNING: This class may contain out-of-date information. It should be
|
||||||
|
* updated or replaced with an appropriate implementation. See
|
||||||
|
* sun.security.util.RegisteredDomain for more information.
|
||||||
|
*
|
||||||
* The naming tables listed below were gathered from publicly available data such as
|
* The naming tables listed below were gathered from publicly available data such as
|
||||||
* the subdomain registration websites listed for each top-level domain by the Internet
|
* the subdomain registration websites listed for each top-level domain by the Internet
|
||||||
* Assigned Numbers Authority and the website of the Internet Corporation for Assigned Names
|
* Assigned Numbers Authority and the website of the Internet Corporation for Assigned Names
|
||||||
@ -696,6 +700,36 @@ static {
|
|||||||
top3Map.put("tr", new HashSet<String>(Arrays.asList("gov.nc.tr")));
|
top3Map.put("tr", new HashSet<String>(Arrays.asList("gov.nc.tr")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@code sun.security.util.RegisteredDomain} representing the
|
||||||
|
* registered part of the specified domain.
|
||||||
|
*
|
||||||
|
* @param domain the domain name
|
||||||
|
* @return a {@code sun.security.util.RegisteredDomain} or null
|
||||||
|
* if the domain is unknown or not registerable
|
||||||
|
* @throws NullPointerException if domain is null
|
||||||
|
*/
|
||||||
|
public static sun.security.util.RegisteredDomain registeredDomain(String domain) {
|
||||||
|
String name = getRegisteredDomain(domain);
|
||||||
|
if (name.equals(domain)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new sun.security.util.RegisteredDomain() {
|
||||||
|
private String rname = name;
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return rname;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public sun.security.util.RegisteredDomain.Type type() {
|
||||||
|
return sun.security.util.RegisteredDomain.Type.ICANN;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String publicSuffix() {
|
||||||
|
return rname.substring(rname.indexOf(".") + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the registered part of a qualified domain
|
* Return the registered part of a qualified domain
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -35,6 +35,7 @@ import java.security.cert.*;
|
|||||||
import javax.net.ssl.*;
|
import javax.net.ssl.*;
|
||||||
|
|
||||||
import sun.security.validator.*;
|
import sun.security.validator.*;
|
||||||
|
import sun.security.util.AnchorCertificates;
|
||||||
import sun.security.util.HostnameChecker;
|
import sun.security.util.HostnameChecker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,13 +187,11 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void checkTrusted(X509Certificate[] chain, String authType,
|
private void checkTrusted(X509Certificate[] chain, String authType,
|
||||||
Socket socket, boolean isClient) throws CertificateException {
|
Socket socket, boolean isClient) throws CertificateException {
|
||||||
Validator v = checkTrustedInit(chain, authType, isClient);
|
Validator v = checkTrustedInit(chain, authType, isClient);
|
||||||
|
|
||||||
AlgorithmConstraints constraints = null;
|
X509Certificate[] trustedChain = null;
|
||||||
List<byte[]> responseList = Collections.emptyList();
|
|
||||||
if ((socket != null) && socket.isConnected() &&
|
if ((socket != null) && socket.isConnected() &&
|
||||||
(socket instanceof SSLSocket)) {
|
(socket instanceof SSLSocket)) {
|
||||||
|
|
||||||
@ -202,48 +201,46 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
throw new CertificateException("No handshake session");
|
throw new CertificateException("No handshake session");
|
||||||
}
|
}
|
||||||
|
|
||||||
// check endpoint identity
|
|
||||||
String identityAlg = sslSocket.getSSLParameters().
|
|
||||||
getEndpointIdentificationAlgorithm();
|
|
||||||
if (identityAlg != null && identityAlg.length() != 0) {
|
|
||||||
checkIdentity(session, chain[0], identityAlg, isClient,
|
|
||||||
getRequestedServerNames(socket));
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the algorithm constraints
|
// create the algorithm constraints
|
||||||
ProtocolVersion protocolVersion =
|
ProtocolVersion protocolVersion =
|
||||||
ProtocolVersion.valueOf(session.getProtocol());
|
ProtocolVersion.valueOf(session.getProtocol());
|
||||||
if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
|
boolean isExtSession = (session instanceof ExtendedSSLSession);
|
||||||
if (session instanceof ExtendedSSLSession) {
|
AlgorithmConstraints constraints = null;
|
||||||
ExtendedSSLSession extSession =
|
if (protocolVersion.v >= ProtocolVersion.TLS12.v && isExtSession) {
|
||||||
(ExtendedSSLSession)session;
|
ExtendedSSLSession extSession = (ExtendedSSLSession)session;
|
||||||
String[] localSupportedSignAlgs =
|
String[] localSupportedSignAlgs =
|
||||||
extSession.getLocalSupportedSignatureAlgorithms();
|
extSession.getLocalSupportedSignatureAlgorithms();
|
||||||
|
|
||||||
constraints = new SSLAlgorithmConstraints(
|
constraints = new SSLAlgorithmConstraints(
|
||||||
sslSocket, localSupportedSignAlgs, false);
|
sslSocket, localSupportedSignAlgs, false);
|
||||||
} else {
|
|
||||||
constraints =
|
|
||||||
new SSLAlgorithmConstraints(sslSocket, false);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
constraints = new SSLAlgorithmConstraints(sslSocket, false);
|
constraints = new SSLAlgorithmConstraints(sslSocket, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab any stapled OCSP responses for use in validation
|
// Grab any stapled OCSP responses for use in validation
|
||||||
if (session instanceof ExtendedSSLSession) {
|
List<byte[]> responseList = Collections.emptyList();
|
||||||
|
if (!isClient && isExtSession) {
|
||||||
responseList =
|
responseList =
|
||||||
((ExtendedSSLSession)session).getStatusResponses();
|
((ExtendedSSLSession)session).getStatusResponses();
|
||||||
}
|
}
|
||||||
}
|
trustedChain = validate(v, chain, responseList,
|
||||||
|
constraints, isClient ? null : authType);
|
||||||
|
|
||||||
X509Certificate[] trustedChain = null;
|
// check if EE certificate chains to a public root CA (as
|
||||||
if (isClient) {
|
// pre-installed in cacerts)
|
||||||
trustedChain = validate(v, chain, Collections.emptyList(),
|
boolean chainsToPublicCA =
|
||||||
constraints, null);
|
AnchorCertificates.contains(trustedChain[trustedChain.length-1]);
|
||||||
|
|
||||||
|
// check endpoint identity
|
||||||
|
String identityAlg = sslSocket.getSSLParameters().
|
||||||
|
getEndpointIdentificationAlgorithm();
|
||||||
|
if (identityAlg != null && identityAlg.length() != 0) {
|
||||||
|
checkIdentity(session, trustedChain[0], identityAlg, isClient,
|
||||||
|
getRequestedServerNames(socket), chainsToPublicCA);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
trustedChain = validate(v, chain, responseList, constraints,
|
trustedChain = validate(v, chain, Collections.emptyList(),
|
||||||
authType);
|
null, isClient ? null : authType);
|
||||||
}
|
}
|
||||||
if (debug != null && Debug.isOn("trustmanager")) {
|
if (debug != null && Debug.isOn("trustmanager")) {
|
||||||
System.out.println("Found trusted certificate:");
|
System.out.println("Found trusted certificate:");
|
||||||
@ -255,56 +252,53 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
SSLEngine engine, boolean isClient) throws CertificateException {
|
SSLEngine engine, boolean isClient) throws CertificateException {
|
||||||
Validator v = checkTrustedInit(chain, authType, isClient);
|
Validator v = checkTrustedInit(chain, authType, isClient);
|
||||||
|
|
||||||
AlgorithmConstraints constraints = null;
|
X509Certificate[] trustedChain = null;
|
||||||
List<byte[]> responseList = Collections.emptyList();
|
|
||||||
if (engine != null) {
|
if (engine != null) {
|
||||||
SSLSession session = engine.getHandshakeSession();
|
SSLSession session = engine.getHandshakeSession();
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
throw new CertificateException("No handshake session");
|
throw new CertificateException("No handshake session");
|
||||||
}
|
}
|
||||||
|
|
||||||
// check endpoint identity
|
|
||||||
String identityAlg = engine.getSSLParameters().
|
|
||||||
getEndpointIdentificationAlgorithm();
|
|
||||||
if (identityAlg != null && identityAlg.length() != 0) {
|
|
||||||
checkIdentity(session, chain[0], identityAlg, isClient,
|
|
||||||
getRequestedServerNames(engine));
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the algorithm constraints
|
// create the algorithm constraints
|
||||||
ProtocolVersion protocolVersion =
|
ProtocolVersion protocolVersion =
|
||||||
ProtocolVersion.valueOf(session.getProtocol());
|
ProtocolVersion.valueOf(session.getProtocol());
|
||||||
if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
|
boolean isExtSession = (session instanceof ExtendedSSLSession);
|
||||||
if (session instanceof ExtendedSSLSession) {
|
AlgorithmConstraints constraints = null;
|
||||||
ExtendedSSLSession extSession =
|
if (protocolVersion.v >= ProtocolVersion.TLS12.v && isExtSession) {
|
||||||
(ExtendedSSLSession)session;
|
ExtendedSSLSession extSession = (ExtendedSSLSession)session;
|
||||||
String[] localSupportedSignAlgs =
|
String[] localSupportedSignAlgs =
|
||||||
extSession.getLocalSupportedSignatureAlgorithms();
|
extSession.getLocalSupportedSignatureAlgorithms();
|
||||||
|
|
||||||
constraints = new SSLAlgorithmConstraints(
|
constraints = new SSLAlgorithmConstraints(
|
||||||
engine, localSupportedSignAlgs, false);
|
engine, localSupportedSignAlgs, false);
|
||||||
} else {
|
|
||||||
constraints =
|
|
||||||
new SSLAlgorithmConstraints(engine, false);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
constraints = new SSLAlgorithmConstraints(engine, false);
|
constraints = new SSLAlgorithmConstraints(engine, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab any stapled OCSP responses for use in validation
|
// Grab any stapled OCSP responses for use in validation
|
||||||
if (session instanceof ExtendedSSLSession) {
|
List<byte[]> responseList = Collections.emptyList();
|
||||||
|
if (!isClient && isExtSession) {
|
||||||
responseList =
|
responseList =
|
||||||
((ExtendedSSLSession)session).getStatusResponses();
|
((ExtendedSSLSession)session).getStatusResponses();
|
||||||
}
|
}
|
||||||
}
|
trustedChain = validate(v, chain, responseList,
|
||||||
|
constraints, isClient ? null : authType);
|
||||||
|
|
||||||
X509Certificate[] trustedChain = null;
|
// check if EE certificate chains to a public root CA (as
|
||||||
if (isClient) {
|
// pre-installed in cacerts)
|
||||||
trustedChain = validate(v, chain, Collections.emptyList(),
|
boolean chainsToPublicCA =
|
||||||
constraints, null);
|
AnchorCertificates.contains(trustedChain[trustedChain.length-1]);
|
||||||
|
|
||||||
|
// check endpoint identity
|
||||||
|
String identityAlg = engine.getSSLParameters().
|
||||||
|
getEndpointIdentificationAlgorithm();
|
||||||
|
if (identityAlg != null && identityAlg.length() != 0) {
|
||||||
|
checkIdentity(session, trustedChain[0], identityAlg, isClient,
|
||||||
|
getRequestedServerNames(engine), chainsToPublicCA);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
trustedChain = validate(v, chain, responseList, constraints,
|
trustedChain = validate(v, chain, Collections.emptyList(),
|
||||||
authType);
|
null, isClient ? null : authType);
|
||||||
}
|
}
|
||||||
if (debug != null && Debug.isOn("trustmanager")) {
|
if (debug != null && Debug.isOn("trustmanager")) {
|
||||||
System.out.println("Found trusted certificate:");
|
System.out.println("Found trusted certificate:");
|
||||||
@ -437,7 +431,8 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
X509Certificate cert,
|
X509Certificate cert,
|
||||||
String algorithm,
|
String algorithm,
|
||||||
boolean isClient,
|
boolean isClient,
|
||||||
List<SNIServerName> sniNames) throws CertificateException {
|
List<SNIServerName> sniNames,
|
||||||
|
boolean chainsToPublicCA) throws CertificateException {
|
||||||
|
|
||||||
boolean identifiable = false;
|
boolean identifiable = false;
|
||||||
String peerHost = session.getPeerHost();
|
String peerHost = session.getPeerHost();
|
||||||
@ -445,7 +440,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
String hostname = getHostNameInSNI(sniNames);
|
String hostname = getHostNameInSNI(sniNames);
|
||||||
if (hostname != null) {
|
if (hostname != null) {
|
||||||
try {
|
try {
|
||||||
checkIdentity(hostname, cert, algorithm);
|
checkIdentity(hostname, cert, algorithm, chainsToPublicCA);
|
||||||
identifiable = true;
|
identifiable = true;
|
||||||
} catch (CertificateException ce) {
|
} catch (CertificateException ce) {
|
||||||
if (hostname.equalsIgnoreCase(peerHost)) {
|
if (hostname.equalsIgnoreCase(peerHost)) {
|
||||||
@ -458,7 +453,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!identifiable) {
|
if (!identifiable) {
|
||||||
checkIdentity(peerHost, cert, algorithm);
|
checkIdentity(peerHost, cert, algorithm, chainsToPublicCA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,6 +464,12 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
*/
|
*/
|
||||||
static void checkIdentity(String hostname, X509Certificate cert,
|
static void checkIdentity(String hostname, X509Certificate cert,
|
||||||
String algorithm) throws CertificateException {
|
String algorithm) throws CertificateException {
|
||||||
|
checkIdentity(hostname, cert, algorithm, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkIdentity(String hostname, X509Certificate cert,
|
||||||
|
String algorithm, boolean chainsToPublicCA)
|
||||||
|
throws CertificateException {
|
||||||
if (algorithm != null && algorithm.length() != 0) {
|
if (algorithm != null && algorithm.length() != 0) {
|
||||||
// if IPv6 strip off the "[]"
|
// if IPv6 strip off the "[]"
|
||||||
if ((hostname != null) && hostname.startsWith("[") &&
|
if ((hostname != null) && hostname.startsWith("[") &&
|
||||||
@ -478,11 +479,11 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
|
|
||||||
if (algorithm.equalsIgnoreCase("HTTPS")) {
|
if (algorithm.equalsIgnoreCase("HTTPS")) {
|
||||||
HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match(
|
HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match(
|
||||||
hostname, cert);
|
hostname, cert, chainsToPublicCA);
|
||||||
} else if (algorithm.equalsIgnoreCase("LDAP") ||
|
} else if (algorithm.equalsIgnoreCase("LDAP") ||
|
||||||
algorithm.equalsIgnoreCase("LDAPS")) {
|
algorithm.equalsIgnoreCase("LDAPS")) {
|
||||||
HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP).match(
|
HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP).match(
|
||||||
hostname, cert);
|
hostname, cert, chainsToPublicCA);
|
||||||
} else {
|
} else {
|
||||||
throw new CertificateException(
|
throw new CertificateException(
|
||||||
"Unknown identification algorithm: " + algorithm);
|
"Unknown identification algorithm: " + algorithm);
|
||||||
|
@ -28,17 +28,15 @@ package sun.security.util;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.security.cert.*;
|
import java.security.cert.*;
|
||||||
|
import java.util.*;
|
||||||
import javax.security.auth.x500.X500Principal;
|
import javax.security.auth.x500.X500Principal;
|
||||||
|
|
||||||
import sun.security.ssl.ClientKeyExchangeService;
|
|
||||||
import sun.security.x509.X500Name;
|
|
||||||
|
|
||||||
import sun.net.util.IPAddressUtil;
|
import sun.net.util.IPAddressUtil;
|
||||||
|
import sun.security.ssl.ClientKeyExchangeService;
|
||||||
|
import sun.security.ssl.Debug;
|
||||||
|
import sun.security.x509.X500Name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to check hostnames against the names specified in a certificate as
|
* Class to check hostnames against the names specified in a certificate as
|
||||||
@ -61,6 +59,8 @@ public class HostnameChecker {
|
|||||||
private static final int ALTNAME_DNS = 2;
|
private static final int ALTNAME_DNS = 2;
|
||||||
private static final int ALTNAME_IP = 7;
|
private static final int ALTNAME_IP = 7;
|
||||||
|
|
||||||
|
private static final Debug debug = Debug.getInstance("ssl");
|
||||||
|
|
||||||
// the algorithm to follow to perform the check. Currently unused.
|
// the algorithm to follow to perform the check. Currently unused.
|
||||||
private final byte checkType;
|
private final byte checkType;
|
||||||
|
|
||||||
@ -84,18 +84,27 @@ public class HostnameChecker {
|
|||||||
/**
|
/**
|
||||||
* Perform the check.
|
* Perform the check.
|
||||||
*
|
*
|
||||||
* @exception CertificateException if the name does not match any of
|
* @param expectedName the expected host name or ip address
|
||||||
* the names specified in the certificate
|
* @param cert the certificate to check against
|
||||||
|
* @param chainsToPublicCA true if the certificate chains to a public
|
||||||
|
* root CA (as pre-installed in the cacerts file)
|
||||||
|
* @throws CertificateException if the name does not match any of
|
||||||
|
* the names specified in the certificate
|
||||||
*/
|
*/
|
||||||
public void match(String expectedName, X509Certificate cert)
|
public void match(String expectedName, X509Certificate cert,
|
||||||
throws CertificateException {
|
boolean chainsToPublicCA) throws CertificateException {
|
||||||
if (isIpAddress(expectedName)) {
|
if (isIpAddress(expectedName)) {
|
||||||
matchIP(expectedName, cert);
|
matchIP(expectedName, cert);
|
||||||
} else {
|
} else {
|
||||||
matchDNS(expectedName, cert);
|
matchDNS(expectedName, cert, chainsToPublicCA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void match(String expectedName, X509Certificate cert)
|
||||||
|
throws CertificateException {
|
||||||
|
match(expectedName, cert, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the check for Kerberos.
|
* Perform the check for Kerberos.
|
||||||
*/
|
*/
|
||||||
@ -185,20 +194,21 @@ public class HostnameChecker {
|
|||||||
* Certification Authorities are encouraged to use the dNSName instead.
|
* Certification Authorities are encouraged to use the dNSName instead.
|
||||||
*
|
*
|
||||||
* Matching is performed using the matching rules specified by
|
* Matching is performed using the matching rules specified by
|
||||||
* [RFC2459]. If more than one identity of a given type is present in
|
* [RFC5280]. If more than one identity of a given type is present in
|
||||||
* the certificate (e.g., more than one dNSName name, a match in any one
|
* the certificate (e.g., more than one dNSName name, a match in any one
|
||||||
* of the set is considered acceptable.)
|
* of the set is considered acceptable.)
|
||||||
*/
|
*/
|
||||||
private void matchDNS(String expectedName, X509Certificate cert)
|
private void matchDNS(String expectedName, X509Certificate cert,
|
||||||
|
boolean chainsToPublicCA)
|
||||||
throws CertificateException {
|
throws CertificateException {
|
||||||
Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames();
|
Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames();
|
||||||
if (subjAltNames != null) {
|
if (subjAltNames != null) {
|
||||||
boolean foundDNS = false;
|
boolean foundDNS = false;
|
||||||
for ( List<?> next : subjAltNames) {
|
for (List<?> next : subjAltNames) {
|
||||||
if (((Integer)next.get(0)).intValue() == ALTNAME_DNS) {
|
if (((Integer)next.get(0)).intValue() == ALTNAME_DNS) {
|
||||||
foundDNS = true;
|
foundDNS = true;
|
||||||
String dnsName = (String)next.get(1);
|
String dnsName = (String)next.get(1);
|
||||||
if (isMatched(expectedName, dnsName)) {
|
if (isMatched(expectedName, dnsName, chainsToPublicCA)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,7 +225,8 @@ public class HostnameChecker {
|
|||||||
(X500Name.commonName_oid);
|
(X500Name.commonName_oid);
|
||||||
if (derValue != null) {
|
if (derValue != null) {
|
||||||
try {
|
try {
|
||||||
if (isMatched(expectedName, derValue.getAsString())) {
|
if (isMatched(expectedName, derValue.getAsString(),
|
||||||
|
chainsToPublicCA)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -261,7 +272,11 @@ public class HostnameChecker {
|
|||||||
* The <code>template</code> parameter
|
* The <code>template</code> parameter
|
||||||
* may contain the wildcard character *
|
* may contain the wildcard character *
|
||||||
*/
|
*/
|
||||||
private boolean isMatched(String name, String template) {
|
private boolean isMatched(String name, String template,
|
||||||
|
boolean chainsToPublicCA) {
|
||||||
|
if (hasIllegalWildcard(name, template, chainsToPublicCA)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (checkType == TYPE_TLS) {
|
if (checkType == TYPE_TLS) {
|
||||||
return matchAllWildcards(name, template);
|
return matchAllWildcards(name, template);
|
||||||
} else if (checkType == TYPE_LDAP) {
|
} else if (checkType == TYPE_LDAP) {
|
||||||
@ -271,6 +286,61 @@ public class HostnameChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the template contains an illegal wildcard character.
|
||||||
|
*/
|
||||||
|
private static boolean hasIllegalWildcard(String domain, String template,
|
||||||
|
boolean chainsToPublicCA) {
|
||||||
|
// not ok if it is a single wildcard character or "*."
|
||||||
|
if (template.equals("*") || template.equals("*.")) {
|
||||||
|
if (debug != null) {
|
||||||
|
debug.println("Certificate domain name has illegal single " +
|
||||||
|
"wildcard character: " + template);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lastWildcardIndex = template.lastIndexOf("*");
|
||||||
|
|
||||||
|
// ok if it has no wildcard character
|
||||||
|
if (lastWildcardIndex == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String afterWildcard = template.substring(lastWildcardIndex);
|
||||||
|
int firstDotIndex = afterWildcard.indexOf(".");
|
||||||
|
|
||||||
|
// not ok if there is no dot after wildcard (ex: "*com")
|
||||||
|
if (firstDotIndex == -1) {
|
||||||
|
if (debug != null) {
|
||||||
|
debug.println("Certificate domain name has illegal wildcard, " +
|
||||||
|
"no dot after wildcard character: " + template);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the wildcarded domain is a top-level domain under which names
|
||||||
|
// can be registered, then a wildcard is not allowed.
|
||||||
|
|
||||||
|
if (!chainsToPublicCA) {
|
||||||
|
return false; // skip check for non-public certificates
|
||||||
|
}
|
||||||
|
Optional<RegisteredDomain> rd = RegisteredDomain.from(domain)
|
||||||
|
.filter(d -> d.type() == RegisteredDomain.Type.ICANN);
|
||||||
|
|
||||||
|
if (rd.isPresent()) {
|
||||||
|
String wDomain = afterWildcard.substring(firstDotIndex + 1);
|
||||||
|
if (rd.get().publicSuffix().equalsIgnoreCase(wDomain)) {
|
||||||
|
if (debug != null) {
|
||||||
|
debug.println("Certificate domain name has illegal " +
|
||||||
|
"wildcard for public suffix: " + template);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if name matches against template.<p>
|
* Returns true if name matches against template.<p>
|
||||||
@ -317,9 +387,9 @@ public class HostnameChecker {
|
|||||||
name = name.toLowerCase(Locale.ENGLISH);
|
name = name.toLowerCase(Locale.ENGLISH);
|
||||||
template = template.toLowerCase(Locale.ENGLISH);
|
template = template.toLowerCase(Locale.ENGLISH);
|
||||||
|
|
||||||
// Retreive leftmost component
|
// Retrieve leftmost component
|
||||||
int templateIdx = template.indexOf('.');
|
int templateIdx = template.indexOf(".");
|
||||||
int nameIdx = name.indexOf('.');
|
int nameIdx = name.indexOf(".");
|
||||||
|
|
||||||
if (templateIdx == -1)
|
if (templateIdx == -1)
|
||||||
templateIdx = template.length();
|
templateIdx = template.length();
|
||||||
@ -344,7 +414,7 @@ public class HostnameChecker {
|
|||||||
*/
|
*/
|
||||||
private static boolean matchWildCards(String name, String template) {
|
private static boolean matchWildCards(String name, String template) {
|
||||||
|
|
||||||
int wildcardIdx = template.indexOf('*');
|
int wildcardIdx = template.indexOf("*");
|
||||||
if (wildcardIdx == -1)
|
if (wildcardIdx == -1)
|
||||||
return name.equals(template);
|
return name.equals(template);
|
||||||
|
|
||||||
@ -367,7 +437,7 @@ public class HostnameChecker {
|
|||||||
|
|
||||||
// update the match scope
|
// update the match scope
|
||||||
name = name.substring(beforeStartIdx + beforeWildcard.length());
|
name = name.substring(beforeStartIdx + beforeWildcard.length());
|
||||||
wildcardIdx = afterWildcard.indexOf('*');
|
wildcardIdx = afterWildcard.indexOf("*");
|
||||||
}
|
}
|
||||||
return name.endsWith(afterWildcard);
|
return name.endsWith(afterWildcard);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.util;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A domain that is registered under a "public suffix". The public suffix is
|
||||||
|
* a top-level domain under which names can be registered. For example,
|
||||||
|
* "com" and "co.uk" are public suffixes, and "example.com" and "example.co.uk"
|
||||||
|
* are registered domains.
|
||||||
|
* <p>
|
||||||
|
* The primary purpose of this class is to determine if domains are safe to
|
||||||
|
* use in various use-cases.
|
||||||
|
*/
|
||||||
|
public interface RegisteredDomain {
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
/**
|
||||||
|
* An ICANN registered domain.
|
||||||
|
*/
|
||||||
|
ICANN,
|
||||||
|
/**
|
||||||
|
* A private registered domain.
|
||||||
|
*/
|
||||||
|
PRIVATE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the registered domain.
|
||||||
|
*
|
||||||
|
* @return the name of the registered domain
|
||||||
|
*/
|
||||||
|
String name();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of the registered domain.
|
||||||
|
*
|
||||||
|
* @return the type of the registered domain
|
||||||
|
*/
|
||||||
|
Type type();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the public suffix of the registered domain.
|
||||||
|
*
|
||||||
|
* @return the public suffix of the registered domain
|
||||||
|
*/
|
||||||
|
String publicSuffix();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@code Optional<RegisteredDomain>} representing the
|
||||||
|
* registered part of the specified domain.
|
||||||
|
*
|
||||||
|
* {@implNote}
|
||||||
|
* The default implementation is based on the legacy
|
||||||
|
* {@code sun.net.RegisteredDomain} class which is no longer maintained.
|
||||||
|
* It should be updated or replaced with an appropriate implementation.
|
||||||
|
*
|
||||||
|
* @param domain the domain name
|
||||||
|
* @return an {@code Optional<RegisteredDomain>}; the {@code Optional} is
|
||||||
|
* empty if the domain is unknown or not registerable
|
||||||
|
* @throws NullPointerException if domain is null
|
||||||
|
*/
|
||||||
|
public static Optional<RegisteredDomain> from(String domain) {
|
||||||
|
if (domain == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(sun.net.RegisteredDomain.registeredDomain(domain));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user