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/ClientHello.java
38830 views
1
/*
2
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
3
* Copyright (c) 2020, Azul Systems, Inc. All rights reserved.
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
*
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation. Oracle designates this
9
* particular file as subject to the "Classpath" exception as provided
10
* by Oracle in the LICENSE file that accompanied this code.
11
*
12
* This code is distributed in the hope that it will be useful, but WITHOUT
13
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15
* version 2 for more details (a copy is included in the LICENSE file that
16
* accompanied this code).
17
*
18
* You should have received a copy of the GNU General Public License version
19
* 2 along with this work; if not, write to the Free Software Foundation,
20
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21
*
22
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23
* or visit www.oracle.com if you need additional information or have any
24
* questions.
25
*/
26
27
package sun.security.ssl;
28
29
import java.io.IOException;
30
import java.nio.ByteBuffer;
31
import java.security.AccessController;
32
import java.security.Principal;
33
import java.security.PrivilegedActionException;
34
import java.security.PrivilegedExceptionAction;
35
import java.security.SecureRandom;
36
import java.security.cert.X509Certificate;
37
import java.text.MessageFormat;
38
import java.util.Arrays;
39
import java.util.Collections;
40
import java.util.LinkedList;
41
import java.util.List;
42
import java.util.Locale;
43
import java.util.Objects;
44
import javax.net.ssl.SSLException;
45
import javax.net.ssl.SSLHandshakeException;
46
import javax.net.ssl.SSLPeerUnverifiedException;
47
import javax.net.ssl.SSLProtocolException;
48
import javax.security.auth.Subject;
49
50
import static sun.security.ssl.CipherSuite.KeyExchange.K_KRB5;
51
import static sun.security.ssl.CipherSuite.KeyExchange.K_KRB5_EXPORT;
52
import static sun.security.ssl.ClientAuthType.CLIENT_AUTH_REQUIRED;
53
import sun.security.ssl.SSLHandshake.HandshakeMessage;
54
import sun.security.ssl.SupportedVersionsExtension.CHSupportedVersionsSpec;
55
56
/**
57
* Pack of the ClientHello handshake message.
58
*/
59
final class ClientHello {
60
static final SSLProducer kickstartProducer =
61
new ClientHelloKickstartProducer();
62
static final SSLConsumer handshakeConsumer =
63
new ClientHelloConsumer();
64
static final HandshakeProducer handshakeProducer =
65
new ClientHelloProducer();
66
67
private static final HandshakeConsumer t12HandshakeConsumer =
68
new T12ClientHelloConsumer();
69
private static final HandshakeConsumer t13HandshakeConsumer =
70
new T13ClientHelloConsumer();
71
72
/**
73
* The ClientHello handshake message.
74
*
75
* See RFC 5264/4346/2246/6347 for the specifications.
76
*/
77
static final class ClientHelloMessage extends HandshakeMessage {
78
final int clientVersion;
79
final RandomCookie clientRandom;
80
final SessionId sessionId;
81
final int[] cipherSuiteIds;
82
final List<CipherSuite> cipherSuites; // known cipher suites only
83
final byte[] compressionMethod;
84
final SSLExtensions extensions;
85
86
private static final byte[] NULL_COMPRESSION = new byte[] {0};
87
88
ClientHelloMessage(HandshakeContext handshakeContext,
89
int clientVersion, SessionId sessionId,
90
List<CipherSuite> cipherSuites, SecureRandom generator) {
91
super(handshakeContext);
92
93
this.clientVersion = clientVersion;
94
this.clientRandom = new RandomCookie(generator);
95
this.sessionId = sessionId;
96
97
this.cipherSuites = cipherSuites;
98
this.cipherSuiteIds = getCipherSuiteIds(cipherSuites);
99
this.extensions = new SSLExtensions(this);
100
101
// Don't support compression.
102
this.compressionMethod = NULL_COMPRESSION;
103
}
104
105
/* Read up to the binders in the PSK extension. After this method
106
* returns, the ByteBuffer position will be at end of the message
107
* fragment that should be hashed to produce the PSK binder values.
108
* The client of this method can use this position to determine the
109
* message fragment and produce the binder values.
110
*/
111
static void readPartial(TransportContext tc,
112
ByteBuffer m) throws IOException {
113
// version
114
Record.getInt16(m);
115
116
new RandomCookie(m);
117
118
// session ID
119
Record.getBytes8(m);
120
121
// cipher suite IDs
122
Record.getBytes16(m);
123
// compression method
124
Record.getBytes8(m);
125
// read extensions, if present
126
if (m.remaining() >= 2) {
127
int remaining = Record.getInt16(m);
128
while (remaining > 0) {
129
int id = Record.getInt16(m);
130
int extLen = Record.getInt16(m);
131
remaining -= extLen + 4;
132
133
if (id == SSLExtension.CH_PRE_SHARED_KEY.id) {
134
// ensure pre_shared_key is the last extension
135
if (remaining > 0) {
136
throw tc.fatal(Alert.ILLEGAL_PARAMETER,
137
"pre_shared_key extension is not last");
138
}
139
// read only up to the IDs
140
Record.getBytes16(m);
141
return;
142
} else {
143
m.position(m.position() + extLen);
144
145
}
146
}
147
} // Otherwise, ignore the remaining bytes.
148
}
149
150
ClientHelloMessage(HandshakeContext handshakeContext, ByteBuffer m,
151
SSLExtension[] supportedExtensions) throws IOException {
152
super(handshakeContext);
153
154
this.clientVersion = ((m.get() & 0xFF) << 8) | (m.get() & 0xFF);
155
this.clientRandom = new RandomCookie(m);
156
this.sessionId = new SessionId(Record.getBytes8(m));
157
try {
158
sessionId.checkLength(clientVersion);
159
} catch (SSLProtocolException ex) {
160
throw handshakeContext.conContext.fatal(
161
Alert.ILLEGAL_PARAMETER, ex);
162
}
163
byte[] encodedIds = Record.getBytes16(m);
164
if (encodedIds.length == 0 || (encodedIds.length & 0x01) != 0) {
165
throw handshakeContext.conContext.fatal(
166
Alert.ILLEGAL_PARAMETER,
167
"Invalid ClientHello message");
168
}
169
170
this.cipherSuiteIds = new int[encodedIds.length >> 1];
171
for (int i = 0, j = 0; i < encodedIds.length; i++, j++) {
172
cipherSuiteIds[j] =
173
((encodedIds[i++] & 0xFF) << 8) | (encodedIds[i] & 0xFF);
174
}
175
this.cipherSuites = getCipherSuites(cipherSuiteIds);
176
177
this.compressionMethod = Record.getBytes8(m);
178
// In TLS 1.3, use of certain extensions is mandatory.
179
if (m.hasRemaining()) {
180
this.extensions =
181
new SSLExtensions(this, m, supportedExtensions);
182
} else {
183
this.extensions = new SSLExtensions(this);
184
}
185
}
186
187
// TLS 1.3, for cookie generation.
188
byte[] getHeaderBytes() {
189
HandshakeOutStream hos = new HandshakeOutStream(null);
190
try {
191
// copied from send() method
192
hos.putInt8((byte)((clientVersion >>> 8) & 0xFF));
193
hos.putInt8((byte)(clientVersion & 0xFF));
194
hos.write(clientRandom.randomBytes, 0, 32);
195
hos.putBytes8(sessionId.getId());
196
hos.putBytes16(getEncodedCipherSuites());
197
hos.putBytes8(compressionMethod);
198
} catch (IOException ioe) {
199
// unlikely
200
}
201
202
return hos.toByteArray();
203
}
204
205
private static int[] getCipherSuiteIds(
206
List<CipherSuite> cipherSuites) {
207
if (cipherSuites != null) {
208
int[] ids = new int[cipherSuites.size()];
209
int i = 0;
210
for (CipherSuite cipherSuite : cipherSuites) {
211
ids[i++] = cipherSuite.id;
212
}
213
214
return ids;
215
}
216
217
return new int[0];
218
}
219
220
private static List<CipherSuite> getCipherSuites(int[] ids) {
221
List<CipherSuite> cipherSuites = new LinkedList<>();
222
for (int id : ids) {
223
CipherSuite cipherSuite = CipherSuite.valueOf(id);
224
if (cipherSuite != null) {
225
cipherSuites.add(cipherSuite);
226
}
227
}
228
229
return Collections.unmodifiableList(cipherSuites);
230
}
231
232
private List<String> getCipherSuiteNames() {
233
List<String> names = new LinkedList<>();
234
for (int id : cipherSuiteIds) {
235
names.add(CipherSuite.nameOf(id) +
236
"(" + Utilities.byte16HexString(id) + ")"); }
237
238
return names;
239
}
240
241
private byte[] getEncodedCipherSuites() {
242
byte[] encoded = new byte[cipherSuiteIds.length << 1];
243
int i = 0;
244
for (int id : cipherSuiteIds) {
245
encoded[i++] = (byte)(id >> 8);
246
encoded[i++] = (byte)id;
247
}
248
return encoded;
249
}
250
251
@Override
252
public SSLHandshake handshakeType() {
253
return SSLHandshake.CLIENT_HELLO;
254
}
255
256
@Override
257
public int messageLength() {
258
/*
259
* Add fixed size parts of each field...
260
* version + random + session + cipher + compress
261
*/
262
return (2 + 32 + 1 + 2 + 1
263
+ sessionId.length() /* ... + variable parts */
264
+ (cipherSuiteIds.length * 2)
265
+ compressionMethod.length)
266
+ extensions.length(); // In TLS 1.3, use of certain
267
// extensions is mandatory.
268
}
269
270
@Override
271
public void send(HandshakeOutStream hos) throws IOException {
272
sendCore(hos);
273
extensions.send(hos); // In TLS 1.3, use of certain
274
// extensions is mandatory.
275
}
276
277
void sendCore(HandshakeOutStream hos) throws IOException {
278
hos.putInt8((byte) (clientVersion >>> 8));
279
hos.putInt8((byte) clientVersion);
280
hos.write(clientRandom.randomBytes, 0, 32);
281
hos.putBytes8(sessionId.getId());
282
hos.putBytes16(getEncodedCipherSuites());
283
hos.putBytes8(compressionMethod);
284
}
285
286
@Override
287
public String toString() {
288
MessageFormat messageFormat = new MessageFormat(
289
"\"ClientHello\": '{'\n" +
290
" \"client version\" : \"{0}\",\n" +
291
" \"random\" : \"{1}\",\n" +
292
" \"session id\" : \"{2}\",\n" +
293
" \"cipher suites\" : \"{3}\",\n" +
294
" \"compression methods\" : \"{4}\",\n" +
295
" \"extensions\" : [\n" +
296
"{5}\n" +
297
" ]\n" +
298
"'}'",
299
Locale.ENGLISH);
300
Object[] messageFields = {
301
ProtocolVersion.nameOf(clientVersion),
302
Utilities.toHexString(clientRandom.randomBytes),
303
sessionId.toString(),
304
getCipherSuiteNames().toString(),
305
Utilities.toHexString(compressionMethod),
306
Utilities.indent(Utilities.indent(extensions.toString()))
307
};
308
309
return messageFormat.format(messageFields);
310
}
311
}
312
313
/**
314
* The "ClientHello" handshake message kick start producer.
315
*/
316
private static final
317
class ClientHelloKickstartProducer implements SSLProducer {
318
// Prevent instantiation of this class.
319
private ClientHelloKickstartProducer() {
320
// blank
321
}
322
323
// Produce kickstart handshake message.
324
@Override
325
public byte[] produce(ConnectionContext context) throws IOException {
326
// The producing happens in client side only.
327
ClientHandshakeContext chc = (ClientHandshakeContext)context;
328
329
// clean up this producer
330
chc.handshakeProducers.remove(SSLHandshake.CLIENT_HELLO.id);
331
332
// the max protocol version this client is supporting.
333
ProtocolVersion maxProtocolVersion = chc.maximumActiveProtocol;
334
335
// session ID of the ClientHello message
336
SessionId sessionId = new SessionId(new byte[0]);
337
338
// a list of cipher suites sent by the client
339
List<CipherSuite> cipherSuites = chc.activeCipherSuites;
340
341
//
342
// Try to resume an existing session.
343
//
344
SSLSessionContextImpl ssci = (SSLSessionContextImpl)
345
chc.sslContext.engineGetClientSessionContext();
346
SSLSessionImpl session = ssci.get(
347
chc.conContext.transport.getPeerHost(),
348
chc.conContext.transport.getPeerPort());
349
if (session != null) {
350
// If unsafe server certificate change is not allowed, reserve
351
// current server certificates if the previous handshake is a
352
// session-resumption abbreviated initial handshake.
353
if (!ClientHandshakeContext.allowUnsafeServerCertChange &&
354
session.isSessionResumption()) {
355
try {
356
// If existing, peer certificate chain cannot be null.
357
chc.reservedServerCerts =
358
(X509Certificate[])session.getPeerCertificates();
359
} catch (SSLPeerUnverifiedException puve) {
360
// Maybe not certificate-based, ignore the exception.
361
}
362
}
363
364
if (!session.isRejoinable()) {
365
session = null;
366
if (SSLLogger.isOn &&
367
SSLLogger.isOn("ssl,handshake,verbose")) {
368
SSLLogger.finest(
369
"Can't resume, the session is not rejoinable");
370
}
371
}
372
}
373
374
CipherSuite sessionSuite = null;
375
if (session != null) {
376
sessionSuite = session.getSuite();
377
if (!chc.isNegotiable(sessionSuite)) {
378
session = null;
379
if (SSLLogger.isOn &&
380
SSLLogger.isOn("ssl,handshake,verbose")) {
381
SSLLogger.finest(
382
"Can't resume, unavailable session cipher suite");
383
}
384
}
385
}
386
387
ProtocolVersion sessionVersion = null;
388
if (session != null) {
389
sessionVersion = session.getProtocolVersion();
390
if (!chc.isNegotiable(sessionVersion)) {
391
session = null;
392
if (SSLLogger.isOn &&
393
SSLLogger.isOn("ssl,handshake,verbose")) {
394
SSLLogger.finest(
395
"Can't resume, unavailable protocol version");
396
}
397
}
398
}
399
400
if (session != null &&
401
!sessionVersion.useTLS13PlusSpec() &&
402
SSLConfiguration.useExtendedMasterSecret) {
403
404
boolean isEmsAvailable = chc.sslConfig.isAvailable(
405
SSLExtension.CH_EXTENDED_MASTER_SECRET, sessionVersion);
406
if (isEmsAvailable && !session.useExtendedMasterSecret &&
407
!SSLConfiguration.allowLegacyResumption) {
408
// perform full handshake instead
409
//
410
// The client SHOULD NOT offer an abbreviated handshake
411
// to resume a session that does not use an extended
412
// master secret. Instead, it SHOULD offer a full
413
// handshake.
414
session = null;
415
}
416
417
if ((session != null) &&
418
!ClientHandshakeContext.allowUnsafeServerCertChange) {
419
// It is fine to move on with abbreviate handshake if
420
// endpoint identification is enabled.
421
String identityAlg = chc.sslConfig.identificationProtocol;
422
if (identityAlg == null || identityAlg.isEmpty()) {
423
if (isEmsAvailable) {
424
if (!session.useExtendedMasterSecret) {
425
// perform full handshake instead
426
session = null;
427
} // Otherwise, use extended master secret.
428
} else {
429
// The extended master secret extension does not
430
// apply to SSL 3.0. Perform a full handshake
431
// instead.
432
//
433
// Note that the useExtendedMasterSecret is
434
// extended to protect SSL 3.0 connections,
435
// by discarding abbreviate handshake.
436
session = null;
437
}
438
}
439
}
440
}
441
442
// ensure that the endpoint identification algorithm matches the
443
// one in the session
444
String identityAlg = chc.sslConfig.identificationProtocol;
445
if (session != null && identityAlg != null) {
446
String sessionIdentityAlg =
447
session.getIdentificationProtocol();
448
if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) {
449
if (SSLLogger.isOn &&
450
SSLLogger.isOn("ssl,handshake,verbose")) {
451
SSLLogger.finest("Can't resume, endpoint id" +
452
" algorithm does not match, requested: " +
453
identityAlg + ", cached: " + sessionIdentityAlg);
454
}
455
session = null;
456
}
457
}
458
459
if (session != null) {
460
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {
461
SSLLogger.finest("Try resuming session", session);
462
}
463
464
// only set session id if session is 1.2 or earlier
465
if (!session.getProtocolVersion().useTLS13PlusSpec()) {
466
sessionId = session.getSessionId();
467
}
468
if (!maxProtocolVersion.equals(sessionVersion)) {
469
maxProtocolVersion = sessionVersion;
470
471
// Update protocol version number in underlying socket and
472
// handshake output stream, so that the output records
473
// (at the record layer) have the correct version
474
chc.setVersion(sessionVersion);
475
}
476
477
// If no new session is allowed, force use of the previous
478
// session ciphersuite, and add the renegotiation SCSV if
479
// necessary.
480
if (!chc.sslConfig.enableSessionCreation) {
481
if (!chc.conContext.isNegotiated &&
482
!sessionVersion.useTLS13PlusSpec() &&
483
cipherSuites.contains(
484
CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
485
cipherSuites = Arrays.asList(sessionSuite,
486
CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
487
} else { // otherwise, use renegotiation_info extension
488
cipherSuites = Arrays.asList(sessionSuite);
489
}
490
491
if (SSLLogger.isOn &&
492
SSLLogger.isOn("ssl,handshake,verbose")) {
493
SSLLogger.finest(
494
"No new session is allowed, so try to resume " +
495
"the session cipher suite only", sessionSuite);
496
}
497
}
498
499
chc.isResumption = true;
500
chc.resumingSession = session;
501
}
502
503
if (session == null) {
504
if (!chc.sslConfig.enableSessionCreation) {
505
throw new SSLHandshakeException(
506
"No new session is allowed and " +
507
"no existing session can be resumed");
508
}
509
510
if (maxProtocolVersion.useTLS13PlusSpec() &&
511
SSLConfiguration.useCompatibilityMode) {
512
// In compatibility mode, the TLS 1.3 legacy_session_id
513
// field MUST be non-empty, so a client not offering a
514
// pre-TLS 1.3 session MUST generate a new 32-byte value.
515
sessionId =
516
new SessionId(true, chc.sslContext.getSecureRandom());
517
}
518
}
519
520
ProtocolVersion minimumVersion = ProtocolVersion.NONE;
521
for (ProtocolVersion pv : chc.activeProtocols) {
522
if (minimumVersion == ProtocolVersion.NONE ||
523
pv.compare(minimumVersion) < 0) {
524
minimumVersion = pv;
525
}
526
}
527
528
// exclude SCSV for secure renegotiation
529
if (!minimumVersion.useTLS13PlusSpec()) {
530
if (chc.conContext.secureRenegotiation &&
531
cipherSuites.contains(
532
CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
533
// The cipherSuites may be unmodifiable
534
cipherSuites = new LinkedList<>(cipherSuites);
535
cipherSuites.remove(
536
CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
537
}
538
}
539
540
// make sure there is a negotiable cipher suite.
541
boolean negotiable = false;
542
for (CipherSuite suite : cipherSuites) {
543
if (chc.isNegotiable(suite)) {
544
negotiable = true;
545
break;
546
}
547
}
548
if (!negotiable) {
549
throw new SSLHandshakeException("No negotiable cipher suite");
550
}
551
552
// Create the handshake message.
553
ProtocolVersion clientHelloVersion = maxProtocolVersion;
554
if (clientHelloVersion.useTLS13PlusSpec()) {
555
// In TLS 1.3, the client indicates its version preferences
556
// in the "supported_versions" extension and the client_version
557
// (legacy_version) field MUST be set to TLS 1.2.
558
clientHelloVersion = ProtocolVersion.TLS12;
559
}
560
561
ClientHelloMessage chm = new ClientHelloMessage(chc,
562
clientHelloVersion.id, sessionId, cipherSuites,
563
chc.sslContext.getSecureRandom());
564
565
// cache the client random number for further using
566
chc.clientHelloRandom = chm.clientRandom;
567
chc.clientHelloVersion = clientHelloVersion.id;
568
569
// Produce extensions for ClientHello handshake message.
570
SSLExtension[] extTypes = chc.sslConfig.getEnabledExtensions(
571
SSLHandshake.CLIENT_HELLO, chc.activeProtocols);
572
chm.extensions.produce(chc, extTypes);
573
574
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
575
SSLLogger.fine("Produced ClientHello handshake message", chm);
576
}
577
578
// Output the handshake message.
579
chm.write(chc.handshakeOutput);
580
chc.handshakeOutput.flush();
581
582
// Reserve the initial ClientHello message for the follow on
583
// cookie exchange if needed.
584
chc.initialClientHelloMsg = chm;
585
586
// What's the expected response?
587
chc.handshakeConsumers.put(
588
SSLHandshake.SERVER_HELLO.id, SSLHandshake.SERVER_HELLO);
589
590
// The handshake message has been delivered.
591
return null;
592
}
593
}
594
595
private static final
596
class ClientHelloProducer implements HandshakeProducer {
597
// Prevent instantiation of this class.
598
private ClientHelloProducer() {
599
// blank
600
}
601
602
// Response to one of the following handshake message:
603
// HelloRequest (SSL 3.0/TLS 1.0/1.1/1.2)
604
// ServerHello(HelloRetryRequest) (TLS 1.3)
605
@Override
606
public byte[] produce(ConnectionContext context,
607
HandshakeMessage message) throws IOException {
608
// The producing happens in client side only.
609
ClientHandshakeContext chc = (ClientHandshakeContext)context;
610
611
SSLHandshake ht = message.handshakeType();
612
if (ht == null) {
613
throw new UnsupportedOperationException("Not supported yet.");
614
}
615
616
switch (ht) {
617
case HELLO_REQUEST:
618
// SSL 3.0/TLS 1.0/1.1/1.2
619
try {
620
chc.kickstart();
621
} catch (IOException ioe) {
622
throw chc.conContext.fatal(
623
Alert.HANDSHAKE_FAILURE, ioe);
624
}
625
626
// The handshake message has been delivered.
627
return null;
628
case HELLO_RETRY_REQUEST:
629
// TLS 1.3
630
// The HelloRetryRequest consumer should have updated the
631
// ClientHello handshake message with cookie.
632
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
633
SSLLogger.fine(
634
"Produced ClientHello(HRR) handshake message",
635
chc.initialClientHelloMsg);
636
}
637
638
// Output the handshake message.
639
chc.initialClientHelloMsg.write(chc.handshakeOutput);
640
chc.handshakeOutput.flush();
641
642
// What's the expected response?
643
chc.conContext.consumers.putIfAbsent(
644
ContentType.CHANGE_CIPHER_SPEC.id,
645
ChangeCipherSpec.t13Consumer);
646
chc.handshakeConsumers.put(SSLHandshake.SERVER_HELLO.id,
647
SSLHandshake.SERVER_HELLO);
648
649
// The handshake message has been delivered.
650
return null;
651
default:
652
throw new UnsupportedOperationException(
653
"Not supported yet.");
654
}
655
}
656
}
657
658
/**
659
* The "ClientHello" handshake message consumer.
660
*/
661
private static final class ClientHelloConsumer implements SSLConsumer {
662
// Prevent instantiation of this class.
663
private ClientHelloConsumer() {
664
// blank
665
}
666
667
@Override
668
public void consume(ConnectionContext context,
669
ByteBuffer message) throws IOException {
670
// The consuming happens in server side only.
671
ServerHandshakeContext shc = (ServerHandshakeContext)context;
672
673
// clean up this consumer
674
shc.handshakeConsumers.remove(SSLHandshake.CLIENT_HELLO.id);
675
if (!shc.handshakeConsumers.isEmpty()) {
676
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
677
"No more handshake message allowed " +
678
"in a ClientHello flight");
679
}
680
681
// Get enabled extension types in ClientHello handshake message.
682
SSLExtension[] enabledExtensions =
683
shc.sslConfig.getEnabledExtensions(
684
SSLHandshake.CLIENT_HELLO);
685
686
ClientHelloMessage chm =
687
new ClientHelloMessage(shc, message, enabledExtensions);
688
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
689
SSLLogger.fine("Consuming ClientHello handshake message", chm);
690
}
691
692
shc.clientHelloVersion = chm.clientVersion;
693
onClientHello(shc, chm);
694
}
695
696
private void onClientHello(ServerHandshakeContext context,
697
ClientHelloMessage clientHello) throws IOException {
698
// Negotiate protocol version.
699
//
700
// Check and launch SupportedVersions.
701
SSLExtension[] extTypes = new SSLExtension[] {
702
SSLExtension.CH_SUPPORTED_VERSIONS
703
};
704
clientHello.extensions.consumeOnLoad(context, extTypes);
705
706
ProtocolVersion negotiatedProtocol;
707
CHSupportedVersionsSpec svs =
708
(CHSupportedVersionsSpec)context.handshakeExtensions.get(
709
SSLExtension.CH_SUPPORTED_VERSIONS);
710
if (svs != null) {
711
negotiatedProtocol =
712
negotiateProtocol(context, svs.requestedProtocols);
713
} else {
714
negotiatedProtocol =
715
negotiateProtocol(context, clientHello.clientVersion);
716
}
717
context.negotiatedProtocol = negotiatedProtocol;
718
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
719
SSLLogger.fine(
720
"Negotiated protocol version: " + negotiatedProtocol.name);
721
}
722
723
// Consume the handshake message for the specific protocol version.
724
if (negotiatedProtocol.useTLS13PlusSpec()) {
725
t13HandshakeConsumer.consume(context, clientHello);
726
} else {
727
t12HandshakeConsumer.consume(context, clientHello);
728
}
729
}
730
731
// Select a protocol version according to the
732
// ClientHello.client_version.
733
private ProtocolVersion negotiateProtocol(
734
ServerHandshakeContext context,
735
int clientHelloVersion) throws SSLException {
736
737
// Per TLS 1.3 specification, server MUST negotiate TLS 1.2 or prior
738
// even if ClientHello.client_version is 0x0304 or later.
739
int chv = clientHelloVersion;
740
if (chv > ProtocolVersion.TLS12.id) {
741
chv = ProtocolVersion.TLS12.id;
742
}
743
744
// Select a protocol version from the activated protocols.
745
ProtocolVersion pv = ProtocolVersion.selectedFrom(
746
context.activeProtocols, chv);
747
if (pv == null || pv == ProtocolVersion.NONE ||
748
pv == ProtocolVersion.SSL20Hello) {
749
throw context.conContext.fatal(Alert.PROTOCOL_VERSION,
750
"Client requested protocol " +
751
ProtocolVersion.nameOf(clientHelloVersion) +
752
" is not enabled or supported in server context");
753
}
754
755
return pv;
756
}
757
758
// Select a protocol version according to the
759
// supported_versions extension.
760
private ProtocolVersion negotiateProtocol(
761
ServerHandshakeContext context,
762
int[] clientSupportedVersions) throws SSLException {
763
764
// The client supported protocol versions are present in client
765
// preference order. This implementation chooses to use the server
766
// preference of protocol versions instead.
767
for (ProtocolVersion spv : context.activeProtocols) {
768
if (spv == ProtocolVersion.SSL20Hello) {
769
continue;
770
}
771
for (int cpv : clientSupportedVersions) {
772
if (cpv == ProtocolVersion.SSL20Hello.id) {
773
continue;
774
}
775
if (spv.id == cpv) {
776
return spv;
777
}
778
}
779
}
780
781
// No protocol version can be negotiated.
782
throw context.conContext.fatal(Alert.PROTOCOL_VERSION,
783
"The client supported protocol versions " + Arrays.toString(
784
ProtocolVersion.toStringArray(clientSupportedVersions)) +
785
" are not accepted by server preferences " +
786
context.activeProtocols);
787
}
788
}
789
790
/**
791
* The "ClientHello" handshake message consumer for TLS 1.2 and
792
* prior SSL/TLS protocol versions.
793
*/
794
private static final
795
class T12ClientHelloConsumer implements HandshakeConsumer {
796
// Prevent instantiation of this class.
797
private T12ClientHelloConsumer() {
798
// blank
799
}
800
801
@Override
802
public void consume(ConnectionContext context,
803
HandshakeMessage message) throws IOException {
804
// The consuming happens in server side only.
805
ServerHandshakeContext shc = (ServerHandshakeContext)context;
806
ClientHelloMessage clientHello = (ClientHelloMessage)message;
807
808
//
809
// validate
810
//
811
812
// Reject client initiated renegotiation?
813
//
814
// If server side should reject client-initiated renegotiation,
815
// send an Alert.HANDSHAKE_FAILURE fatal alert, not a
816
// no_renegotiation warning alert (no_renegotiation must be a
817
// warning: RFC 2246). no_renegotiation might seem more
818
// natural at first, but warnings are not appropriate because
819
// the sending party does not know how the receiving party
820
// will behave. This state must be treated as a fatal server
821
// condition.
822
//
823
// This will not have any impact on server initiated renegotiation.
824
if (shc.conContext.isNegotiated) {
825
if (!shc.conContext.secureRenegotiation &&
826
!HandshakeContext.allowUnsafeRenegotiation) {
827
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
828
"Unsafe renegotiation is not allowed");
829
}
830
831
if (ServerHandshakeContext.rejectClientInitiatedRenego &&
832
!shc.kickstartMessageDelivered) {
833
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
834
"Client initiated renegotiation is not allowed");
835
}
836
}
837
838
// Is it an abbreviated handshake?
839
if (clientHello.sessionId.length() != 0) {
840
SSLSessionImpl previous = ((SSLSessionContextImpl)shc.sslContext
841
.engineGetServerSessionContext())
842
.get(clientHello.sessionId.getId());
843
844
boolean resumingSession =
845
(previous != null) && previous.isRejoinable();
846
if (!resumingSession) {
847
if (SSLLogger.isOn &&
848
SSLLogger.isOn("ssl,handshake,verbose")) {
849
SSLLogger.finest(
850
"Can't resume, " +
851
"the existing session is not rejoinable");
852
}
853
}
854
// Validate the negotiated protocol version.
855
if (resumingSession) {
856
ProtocolVersion sessionProtocol =
857
previous.getProtocolVersion();
858
if (sessionProtocol != shc.negotiatedProtocol) {
859
resumingSession = false;
860
if (SSLLogger.isOn &&
861
SSLLogger.isOn("ssl,handshake,verbose")) {
862
SSLLogger.finest(
863
"Can't resume, not the same protocol version");
864
}
865
}
866
}
867
868
// Validate the required client authentication.
869
if (resumingSession &&
870
(shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED)) {
871
try {
872
previous.getPeerPrincipal();
873
} catch (SSLPeerUnverifiedException e) {
874
resumingSession = false;
875
if (SSLLogger.isOn &&
876
SSLLogger.isOn("ssl,handshake,verbose")) {
877
SSLLogger.finest(
878
"Can't resume, " +
879
"client authentication is required");
880
}
881
}
882
}
883
884
// Validate that the cached cipher suite.
885
if (resumingSession) {
886
CipherSuite suite = previous.getSuite();
887
if ((!shc.isNegotiable(suite)) ||
888
(!clientHello.cipherSuites.contains(suite))) {
889
resumingSession = false;
890
if (SSLLogger.isOn &&
891
SSLLogger.isOn("ssl,handshake,verbose")) {
892
SSLLogger.finest(
893
"Can't resume, " +
894
"the session cipher suite is absent");
895
}
896
}
897
}
898
899
// Validate KRB5 cipher suites
900
if (resumingSession) {
901
CipherSuite suite = previous.getSuite();
902
if (suite.keyExchange == K_KRB5 ||
903
suite.keyExchange == K_KRB5_EXPORT) {
904
Principal localPrincipal = previous.getLocalPrincipal();
905
906
Subject subject = null;
907
try {
908
subject = AccessController.doPrivileged(
909
new PrivilegedExceptionAction<Subject>() {
910
@Override
911
public Subject run() throws Exception {
912
return Krb5Helper.getServerSubject(
913
shc.conContext.acc);
914
}});
915
} catch (PrivilegedActionException e) {
916
subject = null;
917
if (SSLLogger.isOn &&
918
SSLLogger.isOn("ssl,handshake,verbose")) {
919
SSLLogger.finest("Attempt to obtain" +
920
" subject failed!");
921
}
922
}
923
924
if (subject != null) {
925
// Eliminate dependency on KerberosPrincipal
926
if (Krb5Helper.isRelated(subject, localPrincipal)) {
927
if (SSLLogger.isOn &&
928
SSLLogger.isOn("ssl,handshake,verbose"))
929
SSLLogger.finest("Subject can" +
930
" provide creds for princ");
931
} else {
932
resumingSession = false;
933
if (SSLLogger.isOn &&
934
SSLLogger.isOn("ssl,handshake,verbose"))
935
SSLLogger.finest("Subject cannot" +
936
" provide creds for princ");
937
}
938
} else {
939
resumingSession = false;
940
if (SSLLogger.isOn &&
941
SSLLogger.isOn("ssl,handshake,verbose"))
942
SSLLogger.finest("Kerberos credentials are" +
943
" not present in the current Subject;" +
944
" check if " +
945
" javax.security.auth.useSubjectCredsOnly" +
946
" system property has been set to false");
947
}
948
}
949
}
950
951
// ensure that the endpoint identification algorithm matches the
952
// one in the session
953
String identityAlg = shc.sslConfig.identificationProtocol;
954
if (resumingSession && identityAlg != null) {
955
String sessionIdentityAlg =
956
previous.getIdentificationProtocol();
957
if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) {
958
if (SSLLogger.isOn &&
959
SSLLogger.isOn("ssl,handshake,verbose")) {
960
SSLLogger.finest("Can't resume, endpoint id" +
961
" algorithm does not match, requested: " +
962
identityAlg + ", cached: " + sessionIdentityAlg);
963
}
964
resumingSession = false;
965
}
966
}
967
968
// So far so good. Note that the handshake extensions may reset
969
// the resuming options later.
970
shc.isResumption = resumingSession;
971
shc.resumingSession = resumingSession ? previous : null;
972
}
973
974
// cache the client random number for further using
975
shc.clientHelloRandom = clientHello.clientRandom;
976
977
// Check and launch ClientHello extensions.
978
SSLExtension[] extTypes = shc.sslConfig.getEnabledExtensions(
979
SSLHandshake.CLIENT_HELLO);
980
clientHello.extensions.consumeOnLoad(shc, extTypes);
981
982
//
983
// update
984
//
985
if (!shc.conContext.isNegotiated) {
986
shc.conContext.protocolVersion = shc.negotiatedProtocol;
987
shc.conContext.outputRecord.setVersion(shc.negotiatedProtocol);
988
}
989
990
// update the responders
991
//
992
// Only need to ServerHello, which may add more responders later.
993
// Note that ServerHello and HelloRetryRequest share the same
994
// handshake type/id. The ServerHello producer may be replaced
995
// by HelloRetryRequest producer if needed.
996
shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,
997
SSLHandshake.SERVER_HELLO);
998
999
//
1000
// produce
1001
//
1002
SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {
1003
SSLHandshake.SERVER_HELLO,
1004
1005
// full handshake messages
1006
SSLHandshake.CERTIFICATE,
1007
SSLHandshake.CERTIFICATE_STATUS,
1008
SSLHandshake.SERVER_KEY_EXCHANGE,
1009
SSLHandshake.CERTIFICATE_REQUEST,
1010
SSLHandshake.SERVER_HELLO_DONE,
1011
1012
// abbreviated handshake messages
1013
SSLHandshake.FINISHED
1014
};
1015
1016
for (SSLHandshake hs : probableHandshakeMessages) {
1017
HandshakeProducer handshakeProducer =
1018
shc.handshakeProducers.remove(hs.id);
1019
if (handshakeProducer != null) {
1020
handshakeProducer.produce(context, clientHello);
1021
}
1022
}
1023
}
1024
}
1025
1026
/**
1027
* The "ClientHello" handshake message consumer for TLS 1.3.
1028
*/
1029
private static final
1030
class T13ClientHelloConsumer implements HandshakeConsumer {
1031
// Prevent instantiation of this class.
1032
private T13ClientHelloConsumer() {
1033
// blank
1034
}
1035
1036
@Override
1037
public void consume(ConnectionContext context,
1038
HandshakeMessage message) throws IOException {
1039
// The consuming happens in server side only.
1040
ServerHandshakeContext shc = (ServerHandshakeContext)context;
1041
ClientHelloMessage clientHello = (ClientHelloMessage)message;
1042
1043
// [RFC 8446] TLS 1.3 forbids renegotiation. If a server has
1044
// negotiated TLS 1.3 and receives a ClientHello at any other
1045
// time, it MUST terminate the connection with an
1046
// "unexpected_message" alert.
1047
if (shc.conContext.isNegotiated) {
1048
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
1049
"Received unexpected renegotiation handshake message");
1050
}
1051
1052
// The client may send a dummy change_cipher_spec record
1053
// immediately after the first ClientHello.
1054
shc.conContext.consumers.putIfAbsent(
1055
ContentType.CHANGE_CIPHER_SPEC.id,
1056
ChangeCipherSpec.t13Consumer);
1057
1058
// Is it a resumption?
1059
//
1060
// Check and launch the "psk_key_exchange_modes" and
1061
// "pre_shared_key" extensions first, which will reset the
1062
// resuming session, no matter the extensions present or not.
1063
shc.isResumption = true;
1064
SSLExtension[] extTypes = new SSLExtension[] {
1065
SSLExtension.PSK_KEY_EXCHANGE_MODES,
1066
SSLExtension.CH_PRE_SHARED_KEY
1067
};
1068
clientHello.extensions.consumeOnLoad(shc, extTypes);
1069
1070
// Check and launch ClientHello extensions other than
1071
// "psk_key_exchange_modes", "pre_shared_key", "protocol_version"
1072
// and "key_share" extensions.
1073
//
1074
// These extensions may discard session resumption, or ask for
1075
// hello retry.
1076
extTypes = shc.sslConfig.getExclusiveExtensions(
1077
SSLHandshake.CLIENT_HELLO,
1078
Arrays.asList(
1079
SSLExtension.PSK_KEY_EXCHANGE_MODES,
1080
SSLExtension.CH_PRE_SHARED_KEY,
1081
SSLExtension.CH_SUPPORTED_VERSIONS));
1082
clientHello.extensions.consumeOnLoad(shc, extTypes);
1083
1084
if (!shc.handshakeProducers.isEmpty()) {
1085
// Should be HelloRetryRequest producer.
1086
goHelloRetryRequest(shc, clientHello);
1087
} else {
1088
goServerHello(shc, clientHello);
1089
}
1090
}
1091
1092
private void goHelloRetryRequest(ServerHandshakeContext shc,
1093
ClientHelloMessage clientHello) throws IOException {
1094
HandshakeProducer handshakeProducer =
1095
shc.handshakeProducers.remove(
1096
SSLHandshake.HELLO_RETRY_REQUEST.id);
1097
if (handshakeProducer != null) {
1098
handshakeProducer.produce(shc, clientHello);
1099
} else {
1100
// unlikely
1101
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
1102
"No HelloRetryRequest producer: " + shc.handshakeProducers);
1103
}
1104
1105
if (!shc.handshakeProducers.isEmpty()) {
1106
// unlikely, but please double check.
1107
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
1108
"unknown handshake producers: " + shc.handshakeProducers);
1109
}
1110
}
1111
1112
private void goServerHello(ServerHandshakeContext shc,
1113
ClientHelloMessage clientHello) throws IOException {
1114
//
1115
// validate
1116
//
1117
shc.clientHelloRandom = clientHello.clientRandom;
1118
1119
//
1120
// update
1121
//
1122
if (!shc.conContext.isNegotiated) {
1123
shc.conContext.protocolVersion = shc.negotiatedProtocol;
1124
shc.conContext.outputRecord.setVersion(shc.negotiatedProtocol);
1125
}
1126
1127
// update the responders
1128
//
1129
// Only ServerHello/HelloRetryRequest producer, which adds
1130
// more responders later.
1131
shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,
1132
SSLHandshake.SERVER_HELLO);
1133
1134
SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {
1135
SSLHandshake.SERVER_HELLO,
1136
1137
// full handshake messages
1138
SSLHandshake.ENCRYPTED_EXTENSIONS,
1139
SSLHandshake.CERTIFICATE_REQUEST,
1140
SSLHandshake.CERTIFICATE,
1141
SSLHandshake.CERTIFICATE_VERIFY,
1142
SSLHandshake.FINISHED
1143
};
1144
1145
//
1146
// produce
1147
//
1148
for (SSLHandshake hs : probableHandshakeMessages) {
1149
HandshakeProducer handshakeProducer =
1150
shc.handshakeProducers.remove(hs.id);
1151
if (handshakeProducer != null) {
1152
handshakeProducer.produce(shc, clientHello);
1153
}
1154
}
1155
}
1156
}
1157
}
1158
1159