提交 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;
}
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册