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;
|