1 /*
2  * Copyright (c) 2005, 2017, 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 com.sun.crypto.provider;
27 
28 import java.util.Arrays;
29 
30 import java.security.*;
31 import java.security.spec.AlgorithmParameterSpec;
32 
33 import javax.crypto.*;
34 import javax.crypto.spec.SecretKeySpec;
35 
36 import sun.security.internal.spec.TlsPrfParameterSpec;
37 
38 /**
39  * KeyGenerator implementation for the TLS PRF function.
40  * <p>
41  * This class duplicates the HMAC functionality (RFC 2104) with
42  * performance optimizations (e.g. XOR'ing keys with padding doesn't
43  * need to be redone for each HMAC operation).
44  *
45  * @author  Andreas Sterbenz
46  * @since   1.6
47  */
48 abstract class TlsPrfGenerator extends KeyGeneratorSpi {
49 
50     // magic constants and utility functions, also used by other files
51     // in this package
52 
53     private static final byte[] B0 = new byte[0];
54 
55     static final byte[] LABEL_MASTER_SECRET = // "master secret"
56         { 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 };
57 
58     static final byte[] LABEL_EXTENDED_MASTER_SECRET =
59                                             // "extended master secret"
60         { 101, 120, 116, 101, 110, 100, 101, 100, 32, 109, 97, 115, 116,
61           101, 114, 32, 115, 101, 99, 114, 101, 116 };
62 
63     static final byte[] LABEL_KEY_EXPANSION = // "key expansion"
64         { 107, 101, 121, 32, 101, 120, 112, 97, 110, 115, 105, 111, 110 };
65 
66     static final byte[] LABEL_CLIENT_WRITE_KEY = // "client write key"
67         { 99, 108, 105, 101, 110, 116, 32, 119, 114, 105, 116, 101, 32,
68           107, 101, 121 };
69 
70     static final byte[] LABEL_SERVER_WRITE_KEY = // "server write key"
71         { 115, 101, 114, 118, 101, 114, 32, 119, 114, 105, 116, 101, 32,
72           107, 101, 121 };
73 
74     static final byte[] LABEL_IV_BLOCK = // "IV block"
75         { 73, 86, 32, 98, 108, 111, 99, 107 };
76 
77     /*
78      * TLS HMAC "inner" and "outer" padding.  This isn't a function
79      * of the digest algorithm.
80      */
81     private static final byte[] HMAC_ipad64  = genPad((byte)0x36, 64);
82     private static final byte[] HMAC_ipad128 = genPad((byte)0x36, 128);
83     private static final byte[] HMAC_opad64  = genPad((byte)0x5c, 64);
84     private static final byte[] HMAC_opad128 = genPad((byte)0x5c, 128);
85 
86     // SSL3 magic mix constants ("A", "BB", "CCC", ...)
87     static final byte[][] SSL3_CONST = genConst();
88 
genPad(byte b, int count)89     static byte[] genPad(byte b, int count) {
90         byte[] padding = new byte[count];
91         Arrays.fill(padding, b);
92         return padding;
93     }
94 
concat(byte[] b1, byte[] b2)95     static byte[] concat(byte[] b1, byte[] b2) {
96         int n1 = b1.length;
97         int n2 = b2.length;
98         byte[] b = new byte[n1 + n2];
99         System.arraycopy(b1, 0, b, 0, n1);
100         System.arraycopy(b2, 0, b, n1, n2);
101         return b;
102     }
103 
genConst()104     private static byte[][] genConst() {
105         int n = 10;
106         byte[][] arr = new byte[n][];
107         for (int i = 0; i < n; i++) {
108             byte[] b = new byte[i + 1];
109             Arrays.fill(b, (byte)('A' + i));
110             arr[i] = b;
111         }
112         return arr;
113     }
114 
115     // PRF implementation
116 
117     private static final String MSG = "TlsPrfGenerator must be "
118         + "initialized using a TlsPrfParameterSpec";
119 
120     @SuppressWarnings("deprecation")
121     private TlsPrfParameterSpec spec;
122 
TlsPrfGenerator()123     public TlsPrfGenerator() {
124     }
125 
engineInit(SecureRandom random)126     protected void engineInit(SecureRandom random) {
127         throw new InvalidParameterException(MSG);
128     }
129 
130     @SuppressWarnings("deprecation")
engineInit(AlgorithmParameterSpec params, SecureRandom random)131     protected void engineInit(AlgorithmParameterSpec params,
132             SecureRandom random) throws InvalidAlgorithmParameterException {
133         if (params instanceof TlsPrfParameterSpec == false) {
134             throw new InvalidAlgorithmParameterException(MSG);
135         }
136         this.spec = (TlsPrfParameterSpec)params;
137         SecretKey key = spec.getSecret();
138         if ((key != null) && ("RAW".equals(key.getFormat()) == false)) {
139             throw new InvalidAlgorithmParameterException(
140                 "Key encoding format must be RAW");
141         }
142     }
143 
engineInit(int keysize, SecureRandom random)144     protected void engineInit(int keysize, SecureRandom random) {
145         throw new InvalidParameterException(MSG);
146     }
147 
engineGenerateKey0(boolean tls12)148     SecretKey engineGenerateKey0(boolean tls12) {
149         if (spec == null) {
150             throw new IllegalStateException(
151                 "TlsPrfGenerator must be initialized");
152         }
153         SecretKey key = spec.getSecret();
154         byte[] secret = (key == null) ? null : key.getEncoded();
155         try {
156             byte[] labelBytes = spec.getLabel().getBytes("UTF8");
157             int n = spec.getOutputLength();
158             byte[] prfBytes = (tls12 ?
159                 doTLS12PRF(secret, labelBytes, spec.getSeed(), n,
160                     spec.getPRFHashAlg(), spec.getPRFHashLength(),
161                     spec.getPRFBlockSize()) :
162                 doTLS10PRF(secret, labelBytes, spec.getSeed(), n));
163             return new SecretKeySpec(prfBytes, "TlsPrf");
164         } catch (GeneralSecurityException e) {
165             throw new ProviderException("Could not generate PRF", e);
166         } catch (java.io.UnsupportedEncodingException e) {
167             throw new ProviderException("Could not generate PRF", e);
168         }
169     }
170 
doTLS12PRF(byte[] secret, byte[] labelBytes, byte[] seed, int outputLength, String prfHash, int prfHashLength, int prfBlockSize)171     static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,
172             byte[] seed, int outputLength,
173             String prfHash, int prfHashLength, int prfBlockSize)
174             throws NoSuchAlgorithmException, DigestException {
175         if (prfHash == null) {
176             throw new NoSuchAlgorithmException("Unspecified PRF algorithm");
177         }
178         MessageDigest prfMD = MessageDigest.getInstance(prfHash);
179         return doTLS12PRF(secret, labelBytes, seed, outputLength,
180             prfMD, prfHashLength, prfBlockSize);
181     }
182 
doTLS12PRF(byte[] secret, byte[] labelBytes, byte[] seed, int outputLength, MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize)183     static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,
184             byte[] seed, int outputLength,
185             MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize)
186             throws DigestException {
187 
188         if (secret == null) {
189             secret = B0;
190         }
191 
192         // If we have a long secret, digest it first.
193         if (secret.length > mdPRFBlockSize) {
194             secret = mdPRF.digest(secret);
195         }
196 
197         byte[] output = new byte[outputLength];
198         byte [] ipad;
199         byte [] opad;
200 
201         switch (mdPRFBlockSize) {
202         case 64:
203             ipad = HMAC_ipad64.clone();
204             opad = HMAC_opad64.clone();
205             break;
206         case 128:
207             ipad = HMAC_ipad128.clone();
208             opad = HMAC_opad128.clone();
209             break;
210         default:
211             throw new DigestException("Unexpected block size.");
212         }
213 
214         // P_HASH(Secret, label + seed)
215         expand(mdPRF, mdPRFLen, secret, 0, secret.length, labelBytes,
216             seed, output, ipad, opad);
217 
218         return output;
219     }
220 
doTLS10PRF(byte[] secret, byte[] labelBytes, byte[] seed, int outputLength)221     static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,
222             byte[] seed, int outputLength) throws NoSuchAlgorithmException,
223             DigestException {
224         MessageDigest md5 = MessageDigest.getInstance("MD5");
225         MessageDigest sha = MessageDigest.getInstance("SHA1");
226         return doTLS10PRF(secret, labelBytes, seed, outputLength, md5, sha);
227     }
228 
doTLS10PRF(byte[] secret, byte[] labelBytes, byte[] seed, int outputLength, MessageDigest md5, MessageDigest sha)229     static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,
230             byte[] seed, int outputLength, MessageDigest md5,
231             MessageDigest sha) throws DigestException {
232         /*
233          * Split the secret into two halves S1 and S2 of same length.
234          * S1 is taken from the first half of the secret, S2 from the
235          * second half.
236          * Their length is created by rounding up the length of the
237          * overall secret divided by two; thus, if the original secret
238          * is an odd number of bytes long, the last byte of S1 will be
239          * the same as the first byte of S2.
240          *
241          * Note: Instead of creating S1 and S2, we determine the offset into
242          * the overall secret where S2 starts.
243          */
244 
245         if (secret == null) {
246             secret = B0;
247         }
248         int off = secret.length >> 1;
249         int seclen = off + (secret.length & 1);
250 
251         byte[] secKey = secret;
252         int keyLen = seclen;
253         byte[] output = new byte[outputLength];
254 
255         // P_MD5(S1, label + seed)
256         // If we have a long secret, digest it first.
257         if (seclen > 64) {              // 64: block size of HMAC-MD5
258             md5.update(secret, 0, seclen);
259             secKey = md5.digest();
260             keyLen = secKey.length;
261         }
262         expand(md5, 16, secKey, 0, keyLen, labelBytes, seed, output,
263             HMAC_ipad64.clone(), HMAC_opad64.clone());
264 
265         // P_SHA-1(S2, label + seed)
266         // If we have a long secret, digest it first.
267         if (seclen > 64) {              // 64: block size of HMAC-SHA1
268             sha.update(secret, off, seclen);
269             secKey = sha.digest();
270             keyLen = secKey.length;
271             off = 0;
272         }
273         expand(sha, 20, secKey, off, keyLen, labelBytes, seed, output,
274             HMAC_ipad64.clone(), HMAC_opad64.clone());
275 
276         return output;
277     }
278 
279     /*
280      * @param digest the MessageDigest to produce the HMAC
281      * @param hmacSize the HMAC size
282      * @param secret the secret
283      * @param secOff the offset into the secret
284      * @param secLen the secret length
285      * @param label the label
286      * @param seed the seed
287      * @param output the output array
288      */
expand(MessageDigest digest, int hmacSize, byte[] secret, int secOff, int secLen, byte[] label, byte[] seed, byte[] output, byte[] pad1, byte[] pad2)289     private static void expand(MessageDigest digest, int hmacSize,
290             byte[] secret, int secOff, int secLen, byte[] label, byte[] seed,
291             byte[] output, byte[] pad1, byte[] pad2) throws DigestException {
292         /*
293          * modify the padding used, by XORing the key into our copy of that
294          * padding.  That's to avoid doing that for each HMAC computation.
295          */
296         for (int i = 0; i < secLen; i++) {
297             pad1[i] ^= secret[i + secOff];
298             pad2[i] ^= secret[i + secOff];
299         }
300 
301         byte[] tmp = new byte[hmacSize];
302         byte[] aBytes = null;
303 
304         /*
305          * compute:
306          *
307          *     P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
308          *                            HMAC_hash(secret, A(2) + seed) +
309          *                            HMAC_hash(secret, A(3) + seed) + ...
310          * A() is defined as:
311          *
312          *     A(0) = seed
313          *     A(i) = HMAC_hash(secret, A(i-1))
314          */
315         int remaining = output.length;
316         int ofs = 0;
317         while (remaining > 0) {
318             /*
319              * compute A() ...
320              */
321             // inner digest
322             digest.update(pad1);
323             if (aBytes == null) {
324                 digest.update(label);
325                 digest.update(seed);
326             } else {
327                 digest.update(aBytes);
328             }
329             digest.digest(tmp, 0, hmacSize);
330 
331             // outer digest
332             digest.update(pad2);
333             digest.update(tmp);
334             if (aBytes == null) {
335                 aBytes = new byte[hmacSize];
336             }
337             digest.digest(aBytes, 0, hmacSize);
338 
339             /*
340              * compute HMAC_hash() ...
341              */
342             // inner digest
343             digest.update(pad1);
344             digest.update(aBytes);
345             digest.update(label);
346             digest.update(seed);
347             digest.digest(tmp, 0, hmacSize);
348 
349             // outer digest
350             digest.update(pad2);
351             digest.update(tmp);
352             digest.digest(tmp, 0, hmacSize);
353 
354             int k = Math.min(hmacSize, remaining);
355             for (int i = 0; i < k; i++) {
356                 output[ofs++] ^= tmp[i];
357             }
358             remaining -= k;
359         }
360     }
361 
362     /**
363      * A KeyGenerator implementation that supports TLS 1.2.
364      * <p>
365      * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF
366      * calculations.  As of 2010, there is no PKCS11-level support for TLS
367      * 1.2 PRF calculations, and no known OS's have an internal variant
368      * we could use.  Therefore for TLS 1.2, we are updating JSSE to request
369      * a different provider algorithm:  "SunTls12Prf".  If we reused the
370      * name "SunTlsPrf", the PKCS11 provider would need be updated to
371      * fail correctly when presented with the wrong version number
372      * (via Provider.Service.supportsParameters()), and add the
373      * appropriate supportsParamters() checks into KeyGenerators (not
374      * currently there).
375      */
376     public static class V12 extends TlsPrfGenerator {
engineGenerateKey()377         protected SecretKey engineGenerateKey() {
378             return engineGenerateKey0(true);
379         }
380     }
381 
382     /**
383      * A KeyGenerator implementation that supports TLS 1.0/1.1.
384      */
385     public static class V10 extends TlsPrfGenerator {
engineGenerateKey()386         protected SecretKey engineGenerateKey() {
387             return engineGenerateKey0(false);
388         }
389     }
390 }
391