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