Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/ssl/Finished.java
41159 views
1
/*
2
* Copyright (c) 2015, 2021, 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.IOException;
29
import java.nio.ByteBuffer;
30
import java.security.GeneralSecurityException;
31
import java.security.InvalidKeyException;
32
import java.security.MessageDigest;
33
import java.security.NoSuchAlgorithmException;
34
import java.security.ProviderException;
35
import java.security.spec.AlgorithmParameterSpec;
36
import java.text.MessageFormat;
37
import java.util.Locale;
38
import javax.crypto.KeyGenerator;
39
import javax.crypto.Mac;
40
import javax.crypto.SecretKey;
41
import javax.crypto.spec.IvParameterSpec;
42
import javax.crypto.spec.SecretKeySpec;
43
import javax.net.ssl.SSLPeerUnverifiedException;
44
45
import jdk.internal.event.EventHelper;
46
import jdk.internal.event.TLSHandshakeEvent;
47
import sun.security.internal.spec.TlsPrfParameterSpec;
48
import sun.security.ssl.CipherSuite.HashAlg;
49
import static sun.security.ssl.CipherSuite.HashAlg.H_NONE;
50
import sun.security.ssl.SSLBasicKeyDerivation.SecretSizeSpec;
51
import sun.security.ssl.SSLCipher.SSLReadCipher;
52
import sun.security.ssl.SSLCipher.SSLWriteCipher;
53
import sun.security.ssl.SSLHandshake.HandshakeMessage;
54
import sun.security.util.HexDumpEncoder;
55
56
/**
57
* Pack of the Finished handshake message.
58
*/
59
final class Finished {
60
static final SSLConsumer t12HandshakeConsumer =
61
new T12FinishedConsumer();
62
static final HandshakeProducer t12HandshakeProducer =
63
new T12FinishedProducer();
64
65
static final SSLConsumer t13HandshakeConsumer =
66
new T13FinishedConsumer();
67
static final HandshakeProducer t13HandshakeProducer =
68
new T13FinishedProducer();
69
70
/**
71
* The Finished handshake message.
72
*/
73
private static final class FinishedMessage extends HandshakeMessage {
74
private final byte[] verifyData;
75
76
FinishedMessage(HandshakeContext context) throws IOException {
77
super(context);
78
79
VerifyDataScheme vds =
80
VerifyDataScheme.valueOf(context.negotiatedProtocol);
81
82
byte[] vd;
83
try {
84
vd = vds.createVerifyData(context, false);
85
} catch (IOException ioe) {
86
throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
87
"Failed to generate verify_data", ioe);
88
}
89
90
this.verifyData = vd;
91
}
92
93
FinishedMessage(HandshakeContext context,
94
ByteBuffer m) throws IOException {
95
super(context);
96
int verifyDataLen = 12;
97
if (context.negotiatedProtocol == ProtocolVersion.SSL30) {
98
verifyDataLen = 36;
99
} else if (context.negotiatedProtocol.useTLS13PlusSpec()) {
100
verifyDataLen =
101
context.negotiatedCipherSuite.hashAlg.hashLength;
102
}
103
104
if (m.remaining() != verifyDataLen) {
105
throw context.conContext.fatal(Alert.DECODE_ERROR,
106
"Inappropriate finished message: need " + verifyDataLen +
107
" but remaining " + m.remaining() + " bytes verify_data");
108
}
109
110
this.verifyData = new byte[verifyDataLen];
111
m.get(verifyData);
112
113
VerifyDataScheme vd =
114
VerifyDataScheme.valueOf(context.negotiatedProtocol);
115
byte[] myVerifyData;
116
try {
117
myVerifyData = vd.createVerifyData(context, true);
118
} catch (IOException ioe) {
119
throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
120
"Failed to generate verify_data", ioe);
121
}
122
if (!MessageDigest.isEqual(myVerifyData, verifyData)) {
123
throw context.conContext.fatal(Alert.DECRYPT_ERROR,
124
"The Finished message cannot be verified.");
125
}
126
}
127
128
@Override
129
public SSLHandshake handshakeType() {
130
return SSLHandshake.FINISHED;
131
}
132
133
@Override
134
public int messageLength() {
135
return verifyData.length;
136
}
137
138
@Override
139
public void send(HandshakeOutStream hos) throws IOException {
140
hos.write(verifyData);
141
}
142
143
@Override
144
public String toString() {
145
MessageFormat messageFormat = new MessageFormat(
146
"\"Finished\": '{'\n" +
147
" \"verify data\": '{'\n" +
148
"{0}\n" +
149
" '}'" +
150
"'}'",
151
Locale.ENGLISH);
152
153
HexDumpEncoder hexEncoder = new HexDumpEncoder();
154
Object[] messageFields = {
155
Utilities.indent(hexEncoder.encode(verifyData), " "),
156
};
157
return messageFormat.format(messageFields);
158
}
159
}
160
161
interface VerifyDataGenerator {
162
byte[] createVerifyData(HandshakeContext context,
163
boolean isValidation) throws IOException;
164
}
165
166
enum VerifyDataScheme {
167
SSL30 ("kdf_ssl30", new S30VerifyDataGenerator()),
168
TLS10 ("kdf_tls10", new T10VerifyDataGenerator()),
169
TLS12 ("kdf_tls12", new T12VerifyDataGenerator()),
170
TLS13 ("kdf_tls13", new T13VerifyDataGenerator());
171
172
final String name;
173
final VerifyDataGenerator generator;
174
175
VerifyDataScheme(String name, VerifyDataGenerator verifyDataGenerator) {
176
this.name = name;
177
this.generator = verifyDataGenerator;
178
}
179
180
static VerifyDataScheme valueOf(ProtocolVersion protocolVersion) {
181
switch (protocolVersion) {
182
case SSL30:
183
return VerifyDataScheme.SSL30;
184
case TLS10:
185
case TLS11:
186
case DTLS10:
187
return VerifyDataScheme.TLS10;
188
case TLS12:
189
case DTLS12:
190
return VerifyDataScheme.TLS12;
191
case TLS13:
192
return VerifyDataScheme.TLS13;
193
default:
194
return null;
195
}
196
}
197
198
public byte[] createVerifyData(HandshakeContext context,
199
boolean isValidation) throws IOException {
200
if (generator != null) {
201
return generator.createVerifyData(context, isValidation);
202
}
203
204
throw new UnsupportedOperationException("Not supported yet.");
205
}
206
}
207
208
// SSL 3.0
209
private static final
210
class S30VerifyDataGenerator implements VerifyDataGenerator {
211
@Override
212
public byte[] createVerifyData(HandshakeContext context,
213
boolean isValidation) throws IOException {
214
HandshakeHash handshakeHash = context.handshakeHash;
215
SecretKey masterSecretKey =
216
context.handshakeSession.getMasterSecret();
217
218
boolean useClientLabel =
219
(context.sslConfig.isClientMode && !isValidation) ||
220
(!context.sslConfig.isClientMode && isValidation);
221
return handshakeHash.digest(useClientLabel, masterSecretKey);
222
}
223
}
224
225
// TLS 1.0, TLS 1.1, DTLS 1.0
226
private static final
227
class T10VerifyDataGenerator implements VerifyDataGenerator {
228
@Override
229
public byte[] createVerifyData(HandshakeContext context,
230
boolean isValidation) throws IOException {
231
HandshakeHash handshakeHash = context.handshakeHash;
232
SecretKey masterSecretKey =
233
context.handshakeSession.getMasterSecret();
234
235
boolean useClientLabel =
236
(context.sslConfig.isClientMode && !isValidation) ||
237
(!context.sslConfig.isClientMode && isValidation);
238
String tlsLabel;
239
if (useClientLabel) {
240
tlsLabel = "client finished";
241
} else {
242
tlsLabel = "server finished";
243
}
244
245
try {
246
byte[] seed = handshakeHash.digest();
247
String prfAlg = "SunTlsPrf";
248
HashAlg hashAlg = H_NONE;
249
250
/*
251
* RFC 5246/7.4.9 says that finished messages can
252
* be ciphersuite-specific in both length/PRF hash
253
* algorithm. If we ever run across a different
254
* length, this call will need to be updated.
255
*/
256
@SuppressWarnings("deprecation")
257
TlsPrfParameterSpec spec = new TlsPrfParameterSpec(
258
masterSecretKey, tlsLabel, seed, 12,
259
hashAlg.name, hashAlg.hashLength, hashAlg.blockSize);
260
KeyGenerator kg = KeyGenerator.getInstance(prfAlg);
261
kg.init(spec);
262
SecretKey prfKey = kg.generateKey();
263
if (!"RAW".equals(prfKey.getFormat())) {
264
throw new ProviderException(
265
"Invalid PRF output, format must be RAW. " +
266
"Format received: " + prfKey.getFormat());
267
}
268
return prfKey.getEncoded();
269
} catch (GeneralSecurityException e) {
270
throw new RuntimeException("PRF failed", e);
271
}
272
}
273
}
274
275
// TLS 1.2
276
private static final
277
class T12VerifyDataGenerator implements VerifyDataGenerator {
278
@Override
279
public byte[] createVerifyData(HandshakeContext context,
280
boolean isValidation) throws IOException {
281
CipherSuite cipherSuite = context.negotiatedCipherSuite;
282
HandshakeHash handshakeHash = context.handshakeHash;
283
SecretKey masterSecretKey =
284
context.handshakeSession.getMasterSecret();
285
286
boolean useClientLabel =
287
(context.sslConfig.isClientMode && !isValidation) ||
288
(!context.sslConfig.isClientMode && isValidation);
289
String tlsLabel;
290
if (useClientLabel) {
291
tlsLabel = "client finished";
292
} else {
293
tlsLabel = "server finished";
294
}
295
296
try {
297
byte[] seed = handshakeHash.digest();
298
String prfAlg = "SunTls12Prf";
299
HashAlg hashAlg = cipherSuite.hashAlg;
300
301
/*
302
* RFC 5246/7.4.9 says that finished messages can
303
* be ciphersuite-specific in both length/PRF hash
304
* algorithm. If we ever run across a different
305
* length, this call will need to be updated.
306
*/
307
@SuppressWarnings("deprecation")
308
TlsPrfParameterSpec spec = new TlsPrfParameterSpec(
309
masterSecretKey, tlsLabel, seed, 12,
310
hashAlg.name, hashAlg.hashLength, hashAlg.blockSize);
311
KeyGenerator kg = KeyGenerator.getInstance(prfAlg);
312
kg.init(spec);
313
SecretKey prfKey = kg.generateKey();
314
if (!"RAW".equals(prfKey.getFormat())) {
315
throw new ProviderException(
316
"Invalid PRF output, format must be RAW. " +
317
"Format received: " + prfKey.getFormat());
318
}
319
return prfKey.getEncoded();
320
} catch (GeneralSecurityException e) {
321
throw new RuntimeException("PRF failed", e);
322
}
323
}
324
}
325
326
// TLS 1.3
327
private static final
328
class T13VerifyDataGenerator implements VerifyDataGenerator {
329
private static final byte[] hkdfLabel = "tls13 finished".getBytes();
330
private static final byte[] hkdfContext = new byte[0];
331
332
@Override
333
public byte[] createVerifyData(HandshakeContext context,
334
boolean isValidation) throws IOException {
335
// create finished secret key
336
HashAlg hashAlg =
337
context.negotiatedCipherSuite.hashAlg;
338
SecretKey secret = isValidation ?
339
context.baseReadSecret : context.baseWriteSecret;
340
SSLBasicKeyDerivation kdf = new SSLBasicKeyDerivation(
341
secret, hashAlg.name,
342
hkdfLabel, hkdfContext, hashAlg.hashLength);
343
AlgorithmParameterSpec keySpec =
344
new SecretSizeSpec(hashAlg.hashLength);
345
SecretKey finishedSecret =
346
kdf.deriveKey("TlsFinishedSecret", keySpec);
347
348
String hmacAlg =
349
"Hmac" + hashAlg.name.replace("-", "");
350
try {
351
Mac hmac = Mac.getInstance(hmacAlg);
352
hmac.init(finishedSecret);
353
return hmac.doFinal(context.handshakeHash.digest());
354
} catch (NoSuchAlgorithmException |InvalidKeyException ex) {
355
throw new ProviderException(
356
"Failed to generate verify_data", ex);
357
}
358
}
359
}
360
361
/**
362
* The "Finished" handshake message producer.
363
*/
364
private static final
365
class T12FinishedProducer implements HandshakeProducer {
366
// Prevent instantiation of this class.
367
private T12FinishedProducer() {
368
// blank
369
}
370
371
@Override
372
public byte[] produce(ConnectionContext context,
373
HandshakeMessage message) throws IOException {
374
// The consuming happens in handshake context only.
375
HandshakeContext hc = (HandshakeContext)context;
376
if (hc.sslConfig.isClientMode) {
377
return onProduceFinished(
378
(ClientHandshakeContext)context, message);
379
} else {
380
return onProduceFinished(
381
(ServerHandshakeContext)context, message);
382
}
383
}
384
385
private byte[] onProduceFinished(ClientHandshakeContext chc,
386
HandshakeMessage message) throws IOException {
387
// Refresh handshake hash
388
chc.handshakeHash.update();
389
390
FinishedMessage fm = new FinishedMessage(chc);
391
392
// Change write cipher and delivery ChangeCipherSpec message.
393
ChangeCipherSpec.t10Producer.produce(chc, message);
394
395
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
396
SSLLogger.fine(
397
"Produced client Finished handshake message", fm);
398
}
399
400
// Output the handshake message.
401
fm.write(chc.handshakeOutput);
402
chc.handshakeOutput.flush();
403
404
/*
405
* save server verify data for secure renegotiation
406
*/
407
if (chc.conContext.secureRenegotiation) {
408
chc.conContext.clientVerifyData = fm.verifyData;
409
}
410
411
if (chc.statelessResumption) {
412
chc.handshakeConsumers.put(
413
SSLHandshake.NEW_SESSION_TICKET.id, SSLHandshake.NEW_SESSION_TICKET);
414
}
415
// update the consumers and producers
416
if (!chc.isResumption) {
417
chc.conContext.consumers.put(ContentType.CHANGE_CIPHER_SPEC.id,
418
ChangeCipherSpec.t10Consumer);
419
chc.handshakeConsumers.put(
420
SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);
421
chc.conContext.inputRecord.expectingFinishFlight();
422
} else {
423
if (chc.handshakeSession.isRejoinable()) {
424
((SSLSessionContextImpl)chc.sslContext.
425
engineGetClientSessionContext()).put(
426
chc.handshakeSession);
427
}
428
chc.conContext.conSession = chc.handshakeSession.finish();
429
chc.conContext.protocolVersion = chc.negotiatedProtocol;
430
431
// handshake context cleanup.
432
chc.handshakeFinished = true;
433
434
// May need to retransmit the last flight for DTLS.
435
if (!chc.sslContext.isDTLS()) {
436
chc.conContext.finishHandshake();
437
}
438
}
439
440
// The handshake message has been delivered.
441
return null;
442
}
443
444
private byte[] onProduceFinished(ServerHandshakeContext shc,
445
HandshakeMessage message) throws IOException {
446
if (shc.statelessResumption) {
447
NewSessionTicket.handshake12Producer.produce(shc, message);
448
}
449
450
// Refresh handshake hash
451
shc.handshakeHash.update();
452
453
FinishedMessage fm = new FinishedMessage(shc);
454
455
// Change write cipher and delivery ChangeCipherSpec message.
456
ChangeCipherSpec.t10Producer.produce(shc, message);
457
458
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
459
SSLLogger.fine(
460
"Produced server Finished handshake message", fm);
461
}
462
463
// Output the handshake message.
464
fm.write(shc.handshakeOutput);
465
shc.handshakeOutput.flush();
466
467
/*
468
* save client verify data for secure renegotiation
469
*/
470
if (shc.conContext.secureRenegotiation) {
471
shc.conContext.serverVerifyData = fm.verifyData;
472
}
473
474
// update the consumers and producers
475
if (shc.isResumption) {
476
shc.conContext.consumers.put(ContentType.CHANGE_CIPHER_SPEC.id,
477
ChangeCipherSpec.t10Consumer);
478
shc.handshakeConsumers.put(
479
SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);
480
shc.conContext.inputRecord.expectingFinishFlight();
481
} else {
482
// Set the session's context based on stateless/cache status
483
if (shc.statelessResumption &&
484
shc.handshakeSession.isStatelessable()) {
485
shc.handshakeSession.setContext((SSLSessionContextImpl)
486
shc.sslContext.engineGetServerSessionContext());
487
} else {
488
if (shc.handshakeSession.isRejoinable()) {
489
((SSLSessionContextImpl)shc.sslContext.
490
engineGetServerSessionContext()).put(
491
shc.handshakeSession);
492
}
493
}
494
shc.conContext.conSession = shc.handshakeSession.finish();
495
shc.conContext.protocolVersion = shc.negotiatedProtocol;
496
497
// handshake context cleanup.
498
shc.handshakeFinished = true;
499
500
// May need to retransmit the last flight for DTLS.
501
if (!shc.sslContext.isDTLS()) {
502
shc.conContext.finishHandshake();
503
}
504
}
505
506
// The handshake message has been delivered.
507
return null;
508
}
509
}
510
511
/**
512
* The "Finished" handshake message consumer.
513
*/
514
private static final class T12FinishedConsumer implements SSLConsumer {
515
// Prevent instantiation of this class.
516
private T12FinishedConsumer() {
517
// blank
518
}
519
520
@Override
521
public void consume(ConnectionContext context,
522
ByteBuffer message) throws IOException {
523
// The consuming happens in handshake context only.
524
HandshakeContext hc = (HandshakeContext)context;
525
526
// This consumer can be used only once.
527
hc.handshakeConsumers.remove(SSLHandshake.FINISHED.id);
528
529
// We should not be processing finished messages unless
530
// we have received ChangeCipherSpec
531
if (hc.conContext.consumers.containsKey(
532
ContentType.CHANGE_CIPHER_SPEC.id)) {
533
throw hc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
534
"Missing ChangeCipherSpec message");
535
}
536
537
if (hc.sslConfig.isClientMode) {
538
onConsumeFinished((ClientHandshakeContext)context, message);
539
} else {
540
onConsumeFinished((ServerHandshakeContext)context, message);
541
}
542
}
543
544
private void onConsumeFinished(ClientHandshakeContext chc,
545
ByteBuffer message) throws IOException {
546
FinishedMessage fm = new FinishedMessage(chc, message);
547
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
548
SSLLogger.fine(
549
"Consuming server Finished handshake message", fm);
550
}
551
552
if (chc.conContext.secureRenegotiation) {
553
chc.conContext.serverVerifyData = fm.verifyData;
554
}
555
556
if (!chc.isResumption) {
557
if (chc.handshakeSession.isRejoinable()) {
558
((SSLSessionContextImpl)chc.sslContext.
559
engineGetClientSessionContext()).put(
560
chc.handshakeSession);
561
}
562
chc.conContext.conSession = chc.handshakeSession.finish();
563
chc.conContext.protocolVersion = chc.negotiatedProtocol;
564
565
// handshake context cleanup.
566
chc.handshakeFinished = true;
567
recordEvent(chc.conContext.conSession);
568
569
// May need to retransmit the last flight for DTLS.
570
if (!chc.sslContext.isDTLS()) {
571
chc.conContext.finishHandshake();
572
}
573
} else {
574
chc.handshakeProducers.put(SSLHandshake.FINISHED.id,
575
SSLHandshake.FINISHED);
576
}
577
578
//
579
// produce
580
//
581
SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {
582
SSLHandshake.FINISHED
583
};
584
585
for (SSLHandshake hs : probableHandshakeMessages) {
586
HandshakeProducer handshakeProducer =
587
chc.handshakeProducers.remove(hs.id);
588
if (handshakeProducer != null) {
589
handshakeProducer.produce(chc, fm);
590
}
591
}
592
}
593
594
private void onConsumeFinished(ServerHandshakeContext shc,
595
ByteBuffer message) throws IOException {
596
// Make sure that any expected CertificateVerify message
597
// has been received and processed.
598
if (!shc.isResumption) {
599
if (shc.handshakeConsumers.containsKey(
600
SSLHandshake.CERTIFICATE_VERIFY.id)) {
601
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
602
"Unexpected Finished handshake message");
603
}
604
}
605
606
FinishedMessage fm = new FinishedMessage(shc, message);
607
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
608
SSLLogger.fine(
609
"Consuming client Finished handshake message", fm);
610
}
611
612
if (shc.conContext.secureRenegotiation) {
613
shc.conContext.clientVerifyData = fm.verifyData;
614
}
615
616
if (shc.isResumption) {
617
if (shc.handshakeSession.isRejoinable() &&
618
!shc.statelessResumption) {
619
((SSLSessionContextImpl)shc.sslContext.
620
engineGetServerSessionContext()).put(
621
shc.handshakeSession);
622
}
623
shc.conContext.conSession = shc.handshakeSession.finish();
624
shc.conContext.protocolVersion = shc.negotiatedProtocol;
625
626
// handshake context cleanup.
627
shc.handshakeFinished = true;
628
recordEvent(shc.conContext.conSession);
629
630
// May need to retransmit the last flight for DTLS.
631
if (!shc.sslContext.isDTLS()) {
632
shc.conContext.finishHandshake();
633
}
634
} else {
635
shc.handshakeProducers.put(SSLHandshake.FINISHED.id,
636
SSLHandshake.FINISHED);
637
}
638
639
//
640
// produce
641
//
642
SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {
643
SSLHandshake.FINISHED
644
};
645
646
for (SSLHandshake hs : probableHandshakeMessages) {
647
HandshakeProducer handshakeProducer =
648
shc.handshakeProducers.remove(hs.id);
649
if (handshakeProducer != null) {
650
handshakeProducer.produce(shc, fm);
651
}
652
}
653
}
654
}
655
656
/**
657
* The "Finished" handshake message producer.
658
*/
659
private static final
660
class T13FinishedProducer implements HandshakeProducer {
661
// Prevent instantiation of this class.
662
private T13FinishedProducer() {
663
// blank
664
}
665
666
@Override
667
public byte[] produce(ConnectionContext context,
668
HandshakeMessage message) throws IOException {
669
// The consuming happens in handshake context only.
670
HandshakeContext hc = (HandshakeContext)context;
671
if (hc.sslConfig.isClientMode) {
672
return onProduceFinished(
673
(ClientHandshakeContext)context, message);
674
} else {
675
return onProduceFinished(
676
(ServerHandshakeContext)context, message);
677
}
678
}
679
680
private byte[] onProduceFinished(ClientHandshakeContext chc,
681
HandshakeMessage message) throws IOException {
682
// Refresh handshake hash
683
chc.handshakeHash.update();
684
685
FinishedMessage fm = new FinishedMessage(chc);
686
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
687
SSLLogger.fine(
688
"Produced client Finished handshake message", fm);
689
}
690
691
// Output the handshake message.
692
fm.write(chc.handshakeOutput);
693
chc.handshakeOutput.flush();
694
695
// save server verify data for secure renegotiation
696
if (chc.conContext.secureRenegotiation) {
697
chc.conContext.clientVerifyData = fm.verifyData;
698
}
699
700
// update the context
701
// Change client/server application traffic secrets.
702
SSLKeyDerivation kd = chc.handshakeKeyDerivation;
703
if (kd == null) {
704
// unlikely
705
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
706
"no key derivation");
707
}
708
709
SSLTrafficKeyDerivation kdg =
710
SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);
711
if (kdg == null) {
712
// unlikely
713
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
714
"Not supported key derivation: " +
715
chc.negotiatedProtocol);
716
}
717
718
try {
719
// update the application traffic read keys.
720
SecretKey writeSecret = kd.deriveKey(
721
"TlsClientAppTrafficSecret", null);
722
723
SSLKeyDerivation writeKD =
724
kdg.createKeyDerivation(chc, writeSecret);
725
SecretKey writeKey = writeKD.deriveKey(
726
"TlsKey", null);
727
SecretKey writeIvSecret = writeKD.deriveKey(
728
"TlsIv", null);
729
IvParameterSpec writeIv =
730
new IvParameterSpec(writeIvSecret.getEncoded());
731
SSLWriteCipher writeCipher =
732
chc.negotiatedCipherSuite.bulkCipher.createWriteCipher(
733
Authenticator.valueOf(chc.negotiatedProtocol),
734
chc.negotiatedProtocol, writeKey, writeIv,
735
chc.sslContext.getSecureRandom());
736
737
if (writeCipher == null) {
738
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
739
"Illegal cipher suite (" + chc.negotiatedCipherSuite +
740
") and protocol version (" + chc.negotiatedProtocol +
741
")");
742
}
743
744
chc.baseWriteSecret = writeSecret;
745
chc.conContext.outputRecord.changeWriteCiphers(
746
writeCipher, false);
747
748
} catch (GeneralSecurityException gse) {
749
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
750
"Failure to derive application secrets", gse);
751
}
752
753
// The resumption master secret is stored in the session so
754
// it can be used after the handshake is completed.
755
SSLSecretDerivation sd = ((SSLSecretDerivation) kd).forContext(chc);
756
SecretKey resumptionMasterSecret = sd.deriveKey(
757
"TlsResumptionMasterSecret", null);
758
chc.handshakeSession.setResumptionMasterSecret(
759
resumptionMasterSecret);
760
761
chc.conContext.conSession = chc.handshakeSession.finish();
762
chc.conContext.protocolVersion = chc.negotiatedProtocol;
763
764
// handshake context cleanup.
765
chc.handshakeFinished = true;
766
chc.conContext.finishHandshake();
767
recordEvent(chc.conContext.conSession);
768
769
770
// The handshake message has been delivered.
771
return null;
772
}
773
774
private byte[] onProduceFinished(ServerHandshakeContext shc,
775
HandshakeMessage message) throws IOException {
776
// Refresh handshake hash
777
shc.handshakeHash.update();
778
779
FinishedMessage fm = new FinishedMessage(shc);
780
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
781
SSLLogger.fine(
782
"Produced server Finished handshake message", fm);
783
}
784
785
// Output the handshake message.
786
fm.write(shc.handshakeOutput);
787
shc.handshakeOutput.flush();
788
789
// Change client/server application traffic secrets.
790
SSLKeyDerivation kd = shc.handshakeKeyDerivation;
791
if (kd == null) {
792
// unlikely
793
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
794
"no key derivation");
795
}
796
797
SSLTrafficKeyDerivation kdg =
798
SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
799
if (kdg == null) {
800
// unlikely
801
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
802
"Not supported key derivation: " +
803
shc.negotiatedProtocol);
804
}
805
806
// derive salt secret
807
try {
808
SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
809
810
// derive application secrets
811
HashAlg hashAlg = shc.negotiatedCipherSuite.hashAlg;
812
HKDF hkdf = new HKDF(hashAlg.name);
813
byte[] zeros = new byte[hashAlg.hashLength];
814
SecretKeySpec sharedSecret =
815
new SecretKeySpec(zeros, "TlsZeroSecret");
816
SecretKey masterSecret =
817
hkdf.extract(saltSecret, sharedSecret, "TlsMasterSecret");
818
819
SSLKeyDerivation secretKD =
820
new SSLSecretDerivation(shc, masterSecret);
821
822
// update the handshake traffic write keys.
823
SecretKey writeSecret = secretKD.deriveKey(
824
"TlsServerAppTrafficSecret", null);
825
SSLKeyDerivation writeKD =
826
kdg.createKeyDerivation(shc, writeSecret);
827
SecretKey writeKey = writeKD.deriveKey(
828
"TlsKey", null);
829
SecretKey writeIvSecret = writeKD.deriveKey(
830
"TlsIv", null);
831
IvParameterSpec writeIv =
832
new IvParameterSpec(writeIvSecret.getEncoded());
833
SSLWriteCipher writeCipher =
834
shc.negotiatedCipherSuite.bulkCipher.createWriteCipher(
835
Authenticator.valueOf(shc.negotiatedProtocol),
836
shc.negotiatedProtocol, writeKey, writeIv,
837
shc.sslContext.getSecureRandom());
838
839
if (writeCipher == null) {
840
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
841
"Illegal cipher suite (" + shc.negotiatedCipherSuite +
842
") and protocol version (" + shc.negotiatedProtocol +
843
")");
844
}
845
846
shc.baseWriteSecret = writeSecret;
847
shc.conContext.outputRecord.changeWriteCiphers(
848
writeCipher, false);
849
850
// update the context for the following key derivation
851
shc.handshakeKeyDerivation = secretKD;
852
} catch (GeneralSecurityException gse) {
853
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
854
"Failure to derive application secrets", gse);
855
}
856
857
/*
858
* save client verify data for secure renegotiation
859
*/
860
if (shc.conContext.secureRenegotiation) {
861
shc.conContext.serverVerifyData = fm.verifyData;
862
}
863
864
// Make sure session's context is set
865
shc.handshakeSession.setContext((SSLSessionContextImpl)
866
shc.sslContext.engineGetServerSessionContext());
867
shc.conContext.conSession = shc.handshakeSession.finish();
868
869
// update the context
870
shc.handshakeConsumers.put(
871
SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);
872
873
// The handshake message has been delivered.
874
return null;
875
}
876
}
877
878
/**
879
* The "Finished" handshake message consumer.
880
*/
881
private static final class T13FinishedConsumer implements SSLConsumer {
882
// Prevent instantiation of this class.
883
private T13FinishedConsumer() {
884
// blank
885
}
886
887
@Override
888
public void consume(ConnectionContext context,
889
ByteBuffer message) throws IOException {
890
// The consuming happens in handshake context only.
891
HandshakeContext hc = (HandshakeContext)context;
892
if (hc.sslConfig.isClientMode) {
893
onConsumeFinished(
894
(ClientHandshakeContext)context, message);
895
} else {
896
onConsumeFinished(
897
(ServerHandshakeContext)context, message);
898
}
899
}
900
901
private void onConsumeFinished(ClientHandshakeContext chc,
902
ByteBuffer message) throws IOException {
903
// Make sure that any expected CertificateVerify message
904
// has been received and processed.
905
if (!chc.isResumption) {
906
if (chc.handshakeConsumers.containsKey(
907
SSLHandshake.CERTIFICATE.id) ||
908
chc.handshakeConsumers.containsKey(
909
SSLHandshake.CERTIFICATE_VERIFY.id)) {
910
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
911
"Unexpected Finished handshake message");
912
}
913
}
914
915
FinishedMessage fm = new FinishedMessage(chc, message);
916
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
917
SSLLogger.fine(
918
"Consuming server Finished handshake message", fm);
919
}
920
921
// Save client verify data for secure renegotiation.
922
if (chc.conContext.secureRenegotiation) {
923
chc.conContext.serverVerifyData = fm.verifyData;
924
}
925
926
//
927
// validate
928
//
929
// blank
930
931
//
932
// update
933
//
934
// A change_cipher_spec record received after the peer's Finished
935
// message MUST be treated as an unexpected record type.
936
chc.conContext.consumers.remove(ContentType.CHANGE_CIPHER_SPEC.id);
937
938
// Change client/server application traffic secrets.
939
// Refresh handshake hash
940
chc.handshakeHash.update();
941
SSLKeyDerivation kd = chc.handshakeKeyDerivation;
942
if (kd == null) {
943
// unlikely
944
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
945
"no key derivation");
946
}
947
948
SSLTrafficKeyDerivation kdg =
949
SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);
950
if (kdg == null) {
951
// unlikely
952
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
953
"Not supported key derivation: " +
954
chc.negotiatedProtocol);
955
}
956
957
// save the session
958
if (!chc.isResumption && chc.handshakeSession.isRejoinable()) {
959
((SSLSessionContextImpl)chc.sslContext.
960
engineGetClientSessionContext()).
961
put(chc.handshakeSession);
962
}
963
964
// derive salt secret
965
try {
966
SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
967
968
// derive application secrets
969
HashAlg hashAlg = chc.negotiatedCipherSuite.hashAlg;
970
HKDF hkdf = new HKDF(hashAlg.name);
971
byte[] zeros = new byte[hashAlg.hashLength];
972
SecretKeySpec sharedSecret =
973
new SecretKeySpec(zeros, "TlsZeroSecret");
974
SecretKey masterSecret =
975
hkdf.extract(saltSecret, sharedSecret, "TlsMasterSecret");
976
977
SSLKeyDerivation secretKD =
978
new SSLSecretDerivation(chc, masterSecret);
979
980
// update the handshake traffic read keys.
981
SecretKey readSecret = secretKD.deriveKey(
982
"TlsServerAppTrafficSecret", null);
983
SSLKeyDerivation writeKD =
984
kdg.createKeyDerivation(chc, readSecret);
985
SecretKey readKey = writeKD.deriveKey(
986
"TlsKey", null);
987
SecretKey readIvSecret = writeKD.deriveKey(
988
"TlsIv", null);
989
IvParameterSpec readIv =
990
new IvParameterSpec(readIvSecret.getEncoded());
991
SSLReadCipher readCipher =
992
chc.negotiatedCipherSuite.bulkCipher.createReadCipher(
993
Authenticator.valueOf(chc.negotiatedProtocol),
994
chc.negotiatedProtocol, readKey, readIv,
995
chc.sslContext.getSecureRandom());
996
997
if (readCipher == null) {
998
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
999
"Illegal cipher suite (" + chc.negotiatedCipherSuite +
1000
") and protocol version (" + chc.negotiatedProtocol +
1001
")");
1002
}
1003
1004
chc.baseReadSecret = readSecret;
1005
chc.conContext.inputRecord.changeReadCiphers(readCipher);
1006
1007
// update the context for the following key derivation
1008
chc.handshakeKeyDerivation = secretKD;
1009
} catch (GeneralSecurityException gse) {
1010
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
1011
"Failure to derive application secrets", gse);
1012
}
1013
1014
//
1015
// produce
1016
//
1017
chc.handshakeProducers.put(SSLHandshake.FINISHED.id,
1018
SSLHandshake.FINISHED);
1019
SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {
1020
// full handshake messages
1021
SSLHandshake.CERTIFICATE,
1022
SSLHandshake.CERTIFICATE_VERIFY,
1023
SSLHandshake.FINISHED
1024
};
1025
1026
for (SSLHandshake hs : probableHandshakeMessages) {
1027
HandshakeProducer handshakeProducer =
1028
chc.handshakeProducers.remove(hs.id);
1029
if (handshakeProducer != null) {
1030
handshakeProducer.produce(chc, null);
1031
}
1032
}
1033
}
1034
1035
private void onConsumeFinished(ServerHandshakeContext shc,
1036
ByteBuffer message) throws IOException {
1037
// Make sure that any expected CertificateVerify message
1038
// has been received and processed.
1039
if (!shc.isResumption) {
1040
if (shc.handshakeConsumers.containsKey(
1041
SSLHandshake.CERTIFICATE.id) ||
1042
shc.handshakeConsumers.containsKey(
1043
SSLHandshake.CERTIFICATE_VERIFY.id)) {
1044
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
1045
"Unexpected Finished handshake message");
1046
}
1047
}
1048
1049
FinishedMessage fm = new FinishedMessage(shc, message);
1050
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1051
SSLLogger.fine(
1052
"Consuming client Finished handshake message", fm);
1053
}
1054
1055
if (shc.conContext.secureRenegotiation) {
1056
shc.conContext.clientVerifyData = fm.verifyData;
1057
}
1058
1059
//
1060
// validate
1061
//
1062
// blank
1063
1064
//
1065
// update
1066
//
1067
// Change client/server application traffic secrets.
1068
SSLKeyDerivation kd = shc.handshakeKeyDerivation;
1069
if (kd == null) {
1070
// unlikely
1071
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
1072
"no key derivation");
1073
}
1074
1075
SSLTrafficKeyDerivation kdg =
1076
SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
1077
if (kdg == null) {
1078
// unlikely
1079
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
1080
"Not supported key derivation: " +
1081
shc.negotiatedProtocol);
1082
}
1083
1084
try {
1085
// update the application traffic read keys.
1086
SecretKey readSecret = kd.deriveKey(
1087
"TlsClientAppTrafficSecret", null);
1088
1089
SSLKeyDerivation readKD =
1090
kdg.createKeyDerivation(shc, readSecret);
1091
SecretKey readKey = readKD.deriveKey(
1092
"TlsKey", null);
1093
SecretKey readIvSecret = readKD.deriveKey(
1094
"TlsIv", null);
1095
IvParameterSpec readIv =
1096
new IvParameterSpec(readIvSecret.getEncoded());
1097
SSLReadCipher readCipher =
1098
shc.negotiatedCipherSuite.bulkCipher.createReadCipher(
1099
Authenticator.valueOf(shc.negotiatedProtocol),
1100
shc.negotiatedProtocol, readKey, readIv,
1101
shc.sslContext.getSecureRandom());
1102
1103
if (readCipher == null) {
1104
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
1105
"Illegal cipher suite (" + shc.negotiatedCipherSuite +
1106
") and protocol version (" + shc.negotiatedProtocol +
1107
")");
1108
}
1109
1110
shc.baseReadSecret = readSecret;
1111
shc.conContext.inputRecord.changeReadCiphers(readCipher);
1112
1113
// The resumption master secret is stored in the session so
1114
// it can be used after the handshake is completed.
1115
shc.handshakeHash.update();
1116
SSLSecretDerivation sd =
1117
((SSLSecretDerivation)kd).forContext(shc);
1118
SecretKey resumptionMasterSecret = sd.deriveKey(
1119
"TlsResumptionMasterSecret", null);
1120
shc.handshakeSession.setResumptionMasterSecret(
1121
resumptionMasterSecret);
1122
} catch (GeneralSecurityException gse) {
1123
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
1124
"Failure to derive application secrets", gse);
1125
}
1126
1127
// update connection context
1128
shc.conContext.conSession = shc.handshakeSession.finish();
1129
shc.conContext.protocolVersion = shc.negotiatedProtocol;
1130
1131
// handshake context cleanup.
1132
shc.handshakeFinished = true;
1133
1134
// May need to retransmit the last flight for DTLS.
1135
if (!shc.sslContext.isDTLS()) {
1136
shc.conContext.finishHandshake();
1137
}
1138
recordEvent(shc.conContext.conSession);
1139
1140
//
1141
// produce
1142
NewSessionTicket.t13PosthandshakeProducer.produce(shc);
1143
}
1144
}
1145
1146
private static void recordEvent(SSLSessionImpl session) {
1147
TLSHandshakeEvent event = new TLSHandshakeEvent();
1148
if (event.shouldCommit() || EventHelper.isLoggingSecurity()) {
1149
int peerCertificateId = 0;
1150
try {
1151
// use hash code for Id
1152
peerCertificateId = session
1153
.getCertificateChain()[0]
1154
.hashCode();
1155
} catch (SSLPeerUnverifiedException e) {
1156
// not verified msg
1157
}
1158
if (event.shouldCommit()) {
1159
event.peerHost = session.getPeerHost();
1160
event.peerPort = session.getPeerPort();
1161
event.cipherSuite = session.getCipherSuite();
1162
event.protocolVersion = session.getProtocol();
1163
event.certificateId = peerCertificateId;
1164
event.commit();
1165
}
1166
if (EventHelper.isLoggingSecurity()) {
1167
EventHelper.logTLSHandshakeEvent(null,
1168
session.getPeerHost(),
1169
session.getPeerPort(),
1170
session.getCipherSuite(),
1171
session.getProtocol(),
1172
peerCertificateId);
1173
}
1174
}
1175
}
1176
}
1177
1178