1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.ssl; 27 28 import java.nio.ByteBuffer; 29 import java.security.AccessController; 30 import java.security.GeneralSecurityException; 31 import java.security.InvalidAlgorithmParameterException; 32 import java.security.InvalidKeyException; 33 import java.security.Key; 34 import java.security.PrivilegedAction; 35 import java.security.SecureRandom; 36 import java.security.Security; 37 import java.security.spec.AlgorithmParameterSpec; 38 import java.util.AbstractMap.SimpleImmutableEntry; 39 import java.util.Arrays; 40 import java.util.HashMap; 41 import java.util.Map; 42 import javax.crypto.BadPaddingException; 43 import javax.crypto.Cipher; 44 import javax.crypto.IllegalBlockSizeException; 45 import javax.crypto.SecretKey; 46 import javax.crypto.ShortBufferException; 47 import javax.crypto.spec.GCMParameterSpec; 48 import javax.crypto.spec.IvParameterSpec; 49 import sun.security.ssl.Authenticator.MAC; 50 import static sun.security.ssl.CipherType.*; 51 import static sun.security.ssl.JsseJce.*; 52 53 enum SSLCipher { 54 // exportable ciphers 55 @SuppressWarnings({"unchecked", "rawtypes"}) 56 B_NULL("NULL", NULL_CIPHER, 0, 0, 0, 0, true, true, 57 (Map.Entry<ReadCipherGenerator, 58 ProtocolVersion[]>[])(new Map.Entry[] { 59 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 60 new NullReadCipherGenerator(), 61 ProtocolVersion.PROTOCOLS_OF_NONE 62 ), 63 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 64 new NullReadCipherGenerator(), 65 ProtocolVersion.PROTOCOLS_TO_13 66 ) 67 }), 68 (Map.Entry<WriteCipherGenerator, 69 ProtocolVersion[]>[])(new Map.Entry[] { 70 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 71 new NullWriteCipherGenerator(), 72 ProtocolVersion.PROTOCOLS_OF_NONE 73 ), 74 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 75 new NullWriteCipherGenerator(), 76 ProtocolVersion.PROTOCOLS_TO_13 77 ) 78 })), 79 80 @SuppressWarnings({"unchecked", "rawtypes"}) 81 B_RC4_40(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true, true, 82 (Map.Entry<ReadCipherGenerator, 83 ProtocolVersion[]>[])(new Map.Entry[] { 84 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 85 new StreamReadCipherGenerator(), 86 ProtocolVersion.PROTOCOLS_TO_10 87 ) 88 }), 89 (Map.Entry<WriteCipherGenerator, 90 ProtocolVersion[]>[])(new Map.Entry[] { 91 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 92 new StreamWriteCipherGenerator(), 93 ProtocolVersion.PROTOCOLS_TO_10 94 ) 95 })), 96 97 @SuppressWarnings({"unchecked", "rawtypes"}) 98 B_RC2_40("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false, true, 99 (Map.Entry<ReadCipherGenerator, 100 ProtocolVersion[]>[])(new Map.Entry[] { 101 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 102 new StreamReadCipherGenerator(), 103 ProtocolVersion.PROTOCOLS_TO_10 104 ) 105 }), 106 (Map.Entry<WriteCipherGenerator, 107 ProtocolVersion[]>[])(new Map.Entry[] { 108 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 109 new StreamWriteCipherGenerator(), 110 ProtocolVersion.PROTOCOLS_TO_10 111 ) 112 })), 113 114 @SuppressWarnings({"unchecked", "rawtypes"}) 115 B_DES_40(CIPHER_DES, BLOCK_CIPHER, 5, 8, 8, 0, true, true, 116 (Map.Entry<ReadCipherGenerator, 117 ProtocolVersion[]>[])(new Map.Entry[] { 118 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 119 new T10BlockReadCipherGenerator(), 120 ProtocolVersion.PROTOCOLS_TO_10 121 ) 122 }), 123 (Map.Entry<WriteCipherGenerator, 124 ProtocolVersion[]>[])(new Map.Entry[] { 125 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 126 new T10BlockWriteCipherGenerator(), 127 ProtocolVersion.PROTOCOLS_TO_10 128 ) 129 })), 130 131 // domestic strength ciphers 132 @SuppressWarnings({"unchecked", "rawtypes"}) 133 B_RC4_128(CIPHER_RC4, STREAM_CIPHER, 16, 16, 0, 0, true, false, 134 (Map.Entry<ReadCipherGenerator, 135 ProtocolVersion[]>[])(new Map.Entry[] { 136 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 137 new StreamReadCipherGenerator(), 138 ProtocolVersion.PROTOCOLS_TO_12 139 ) 140 }), 141 (Map.Entry<WriteCipherGenerator, 142 ProtocolVersion[]>[])(new Map.Entry[] { 143 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 144 new StreamWriteCipherGenerator(), 145 ProtocolVersion.PROTOCOLS_TO_12 146 ) 147 })), 148 149 @SuppressWarnings({"unchecked", "rawtypes"}) 150 B_DES(CIPHER_DES, BLOCK_CIPHER, 8, 8, 8, 0, true, false, 151 (Map.Entry<ReadCipherGenerator, 152 ProtocolVersion[]>[])(new Map.Entry[] { 153 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 154 new T10BlockReadCipherGenerator(), 155 ProtocolVersion.PROTOCOLS_TO_10 156 ), 157 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 158 new T11BlockReadCipherGenerator(), 159 ProtocolVersion.PROTOCOLS_OF_11 160 ) 161 }), 162 (Map.Entry<WriteCipherGenerator, 163 ProtocolVersion[]>[])(new Map.Entry[] { 164 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 165 new T10BlockWriteCipherGenerator(), 166 ProtocolVersion.PROTOCOLS_TO_10 167 ), 168 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 169 new T11BlockWriteCipherGenerator(), 170 ProtocolVersion.PROTOCOLS_OF_11 171 ) 172 })), 173 174 @SuppressWarnings({"unchecked", "rawtypes"}) 175 B_3DES(CIPHER_3DES, BLOCK_CIPHER, 24, 24, 8, 0, true, false, 176 (Map.Entry<ReadCipherGenerator, 177 ProtocolVersion[]>[])(new Map.Entry[] { 178 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 179 new T10BlockReadCipherGenerator(), 180 ProtocolVersion.PROTOCOLS_TO_10 181 ), 182 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 183 new T11BlockReadCipherGenerator(), 184 ProtocolVersion.PROTOCOLS_11_12 185 ) 186 }), 187 (Map.Entry<WriteCipherGenerator, 188 ProtocolVersion[]>[])(new Map.Entry[] { 189 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 190 new T10BlockWriteCipherGenerator(), 191 ProtocolVersion.PROTOCOLS_TO_10 192 ), 193 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 194 new T11BlockWriteCipherGenerator(), 195 ProtocolVersion.PROTOCOLS_11_12 196 ) 197 })), 198 199 @SuppressWarnings({"unchecked", "rawtypes"}) 200 B_IDEA("IDEA", BLOCK_CIPHER, 16, 16, 8, 0, false, false, 201 (Map.Entry<ReadCipherGenerator, 202 ProtocolVersion[]>[])(new Map.Entry[] { 203 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 204 null, 205 ProtocolVersion.PROTOCOLS_TO_12 206 ) 207 }), 208 (Map.Entry<WriteCipherGenerator, 209 ProtocolVersion[]>[])(new Map.Entry[] { 210 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 211 null, 212 ProtocolVersion.PROTOCOLS_TO_12 213 ) 214 })), 215 216 @SuppressWarnings({"unchecked", "rawtypes"}) 217 B_AES_128(CIPHER_AES, BLOCK_CIPHER, 16, 16, 16, 0, true, false, 218 (Map.Entry<ReadCipherGenerator, 219 ProtocolVersion[]>[])(new Map.Entry[] { 220 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 221 new T10BlockReadCipherGenerator(), 222 ProtocolVersion.PROTOCOLS_TO_10 223 ), 224 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 225 new T11BlockReadCipherGenerator(), 226 ProtocolVersion.PROTOCOLS_11_12 227 ) 228 }), 229 (Map.Entry<WriteCipherGenerator, 230 ProtocolVersion[]>[])(new Map.Entry[] { 231 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 232 new T10BlockWriteCipherGenerator(), 233 ProtocolVersion.PROTOCOLS_TO_10 234 ), 235 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 236 new T11BlockWriteCipherGenerator(), 237 ProtocolVersion.PROTOCOLS_11_12 238 ) 239 })), 240 241 @SuppressWarnings({"unchecked", "rawtypes"}) 242 B_AES_256(CIPHER_AES, BLOCK_CIPHER, 32, 32, 16, 0, true, false, 243 (Map.Entry<ReadCipherGenerator, 244 ProtocolVersion[]>[])(new Map.Entry[] { 245 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 246 new T10BlockReadCipherGenerator(), 247 ProtocolVersion.PROTOCOLS_TO_10 248 ), 249 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 250 new T11BlockReadCipherGenerator(), 251 ProtocolVersion.PROTOCOLS_11_12 252 ) 253 }), 254 (Map.Entry<WriteCipherGenerator, 255 ProtocolVersion[]>[])(new Map.Entry[] { 256 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 257 new T10BlockWriteCipherGenerator(), 258 ProtocolVersion.PROTOCOLS_TO_10 259 ), 260 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 261 new T11BlockWriteCipherGenerator(), 262 ProtocolVersion.PROTOCOLS_11_12 263 ) 264 })), 265 266 @SuppressWarnings({"unchecked", "rawtypes"}) 267 B_AES_128_GCM(CIPHER_AES_GCM, AEAD_CIPHER, 16, 16, 12, 4, true, false, 268 (Map.Entry<ReadCipherGenerator, 269 ProtocolVersion[]>[])(new Map.Entry[] { 270 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 271 new T12GcmReadCipherGenerator(), 272 ProtocolVersion.PROTOCOLS_OF_12 273 ) 274 }), 275 (Map.Entry<WriteCipherGenerator, 276 ProtocolVersion[]>[])(new Map.Entry[] { 277 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 278 new T12GcmWriteCipherGenerator(), 279 ProtocolVersion.PROTOCOLS_OF_12 280 ) 281 })), 282 283 @SuppressWarnings({"unchecked", "rawtypes"}) 284 B_AES_256_GCM(CIPHER_AES_GCM, AEAD_CIPHER, 32, 32, 12, 4, true, false, 285 (Map.Entry<ReadCipherGenerator, 286 ProtocolVersion[]>[])(new Map.Entry[] { 287 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 288 new T12GcmReadCipherGenerator(), 289 ProtocolVersion.PROTOCOLS_OF_12 290 ) 291 }), 292 (Map.Entry<WriteCipherGenerator, 293 ProtocolVersion[]>[])(new Map.Entry[] { 294 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 295 new T12GcmWriteCipherGenerator(), 296 ProtocolVersion.PROTOCOLS_OF_12 297 ) 298 })), 299 300 @SuppressWarnings({"unchecked", "rawtypes"}) 301 B_AES_128_GCM_IV(CIPHER_AES_GCM, AEAD_CIPHER, 16, 16, 12, 0, true, false, 302 (Map.Entry<ReadCipherGenerator, 303 ProtocolVersion[]>[])(new Map.Entry[] { 304 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 305 new T13GcmReadCipherGenerator(), 306 ProtocolVersion.PROTOCOLS_OF_13 307 ) 308 }), 309 (Map.Entry<WriteCipherGenerator, 310 ProtocolVersion[]>[])(new Map.Entry[] { 311 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 312 new T13GcmWriteCipherGenerator(), 313 ProtocolVersion.PROTOCOLS_OF_13 314 ) 315 })), 316 317 @SuppressWarnings({"unchecked", "rawtypes"}) 318 B_AES_256_GCM_IV(CIPHER_AES_GCM, AEAD_CIPHER, 32, 32, 12, 0, true, false, 319 (Map.Entry<ReadCipherGenerator, 320 ProtocolVersion[]>[])(new Map.Entry[] { 321 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 322 new T13GcmReadCipherGenerator(), 323 ProtocolVersion.PROTOCOLS_OF_13 324 ) 325 }), 326 (Map.Entry<WriteCipherGenerator, 327 ProtocolVersion[]>[])(new Map.Entry[] { 328 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 329 new T13GcmWriteCipherGenerator(), 330 ProtocolVersion.PROTOCOLS_OF_13 331 ) 332 })), 333 334 @SuppressWarnings({"unchecked", "rawtypes"}) 335 B_CC20_P1305(CIPHER_CHACHA20_POLY1305, AEAD_CIPHER, 32, 32, 12, 336 12, true, false, 337 (Map.Entry<ReadCipherGenerator, 338 ProtocolVersion[]>[])(new Map.Entry[] { 339 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 340 new T12CC20P1305ReadCipherGenerator(), 341 ProtocolVersion.PROTOCOLS_OF_12 342 ), 343 new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>( 344 new T13CC20P1305ReadCipherGenerator(), 345 ProtocolVersion.PROTOCOLS_OF_13 346 ) 347 }), 348 (Map.Entry<WriteCipherGenerator, 349 ProtocolVersion[]>[])(new Map.Entry[] { 350 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 351 new T12CC20P1305WriteCipherGenerator(), 352 ProtocolVersion.PROTOCOLS_OF_12 353 ), 354 new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>( 355 new T13CC20P1305WriteCipherGenerator(), 356 ProtocolVersion.PROTOCOLS_OF_13 357 ) 358 })); 359 360 // descriptive name including key size, e.g. AES/128 361 final String description; 362 363 // JCE cipher transformation string, e.g. AES/CBC/NoPadding 364 final String transformation; 365 366 // algorithm name, e.g. AES 367 final String algorithm; 368 369 // supported and compile time enabled. Also see isAvailable() 370 final boolean allowed; 371 372 // number of bytes of entropy in the key 373 final int keySize; 374 375 // length of the actual cipher key in bytes. 376 // for non-exportable ciphers, this is the same as keySize 377 final int expandedKeySize; 378 379 // size of the IV 380 final int ivSize; 381 382 // size of fixed IV 383 // 384 // record_iv_length = ivSize - fixedIvSize 385 final int fixedIvSize; 386 387 // exportable under 512/40 bit rules 388 final boolean exportable; 389 390 // Is the cipher algorithm of Cipher Block Chaining (CBC) mode? 391 final CipherType cipherType; 392 393 // size of the authentication tag, only applicable to cipher suites in 394 // Galois Counter Mode (GCM) 395 // 396 // As far as we know, all supported GCM cipher suites use 128-bits 397 // authentication tags. 398 final int tagSize = 16; 399 400 // runtime availability 401 private final boolean isAvailable; 402 403 private final Map.Entry<ReadCipherGenerator, 404 ProtocolVersion[]>[] readCipherGenerators; 405 private final Map.Entry<WriteCipherGenerator, 406 ProtocolVersion[]>[] writeCipherGenerators; 407 408 // Map of Ciphers listed in jdk.tls.keyLimits 409 private static final HashMap<String, Long> cipherLimits = new HashMap<>(); 410 411 // Keywords found on the jdk.tls.keyLimits security property. 412 final static String tag[] = {"KEYUPDATE"}; 413 414 static { 415 final long max = 4611686018427387904L; // 2^62 416 String prop = AccessController.doPrivileged( 417 new PrivilegedAction<String>() { 418 @Override 419 public String run() { 420 return Security.getProperty("jdk.tls.keyLimits"); 421 } 422 }); 423 424 if (prop != null) { 425 String propvalue[] = prop.split(","); 426 427 for (String entry : propvalue) { 428 int index; 429 // If this is not a UsageLimit, goto to next entry. 430 String values[] = entry.trim().toUpperCase().split(" "); 431 432 if (values[1].contains(tag[0])) { 433 index = 0; 434 } else { 435 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 436 SSLLogger.fine("jdk.tls.keyLimits: Unknown action: " + 437 entry); 438 } 439 continue; 440 } 441 442 long size; 443 int i = values[2].indexOf("^"); 444 try { 445 if (i >= 0) { 446 size = (long) Math.pow(2, 447 Integer.parseInt(values[2].substring(i + 1))); 448 } else { 449 size = Long.parseLong(values[2]); 450 } 451 if (size < 1 || size > max) { 452 throw new NumberFormatException( 453 "Length exceeded limits"); 454 } 455 } catch (NumberFormatException e) { 456 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 457 SSLLogger.fine("jdk.tls.keyLimits: " + e.getMessage() + 458 ": " + entry); 459 } 460 continue; 461 } 462 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 463 SSLLogger.fine("jdk.tls.keyLimits: entry = " + entry + 464 ". " + values[0] + ":" + tag[index] + " = " + size); 465 } 466 cipherLimits.put(values[0] + ":" + tag[index], size); 467 } 468 } 469 } 470 SSLCipher(String transformation, CipherType cipherType, int keySize, int expandedKeySize, int ivSize, int fixedIvSize, boolean allowed, boolean exportable, Map.Entry<ReadCipherGenerator, ProtocolVersion[]>[] readCipherGenerators, Map.Entry<WriteCipherGenerator, ProtocolVersion[]>[] writeCipherGenerators)471 private SSLCipher(String transformation, 472 CipherType cipherType, int keySize, 473 int expandedKeySize, int ivSize, 474 int fixedIvSize, boolean allowed, boolean exportable, 475 Map.Entry<ReadCipherGenerator, 476 ProtocolVersion[]>[] readCipherGenerators, 477 Map.Entry<WriteCipherGenerator, 478 ProtocolVersion[]>[] writeCipherGenerators) { 479 this.transformation = transformation; 480 String[] splits = transformation.split("/"); 481 this.algorithm = splits[0]; 482 this.cipherType = cipherType; 483 this.description = this.algorithm + "/" + (keySize << 3); 484 this.keySize = keySize; 485 this.ivSize = ivSize; 486 this.fixedIvSize = fixedIvSize; 487 this.allowed = allowed; 488 489 this.expandedKeySize = expandedKeySize; 490 this.exportable = exportable; 491 492 // availability of this bulk cipher 493 // 494 // We assume all supported ciphers are always available since they are 495 // shipped with the SunJCE provider. However, AES/256 is unavailable 496 // when the default JCE policy jurisdiction files are installed because 497 // of key length restrictions. 498 this.isAvailable = allowed && isUnlimited(keySize, transformation); 499 500 this.readCipherGenerators = readCipherGenerators; 501 this.writeCipherGenerators = writeCipherGenerators; 502 } 503 createReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SecretKey key, IvParameterSpec iv, SecureRandom random)504 SSLReadCipher createReadCipher(Authenticator authenticator, 505 ProtocolVersion protocolVersion, 506 SecretKey key, IvParameterSpec iv, 507 SecureRandom random) throws GeneralSecurityException { 508 if (readCipherGenerators.length == 0) { 509 return null; 510 } 511 512 ReadCipherGenerator rcg = null; 513 for (Map.Entry<ReadCipherGenerator, 514 ProtocolVersion[]> me : readCipherGenerators) { 515 for (ProtocolVersion pv : me.getValue()) { 516 if (protocolVersion == pv) { 517 rcg = me.getKey(); 518 } 519 } 520 } 521 522 if (rcg != null) { 523 return rcg.createCipher(this, authenticator, 524 protocolVersion, transformation, key, iv, random); 525 } 526 return null; 527 } 528 createWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SecretKey key, IvParameterSpec iv, SecureRandom random)529 SSLWriteCipher createWriteCipher(Authenticator authenticator, 530 ProtocolVersion protocolVersion, 531 SecretKey key, IvParameterSpec iv, 532 SecureRandom random) throws GeneralSecurityException { 533 if (writeCipherGenerators.length == 0) { 534 return null; 535 } 536 537 WriteCipherGenerator wcg = null; 538 for (Map.Entry<WriteCipherGenerator, 539 ProtocolVersion[]> me : writeCipherGenerators) { 540 for (ProtocolVersion pv : me.getValue()) { 541 if (protocolVersion == pv) { 542 wcg = me.getKey(); 543 } 544 } 545 } 546 547 if (wcg != null) { 548 return wcg.createCipher(this, authenticator, 549 protocolVersion, transformation, key, iv, random); 550 } 551 return null; 552 } 553 554 /** 555 * Test if this bulk cipher is available. For use by CipherSuite. 556 */ isAvailable()557 boolean isAvailable() { 558 return this.isAvailable; 559 } 560 isUnlimited(int keySize, String transformation)561 private static boolean isUnlimited(int keySize, String transformation) { 562 int keySizeInBits = keySize * 8; 563 if (keySizeInBits > 128) { // need the JCE unlimited 564 // strength jurisdiction policy 565 try { 566 if (Cipher.getMaxAllowedKeyLength( 567 transformation) < keySizeInBits) { 568 return false; 569 } 570 } catch (Exception e) { 571 return false; 572 } 573 } 574 575 return true; 576 } 577 578 @Override toString()579 public String toString() { 580 return description; 581 } 582 583 interface ReadCipherGenerator { createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)584 SSLReadCipher createCipher(SSLCipher sslCipher, 585 Authenticator authenticator, 586 ProtocolVersion protocolVersion, String algorithm, 587 Key key, AlgorithmParameterSpec params, 588 SecureRandom random) throws GeneralSecurityException; 589 } 590 591 abstract static class SSLReadCipher { 592 final Authenticator authenticator; 593 final ProtocolVersion protocolVersion; 594 boolean keyLimitEnabled = false; 595 long keyLimitCountdown = 0; 596 SecretKey baseSecret; 597 SSLReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion)598 SSLReadCipher(Authenticator authenticator, 599 ProtocolVersion protocolVersion) { 600 this.authenticator = authenticator; 601 this.protocolVersion = protocolVersion; 602 } 603 nullTlsReadCipher()604 static final SSLReadCipher nullTlsReadCipher() { 605 try { 606 return B_NULL.createReadCipher( 607 Authenticator.nullTlsMac(), 608 ProtocolVersion.NONE, null, null, null); 609 } catch (GeneralSecurityException gse) { 610 // unlikely 611 throw new RuntimeException("Cannot create NULL SSLCipher", gse); 612 } 613 } 614 nullDTlsReadCipher()615 static final SSLReadCipher nullDTlsReadCipher() { 616 try { 617 return B_NULL.createReadCipher( 618 Authenticator.nullDtlsMac(), 619 ProtocolVersion.NONE, null, null, null); 620 } catch (GeneralSecurityException gse) { 621 // unlikely 622 throw new RuntimeException("Cannot create NULL SSLCipher", gse); 623 } 624 } 625 decrypt(byte contentType, ByteBuffer bb, byte[] sequence)626 abstract Plaintext decrypt(byte contentType, ByteBuffer bb, 627 byte[] sequence) throws GeneralSecurityException; 628 dispose()629 void dispose() { 630 // blank 631 } 632 estimateFragmentSize(int packetSize, int headerSize)633 abstract int estimateFragmentSize(int packetSize, int headerSize); 634 isNullCipher()635 boolean isNullCipher() { 636 return false; 637 } 638 639 /** 640 * Check if processed bytes have reached the key usage limit. 641 * If key usage limit is not be monitored, return false. 642 */ atKeyLimit()643 public boolean atKeyLimit() { 644 if (keyLimitCountdown >= 0) { 645 return false; 646 } 647 648 // Turn off limit checking as KeyUpdate will be occurring 649 keyLimitEnabled = false; 650 return true; 651 } 652 } 653 654 interface WriteCipherGenerator { createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)655 SSLWriteCipher createCipher(SSLCipher sslCipher, 656 Authenticator authenticator, 657 ProtocolVersion protocolVersion, String algorithm, 658 Key key, AlgorithmParameterSpec params, 659 SecureRandom random) throws GeneralSecurityException; 660 } 661 662 abstract static class SSLWriteCipher { 663 final Authenticator authenticator; 664 final ProtocolVersion protocolVersion; 665 boolean keyLimitEnabled = false; 666 long keyLimitCountdown = 0; 667 SecretKey baseSecret; 668 SSLWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion)669 SSLWriteCipher(Authenticator authenticator, 670 ProtocolVersion protocolVersion) { 671 this.authenticator = authenticator; 672 this.protocolVersion = protocolVersion; 673 } 674 encrypt(byte contentType, ByteBuffer bb)675 abstract int encrypt(byte contentType, ByteBuffer bb); 676 nullTlsWriteCipher()677 static final SSLWriteCipher nullTlsWriteCipher() { 678 try { 679 return B_NULL.createWriteCipher( 680 Authenticator.nullTlsMac(), 681 ProtocolVersion.NONE, null, null, null); 682 } catch (GeneralSecurityException gse) { 683 // unlikely 684 throw new RuntimeException( 685 "Cannot create NULL SSL write Cipher", gse); 686 } 687 } 688 nullDTlsWriteCipher()689 static final SSLWriteCipher nullDTlsWriteCipher() { 690 try { 691 return B_NULL.createWriteCipher( 692 Authenticator.nullDtlsMac(), 693 ProtocolVersion.NONE, null, null, null); 694 } catch (GeneralSecurityException gse) { 695 // unlikely 696 throw new RuntimeException( 697 "Cannot create NULL SSL write Cipher", gse); 698 } 699 } 700 dispose()701 void dispose() { 702 // blank 703 } 704 getExplicitNonceSize()705 abstract int getExplicitNonceSize(); calculateFragmentSize(int packetLimit, int headerSize)706 abstract int calculateFragmentSize(int packetLimit, int headerSize); calculatePacketSize(int fragmentSize, int headerSize)707 abstract int calculatePacketSize(int fragmentSize, int headerSize); 708 isCBCMode()709 boolean isCBCMode() { 710 return false; 711 } 712 isNullCipher()713 boolean isNullCipher() { 714 return false; 715 } 716 717 /** 718 * Check if processed bytes have reached the key usage limit. 719 * If key usage limit is not be monitored, return false. 720 */ atKeyLimit()721 public boolean atKeyLimit() { 722 if (keyLimitCountdown >= 0) { 723 return false; 724 } 725 726 // Turn off limit checking as KeyUpdate will be occurring 727 keyLimitEnabled = false; 728 return true; 729 } 730 } 731 732 private static final 733 class NullReadCipherGenerator implements ReadCipherGenerator { 734 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)735 public SSLReadCipher createCipher(SSLCipher sslCipher, 736 Authenticator authenticator, 737 ProtocolVersion protocolVersion, String algorithm, 738 Key key, AlgorithmParameterSpec params, 739 SecureRandom random) throws GeneralSecurityException { 740 return new NullReadCipher(authenticator, protocolVersion); 741 } 742 743 static final class NullReadCipher extends SSLReadCipher { NullReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion)744 NullReadCipher(Authenticator authenticator, 745 ProtocolVersion protocolVersion) { 746 super(authenticator, protocolVersion); 747 } 748 749 @Override decrypt(byte contentType, ByteBuffer bb, byte[] sequence)750 public Plaintext decrypt(byte contentType, ByteBuffer bb, 751 byte[] sequence) throws GeneralSecurityException { 752 MAC signer = (MAC)authenticator; 753 if (signer.macAlg().size != 0) { 754 checkStreamMac(signer, bb, contentType, sequence); 755 } else { 756 authenticator.increaseSequenceNumber(); 757 } 758 759 return new Plaintext(contentType, 760 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, 761 -1, -1L, bb.slice()); 762 } 763 764 @Override estimateFragmentSize(int packetSize, int headerSize)765 int estimateFragmentSize(int packetSize, int headerSize) { 766 int macLen = ((MAC)authenticator).macAlg().size; 767 return packetSize - headerSize - macLen; 768 } 769 770 @Override isNullCipher()771 boolean isNullCipher() { 772 return true; 773 } 774 } 775 } 776 777 private static final 778 class NullWriteCipherGenerator implements WriteCipherGenerator { 779 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)780 public SSLWriteCipher createCipher(SSLCipher sslCipher, 781 Authenticator authenticator, 782 ProtocolVersion protocolVersion, String algorithm, 783 Key key, AlgorithmParameterSpec params, 784 SecureRandom random) throws GeneralSecurityException { 785 return new NullWriteCipher(authenticator, protocolVersion); 786 } 787 788 static final class NullWriteCipher extends SSLWriteCipher { NullWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion)789 NullWriteCipher(Authenticator authenticator, 790 ProtocolVersion protocolVersion) { 791 super(authenticator, protocolVersion); 792 } 793 794 @Override encrypt(byte contentType, ByteBuffer bb)795 public int encrypt(byte contentType, ByteBuffer bb) { 796 // add message authentication code 797 MAC signer = (MAC)authenticator; 798 if (signer.macAlg().size != 0) { 799 addMac(signer, bb, contentType); 800 } else { 801 authenticator.increaseSequenceNumber(); 802 } 803 804 int len = bb.remaining(); 805 bb.position(bb.limit()); 806 return len; 807 } 808 809 810 @Override getExplicitNonceSize()811 int getExplicitNonceSize() { 812 return 0; 813 } 814 815 @Override calculateFragmentSize(int packetLimit, int headerSize)816 int calculateFragmentSize(int packetLimit, int headerSize) { 817 int macLen = ((MAC)authenticator).macAlg().size; 818 return packetLimit - headerSize - macLen; 819 } 820 821 @Override calculatePacketSize(int fragmentSize, int headerSize)822 int calculatePacketSize(int fragmentSize, int headerSize) { 823 int macLen = ((MAC)authenticator).macAlg().size; 824 return fragmentSize + headerSize + macLen; 825 } 826 827 @Override isNullCipher()828 boolean isNullCipher() { 829 return true; 830 } 831 } 832 } 833 834 private static final 835 class StreamReadCipherGenerator implements ReadCipherGenerator { 836 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)837 public SSLReadCipher createCipher(SSLCipher sslCipher, 838 Authenticator authenticator, 839 ProtocolVersion protocolVersion, String algorithm, 840 Key key, AlgorithmParameterSpec params, 841 SecureRandom random) throws GeneralSecurityException { 842 return new StreamReadCipher(authenticator, protocolVersion, 843 algorithm, key, params, random); 844 } 845 846 static final class StreamReadCipher extends SSLReadCipher { 847 private final Cipher cipher; 848 StreamReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)849 StreamReadCipher(Authenticator authenticator, 850 ProtocolVersion protocolVersion, String algorithm, 851 Key key, AlgorithmParameterSpec params, 852 SecureRandom random) throws GeneralSecurityException { 853 super(authenticator, protocolVersion); 854 this.cipher = JsseJce.getCipher(algorithm); 855 cipher.init(Cipher.DECRYPT_MODE, key, params, random); 856 } 857 858 @Override decrypt(byte contentType, ByteBuffer bb, byte[] sequence)859 public Plaintext decrypt(byte contentType, ByteBuffer bb, 860 byte[] sequence) throws GeneralSecurityException { 861 int len = bb.remaining(); 862 int pos = bb.position(); 863 ByteBuffer dup = bb.duplicate(); 864 try { 865 if (len != cipher.update(dup, bb)) { 866 // catch BouncyCastle buffering error 867 throw new RuntimeException( 868 "Unexpected number of plaintext bytes"); 869 } 870 if (bb.position() != dup.position()) { 871 throw new RuntimeException( 872 "Unexpected ByteBuffer position"); 873 } 874 } catch (ShortBufferException sbe) { 875 // catch BouncyCastle buffering error 876 throw new RuntimeException("Cipher buffering error in " + 877 "JCE provider " + cipher.getProvider().getName(), sbe); 878 } 879 bb.position(pos); 880 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 881 SSLLogger.fine( 882 "Plaintext after DECRYPTION", bb.duplicate()); 883 } 884 885 MAC signer = (MAC)authenticator; 886 if (signer.macAlg().size != 0) { 887 checkStreamMac(signer, bb, contentType, sequence); 888 } else { 889 authenticator.increaseSequenceNumber(); 890 } 891 892 return new Plaintext(contentType, 893 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, 894 -1, -1L, bb.slice()); 895 } 896 897 @Override dispose()898 void dispose() { 899 if (cipher != null) { 900 try { 901 cipher.doFinal(); 902 } catch (Exception e) { 903 // swallow all types of exceptions. 904 } 905 } 906 } 907 908 @Override estimateFragmentSize(int packetSize, int headerSize)909 int estimateFragmentSize(int packetSize, int headerSize) { 910 int macLen = ((MAC)authenticator).macAlg().size; 911 return packetSize - headerSize - macLen; 912 } 913 } 914 } 915 916 private static final 917 class StreamWriteCipherGenerator implements WriteCipherGenerator { 918 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)919 public SSLWriteCipher createCipher(SSLCipher sslCipher, 920 Authenticator authenticator, 921 ProtocolVersion protocolVersion, String algorithm, 922 Key key, AlgorithmParameterSpec params, 923 SecureRandom random) throws GeneralSecurityException { 924 return new StreamWriteCipher(authenticator, 925 protocolVersion, algorithm, key, params, random); 926 } 927 928 static final class StreamWriteCipher extends SSLWriteCipher { 929 private final Cipher cipher; 930 StreamWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)931 StreamWriteCipher(Authenticator authenticator, 932 ProtocolVersion protocolVersion, String algorithm, 933 Key key, AlgorithmParameterSpec params, 934 SecureRandom random) throws GeneralSecurityException { 935 super(authenticator, protocolVersion); 936 this.cipher = JsseJce.getCipher(algorithm); 937 cipher.init(Cipher.ENCRYPT_MODE, key, params, random); 938 } 939 940 @Override encrypt(byte contentType, ByteBuffer bb)941 public int encrypt(byte contentType, ByteBuffer bb) { 942 // add message authentication code 943 MAC signer = (MAC)authenticator; 944 if (signer.macAlg().size != 0) { 945 addMac(signer, bb, contentType); 946 } else { 947 authenticator.increaseSequenceNumber(); 948 } 949 950 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 951 SSLLogger.finest( 952 "Padded plaintext before ENCRYPTION", bb.duplicate()); 953 } 954 955 int len = bb.remaining(); 956 ByteBuffer dup = bb.duplicate(); 957 try { 958 if (len != cipher.update(dup, bb)) { 959 // catch BouncyCastle buffering error 960 throw new RuntimeException( 961 "Unexpected number of plaintext bytes"); 962 } 963 if (bb.position() != dup.position()) { 964 throw new RuntimeException( 965 "Unexpected ByteBuffer position"); 966 } 967 } catch (ShortBufferException sbe) { 968 // catch BouncyCastle buffering error 969 throw new RuntimeException("Cipher buffering error in " + 970 "JCE provider " + cipher.getProvider().getName(), sbe); 971 } 972 973 return len; 974 } 975 976 @Override dispose()977 void dispose() { 978 if (cipher != null) { 979 try { 980 cipher.doFinal(); 981 } catch (Exception e) { 982 // swallow all types of exceptions. 983 } 984 } 985 } 986 987 @Override getExplicitNonceSize()988 int getExplicitNonceSize() { 989 return 0; 990 } 991 992 @Override calculateFragmentSize(int packetLimit, int headerSize)993 int calculateFragmentSize(int packetLimit, int headerSize) { 994 int macLen = ((MAC)authenticator).macAlg().size; 995 return packetLimit - headerSize - macLen; 996 } 997 998 @Override calculatePacketSize(int fragmentSize, int headerSize)999 int calculatePacketSize(int fragmentSize, int headerSize) { 1000 int macLen = ((MAC)authenticator).macAlg().size; 1001 return fragmentSize + headerSize + macLen; 1002 } 1003 } 1004 } 1005 1006 private static final 1007 class T10BlockReadCipherGenerator implements ReadCipherGenerator { 1008 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1009 public SSLReadCipher createCipher(SSLCipher sslCipher, 1010 Authenticator authenticator, 1011 ProtocolVersion protocolVersion, String algorithm, 1012 Key key, AlgorithmParameterSpec params, 1013 SecureRandom random) throws GeneralSecurityException { 1014 return new BlockReadCipher(authenticator, 1015 protocolVersion, algorithm, key, params, random); 1016 } 1017 1018 static final class BlockReadCipher extends SSLReadCipher { 1019 private final Cipher cipher; 1020 BlockReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1021 BlockReadCipher(Authenticator authenticator, 1022 ProtocolVersion protocolVersion, String algorithm, 1023 Key key, AlgorithmParameterSpec params, 1024 SecureRandom random) throws GeneralSecurityException { 1025 super(authenticator, protocolVersion); 1026 this.cipher = JsseJce.getCipher(algorithm); 1027 cipher.init(Cipher.DECRYPT_MODE, key, params, random); 1028 } 1029 1030 @Override decrypt(byte contentType, ByteBuffer bb, byte[] sequence)1031 public Plaintext decrypt(byte contentType, ByteBuffer bb, 1032 byte[] sequence) throws GeneralSecurityException { 1033 BadPaddingException reservedBPE = null; 1034 1035 // sanity check length of the ciphertext 1036 MAC signer = (MAC)authenticator; 1037 int cipheredLength = bb.remaining(); 1038 int tagLen = signer.macAlg().size; 1039 if (tagLen != 0) { 1040 if (!sanityCheck(tagLen, bb.remaining())) { 1041 reservedBPE = new BadPaddingException( 1042 "ciphertext sanity check failed"); 1043 } 1044 } 1045 // decryption 1046 int len = bb.remaining(); 1047 int pos = bb.position(); 1048 ByteBuffer dup = bb.duplicate(); 1049 try { 1050 if (len != cipher.update(dup, bb)) { 1051 // catch BouncyCastle buffering error 1052 throw new RuntimeException( 1053 "Unexpected number of plaintext bytes"); 1054 } 1055 1056 if (bb.position() != dup.position()) { 1057 throw new RuntimeException( 1058 "Unexpected ByteBuffer position"); 1059 } 1060 } catch (ShortBufferException sbe) { 1061 // catch BouncyCastle buffering error 1062 throw new RuntimeException("Cipher buffering error in " + 1063 "JCE provider " + cipher.getProvider().getName(), sbe); 1064 } 1065 1066 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 1067 SSLLogger.fine( 1068 "Padded plaintext after DECRYPTION", 1069 bb.duplicate().position(pos)); 1070 } 1071 1072 // remove the block padding 1073 int blockSize = cipher.getBlockSize(); 1074 bb.position(pos); 1075 try { 1076 removePadding(bb, tagLen, blockSize, protocolVersion); 1077 } catch (BadPaddingException bpe) { 1078 if (reservedBPE == null) { 1079 reservedBPE = bpe; 1080 } 1081 } 1082 1083 // Requires message authentication code for null, stream and 1084 // block cipher suites. 1085 try { 1086 if (tagLen != 0) { 1087 checkCBCMac(signer, bb, 1088 contentType, cipheredLength, sequence); 1089 } else { 1090 authenticator.increaseSequenceNumber(); 1091 } 1092 } catch (BadPaddingException bpe) { 1093 if (reservedBPE == null) { 1094 reservedBPE = bpe; 1095 } 1096 } 1097 1098 // Is it a failover? 1099 if (reservedBPE != null) { 1100 throw reservedBPE; 1101 } 1102 1103 return new Plaintext(contentType, 1104 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, 1105 -1, -1L, bb.slice()); 1106 } 1107 1108 @Override dispose()1109 void dispose() { 1110 if (cipher != null) { 1111 try { 1112 cipher.doFinal(); 1113 } catch (Exception e) { 1114 // swallow all types of exceptions. 1115 } 1116 } 1117 } 1118 1119 @Override estimateFragmentSize(int packetSize, int headerSize)1120 int estimateFragmentSize(int packetSize, int headerSize) { 1121 int macLen = ((MAC)authenticator).macAlg().size; 1122 1123 // No padding for a maximum fragment. 1124 // 1125 // 1 byte padding length field: 0x00 1126 return packetSize - headerSize - macLen - 1; 1127 } 1128 1129 /** 1130 * Sanity check the length of a fragment before decryption. 1131 * 1132 * In CBC mode, check that the fragment length is one or multiple 1133 * times of the block size of the cipher suite, and is at least 1134 * one (one is the smallest size of padding in CBC mode) bigger 1135 * than the tag size of the MAC algorithm except the explicit IV 1136 * size for TLS 1.1 or later. 1137 * 1138 * In non-CBC mode, check that the fragment length is not less than 1139 * the tag size of the MAC algorithm. 1140 * 1141 * @return true if the length of a fragment matches above 1142 * requirements 1143 */ sanityCheck(int tagLen, int fragmentLen)1144 private boolean sanityCheck(int tagLen, int fragmentLen) { 1145 int blockSize = cipher.getBlockSize(); 1146 if ((fragmentLen % blockSize) == 0) { 1147 int minimal = tagLen + 1; 1148 minimal = (minimal >= blockSize) ? minimal : blockSize; 1149 1150 return (fragmentLen >= minimal); 1151 } 1152 1153 return false; 1154 } 1155 } 1156 } 1157 1158 private static final 1159 class T10BlockWriteCipherGenerator implements WriteCipherGenerator { 1160 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1161 public SSLWriteCipher createCipher(SSLCipher sslCipher, 1162 Authenticator authenticator, 1163 ProtocolVersion protocolVersion, String algorithm, 1164 Key key, AlgorithmParameterSpec params, 1165 SecureRandom random) throws GeneralSecurityException { 1166 return new BlockWriteCipher(authenticator, 1167 protocolVersion, algorithm, key, params, random); 1168 } 1169 1170 static final class BlockWriteCipher extends SSLWriteCipher { 1171 private final Cipher cipher; 1172 BlockWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1173 BlockWriteCipher(Authenticator authenticator, 1174 ProtocolVersion protocolVersion, String algorithm, 1175 Key key, AlgorithmParameterSpec params, 1176 SecureRandom random) throws GeneralSecurityException { 1177 super(authenticator, protocolVersion); 1178 this.cipher = JsseJce.getCipher(algorithm); 1179 cipher.init(Cipher.ENCRYPT_MODE, key, params, random); 1180 } 1181 1182 @Override encrypt(byte contentType, ByteBuffer bb)1183 public int encrypt(byte contentType, ByteBuffer bb) { 1184 int pos = bb.position(); 1185 1186 // add message authentication code 1187 MAC signer = (MAC)authenticator; 1188 if (signer.macAlg().size != 0) { 1189 addMac(signer, bb, contentType); 1190 } else { 1191 authenticator.increaseSequenceNumber(); 1192 } 1193 1194 int blockSize = cipher.getBlockSize(); 1195 int len = addPadding(bb, blockSize); 1196 bb.position(pos); 1197 1198 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 1199 SSLLogger.fine( 1200 "Padded plaintext before ENCRYPTION", 1201 bb.duplicate()); 1202 } 1203 1204 ByteBuffer dup = bb.duplicate(); 1205 try { 1206 if (len != cipher.update(dup, bb)) { 1207 // catch BouncyCastle buffering error 1208 throw new RuntimeException( 1209 "Unexpected number of plaintext bytes"); 1210 } 1211 1212 if (bb.position() != dup.position()) { 1213 throw new RuntimeException( 1214 "Unexpected ByteBuffer position"); 1215 } 1216 } catch (ShortBufferException sbe) { 1217 // catch BouncyCastle buffering error 1218 throw new RuntimeException("Cipher buffering error in " + 1219 "JCE provider " + cipher.getProvider().getName(), sbe); 1220 } 1221 1222 return len; 1223 } 1224 1225 @Override dispose()1226 void dispose() { 1227 if (cipher != null) { 1228 try { 1229 cipher.doFinal(); 1230 } catch (Exception e) { 1231 // swallow all types of exceptions. 1232 } 1233 } 1234 } 1235 1236 @Override getExplicitNonceSize()1237 int getExplicitNonceSize() { 1238 return 0; 1239 } 1240 1241 @Override calculateFragmentSize(int packetLimit, int headerSize)1242 int calculateFragmentSize(int packetLimit, int headerSize) { 1243 int macLen = ((MAC)authenticator).macAlg().size; 1244 int blockSize = cipher.getBlockSize(); 1245 int fragLen = packetLimit - headerSize; 1246 fragLen -= (fragLen % blockSize); // cannot hold a block 1247 // No padding for a maximum fragment. 1248 fragLen -= 1; // 1 byte padding length field: 0x00 1249 fragLen -= macLen; 1250 return fragLen; 1251 } 1252 1253 @Override calculatePacketSize(int fragmentSize, int headerSize)1254 int calculatePacketSize(int fragmentSize, int headerSize) { 1255 int macLen = ((MAC)authenticator).macAlg().size; 1256 int blockSize = cipher.getBlockSize(); 1257 int paddedLen = fragmentSize + macLen + 1; 1258 if ((paddedLen % blockSize) != 0) { 1259 paddedLen += blockSize - 1; 1260 paddedLen -= paddedLen % blockSize; 1261 } 1262 1263 return headerSize + paddedLen; 1264 } 1265 1266 @Override isCBCMode()1267 boolean isCBCMode() { 1268 return true; 1269 } 1270 } 1271 } 1272 1273 // For TLS 1.1 and 1.2 1274 private static final 1275 class T11BlockReadCipherGenerator implements ReadCipherGenerator { 1276 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1277 public SSLReadCipher createCipher(SSLCipher sslCipher, 1278 Authenticator authenticator, ProtocolVersion protocolVersion, 1279 String algorithm, Key key, AlgorithmParameterSpec params, 1280 SecureRandom random) throws GeneralSecurityException { 1281 return new BlockReadCipher(authenticator, protocolVersion, 1282 sslCipher, algorithm, key, params, random); 1283 } 1284 1285 static final class BlockReadCipher extends SSLReadCipher { 1286 private final Cipher cipher; 1287 BlockReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1288 BlockReadCipher(Authenticator authenticator, 1289 ProtocolVersion protocolVersion, 1290 SSLCipher sslCipher, String algorithm, 1291 Key key, AlgorithmParameterSpec params, 1292 SecureRandom random) throws GeneralSecurityException { 1293 super(authenticator, protocolVersion); 1294 this.cipher = JsseJce.getCipher(algorithm); 1295 if (params == null) { 1296 params = new IvParameterSpec(new byte[sslCipher.ivSize]); 1297 } 1298 cipher.init(Cipher.DECRYPT_MODE, key, params, random); 1299 } 1300 1301 @Override decrypt(byte contentType, ByteBuffer bb, byte[] sequence)1302 public Plaintext decrypt(byte contentType, ByteBuffer bb, 1303 byte[] sequence) throws GeneralSecurityException { 1304 BadPaddingException reservedBPE = null; 1305 1306 // sanity check length of the ciphertext 1307 MAC signer = (MAC)authenticator; 1308 int cipheredLength = bb.remaining(); 1309 int tagLen = signer.macAlg().size; 1310 if (tagLen != 0) { 1311 if (!sanityCheck(tagLen, bb.remaining())) { 1312 reservedBPE = new BadPaddingException( 1313 "ciphertext sanity check failed"); 1314 } 1315 } 1316 1317 // decryption 1318 int len = bb.remaining(); 1319 int pos = bb.position(); 1320 ByteBuffer dup = bb.duplicate(); 1321 try { 1322 if (len != cipher.update(dup, bb)) { 1323 // catch BouncyCastle buffering error 1324 throw new RuntimeException( 1325 "Unexpected number of plaintext bytes"); 1326 } 1327 1328 if (bb.position() != dup.position()) { 1329 throw new RuntimeException( 1330 "Unexpected ByteBuffer position"); 1331 } 1332 } catch (ShortBufferException sbe) { 1333 // catch BouncyCastle buffering error 1334 throw new RuntimeException("Cipher buffering error in " + 1335 "JCE provider " + cipher.getProvider().getName(), sbe); 1336 } 1337 1338 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 1339 SSLLogger.fine( 1340 "Padded plaintext after DECRYPTION", 1341 bb.duplicate().position(pos)); 1342 } 1343 1344 // Ignore the explicit nonce. 1345 bb.position(pos + cipher.getBlockSize()); 1346 pos = bb.position(); 1347 1348 // remove the block padding 1349 int blockSize = cipher.getBlockSize(); 1350 bb.position(pos); 1351 try { 1352 removePadding(bb, tagLen, blockSize, protocolVersion); 1353 } catch (BadPaddingException bpe) { 1354 if (reservedBPE == null) { 1355 reservedBPE = bpe; 1356 } 1357 } 1358 1359 // Requires message authentication code for null, stream and 1360 // block cipher suites. 1361 try { 1362 if (tagLen != 0) { 1363 checkCBCMac(signer, bb, 1364 contentType, cipheredLength, sequence); 1365 } else { 1366 authenticator.increaseSequenceNumber(); 1367 } 1368 } catch (BadPaddingException bpe) { 1369 if (reservedBPE == null) { 1370 reservedBPE = bpe; 1371 } 1372 } 1373 1374 // Is it a failover? 1375 if (reservedBPE != null) { 1376 throw reservedBPE; 1377 } 1378 1379 return new Plaintext(contentType, 1380 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, 1381 -1, -1L, bb.slice()); 1382 } 1383 1384 @Override dispose()1385 void dispose() { 1386 if (cipher != null) { 1387 try { 1388 cipher.doFinal(); 1389 } catch (Exception e) { 1390 // swallow all types of exceptions. 1391 } 1392 } 1393 } 1394 1395 @Override estimateFragmentSize(int packetSize, int headerSize)1396 int estimateFragmentSize(int packetSize, int headerSize) { 1397 int macLen = ((MAC)authenticator).macAlg().size; 1398 1399 // No padding for a maximum fragment. 1400 // 1401 // 1 byte padding length field: 0x00 1402 int nonceSize = cipher.getBlockSize(); 1403 return packetSize - headerSize - nonceSize - macLen - 1; 1404 } 1405 1406 /** 1407 * Sanity check the length of a fragment before decryption. 1408 * 1409 * In CBC mode, check that the fragment length is one or multiple 1410 * times of the block size of the cipher suite, and is at least 1411 * one (one is the smallest size of padding in CBC mode) bigger 1412 * than the tag size of the MAC algorithm except the explicit IV 1413 * size for TLS 1.1 or later. 1414 * 1415 * In non-CBC mode, check that the fragment length is not less than 1416 * the tag size of the MAC algorithm. 1417 * 1418 * @return true if the length of a fragment matches above 1419 * requirements 1420 */ sanityCheck(int tagLen, int fragmentLen)1421 private boolean sanityCheck(int tagLen, int fragmentLen) { 1422 int blockSize = cipher.getBlockSize(); 1423 if ((fragmentLen % blockSize) == 0) { 1424 int minimal = tagLen + 1; 1425 minimal = (minimal >= blockSize) ? minimal : blockSize; 1426 minimal += blockSize; 1427 1428 return (fragmentLen >= minimal); 1429 } 1430 1431 return false; 1432 } 1433 } 1434 } 1435 1436 // For TLS 1.1 and 1.2 1437 private static final 1438 class T11BlockWriteCipherGenerator implements WriteCipherGenerator { 1439 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1440 public SSLWriteCipher createCipher(SSLCipher sslCipher, 1441 Authenticator authenticator, ProtocolVersion protocolVersion, 1442 String algorithm, Key key, AlgorithmParameterSpec params, 1443 SecureRandom random) throws GeneralSecurityException { 1444 return new BlockWriteCipher(authenticator, protocolVersion, 1445 sslCipher, algorithm, key, params, random); 1446 } 1447 1448 static final class BlockWriteCipher extends SSLWriteCipher { 1449 private final Cipher cipher; 1450 private final SecureRandom random; 1451 BlockWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1452 BlockWriteCipher(Authenticator authenticator, 1453 ProtocolVersion protocolVersion, 1454 SSLCipher sslCipher, String algorithm, 1455 Key key, AlgorithmParameterSpec params, 1456 SecureRandom random) throws GeneralSecurityException { 1457 super(authenticator, protocolVersion); 1458 this.cipher = JsseJce.getCipher(algorithm); 1459 this.random = random; 1460 if (params == null) { 1461 params = new IvParameterSpec(new byte[sslCipher.ivSize]); 1462 } 1463 cipher.init(Cipher.ENCRYPT_MODE, key, params, random); 1464 } 1465 1466 @Override encrypt(byte contentType, ByteBuffer bb)1467 public int encrypt(byte contentType, ByteBuffer bb) { 1468 // To be unique and aware of overflow-wrap, sequence number 1469 // is used as the nonce_explicit of block cipher suites. 1470 int pos = bb.position(); 1471 1472 // add message authentication code 1473 MAC signer = (MAC)authenticator; 1474 if (signer.macAlg().size != 0) { 1475 addMac(signer, bb, contentType); 1476 } else { 1477 authenticator.increaseSequenceNumber(); 1478 } 1479 1480 // DON'T WORRY, the nonce spaces are considered already. 1481 byte[] nonce = new byte[cipher.getBlockSize()]; 1482 random.nextBytes(nonce); 1483 pos = pos - nonce.length; 1484 bb.position(pos); 1485 bb.put(nonce); 1486 bb.position(pos); 1487 1488 int blockSize = cipher.getBlockSize(); 1489 int len = addPadding(bb, blockSize); 1490 bb.position(pos); 1491 1492 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 1493 SSLLogger.fine( 1494 "Padded plaintext before ENCRYPTION", 1495 bb.duplicate()); 1496 } 1497 1498 ByteBuffer dup = bb.duplicate(); 1499 try { 1500 if (len != cipher.update(dup, bb)) { 1501 // catch BouncyCastle buffering error 1502 throw new RuntimeException( 1503 "Unexpected number of plaintext bytes"); 1504 } 1505 1506 if (bb.position() != dup.position()) { 1507 throw new RuntimeException( 1508 "Unexpected ByteBuffer position"); 1509 } 1510 } catch (ShortBufferException sbe) { 1511 // catch BouncyCastle buffering error 1512 throw new RuntimeException("Cipher buffering error in " + 1513 "JCE provider " + cipher.getProvider().getName(), sbe); 1514 } 1515 1516 return len; 1517 } 1518 1519 @Override dispose()1520 void dispose() { 1521 if (cipher != null) { 1522 try { 1523 cipher.doFinal(); 1524 } catch (Exception e) { 1525 // swallow all types of exceptions. 1526 } 1527 } 1528 } 1529 1530 @Override getExplicitNonceSize()1531 int getExplicitNonceSize() { 1532 return cipher.getBlockSize(); 1533 } 1534 1535 @Override calculateFragmentSize(int packetLimit, int headerSize)1536 int calculateFragmentSize(int packetLimit, int headerSize) { 1537 int macLen = ((MAC)authenticator).macAlg().size; 1538 int blockSize = cipher.getBlockSize(); 1539 int fragLen = packetLimit - headerSize - blockSize; 1540 fragLen -= (fragLen % blockSize); // cannot hold a block 1541 // No padding for a maximum fragment. 1542 fragLen -= 1; // 1 byte padding length field: 0x00 1543 fragLen -= macLen; 1544 return fragLen; 1545 } 1546 1547 @Override calculatePacketSize(int fragmentSize, int headerSize)1548 int calculatePacketSize(int fragmentSize, int headerSize) { 1549 int macLen = ((MAC)authenticator).macAlg().size; 1550 int blockSize = cipher.getBlockSize(); 1551 int paddedLen = fragmentSize + macLen + 1; 1552 if ((paddedLen % blockSize) != 0) { 1553 paddedLen += blockSize - 1; 1554 paddedLen -= paddedLen % blockSize; 1555 } 1556 1557 return headerSize + blockSize + paddedLen; 1558 } 1559 1560 @Override isCBCMode()1561 boolean isCBCMode() { 1562 return true; 1563 } 1564 } 1565 } 1566 1567 private static final 1568 class T12GcmReadCipherGenerator implements ReadCipherGenerator { 1569 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1570 public SSLReadCipher createCipher(SSLCipher sslCipher, 1571 Authenticator authenticator, 1572 ProtocolVersion protocolVersion, String algorithm, 1573 Key key, AlgorithmParameterSpec params, 1574 SecureRandom random) throws GeneralSecurityException { 1575 return new GcmReadCipher(authenticator, protocolVersion, sslCipher, 1576 algorithm, key, params, random); 1577 } 1578 1579 static final class GcmReadCipher extends SSLReadCipher { 1580 private final Cipher cipher; 1581 private final int tagSize; 1582 private final Key key; 1583 private final byte[] fixedIv; 1584 private final int recordIvSize; 1585 private final SecureRandom random; 1586 GcmReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1587 GcmReadCipher(Authenticator authenticator, 1588 ProtocolVersion protocolVersion, 1589 SSLCipher sslCipher, String algorithm, 1590 Key key, AlgorithmParameterSpec params, 1591 SecureRandom random) throws GeneralSecurityException { 1592 super(authenticator, protocolVersion); 1593 this.cipher = JsseJce.getCipher(algorithm); 1594 this.tagSize = sslCipher.tagSize; 1595 this.key = key; 1596 this.fixedIv = ((IvParameterSpec)params).getIV(); 1597 this.recordIvSize = sslCipher.ivSize - sslCipher.fixedIvSize; 1598 this.random = random; 1599 1600 // DON'T initialize the cipher for AEAD! 1601 } 1602 1603 @Override decrypt(byte contentType, ByteBuffer bb, byte[] sequence)1604 public Plaintext decrypt(byte contentType, ByteBuffer bb, 1605 byte[] sequence) throws GeneralSecurityException { 1606 if (bb.remaining() < (recordIvSize + tagSize)) { 1607 throw new BadPaddingException( 1608 "Insufficient buffer remaining for AEAD cipher " + 1609 "fragment (" + bb.remaining() + "). Needs to be " + 1610 "more than or equal to IV size (" + recordIvSize + 1611 ") + tag size (" + tagSize + ")"); 1612 } 1613 1614 // initialize the AEAD cipher for the unique IV 1615 byte[] iv = Arrays.copyOf(fixedIv, 1616 fixedIv.length + recordIvSize); 1617 bb.get(iv, fixedIv.length, recordIvSize); 1618 GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); 1619 try { 1620 cipher.init(Cipher.DECRYPT_MODE, key, spec, random); 1621 } catch (InvalidKeyException | 1622 InvalidAlgorithmParameterException ikae) { 1623 // unlikely to happen 1624 throw new RuntimeException( 1625 "invalid key or spec in GCM mode", ikae); 1626 } 1627 1628 // update the additional authentication data 1629 byte[] aad = authenticator.acquireAuthenticationBytes( 1630 contentType, bb.remaining() - tagSize, 1631 sequence); 1632 cipher.updateAAD(aad); 1633 1634 // DON'T decrypt the nonce_explicit for AEAD mode. The buffer 1635 // position has moved out of the nonce_explicit range. 1636 int len, pos = bb.position(); 1637 ByteBuffer dup = bb.duplicate(); 1638 try { 1639 len = cipher.doFinal(dup, bb); 1640 } catch (IllegalBlockSizeException ibse) { 1641 // unlikely to happen 1642 throw new RuntimeException( 1643 "Cipher error in AEAD mode \"" + ibse.getMessage() + 1644 " \"in JCE provider " + cipher.getProvider().getName()); 1645 } catch (ShortBufferException sbe) { 1646 // catch BouncyCastle buffering error 1647 throw new RuntimeException("Cipher buffering error in " + 1648 "JCE provider " + cipher.getProvider().getName(), sbe); 1649 } 1650 // reset the limit to the end of the decrypted data 1651 bb.position(pos); 1652 bb.limit(pos + len); 1653 1654 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 1655 SSLLogger.fine( 1656 "Plaintext after DECRYPTION", bb.duplicate()); 1657 } 1658 1659 return new Plaintext(contentType, 1660 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, 1661 -1, -1L, bb.slice()); 1662 } 1663 1664 @Override dispose()1665 void dispose() { 1666 if (cipher != null) { 1667 try { 1668 cipher.doFinal(); 1669 } catch (Exception e) { 1670 // swallow all types of exceptions. 1671 } 1672 } 1673 } 1674 1675 @Override estimateFragmentSize(int packetSize, int headerSize)1676 int estimateFragmentSize(int packetSize, int headerSize) { 1677 return packetSize - headerSize - recordIvSize - tagSize; 1678 } 1679 } 1680 } 1681 1682 private static final 1683 class T12GcmWriteCipherGenerator implements WriteCipherGenerator { 1684 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1685 public SSLWriteCipher createCipher(SSLCipher sslCipher, 1686 Authenticator authenticator, 1687 ProtocolVersion protocolVersion, String algorithm, 1688 Key key, AlgorithmParameterSpec params, 1689 SecureRandom random) throws GeneralSecurityException { 1690 return new GcmWriteCipher(authenticator, protocolVersion, sslCipher, 1691 algorithm, key, params, random); 1692 } 1693 1694 private static final class GcmWriteCipher extends SSLWriteCipher { 1695 private final Cipher cipher; 1696 private final int tagSize; 1697 private final Key key; 1698 private final byte[] fixedIv; 1699 private final int recordIvSize; 1700 private final SecureRandom random; 1701 GcmWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1702 GcmWriteCipher(Authenticator authenticator, 1703 ProtocolVersion protocolVersion, 1704 SSLCipher sslCipher, String algorithm, 1705 Key key, AlgorithmParameterSpec params, 1706 SecureRandom random) throws GeneralSecurityException { 1707 super(authenticator, protocolVersion); 1708 this.cipher = JsseJce.getCipher(algorithm); 1709 this.tagSize = sslCipher.tagSize; 1710 this.key = key; 1711 this.fixedIv = ((IvParameterSpec)params).getIV(); 1712 this.recordIvSize = sslCipher.ivSize - sslCipher.fixedIvSize; 1713 this.random = random; 1714 1715 // DON'T initialize the cipher for AEAD! 1716 } 1717 1718 @Override encrypt(byte contentType, ByteBuffer bb)1719 public int encrypt(byte contentType, 1720 ByteBuffer bb) { 1721 // To be unique and aware of overflow-wrap, sequence number 1722 // is used as the nonce_explicit of AEAD cipher suites. 1723 byte[] nonce = authenticator.sequenceNumber(); 1724 1725 // initialize the AEAD cipher for the unique IV 1726 byte[] iv = Arrays.copyOf(fixedIv, 1727 fixedIv.length + nonce.length); 1728 System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length); 1729 1730 GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); 1731 try { 1732 cipher.init(Cipher.ENCRYPT_MODE, key, spec, random); 1733 } catch (InvalidKeyException | 1734 InvalidAlgorithmParameterException ikae) { 1735 // unlikely to happen 1736 throw new RuntimeException( 1737 "invalid key or spec in GCM mode", ikae); 1738 } 1739 1740 // Update the additional authentication data, using the 1741 // implicit sequence number of the authenticator. 1742 byte[] aad = authenticator.acquireAuthenticationBytes( 1743 contentType, bb.remaining(), null); 1744 cipher.updateAAD(aad); 1745 1746 // DON'T WORRY, the nonce spaces are considered already. 1747 bb.position(bb.position() - nonce.length); 1748 bb.put(nonce); 1749 1750 // DON'T encrypt the nonce for AEAD mode. 1751 int len, pos = bb.position(); 1752 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 1753 SSLLogger.fine( 1754 "Plaintext before ENCRYPTION", 1755 bb.duplicate()); 1756 } 1757 1758 ByteBuffer dup = bb.duplicate(); 1759 int outputSize = cipher.getOutputSize(dup.remaining()); 1760 if (outputSize > bb.remaining()) { 1761 // Need to expand the limit of the output buffer for 1762 // the authentication tag. 1763 // 1764 // DON'T worry about the buffer's capacity, we have 1765 // reserved space for the authentication tag. 1766 bb.limit(pos + outputSize); 1767 } 1768 1769 try { 1770 len = cipher.doFinal(dup, bb); 1771 } catch (IllegalBlockSizeException | 1772 BadPaddingException | ShortBufferException ibse) { 1773 // unlikely to happen 1774 throw new RuntimeException( 1775 "Cipher error in AEAD mode in JCE provider " + 1776 cipher.getProvider().getName(), ibse); 1777 } 1778 1779 if (len != outputSize) { 1780 throw new RuntimeException( 1781 "Cipher buffering error in JCE provider " + 1782 cipher.getProvider().getName()); 1783 } 1784 1785 return len + nonce.length; 1786 } 1787 1788 @Override dispose()1789 void dispose() { 1790 if (cipher != null) { 1791 try { 1792 cipher.doFinal(); 1793 } catch (Exception e) { 1794 // swallow all types of exceptions. 1795 } 1796 } 1797 } 1798 1799 @Override getExplicitNonceSize()1800 int getExplicitNonceSize() { 1801 return recordIvSize; 1802 } 1803 1804 @Override calculateFragmentSize(int packetLimit, int headerSize)1805 int calculateFragmentSize(int packetLimit, int headerSize) { 1806 return packetLimit - headerSize - recordIvSize - tagSize; 1807 } 1808 1809 @Override calculatePacketSize(int fragmentSize, int headerSize)1810 int calculatePacketSize(int fragmentSize, int headerSize) { 1811 return fragmentSize + headerSize + recordIvSize + tagSize; 1812 } 1813 } 1814 } 1815 1816 private static final 1817 class T13GcmReadCipherGenerator implements ReadCipherGenerator { 1818 1819 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1820 public SSLReadCipher createCipher(SSLCipher sslCipher, 1821 Authenticator authenticator, ProtocolVersion protocolVersion, 1822 String algorithm, Key key, AlgorithmParameterSpec params, 1823 SecureRandom random) throws GeneralSecurityException { 1824 return new GcmReadCipher(authenticator, protocolVersion, sslCipher, 1825 algorithm, key, params, random); 1826 } 1827 1828 static final class GcmReadCipher extends SSLReadCipher { 1829 private final Cipher cipher; 1830 private final int tagSize; 1831 private final Key key; 1832 private final byte[] iv; 1833 private final SecureRandom random; 1834 GcmReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1835 GcmReadCipher(Authenticator authenticator, 1836 ProtocolVersion protocolVersion, 1837 SSLCipher sslCipher, String algorithm, 1838 Key key, AlgorithmParameterSpec params, 1839 SecureRandom random) throws GeneralSecurityException { 1840 super(authenticator, protocolVersion); 1841 this.cipher = JsseJce.getCipher(algorithm); 1842 this.tagSize = sslCipher.tagSize; 1843 this.key = key; 1844 this.iv = ((IvParameterSpec)params).getIV(); 1845 this.random = random; 1846 1847 keyLimitCountdown = cipherLimits.getOrDefault( 1848 algorithm.toUpperCase() + ":" + tag[0], 0L); 1849 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 1850 SSLLogger.fine("KeyLimit read side: algorithm = " + 1851 algorithm.toUpperCase() + ":" + tag[0] + 1852 "\ncountdown value = " + keyLimitCountdown); 1853 } 1854 if (keyLimitCountdown > 0) { 1855 keyLimitEnabled = true; 1856 } 1857 // DON'T initialize the cipher for AEAD! 1858 } 1859 1860 @Override decrypt(byte contentType, ByteBuffer bb, byte[] sequence)1861 public Plaintext decrypt(byte contentType, ByteBuffer bb, 1862 byte[] sequence) throws GeneralSecurityException { 1863 // An implementation may receive an unencrypted record of type 1864 // change_cipher_spec consisting of the single byte value 0x01 1865 // at any time after the first ClientHello message has been 1866 // sent or received and before the peer's Finished message has 1867 // been received and MUST simply drop it without further 1868 // processing. 1869 if (contentType == ContentType.CHANGE_CIPHER_SPEC.id) { 1870 return new Plaintext(contentType, 1871 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, 1872 -1, -1L, bb.slice()); 1873 } 1874 1875 if (bb.remaining() <= tagSize) { 1876 throw new BadPaddingException( 1877 "Insufficient buffer remaining for AEAD cipher " + 1878 "fragment (" + bb.remaining() + "). Needs to be " + 1879 "more than tag size (" + tagSize + ")"); 1880 } 1881 1882 byte[] sn = sequence; 1883 if (sn == null) { 1884 sn = authenticator.sequenceNumber(); 1885 } 1886 byte[] nonce = iv.clone(); 1887 int offset = nonce.length - sn.length; 1888 for (int i = 0; i < sn.length; i++) { 1889 nonce[offset + i] ^= sn[i]; 1890 } 1891 1892 // initialize the AEAD cipher for the unique IV 1893 GCMParameterSpec spec = 1894 new GCMParameterSpec(tagSize * 8, nonce); 1895 try { 1896 cipher.init(Cipher.DECRYPT_MODE, key, spec, random); 1897 } catch (InvalidKeyException | 1898 InvalidAlgorithmParameterException ikae) { 1899 // unlikely to happen 1900 throw new RuntimeException( 1901 "invalid key or spec in GCM mode", ikae); 1902 } 1903 1904 // Update the additional authentication data, using the 1905 // implicit sequence number of the authenticator. 1906 byte[] aad = authenticator.acquireAuthenticationBytes( 1907 contentType, bb.remaining(), sn); 1908 cipher.updateAAD(aad); 1909 1910 int len, pos = bb.position(); 1911 ByteBuffer dup = bb.duplicate(); 1912 try { 1913 len = cipher.doFinal(dup, bb); 1914 } catch (IllegalBlockSizeException ibse) { 1915 // unlikely to happen 1916 throw new RuntimeException( 1917 "Cipher error in AEAD mode \"" + ibse.getMessage() + 1918 " \"in JCE provider " + cipher.getProvider().getName()); 1919 } catch (ShortBufferException sbe) { 1920 // catch BouncyCastle buffering error 1921 throw new RuntimeException("Cipher buffering error in " + 1922 "JCE provider " + cipher.getProvider().getName(), sbe); 1923 } 1924 // reset the limit to the end of the decrypted data 1925 bb.position(pos); 1926 bb.limit(pos + len); 1927 1928 // remove inner plaintext padding 1929 int i = bb.limit() - 1; 1930 for (; i > 0 && bb.get(i) == 0; i--) { 1931 // blank 1932 } 1933 if (i < (pos + 1)) { 1934 throw new BadPaddingException( 1935 "Incorrect inner plaintext: no content type"); 1936 } 1937 contentType = bb.get(i); 1938 bb.limit(i); 1939 1940 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 1941 SSLLogger.fine( 1942 "Plaintext after DECRYPTION", bb.duplicate()); 1943 } 1944 if (keyLimitEnabled) { 1945 keyLimitCountdown -= len; 1946 } 1947 1948 return new Plaintext(contentType, 1949 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, 1950 -1, -1L, bb.slice()); 1951 } 1952 1953 @Override dispose()1954 void dispose() { 1955 if (cipher != null) { 1956 try { 1957 cipher.doFinal(); 1958 } catch (Exception e) { 1959 // swallow all types of exceptions. 1960 } 1961 } 1962 } 1963 1964 @Override estimateFragmentSize(int packetSize, int headerSize)1965 int estimateFragmentSize(int packetSize, int headerSize) { 1966 return packetSize - headerSize - tagSize; 1967 } 1968 } 1969 } 1970 1971 private static final 1972 class T13GcmWriteCipherGenerator implements WriteCipherGenerator { 1973 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1974 public SSLWriteCipher createCipher(SSLCipher sslCipher, 1975 Authenticator authenticator, ProtocolVersion protocolVersion, 1976 String algorithm, Key key, AlgorithmParameterSpec params, 1977 SecureRandom random) throws GeneralSecurityException { 1978 return new GcmWriteCipher(authenticator, protocolVersion, sslCipher, 1979 algorithm, key, params, random); 1980 } 1981 1982 private static final class GcmWriteCipher extends SSLWriteCipher { 1983 private final Cipher cipher; 1984 private final int tagSize; 1985 private final Key key; 1986 private final byte[] iv; 1987 private final SecureRandom random; 1988 GcmWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)1989 GcmWriteCipher(Authenticator authenticator, 1990 ProtocolVersion protocolVersion, 1991 SSLCipher sslCipher, String algorithm, 1992 Key key, AlgorithmParameterSpec params, 1993 SecureRandom random) throws GeneralSecurityException { 1994 super(authenticator, protocolVersion); 1995 this.cipher = JsseJce.getCipher(algorithm); 1996 this.tagSize = sslCipher.tagSize; 1997 this.key = key; 1998 this.iv = ((IvParameterSpec)params).getIV(); 1999 this.random = random; 2000 2001 keyLimitCountdown = cipherLimits.getOrDefault( 2002 algorithm.toUpperCase() + ":" + tag[0], 0L); 2003 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 2004 SSLLogger.fine("KeyLimit write side: algorithm = " 2005 + algorithm.toUpperCase() + ":" + tag[0] + 2006 "\ncountdown value = " + keyLimitCountdown); 2007 } 2008 if (keyLimitCountdown > 0) { 2009 keyLimitEnabled = true; 2010 } 2011 2012 // DON'T initialize the cipher for AEAD! 2013 } 2014 2015 @Override encrypt(byte contentType, ByteBuffer bb)2016 public int encrypt(byte contentType, 2017 ByteBuffer bb) { 2018 byte[] sn = authenticator.sequenceNumber(); 2019 byte[] nonce = iv.clone(); 2020 int offset = nonce.length - sn.length; 2021 for (int i = 0; i < sn.length; i++) { 2022 nonce[offset + i] ^= sn[i]; 2023 } 2024 2025 // initialize the AEAD cipher for the unique IV 2026 GCMParameterSpec spec = 2027 new GCMParameterSpec(tagSize * 8, nonce); 2028 try { 2029 cipher.init(Cipher.ENCRYPT_MODE, key, spec, random); 2030 } catch (InvalidKeyException | 2031 InvalidAlgorithmParameterException ikae) { 2032 // unlikely to happen 2033 throw new RuntimeException( 2034 "invalid key or spec in GCM mode", ikae); 2035 } 2036 2037 // Update the additional authentication data, using the 2038 // implicit sequence number of the authenticator. 2039 int outputSize = cipher.getOutputSize(bb.remaining()); 2040 byte[] aad = authenticator.acquireAuthenticationBytes( 2041 contentType, outputSize, sn); 2042 cipher.updateAAD(aad); 2043 2044 int len, pos = bb.position(); 2045 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 2046 SSLLogger.fine( 2047 "Plaintext before ENCRYPTION", 2048 bb.duplicate()); 2049 } 2050 2051 ByteBuffer dup = bb.duplicate(); 2052 if (outputSize > bb.remaining()) { 2053 // Need to expand the limit of the output buffer for 2054 // the authentication tag. 2055 // 2056 // DON'T worry about the buffer's capacity, we have 2057 // reserved space for the authentication tag. 2058 bb.limit(pos + outputSize); 2059 } 2060 2061 try { 2062 len = cipher.doFinal(dup, bb); 2063 } catch (IllegalBlockSizeException | 2064 BadPaddingException | ShortBufferException ibse) { 2065 // unlikely to happen 2066 throw new RuntimeException( 2067 "Cipher error in AEAD mode in JCE provider " + 2068 cipher.getProvider().getName(), ibse); 2069 } 2070 2071 if (len != outputSize) { 2072 throw new RuntimeException( 2073 "Cipher buffering error in JCE provider " + 2074 cipher.getProvider().getName()); 2075 } 2076 2077 if (keyLimitEnabled) { 2078 keyLimitCountdown -= len; 2079 } 2080 return len; 2081 } 2082 2083 @Override dispose()2084 void dispose() { 2085 if (cipher != null) { 2086 try { 2087 cipher.doFinal(); 2088 } catch (Exception e) { 2089 // swallow all types of exceptions. 2090 } 2091 } 2092 } 2093 2094 @Override getExplicitNonceSize()2095 int getExplicitNonceSize() { 2096 return 0; 2097 } 2098 2099 @Override calculateFragmentSize(int packetLimit, int headerSize)2100 int calculateFragmentSize(int packetLimit, int headerSize) { 2101 return packetLimit - headerSize - tagSize; 2102 } 2103 2104 @Override calculatePacketSize(int fragmentSize, int headerSize)2105 int calculatePacketSize(int fragmentSize, int headerSize) { 2106 return fragmentSize + headerSize + tagSize; 2107 } 2108 } 2109 } 2110 2111 private static final class T12CC20P1305ReadCipherGenerator 2112 implements ReadCipherGenerator { 2113 2114 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)2115 public SSLReadCipher createCipher(SSLCipher sslCipher, 2116 Authenticator authenticator, ProtocolVersion protocolVersion, 2117 String algorithm, Key key, AlgorithmParameterSpec params, 2118 SecureRandom random) throws GeneralSecurityException { 2119 return new CC20P1305ReadCipher(authenticator, protocolVersion, 2120 sslCipher, algorithm, key, params, random); 2121 } 2122 2123 static final class CC20P1305ReadCipher extends SSLReadCipher { 2124 private final Cipher cipher; 2125 private final int tagSize; 2126 private final Key key; 2127 private final byte[] iv; 2128 private final SecureRandom random; 2129 CC20P1305ReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)2130 CC20P1305ReadCipher(Authenticator authenticator, 2131 ProtocolVersion protocolVersion, 2132 SSLCipher sslCipher, String algorithm, 2133 Key key, AlgorithmParameterSpec params, 2134 SecureRandom random) throws GeneralSecurityException { 2135 super(authenticator, protocolVersion); 2136 this.cipher = JsseJce.getCipher(algorithm); 2137 this.tagSize = sslCipher.tagSize; 2138 this.key = key; 2139 this.iv = ((IvParameterSpec)params).getIV(); 2140 this.random = random; 2141 2142 // DON'T initialize the cipher for AEAD! 2143 } 2144 2145 @Override decrypt(byte contentType, ByteBuffer bb, byte[] sequence)2146 public Plaintext decrypt(byte contentType, ByteBuffer bb, 2147 byte[] sequence) throws GeneralSecurityException { 2148 if (bb.remaining() <= tagSize) { 2149 throw new BadPaddingException( 2150 "Insufficient buffer remaining for AEAD cipher " + 2151 "fragment (" + bb.remaining() + "). Needs to be " + 2152 "more than tag size (" + tagSize + ")"); 2153 } 2154 2155 byte[] sn = sequence; 2156 if (sn == null) { 2157 sn = authenticator.sequenceNumber(); 2158 } 2159 byte[] nonce = new byte[iv.length]; 2160 System.arraycopy(sn, 0, nonce, nonce.length - sn.length, 2161 sn.length); 2162 for (int i = 0; i < nonce.length; i++) { 2163 nonce[i] ^= iv[i]; 2164 } 2165 2166 // initialize the AEAD cipher with the unique IV 2167 AlgorithmParameterSpec spec = new IvParameterSpec(nonce); 2168 try { 2169 cipher.init(Cipher.DECRYPT_MODE, key, spec, random); 2170 } catch (InvalidKeyException | 2171 InvalidAlgorithmParameterException ikae) { 2172 // unlikely to happen 2173 throw new RuntimeException( 2174 "invalid key or spec in AEAD mode", ikae); 2175 } 2176 2177 // update the additional authentication data 2178 byte[] aad = authenticator.acquireAuthenticationBytes( 2179 contentType, bb.remaining() - tagSize, sequence); 2180 cipher.updateAAD(aad); 2181 2182 // DON'T decrypt the nonce_explicit for AEAD mode. The buffer 2183 // position has moved out of the nonce_explicit range. 2184 int len = bb.remaining(); 2185 int pos = bb.position(); 2186 ByteBuffer dup = bb.duplicate(); 2187 try { 2188 len = cipher.doFinal(dup, bb); 2189 } catch (IllegalBlockSizeException ibse) { 2190 // unlikely to happen 2191 throw new RuntimeException( 2192 "Cipher error in AEAD mode \"" + ibse.getMessage() + 2193 " \"in JCE provider " + cipher.getProvider().getName()); 2194 } catch (ShortBufferException sbe) { 2195 // catch BouncyCastle buffering error 2196 throw new RuntimeException("Cipher buffering error in " + 2197 "JCE provider " + cipher.getProvider().getName(), sbe); 2198 } 2199 // reset the limit to the end of the decrypted data 2200 bb.position(pos); 2201 bb.limit(pos + len); 2202 2203 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 2204 SSLLogger.fine( 2205 "Plaintext after DECRYPTION", bb.duplicate()); 2206 } 2207 2208 return new Plaintext(contentType, 2209 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, 2210 -1, -1L, bb.slice()); 2211 } 2212 2213 @Override dispose()2214 void dispose() { 2215 if (cipher != null) { 2216 try { 2217 cipher.doFinal(); 2218 } catch (Exception e) { 2219 // swallow all types of exceptions. 2220 } 2221 } 2222 } 2223 2224 @Override estimateFragmentSize(int packetSize, int headerSize)2225 int estimateFragmentSize(int packetSize, int headerSize) { 2226 return packetSize - headerSize - tagSize; 2227 } 2228 } 2229 } 2230 2231 private static final class T12CC20P1305WriteCipherGenerator 2232 implements WriteCipherGenerator { 2233 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)2234 public SSLWriteCipher createCipher(SSLCipher sslCipher, 2235 Authenticator authenticator, ProtocolVersion protocolVersion, 2236 String algorithm, Key key, AlgorithmParameterSpec params, 2237 SecureRandom random) throws GeneralSecurityException { 2238 return new CC20P1305WriteCipher(authenticator, protocolVersion, 2239 sslCipher, algorithm, key, params, random); 2240 } 2241 2242 private static final class CC20P1305WriteCipher extends SSLWriteCipher { 2243 private final Cipher cipher; 2244 private final int tagSize; 2245 private final Key key; 2246 private final byte[] iv; 2247 private final SecureRandom random; 2248 CC20P1305WriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)2249 CC20P1305WriteCipher(Authenticator authenticator, 2250 ProtocolVersion protocolVersion, 2251 SSLCipher sslCipher, String algorithm, 2252 Key key, AlgorithmParameterSpec params, 2253 SecureRandom random) throws GeneralSecurityException { 2254 super(authenticator, protocolVersion); 2255 this.cipher = JsseJce.getCipher(algorithm); 2256 this.tagSize = sslCipher.tagSize; 2257 this.key = key; 2258 this.iv = ((IvParameterSpec)params).getIV(); 2259 this.random = random; 2260 2261 keyLimitCountdown = cipherLimits.getOrDefault( 2262 algorithm.toUpperCase() + ":" + tag[0], 0L); 2263 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 2264 SSLLogger.fine("algorithm = " + algorithm.toUpperCase() + 2265 ":" + tag[0] + "\ncountdown value = " + 2266 keyLimitCountdown); 2267 } 2268 if (keyLimitCountdown > 0) { 2269 keyLimitEnabled = true; 2270 } 2271 2272 // DON'T initialize the cipher for AEAD! 2273 } 2274 2275 @Override encrypt(byte contentType, ByteBuffer bb)2276 public int encrypt(byte contentType, 2277 ByteBuffer bb) { 2278 byte[] sn = authenticator.sequenceNumber(); 2279 byte[] nonce = new byte[iv.length]; 2280 System.arraycopy(sn, 0, nonce, nonce.length - sn.length, 2281 sn.length); 2282 for (int i = 0; i < nonce.length; i++) { 2283 nonce[i] ^= iv[i]; 2284 } 2285 2286 // initialize the AEAD cipher for the unique IV 2287 AlgorithmParameterSpec spec = new IvParameterSpec(nonce); 2288 try { 2289 cipher.init(Cipher.ENCRYPT_MODE, key, spec, random); 2290 } catch (InvalidKeyException | 2291 InvalidAlgorithmParameterException ikae) { 2292 // unlikely to happen 2293 throw new RuntimeException( 2294 "invalid key or spec in AEAD mode", ikae); 2295 } 2296 2297 // Update the additional authentication data, using the 2298 // implicit sequence number of the authenticator. 2299 byte[] aad = authenticator.acquireAuthenticationBytes( 2300 contentType, bb.remaining(), null); 2301 cipher.updateAAD(aad); 2302 2303 // DON'T encrypt the nonce for AEAD mode. 2304 int len = bb.remaining(); 2305 int pos = bb.position(); 2306 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 2307 SSLLogger.fine( 2308 "Plaintext before ENCRYPTION", 2309 bb.duplicate()); 2310 } 2311 2312 ByteBuffer dup = bb.duplicate(); 2313 int outputSize = cipher.getOutputSize(dup.remaining()); 2314 if (outputSize > bb.remaining()) { 2315 // Need to expand the limit of the output buffer for 2316 // the authentication tag. 2317 // 2318 // DON'T worry about the buffer's capacity, we have 2319 // reserved space for the authentication tag. 2320 bb.limit(pos + outputSize); 2321 } 2322 2323 try { 2324 len = cipher.doFinal(dup, bb); 2325 } catch (IllegalBlockSizeException | 2326 BadPaddingException | ShortBufferException ibse) { 2327 // unlikely to happen 2328 throw new RuntimeException( 2329 "Cipher error in AEAD mode in JCE provider " + 2330 cipher.getProvider().getName(), ibse); 2331 } 2332 2333 if (len != outputSize) { 2334 throw new RuntimeException( 2335 "Cipher buffering error in JCE provider " + 2336 cipher.getProvider().getName()); 2337 } 2338 2339 return len; 2340 } 2341 2342 @Override dispose()2343 void dispose() { 2344 if (cipher != null) { 2345 try { 2346 cipher.doFinal(); 2347 } catch (Exception e) { 2348 // swallow all types of exceptions. 2349 } 2350 } 2351 } 2352 2353 @Override getExplicitNonceSize()2354 int getExplicitNonceSize() { 2355 return 0; 2356 } 2357 2358 @Override calculateFragmentSize(int packetLimit, int headerSize)2359 int calculateFragmentSize(int packetLimit, int headerSize) { 2360 return packetLimit - headerSize - tagSize; 2361 } 2362 2363 @Override calculatePacketSize(int fragmentSize, int headerSize)2364 int calculatePacketSize(int fragmentSize, int headerSize) { 2365 return fragmentSize + headerSize + tagSize; 2366 } 2367 } 2368 } 2369 2370 private static final class T13CC20P1305ReadCipherGenerator 2371 implements ReadCipherGenerator { 2372 2373 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)2374 public SSLReadCipher createCipher(SSLCipher sslCipher, 2375 Authenticator authenticator, ProtocolVersion protocolVersion, 2376 String algorithm, Key key, AlgorithmParameterSpec params, 2377 SecureRandom random) throws GeneralSecurityException { 2378 return new CC20P1305ReadCipher(authenticator, protocolVersion, 2379 sslCipher, algorithm, key, params, random); 2380 } 2381 2382 static final class CC20P1305ReadCipher extends SSLReadCipher { 2383 private final Cipher cipher; 2384 private final int tagSize; 2385 private final Key key; 2386 private final byte[] iv; 2387 private final SecureRandom random; 2388 CC20P1305ReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)2389 CC20P1305ReadCipher(Authenticator authenticator, 2390 ProtocolVersion protocolVersion, 2391 SSLCipher sslCipher, String algorithm, 2392 Key key, AlgorithmParameterSpec params, 2393 SecureRandom random) throws GeneralSecurityException { 2394 super(authenticator, protocolVersion); 2395 this.cipher = JsseJce.getCipher(algorithm); 2396 this.tagSize = sslCipher.tagSize; 2397 this.key = key; 2398 this.iv = ((IvParameterSpec)params).getIV(); 2399 this.random = random; 2400 2401 // DON'T initialize the cipher for AEAD! 2402 } 2403 2404 @Override decrypt(byte contentType, ByteBuffer bb, byte[] sequence)2405 public Plaintext decrypt(byte contentType, ByteBuffer bb, 2406 byte[] sequence) throws GeneralSecurityException { 2407 // An implementation may receive an unencrypted record of type 2408 // change_cipher_spec consisting of the single byte value 0x01 2409 // at any time after the first ClientHello message has been 2410 // sent or received and before the peer's Finished message has 2411 // been received and MUST simply drop it without further 2412 // processing. 2413 if (contentType == ContentType.CHANGE_CIPHER_SPEC.id) { 2414 return new Plaintext(contentType, 2415 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, 2416 -1, -1L, bb.slice()); 2417 } 2418 2419 if (bb.remaining() <= tagSize) { 2420 throw new BadPaddingException( 2421 "Insufficient buffer remaining for AEAD cipher " + 2422 "fragment (" + bb.remaining() + "). Needs to be " + 2423 "more than tag size (" + tagSize + ")"); 2424 } 2425 2426 byte[] sn = sequence; 2427 if (sn == null) { 2428 sn = authenticator.sequenceNumber(); 2429 } 2430 byte[] nonce = new byte[iv.length]; 2431 System.arraycopy(sn, 0, nonce, nonce.length - sn.length, 2432 sn.length); 2433 for (int i = 0; i < nonce.length; i++) { 2434 nonce[i] ^= iv[i]; 2435 } 2436 2437 // initialize the AEAD cipher with the unique IV 2438 AlgorithmParameterSpec spec = new IvParameterSpec(nonce); 2439 try { 2440 cipher.init(Cipher.DECRYPT_MODE, key, spec, random); 2441 } catch (InvalidKeyException | 2442 InvalidAlgorithmParameterException ikae) { 2443 // unlikely to happen 2444 throw new RuntimeException( 2445 "invalid key or spec in AEAD mode", ikae); 2446 } 2447 2448 // Update the additional authentication data, using the 2449 // implicit sequence number of the authenticator. 2450 byte[] aad = authenticator.acquireAuthenticationBytes( 2451 contentType, bb.remaining(), sn); 2452 cipher.updateAAD(aad); 2453 2454 int len = bb.remaining(); 2455 int pos = bb.position(); 2456 ByteBuffer dup = bb.duplicate(); 2457 try { 2458 len = cipher.doFinal(dup, bb); 2459 } catch (IllegalBlockSizeException ibse) { 2460 // unlikely to happen 2461 throw new RuntimeException( 2462 "Cipher error in AEAD mode \"" + ibse.getMessage() + 2463 " \"in JCE provider " + cipher.getProvider().getName()); 2464 } catch (ShortBufferException sbe) { 2465 // catch BouncyCastle buffering error 2466 throw new RuntimeException("Cipher buffering error in " + 2467 "JCE provider " + cipher.getProvider().getName(), sbe); 2468 } 2469 // reset the limit to the end of the decrypted data 2470 bb.position(pos); 2471 bb.limit(pos + len); 2472 2473 // remove inner plaintext padding 2474 int i = bb.limit() - 1; 2475 for (; i > 0 && bb.get(i) == 0; i--) { 2476 // blank 2477 } 2478 if (i < (pos + 1)) { 2479 throw new BadPaddingException( 2480 "Incorrect inner plaintext: no content type"); 2481 } 2482 contentType = bb.get(i); 2483 bb.limit(i); 2484 2485 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 2486 SSLLogger.fine( 2487 "Plaintext after DECRYPTION", bb.duplicate()); 2488 } 2489 2490 return new Plaintext(contentType, 2491 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, 2492 -1, -1L, bb.slice()); 2493 } 2494 2495 @Override dispose()2496 void dispose() { 2497 if (cipher != null) { 2498 try { 2499 cipher.doFinal(); 2500 } catch (Exception e) { 2501 // swallow all types of exceptions. 2502 } 2503 } 2504 } 2505 2506 @Override estimateFragmentSize(int packetSize, int headerSize)2507 int estimateFragmentSize(int packetSize, int headerSize) { 2508 return packetSize - headerSize - tagSize; 2509 } 2510 } 2511 } 2512 2513 private static final class T13CC20P1305WriteCipherGenerator 2514 implements WriteCipherGenerator { 2515 @Override createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)2516 public SSLWriteCipher createCipher(SSLCipher sslCipher, 2517 Authenticator authenticator, ProtocolVersion protocolVersion, 2518 String algorithm, Key key, AlgorithmParameterSpec params, 2519 SecureRandom random) throws GeneralSecurityException { 2520 return new CC20P1305WriteCipher(authenticator, protocolVersion, 2521 sslCipher, algorithm, key, params, random); 2522 } 2523 2524 private static final class CC20P1305WriteCipher extends SSLWriteCipher { 2525 private final Cipher cipher; 2526 private final int tagSize; 2527 private final Key key; 2528 private final byte[] iv; 2529 private final SecureRandom random; 2530 CC20P1305WriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)2531 CC20P1305WriteCipher(Authenticator authenticator, 2532 ProtocolVersion protocolVersion, 2533 SSLCipher sslCipher, String algorithm, 2534 Key key, AlgorithmParameterSpec params, 2535 SecureRandom random) throws GeneralSecurityException { 2536 super(authenticator, protocolVersion); 2537 this.cipher = JsseJce.getCipher(algorithm); 2538 this.tagSize = sslCipher.tagSize; 2539 this.key = key; 2540 this.iv = ((IvParameterSpec)params).getIV(); 2541 this.random = random; 2542 2543 keyLimitCountdown = cipherLimits.getOrDefault( 2544 algorithm.toUpperCase() + ":" + tag[0], 0L); 2545 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 2546 SSLLogger.fine("algorithm = " + algorithm.toUpperCase() + 2547 ":" + tag[0] + "\ncountdown value = " + 2548 keyLimitCountdown); 2549 } 2550 if (keyLimitCountdown > 0) { 2551 keyLimitEnabled = true; 2552 } 2553 2554 // DON'T initialize the cipher for AEAD! 2555 } 2556 2557 @Override encrypt(byte contentType, ByteBuffer bb)2558 public int encrypt(byte contentType, 2559 ByteBuffer bb) { 2560 byte[] sn = authenticator.sequenceNumber(); 2561 byte[] nonce = new byte[iv.length]; 2562 System.arraycopy(sn, 0, nonce, nonce.length - sn.length, 2563 sn.length); 2564 for (int i = 0; i < nonce.length; i++) { 2565 nonce[i] ^= iv[i]; 2566 } 2567 2568 // initialize the AEAD cipher for the unique IV 2569 AlgorithmParameterSpec spec = new IvParameterSpec(nonce); 2570 try { 2571 cipher.init(Cipher.ENCRYPT_MODE, key, spec, random); 2572 } catch (InvalidKeyException | 2573 InvalidAlgorithmParameterException ikae) { 2574 // unlikely to happen 2575 throw new RuntimeException( 2576 "invalid key or spec in AEAD mode", ikae); 2577 } 2578 2579 // Update the additional authentication data, using the 2580 // implicit sequence number of the authenticator. 2581 int outputSize = cipher.getOutputSize(bb.remaining()); 2582 byte[] aad = authenticator.acquireAuthenticationBytes( 2583 contentType, outputSize, sn); 2584 cipher.updateAAD(aad); 2585 2586 int len = bb.remaining(); 2587 int pos = bb.position(); 2588 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { 2589 SSLLogger.fine( 2590 "Plaintext before ENCRYPTION", 2591 bb.duplicate()); 2592 } 2593 2594 ByteBuffer dup = bb.duplicate(); 2595 if (outputSize > bb.remaining()) { 2596 // Need to expand the limit of the output buffer for 2597 // the authentication tag. 2598 // 2599 // DON'T worry about the buffer's capacity, we have 2600 // reserved space for the authentication tag. 2601 bb.limit(pos + outputSize); 2602 } 2603 2604 try { 2605 len = cipher.doFinal(dup, bb); 2606 } catch (IllegalBlockSizeException | 2607 BadPaddingException | ShortBufferException ibse) { 2608 // unlikely to happen 2609 throw new RuntimeException( 2610 "Cipher error in AEAD mode in JCE provider " + 2611 cipher.getProvider().getName(), ibse); 2612 } 2613 2614 if (len != outputSize) { 2615 throw new RuntimeException( 2616 "Cipher buffering error in JCE provider " + 2617 cipher.getProvider().getName()); 2618 } 2619 2620 if (keyLimitEnabled) { 2621 keyLimitCountdown -= len; 2622 } 2623 return len; 2624 } 2625 2626 @Override dispose()2627 void dispose() { 2628 if (cipher != null) { 2629 try { 2630 cipher.doFinal(); 2631 } catch (Exception e) { 2632 // swallow all types of exceptions. 2633 } 2634 } 2635 } 2636 2637 @Override getExplicitNonceSize()2638 int getExplicitNonceSize() { 2639 return 0; 2640 } 2641 2642 @Override calculateFragmentSize(int packetLimit, int headerSize)2643 int calculateFragmentSize(int packetLimit, int headerSize) { 2644 return packetLimit - headerSize - tagSize; 2645 } 2646 2647 @Override calculatePacketSize(int fragmentSize, int headerSize)2648 int calculatePacketSize(int fragmentSize, int headerSize) { 2649 return fragmentSize + headerSize + tagSize; 2650 } 2651 } 2652 } 2653 addMac(MAC signer, ByteBuffer destination, byte contentType)2654 private static void addMac(MAC signer, 2655 ByteBuffer destination, byte contentType) { 2656 if (signer.macAlg().size != 0) { 2657 int dstContent = destination.position(); 2658 byte[] hash = signer.compute(contentType, destination, false); 2659 2660 /* 2661 * position was advanced to limit in MAC compute above. 2662 * 2663 * Mark next area as writable (above layers should have 2664 * established that we have plenty of room), then write 2665 * out the hash. 2666 */ 2667 destination.limit(destination.limit() + hash.length); 2668 destination.put(hash); 2669 2670 // reset the position and limit 2671 destination.position(dstContent); 2672 } 2673 } 2674 2675 // for null and stream cipher checkStreamMac(MAC signer, ByteBuffer bb, byte contentType, byte[] sequence)2676 private static void checkStreamMac(MAC signer, ByteBuffer bb, 2677 byte contentType, byte[] sequence) throws BadPaddingException { 2678 int tagLen = signer.macAlg().size; 2679 2680 // Requires message authentication code for null, stream and 2681 // block cipher suites. 2682 if (tagLen != 0) { 2683 int contentLen = bb.remaining() - tagLen; 2684 if (contentLen < 0) { 2685 throw new BadPaddingException("bad record"); 2686 } 2687 2688 // Run MAC computation and comparison on the payload. 2689 // 2690 // MAC data would be stripped off during the check. 2691 if (checkMacTags(contentType, bb, signer, sequence, false)) { 2692 throw new BadPaddingException("bad record MAC"); 2693 } 2694 } 2695 } 2696 2697 // for CBC cipher checkCBCMac(MAC signer, ByteBuffer bb, byte contentType, int cipheredLength, byte[] sequence)2698 private static void checkCBCMac(MAC signer, ByteBuffer bb, 2699 byte contentType, int cipheredLength, 2700 byte[] sequence) throws BadPaddingException { 2701 BadPaddingException reservedBPE = null; 2702 int tagLen = signer.macAlg().size; 2703 int pos = bb.position(); 2704 2705 if (tagLen != 0) { 2706 int contentLen = bb.remaining() - tagLen; 2707 if (contentLen < 0) { 2708 reservedBPE = new BadPaddingException("bad record"); 2709 2710 // set offset of the dummy MAC 2711 contentLen = cipheredLength - tagLen; 2712 bb.limit(pos + cipheredLength); 2713 } 2714 2715 // Run MAC computation and comparison on the payload. 2716 // 2717 // MAC data would be stripped off during the check. 2718 if (checkMacTags(contentType, bb, signer, sequence, false)) { 2719 if (reservedBPE == null) { 2720 reservedBPE = 2721 new BadPaddingException("bad record MAC"); 2722 } 2723 } 2724 2725 // Run MAC computation and comparison on the remainder. 2726 int remainingLen = calculateRemainingLen( 2727 signer, cipheredLength, contentLen); 2728 2729 // NOTE: remainingLen may be bigger (less than 1 block of the 2730 // hash algorithm of the MAC) than the cipheredLength. 2731 // 2732 // Is it possible to use a static buffer, rather than allocate 2733 // it dynamically? 2734 remainingLen += signer.macAlg().size; 2735 ByteBuffer temporary = ByteBuffer.allocate(remainingLen); 2736 2737 // Won't need to worry about the result on the remainder. And 2738 // then we won't need to worry about what's actual data to 2739 // check MAC tag on. We start the check from the header of the 2740 // buffer so that we don't need to construct a new byte buffer. 2741 checkMacTags(contentType, temporary, signer, sequence, true); 2742 } 2743 2744 // Is it a failover? 2745 if (reservedBPE != null) { 2746 throw reservedBPE; 2747 } 2748 } 2749 2750 /* 2751 * Run MAC computation and comparison 2752 */ checkMacTags(byte contentType, ByteBuffer bb, MAC signer, byte[] sequence, boolean isSimulated)2753 private static boolean checkMacTags(byte contentType, ByteBuffer bb, 2754 MAC signer, byte[] sequence, boolean isSimulated) { 2755 int tagLen = signer.macAlg().size; 2756 int position = bb.position(); 2757 int lim = bb.limit(); 2758 int macOffset = lim - tagLen; 2759 2760 bb.limit(macOffset); 2761 byte[] hash = signer.compute(contentType, bb, sequence, isSimulated); 2762 if (hash == null || tagLen != hash.length) { 2763 // Something is wrong with MAC implementation. 2764 throw new RuntimeException("Internal MAC error"); 2765 } 2766 2767 bb.position(macOffset); 2768 bb.limit(lim); 2769 try { 2770 int[] results = compareMacTags(bb, hash); 2771 return (results[0] != 0); 2772 } finally { 2773 // reset to the data 2774 bb.position(position); 2775 bb.limit(macOffset); 2776 } 2777 } 2778 2779 /* 2780 * A constant-time comparison of the MAC tags. 2781 * 2782 * Please DON'T change the content of the ByteBuffer parameter! 2783 */ compareMacTags(ByteBuffer bb, byte[] tag)2784 private static int[] compareMacTags(ByteBuffer bb, byte[] tag) { 2785 // An array of hits is used to prevent Hotspot optimization for 2786 // the purpose of a constant-time check. 2787 int[] results = {0, 0}; // {missed #, matched #} 2788 2789 // The caller ensures there are enough bytes available in the buffer. 2790 // So we won't need to check the remaining of the buffer. 2791 for (byte t : tag) { 2792 if (bb.get() != t) { 2793 results[0]++; // mismatched bytes 2794 } else { 2795 results[1]++; // matched bytes 2796 } 2797 } 2798 2799 return results; 2800 } 2801 2802 /* 2803 * Calculate the length of a dummy buffer to run MAC computation 2804 * and comparison on the remainder. 2805 * 2806 * The caller MUST ensure that the fullLen is not less than usedLen. 2807 */ calculateRemainingLen( MAC signer, int fullLen, int usedLen)2808 private static int calculateRemainingLen( 2809 MAC signer, int fullLen, int usedLen) { 2810 2811 int blockLen = signer.macAlg().hashBlockSize; 2812 int minimalPaddingLen = signer.macAlg().minimalPaddingSize; 2813 2814 // (blockLen - minimalPaddingLen) is the maximum message size of 2815 // the last block of hash function operation. See FIPS 180-4, or 2816 // MD5 specification. 2817 fullLen += 13 - (blockLen - minimalPaddingLen); 2818 usedLen += 13 - (blockLen - minimalPaddingLen); 2819 2820 // Note: fullLen is always not less than usedLen, and blockLen 2821 // is always bigger than minimalPaddingLen, so we don't worry 2822 // about negative values. 0x01 is added to the result to ensure 2823 // that the return value is positive. The extra one byte does 2824 // not impact the overall MAC compression function evaluations. 2825 return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) - 2826 Math.ceil(usedLen/(1.0d * blockLen))) * blockLen; 2827 } 2828 addPadding(ByteBuffer bb, int blockSize)2829 private static int addPadding(ByteBuffer bb, int blockSize) { 2830 2831 int len = bb.remaining(); 2832 int offset = bb.position(); 2833 2834 int newlen = len + 1; 2835 byte pad; 2836 int i; 2837 2838 if ((newlen % blockSize) != 0) { 2839 newlen += blockSize - 1; 2840 newlen -= newlen % blockSize; 2841 } 2842 pad = (byte) (newlen - len); 2843 2844 /* 2845 * Update the limit to what will be padded. 2846 */ 2847 bb.limit(newlen + offset); 2848 2849 /* 2850 * TLS version of the padding works for both SSLv3 and TLSv1 2851 */ 2852 for (i = 0, offset += len; i < pad; i++) { 2853 bb.put(offset++, (byte) (pad - 1)); 2854 } 2855 2856 bb.position(offset); 2857 bb.limit(offset); 2858 2859 return newlen; 2860 } 2861 removePadding(ByteBuffer bb, int tagLen, int blockSize, ProtocolVersion protocolVersion)2862 private static int removePadding(ByteBuffer bb, 2863 int tagLen, int blockSize, 2864 ProtocolVersion protocolVersion) throws BadPaddingException { 2865 int len = bb.remaining(); 2866 int offset = bb.position(); 2867 2868 // last byte is length byte (i.e. actual padding length - 1) 2869 int padOffset = offset + len - 1; 2870 int padLen = bb.get(padOffset) & 0xFF; 2871 2872 int newLen = len - (padLen + 1); 2873 if ((newLen - tagLen) < 0) { 2874 // If the buffer is not long enough to contain the padding plus 2875 // a MAC tag, do a dummy constant-time padding check. 2876 // 2877 // Note that it is a dummy check, so we won't care about what is 2878 // the actual padding data. 2879 checkPadding(bb.duplicate(), (byte)(padLen & 0xFF)); 2880 2881 throw new BadPaddingException("Invalid Padding length: " + padLen); 2882 } 2883 2884 // The padding data should be filled with the padding length value. 2885 int[] results = checkPadding( 2886 bb.duplicate().position(offset + newLen), 2887 (byte)(padLen & 0xFF)); 2888 if (protocolVersion.useTLS10PlusSpec()) { 2889 if (results[0] != 0) { // padding data has invalid bytes 2890 throw new BadPaddingException("Invalid TLS padding data"); 2891 } 2892 } else { // SSLv3 2893 // SSLv3 requires 0 <= length byte < block size 2894 // some implementations do 1 <= length byte <= block size, 2895 // so accept that as well 2896 // v3 does not require any particular value for the other bytes 2897 if (padLen > blockSize) { 2898 throw new BadPaddingException("Padding length (" + 2899 padLen + ") of SSLv3 message should not be bigger " + 2900 "than the block size (" + blockSize + ")"); 2901 } 2902 } 2903 2904 // Reset buffer limit to remove padding. 2905 bb.limit(offset + newLen); 2906 2907 return newLen; 2908 } 2909 2910 /* 2911 * A constant-time check of the padding. 2912 * 2913 * NOTE that we are checking both the padding and the padLen bytes here. 2914 * 2915 * The caller MUST ensure that the bb parameter has remaining. 2916 */ checkPadding(ByteBuffer bb, byte pad)2917 private static int[] checkPadding(ByteBuffer bb, byte pad) { 2918 if (!bb.hasRemaining()) { 2919 throw new RuntimeException("hasRemaining() must be positive"); 2920 } 2921 2922 // An array of hits is used to prevent Hotspot optimization for 2923 // the purpose of a constant-time check. 2924 int[] results = {0, 0}; // {missed #, matched #} 2925 bb.mark(); 2926 for (int i = 0; i <= 256; bb.reset()) { 2927 for (; bb.hasRemaining() && i <= 256; i++) { 2928 if (bb.get() != pad) { 2929 results[0]++; // mismatched padding data 2930 } else { 2931 results[1]++; // matched padding data 2932 } 2933 } 2934 } 2935 2936 return results; 2937 } 2938 } 2939