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