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