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