2
|
1 |
/*
|
7043
|
2 |
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
2
|
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
|
5506
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
2
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
5506
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
2
|
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 |
*
|
5506
|
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.
|
2
|
24 |
*/
|
|
25 |
|
|
26 |
|
|
27 |
package sun.security.ssl;
|
|
28 |
|
7043
|
29 |
import java.io.ByteArrayOutputStream;
|
2
|
30 |
import java.security.*;
|
7043
|
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;
|
2
|
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 |
*
|
7043
|
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 |
*
|
7804
|
52 |
* 1. protocolDetermined(version) should be called when the negotiated
|
7043
|
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 |
*
|
7804
|
59 |
* 3. After protocolDetermined() is called, reset() cannot be called.
|
7043
|
60 |
*
|
7804
|
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.
|
7043
|
64 |
*
|
|
65 |
* 5. getMD5Clone() and getSHAClone() can only be called after
|
7804
|
66 |
* protocolDetermined() is called and version is pre-TLS 1.2.
|
7043
|
67 |
*
|
|
68 |
* 6. getFinishedHash() and getCertificateVerifyHash() can only be called after
|
7804
|
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
|
7043
|
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(...)
|
7804
|
81 |
* hh.protocolDetermined(ProtocolVersion.TLS12);
|
7043
|
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.
|
2
|
101 |
*/
|
|
102 |
final class HandshakeHash {
|
|
103 |
|
7043
|
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;
|
2
|
122 |
|
|
123 |
/**
|
|
124 |
* Create a new HandshakeHash. needCertificateVerify indicates whether
|
7043
|
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.
|
2
|
129 |
*/
|
7043
|
130 |
HandshakeHash(boolean isServer, boolean needCertificateVerify,
|
|
131 |
Set<String> algs) {
|
|
132 |
this.isServer = isServer;
|
|
133 |
clonesNeeded = needCertificateVerify ? 3 : 2;
|
|
134 |
}
|
2
|
135 |
|
7043
|
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;
|
2
|
148 |
}
|
|
149 |
}
|
|
150 |
|
|
151 |
/**
|
7043
|
152 |
* Reset the remaining digests. Note this does *not* reset the number of
|
2
|
153 |
* digest clones that can be obtained. Digests that have already been
|
|
154 |
* cloned and are gone remain gone.
|
|
155 |
*/
|
|
156 |
void reset() {
|
7043
|
157 |
if (version != -1) {
|
|
158 |
throw new RuntimeException(
|
|
159 |
"reset() can be only be called before protocolDetermined");
|
|
160 |
}
|
|
161 |
data.reset();
|
2
|
162 |
}
|
|
163 |
|
7043
|
164 |
|
7804
|
165 |
void protocolDetermined(ProtocolVersion pv) {
|
7043
|
166 |
|
|
167 |
// Do not set again, will ignore
|
|
168 |
if (version != -1) return;
|
|
169 |
|
7804
|
170 |
version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1;
|
7043
|
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 |
|
2
|
193 |
/**
|
|
194 |
* Return a new MD5 digest updated with all data hashed so far.
|
|
195 |
*/
|
|
196 |
MessageDigest getMD5Clone() {
|
7043
|
197 |
if (version != 1) {
|
|
198 |
throw new RuntimeException(
|
|
199 |
"getMD5Clone() can be only be called for TLS 1.1");
|
|
200 |
}
|
2
|
201 |
return cloneDigest(md5);
|
|
202 |
}
|
|
203 |
|
|
204 |
/**
|
|
205 |
* Return a new SHA digest updated with all data hashed so far.
|
|
206 |
*/
|
|
207 |
MessageDigest getSHAClone() {
|
7043
|
208 |
if (version != 1) {
|
|
209 |
throw new RuntimeException(
|
|
210 |
"getSHAClone() can be only be called for TLS 1.1");
|
|
211 |
}
|
2
|
212 |
return cloneDigest(sha);
|
|
213 |
}
|
|
214 |
|
|
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 |
|
7043
|
224 |
/////////////////////////////////////////////////////////////
|
|
225 |
// Below are new methods for TLS 1.2
|
|
226 |
/////////////////////////////////////////////////////////////
|
|
227 |
|
|
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 |
*/
|
|
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 |
*/
|
|
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 |
*/
|
|
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 |
|
|
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 |
*/
|
|
307 |
byte[] getFinishedHash() {
|
|
308 |
try {
|
|
309 |
return cloneDigest(finMD).digest();
|
|
310 |
} catch (Exception e) {
|
|
311 |
throw new Error("BAD");
|
|
312 |
}
|
|
313 |
}
|
2
|
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 |
|
|
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 |
*/
|
|
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 |
*/
|
|
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 |
|
|
394 |
protected int engineGetDigestLength() {
|
|
395 |
checkState();
|
|
396 |
return digests[0].getDigestLength();
|
|
397 |
}
|
|
398 |
|
|
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 |
|
|
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 |
|
|
413 |
protected byte[] engineDigest() {
|
|
414 |
checkState();
|
|
415 |
byte[] digest = digests[0].digest();
|
|
416 |
digestReset();
|
|
417 |
return digest;
|
|
418 |
}
|
|
419 |
|
|
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 |
*/
|
|
433 |
private void digestReset() {
|
|
434 |
for (int i = 1; (i < digests.length) && (digests[i] != null); i++) {
|
|
435 |
digests[i].reset();
|
|
436 |
}
|
|
437 |
}
|
|
438 |
|
|
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 |
|
|
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 |
}
|