< prev index next >

src/share/classes/sun/security/ssl/CipherSuite.java

Print this page
rev 11548 : 8133070: Hot lock on BulkCipher.isAvailable
Reviewed-by: mullan
Contributed-by: xuelei.fan@oracle.com, kungu.mjh@alibaba-inc.com

@@ -73,16 +73,10 @@
     final static int SUPPORTED_SUITES_PRIORITY = 1;
 
     // 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);
 
     // Map Integer(id) -> CipherSuite
     // contains all known CipherSuites

@@ -184,13 +178,10 @@
 
     /**
      * 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();
     }
 

@@ -402,14 +393,10 @@
      * Also contains a factory method to obtain in initialized CipherBox
      * for this algorithm.
      */
     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;
 
         // JCE cipher transformation string, e.g. AES/CBC/NoPadding
         final String transformation;

@@ -449,10 +436,13 @@
         final int tagSize = 16;
 
         // 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();
             } catch (KeyManagementException kme) {
                 throw new RuntimeException(kme);

@@ -473,10 +463,21 @@
             this.fixedIvSize = fixedIvSize;
             this.allowed = allowed;
 
             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,
                 int ivSize, int fixedIvSize, boolean allowed) {
             this.transformation = transformation;

@@ -489,10 +490,21 @@
             this.fixedIvSize = fixedIvSize;
             this.allowed = allowed;
 
             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;
         }
 
         /**
          * Return an initialized CipherBox for this BulkCipher.
          * IV must be null for stream ciphers.

@@ -506,88 +518,31 @@
                                             key, iv, random, encrypt);
         }
 
         /**
          * 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
         public String toString() {
             return description;
< prev index next >