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