1/*
2 * Copyright (c) 2002, 2016, 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
27package sun.security.ssl;
28
29import java.io.ByteArrayOutputStream;
30import java.security.*;
31import java.util.Locale;
32import java.nio.ByteBuffer;
33
34/**
35 * Abstraction for the SSL/TLS hash of all handshake messages that is
36 * maintained to verify the integrity of the negotiation. Internally,
37 * it consists of an MD5 and an SHA1 digest. They are used in the client
38 * and server finished messages and in certificate verify messages (if sent).
39 *
40 * This class transparently deals with cloneable and non-cloneable digests.
41 *
42 * This class now supports TLS 1.2 also. The key difference for TLS 1.2
43 * is that you cannot determine the hash algorithms for CertificateVerify
44 * at a early stage. On the other hand, it's simpler than TLS 1.1 (and earlier)
45 * that there is no messy MD5+SHA1 digests.
46 *
47 * You need to obey these conventions when using this class:
48 *
49 * 1. protocolDetermined(version) should be called when the negotiated
50 * protocol version is determined.
51 *
52 * 2. Before protocolDetermined() is called, only update(), and reset()
53 * and setFinishedAlg() can be called.
54 *
55 * 3. After protocolDetermined() is called, reset() cannot be called.
56 *
57 * 4. After protocolDetermined() is called, if the version is pre-TLS 1.2,
58 * getFinishedHash() cannot be called. Otherwise,
59 * getMD5Clone() and getSHAClone() cannot be called.
60 *
61 * 5. getMD5Clone() and getSHAClone() can only be called after
62 * protocolDetermined() is called and version is pre-TLS 1.2.
63 *
64 * 6. getFinishedHash() can only be called after protocolDetermined()
65 * and setFinishedAlg() have been called and the version is TLS 1.2.
66 *
67 * Suggestion: Call protocolDetermined() and setFinishedAlg()
68 * as early as possible.
69 *
70 * Example:
71 * <pre>
72 * HandshakeHash hh = new HandshakeHash(...)
73 * hh.protocolDetermined(ProtocolVersion.TLS12);
74 * hh.update(clientHelloBytes);
75 * hh.setFinishedAlg("SHA-256");
76 * hh.update(serverHelloBytes);
77 * ...
78 * hh.update(CertificateVerifyBytes);
79 * ...
80 * hh.update(finished1);
81 * byte[] finDigest1 = hh.getFinishedHash();
82 * hh.update(finished2);
83 * byte[] finDigest2 = hh.getFinishedHash();
84 * </pre>
85 */
86final class HandshakeHash {
87
88    // Common
89
90    // -1:  unknown
91    //  1:  <=TLS 1.1
92    //  2:  TLS 1.2
93    private int version = -1;
94    private ByteArrayOutputStream data = new ByteArrayOutputStream();
95
96    // For TLS 1.1
97    private MessageDigest md5, sha;
98    private final int clonesNeeded;    // needs to be saved for later use
99
100    // For TLS 1.2
101    private MessageDigest finMD;
102
103    // Cache for input record handshake hash computation
104    private ByteArrayOutputStream reserve = new ByteArrayOutputStream();
105
106    /**
107     * Create a new HandshakeHash. needCertificateVerify indicates whether
108     * a hash for the certificate verify message is required.
109     */
110    HandshakeHash(boolean needCertificateVerify) {
111        clonesNeeded = needCertificateVerify ? 4 : 3;
112    }
113
114    void reserve(ByteBuffer input) {
115        if (input.hasArray()) {
116            reserve.write(input.array(),
117                    input.position() + input.arrayOffset(), input.remaining());
118        } else {
119            int inPos = input.position();
120            byte[] holder = new byte[input.remaining()];
121            input.get(holder);
122            input.position(inPos);
123            reserve.write(holder, 0, holder.length);
124        }
125    }
126
127    void reserve(byte[] b, int offset, int len) {
128        reserve.write(b, offset, len);
129    }
130
131    void reload() {
132        if (reserve.size() != 0) {
133            byte[] bytes = reserve.toByteArray();
134            reserve.reset();
135            update(bytes, 0, bytes.length);
136        }
137    }
138
139    void update(ByteBuffer input) {
140
141        // reload if there are reserved messages.
142        reload();
143
144        int inPos = input.position();
145        switch (version) {
146            case 1:
147                md5.update(input);
148                input.position(inPos);
149
150                sha.update(input);
151                input.position(inPos);
152
153                break;
154            default:
155                if (finMD != null) {
156                    finMD.update(input);
157                    input.position(inPos);
158                }
159                if (input.hasArray()) {
160                    data.write(input.array(),
161                            inPos + input.arrayOffset(), input.remaining());
162                } else {
163                    byte[] holder = new byte[input.remaining()];
164                    input.get(holder);
165                    input.position(inPos);
166                    data.write(holder, 0, holder.length);
167                }
168                break;
169        }
170    }
171
172    void update(byte handshakeType, byte[] handshakeBody) {
173
174        // reload if there are reserved messages.
175        reload();
176
177        switch (version) {
178            case 1:
179                md5.update(handshakeType);
180                sha.update(handshakeType);
181
182                md5.update((byte)((handshakeBody.length >> 16) & 0xFF));
183                sha.update((byte)((handshakeBody.length >> 16) & 0xFF));
184                md5.update((byte)((handshakeBody.length >> 8) & 0xFF));
185                sha.update((byte)((handshakeBody.length >> 8) & 0xFF));
186                md5.update((byte)(handshakeBody.length & 0xFF));
187                sha.update((byte)(handshakeBody.length & 0xFF));
188
189                md5.update(handshakeBody);
190                sha.update(handshakeBody);
191                break;
192            default:
193                if (finMD != null) {
194                    finMD.update(handshakeType);
195                    finMD.update((byte)((handshakeBody.length >> 16) & 0xFF));
196                    finMD.update((byte)((handshakeBody.length >> 8) & 0xFF));
197                    finMD.update((byte)(handshakeBody.length & 0xFF));
198                    finMD.update(handshakeBody);
199                }
200                data.write(handshakeType);
201                data.write((byte)((handshakeBody.length >> 16) & 0xFF));
202                data.write((byte)((handshakeBody.length >> 8) & 0xFF));
203                data.write((byte)(handshakeBody.length & 0xFF));
204                data.write(handshakeBody, 0, handshakeBody.length);
205                break;
206        }
207    }
208
209    void update(byte[] b, int offset, int len) {
210
211        // reload if there are reserved messages.
212        reload();
213
214        switch (version) {
215            case 1:
216                md5.update(b, offset, len);
217                sha.update(b, offset, len);
218                break;
219            default:
220                if (finMD != null) {
221                    finMD.update(b, offset, len);
222                }
223                data.write(b, offset, len);
224                break;
225        }
226    }
227
228    /**
229     * Reset the remaining digests. Note this does *not* reset the number of
230     * digest clones that can be obtained. Digests that have already been
231     * cloned and are gone remain gone.
232     */
233    void reset() {
234        if (version != -1) {
235            throw new RuntimeException(
236                    "reset() can be only be called before protocolDetermined");
237        }
238        data.reset();
239    }
240
241
242    void protocolDetermined(ProtocolVersion pv) {
243
244        // Do not set again, will ignore
245        if (version != -1) {
246            return;
247        }
248
249        if (pv.maybeDTLSProtocol()) {
250            version = pv.compareTo(ProtocolVersion.DTLS12) >= 0 ? 2 : 1;
251        } else {
252            version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1;
253        }
254        switch (version) {
255            case 1:
256                // initiate md5, sha and call update on saved array
257                try {
258                    md5 = CloneableDigest.getDigest("MD5", clonesNeeded);
259                    sha = CloneableDigest.getDigest("SHA", clonesNeeded);
260                } catch (NoSuchAlgorithmException e) {
261                    throw new RuntimeException
262                                ("Algorithm MD5 or SHA not available", e);
263                }
264                byte[] bytes = data.toByteArray();
265                update(bytes, 0, bytes.length);
266                break;
267            case 2:
268                break;
269        }
270    }
271
272    /////////////////////////////////////////////////////////////
273    // Below are old methods for pre-TLS 1.1
274    /////////////////////////////////////////////////////////////
275
276    /**
277     * Return a new MD5 digest updated with all data hashed so far.
278     */
279    MessageDigest getMD5Clone() {
280        if (version != 1) {
281            throw new RuntimeException(
282                    "getMD5Clone() can be only be called for TLS 1.1");
283        }
284        return cloneDigest(md5);
285    }
286
287    /**
288     * Return a new SHA digest updated with all data hashed so far.
289     */
290    MessageDigest getSHAClone() {
291        if (version != 1) {
292            throw new RuntimeException(
293                    "getSHAClone() can be only be called for TLS 1.1");
294        }
295        return cloneDigest(sha);
296    }
297
298    private static MessageDigest cloneDigest(MessageDigest digest) {
299        try {
300            return (MessageDigest)digest.clone();
301        } catch (CloneNotSupportedException e) {
302            // cannot occur for digests generated via CloneableDigest
303            throw new RuntimeException("Could not clone digest", e);
304        }
305    }
306
307    /////////////////////////////////////////////////////////////
308    // Below are new methods for TLS 1.2
309    /////////////////////////////////////////////////////////////
310
311    private static String normalizeAlgName(String alg) {
312        alg = alg.toUpperCase(Locale.US);
313        if (alg.startsWith("SHA")) {
314            if (alg.length() == 3) {
315                return "SHA-1";
316            }
317            if (alg.charAt(3) != '-') {
318                return "SHA-" + alg.substring(3);
319            }
320        }
321        return alg;
322    }
323    /**
324     * Specifies the hash algorithm used in Finished. This should be called
325     * based in info in ServerHello.
326     * Can be called multiple times.
327     */
328    void setFinishedAlg(String s) {
329        if (s == null) {
330            throw new RuntimeException(
331                    "setFinishedAlg's argument cannot be null");
332        }
333
334        // Can be called multiple times, but only set once
335        if (finMD != null) return;
336
337        try {
338            finMD = CloneableDigest.getDigest(normalizeAlgName(s), 2);
339        } catch (NoSuchAlgorithmException e) {
340            throw new Error(e);
341        }
342        finMD.update(data.toByteArray());
343    }
344
345    byte[] getAllHandshakeMessages() {
346        return data.toByteArray();
347    }
348
349    /**
350     * Calculates the hash in Finished. Must be called after setFinishedAlg().
351     * This method can be called twice, for Finished messages of the server
352     * side and client side respectively.
353     */
354    byte[] getFinishedHash() {
355        try {
356            return cloneDigest(finMD).digest();
357        } catch (Exception e) {
358            throw new Error("Error during hash calculation", e);
359        }
360    }
361}
362
363/**
364 * A wrapper for MessageDigests that simulates cloning of non-cloneable
365 * digests. It uses the standard MessageDigest API and therefore can be used
366 * transparently in place of a regular digest.
367 *
368 * Note that we extend the MessageDigest class directly rather than
369 * MessageDigestSpi. This works because MessageDigest was originally designed
370 * this way in the JDK 1.1 days which allows us to avoid creating an internal
371 * provider.
372 *
373 * It can be "cloned" a limited number of times, which is specified at
374 * construction time. This is achieved by internally maintaining n digests
375 * in parallel. Consequently, it is only 1/n-th times as fast as the original
376 * digest.
377 *
378 * Example:
379 *   MessageDigest md = CloneableDigest.getDigest("SHA", 2);
380 *   md.update(data1);
381 *   MessageDigest md2 = (MessageDigest)md.clone();
382 *   md2.update(data2);
383 *   byte[] d1 = md2.digest(); // digest of data1 || data2
384 *   md.update(data3);
385 *   byte[] d2 = md.digest();  // digest of data1 || data3
386 *
387 * This class is not thread safe.
388 *
389 */
390final class CloneableDigest extends MessageDigest implements Cloneable {
391
392    /**
393     * The individual MessageDigests. Initially, all elements are non-null.
394     * When clone() is called, the non-null element with the maximum index is
395     * returned and the array element set to null.
396     *
397     * All non-null element are always in the same state.
398     */
399    private final MessageDigest[] digests;
400
401    private CloneableDigest(MessageDigest digest, int n, String algorithm)
402            throws NoSuchAlgorithmException {
403        super(algorithm);
404        digests = new MessageDigest[n];
405        digests[0] = digest;
406        for (int i = 1; i < n; i++) {
407            digests[i] = JsseJce.getMessageDigest(algorithm);
408        }
409    }
410
411    /**
412     * Return a MessageDigest for the given algorithm that can be cloned the
413     * specified number of times. If the default implementation supports
414     * cloning, it is returned. Otherwise, an instance of this class is
415     * returned.
416     */
417    static MessageDigest getDigest(String algorithm, int n)
418            throws NoSuchAlgorithmException {
419        MessageDigest digest = JsseJce.getMessageDigest(algorithm);
420        try {
421            digest.clone();
422            // already cloneable, use it
423            return digest;
424        } catch (CloneNotSupportedException e) {
425            return new CloneableDigest(digest, n, algorithm);
426        }
427    }
428
429    /**
430     * Check if this object is still usable. If it has already been cloned the
431     * maximum number of times, there are no digests left and this object can no
432     * longer be used.
433     */
434    private void checkState() {
435        // XXX handshaking currently doesn't stop updating hashes...
436        // if (digests[0] == null) {
437        //     throw new IllegalStateException("no digests left");
438        // }
439    }
440
441    @Override
442    protected int engineGetDigestLength() {
443        checkState();
444        return digests[0].getDigestLength();
445    }
446
447    @Override
448    protected void engineUpdate(byte b) {
449        checkState();
450        for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
451            digests[i].update(b);
452        }
453    }
454
455    @Override
456    protected void engineUpdate(byte[] b, int offset, int len) {
457        checkState();
458        for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
459            digests[i].update(b, offset, len);
460        }
461    }
462
463    @Override
464    protected byte[] engineDigest() {
465        checkState();
466        byte[] digest = digests[0].digest();
467        digestReset();
468        return digest;
469    }
470
471    @Override
472    protected int engineDigest(byte[] buf, int offset, int len)
473            throws DigestException {
474        checkState();
475        int n = digests[0].digest(buf, offset, len);
476        digestReset();
477        return n;
478    }
479
480    /**
481     * Reset all digests after a digest() call. digests[0] has already been
482     * implicitly reset by the digest() call and does not need to be reset
483     * again.
484     */
485    private void digestReset() {
486        for (int i = 1; (i < digests.length) && (digests[i] != null); i++) {
487            digests[i].reset();
488        }
489    }
490
491    @Override
492    protected void engineReset() {
493        checkState();
494        for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
495            digests[i].reset();
496        }
497    }
498
499    @Override
500    public Object clone() {
501        checkState();
502        for (int i = digests.length - 1; i >= 0; i--) {
503            if (digests[i] != null) {
504                MessageDigest digest = digests[i];
505                digests[i] = null;
506                return digest;
507            }
508        }
509        // cannot occur
510        throw new InternalError();
511    }
512
513}
514