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

Print this page




 105     // better. Each supported CipherSuite *must* have a unique priority.
 106     // Ciphersuites with priority >= DEFAULT_SUITES_PRIORITY are enabled
 107     // by default
 108     final int priority;
 109 
 110     // key exchange, bulk cipher, mac and prf algorithms. See those
 111     // classes below.
 112     final KeyExchange keyExchange;
 113     final BulkCipher cipher;
 114     final MacAlg macAlg;
 115     final PRF prfAlg;
 116 
 117     // whether a CipherSuite qualifies as exportable under 512/40 bit rules.
 118     // TLS 1.1+ (RFC 4346) must not negotiate to these suites.
 119     final boolean exportable;
 120 
 121     // true iff implemented and enabled at compile time
 122     final boolean allowed;
 123 
 124     // obsoleted since protocol version



 125     final int obsoleted;
 126 
 127     // supported since protocol version



 128     final int supported;
 129 
 130     /**
 131      * Constructor for implemented CipherSuites.
 132      */
 133     private CipherSuite(String name, int id, int priority,
 134             KeyExchange keyExchange, BulkCipher cipher, MacAlg mac,
 135             boolean allowed, int obsoleted, int supported, PRF prfAlg) {
 136         this.name = name;
 137         this.id = id;
 138         this.priority = priority;
 139         this.keyExchange = keyExchange;
 140         this.cipher = cipher;
 141         this.macAlg = mac;
 142         this.exportable = cipher.exportable;
 143         allowed &= keyExchange.allowed;
 144         allowed &= cipher.allowed;
 145         this.allowed = allowed;
 146         this.obsoleted = obsoleted;
 147         this.supported = supported;


 165         this.supported = ProtocolVersion.LIMIT_MIN_VALUE;
 166         this.prfAlg = P_NONE;
 167     }
 168 
 169     /**
 170      * Return whether this CipherSuite is available for use. A
 171      * CipherSuite may be unavailable even if it is supported
 172      * (i.e. allowed == true) if the required JCE cipher is not installed.
 173      * In some configuration, this situation may change over time, call
 174      * CipherSuiteList.clearAvailableCache() before this method to obtain
 175      * the most current status.
 176      */
 177     boolean isAvailable() {
 178         return allowed && keyExchange.isAvailable() && cipher.isAvailable();
 179     }
 180 
 181     boolean isNegotiable() {
 182         return this != C_SCSV && isAvailable();
 183     }
 184 
































































 185     /**
 186      * Compares CipherSuites based on their priority. Has the effect of
 187      * sorting CipherSuites when put in a sorted collection, which is
 188      * used by CipherSuiteList. Follows standard Comparable contract.
 189      *
 190      * Note that for unsupported CipherSuites parsed from a handshake
 191      * message we violate the equals() contract.
 192      */
 193     @Override
 194     public int compareTo(CipherSuite o) {
 195         return o.priority - priority;
 196     }
 197 
 198     /**
 199      * Returns this.name.
 200      */
 201     @Override
 202     public String toString() {
 203         return name;
 204     }


 225     }
 226 
 227     /**
 228      * Return a CipherSuite with the given ID. A temporary object is
 229      * constructed if the ID is unknown. Use isAvailable() to verify that
 230      * the CipherSuite can actually be used.
 231      */
 232     static CipherSuite valueOf(int id1, int id2) {
 233         id1 &= 0xff;
 234         id2 &= 0xff;
 235         int id = (id1 << 8) | id2;
 236         CipherSuite c = idMap.get(id);
 237         if (c == null) {
 238             String h1 = Integer.toString(id1, 16);
 239             String h2 = Integer.toString(id2, 16);
 240             c = new CipherSuite("Unknown 0x" + h1 + ":0x" + h2, id);
 241         }
 242         return c;
 243     }
 244 
 245     // for use by CipherSuiteList only
 246     static Collection<CipherSuite> allowedCipherSuites() {
 247         return nameMap.values();
 248     }
 249 
 250     /*
 251      * Use this method when all of the values need to be specified.
 252      * This is primarily used when defining a new ciphersuite for
 253      * TLS 1.2+ that doesn't use the "default" PRF.
 254      */
 255     private static void add(String name, int id, int priority,
 256             KeyExchange keyExchange, BulkCipher cipher, MacAlg mac,
 257             boolean allowed, int obsoleted, int supported, PRF prf) {
 258 
 259         CipherSuite c = new CipherSuite(name, id, priority, keyExchange,
 260             cipher, mac, allowed, obsoleted, supported, prf);
 261         if (idMap.put(id, c) != null) {
 262             throw new RuntimeException("Duplicate ciphersuite definition: "
 263                                         + id + ", " + name);
 264         }
 265         if (c.allowed) {


 355             if (alwaysAvailable) {
 356                 return true;
 357             }
 358 
 359             if (name.startsWith("EC")) {
 360                 return (allowed && JsseJce.isEcAvailable());
 361             } else if (name.startsWith("KRB")) {
 362                 return (allowed && JsseJce.isKerberosAvailable());
 363             } else {
 364                 return allowed;
 365             }
 366         }
 367 
 368         @Override
 369         public String toString() {
 370             return name;
 371         }
 372     }
 373 
 374     static enum CipherType {
 375         STREAM_CIPHER,         // null or stream cipher

 376         BLOCK_CIPHER,          // block cipher in CBC mode
 377         AEAD_CIPHER            // AEAD cipher
 378     }
 379 
 380     /**
 381      * An SSL/TLS bulk cipher algorithm. One instance per combination of
 382      * cipher and key length.
 383      *
 384      * Also contains a factory method to obtain in initialized CipherBox
 385      * for this algorithm.
 386      */
 387     static enum BulkCipher {
 388 
 389         // export strength ciphers
 390         B_NULL("NULL", STREAM_CIPHER, 0, 0, 0, 0, true),
 391         B_RC4_40(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true),
 392         B_RC2_40("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false),
 393         B_DES_40(CIPHER_DES,  BLOCK_CIPHER, 5, 8, 8, 0, true),
 394 
 395         // domestic strength ciphers
 396         B_RC4_128(CIPHER_RC4, STREAM_CIPHER, 16, 0, 0, true),
 397         B_DES(CIPHER_DES, BLOCK_CIPHER, 8, 8, 0, true),
 398         B_3DES(CIPHER_3DES, BLOCK_CIPHER, 24, 8, 0, true),
 399         B_IDEA("IDEA", BLOCK_CIPHER, 16, 8, 0, false),
 400         B_AES_128(CIPHER_AES, BLOCK_CIPHER, 16, 16, 0, true),
 401         B_AES_256(CIPHER_AES, BLOCK_CIPHER, 32, 16, 0, true),
 402         B_AES_128_GCM(CIPHER_AES_GCM, AEAD_CIPHER, 16, 12, 4, true),
 403         B_AES_256_GCM(CIPHER_AES_GCM, AEAD_CIPHER, 32, 12, 4, true);
 404 
 405         // Map BulkCipher -> Boolean(available)
 406         private final static Map<BulkCipher,Boolean> availableCache =
 407                                             new HashMap<>(8);
 408 
 409         // descriptive name including key size, e.g. AES/128
 410         final String description;


 551                         b = Boolean.FALSE;
 552                     }
 553                 }
 554 
 555                 if (b == null) {
 556                     b = Boolean.FALSE;          // may be reset to TRUE if
 557                                                 // the cipher is available
 558                     CipherBox temporary = null;
 559                     try {
 560                         SecretKey key = new SecretKeySpec(
 561                                             new byte[cipher.expandedKeySize],
 562                                             cipher.algorithm);
 563                         IvParameterSpec iv;
 564                         if (cipher.cipherType == CipherType.AEAD_CIPHER) {
 565                             iv = new IvParameterSpec(
 566                                             new byte[cipher.fixedIvSize]);
 567                         } else {
 568                             iv = new IvParameterSpec(new byte[cipher.ivSize]);
 569                         }
 570                         temporary = cipher.newCipher(
 571                                             ProtocolVersion.DEFAULT,
 572                                             key, iv, secureRandom, true);
 573                         b = temporary.isAvailable();
 574                     } catch (NoSuchAlgorithmException e) {
 575                         // not available
 576                     } finally {
 577                         if (temporary != null) {
 578                             temporary.dispose();
 579                         }
 580                     }
 581                 }
 582 
 583                 availableCache.put(cipher, b);
 584             }
 585 
 586             return b.booleanValue();
 587         }
 588 
 589         @Override
 590         public String toString() {
 591             return description;




 105     // better. Each supported CipherSuite *must* have a unique priority.
 106     // Ciphersuites with priority >= DEFAULT_SUITES_PRIORITY are enabled
 107     // by default
 108     final int priority;
 109 
 110     // key exchange, bulk cipher, mac and prf algorithms. See those
 111     // classes below.
 112     final KeyExchange keyExchange;
 113     final BulkCipher cipher;
 114     final MacAlg macAlg;
 115     final PRF prfAlg;
 116 
 117     // whether a CipherSuite qualifies as exportable under 512/40 bit rules.
 118     // TLS 1.1+ (RFC 4346) must not negotiate to these suites.
 119     final boolean exportable;
 120 
 121     // true iff implemented and enabled at compile time
 122     final boolean allowed;
 123 
 124     // obsoleted since protocol version
 125     //
 126     // TLS version is used.  If checking DTLS versions, please map to
 127     // TLS version firstly.  See ProtocolVersion.mapToTLSProtocol(). 
 128     final int obsoleted;
 129 
 130     // supported since protocol version (TLS version is used)
 131     //
 132     // TLS version is used.  If checking DTLS versions, please map to
 133     // TLS version firstly.  See ProtocolVersion.mapToTLSProtocol(). 
 134     final int supported;
 135 
 136     /**
 137      * Constructor for implemented CipherSuites.
 138      */
 139     private CipherSuite(String name, int id, int priority,
 140             KeyExchange keyExchange, BulkCipher cipher, MacAlg mac,
 141             boolean allowed, int obsoleted, int supported, PRF prfAlg) {
 142         this.name = name;
 143         this.id = id;
 144         this.priority = priority;
 145         this.keyExchange = keyExchange;
 146         this.cipher = cipher;
 147         this.macAlg = mac;
 148         this.exportable = cipher.exportable;
 149         allowed &= keyExchange.allowed;
 150         allowed &= cipher.allowed;
 151         this.allowed = allowed;
 152         this.obsoleted = obsoleted;
 153         this.supported = supported;


 171         this.supported = ProtocolVersion.LIMIT_MIN_VALUE;
 172         this.prfAlg = P_NONE;
 173     }
 174 
 175     /**
 176      * Return whether this CipherSuite is available for use. A
 177      * CipherSuite may be unavailable even if it is supported
 178      * (i.e. allowed == true) if the required JCE cipher is not installed.
 179      * In some configuration, this situation may change over time, call
 180      * CipherSuiteList.clearAvailableCache() before this method to obtain
 181      * the most current status.
 182      */
 183     boolean isAvailable() {
 184         return allowed && keyExchange.isAvailable() && cipher.isAvailable();
 185     }
 186 
 187     boolean isNegotiable() {
 188         return this != C_SCSV && isAvailable();
 189     }
 190 
 191     // See also CipherBox.calculatePacketSize().
 192     int calculatePacketSize(int fragmentSize,
 193             ProtocolVersion protocolVersion, boolean isDTLS) {
 194 
 195         int packetSize = fragmentSize;
 196         if (cipher != B_NULL) {
 197             int blockSize = cipher.ivSize;
 198             switch (cipher.cipherType) {
 199                 case BLOCK_CIPHER:
 200                     packetSize += macAlg.size;
 201                     packetSize += 1;        // 1 byte padding length field
 202                     packetSize +=           // use the minimal padding
 203                             (blockSize - (packetSize % blockSize)) % blockSize;
 204                     if (protocolVersion.useTLS11PlusSpec()) {
 205                         packetSize += blockSize;        // explicit IV
 206                     }
 207 
 208                     break;
 209             case AEAD_CIPHER:
 210                 packetSize += cipher.ivSize - cipher.fixedIvSize;   // record IV
 211                 packetSize += cipher.tagSize;
 212 
 213                 break;
 214             default:    // NULL_CIPHER or STREAM_CIPHER
 215                 packetSize += macAlg.size;
 216             }
 217         }
 218 
 219         return packetSize +
 220             (isDTLS ? DTLSRecord.headerSize : SSLRecord.headerSize);
 221     }
 222 
 223     // See also CipherBox.calculateFragmentSize().
 224     int calculateFragSize(int packetLimit,
 225             ProtocolVersion protocolVersion, boolean isDTLS) {
 226 
 227         int fragSize = packetLimit -
 228                 (isDTLS ? DTLSRecord.headerSize : SSLRecord.headerSize);
 229         if (cipher != B_NULL) {
 230             int blockSize = cipher.ivSize;
 231             switch (cipher.cipherType) {
 232             case BLOCK_CIPHER:
 233                 if (protocolVersion.useTLS11PlusSpec()) {
 234                     fragSize -= blockSize;              // explicit IV
 235                 }
 236                 fragSize -= (fragSize % blockSize);     // cannot hold a block
 237                 // No padding for a maximum fragment.
 238                 fragSize -= 1;        // 1 byte padding length field: 0x00
 239                 fragSize -= macAlg.size;
 240 
 241                 break;
 242             case AEAD_CIPHER:
 243                 fragSize -= cipher.tagSize;
 244                 fragSize -= cipher.ivSize - cipher.fixedIvSize;     // record IV
 245 
 246                 break;
 247             default:    // NULL_CIPHER or STREAM_CIPHER
 248                 fragSize -= macAlg.size;
 249             }
 250         }
 251 
 252         return fragSize;
 253     }
 254 
 255     /**
 256      * Compares CipherSuites based on their priority. Has the effect of
 257      * sorting CipherSuites when put in a sorted collection, which is
 258      * used by CipherSuiteList. Follows standard Comparable contract.
 259      *
 260      * Note that for unsupported CipherSuites parsed from a handshake
 261      * message we violate the equals() contract.
 262      */
 263     @Override
 264     public int compareTo(CipherSuite o) {
 265         return o.priority - priority;
 266     }
 267 
 268     /**
 269      * Returns this.name.
 270      */
 271     @Override
 272     public String toString() {
 273         return name;
 274     }


 295     }
 296 
 297     /**
 298      * Return a CipherSuite with the given ID. A temporary object is
 299      * constructed if the ID is unknown. Use isAvailable() to verify that
 300      * the CipherSuite can actually be used.
 301      */
 302     static CipherSuite valueOf(int id1, int id2) {
 303         id1 &= 0xff;
 304         id2 &= 0xff;
 305         int id = (id1 << 8) | id2;
 306         CipherSuite c = idMap.get(id);
 307         if (c == null) {
 308             String h1 = Integer.toString(id1, 16);
 309             String h2 = Integer.toString(id2, 16);
 310             c = new CipherSuite("Unknown 0x" + h1 + ":0x" + h2, id);
 311         }
 312         return c;
 313     }
 314 
 315     // for use by SSLContextImpl only
 316     static Collection<CipherSuite> allowedCipherSuites() {
 317         return nameMap.values();
 318     }
 319 
 320     /*
 321      * Use this method when all of the values need to be specified.
 322      * This is primarily used when defining a new ciphersuite for
 323      * TLS 1.2+ that doesn't use the "default" PRF.
 324      */
 325     private static void add(String name, int id, int priority,
 326             KeyExchange keyExchange, BulkCipher cipher, MacAlg mac,
 327             boolean allowed, int obsoleted, int supported, PRF prf) {
 328 
 329         CipherSuite c = new CipherSuite(name, id, priority, keyExchange,
 330             cipher, mac, allowed, obsoleted, supported, prf);
 331         if (idMap.put(id, c) != null) {
 332             throw new RuntimeException("Duplicate ciphersuite definition: "
 333                                         + id + ", " + name);
 334         }
 335         if (c.allowed) {


 425             if (alwaysAvailable) {
 426                 return true;
 427             }
 428 
 429             if (name.startsWith("EC")) {
 430                 return (allowed && JsseJce.isEcAvailable());
 431             } else if (name.startsWith("KRB")) {
 432                 return (allowed && JsseJce.isKerberosAvailable());
 433             } else {
 434                 return allowed;
 435             }
 436         }
 437 
 438         @Override
 439         public String toString() {
 440             return name;
 441         }
 442     }
 443 
 444     static enum CipherType {
 445         NULL_CIPHER,           // null cipher
 446         STREAM_CIPHER,         // stream cipher
 447         BLOCK_CIPHER,          // block cipher in CBC mode
 448         AEAD_CIPHER            // AEAD cipher
 449     }
 450 
 451     /**
 452      * An SSL/TLS bulk cipher algorithm. One instance per combination of
 453      * cipher and key length.
 454      *
 455      * Also contains a factory method to obtain in initialized CipherBox
 456      * for this algorithm.
 457      */
 458     static enum BulkCipher {
 459 
 460         // export strength ciphers
 461         B_NULL("NULL", NULL_CIPHER, 0, 0, 0, 0, true),
 462         B_RC4_40(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true),
 463         B_RC2_40("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false),
 464         B_DES_40(CIPHER_DES,  BLOCK_CIPHER, 5, 8, 8, 0, true),
 465 
 466         // domestic strength ciphers
 467         B_RC4_128(CIPHER_RC4, STREAM_CIPHER, 16, 0, 0, true),
 468         B_DES(CIPHER_DES, BLOCK_CIPHER, 8, 8, 0, true),
 469         B_3DES(CIPHER_3DES, BLOCK_CIPHER, 24, 8, 0, true),
 470         B_IDEA("IDEA", BLOCK_CIPHER, 16, 8, 0, false),
 471         B_AES_128(CIPHER_AES, BLOCK_CIPHER, 16, 16, 0, true),
 472         B_AES_256(CIPHER_AES, BLOCK_CIPHER, 32, 16, 0, true),
 473         B_AES_128_GCM(CIPHER_AES_GCM, AEAD_CIPHER, 16, 12, 4, true),
 474         B_AES_256_GCM(CIPHER_AES_GCM, AEAD_CIPHER, 32, 12, 4, true);
 475 
 476         // Map BulkCipher -> Boolean(available)
 477         private final static Map<BulkCipher,Boolean> availableCache =
 478                                             new HashMap<>(8);
 479 
 480         // descriptive name including key size, e.g. AES/128
 481         final String description;


 622                         b = Boolean.FALSE;
 623                     }
 624                 }
 625 
 626                 if (b == null) {
 627                     b = Boolean.FALSE;          // may be reset to TRUE if
 628                                                 // the cipher is available
 629                     CipherBox temporary = null;
 630                     try {
 631                         SecretKey key = new SecretKeySpec(
 632                                             new byte[cipher.expandedKeySize],
 633                                             cipher.algorithm);
 634                         IvParameterSpec iv;
 635                         if (cipher.cipherType == CipherType.AEAD_CIPHER) {
 636                             iv = new IvParameterSpec(
 637                                             new byte[cipher.fixedIvSize]);
 638                         } else {
 639                             iv = new IvParameterSpec(new byte[cipher.ivSize]);
 640                         }
 641                         temporary = cipher.newCipher(
 642                                             ProtocolVersion.DEFAULT_TLS,
 643                                             key, iv, secureRandom, true);
 644                         b = temporary.isAvailable();
 645                     } catch (NoSuchAlgorithmException e) {
 646                         // not available
 647                     } finally {
 648                         if (temporary != null) {
 649                             temporary.dispose();
 650                         }
 651                     }
 652                 }
 653 
 654                 availableCache.put(cipher, b);
 655             }
 656 
 657             return b.booleanValue();
 658         }
 659 
 660         @Override
 661         public String toString() {
 662             return description;