提交 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 {
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.
*
......
......@@ -75,12 +75,6 @@ final class CipherSuite implements Comparable<CipherSuite> {
// minimum priority for default enabled CipherSuites
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
("com.sun.net.ssl.enableECC", true);
......@@ -186,9 +180,6 @@ final class CipherSuite implements Comparable<CipherSuite> {
* Return whether this CipherSuite is available for use. A
* CipherSuite may be unavailable even if it is supported
* (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() {
return allowed && keyExchange.isAvailable() && cipher.isAvailable();
......@@ -404,10 +395,6 @@ final class CipherSuite implements Comparable<CipherSuite> {
*/
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
final String description;
......@@ -451,6 +438,9 @@ final class CipherSuite implements Comparable<CipherSuite> {
// The secure random used to detect the cipher availability.
private final static SecureRandom secureRandom;
// runtime availability
private final boolean isAvailable;
static {
try {
secureRandom = JsseJce.getSecureRandom();
......@@ -475,6 +465,17 @@ final class CipherSuite implements Comparable<CipherSuite> {
this.expandedKeySize = expandedKeySize;
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,
......@@ -491,6 +492,17 @@ final class CipherSuite implements Comparable<CipherSuite> {
this.expandedKeySize = keySize;
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> {
/**
* 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() {
if (allowed == false) {
return false;
}
if ((this == B_AES_256) ||
(this.cipherType == CipherType.AEAD_CIPHER)) {
return isAvailable(this);
}
// always available
return true;
return this.isAvailable;
}
// for use by CipherSuiteList.clearAvailableCache();
static synchronized void clearAvailableCache() {
if (DYNAMIC_AVAILABILITY) {
availableCache.clear();
}
}
private static synchronized boolean isAvailable(BulkCipher cipher) {
Boolean b = availableCache.get(cipher);
if (b == null) {
int keySizeInBits = cipher.keySize * 8;
private static boolean isUnlimited(int keySize, String transformation) {
int keySizeInBits = 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;
}
}
transformation) < keySizeInBits) {
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();
}
return false;
}
} catch (Exception e) {
return false;
}
availableCache.put(cipher, b);
}
return b.booleanValue();
return true;
}
@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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -74,25 +74,13 @@ final class CipherSuiteList {
throw new IllegalArgumentException("CipherSuites may not be null");
}
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++) {
String suiteName = names[i];
CipherSuite suite = CipherSuite.valueOf(suiteName);
if (suite.isAvailable() == false) {
if (refreshed == false) {
// clear the cache so that the isAvailable() call below
// 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);
}
}
......@@ -195,16 +183,4 @@ final class CipherSuiteList {
}
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 {
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.
// If true, then all the Kerberos-based crypto we need is available.
private final static boolean kerberosAvailable;
......@@ -195,24 +190,8 @@ final class JsseJce {
// no instantiation of this class
}
synchronized static boolean isEcAvailable() {
if (ecAvailable == null) {
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 isEcAvailable() {
return EcAvailability.isAvailable;
}
static boolean isKerberosAvailable() {
......@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -52,16 +52,6 @@ public abstract class SSLContextImpl extends SSLContextSpi {
private X509TrustManager trustManager;
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() {
ephemeralKeyManager = new EphemeralKeyManager();
clientCache = new SSLSessionContextImpl();
......@@ -191,6 +181,8 @@ public abstract class SSLContextImpl extends SSLContextSpi {
}
return new SSLServerSocketFactoryImpl(this);
}
abstract SSLEngine createSSLEngineImpl();
abstract SSLEngine createSSLEngineImpl(String host, int port);
@Override
protected SSLEngine engineCreateSSLEngine() {
......@@ -198,7 +190,7 @@ public abstract class SSLContextImpl extends SSLContextSpi {
throw new IllegalStateException(
"SSLContextImpl is not initialized");
}
return new SSLEngineImpl(this);
return createSSLEngineImpl();
}
@Override
......@@ -207,7 +199,7 @@ public abstract class SSLContextImpl extends SSLContextSpi {
throw new IllegalStateException(
"SSLContextImpl is not initialized");
}
return new SSLEngineImpl(this, host, port);
return createSSLEngineImpl(host, port);
}
@Override
......@@ -236,78 +228,35 @@ public abstract class SSLContextImpl extends SSLContextSpi {
return ephemeralKeyManager;
}
abstract SSLParameters getDefaultServerSSLParams();
abstract SSLParameters getDefaultClientSSLParams();
abstract SSLParameters getSupportedSSLParams();
// Get supported ProtocolList.
ProtocolList getSuportedProtocolList() {
if (supportedProtocolList == null) {
supportedProtocolList =
new ProtocolList(getSupportedSSLParams().getProtocols());
}
abstract ProtocolList getSuportedProtocolList();
return supportedProtocolList;
}
// Get default ProtocolList for server mode.
abstract ProtocolList getServerDefaultProtocolList();
// Get default ProtocolList.
ProtocolList getDefaultProtocolList(boolean roleIsServer) {
if (roleIsServer) {
if (defaultServerProtocolList == null) {
defaultServerProtocolList = new ProtocolList(
getDefaultServerSSLParams().getProtocols());
}
return defaultServerProtocolList;
} else {
if (defaultClientProtocolList == null) {
defaultClientProtocolList = new ProtocolList(
getDefaultClientSSLParams().getProtocols());
}
return defaultClientProtocolList;
}
}
// Get default ProtocolList for client mode.
abstract ProtocolList getClientDefaultProtocolList();
// Get supported CipherSuiteList.
CipherSuiteList getSupportedCipherSuiteList() {
// The maintenance of cipher suites needs to be synchronized.
synchronized (this) {
// Clear cache of available ciphersuites.
clearAvailableCache();
abstract CipherSuiteList getSupportedCipherSuiteList();
if (supportedCipherSuiteList == null) {
supportedCipherSuiteList = getApplicableCipherSuiteList(
getSuportedProtocolList(), false);
}
// Get default CipherSuiteList for server mode.
abstract CipherSuiteList getServerDefaultCipherSuiteList();
return supportedCipherSuiteList;
}
// 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) {
// The maintenance of cipher suites needs to be synchronized.
synchronized (this) {
// 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;
}
}
return roleIsServer ? getServerDefaultCipherSuiteList()
: getClientDefaultCipherSuiteList();
}
/**
......@@ -315,16 +264,24 @@ public abstract class SSLContextImpl extends SSLContextSpi {
* protocols. See: SSLSocket/SSLEngine.setEnabledProtocols()
*/
boolean isDefaultProtocolList(ProtocolList protocols) {
return (protocols == defaultServerProtocolList) ||
(protocols == defaultClientProtocolList);
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 the list of all available CipherSuites with a priority of
* minPriority or above.
*/
private CipherSuiteList getApplicableCipherSuiteList(
private static CipherSuiteList getApplicableCipherSuiteList(
ProtocolList protocols, boolean onlyEnabled) {
int minPriority = CipherSuite.SUPPORTED_SUITES_PRIORITY;
......@@ -370,24 +327,22 @@ public abstract class SSLContextImpl extends SSLContextSpi {
return new CipherSuiteList(suites);
}
/**
* 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.
*
* Note that every call to clearAvailableCache() and the maintenance of
* cipher suites need to be synchronized with this instance.
*/
private void clearAvailableCache() {
if (CipherSuite.DYNAMIC_AVAILABILITY) {
supportedCipherSuiteList = null;
defaultServerCipherSuiteList = null;
defaultClientCipherSuiteList = null;
CipherSuite.BulkCipher.clearAvailableCache();
JsseJce.clearEcAvailable();
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 TLS/SSL algorithm
*
......@@ -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
* SSL parameters.
* SSL/TLS parameters.
*
* @see SSLContext
*/
private abstract static class AbstractSSLContext extends SSLContextImpl {
// parameters
private static final SSLParameters defaultServerSSLParams;
private static final SSLParameters supportedSSLParams;
static {
// supported SSL parameters
supportedSSLParams = new SSLParameters();
private abstract static class AbstractTLSContext extends SSLContextImpl {
private static final ProtocolList supportedProtocolList;
private static final ProtocolList serverDefaultProtocolList;
// candidates for available protocols
ProtocolVersion[] candidates;
private static final CipherSuiteList supportedCipherSuiteList;
private static final CipherSuiteList serverDefaultCipherSuiteList;
static {
if (SunJSSE.isFIPS()) {
supportedSSLParams.setProtocols(new String[] {
supportedProtocolList = new ProtocolList(new String[] {
ProtocolVersion.TLS10.name,
ProtocolVersion.TLS11.name,
ProtocolVersion.TLS12.name
});
candidates = new ProtocolVersion[] {
serverDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.TLS10,
ProtocolVersion.TLS11,
ProtocolVersion.TLS12
};
}));
} else {
supportedSSLParams.setProtocols(new String[] {
supportedProtocolList = new ProtocolList(new String[] {
ProtocolVersion.SSL20Hello.name,
ProtocolVersion.SSL30.name,
ProtocolVersion.TLS10.name,
......@@ -458,44 +411,50 @@ public abstract class SSLContextImpl extends SSLContextSpi {
ProtocolVersion.TLS12.name
});
candidates = new ProtocolVersion[] {
serverDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.SSL20Hello,
ProtocolVersion.SSL30,
ProtocolVersion.TLS10,
ProtocolVersion.TLS11,
ProtocolVersion.TLS12
};
}));
}
defaultServerSSLParams = new SSLParameters();
defaultServerSSLParams.setProtocols(
getAvailableProtocols(candidates).toArray(new String[0]));
supportedCipherSuiteList = getApplicableCipherSuiteList(
supportedProtocolList, false); // all supported
serverDefaultCipherSuiteList = getApplicableCipherSuiteList(
serverDefaultProtocolList, true); // enabled only
}
@Override
SSLParameters getDefaultServerSSLParams() {
return defaultServerSSLParams;
ProtocolList getSuportedProtocolList() {
return supportedProtocolList;
}
@Override
SSLParameters getSupportedSSLParams() {
return supportedSSLParams;
CipherSuiteList getSupportedCipherSuiteList() {
return supportedCipherSuiteList;
}
static List<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);
@Override
ProtocolList getServerDefaultProtocolList() {
return serverDefaultProtocolList;
}
@Override
CipherSuiteList getServerDefaultCipherSuiteList() {
return serverDefaultCipherSuiteList;
}
@Override
SSLEngine createSSLEngineImpl() {
return new SSLEngineImpl(this);
}
return availableProtocols;
@Override
SSLEngine createSSLEngineImpl(String host, int port) {
return new SSLEngineImpl(this, host, port);
}
}
......@@ -504,31 +463,36 @@ public abstract class SSLContextImpl extends SSLContextSpi {
*
* @see SSLContext
*/
public static final class TLS10Context extends AbstractSSLContext {
private static final SSLParameters defaultClientSSLParams;
public static final class TLS10Context extends AbstractTLSContext {
private static final ProtocolList clientDefaultProtocolList;
private static final CipherSuiteList clientDefaultCipherSuiteList;
static {
// candidates for available protocols
ProtocolVersion[] candidates;
if (SunJSSE.isFIPS()) {
candidates = new ProtocolVersion[] {
clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.TLS10
};
}));
} else {
candidates = new ProtocolVersion[] {
clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.SSL30,
ProtocolVersion.TLS10
};
}));
}
clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
clientDefaultProtocolList, true); // enabled only
}
defaultClientSSLParams = new SSLParameters();
defaultClientSSLParams.setProtocols(
getAvailableProtocols(candidates).toArray(new String[0]));
@Override
ProtocolList getClientDefaultProtocolList() {
return clientDefaultProtocolList;
}
@Override
SSLParameters getDefaultClientSSLParams() {
return defaultClientSSLParams;
CipherSuiteList getClientDefaultCipherSuiteList() {
return clientDefaultCipherSuiteList;
}
}
......@@ -537,33 +501,38 @@ public abstract class SSLContextImpl extends SSLContextSpi {
*
* @see SSLContext
*/
public static final class TLS11Context extends AbstractSSLContext {
private static final SSLParameters defaultClientSSLParams;
public static final class TLS11Context extends AbstractTLSContext {
private static final ProtocolList clientDefaultProtocolList;
private static final CipherSuiteList clientDefaultCipherSuiteList;
static {
// candidates for available protocols
ProtocolVersion[] candidates;
if (SunJSSE.isFIPS()) {
candidates = new ProtocolVersion[] {
clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.TLS10,
ProtocolVersion.TLS11
};
}));
} else {
candidates = new ProtocolVersion[] {
clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.SSL30,
ProtocolVersion.TLS10,
ProtocolVersion.TLS11
};
}));
}
defaultClientSSLParams = new SSLParameters();
defaultClientSSLParams.setProtocols(
getAvailableProtocols(candidates).toArray(new String[0]));
clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
clientDefaultProtocolList, true); // enabled only
}
@Override
SSLParameters getDefaultClientSSLParams() {
return defaultClientSSLParams;
ProtocolList getClientDefaultProtocolList() {
return clientDefaultProtocolList;
}
@Override
CipherSuiteList getClientDefaultCipherSuiteList() {
return clientDefaultCipherSuiteList;
}
}
......@@ -572,135 +541,182 @@ public abstract class SSLContextImpl extends SSLContextSpi {
*
* @see SSLContext
*/
public static final class TLS12Context extends AbstractSSLContext {
private static final SSLParameters defaultClientSSLParams;
public static final class TLS12Context extends AbstractTLSContext {
private static final ProtocolList clientDefaultProtocolList;
private static final CipherSuiteList clientDefaultCipherSuiteList;
static {
// candidates for available protocols
ProtocolVersion[] candidates;
if (SunJSSE.isFIPS()) {
candidates = new ProtocolVersion[] {
clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.TLS10,
ProtocolVersion.TLS11,
ProtocolVersion.TLS12
};
}));
} else {
candidates = new ProtocolVersion[] {
clientDefaultProtocolList = new ProtocolList(
getAvailableProtocols(new ProtocolVersion[] {
ProtocolVersion.SSL30,
ProtocolVersion.TLS10,
ProtocolVersion.TLS11,
ProtocolVersion.TLS12
};
}));
}
clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
clientDefaultProtocolList, true); // enabled only
}
defaultClientSSLParams = new SSLParameters();
defaultClientSSLParams.setProtocols(
getAvailableProtocols(candidates).toArray(new String[0]));
@Override
ProtocolList getClientDefaultProtocolList() {
return clientDefaultProtocolList;
}
@Override
SSLParameters getDefaultClientSSLParams() {
return defaultClientSSLParams;
CipherSuiteList getClientDefaultCipherSuiteList() {
return clientDefaultCipherSuiteList;
}
}
/*
* The SSLContext implementation for customized TLS protocols
* The interface for the customized SSL/(D)TLS 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 SSLParameters defaultClientSSLParams;
private static IllegalArgumentException reservedException = null;
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, let's handle the initialization
// exception in constructor.
// the provider service. Instead, please handle the initialization
// exception in the caller's constructor.
static {
// candidates for available protocols
ProtocolVersion[] candidates;
String property = AccessController.doPrivileged(
new GetPropertyAction(PROPERTY_NAME));
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 {
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);
}
String[] protocols = null;
if (property != null && property.length() != 0) {
protocols = property.split(",");
} else {
reservedException = new IllegalArgumentException(
"No protocol specified in " +
PROPERTY_NAME + " system property");
protocols = new String[0];
}
candidates = new ProtocolVersion[protocols.length];
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 {
candidates[i] = ProtocolVersion.valueOf(protocols[i]);
} catch (IllegalArgumentException iae) {
ProtocolVersion pro =
ProtocolVersion.valueOf(protocols[i]);
if (SunJSSE.isFIPS() &&
((pro.v == ProtocolVersion.SSL30.v) ||
(pro.v == ProtocolVersion.SSL20Hello.v))) {
reservedException = new IllegalArgumentException(
PROPERTY_NAME + ": " + protocols[i] +
" is not a standard SSL/TLS protocol name", iae);
PROPERTY_NAME + ": " + pro +
" is not FIPS compliant");
break;
}
}
if ((reservedException == null) && SunJSSE.isFIPS()) {
for (ProtocolVersion protocolVersion : candidates) {
if (ProtocolVersion.SSL20Hello.v == protocolVersion.v ||
ProtocolVersion.SSL30.v == protocolVersion.v) {
// ignore duplicated protocols
if (!customizedProtocols.contains(pro)) {
customizedProtocols.add(pro);
}
} catch (IllegalArgumentException iae) {
reservedException = new IllegalArgumentException(
PROPERTY_NAME + ": " + protocolVersion +
" is not FIPS compliant");
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;
defaultClientSSLParams = new SSLParameters();
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) {
defaultClientSSLParams.setProtocols(
getAvailableProtocols(candidates).toArray(new String[0]));
ArrayList<ProtocolVersion>
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) {
throw reservedException;
}
}
@Override
SSLParameters getDefaultClientSSLParams() {
return defaultClientSSLParams;
ProtocolList getClientDefaultProtocolList() {
return clientDefaultProtocolList;
}
@Override
CipherSuiteList getClientDefaultCipherSuiteList() {
return clientDefaultCipherSuiteList;
}
}
......@@ -709,75 +725,57 @@ public abstract class SSLContextImpl extends SSLContextSpi {
*
* @see SSLContext
*/
public static final class TLSContext extends CustomizedSSLContext {
public static final class TLSContext extends CustomizedTLSContext {
// use the default constructor and methods
}
/*
* The SSLContext implementation for default "Default" algorithm
*
* @see SSLContext
*/
public static final class DefaultSSLContext extends CustomizedSSLContext {
// 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 volatile SSLContextImpl defaultImpl;
private static final TrustManager[] trustManagers;
private static final KeyManager[] keyManagers;
private static TrustManager[] defaultTrustManagers;
private static KeyManager[] defaultKeyManagers;
static Exception reservedException = null;
public DefaultSSLContext() throws Exception {
static {
TrustManager[] tmMediator;
try {
super.engineInit(getDefaultKeyManager(),
getDefaultTrustManager(), null);
tmMediator = getTrustManagers();
} catch (Exception e) {
if (debug != null && Debug.isOn("defaultctx")) {
System.out.println("default context init failed: " + e);
}
throw e;
reservedException = e;
tmMediator = new TrustManager[0];
}
trustManagers = tmMediator;
if (defaultImpl == null) {
defaultImpl = this;
}
}
@Override
protected void engineInit(KeyManager[] km, TrustManager[] tm,
SecureRandom sr) throws KeyManagementException {
throw new KeyManagementException
("Default SSLContext is initialized automatically");
}
static synchronized SSLContextImpl getDefaultImpl() throws Exception {
if (defaultImpl == null) {
new DefaultSSLContext();
if (reservedException == null) {
KeyManager[] kmMediator;
try {
kmMediator = getKeyManagers();
} catch (Exception e) {
reservedException = e;
kmMediator = new KeyManager[0];
}
return defaultImpl;
keyManagers = kmMediator;
} else {
keyManagers = new KeyManager[0];
}
private static synchronized TrustManager[] getDefaultTrustManager()
throws Exception {
if (defaultTrustManagers != null) {
return defaultTrustManagers;
}
private static TrustManager[] getTrustManagers() throws Exception {
KeyStore ks =
TrustManagerFactoryImpl.getCacertsKeyStore("defaultctx");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
defaultTrustManagers = tmf.getTrustManagers();
return defaultTrustManagers;
return tmf.getTrustManagers();
}
private static synchronized KeyManager[] getDefaultKeyManager()
throws Exception {
if (defaultKeyManagers != null) {
return defaultKeyManagers;
}
private static KeyManager[] getKeyManagers() throws Exception {
final Map<String,String> props = new HashMap<>();
AccessController.doPrivileged(
......@@ -874,11 +872,75 @@ public abstract class SSLContextImpl extends SSLContextSpi {
kmf.init(ks, passwd);
}
defaultKeyManagers = kmf.getKeyManagers();
return defaultKeyManagers;
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;
}
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册