--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,1746 @@
+/*
+ * Copyright (c) 1999, 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.ssl;
+
+import java.net.Socket;
+
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.cert.Certificate;
+
+import javax.net.ssl.*;
+
+import sun.security.provider.certpath.AlgorithmChecker;
+import sun.security.action.GetPropertyAction;
+import sun.security.validator.Validator;
+
+public abstract class SSLContextImpl extends SSLContextSpi {
+
+ private static final Debug debug = Debug.getInstance("ssl");
+
+ private final EphemeralKeyManager ephemeralKeyManager;
+ private final SSLSessionContextImpl clientCache;
+ private final SSLSessionContextImpl serverCache;
+
+ private boolean isInitialized;
+
+ private X509ExtendedKeyManager keyManager;
+ private X509TrustManager trustManager;
+ private SecureRandom secureRandom;
+
+ // DTLS cookie exchange manager
+ private volatile HelloCookieManager helloCookieManager;
+
+ private final boolean clientEnableStapling = Debug.getBooleanProperty(
+ "jdk.tls.client.enableStatusRequestExtension", true);
+ private final boolean serverEnableStapling = Debug.getBooleanProperty(
+ "jdk.tls.server.enableStatusRequestExtension", false);
+ private final static Collection<CipherSuite> clientCustomizedCipherSuites =
+ getCustomizedCipherSuites("jdk.tls.client.cipherSuites");
+ private final static Collection<CipherSuite> serverCustomizedCipherSuites =
+ getCustomizedCipherSuites("jdk.tls.server.cipherSuites");
+
+ private volatile StatusResponseManager statusResponseManager;
+
+ SSLContextImpl() {
+ ephemeralKeyManager = new EphemeralKeyManager();
+ clientCache = new SSLSessionContextImpl();
+ serverCache = new SSLSessionContextImpl();
+ }
+
+ @Override
+ protected void engineInit(KeyManager[] km, TrustManager[] tm,
+ SecureRandom sr) throws KeyManagementException {
+ isInitialized = false;
+ keyManager = chooseKeyManager(km);
+
+ if (tm == null) {
+ try {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init((KeyStore)null);
+ tm = tmf.getTrustManagers();
+ } catch (Exception e) {
+ // eat
+ }
+ }
+ trustManager = chooseTrustManager(tm);
+
+ if (sr == null) {
+ secureRandom = JsseJce.getSecureRandom();
+ } else {
+ if (SunJSSE.isFIPS() &&
+ (sr.getProvider() != SunJSSE.cryptoProvider)) {
+ throw new KeyManagementException
+ ("FIPS mode: SecureRandom must be from provider "
+ + SunJSSE.cryptoProvider.getName());
+ }
+ secureRandom = sr;
+ }
+
+ /*
+ * The initial delay of seeding the random number generator
+ * could be long enough to cause the initial handshake on our
+ * first connection to timeout and fail. Make sure it is
+ * primed and ready by getting some initial output from it.
+ */
+ if (debug != null && Debug.isOn("sslctx")) {
+ System.out.println("trigger seeding of SecureRandom");
+ }
+ secureRandom.nextInt();
+ if (debug != null && Debug.isOn("sslctx")) {
+ System.out.println("done seeding SecureRandom");
+ }
+
+ isInitialized = true;
+ }
+
+ private X509TrustManager chooseTrustManager(TrustManager[] tm)
+ throws KeyManagementException {
+ // We only use the first instance of X509TrustManager passed to us.
+ for (int i = 0; tm != null && i < tm.length; i++) {
+ if (tm[i] instanceof X509TrustManager) {
+ if (SunJSSE.isFIPS() &&
+ !(tm[i] instanceof X509TrustManagerImpl)) {
+ throw new KeyManagementException
+ ("FIPS mode: only SunJSSE TrustManagers may be used");
+ }
+
+ if (tm[i] instanceof X509ExtendedTrustManager) {
+ return (X509TrustManager)tm[i];
+ } else {
+ return new AbstractTrustManagerWrapper(
+ (X509TrustManager)tm[i]);
+ }
+ }
+ }
+
+ // nothing found, return a dummy X509TrustManager.
+ return DummyX509TrustManager.INSTANCE;
+ }
+
+ private X509ExtendedKeyManager chooseKeyManager(KeyManager[] kms)
+ throws KeyManagementException {
+ for (int i = 0; kms != null && i < kms.length; i++) {
+ KeyManager km = kms[i];
+ if (!(km instanceof X509KeyManager)) {
+ continue;
+ }
+ if (SunJSSE.isFIPS()) {
+ // In FIPS mode, require that one of SunJSSE's own keymanagers
+ // is used. Otherwise, we cannot be sure that only keys from
+ // the FIPS token are used.
+ if ((km instanceof X509KeyManagerImpl)
+ || (km instanceof SunX509KeyManagerImpl)) {
+ return (X509ExtendedKeyManager)km;
+ } else {
+ // throw exception, we don't want to silently use the
+ // dummy keymanager without telling the user.
+ throw new KeyManagementException
+ ("FIPS mode: only SunJSSE KeyManagers may be used");
+ }
+ }
+ if (km instanceof X509ExtendedKeyManager) {
+ return (X509ExtendedKeyManager)km;
+ }
+ if (debug != null && Debug.isOn("sslctx")) {
+ System.out.println(
+ "X509KeyManager passed to " +
+ "SSLContext.init(): need an " +
+ "X509ExtendedKeyManager for SSLEngine use");
+ }
+ return new AbstractKeyManagerWrapper((X509KeyManager)km);
+ }
+
+ // nothing found, return a dummy X509ExtendedKeyManager
+ return DummyX509KeyManager.INSTANCE;
+ }
+
+ abstract SSLEngine createSSLEngineImpl();
+ abstract SSLEngine createSSLEngineImpl(String host, int port);
+
+ @Override
+ protected SSLEngine engineCreateSSLEngine() {
+ if (!isInitialized) {
+ throw new IllegalStateException("SSLContext is not initialized");
+ }
+ return createSSLEngineImpl();
+ }
+
+ @Override
+ protected SSLEngine engineCreateSSLEngine(String host, int port) {
+ if (!isInitialized) {
+ throw new IllegalStateException("SSLContext is not initialized");
+ }
+ return createSSLEngineImpl(host, port);
+ }
+
+ @Override
+ protected SSLSocketFactory engineGetSocketFactory() {
+ if (!isInitialized) {
+ throw new IllegalStateException("SSLContext is not initialized");
+ }
+ return new SSLSocketFactoryImpl(this);
+ }
+
+ @Override
+ protected SSLServerSocketFactory engineGetServerSocketFactory() {
+ if (!isInitialized) {
+ throw new IllegalStateException("SSLContext is not initialized");
+ }
+ return new SSLServerSocketFactoryImpl(this);
+ }
+
+ @Override
+ protected SSLSessionContext engineGetClientSessionContext() {
+ return clientCache;
+ }
+
+ @Override
+ protected SSLSessionContext engineGetServerSessionContext() {
+ return serverCache;
+ }
+
+ SecureRandom getSecureRandom() {
+ return secureRandom;
+ }
+
+ X509ExtendedKeyManager getX509KeyManager() {
+ return keyManager;
+ }
+
+ X509TrustManager getX509TrustManager() {
+ return trustManager;
+ }
+
+ EphemeralKeyManager getEphemeralKeyManager() {
+ return ephemeralKeyManager;
+ }
+
+ // Used for DTLS in server mode only, see ServerHandshaker.
+ HelloCookieManager getHelloCookieManager() {
+ if (!isInitialized) {
+ throw new IllegalStateException("SSLContext is not initialized");
+ }
+
+ if (helloCookieManager != null) {
+ return helloCookieManager;
+ }
+
+ synchronized (this) {
+ if (helloCookieManager == null) {
+ helloCookieManager = getHelloCookieManager(secureRandom);
+ }
+ }
+
+ return helloCookieManager;
+ }
+
+ HelloCookieManager getHelloCookieManager(SecureRandom secureRandom) {
+ throw new UnsupportedOperationException(
+ "Cookie exchange applies to DTLS only");
+ }
+
+ StatusResponseManager getStatusResponseManager() {
+ if (serverEnableStapling && statusResponseManager == null) {
+ synchronized (this) {
+ if (statusResponseManager == null) {
+ if (debug != null && Debug.isOn("sslctx")) {
+ System.out.println(
+ "Initializing StatusResponseManager");
+ }
+ statusResponseManager = new StatusResponseManager();
+ }
+ }
+ }
+
+ return statusResponseManager;
+ }
+
+ // Get supported ProtocolList.
+ abstract ProtocolList getSuportedProtocolList();
+
+ // Get default ProtocolList for server mode.
+ abstract ProtocolList getServerDefaultProtocolList();
+
+ // Get default ProtocolList for client mode.
+ abstract ProtocolList getClientDefaultProtocolList();
+
+ // Get supported CipherSuiteList.
+ abstract CipherSuiteList getSupportedCipherSuiteList();
+
+ // Get default CipherSuiteList for server mode.
+ abstract CipherSuiteList getServerDefaultCipherSuiteList();
+
+ // Get default CipherSuiteList for client mode.
+ abstract CipherSuiteList getClientDefaultCipherSuiteList();
+
+ // Get default ProtocolList.
+ ProtocolList getDefaultProtocolList(boolean roleIsServer) {
+ return roleIsServer ? getServerDefaultProtocolList()
+ : getClientDefaultProtocolList();
+ }
+
+ // Get default CipherSuiteList.
+ CipherSuiteList getDefaultCipherSuiteList(boolean roleIsServer) {
+ return roleIsServer ? getServerDefaultCipherSuiteList()
+ : getClientDefaultCipherSuiteList();
+ }
+
+ /**
+ * Return whether a protocol list is the original default enabled
+ * protocols. See: SSLSocket/SSLEngine.setEnabledProtocols()
+ */
+ boolean isDefaultProtocolList(ProtocolList protocols) {
+ return (protocols == getServerDefaultProtocolList()) ||
+ (protocols == getClientDefaultProtocolList());
+ }
+
+ /**
+ * Return whether a protocol list is the original default enabled
+ * protocols. See: SSLSocket/SSLEngine.setEnabledProtocols()
+ */
+ boolean isDefaultCipherSuiteList(CipherSuiteList cipherSuites) {
+ return (cipherSuites == getServerDefaultCipherSuiteList()) ||
+ (cipherSuites == getClientDefaultCipherSuiteList());
+ }
+
+ /**
+ * Return whether client or server side stapling has been enabled
+ * for this SSLContextImpl
+ * @param isClient true if the caller is operating in a client side role,
+ * false if acting as a server.
+ * @return true if stapling has been enabled for the specified role, false
+ * otherwise.
+ */
+ boolean isStaplingEnabled(boolean isClient) {
+ return isClient ? clientEnableStapling : serverEnableStapling;
+ }
+
+
+ /*
+ * Return the list of all available CipherSuites that are supported
+ * using currently installed providers.
+ */
+ private static CipherSuiteList getApplicableSupportedCipherSuiteList(
+ ProtocolList protocols) {
+
+ return getApplicableCipherSuiteList(
+ CipherSuite.allowedCipherSuites(),
+ protocols, CipherSuite.SUPPORTED_SUITES_PRIORITY);
+ }
+
+ /*
+ * Return the list of all available CipherSuites that are default enabled
+ * in client or server side.
+ */
+ private static CipherSuiteList getApplicableEnabledCipherSuiteList(
+ ProtocolList protocols, boolean isClient) {
+
+ if (isClient) {
+ if (!clientCustomizedCipherSuites.isEmpty()) {
+ return getApplicableCipherSuiteList(
+ clientCustomizedCipherSuites,
+ protocols, CipherSuite.SUPPORTED_SUITES_PRIORITY);
+ }
+ } else {
+ if (!serverCustomizedCipherSuites.isEmpty()) {
+ return getApplicableCipherSuiteList(
+ serverCustomizedCipherSuites,
+ protocols, CipherSuite.SUPPORTED_SUITES_PRIORITY);
+ }
+ }
+
+ return getApplicableCipherSuiteList(
+ CipherSuite.allowedCipherSuites(),
+ protocols, CipherSuite.DEFAULT_SUITES_PRIORITY);
+ }
+
+ /*
+ * Return the list of available CipherSuites which are applicable to
+ * the specified protocols.
+ */
+ private static CipherSuiteList getApplicableCipherSuiteList(
+ Collection<CipherSuite> allowedCipherSuites,
+ ProtocolList protocols, int minPriority) {
+
+ TreeSet<CipherSuite> suites = new TreeSet<>();
+ if (!(protocols.collection().isEmpty()) &&
+ protocols.min.v != ProtocolVersion.NONE.v) {
+ for (CipherSuite suite : allowedCipherSuites) {
+ if (!suite.allowed || suite.priority < minPriority) {
+ continue;
+ }
+
+ if (suite.isAvailable() &&
+ !protocols.min.obsoletes(suite) &&
+ protocols.max.supports(suite)) {
+ if (SSLAlgorithmConstraints.DEFAULT.permits(
+ EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+ suite.name, null)) {
+ suites.add(suite);
+ } else {
+ if (debug != null && Debug.isOn("sslctx") &&
+ Debug.isOn("verbose")) {
+ System.out.println(
+ "Ignoring disabled cipher suite: " +
+ suite.name);
+ }
+ }
+ } else if (debug != null &&
+ Debug.isOn("sslctx") && Debug.isOn("verbose")) {
+ if (protocols.min.obsoletes(suite)) {
+ System.out.println(
+ "Ignoring obsoleted cipher suite: " + suite);
+ } else if (!protocols.max.supports(suite)) {
+ System.out.println(
+ "Ignoring unsupported cipher suite: " + suite);
+ } else {
+ System.out.println(
+ "Ignoring unavailable cipher suite: " + suite);
+ }
+ }
+ }
+ }
+
+ return new CipherSuiteList(suites);
+ }
+
+ /*
+ * Get the customized cipher suites specified by the given system property.
+ */
+ private static Collection<CipherSuite> getCustomizedCipherSuites(
+ String propertyName) {
+
+ String property = GetPropertyAction.privilegedGetProperty(propertyName);
+ if (debug != null && Debug.isOn("sslctx")) {
+ System.out.println(
+ "System property " + propertyName + " is set to '" +
+ property + "'");
+ }
+ if (property != null && property.length() != 0) {
+ // remove double quote marks from beginning/end of the property
+ if (property.length() > 1 && property.charAt(0) == '"' &&
+ property.charAt(property.length() - 1) == '"') {
+ property = property.substring(1, property.length() - 1);
+ }
+ }
+
+ if (property != null && property.length() != 0) {
+ String[] cipherSuiteNames = property.split(",");
+ Collection<CipherSuite> cipherSuites =
+ new ArrayList<>(cipherSuiteNames.length);
+ for (int i = 0; i < cipherSuiteNames.length; i++) {
+ cipherSuiteNames[i] = cipherSuiteNames[i].trim();
+ if (cipherSuiteNames[i].isEmpty()) {
+ continue;
+ }
+
+ CipherSuite suite;
+ try {
+ suite = CipherSuite.valueOf(cipherSuiteNames[i]);
+ } catch (IllegalArgumentException iae) {
+ if (debug != null && Debug.isOn("sslctx")) {
+ System.out.println(
+ "Unknown or unsupported cipher suite name: " +
+ cipherSuiteNames[i]);
+ }
+
+ continue;
+ }
+
+ if (suite.isAvailable()) {
+ cipherSuites.add(suite);
+ } else {
+ if (debug != null && Debug.isOn("sslctx")) {
+ System.out.println(
+ "The current installed providers do not " +
+ "support cipher suite: " + cipherSuiteNames[i]);
+ }
+ }
+ }
+
+ return cipherSuites;
+ }
+
+ return Collections.emptyList();
+ }
+
+
+ private static String[] getAvailableProtocols(
+ ProtocolVersion[] protocolCandidates) {
+
+ List<String> availableProtocols = Collections.<String>emptyList();
+ if (protocolCandidates != null && protocolCandidates.length != 0) {
+ availableProtocols = new ArrayList<>(protocolCandidates.length);
+ for (ProtocolVersion p : protocolCandidates) {
+ if (ProtocolVersion.availableProtocols.contains(p)) {
+ availableProtocols.add(p.name);
+ }
+ }
+ }
+
+ return availableProtocols.toArray(new String[0]);
+ }
+
+
+ /*
+ * The SSLContext implementation for SSL/(D)TLS algorithm
+ *
+ * SSL/TLS protocols specify the forward compatibility and version
+ * roll-back attack protections, however, a number of SSL/TLS server
+ * vendors did not implement these aspects properly, and some current
+ * SSL/TLS servers may refuse to talk to a TLS 1.1 or later client.
+ *
+ * Considering above interoperability issues, SunJSSE will not set
+ * TLS 1.1 and TLS 1.2 as the enabled protocols for client by default.
+ *
+ * For SSL/TLS servers, there is no such interoperability issues as
+ * SSL/TLS clients. In SunJSSE, TLS 1.1 or later version will be the
+ * enabled protocols for server by default.
+ *
+ * We may change the behavior when popular TLS/SSL vendors support TLS
+ * forward compatibility properly.
+ *
+ * SSLv2Hello is no longer necessary. This interoperability option was
+ * put in place in the late 90's when SSLv3/TLS1.0 were relatively new
+ * and there were a fair number of SSLv2-only servers deployed. Because
+ * of the security issues in SSLv2, it is rarely (if ever) used, as
+ * deployments should now be using SSLv3 and TLSv1.
+ *
+ * Considering the issues of SSLv2Hello, we should not enable SSLv2Hello
+ * by default. Applications still can use it by enabling SSLv2Hello with
+ * the series of setEnabledProtocols APIs.
+ */
+
+ /*
+ * The base abstract SSLContext implementation for the Transport Layer
+ * Security (TLS) protocols.
+ *
+ * This abstract class encapsulates supported and the default server
+ * SSL/TLS parameters.
+ *
+ * @see SSLContext
+ */
+ private abstract static class AbstractTLSContext extends SSLContextImpl {
+ private static final ProtocolList supportedProtocolList;
+ private static final ProtocolList serverDefaultProtocolList;
+
+ private static final CipherSuiteList supportedCipherSuiteList;
+ private static final CipherSuiteList serverDefaultCipherSuiteList;
+
+ static {
+ if (SunJSSE.isFIPS()) {
+ supportedProtocolList = new ProtocolList(new String[] {
+ ProtocolVersion.TLS10.name,
+ ProtocolVersion.TLS11.name,
+ ProtocolVersion.TLS12.name
+ });
+
+ serverDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.TLS10,
+ ProtocolVersion.TLS11,
+ ProtocolVersion.TLS12
+ }));
+ } else {
+ supportedProtocolList = new ProtocolList(new String[] {
+ ProtocolVersion.SSL20Hello.name,
+ ProtocolVersion.SSL30.name,
+ ProtocolVersion.TLS10.name,
+ ProtocolVersion.TLS11.name,
+ ProtocolVersion.TLS12.name
+ });
+
+ serverDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.SSL20Hello,
+ ProtocolVersion.SSL30,
+ ProtocolVersion.TLS10,
+ ProtocolVersion.TLS11,
+ ProtocolVersion.TLS12
+ }));
+ }
+
+ supportedCipherSuiteList = getApplicableSupportedCipherSuiteList(
+ supportedProtocolList);
+ serverDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList(
+ serverDefaultProtocolList, false);
+ }
+
+ @Override
+ ProtocolList getSuportedProtocolList() {
+ return supportedProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getSupportedCipherSuiteList() {
+ return supportedCipherSuiteList;
+ }
+
+ @Override
+ ProtocolList getServerDefaultProtocolList() {
+ return serverDefaultProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getServerDefaultCipherSuiteList() {
+ return serverDefaultCipherSuiteList;
+ }
+
+ @Override
+ SSLEngine createSSLEngineImpl() {
+ return new SSLEngineImpl(this, false);
+ }
+
+ @Override
+ SSLEngine createSSLEngineImpl(String host, int port) {
+ return new SSLEngineImpl(this, host, port, false);
+ }
+ }
+
+ /*
+ * The SSLContext implementation for SSLv3 and TLS10 algorithm
+ *
+ * @see SSLContext
+ */
+ public static final class TLS10Context extends AbstractTLSContext {
+ private static final ProtocolList clientDefaultProtocolList;
+ private static final CipherSuiteList clientDefaultCipherSuiteList;
+
+ static {
+ if (SunJSSE.isFIPS()) {
+ clientDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.TLS10
+ }));
+ } else {
+ clientDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.SSL30,
+ ProtocolVersion.TLS10
+ }));
+ }
+
+ clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList(
+ clientDefaultProtocolList, true);
+ }
+
+ @Override
+ ProtocolList getClientDefaultProtocolList() {
+ return clientDefaultProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getClientDefaultCipherSuiteList() {
+ return clientDefaultCipherSuiteList;
+ }
+ }
+
+ /*
+ * The SSLContext implementation for TLS11 algorithm
+ *
+ * @see SSLContext
+ */
+ public static final class TLS11Context extends AbstractTLSContext {
+ private static final ProtocolList clientDefaultProtocolList;
+ private static final CipherSuiteList clientDefaultCipherSuiteList;
+
+ static {
+ if (SunJSSE.isFIPS()) {
+ clientDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.TLS10,
+ ProtocolVersion.TLS11
+ }));
+ } else {
+ clientDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.SSL30,
+ ProtocolVersion.TLS10,
+ ProtocolVersion.TLS11
+ }));
+ }
+
+ clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList(
+ clientDefaultProtocolList, true);
+
+ }
+
+ @Override
+ ProtocolList getClientDefaultProtocolList() {
+ return clientDefaultProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getClientDefaultCipherSuiteList() {
+ return clientDefaultCipherSuiteList;
+ }
+ }
+
+ /*
+ * The SSLContext implementation for TLS12 algorithm
+ *
+ * @see SSLContext
+ */
+ public static final class TLS12Context extends AbstractTLSContext {
+ private static final ProtocolList clientDefaultProtocolList;
+ private static final CipherSuiteList clientDefaultCipherSuiteList;
+
+ static {
+ if (SunJSSE.isFIPS()) {
+ clientDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.TLS10,
+ ProtocolVersion.TLS11,
+ ProtocolVersion.TLS12
+ }));
+ } else {
+ clientDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.SSL30,
+ ProtocolVersion.TLS10,
+ ProtocolVersion.TLS11,
+ ProtocolVersion.TLS12
+ }));
+ }
+
+ clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList(
+ clientDefaultProtocolList, true);
+ }
+
+ @Override
+ ProtocolList getClientDefaultProtocolList() {
+ return clientDefaultProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getClientDefaultCipherSuiteList() {
+ return clientDefaultCipherSuiteList;
+ }
+ }
+
+ /*
+ * The interface for the customized SSL/(D)TLS SSLContext.
+ *
+ * @see SSLContext
+ */
+ private static class CustomizedSSLProtocols {
+ private static final String PROPERTY_NAME = "jdk.tls.client.protocols";
+ static IllegalArgumentException reservedException = null;
+ static ArrayList<ProtocolVersion>
+ customizedProtocols = new ArrayList<>();
+
+ // Don't want a java.lang.LinkageError for illegal system property.
+ //
+ // Please don't throw exception in this static block. Otherwise,
+ // java.lang.LinkageError may be thrown during the instantiation of
+ // the provider service. Instead, please handle the initialization
+ // exception in the caller's constructor.
+ static {
+ String property = GetPropertyAction
+ .privilegedGetProperty(PROPERTY_NAME);
+ if (property != null && property.length() != 0) {
+ // remove double quote marks from beginning/end of the property
+ if (property.length() > 1 && property.charAt(0) == '"' &&
+ property.charAt(property.length() - 1) == '"') {
+ property = property.substring(1, property.length() - 1);
+ }
+ }
+
+ if (property != null && property.length() != 0) {
+ String[] protocols = property.split(",");
+ for (int i = 0; i < protocols.length; i++) {
+ protocols[i] = protocols[i].trim();
+ // Is it a supported protocol name?
+ try {
+ ProtocolVersion pro =
+ ProtocolVersion.valueOf(protocols[i]);
+
+ if (SunJSSE.isFIPS() &&
+ ((pro.v == ProtocolVersion.SSL30.v) ||
+ (pro.v == ProtocolVersion.SSL20Hello.v))) {
+ reservedException = new IllegalArgumentException(
+ PROPERTY_NAME + ": " + pro +
+ " is not FIPS compliant");
+
+ break;
+ }
+
+ // ignore duplicated protocols
+ if (!customizedProtocols.contains(pro)) {
+ customizedProtocols.add(pro);
+ }
+ } catch (IllegalArgumentException iae) {
+ reservedException = new IllegalArgumentException(
+ PROPERTY_NAME + ": " + protocols[i] +
+ " is not a standard SSL protocol name", iae);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * The SSLContext implementation for customized TLS protocols
+ *
+ * @see SSLContext
+ */
+ private static class CustomizedTLSContext extends AbstractTLSContext {
+
+ private static final ProtocolList clientDefaultProtocolList;
+ private static final CipherSuiteList clientDefaultCipherSuiteList;
+
+ private static IllegalArgumentException reservedException = null;
+
+ // Don't want a java.lang.LinkageError for illegal system property.
+ //
+ // Please don't throw exception in this static block. Otherwise,
+ // java.lang.LinkageError may be thrown during the instantiation of
+ // the provider service. Instead, let's handle the initialization
+ // exception in constructor.
+ static {
+ reservedException = CustomizedSSLProtocols.reservedException;
+ if (reservedException == null) {
+ ArrayList<ProtocolVersion>
+ customizedTLSProtocols = new ArrayList<>();
+ for (ProtocolVersion protocol :
+ CustomizedSSLProtocols.customizedProtocols) {
+ if (!protocol.isDTLSProtocol()) {
+ customizedTLSProtocols.add(protocol);
+ }
+ }
+
+ // candidates for available protocols
+ ProtocolVersion[] candidates;
+ if (customizedTLSProtocols.isEmpty()) {
+ // Use the default enabled client protocols if no
+ // customized TLS protocols.
+ if (SunJSSE.isFIPS()) {
+ candidates = new ProtocolVersion[] {
+ ProtocolVersion.TLS10,
+ ProtocolVersion.TLS11,
+ ProtocolVersion.TLS12
+ };
+ } else {
+ candidates = new ProtocolVersion[] {
+ ProtocolVersion.SSL30,
+ ProtocolVersion.TLS10,
+ ProtocolVersion.TLS11,
+ ProtocolVersion.TLS12
+ };
+ }
+ } else {
+ // Use the customized TLS protocols.
+ candidates =
+ new ProtocolVersion[customizedTLSProtocols.size()];
+ candidates = customizedTLSProtocols.toArray(candidates);
+ }
+
+ clientDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(candidates));
+ clientDefaultCipherSuiteList =
+ getApplicableEnabledCipherSuiteList(
+ clientDefaultProtocolList, true);
+ } else {
+ clientDefaultProtocolList = null; // unlikely to be used
+ clientDefaultCipherSuiteList = null; // unlikely to be used
+ }
+ }
+
+ protected CustomizedTLSContext() {
+ if (reservedException != null) {
+ throw reservedException;
+ }
+ }
+
+ @Override
+ ProtocolList getClientDefaultProtocolList() {
+ return clientDefaultProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getClientDefaultCipherSuiteList() {
+ return clientDefaultCipherSuiteList;
+ }
+ }
+
+ /*
+ * The SSLContext implementation for default "TLS" algorithm
+ *
+ * @see SSLContext
+ */
+ public static final class TLSContext extends CustomizedTLSContext {
+ // use the default constructor and methods
+ }
+
+ // lazy initialization holder class idiom for static default parameters
+ //
+ // See Effective Java Second Edition: Item 71.
+ private static final class DefaultManagersHolder {
+ private static final String NONE = "NONE";
+ private static final String P11KEYSTORE = "PKCS11";
+
+ private static final TrustManager[] trustManagers;
+ private static final KeyManager[] keyManagers;
+
+ static Exception reservedException = null;
+
+ static {
+ TrustManager[] tmMediator;
+ try {
+ tmMediator = getTrustManagers();
+ } catch (Exception e) {
+ reservedException = e;
+ tmMediator = new TrustManager[0];
+ }
+ trustManagers = tmMediator;
+
+ if (reservedException == null) {
+ KeyManager[] kmMediator;
+ try {
+ kmMediator = getKeyManagers();
+ } catch (Exception e) {
+ reservedException = e;
+ kmMediator = new KeyManager[0];
+ }
+ keyManagers = kmMediator;
+ } else {
+ keyManagers = new KeyManager[0];
+ }
+ }
+
+ private static TrustManager[] getTrustManagers() throws Exception {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ if ("SunJSSE".equals(tmf.getProvider().getName())) {
+ // The implementation will load the default KeyStore
+ // automatically. Cached trust materials may be used
+ // for performance improvement.
+ tmf.init((KeyStore)null);
+ } else {
+ // Use the explicitly specified KeyStore for third party's
+ // TrustManagerFactory implementation.
+ KeyStore ks = TrustStoreManager.getTrustedKeyStore();
+ tmf.init(ks);
+ }
+
+ return tmf.getTrustManagers();
+ }
+
+ private static KeyManager[] getKeyManagers() throws Exception {
+
+ final Map<String,String> props = new HashMap<>();
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Object>() {
+ @Override
+ public Object run() throws Exception {
+ props.put("keyStore", System.getProperty(
+ "javax.net.ssl.keyStore", ""));
+ props.put("keyStoreType", System.getProperty(
+ "javax.net.ssl.keyStoreType",
+ KeyStore.getDefaultType()));
+ props.put("keyStoreProvider", System.getProperty(
+ "javax.net.ssl.keyStoreProvider", ""));
+ props.put("keyStorePasswd", System.getProperty(
+ "javax.net.ssl.keyStorePassword", ""));
+ return null;
+ }
+ });
+
+ final String defaultKeyStore = props.get("keyStore");
+ String defaultKeyStoreType = props.get("keyStoreType");
+ String defaultKeyStoreProvider = props.get("keyStoreProvider");
+ if (debug != null && Debug.isOn("defaultctx")) {
+ System.out.println("keyStore is : " + defaultKeyStore);
+ System.out.println("keyStore type is : " +
+ defaultKeyStoreType);
+ System.out.println("keyStore provider is : " +
+ defaultKeyStoreProvider);
+ }
+
+ if (P11KEYSTORE.equals(defaultKeyStoreType) &&
+ !NONE.equals(defaultKeyStore)) {
+ throw new IllegalArgumentException("if keyStoreType is "
+ + P11KEYSTORE + ", then keyStore must be " + NONE);
+ }
+
+ FileInputStream fs = null;
+ KeyStore ks = null;
+ char[] passwd = null;
+ try {
+ if (defaultKeyStore.length() != 0 &&
+ !NONE.equals(defaultKeyStore)) {
+ fs = AccessController.doPrivileged(
+ new PrivilegedExceptionAction<FileInputStream>() {
+ @Override
+ public FileInputStream run() throws Exception {
+ return new FileInputStream(defaultKeyStore);
+ }
+ });
+ }
+
+ String defaultKeyStorePassword = props.get("keyStorePasswd");
+ if (defaultKeyStorePassword.length() != 0) {
+ passwd = defaultKeyStorePassword.toCharArray();
+ }
+
+ /**
+ * Try to initialize key store.
+ */
+ if ((defaultKeyStoreType.length()) != 0) {
+ if (debug != null && Debug.isOn("defaultctx")) {
+ System.out.println("init keystore");
+ }
+ if (defaultKeyStoreProvider.length() == 0) {
+ ks = KeyStore.getInstance(defaultKeyStoreType);
+ } else {
+ ks = KeyStore.getInstance(defaultKeyStoreType,
+ defaultKeyStoreProvider);
+ }
+
+ // if defaultKeyStore is NONE, fs will be null
+ ks.load(fs, passwd);
+ }
+ } finally {
+ if (fs != null) {
+ fs.close();
+ fs = null;
+ }
+ }
+
+ /*
+ * Try to initialize key manager.
+ */
+ if (debug != null && Debug.isOn("defaultctx")) {
+ System.out.println("init keymanager of type " +
+ KeyManagerFactory.getDefaultAlgorithm());
+ }
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(
+ KeyManagerFactory.getDefaultAlgorithm());
+
+ if (P11KEYSTORE.equals(defaultKeyStoreType)) {
+ kmf.init(ks, null); // do not pass key passwd if using token
+ } else {
+ kmf.init(ks, passwd);
+ }
+
+ return kmf.getKeyManagers();
+ }
+ }
+
+ // lazy initialization holder class idiom for static default parameters
+ //
+ // See Effective Java Second Edition: Item 71.
+ private static final class DefaultSSLContextHolder {
+
+ private static final SSLContextImpl sslContext;
+ static Exception reservedException = null;
+
+ static {
+ SSLContextImpl mediator = null;
+ if (DefaultManagersHolder.reservedException != null) {
+ reservedException = DefaultManagersHolder.reservedException;
+ } else {
+ try {
+ mediator = new DefaultSSLContext();
+ } catch (Exception e) {
+ reservedException = e;
+ }
+ }
+
+ sslContext = mediator;
+ }
+ }
+
+ /*
+ * The SSLContext implementation for default "Default" algorithm
+ *
+ * @see SSLContext
+ */
+ public static final class DefaultSSLContext extends CustomizedTLSContext {
+
+ // public constructor for SSLContext.getInstance("Default")
+ public DefaultSSLContext() throws Exception {
+ if (DefaultManagersHolder.reservedException != null) {
+ throw DefaultManagersHolder.reservedException;
+ }
+
+ try {
+ super.engineInit(DefaultManagersHolder.keyManagers,
+ DefaultManagersHolder.trustManagers, null);
+ } catch (Exception e) {
+ if (debug != null && Debug.isOn("defaultctx")) {
+ System.out.println("default context init failed: " + e);
+ }
+ throw e;
+ }
+ }
+
+ @Override
+ protected void engineInit(KeyManager[] km, TrustManager[] tm,
+ SecureRandom sr) throws KeyManagementException {
+ throw new KeyManagementException
+ ("Default SSLContext is initialized automatically");
+ }
+
+ static SSLContextImpl getDefaultImpl() throws Exception {
+ if (DefaultSSLContextHolder.reservedException != null) {
+ throw DefaultSSLContextHolder.reservedException;
+ }
+
+ return DefaultSSLContextHolder.sslContext;
+ }
+ }
+
+ /*
+ * The base abstract SSLContext implementation for the Datagram Transport
+ * Layer Security (DTLS) protocols.
+ *
+ * This abstract class encapsulates supported and the default server DTLS
+ * parameters.
+ *
+ * @see SSLContext
+ */
+ private abstract static class AbstractDTLSContext extends SSLContextImpl {
+ private static final ProtocolList supportedProtocolList;
+ private static final ProtocolList serverDefaultProtocolList;
+
+ private static final CipherSuiteList supportedCipherSuiteList;
+ private static final CipherSuiteList serverDefaultCipherSuiteList;
+
+ static {
+ // Both DTLSv1.0 and DTLSv1.2 can be used in FIPS mode.
+ supportedProtocolList = new ProtocolList(new String[] {
+ ProtocolVersion.DTLS10.name,
+ ProtocolVersion.DTLS12.name
+ });
+
+ // available protocols for server mode
+ serverDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.DTLS10,
+ ProtocolVersion.DTLS12
+ }));
+
+ supportedCipherSuiteList = getApplicableSupportedCipherSuiteList(
+ supportedProtocolList);
+ serverDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList(
+ serverDefaultProtocolList, false);
+ }
+
+ @Override
+ ProtocolList getSuportedProtocolList() {
+ return supportedProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getSupportedCipherSuiteList() {
+ return supportedCipherSuiteList;
+ }
+
+ @Override
+ ProtocolList getServerDefaultProtocolList() {
+ return serverDefaultProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getServerDefaultCipherSuiteList() {
+ return serverDefaultCipherSuiteList;
+ }
+
+ @Override
+ SSLEngine createSSLEngineImpl() {
+ return new SSLEngineImpl(this, true);
+ }
+
+ @Override
+ SSLEngine createSSLEngineImpl(String host, int port) {
+ return new SSLEngineImpl(this, host, port, true);
+ }
+
+ @Override
+ HelloCookieManager getHelloCookieManager(SecureRandom secureRandom) {
+ return new HelloCookieManager(secureRandom);
+ }
+ }
+
+ /*
+ * The SSLContext implementation for DTLSv1.0 algorithm.
+ *
+ * @see SSLContext
+ */
+ public static final class DTLS10Context extends AbstractDTLSContext {
+ private static final ProtocolList clientDefaultProtocolList;
+ private static final CipherSuiteList clientDefaultCipherSuiteList;
+
+ static {
+ // available protocols for client mode
+ clientDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.DTLS10
+ }));
+
+ clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList(
+ clientDefaultProtocolList, true);
+ }
+
+ @Override
+ ProtocolList getClientDefaultProtocolList() {
+ return clientDefaultProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getClientDefaultCipherSuiteList() {
+ return clientDefaultCipherSuiteList;
+ }
+ }
+
+ /*
+ * The SSLContext implementation for DTLSv1.2 algorithm.
+ *
+ * @see SSLContext
+ */
+ public static final class DTLS12Context extends AbstractDTLSContext {
+ private static final ProtocolList clientDefaultProtocolList;
+ private static final CipherSuiteList clientDefaultCipherSuiteList;
+
+ static {
+ // available protocols for client mode
+ clientDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(new ProtocolVersion[] {
+ ProtocolVersion.DTLS10,
+ ProtocolVersion.DTLS12
+ }));
+
+ clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList(
+ clientDefaultProtocolList, true);
+ }
+
+ @Override
+ ProtocolList getClientDefaultProtocolList() {
+ return clientDefaultProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getClientDefaultCipherSuiteList() {
+ return clientDefaultCipherSuiteList;
+ }
+ }
+
+ /*
+ * The SSLContext implementation for customized TLS protocols
+ *
+ * @see SSLContext
+ */
+ private static class CustomizedDTLSContext extends AbstractDTLSContext {
+ private static final ProtocolList clientDefaultProtocolList;
+ private static final CipherSuiteList clientDefaultCipherSuiteList;
+
+ private static IllegalArgumentException reservedException = null;
+
+ // Don't want a java.lang.LinkageError for illegal system property.
+ //
+ // Please don't throw exception in this static block. Otherwise,
+ // java.lang.LinkageError may be thrown during the instantiation of
+ // the provider service. Instead, let's handle the initialization
+ // exception in constructor.
+ static {
+ reservedException = CustomizedSSLProtocols.reservedException;
+ if (reservedException == null) {
+ ArrayList<ProtocolVersion>
+ customizedDTLSProtocols = new ArrayList<>();
+ for (ProtocolVersion protocol :
+ CustomizedSSLProtocols.customizedProtocols) {
+ if (protocol.isDTLSProtocol()) {
+ customizedDTLSProtocols.add(protocol);
+ }
+ }
+
+ // candidates for available protocols
+ ProtocolVersion[] candidates;
+ if (customizedDTLSProtocols.isEmpty()) {
+ // Use the default enabled client protocols if no
+ // customized TLS protocols.
+ //
+ // Both DTLSv1.0 and DTLSv1.2 can be used in FIPS mode.
+ candidates = new ProtocolVersion[] {
+ ProtocolVersion.DTLS10,
+ ProtocolVersion.DTLS12
+ };
+
+ } else {
+ // Use the customized TLS protocols.
+ candidates =
+ new ProtocolVersion[customizedDTLSProtocols.size()];
+ candidates = customizedDTLSProtocols.toArray(candidates);
+ }
+
+ clientDefaultProtocolList = new ProtocolList(
+ getAvailableProtocols(candidates));
+ clientDefaultCipherSuiteList =
+ getApplicableEnabledCipherSuiteList(
+ clientDefaultProtocolList, true);
+ } else {
+ clientDefaultProtocolList = null; // unlikely to be used
+ clientDefaultCipherSuiteList = null; // unlikely to be used
+ }
+ }
+
+ protected CustomizedDTLSContext() {
+ if (reservedException != null) {
+ throw reservedException;
+ }
+ }
+
+ @Override
+ ProtocolList getClientDefaultProtocolList() {
+ return clientDefaultProtocolList;
+ }
+
+ @Override
+ CipherSuiteList getClientDefaultCipherSuiteList() {
+ return clientDefaultCipherSuiteList;
+ }
+ }
+
+ /*
+ * The SSLContext implementation for default "DTLS" algorithm
+ *
+ * @see SSLContext
+ */
+ public static final class DTLSContext extends CustomizedDTLSContext {
+ // use the default constructor and methods
+ }
+
+}
+
+
+final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
+ implements X509TrustManager {
+
+ // the delegated trust manager
+ private final X509TrustManager tm;
+
+ AbstractTrustManagerWrapper(X509TrustManager tm) {
+ this.tm = tm;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ tm.checkClientTrusted(chain, authType);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ tm.checkServerTrusted(chain, authType);
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return tm.getAcceptedIssuers();
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType,
+ Socket socket) throws CertificateException {
+ tm.checkClientTrusted(chain, authType);
+ checkAdditionalTrust(chain, authType, socket, true);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType,
+ Socket socket) throws CertificateException {
+ tm.checkServerTrusted(chain, authType);
+ checkAdditionalTrust(chain, authType, socket, false);
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType,
+ SSLEngine engine) throws CertificateException {
+ tm.checkClientTrusted(chain, authType);
+ checkAdditionalTrust(chain, authType, engine, true);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType,
+ SSLEngine engine) throws CertificateException {
+ tm.checkServerTrusted(chain, authType);
+ checkAdditionalTrust(chain, authType, engine, false);
+ }
+
+ private void checkAdditionalTrust(X509Certificate[] chain, String authType,
+ Socket socket, boolean isClient) throws CertificateException {
+ if (socket != null && socket.isConnected() &&
+ socket instanceof SSLSocket) {
+
+ SSLSocket sslSocket = (SSLSocket)socket;
+ SSLSession session = sslSocket.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("No handshake session");
+ }
+
+ // check endpoint identity
+ String identityAlg = sslSocket.getSSLParameters().
+ getEndpointIdentificationAlgorithm();
+ if (identityAlg != null && identityAlg.length() != 0) {
+ String hostname = session.getPeerHost();
+ X509TrustManagerImpl.checkIdentity(
+ hostname, chain[0], identityAlg);
+ }
+
+ // try the best to check the algorithm constraints
+ ProtocolVersion protocolVersion =
+ ProtocolVersion.valueOf(session.getProtocol());
+ AlgorithmConstraints constraints = null;
+ if (protocolVersion.useTLS12PlusSpec()) {
+ if (session instanceof ExtendedSSLSession) {
+ ExtendedSSLSession extSession =
+ (ExtendedSSLSession)session;
+ String[] peerSupportedSignAlgs =
+ extSession.getLocalSupportedSignatureAlgorithms();
+
+ constraints = new SSLAlgorithmConstraints(
+ sslSocket, peerSupportedSignAlgs, true);
+ } else {
+ constraints =
+ new SSLAlgorithmConstraints(sslSocket, true);
+ }
+ } else {
+ constraints = new SSLAlgorithmConstraints(sslSocket, true);
+ }
+
+ checkAlgorithmConstraints(chain, constraints, isClient);
+ }
+ }
+
+ private void checkAdditionalTrust(X509Certificate[] chain, String authType,
+ SSLEngine engine, boolean isClient) throws CertificateException {
+ if (engine != null) {
+ SSLSession session = engine.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("No handshake session");
+ }
+
+ // check endpoint identity
+ String identityAlg = engine.getSSLParameters().
+ getEndpointIdentificationAlgorithm();
+ if (identityAlg != null && identityAlg.length() != 0) {
+ String hostname = session.getPeerHost();
+ X509TrustManagerImpl.checkIdentity(
+ hostname, chain[0], identityAlg);
+ }
+
+ // try the best to check the algorithm constraints
+ ProtocolVersion protocolVersion =
+ ProtocolVersion.valueOf(session.getProtocol());
+ AlgorithmConstraints constraints = null;
+ if (protocolVersion.useTLS12PlusSpec()) {
+ if (session instanceof ExtendedSSLSession) {
+ ExtendedSSLSession extSession =
+ (ExtendedSSLSession)session;
+ String[] peerSupportedSignAlgs =
+ extSession.getLocalSupportedSignatureAlgorithms();
+
+ constraints = new SSLAlgorithmConstraints(
+ engine, peerSupportedSignAlgs, true);
+ } else {
+ constraints =
+ new SSLAlgorithmConstraints(engine, true);
+ }
+ } else {
+ constraints = new SSLAlgorithmConstraints(engine, true);
+ }
+
+ checkAlgorithmConstraints(chain, constraints, isClient);
+ }
+ }
+
+ private void checkAlgorithmConstraints(X509Certificate[] chain,
+ AlgorithmConstraints constraints, boolean isClient) throws CertificateException {
+
+ try {
+ // Does the certificate chain end with a trusted certificate?
+ int checkedLength = chain.length - 1;
+
+ Collection<X509Certificate> trustedCerts = new HashSet<>();
+ X509Certificate[] certs = tm.getAcceptedIssuers();
+ if ((certs != null) && (certs.length > 0)){
+ Collections.addAll(trustedCerts, certs);
+ }
+
+ if (trustedCerts.contains(chain[checkedLength])) {
+ checkedLength--;
+ }
+
+ // A forward checker, need to check from trust to target
+ if (checkedLength >= 0) {
+ AlgorithmChecker checker =
+ new AlgorithmChecker(constraints, null,
+ (isClient ? Validator.VAR_TLS_CLIENT : Validator.VAR_TLS_SERVER));
+ checker.init(false);
+ for (int i = checkedLength; i >= 0; i--) {
+ Certificate cert = chain[i];
+ // We don't care about the unresolved critical extensions.
+ checker.check(cert, Collections.<String>emptySet());
+ }
+ }
+ } catch (CertPathValidatorException cpve) {
+ throw new CertificateException(
+ "Certificates do not conform to algorithm constraints", cpve);
+ }
+ }
+}
+
+// Dummy X509TrustManager implementation, rejects all peer certificates.
+// Used if the application did not specify a proper X509TrustManager.
+final class DummyX509TrustManager extends X509ExtendedTrustManager
+ implements X509TrustManager {
+
+ static final X509TrustManager INSTANCE = new DummyX509TrustManager();
+
+ private DummyX509TrustManager() {
+ // empty
+ }
+
+ /*
+ * Given the partial or complete certificate chain
+ * provided by the peer, build a certificate path
+ * to a trusted root and return if it can be
+ * validated and is trusted for client SSL authentication.
+ * If not, it throws an exception.
+ */
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ throw new CertificateException(
+ "No X509TrustManager implementation avaiable");
+ }
+
+ /*
+ * Given the partial or complete certificate chain
+ * provided by the peer, build a certificate path
+ * to a trusted root and return if it can be
+ * validated and is trusted for server SSL authentication.
+ * If not, it throws an exception.
+ */
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ throw new CertificateException(
+ "No X509TrustManager implementation available");
+ }
+
+ /*
+ * Return an array of issuer certificates which are trusted
+ * for authenticating peers.
+ */
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType,
+ Socket socket) throws CertificateException {
+ throw new CertificateException(
+ "No X509TrustManager implementation available");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType,
+ Socket socket) throws CertificateException {
+ throw new CertificateException(
+ "No X509TrustManager implementation available");
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType,
+ SSLEngine engine) throws CertificateException {
+ throw new CertificateException(
+ "No X509TrustManager implementation available");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType,
+ SSLEngine engine) throws CertificateException {
+ throw new CertificateException(
+ "No X509TrustManager implementation available");
+ }
+}
+
+/*
+ * A wrapper class to turn a X509KeyManager into an X509ExtendedKeyManager
+ */
+final class AbstractKeyManagerWrapper extends X509ExtendedKeyManager {
+
+ private final X509KeyManager km;
+
+ AbstractKeyManagerWrapper(X509KeyManager km) {
+ this.km = km;
+ }
+
+ @Override
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ return km.getClientAliases(keyType, issuers);
+ }
+
+ @Override
+ public String chooseClientAlias(String[] keyType, Principal[] issuers,
+ Socket socket) {
+ return km.chooseClientAlias(keyType, issuers, socket);
+ }
+
+ @Override
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ return km.getServerAliases(keyType, issuers);
+ }
+
+ @Override
+ public String chooseServerAlias(String keyType, Principal[] issuers,
+ Socket socket) {
+ return km.chooseServerAlias(keyType, issuers, socket);
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ return km.getCertificateChain(alias);
+ }
+
+ @Override
+ public PrivateKey getPrivateKey(String alias) {
+ return km.getPrivateKey(alias);
+ }
+
+ // Inherit chooseEngineClientAlias() and chooseEngineServerAlias() from
+ // X509ExtendedKeymanager. It defines them to return null;
+}
+
+
+// Dummy X509KeyManager implementation, never returns any certificates/keys.
+// Used if the application did not specify a proper X509TrustManager.
+final class DummyX509KeyManager extends X509ExtendedKeyManager {
+
+ static final X509ExtendedKeyManager INSTANCE = new DummyX509KeyManager();
+
+ private DummyX509KeyManager() {
+ // empty
+ }
+
+ /*
+ * Get the matching aliases for authenticating the client side of a secure
+ * socket given the public key type and the list of
+ * certificate issuer authorities recognized by the peer (if any).
+ */
+ @Override
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ return null;
+ }
+
+ /*
+ * Choose an alias to authenticate the client side of a secure
+ * socket given the public key type and the list of
+ * certificate issuer authorities recognized by the peer (if any).
+ */
+ @Override
+ public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
+ Socket socket) {
+ return null;
+ }
+
+ /*
+ * Choose an alias to authenticate the client side of an
+ * engine given the public key type and the list of
+ * certificate issuer authorities recognized by the peer (if any).
+ */
+ @Override
+ public String chooseEngineClientAlias(
+ String[] keyTypes, Principal[] issuers, SSLEngine engine) {
+ return null;
+ }
+
+ /*
+ * Get the matching aliases for authenticating the server side of a secure
+ * socket given the public key type and the list of
+ * certificate issuer authorities recognized by the peer (if any).
+ */
+ @Override
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ return null;
+ }
+
+ /*
+ * Choose an alias to authenticate the server side of a secure
+ * socket given the public key type and the list of
+ * certificate issuer authorities recognized by the peer (if any).
+ */
+ @Override
+ public String chooseServerAlias(String keyType, Principal[] issuers,
+ Socket socket) {
+ return null;
+ }
+
+ /*
+ * Choose an alias to authenticate the server side of an engine
+ * given the public key type and the list of
+ * certificate issuer authorities recognized by the peer (if any).
+ */
+ @Override
+ public String chooseEngineServerAlias(
+ String keyType, Principal[] issuers, SSLEngine engine) {
+ return null;
+ }
+
+ /**
+ * Returns the certificate chain associated with the given alias.
+ *
+ * @param alias the alias name
+ *
+ * @return the certificate chain (ordered with the user's certificate first
+ * and the root certificate authority last)
+ */
+ @Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ return null;
+ }
+
+ /*
+ * Returns the key associated with the given alias, using the given
+ * password to recover it.
+ *
+ * @param alias the alias name
+ *
+ * @return the requested key
+ */
+ @Override
+ public PrivateKey getPrivateKey(String alias) {
+ return null;
+ }
+}