提交 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 boolean isUnlimited(int keySize, String transformation) {
int keySizeInBits = keySize * 8;
if (keySizeInBits > 128) { // need the JCE unlimited
// strength jurisdiction policy
try {
if (Cipher.getMaxAllowedKeyLength(
transformation) < keySizeInBits) {
private static synchronized boolean isAvailable(BulkCipher cipher) {
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;
return 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
......
/*
* 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,24 +74,12 @@ 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");
}
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;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册