提交 0b9aea70 编写于 作者: I igerasim

8133070: Hot lock on BulkCipher.isAvailable

Reviewed-by: mullan
Contributed-by: xuelei.fan@oracle.com, kungu.mjh@alibaba-inc.com
上级 34174139
...@@ -1044,40 +1044,6 @@ final class CipherBox { ...@@ -1044,40 +1044,6 @@ final class CipherBox {
return nonce; return nonce;
} }
/*
* Is this cipher available?
*
* This method can only be called by CipherSuite.BulkCipher.isAvailable()
* to test the availability of a cipher suites. Please DON'T use it in
* other places, otherwise, the behavior may be unexpected because we may
* initialize AEAD cipher improperly in the method.
*/
Boolean isAvailable() {
// We won't know whether a cipher for a particular key size is
// available until the cipher is successfully initialized.
//
// We do not initialize AEAD cipher in the constructor. Need to
// initialize the cipher to ensure that the AEAD mode for a
// particular key size is supported.
if (cipherType == AEAD_CIPHER) {
try {
Authenticator authenticator =
new Authenticator(protocolVersion);
byte[] nonce = authenticator.sequenceNumber();
byte[] iv = Arrays.copyOf(fixedIv,
fixedIv.length + nonce.length);
System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length);
GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv);
cipher.init(mode, key, spec, random);
} catch (Exception e) {
return Boolean.FALSE;
}
} // Otherwise, we have initialized the cipher in the constructor.
return Boolean.TRUE;
}
/** /**
* Sanity check the length of a fragment before decryption. * Sanity check the length of a fragment before decryption.
* *
......
...@@ -75,12 +75,6 @@ final class CipherSuite implements Comparable<CipherSuite> { ...@@ -75,12 +75,6 @@ final class CipherSuite implements Comparable<CipherSuite> {
// minimum priority for default enabled CipherSuites // minimum priority for default enabled CipherSuites
final static int DEFAULT_SUITES_PRIORITY = 300; final static int DEFAULT_SUITES_PRIORITY = 300;
// Flag indicating if CipherSuite availability can change dynamically.
// This is the case when we rely on a JCE cipher implementation that
// may not be available in the installed JCE providers.
// It is true because we might not have an ECC implementation.
final static boolean DYNAMIC_AVAILABILITY = true;
private final static boolean ALLOW_ECC = Debug.getBooleanProperty private final static boolean ALLOW_ECC = Debug.getBooleanProperty
("com.sun.net.ssl.enableECC", true); ("com.sun.net.ssl.enableECC", true);
...@@ -186,9 +180,6 @@ final class CipherSuite implements Comparable<CipherSuite> { ...@@ -186,9 +180,6 @@ final class CipherSuite implements Comparable<CipherSuite> {
* Return whether this CipherSuite is available for use. A * Return whether this CipherSuite is available for use. A
* CipherSuite may be unavailable even if it is supported * CipherSuite may be unavailable even if it is supported
* (i.e. allowed == true) if the required JCE cipher is not installed. * (i.e. allowed == true) if the required JCE cipher is not installed.
* In some configuration, this situation may change over time, call
* CipherSuiteList.clearAvailableCache() before this method to obtain
* the most current status.
*/ */
boolean isAvailable() { boolean isAvailable() {
return allowed && keyExchange.isAvailable() && cipher.isAvailable(); return allowed && keyExchange.isAvailable() && cipher.isAvailable();
...@@ -404,10 +395,6 @@ final class CipherSuite implements Comparable<CipherSuite> { ...@@ -404,10 +395,6 @@ final class CipherSuite implements Comparable<CipherSuite> {
*/ */
final static class BulkCipher { final static class BulkCipher {
// Map BulkCipher -> Boolean(available)
private final static Map<BulkCipher,Boolean> availableCache =
new HashMap<>(8);
// descriptive name including key size, e.g. AES/128 // descriptive name including key size, e.g. AES/128
final String description; final String description;
...@@ -451,6 +438,9 @@ final class CipherSuite implements Comparable<CipherSuite> { ...@@ -451,6 +438,9 @@ final class CipherSuite implements Comparable<CipherSuite> {
// The secure random used to detect the cipher availability. // The secure random used to detect the cipher availability.
private final static SecureRandom secureRandom; private final static SecureRandom secureRandom;
// runtime availability
private final boolean isAvailable;
static { static {
try { try {
secureRandom = JsseJce.getSecureRandom(); secureRandom = JsseJce.getSecureRandom();
...@@ -475,6 +465,17 @@ final class CipherSuite implements Comparable<CipherSuite> { ...@@ -475,6 +465,17 @@ final class CipherSuite implements Comparable<CipherSuite> {
this.expandedKeySize = expandedKeySize; this.expandedKeySize = expandedKeySize;
this.exportable = true; this.exportable = true;
// availability of this bulk cipher
//
// Currently all supported ciphers except AES are always available
// via the JSSE internal implementations. We also assume AES/128 of
// CBC mode is always available since it is shipped with the SunJCE
// provider. However, AES/256 is unavailable when the default JCE
// policy jurisdiction files are installed because of key length
// restrictions.
this.isAvailable =
allowed ? isUnlimited(keySize, transformation) : false;
} }
BulkCipher(String transformation, CipherType cipherType, int keySize, BulkCipher(String transformation, CipherType cipherType, int keySize,
...@@ -491,6 +492,17 @@ final class CipherSuite implements Comparable<CipherSuite> { ...@@ -491,6 +492,17 @@ final class CipherSuite implements Comparable<CipherSuite> {
this.expandedKeySize = keySize; this.expandedKeySize = keySize;
this.exportable = false; this.exportable = false;
// availability of this bulk cipher
//
// Currently all supported ciphers except AES are always available
// via the JSSE internal implementations. We also assume AES/128 of
// CBC mode is always available since it is shipped with the SunJCE
// provider. However, AES/256 is unavailable when the default JCE
// policy jurisdiction files are installed because of key length
// restrictions.
this.isAvailable =
allowed ? isUnlimited(keySize, transformation) : false;
} }
/** /**
...@@ -508,84 +520,27 @@ final class CipherSuite implements Comparable<CipherSuite> { ...@@ -508,84 +520,27 @@ final class CipherSuite implements Comparable<CipherSuite> {
/** /**
* Test if this bulk cipher is available. For use by CipherSuite. * Test if this bulk cipher is available. For use by CipherSuite.
*
* Currently all supported ciphers except AES are always available
* via the JSSE internal implementations. We also assume AES/128 of
* CBC mode is always available since it is shipped with the SunJCE
* provider. However, AES/256 is unavailable when the default JCE
* policy jurisdiction files are installed because of key length
* restrictions, and AEAD is unavailable when the underlying providers
* do not support AEAD/GCM mode.
*/ */
boolean isAvailable() { boolean isAvailable() {
if (allowed == false) { return this.isAvailable;
return false;
}
if ((this == B_AES_256) ||
(this.cipherType == CipherType.AEAD_CIPHER)) {
return isAvailable(this);
}
// always available
return true;
} }
// for use by CipherSuiteList.clearAvailableCache(); private static boolean isUnlimited(int keySize, String transformation) {
static synchronized void clearAvailableCache() { int keySizeInBits = keySize * 8;
if (DYNAMIC_AVAILABILITY) { if (keySizeInBits > 128) { // need the JCE unlimited
availableCache.clear(); // strength jurisdiction policy
} try {
} if (Cipher.getMaxAllowedKeyLength(
transformation) < keySizeInBits) {
private static synchronized boolean isAvailable(BulkCipher cipher) { return false;
Boolean b = availableCache.get(cipher);
if (b == null) {
int keySizeInBits = cipher.keySize * 8;
if (keySizeInBits > 128) { // need the JCE unlimited
// strength jurisdiction policy
try {
if (Cipher.getMaxAllowedKeyLength(
cipher.transformation) < keySizeInBits) {
b = Boolean.FALSE;
}
} catch (Exception e) {
b = Boolean.FALSE;
} }
} catch (Exception e) {
return false;
} }
if (b == null) {
b = Boolean.FALSE; // may be reset to TRUE if
// the cipher is available
CipherBox temporary = null;
try {
SecretKey key = new SecretKeySpec(
new byte[cipher.expandedKeySize],
cipher.algorithm);
IvParameterSpec iv;
if (cipher.cipherType == CipherType.AEAD_CIPHER) {
iv = new IvParameterSpec(
new byte[cipher.fixedIvSize]);
} else {
iv = new IvParameterSpec(new byte[cipher.ivSize]);
}
temporary = cipher.newCipher(
ProtocolVersion.DEFAULT,
key, iv, secureRandom, true);
b = temporary.isAvailable();
} catch (NoSuchAlgorithmException e) {
// not available
} finally {
if (temporary != null) {
temporary.dispose();
}
}
}
availableCache.put(cipher, b);
} }
return b.booleanValue(); return true;
} }
@Override @Override
......
/* /*
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2015, 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
...@@ -74,24 +74,12 @@ final class CipherSuiteList { ...@@ -74,24 +74,12 @@ final class CipherSuiteList {
throw new IllegalArgumentException("CipherSuites may not be null"); throw new IllegalArgumentException("CipherSuites may not be null");
} }
cipherSuites = new ArrayList<CipherSuite>(names.length); cipherSuites = new ArrayList<CipherSuite>(names.length);
// refresh available cache once if a CipherSuite is not available
// (maybe new JCE providers have been installed)
boolean refreshed = false;
for (int i = 0; i < names.length; i++) { for (int i = 0; i < names.length; i++) {
String suiteName = names[i]; String suiteName = names[i];
CipherSuite suite = CipherSuite.valueOf(suiteName); CipherSuite suite = CipherSuite.valueOf(suiteName);
if (suite.isAvailable() == false) { if (suite.isAvailable() == false) {
if (refreshed == false) { throw new IllegalArgumentException("Cannot support "
// clear the cache so that the isAvailable() call below + suiteName + " with currently installed providers");
// does a full check
clearAvailableCache();
refreshed = true;
}
// still missing?
if (suite.isAvailable() == false) {
throw new IllegalArgumentException("Cannot support "
+ suiteName + " with currently installed providers");
}
} }
cipherSuites.add(suite); cipherSuites.add(suite);
} }
...@@ -195,16 +183,4 @@ final class CipherSuiteList { ...@@ -195,16 +183,4 @@ final class CipherSuiteList {
} }
s.putBytes16(suiteBytes); s.putBytes16(suiteBytes);
} }
/**
* Clear cache of available ciphersuites. If we support all ciphers
* internally, there is no need to clear the cache and calling this
* method has no effect.
*/
static synchronized void clearAvailableCache() {
if (CipherSuite.DYNAMIC_AVAILABILITY) {
CipherSuite.BulkCipher.clearAvailableCache();
JsseJce.clearEcAvailable();
}
}
} }
...@@ -55,11 +55,6 @@ final class JsseJce { ...@@ -55,11 +55,6 @@ final class JsseJce {
private final static ProviderList fipsProviderList; private final static ProviderList fipsProviderList;
// Flag indicating whether EC crypto is available.
// If null, then we have not checked yet.
// If yes, then all the EC based crypto we need is available.
private static Boolean ecAvailable;
// Flag indicating whether Kerberos crypto is available. // Flag indicating whether Kerberos crypto is available.
// If true, then all the Kerberos-based crypto we need is available. // If true, then all the Kerberos-based crypto we need is available.
private final static boolean kerberosAvailable; private final static boolean kerberosAvailable;
...@@ -195,24 +190,8 @@ final class JsseJce { ...@@ -195,24 +190,8 @@ final class JsseJce {
// no instantiation of this class // no instantiation of this class
} }
synchronized static boolean isEcAvailable() { static boolean isEcAvailable() {
if (ecAvailable == null) { return EcAvailability.isAvailable;
try {
JsseJce.getSignature(SIGNATURE_ECDSA);
JsseJce.getSignature(SIGNATURE_RAWECDSA);
JsseJce.getKeyAgreement("ECDH");
JsseJce.getKeyFactory("EC");
JsseJce.getKeyPairGenerator("EC");
ecAvailable = true;
} catch (Exception e) {
ecAvailable = false;
}
}
return ecAvailable;
}
synchronized static void clearEcAvailable() {
ecAvailable = null;
} }
static boolean isKerberosAvailable() { static boolean isKerberosAvailable() {
...@@ -414,4 +393,27 @@ final class JsseJce { ...@@ -414,4 +393,27 @@ final class JsseJce {
} }
} }
// lazy initialization holder class idiom for static default parameters
//
// See Effective Java Second Edition: Item 71.
private static class EcAvailability {
// Is EC crypto available?
private final static boolean isAvailable;
static {
boolean mediator = true;
try {
JsseJce.getSignature(SIGNATURE_ECDSA);
JsseJce.getSignature(SIGNATURE_RAWECDSA);
JsseJce.getKeyAgreement("ECDH");
JsseJce.getKeyFactory("EC");
JsseJce.getKeyPairGenerator("EC");
} catch (Exception e) {
mediator = false;
}
isAvailable = mediator;
}
}
} }
/* /*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2015, 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
...@@ -52,16 +52,6 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -52,16 +52,6 @@ public abstract class SSLContextImpl extends SSLContextSpi {
private X509TrustManager trustManager; private X509TrustManager trustManager;
private SecureRandom secureRandom; private SecureRandom secureRandom;
// supported and default protocols
private ProtocolList defaultServerProtocolList;
private ProtocolList defaultClientProtocolList;
private ProtocolList supportedProtocolList;
// supported and default cipher suites
private CipherSuiteList defaultServerCipherSuiteList;
private CipherSuiteList defaultClientCipherSuiteList;
private CipherSuiteList supportedCipherSuiteList;
SSLContextImpl() { SSLContextImpl() {
ephemeralKeyManager = new EphemeralKeyManager(); ephemeralKeyManager = new EphemeralKeyManager();
clientCache = new SSLSessionContextImpl(); clientCache = new SSLSessionContextImpl();
...@@ -191,6 +181,8 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -191,6 +181,8 @@ public abstract class SSLContextImpl extends SSLContextSpi {
} }
return new SSLServerSocketFactoryImpl(this); return new SSLServerSocketFactoryImpl(this);
} }
abstract SSLEngine createSSLEngineImpl();
abstract SSLEngine createSSLEngineImpl(String host, int port);
@Override @Override
protected SSLEngine engineCreateSSLEngine() { protected SSLEngine engineCreateSSLEngine() {
...@@ -198,7 +190,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -198,7 +190,7 @@ public abstract class SSLContextImpl extends SSLContextSpi {
throw new IllegalStateException( throw new IllegalStateException(
"SSLContextImpl is not initialized"); "SSLContextImpl is not initialized");
} }
return new SSLEngineImpl(this); return createSSLEngineImpl();
} }
@Override @Override
...@@ -207,7 +199,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -207,7 +199,7 @@ public abstract class SSLContextImpl extends SSLContextSpi {
throw new IllegalStateException( throw new IllegalStateException(
"SSLContextImpl is not initialized"); "SSLContextImpl is not initialized");
} }
return new SSLEngineImpl(this, host, port); return createSSLEngineImpl(host, port);
} }
@Override @Override
...@@ -236,78 +228,35 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -236,78 +228,35 @@ public abstract class SSLContextImpl extends SSLContextSpi {
return ephemeralKeyManager; return ephemeralKeyManager;
} }
abstract SSLParameters getDefaultServerSSLParams();
abstract SSLParameters getDefaultClientSSLParams();
abstract SSLParameters getSupportedSSLParams();
// Get supported ProtocolList. // Get supported ProtocolList.
ProtocolList getSuportedProtocolList() { abstract ProtocolList getSuportedProtocolList();
if (supportedProtocolList == null) {
supportedProtocolList =
new ProtocolList(getSupportedSSLParams().getProtocols());
}
return supportedProtocolList; // Get default ProtocolList for server mode.
} abstract ProtocolList getServerDefaultProtocolList();
// Get default ProtocolList. // Get default ProtocolList for client mode.
ProtocolList getDefaultProtocolList(boolean roleIsServer) { abstract ProtocolList getClientDefaultProtocolList();
if (roleIsServer) {
if (defaultServerProtocolList == null) {
defaultServerProtocolList = new ProtocolList(
getDefaultServerSSLParams().getProtocols());
}
return defaultServerProtocolList; // Get supported CipherSuiteList.
} else { abstract CipherSuiteList getSupportedCipherSuiteList();
if (defaultClientProtocolList == null) {
defaultClientProtocolList = new ProtocolList(
getDefaultClientSSLParams().getProtocols());
}
return defaultClientProtocolList; // Get default CipherSuiteList for server mode.
} abstract CipherSuiteList getServerDefaultCipherSuiteList();
}
// Get supported CipherSuiteList. // Get default CipherSuiteList for client mode.
CipherSuiteList getSupportedCipherSuiteList() { abstract CipherSuiteList getClientDefaultCipherSuiteList();
// The maintenance of cipher suites needs to be synchronized.
synchronized (this) {
// Clear cache of available ciphersuites.
clearAvailableCache();
if (supportedCipherSuiteList == null) {
supportedCipherSuiteList = getApplicableCipherSuiteList(
getSuportedProtocolList(), false);
}
return supportedCipherSuiteList; // Get default ProtocolList.
} ProtocolList getDefaultProtocolList(boolean roleIsServer) {
return roleIsServer ? getServerDefaultProtocolList()
: getClientDefaultProtocolList();
} }
// Get default CipherSuiteList. // Get default CipherSuiteList.
CipherSuiteList getDefaultCipherSuiteList(boolean roleIsServer) { CipherSuiteList getDefaultCipherSuiteList(boolean roleIsServer) {
// The maintenance of cipher suites needs to be synchronized. return roleIsServer ? getServerDefaultCipherSuiteList()
synchronized (this) { : getClientDefaultCipherSuiteList();
// Clear cache of available ciphersuites.
clearAvailableCache();
if (roleIsServer) {
if (defaultServerCipherSuiteList == null) {
defaultServerCipherSuiteList = getApplicableCipherSuiteList(
getDefaultProtocolList(true), true);
}
return defaultServerCipherSuiteList;
} else {
if (defaultClientCipherSuiteList == null) {
defaultClientCipherSuiteList = getApplicableCipherSuiteList(
getDefaultProtocolList(false), true);
}
return defaultClientCipherSuiteList;
}
}
} }
/** /**
...@@ -315,16 +264,24 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -315,16 +264,24 @@ public abstract class SSLContextImpl extends SSLContextSpi {
* protocols. See: SSLSocket/SSLEngine.setEnabledProtocols() * protocols. See: SSLSocket/SSLEngine.setEnabledProtocols()
*/ */
boolean isDefaultProtocolList(ProtocolList protocols) { boolean isDefaultProtocolList(ProtocolList protocols) {
return (protocols == defaultServerProtocolList) || return (protocols == getServerDefaultProtocolList()) ||
(protocols == defaultClientProtocolList); (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 the list of all available CipherSuites with a priority of * Return the list of all available CipherSuites with a priority of
* minPriority or above. * minPriority or above.
*/ */
private CipherSuiteList getApplicableCipherSuiteList( private static CipherSuiteList getApplicableCipherSuiteList(
ProtocolList protocols, boolean onlyEnabled) { ProtocolList protocols, boolean onlyEnabled) {
int minPriority = CipherSuite.SUPPORTED_SUITES_PRIORITY; int minPriority = CipherSuite.SUPPORTED_SUITES_PRIORITY;
...@@ -370,22 +327,20 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -370,22 +327,20 @@ public abstract class SSLContextImpl extends SSLContextSpi {
return new CipherSuiteList(suites); return new CipherSuiteList(suites);
} }
/** private static String[] getAvailableProtocols(
* Clear cache of available ciphersuites. If we support all ciphers ProtocolVersion[] protocolCandidates) {
* internally, there is no need to clear the cache and calling this
* method has no effect. List<String> availableProtocols = Collections.<String>emptyList();
* if (protocolCandidates != null && protocolCandidates.length != 0) {
* Note that every call to clearAvailableCache() and the maintenance of availableProtocols = new ArrayList<>(protocolCandidates.length);
* cipher suites need to be synchronized with this instance. for (ProtocolVersion p : protocolCandidates) {
*/ if (ProtocolVersion.availableProtocols.contains(p)) {
private void clearAvailableCache() { availableProtocols.add(p.name);
if (CipherSuite.DYNAMIC_AVAILABILITY) { }
supportedCipherSuiteList = null; }
defaultServerCipherSuiteList = null;
defaultClientCipherSuiteList = null;
CipherSuite.BulkCipher.clearAvailableCache();
JsseJce.clearEcAvailable();
} }
return availableProtocols.toArray(new String[0]);
} }
/* /*
...@@ -418,39 +373,37 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -418,39 +373,37 @@ public abstract class SSLContextImpl extends SSLContextSpi {
*/ */
/* /*
* The base abstract SSLContext implementation. * The base abstract SSLContext implementation for the Transport Layer
* Security (TLS) protocols.
* *
* This abstract class encapsulates supported and the default server * This abstract class encapsulates supported and the default server
* SSL parameters. * SSL/TLS parameters.
* *
* @see SSLContext * @see SSLContext
*/ */
private abstract static class AbstractSSLContext extends SSLContextImpl { private abstract static class AbstractTLSContext extends SSLContextImpl {
// parameters private static final ProtocolList supportedProtocolList;
private static final SSLParameters defaultServerSSLParams; private static final ProtocolList serverDefaultProtocolList;
private static final SSLParameters supportedSSLParams;
static {
// supported SSL parameters
supportedSSLParams = new SSLParameters();
// candidates for available protocols private static final CipherSuiteList supportedCipherSuiteList;
ProtocolVersion[] candidates; private static final CipherSuiteList serverDefaultCipherSuiteList;
static {
if (SunJSSE.isFIPS()) { if (SunJSSE.isFIPS()) {
supportedSSLParams.setProtocols(new String[] { supportedProtocolList = new ProtocolList(new String[] {
ProtocolVersion.TLS10.name, ProtocolVersion.TLS10.name,
ProtocolVersion.TLS11.name, ProtocolVersion.TLS11.name,
ProtocolVersion.TLS12.name ProtocolVersion.TLS12.name
}); });
candidates = new ProtocolVersion[] { serverDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.TLS10, ProtocolVersion.TLS10,
ProtocolVersion.TLS11, ProtocolVersion.TLS11,
ProtocolVersion.TLS12 ProtocolVersion.TLS12
}; }));
} else { } else {
supportedSSLParams.setProtocols(new String[] { supportedProtocolList = new ProtocolList(new String[] {
ProtocolVersion.SSL20Hello.name, ProtocolVersion.SSL20Hello.name,
ProtocolVersion.SSL30.name, ProtocolVersion.SSL30.name,
ProtocolVersion.TLS10.name, ProtocolVersion.TLS10.name,
...@@ -458,44 +411,50 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -458,44 +411,50 @@ public abstract class SSLContextImpl extends SSLContextSpi {
ProtocolVersion.TLS12.name ProtocolVersion.TLS12.name
}); });
candidates = new ProtocolVersion[] { serverDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.SSL20Hello, ProtocolVersion.SSL20Hello,
ProtocolVersion.SSL30, ProtocolVersion.SSL30,
ProtocolVersion.TLS10, ProtocolVersion.TLS10,
ProtocolVersion.TLS11, ProtocolVersion.TLS11,
ProtocolVersion.TLS12 ProtocolVersion.TLS12
}; }));
} }
defaultServerSSLParams = new SSLParameters(); supportedCipherSuiteList = getApplicableCipherSuiteList(
defaultServerSSLParams.setProtocols( supportedProtocolList, false); // all supported
getAvailableProtocols(candidates).toArray(new String[0])); serverDefaultCipherSuiteList = getApplicableCipherSuiteList(
serverDefaultProtocolList, true); // enabled only
} }
@Override @Override
SSLParameters getDefaultServerSSLParams() { ProtocolList getSuportedProtocolList() {
return defaultServerSSLParams; return supportedProtocolList;
} }
@Override @Override
SSLParameters getSupportedSSLParams() { CipherSuiteList getSupportedCipherSuiteList() {
return supportedSSLParams; return supportedCipherSuiteList;
} }
static List<String> getAvailableProtocols( @Override
ProtocolVersion[] protocolCandidates) { ProtocolList getServerDefaultProtocolList() {
return serverDefaultProtocolList;
}
List<String> availableProtocols = Collections.<String>emptyList(); @Override
if (protocolCandidates != null && protocolCandidates.length != 0) { CipherSuiteList getServerDefaultCipherSuiteList() {
availableProtocols = new ArrayList<>(protocolCandidates.length); return serverDefaultCipherSuiteList;
for (ProtocolVersion p : protocolCandidates) { }
if (ProtocolVersion.availableProtocols.contains(p)) {
availableProtocols.add(p.name);
}
}
}
return availableProtocols; @Override
SSLEngine createSSLEngineImpl() {
return new SSLEngineImpl(this);
}
@Override
SSLEngine createSSLEngineImpl(String host, int port) {
return new SSLEngineImpl(this, host, port);
} }
} }
...@@ -504,31 +463,36 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -504,31 +463,36 @@ public abstract class SSLContextImpl extends SSLContextSpi {
* *
* @see SSLContext * @see SSLContext
*/ */
public static final class TLS10Context extends AbstractSSLContext { public static final class TLS10Context extends AbstractTLSContext {
private static final SSLParameters defaultClientSSLParams; private static final ProtocolList clientDefaultProtocolList;
private static final CipherSuiteList clientDefaultCipherSuiteList;
static { static {
// candidates for available protocols
ProtocolVersion[] candidates;
if (SunJSSE.isFIPS()) { if (SunJSSE.isFIPS()) {
candidates = new ProtocolVersion[] { clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.TLS10 ProtocolVersion.TLS10
}; }));
} else { } else {
candidates = new ProtocolVersion[] { clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.SSL30, ProtocolVersion.SSL30,
ProtocolVersion.TLS10 ProtocolVersion.TLS10
}; }));
} }
defaultClientSSLParams = new SSLParameters(); clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
defaultClientSSLParams.setProtocols( clientDefaultProtocolList, true); // enabled only
getAvailableProtocols(candidates).toArray(new String[0])); }
@Override
ProtocolList getClientDefaultProtocolList() {
return clientDefaultProtocolList;
} }
@Override @Override
SSLParameters getDefaultClientSSLParams() { CipherSuiteList getClientDefaultCipherSuiteList() {
return defaultClientSSLParams; return clientDefaultCipherSuiteList;
} }
} }
...@@ -537,33 +501,38 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -537,33 +501,38 @@ public abstract class SSLContextImpl extends SSLContextSpi {
* *
* @see SSLContext * @see SSLContext
*/ */
public static final class TLS11Context extends AbstractSSLContext { public static final class TLS11Context extends AbstractTLSContext {
private static final SSLParameters defaultClientSSLParams; private static final ProtocolList clientDefaultProtocolList;
private static final CipherSuiteList clientDefaultCipherSuiteList;
static { static {
// candidates for available protocols
ProtocolVersion[] candidates;
if (SunJSSE.isFIPS()) { if (SunJSSE.isFIPS()) {
candidates = new ProtocolVersion[] { clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.TLS10, ProtocolVersion.TLS10,
ProtocolVersion.TLS11 ProtocolVersion.TLS11
}; }));
} else { } else {
candidates = new ProtocolVersion[] { clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.SSL30, ProtocolVersion.SSL30,
ProtocolVersion.TLS10, ProtocolVersion.TLS10,
ProtocolVersion.TLS11 ProtocolVersion.TLS11
}; }));
} }
defaultClientSSLParams = new SSLParameters(); clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
defaultClientSSLParams.setProtocols( clientDefaultProtocolList, true); // enabled only
getAvailableProtocols(candidates).toArray(new String[0]));
} }
@Override @Override
SSLParameters getDefaultClientSSLParams() { ProtocolList getClientDefaultProtocolList() {
return defaultClientSSLParams; return clientDefaultProtocolList;
}
@Override
CipherSuiteList getClientDefaultCipherSuiteList() {
return clientDefaultCipherSuiteList;
} }
} }
...@@ -572,135 +541,182 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -572,135 +541,182 @@ public abstract class SSLContextImpl extends SSLContextSpi {
* *
* @see SSLContext * @see SSLContext
*/ */
public static final class TLS12Context extends AbstractSSLContext { public static final class TLS12Context extends AbstractTLSContext {
private static final SSLParameters defaultClientSSLParams; private static final ProtocolList clientDefaultProtocolList;
private static final CipherSuiteList clientDefaultCipherSuiteList;
static { static {
// candidates for available protocols
ProtocolVersion[] candidates;
if (SunJSSE.isFIPS()) { if (SunJSSE.isFIPS()) {
candidates = new ProtocolVersion[] { clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.TLS10, ProtocolVersion.TLS10,
ProtocolVersion.TLS11, ProtocolVersion.TLS11,
ProtocolVersion.TLS12 ProtocolVersion.TLS12
}; }));
} else { } else {
candidates = new ProtocolVersion[] { clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.SSL30, ProtocolVersion.SSL30,
ProtocolVersion.TLS10, ProtocolVersion.TLS10,
ProtocolVersion.TLS11, ProtocolVersion.TLS11,
ProtocolVersion.TLS12 ProtocolVersion.TLS12
}; }));
} }
defaultClientSSLParams = new SSLParameters(); clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
defaultClientSSLParams.setProtocols( clientDefaultProtocolList, true); // enabled only
getAvailableProtocols(candidates).toArray(new String[0])); }
@Override
ProtocolList getClientDefaultProtocolList() {
return clientDefaultProtocolList;
} }
@Override @Override
SSLParameters getDefaultClientSSLParams() { CipherSuiteList getClientDefaultCipherSuiteList() {
return defaultClientSSLParams; return clientDefaultCipherSuiteList;
} }
} }
/* /*
* The SSLContext implementation for customized TLS protocols * The interface for the customized SSL/(D)TLS SSLContext.
* *
* @see SSLContext * @see SSLContext
*/ */
private static class CustomizedSSLContext extends AbstractSSLContext { private static class CustomizedSSLProtocols {
private static final String PROPERTY_NAME = "jdk.tls.client.protocols"; private static final String PROPERTY_NAME = "jdk.tls.client.protocols";
private static final SSLParameters defaultClientSSLParams; static IllegalArgumentException reservedException = null;
private static IllegalArgumentException reservedException = null; static ArrayList<ProtocolVersion>
customizedProtocols = new ArrayList<>();
// Don't want a java.lang.LinkageError for illegal system property. // Don't want a java.lang.LinkageError for illegal system property.
// //
// Please don't throw exception in this static block. Otherwise, // Please don't throw exception in this static block. Otherwise,
// java.lang.LinkageError may be thrown during the instantiation of // java.lang.LinkageError may be thrown during the instantiation of
// the provider service. Instead, let's handle the initialization // the provider service. Instead, please handle the initialization
// exception in constructor. // exception in the caller's constructor.
static { static {
// candidates for available protocols
ProtocolVersion[] candidates;
String property = AccessController.doPrivileged( String property = AccessController.doPrivileged(
new GetPropertyAction(PROPERTY_NAME)); new GetPropertyAction(PROPERTY_NAME));
if (property == null || property.length() == 0) { if (property != null && property.length() != 0) {
// the default enabled client 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 {
// remove double quote marks from beginning/end of the property // remove double quote marks from beginning/end of the property
if (property.length() > 1 && property.charAt(0) == '"' && if (property.length() > 1 && property.charAt(0) == '"' &&
property.charAt(property.length() - 1) == '"') { property.charAt(property.length() - 1) == '"') {
property = property.substring(1, property.length() - 1); property = property.substring(1, property.length() - 1);
} }
}
String[] protocols = null; if (property != null && property.length() != 0) {
if (property != null && property.length() != 0) { String[] protocols = property.split(",");
protocols = property.split(",");
} else {
reservedException = new IllegalArgumentException(
"No protocol specified in " +
PROPERTY_NAME + " system property");
protocols = new String[0];
}
candidates = new ProtocolVersion[protocols.length];
for (int i = 0; i < protocols.length; i++) { for (int i = 0; i < protocols.length; i++) {
protocols[i] = protocols[i].trim(); protocols[i] = protocols[i].trim();
// Is it a supported protocol name? // Is it a supported protocol name?
try { try {
candidates[i] = ProtocolVersion.valueOf(protocols[i]); ProtocolVersion pro =
} catch (IllegalArgumentException iae) { ProtocolVersion.valueOf(protocols[i]);
reservedException = new IllegalArgumentException(
PROPERTY_NAME + ": " + protocols[i] +
" is not a standard SSL/TLS protocol name", iae);
break;
}
}
if ((reservedException == null) && SunJSSE.isFIPS()) { if (SunJSSE.isFIPS() &&
for (ProtocolVersion protocolVersion : candidates) { ((pro.v == ProtocolVersion.SSL30.v) ||
if (ProtocolVersion.SSL20Hello.v == protocolVersion.v || (pro.v == ProtocolVersion.SSL20Hello.v))) {
ProtocolVersion.SSL30.v == protocolVersion.v) {
reservedException = new IllegalArgumentException( reservedException = new IllegalArgumentException(
PROPERTY_NAME + ": " + protocolVersion + PROPERTY_NAME + ": " + pro +
" is not FIPS compliant"); " 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);
} }
} }
} }
}
}
defaultClientSSLParams = new SSLParameters(); /*
* 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) { if (reservedException == null) {
defaultClientSSLParams.setProtocols( ArrayList<ProtocolVersion>
getAvailableProtocols(candidates).toArray(new String[0])); customizedTLSProtocols = new ArrayList<>();
for (ProtocolVersion protocol :
CustomizedSSLProtocols.customizedProtocols) {
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 = getApplicableCipherSuiteList(
clientDefaultProtocolList, true); // enabled only
} else {
clientDefaultProtocolList = null; // unlikely to be used
clientDefaultCipherSuiteList = null; // unlikely to be used
} }
} }
protected CustomizedSSLContext() { protected CustomizedTLSContext() {
if (reservedException != null) { if (reservedException != null) {
throw reservedException; throw reservedException;
} }
} }
@Override @Override
SSLParameters getDefaultClientSSLParams() { ProtocolList getClientDefaultProtocolList() {
return defaultClientSSLParams; return clientDefaultProtocolList;
}
@Override
CipherSuiteList getClientDefaultCipherSuiteList() {
return clientDefaultCipherSuiteList;
} }
} }
...@@ -709,75 +725,57 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -709,75 +725,57 @@ public abstract class SSLContextImpl extends SSLContextSpi {
* *
* @see SSLContext * @see SSLContext
*/ */
public static final class TLSContext extends CustomizedSSLContext { public static final class TLSContext extends CustomizedTLSContext {
// use the default constructor and methods // use the default constructor and methods
} }
/* // lazy initialization holder class idiom for static default parameters
* The SSLContext implementation for default "Default" algorithm //
* // See Effective Java Second Edition: Item 71.
* @see SSLContext private static final class DefaultManagersHolder {
*/
public static final class DefaultSSLContext extends CustomizedSSLContext {
private static final String NONE = "NONE"; private static final String NONE = "NONE";
private static final String P11KEYSTORE = "PKCS11"; private static final String P11KEYSTORE = "PKCS11";
private static volatile SSLContextImpl defaultImpl; private static final TrustManager[] trustManagers;
private static final KeyManager[] keyManagers;
private static TrustManager[] defaultTrustManagers; static Exception reservedException = null;
private static KeyManager[] defaultKeyManagers;
public DefaultSSLContext() throws Exception { static {
TrustManager[] tmMediator;
try { try {
super.engineInit(getDefaultKeyManager(), tmMediator = getTrustManagers();
getDefaultTrustManager(), null);
} catch (Exception e) { } catch (Exception e) {
if (debug != null && Debug.isOn("defaultctx")) { reservedException = e;
System.out.println("default context init failed: " + e); tmMediator = new TrustManager[0];
}
throw e;
}
if (defaultImpl == null) {
defaultImpl = this;
} }
} trustManagers = tmMediator;
@Override if (reservedException == null) {
protected void engineInit(KeyManager[] km, TrustManager[] tm, KeyManager[] kmMediator;
SecureRandom sr) throws KeyManagementException { try {
throw new KeyManagementException kmMediator = getKeyManagers();
("Default SSLContext is initialized automatically"); } catch (Exception e) {
} reservedException = e;
kmMediator = new KeyManager[0];
static synchronized SSLContextImpl getDefaultImpl() throws Exception { }
if (defaultImpl == null) { keyManagers = kmMediator;
new DefaultSSLContext(); } else {
keyManagers = new KeyManager[0];
} }
return defaultImpl;
} }
private static synchronized TrustManager[] getDefaultTrustManager() private static TrustManager[] getTrustManagers() throws Exception {
throws Exception {
if (defaultTrustManagers != null) {
return defaultTrustManagers;
}
KeyStore ks = KeyStore ks =
TrustManagerFactoryImpl.getCacertsKeyStore("defaultctx"); TrustManagerFactoryImpl.getCacertsKeyStore("defaultctx");
TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()); TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks); tmf.init(ks);
defaultTrustManagers = tmf.getTrustManagers(); return tmf.getTrustManagers();
return defaultTrustManagers;
} }
private static synchronized KeyManager[] getDefaultKeyManager() private static KeyManager[] getKeyManagers() throws Exception {
throws Exception {
if (defaultKeyManagers != null) {
return defaultKeyManagers;
}
final Map<String,String> props = new HashMap<>(); final Map<String,String> props = new HashMap<>();
AccessController.doPrivileged( AccessController.doPrivileged(
...@@ -874,11 +872,75 @@ public abstract class SSLContextImpl extends SSLContextSpi { ...@@ -874,11 +872,75 @@ public abstract class SSLContextImpl extends SSLContextSpi {
kmf.init(ks, passwd); kmf.init(ks, passwd);
} }
defaultKeyManagers = kmf.getKeyManagers(); return kmf.getKeyManagers();
return defaultKeyManagers; }
}
// 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;
}
}
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册