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/HandshakeContext.java
38830 views
1
/*
2
* Copyright (c) 2018, 2019, 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.BufferOverflowException;
30
import java.nio.BufferUnderflowException;
31
import java.nio.ByteBuffer;
32
import java.security.AlgorithmConstraints;
33
import java.security.CryptoPrimitive;
34
import java.util.AbstractMap.SimpleImmutableEntry;
35
import java.util.ArrayList;
36
import java.util.Collections;
37
import java.util.EnumMap;
38
import java.util.EnumSet;
39
import java.util.HashMap;
40
import java.util.LinkedHashMap;
41
import java.util.LinkedList;
42
import java.util.List;
43
import java.util.Map;
44
import java.util.Queue;
45
import javax.crypto.SecretKey;
46
import javax.net.ssl.SNIServerName;
47
import javax.net.ssl.SSLHandshakeException;
48
import javax.security.auth.x500.X500Principal;
49
import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
50
import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
51
import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*;
52
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
53
54
abstract class HandshakeContext implements ConnectionContext {
55
// System properties
56
57
// By default, disable the unsafe legacy session renegotiation.
58
static final boolean allowUnsafeRenegotiation =
59
Utilities.getBooleanProperty(
60
"sun.security.ssl.allowUnsafeRenegotiation", false);
61
62
// For maximum interoperability and backward compatibility, RFC 5746
63
// allows server (or client) to accept ClientHello (or ServerHello)
64
// message without the secure renegotiation_info extension or SCSV.
65
//
66
// For maximum security, RFC 5746 also allows server (or client) to
67
// reject such message with a fatal "handshake_failure" alert.
68
//
69
// By default, allow such legacy hello messages.
70
static final boolean allowLegacyHelloMessages =
71
Utilities.getBooleanProperty(
72
"sun.security.ssl.allowLegacyHelloMessages", true);
73
74
// registered handshake message actors
75
LinkedHashMap<Byte, SSLConsumer> handshakeConsumers;
76
final HashMap<Byte, HandshakeProducer> handshakeProducers;
77
78
// context
79
final SSLContextImpl sslContext;
80
final TransportContext conContext;
81
final SSLConfiguration sslConfig;
82
83
// consolidated parameters
84
final List<ProtocolVersion> activeProtocols;
85
final List<CipherSuite> activeCipherSuites;
86
final AlgorithmConstraints algorithmConstraints;
87
final ProtocolVersion maximumActiveProtocol;
88
89
// output stream
90
final HandshakeOutStream handshakeOutput;
91
92
// handshake transcript hash
93
final HandshakeHash handshakeHash;
94
95
// negotiated security parameters
96
SSLSessionImpl handshakeSession;
97
boolean handshakeFinished;
98
// boolean isInvalidated;
99
100
boolean kickstartMessageDelivered;
101
102
// Resumption
103
boolean isResumption;
104
SSLSessionImpl resumingSession;
105
106
final Queue<Map.Entry<Byte, ByteBuffer>> delegatedActions;
107
volatile boolean taskDelegated = false;
108
volatile Exception delegatedThrown = null;
109
110
ProtocolVersion negotiatedProtocol;
111
CipherSuite negotiatedCipherSuite;
112
final List<SSLPossession> handshakePossessions;
113
final List<SSLCredentials> handshakeCredentials;
114
SSLKeyDerivation handshakeKeyDerivation;
115
SSLKeyExchange handshakeKeyExchange;
116
SecretKey baseReadSecret;
117
SecretKey baseWriteSecret;
118
119
// protocol version being established
120
int clientHelloVersion;
121
String applicationProtocol;
122
123
RandomCookie clientHelloRandom;
124
RandomCookie serverHelloRandom;
125
byte[] certRequestContext;
126
127
////////////////////
128
// Extensions
129
130
// the extensions used in the handshake
131
final Map<SSLExtension, SSLExtension.SSLExtensionSpec>
132
handshakeExtensions;
133
134
// MaxFragmentLength
135
int maxFragmentLength;
136
137
// SignatureScheme
138
List<SignatureScheme> localSupportedSignAlgs;
139
List<SignatureScheme> peerRequestedSignatureSchemes;
140
List<SignatureScheme> peerRequestedCertSignSchemes;
141
142
// Known authorities
143
X500Principal[] peerSupportedAuthorities = null;
144
145
// SupportedGroups
146
List<NamedGroup> clientRequestedNamedGroups;
147
148
// HelloRetryRequest
149
NamedGroup serverSelectedNamedGroup;
150
151
// if server name indicator is negotiated
152
//
153
// May need a public API for the indication in the future.
154
List<SNIServerName> requestedServerNames;
155
SNIServerName negotiatedServerName;
156
157
// OCSP Stapling info
158
boolean staplingActive = false;
159
160
protected HandshakeContext(SSLContextImpl sslContext,
161
TransportContext conContext) throws IOException {
162
this.sslContext = sslContext;
163
this.conContext = conContext;
164
this.sslConfig = (SSLConfiguration)conContext.sslConfig.clone();
165
166
this.algorithmConstraints = new SSLAlgorithmConstraints(
167
sslConfig.userSpecifiedAlgorithmConstraints);
168
this.activeProtocols = getActiveProtocols(sslConfig.enabledProtocols,
169
sslConfig.enabledCipherSuites, algorithmConstraints);
170
if (activeProtocols.isEmpty()) {
171
throw new SSLHandshakeException(
172
"No appropriate protocol (protocol is disabled or " +
173
"cipher suites are inappropriate)");
174
}
175
176
ProtocolVersion maximumVersion = ProtocolVersion.NONE;
177
for (ProtocolVersion pv : this.activeProtocols) {
178
if (maximumVersion == ProtocolVersion.NONE ||
179
pv.compare(maximumVersion) > 0) {
180
maximumVersion = pv;
181
}
182
}
183
this.maximumActiveProtocol = maximumVersion;
184
this.activeCipherSuites = getActiveCipherSuites(this.activeProtocols,
185
sslConfig.enabledCipherSuites, algorithmConstraints);
186
if (activeCipherSuites.isEmpty()) {
187
throw new SSLHandshakeException("No appropriate cipher suite");
188
}
189
190
this.handshakeConsumers = new LinkedHashMap<>();
191
this.handshakeProducers = new HashMap<>();
192
this.handshakeHash = conContext.inputRecord.handshakeHash;
193
this.handshakeOutput = new HandshakeOutStream(conContext.outputRecord);
194
195
this.handshakeFinished = false;
196
this.kickstartMessageDelivered = false;
197
198
this.delegatedActions = new LinkedList<>();
199
this.handshakeExtensions = new HashMap<>();
200
this.handshakePossessions = new LinkedList<>();
201
this.handshakeCredentials = new LinkedList<>();
202
this.requestedServerNames = null;
203
this.negotiatedServerName = null;
204
this.negotiatedCipherSuite = conContext.cipherSuite;
205
initialize();
206
}
207
208
/**
209
* Constructor for PostHandshakeContext
210
*/
211
protected HandshakeContext(TransportContext conContext) {
212
this.sslContext = conContext.sslContext;
213
this.conContext = conContext;
214
this.sslConfig = conContext.sslConfig;
215
216
this.negotiatedProtocol = conContext.protocolVersion;
217
this.negotiatedCipherSuite = conContext.cipherSuite;
218
this.handshakeOutput = new HandshakeOutStream(conContext.outputRecord);
219
this.delegatedActions = new LinkedList<>();
220
221
this.handshakeConsumers = new LinkedHashMap<>();
222
this.handshakeProducers = null;
223
this.handshakeHash = null;
224
this.activeProtocols = null;
225
this.activeCipherSuites = null;
226
this.algorithmConstraints = null;
227
this.maximumActiveProtocol = null;
228
this.handshakeExtensions = Collections.emptyMap(); // Not in TLS13
229
this.handshakePossessions = null;
230
this.handshakeCredentials = null;
231
}
232
233
// Initialize the non-final class variables.
234
private void initialize() {
235
ProtocolVersion inputHelloVersion;
236
ProtocolVersion outputHelloVersion;
237
if (conContext.isNegotiated) {
238
inputHelloVersion = conContext.protocolVersion;
239
outputHelloVersion = conContext.protocolVersion;
240
} else {
241
if (activeProtocols.contains(ProtocolVersion.SSL20Hello)) {
242
inputHelloVersion = ProtocolVersion.SSL20Hello;
243
244
// Per TLS 1.3 protocol, implementation MUST NOT send an SSL
245
// version 2.0 compatible CLIENT-HELLO.
246
if (maximumActiveProtocol.useTLS13PlusSpec()) {
247
outputHelloVersion = maximumActiveProtocol;
248
} else {
249
outputHelloVersion = ProtocolVersion.SSL20Hello;
250
}
251
} else {
252
inputHelloVersion = maximumActiveProtocol;
253
outputHelloVersion = maximumActiveProtocol;
254
}
255
}
256
257
conContext.inputRecord.setHelloVersion(inputHelloVersion);
258
conContext.outputRecord.setHelloVersion(outputHelloVersion);
259
260
if (!conContext.isNegotiated) {
261
conContext.protocolVersion = maximumActiveProtocol;
262
}
263
conContext.outputRecord.setVersion(conContext.protocolVersion);
264
}
265
266
private static List<ProtocolVersion> getActiveProtocols(
267
List<ProtocolVersion> enabledProtocols,
268
List<CipherSuite> enabledCipherSuites,
269
AlgorithmConstraints algorithmConstraints) {
270
boolean enabledSSL20Hello = false;
271
ArrayList<ProtocolVersion> protocols = new ArrayList<>(4);
272
for (ProtocolVersion protocol : enabledProtocols) {
273
if (!enabledSSL20Hello && protocol == ProtocolVersion.SSL20Hello) {
274
enabledSSL20Hello = true;
275
continue;
276
}
277
278
if (!algorithmConstraints.permits(
279
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
280
protocol.name, null)) {
281
// Ignore disabled protocol.
282
continue;
283
}
284
285
boolean found = false;
286
Map<NamedGroupType, Boolean> cachedStatus =
287
new EnumMap<>(NamedGroupType.class);
288
for (CipherSuite suite : enabledCipherSuites) {
289
if (suite.isAvailable() && suite.supports(protocol)) {
290
if (isActivatable(suite,
291
algorithmConstraints, cachedStatus)) {
292
protocols.add(protocol);
293
found = true;
294
break;
295
}
296
} else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
297
SSLLogger.fine(
298
"Ignore unsupported cipher suite: " + suite +
299
" for " + protocol);
300
}
301
}
302
303
if (!found && (SSLLogger.isOn) && SSLLogger.isOn("handshake")) {
304
SSLLogger.fine(
305
"No available cipher suite for " + protocol);
306
}
307
}
308
309
if (!protocols.isEmpty()) {
310
if (enabledSSL20Hello) {
311
protocols.add(ProtocolVersion.SSL20Hello);
312
}
313
Collections.sort(protocols);
314
}
315
316
return Collections.unmodifiableList(protocols);
317
}
318
319
private static List<CipherSuite> getActiveCipherSuites(
320
List<ProtocolVersion> enabledProtocols,
321
List<CipherSuite> enabledCipherSuites,
322
AlgorithmConstraints algorithmConstraints) {
323
324
List<CipherSuite> suites = new LinkedList<>();
325
if (enabledProtocols != null && !enabledProtocols.isEmpty()) {
326
Map<NamedGroupType, Boolean> cachedStatus =
327
new EnumMap<>(NamedGroupType.class);
328
for (CipherSuite suite : enabledCipherSuites) {
329
if (!suite.isAvailable()) {
330
continue;
331
}
332
333
boolean isSupported = false;
334
for (ProtocolVersion protocol : enabledProtocols) {
335
if (!suite.supports(protocol)) {
336
continue;
337
}
338
if (isActivatable(suite,
339
algorithmConstraints, cachedStatus)) {
340
suites.add(suite);
341
isSupported = true;
342
break;
343
}
344
}
345
346
if (!isSupported &&
347
SSLLogger.isOn && SSLLogger.isOn("verbose")) {
348
SSLLogger.finest(
349
"Ignore unsupported cipher suite: " + suite);
350
}
351
}
352
}
353
354
return Collections.unmodifiableList(suites);
355
}
356
357
/**
358
* Parse the handshake record and return the contentType
359
*/
360
static byte getHandshakeType(TransportContext conContext,
361
Plaintext plaintext) throws IOException {
362
// struct {
363
// HandshakeType msg_type; /* handshake type */
364
// uint24 length; /* bytes in message */
365
// select (HandshakeType) {
366
// ...
367
// } body;
368
// } Handshake;
369
370
if (plaintext.contentType != ContentType.HANDSHAKE.id) {
371
throw conContext.fatal(Alert.INTERNAL_ERROR,
372
"Unexpected operation for record: " + plaintext.contentType);
373
}
374
375
if (plaintext.fragment == null || plaintext.fragment.remaining() < 4) {
376
throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
377
"Invalid handshake message: insufficient data");
378
}
379
380
byte handshakeType = (byte)Record.getInt8(plaintext.fragment);
381
int handshakeLen = Record.getInt24(plaintext.fragment);
382
if (handshakeLen != plaintext.fragment.remaining()) {
383
throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
384
"Invalid handshake message: insufficient handshake body");
385
}
386
387
return handshakeType;
388
}
389
390
void dispatch(byte handshakeType, Plaintext plaintext) throws IOException {
391
if (conContext.transport.useDelegatedTask()) {
392
boolean hasDelegated = !delegatedActions.isEmpty();
393
if (hasDelegated ||
394
(handshakeType != SSLHandshake.FINISHED.id &&
395
handshakeType != SSLHandshake.KEY_UPDATE.id &&
396
handshakeType != SSLHandshake.NEW_SESSION_TICKET.id)) {
397
if (!hasDelegated) {
398
taskDelegated = false;
399
delegatedThrown = null;
400
}
401
402
// Clone the fragment for delegated actions.
403
//
404
// The plaintext may share the application buffers. It is
405
// fine to use shared buffers if no delegated actions.
406
// However, for delegated actions, the shared buffers may be
407
// polluted in application layer before the delegated actions
408
// executed.
409
ByteBuffer fragment = ByteBuffer.wrap(
410
new byte[plaintext.fragment.remaining()]);
411
fragment.put(plaintext.fragment);
412
fragment = (ByteBuffer)fragment.rewind();
413
414
delegatedActions.add(new SimpleImmutableEntry<>(
415
handshakeType,
416
fragment
417
));
418
} else {
419
dispatch(handshakeType, plaintext.fragment);
420
}
421
} else {
422
dispatch(handshakeType, plaintext.fragment);
423
}
424
}
425
426
void dispatch(byte handshakeType,
427
ByteBuffer fragment) throws IOException {
428
SSLConsumer consumer;
429
if (handshakeType == SSLHandshake.HELLO_REQUEST.id) {
430
// For TLS 1.2 and prior versions, the HelloRequest message MAY
431
// be sent by the server at any time.
432
consumer = SSLHandshake.HELLO_REQUEST;
433
} else {
434
consumer = handshakeConsumers.get(handshakeType);
435
}
436
437
if (consumer == null) {
438
throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
439
"Unexpected handshake message: " +
440
SSLHandshake.nameOf(handshakeType));
441
}
442
443
try {
444
consumer.consume(this, fragment);
445
} catch (UnsupportedOperationException unsoe) {
446
throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
447
"Unsupported handshake message: " +
448
SSLHandshake.nameOf(handshakeType), unsoe);
449
} catch (BufferUnderflowException | BufferOverflowException be) {
450
throw conContext.fatal(Alert.DECODE_ERROR,
451
"Illegal handshake message: " +
452
SSLHandshake.nameOf(handshakeType), be);
453
}
454
455
// update handshake hash after handshake message consumption.
456
handshakeHash.consume();
457
}
458
459
abstract void kickstart() throws IOException;
460
461
/**
462
* Check if the given cipher suite is enabled and available within
463
* the current active cipher suites.
464
*
465
* Does not check if the required server certificates are available.
466
*/
467
boolean isNegotiable(CipherSuite cs) {
468
return isNegotiable(activeCipherSuites, cs);
469
}
470
471
/**
472
* Check if the given cipher suite is enabled and available within
473
* the proposed cipher suite list.
474
*
475
* Does not check if the required server certificates are available.
476
*/
477
static final boolean isNegotiable(
478
List<CipherSuite> proposed, CipherSuite cs) {
479
return proposed.contains(cs) && cs.isNegotiable();
480
}
481
482
/**
483
* Check if the given cipher suite is enabled and available within
484
* the proposed cipher suite list and specific protocol version.
485
*
486
* Does not check if the required server certificates are available.
487
*/
488
static final boolean isNegotiable(List<CipherSuite> proposed,
489
ProtocolVersion protocolVersion, CipherSuite cs) {
490
return proposed.contains(cs) &&
491
cs.isNegotiable() && cs.supports(protocolVersion);
492
}
493
494
/**
495
* Check if the given protocol version is enabled and available.
496
*/
497
boolean isNegotiable(ProtocolVersion protocolVersion) {
498
return activeProtocols.contains(protocolVersion);
499
}
500
501
/**
502
* Set the active protocol version and propagate it to the SSLSocket
503
* and our handshake streams. Called from ClientHandshaker
504
* and ServerHandshaker with the negotiated protocol version.
505
*/
506
void setVersion(ProtocolVersion protocolVersion) {
507
this.conContext.protocolVersion = protocolVersion;
508
}
509
510
private static boolean isActivatable(CipherSuite suite,
511
AlgorithmConstraints algorithmConstraints,
512
Map<NamedGroupType, Boolean> cachedStatus) {
513
514
if (algorithmConstraints.permits(
515
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), suite.name, null)) {
516
if (suite.keyExchange == null) {
517
// TLS 1.3, no definition of key exchange in cipher suite.
518
return true;
519
}
520
521
boolean available;
522
NamedGroupType groupType = suite.keyExchange.groupType;
523
if (groupType != NAMED_GROUP_NONE) {
524
Boolean checkedStatus = cachedStatus.get(groupType);
525
if (checkedStatus == null) {
526
available = SupportedGroups.isActivatable(
527
algorithmConstraints, groupType);
528
cachedStatus.put(groupType, available);
529
530
if (!available &&
531
SSLLogger.isOn && SSLLogger.isOn("verbose")) {
532
SSLLogger.fine("No activated named group");
533
}
534
} else {
535
available = checkedStatus;
536
}
537
538
if (!available && SSLLogger.isOn && SSLLogger.isOn("verbose")) {
539
SSLLogger.fine(
540
"No active named group, ignore " + suite);
541
}
542
return available;
543
} else {
544
return true;
545
}
546
} else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
547
SSLLogger.fine("Ignore disabled cipher suite: " + suite);
548
}
549
550
return false;
551
}
552
553
List<SNIServerName> getRequestedServerNames() {
554
if (requestedServerNames == null) {
555
return Collections.<SNIServerName>emptyList();
556
}
557
return requestedServerNames;
558
}
559
}
560
561
562