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