Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/HandshakeHash.java
38830 views
1
/*
2
* Copyright (c) 2003, 2018, 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 sun.security.ssl;
27
28
import java.io.ByteArrayOutputStream;
29
import java.io.IOException;
30
import java.nio.ByteBuffer;
31
import java.security.MessageDigest;
32
import java.util.Arrays;
33
import java.util.LinkedList;
34
import javax.crypto.SecretKey;
35
import sun.security.util.MessageDigestSpi2;
36
37
final class HandshakeHash {
38
private TranscriptHash transcriptHash;
39
private LinkedList<byte[]> reserves; // one handshake message per entry
40
private boolean hasBeenUsed;
41
42
HandshakeHash() {
43
this.transcriptHash = new CacheOnlyHash();
44
this.reserves = new LinkedList<>();
45
this.hasBeenUsed = false;
46
}
47
48
// fix the negotiated protocol version and cipher suite
49
void determine(ProtocolVersion protocolVersion,
50
CipherSuite cipherSuite) {
51
if (!(transcriptHash instanceof CacheOnlyHash)) {
52
throw new IllegalStateException(
53
"Not expected instance of transcript hash");
54
}
55
56
CacheOnlyHash coh = (CacheOnlyHash)transcriptHash;
57
if (protocolVersion.useTLS13PlusSpec()) {
58
transcriptHash = new T13HandshakeHash(cipherSuite);
59
} else if (protocolVersion.useTLS12PlusSpec()) {
60
transcriptHash = new T12HandshakeHash(cipherSuite);
61
} else if (protocolVersion.useTLS10PlusSpec()) {
62
transcriptHash = new T10HandshakeHash(cipherSuite);
63
} else {
64
transcriptHash = new S30HandshakeHash(cipherSuite);
65
}
66
67
byte[] reserved = coh.baos.toByteArray();
68
if (reserved.length != 0) {
69
transcriptHash.update(reserved, 0, reserved.length);
70
}
71
}
72
73
HandshakeHash copy() {
74
if (transcriptHash instanceof CacheOnlyHash) {
75
HandshakeHash result = new HandshakeHash();
76
result.transcriptHash = ((CacheOnlyHash)transcriptHash).copy();
77
result.reserves = new LinkedList<>(reserves);
78
result.hasBeenUsed = hasBeenUsed;
79
return result;
80
} else {
81
throw new IllegalStateException("Hash does not support copying");
82
}
83
}
84
85
void receive(byte[] input) {
86
reserves.add(Arrays.copyOf(input, input.length));
87
}
88
89
void receive(ByteBuffer input, int length) {
90
if (input.hasArray()) {
91
int from = input.position() + input.arrayOffset();
92
int to = from + length;
93
reserves.add(Arrays.copyOfRange(input.array(), from, to));
94
} else {
95
int inPos = input.position();
96
byte[] holder = new byte[length];
97
input.get(holder);
98
input.position(inPos);
99
reserves.add(Arrays.copyOf(holder, holder.length));
100
}
101
}
102
void receive(ByteBuffer input) {
103
receive(input, input.remaining());
104
}
105
106
// For HelloRetryRequest only! Please use this method very carefully!
107
void push(byte[] input) {
108
reserves.push(Arrays.copyOf(input, input.length));
109
}
110
111
// For PreSharedKey to modify the state of the PSK binder hash
112
byte[] removeLastReceived() {
113
return reserves.removeLast();
114
}
115
116
void deliver(byte[] input) {
117
update();
118
transcriptHash.update(input, 0, input.length);
119
}
120
121
void deliver(byte[] input, int offset, int length) {
122
update();
123
transcriptHash.update(input, offset, length);
124
}
125
126
void deliver(ByteBuffer input) {
127
update();
128
if (input.hasArray()) {
129
transcriptHash.update(input.array(),
130
input.position() + input.arrayOffset(), input.remaining());
131
} else {
132
int inPos = input.position();
133
byte[] holder = new byte[input.remaining()];
134
input.get(holder);
135
input.position(inPos);
136
transcriptHash.update(holder, 0, holder.length);
137
}
138
}
139
140
// Use one handshake message if it has not been used.
141
void utilize() {
142
if (hasBeenUsed) {
143
return;
144
}
145
if (reserves.size() != 0) {
146
byte[] holder = reserves.remove();
147
transcriptHash.update(holder, 0, holder.length);
148
hasBeenUsed = true;
149
}
150
}
151
152
// Consume one handshake message if it has not been consumed.
153
void consume() {
154
if (hasBeenUsed) {
155
hasBeenUsed = false;
156
return;
157
}
158
if (reserves.size() != 0) {
159
byte[] holder = reserves.remove();
160
transcriptHash.update(holder, 0, holder.length);
161
}
162
}
163
164
void update() {
165
while (reserves.size() != 0) {
166
byte[] holder = reserves.remove();
167
transcriptHash.update(holder, 0, holder.length);
168
}
169
hasBeenUsed = false;
170
}
171
172
byte[] digest() {
173
// Note that the reserve handshake message may be not a part of
174
// the expected digest.
175
return transcriptHash.digest();
176
}
177
178
void finish() {
179
this.transcriptHash = new CacheOnlyHash();
180
this.reserves = new LinkedList<>();
181
this.hasBeenUsed = false;
182
}
183
184
// Optional
185
byte[] archived() {
186
// Note that the reserve handshake message may be not a part of
187
// the expected digest.
188
return transcriptHash.archived();
189
}
190
191
// Optional, TLS 1.0/1.1 only
192
byte[] digest(String algorithm) {
193
T10HandshakeHash hh = (T10HandshakeHash)transcriptHash;
194
return hh.digest(algorithm);
195
}
196
197
// Optional, SSL 3.0 only
198
byte[] digest(String algorithm, SecretKey masterSecret) {
199
S30HandshakeHash hh = (S30HandshakeHash)transcriptHash;
200
return hh.digest(algorithm, masterSecret);
201
}
202
203
// Optional, SSL 3.0 only
204
byte[] digest(boolean useClientLabel, SecretKey masterSecret) {
205
S30HandshakeHash hh = (S30HandshakeHash)transcriptHash;
206
return hh.digest(useClientLabel, masterSecret);
207
}
208
209
public boolean isHashable(byte handshakeType) {
210
return handshakeType != SSLHandshake.HELLO_REQUEST.id;
211
}
212
213
interface TranscriptHash {
214
void update(byte[] input, int offset, int length);
215
byte[] digest();
216
byte[] archived(); // optional
217
}
218
219
// For cache only.
220
private static final class CacheOnlyHash implements TranscriptHash {
221
private final ByteArrayOutputStream baos;
222
223
CacheOnlyHash() {
224
this.baos = new ByteArrayOutputStream();
225
}
226
227
@Override
228
public void update(byte[] input, int offset, int length) {
229
baos.write(input, offset, length);
230
}
231
232
@Override
233
public byte[] digest() {
234
throw new IllegalStateException(
235
"Not expected call to handshake hash digest");
236
}
237
238
@Override
239
public byte[] archived() {
240
return baos.toByteArray();
241
}
242
243
CacheOnlyHash copy() {
244
CacheOnlyHash result = new CacheOnlyHash();
245
try {
246
baos.writeTo(result.baos);
247
} catch (IOException ex) {
248
throw new RuntimeException("unable to to clone hash state");
249
}
250
return result;
251
}
252
}
253
254
static final class S30HandshakeHash implements TranscriptHash {
255
static final byte[] MD5_pad1 = genPad(0x36, 48);
256
static final byte[] MD5_pad2 = genPad(0x5c, 48);
257
258
static final byte[] SHA_pad1 = genPad(0x36, 40);
259
static final byte[] SHA_pad2 = genPad(0x5c, 40);
260
261
private static final byte[] SSL_CLIENT = { 0x43, 0x4C, 0x4E, 0x54 };
262
private static final byte[] SSL_SERVER = { 0x53, 0x52, 0x56, 0x52 };
263
264
private final MessageDigest mdMD5;
265
private final MessageDigest mdSHA;
266
private final TranscriptHash md5;
267
private final TranscriptHash sha;
268
private final ByteArrayOutputStream baos;
269
270
S30HandshakeHash(CipherSuite cipherSuite) {
271
this.mdMD5 = JsseJce.getMessageDigest("MD5");
272
this.mdSHA = JsseJce.getMessageDigest("SHA");
273
274
boolean hasArchived = false;
275
if (mdMD5 instanceof Cloneable) {
276
md5 = new CloneableHash(mdMD5);
277
} else {
278
hasArchived = true;
279
md5 = new NonCloneableHash(mdMD5);
280
}
281
if (mdSHA instanceof Cloneable) {
282
sha = new CloneableHash(mdSHA);
283
} else {
284
hasArchived = true;
285
sha = new NonCloneableHash(mdSHA);
286
}
287
288
if (hasArchived) {
289
this.baos = null;
290
} else {
291
this.baos = new ByteArrayOutputStream();
292
}
293
}
294
295
@Override
296
public void update(byte[] input, int offset, int length) {
297
md5.update(input, offset, length);
298
sha.update(input, offset, length);
299
if (baos != null) {
300
baos.write(input, offset, length);
301
}
302
}
303
304
@Override
305
public byte[] digest() {
306
byte[] digest = new byte[36];
307
System.arraycopy(md5.digest(), 0, digest, 0, 16);
308
System.arraycopy(sha.digest(), 0, digest, 16, 20);
309
310
return digest;
311
}
312
313
@Override
314
public byte[] archived() {
315
if (baos != null) {
316
return baos.toByteArray();
317
} else if (md5 instanceof NonCloneableHash) {
318
return md5.archived();
319
} else {
320
return sha.archived();
321
}
322
}
323
324
byte[] digest(boolean useClientLabel, SecretKey masterSecret) {
325
MessageDigest md5Clone = cloneMd5();
326
MessageDigest shaClone = cloneSha();
327
328
if (useClientLabel) {
329
md5Clone.update(SSL_CLIENT);
330
shaClone.update(SSL_CLIENT);
331
} else {
332
md5Clone.update(SSL_SERVER);
333
shaClone.update(SSL_SERVER);
334
}
335
336
updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterSecret);
337
updateDigest(shaClone, SHA_pad1, SHA_pad2, masterSecret);
338
339
byte[] digest = new byte[36];
340
System.arraycopy(md5Clone.digest(), 0, digest, 0, 16);
341
System.arraycopy(shaClone.digest(), 0, digest, 16, 20);
342
343
return digest;
344
}
345
346
byte[] digest(String algorithm, SecretKey masterSecret) {
347
if ("RSA".equalsIgnoreCase(algorithm)) {
348
MessageDigest md5Clone = cloneMd5();
349
MessageDigest shaClone = cloneSha();
350
updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterSecret);
351
updateDigest(shaClone, SHA_pad1, SHA_pad2, masterSecret);
352
353
byte[] digest = new byte[36];
354
System.arraycopy(md5Clone.digest(), 0, digest, 0, 16);
355
System.arraycopy(shaClone.digest(), 0, digest, 16, 20);
356
357
return digest;
358
} else {
359
MessageDigest shaClone = cloneSha();
360
updateDigest(shaClone, SHA_pad1, SHA_pad2, masterSecret);
361
return shaClone.digest();
362
}
363
}
364
365
private static byte[] genPad(int b, int count) {
366
byte[] padding = new byte[count];
367
Arrays.fill(padding, (byte)b);
368
return padding;
369
}
370
371
private MessageDigest cloneMd5() {
372
MessageDigest md5Clone;
373
if (mdMD5 instanceof Cloneable) {
374
try {
375
md5Clone = (MessageDigest)mdMD5.clone();
376
} catch (CloneNotSupportedException ex) { // unlikely
377
throw new RuntimeException(
378
"MessageDigest does no support clone operation");
379
}
380
} else {
381
md5Clone = JsseJce.getMessageDigest("MD5");
382
md5Clone.update(md5.archived());
383
}
384
385
return md5Clone;
386
}
387
388
private MessageDigest cloneSha() {
389
MessageDigest shaClone;
390
if (mdSHA instanceof Cloneable) {
391
try {
392
shaClone = (MessageDigest)mdSHA.clone();
393
} catch (CloneNotSupportedException ex) { // unlikely
394
throw new RuntimeException(
395
"MessageDigest does no support clone operation");
396
}
397
} else {
398
shaClone = JsseJce.getMessageDigest("SHA");
399
shaClone.update(sha.archived());
400
}
401
402
return shaClone;
403
}
404
405
private static void updateDigest(MessageDigest md,
406
byte[] pad1, byte[] pad2, SecretKey masterSecret) {
407
byte[] keyBytes = "RAW".equals(masterSecret.getFormat())
408
? masterSecret.getEncoded() : null;
409
if (keyBytes != null) {
410
md.update(keyBytes);
411
} else {
412
digestKey(md, masterSecret);
413
}
414
md.update(pad1);
415
byte[] temp = md.digest();
416
417
if (keyBytes != null) {
418
md.update(keyBytes);
419
} else {
420
digestKey(md, masterSecret);
421
}
422
md.update(pad2);
423
md.update(temp);
424
}
425
426
private static void digestKey(MessageDigest md, SecretKey key) {
427
try {
428
if (md instanceof MessageDigestSpi2) {
429
((MessageDigestSpi2)md).engineUpdate(key);
430
} else {
431
throw new Exception(
432
"Digest does not support implUpdate(SecretKey)");
433
}
434
} catch (Exception e) {
435
throw new RuntimeException(
436
"Could not obtain encoded key and "
437
+ "MessageDigest cannot digest key", e);
438
}
439
}
440
}
441
442
// TLS 1.0 and TLS 1.1
443
static final class T10HandshakeHash implements TranscriptHash {
444
private final TranscriptHash md5;
445
private final TranscriptHash sha;
446
private final ByteArrayOutputStream baos;
447
448
T10HandshakeHash(CipherSuite cipherSuite) {
449
MessageDigest mdMD5 = JsseJce.getMessageDigest("MD5");
450
MessageDigest mdSHA = JsseJce.getMessageDigest("SHA");
451
452
boolean hasArchived = false;
453
if (mdMD5 instanceof Cloneable) {
454
md5 = new CloneableHash(mdMD5);
455
} else {
456
hasArchived = true;
457
md5 = new NonCloneableHash(mdMD5);
458
}
459
if (mdSHA instanceof Cloneable) {
460
sha = new CloneableHash(mdSHA);
461
} else {
462
hasArchived = true;
463
sha = new NonCloneableHash(mdSHA);
464
}
465
466
if (hasArchived) {
467
this.baos = null;
468
} else {
469
this.baos = new ByteArrayOutputStream();
470
}
471
}
472
473
@Override
474
public void update(byte[] input, int offset, int length) {
475
md5.update(input, offset, length);
476
sha.update(input, offset, length);
477
if (baos != null) {
478
baos.write(input, offset, length);
479
}
480
}
481
482
@Override
483
public byte[] digest() {
484
byte[] digest = new byte[36];
485
System.arraycopy(md5.digest(), 0, digest, 0, 16);
486
System.arraycopy(sha.digest(), 0, digest, 16, 20);
487
488
return digest;
489
}
490
491
byte[] digest(String algorithm) {
492
if ("RSA".equalsIgnoreCase(algorithm)) {
493
return digest();
494
} else {
495
return sha.digest();
496
}
497
}
498
499
@Override
500
public byte[] archived() {
501
if (baos != null) {
502
return baos.toByteArray();
503
} else if (md5 instanceof NonCloneableHash) {
504
return md5.archived();
505
} else {
506
return sha.archived();
507
}
508
}
509
}
510
511
static final class T12HandshakeHash implements TranscriptHash {
512
private final TranscriptHash transcriptHash;
513
private final ByteArrayOutputStream baos;
514
515
T12HandshakeHash(CipherSuite cipherSuite) {
516
MessageDigest md =
517
JsseJce.getMessageDigest(cipherSuite.hashAlg.name);
518
if (md instanceof Cloneable) {
519
transcriptHash = new CloneableHash(md);
520
this.baos = new ByteArrayOutputStream();
521
} else {
522
transcriptHash = new NonCloneableHash(md);
523
this.baos = null;
524
}
525
}
526
527
@Override
528
public void update(byte[] input, int offset, int length) {
529
transcriptHash.update(input, offset, length);
530
if (baos != null) {
531
baos.write(input, offset, length);
532
}
533
}
534
535
@Override
536
public byte[] digest() {
537
return transcriptHash.digest();
538
}
539
540
@Override
541
public byte[] archived() {
542
if (baos != null) {
543
return baos.toByteArray();
544
} else {
545
return transcriptHash.archived();
546
}
547
}
548
}
549
550
static final class T13HandshakeHash implements TranscriptHash {
551
private final TranscriptHash transcriptHash;
552
553
T13HandshakeHash(CipherSuite cipherSuite) {
554
MessageDigest md =
555
JsseJce.getMessageDigest(cipherSuite.hashAlg.name);
556
if (md instanceof Cloneable) {
557
transcriptHash = new CloneableHash(md);
558
} else {
559
transcriptHash = new NonCloneableHash(md);
560
}
561
}
562
563
@Override
564
public void update(byte[] input, int offset, int length) {
565
transcriptHash.update(input, offset, length);
566
}
567
568
@Override
569
public byte[] digest() {
570
return transcriptHash.digest();
571
}
572
573
@Override
574
public byte[] archived() {
575
// This method is not necessary in T13
576
throw new UnsupportedOperationException(
577
"TLS 1.3 does not require archived.");
578
}
579
}
580
581
static final class CloneableHash implements TranscriptHash {
582
private final MessageDigest md;
583
584
CloneableHash(MessageDigest md) {
585
this.md = md;
586
}
587
588
@Override
589
public void update(byte[] input, int offset, int length) {
590
md.update(input, offset, length);
591
}
592
593
@Override
594
public byte[] digest() {
595
try {
596
return ((MessageDigest)md.clone()).digest();
597
} catch (CloneNotSupportedException ex) {
598
// unlikely
599
return new byte[0];
600
}
601
}
602
603
@Override
604
public byte[] archived() {
605
throw new UnsupportedOperationException("Not supported yet.");
606
}
607
}
608
609
static final class NonCloneableHash implements TranscriptHash {
610
private final MessageDigest md;
611
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
612
613
NonCloneableHash(MessageDigest md) {
614
this.md = md;
615
}
616
617
@Override
618
public void update(byte[] input, int offset, int length) {
619
baos.write(input, offset, length);
620
}
621
622
@Override
623
public byte[] digest() {
624
byte[] bytes = baos.toByteArray();
625
md.reset();
626
return md.digest(bytes);
627
}
628
629
@Override
630
public byte[] archived() {
631
return baos.toByteArray();
632
}
633
}
634
}
635
636