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/AlpnExtension.java
38830 views
1
/*
2
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.ssl;
27
28
import java.io.IOException;
29
import java.nio.ByteBuffer;
30
import java.nio.charset.StandardCharsets;
31
import java.util.Arrays;
32
import java.util.Collections;
33
import java.util.LinkedList;
34
import java.util.List;
35
import javax.net.ssl.SSLEngine;
36
import javax.net.ssl.SSLProtocolException;
37
import javax.net.ssl.SSLSocket;
38
import sun.security.ssl.SSLExtension.ExtensionConsumer;
39
import sun.security.ssl.SSLExtension.SSLExtensionSpec;
40
import sun.security.ssl.SSLHandshake.HandshakeMessage;
41
42
/**
43
* Pack of the "application_layer_protocol_negotiation" extensions [RFC 7301].
44
*/
45
final class AlpnExtension {
46
static final HandshakeProducer chNetworkProducer = new CHAlpnProducer();
47
static final ExtensionConsumer chOnLoadConsumer = new CHAlpnConsumer();
48
static final HandshakeAbsence chOnLoadAbsence = new CHAlpnAbsence();
49
50
static final HandshakeProducer shNetworkProducer = new SHAlpnProducer();
51
static final ExtensionConsumer shOnLoadConsumer = new SHAlpnConsumer();
52
static final HandshakeAbsence shOnLoadAbsence = new SHAlpnAbsence();
53
54
// Note: we reuse ServerHello operations for EncryptedExtensions for now.
55
// Please be careful about any code or specification changes in the future.
56
static final HandshakeProducer eeNetworkProducer = new SHAlpnProducer();
57
static final ExtensionConsumer eeOnLoadConsumer = new SHAlpnConsumer();
58
static final HandshakeAbsence eeOnLoadAbsence = new SHAlpnAbsence();
59
60
static final SSLStringizer alpnStringizer = new AlpnStringizer();
61
62
/**
63
* The "application_layer_protocol_negotiation" extension.
64
*
65
* See RFC 7301 for the specification of this extension.
66
*/
67
static final class AlpnSpec implements SSLExtensionSpec {
68
final List<String> applicationProtocols;
69
70
private AlpnSpec(String[] applicationProtocols) {
71
this.applicationProtocols = Collections.unmodifiableList(
72
Arrays.asList(applicationProtocols));
73
}
74
75
private AlpnSpec(ByteBuffer buffer) throws IOException {
76
// ProtocolName protocol_name_list<2..2^16-1>, RFC 7301.
77
if (buffer.remaining() < 2) {
78
throw new SSLProtocolException(
79
"Invalid application_layer_protocol_negotiation: " +
80
"insufficient data (length=" + buffer.remaining() + ")");
81
}
82
83
int listLen = Record.getInt16(buffer);
84
if (listLen < 2 || listLen != buffer.remaining()) {
85
throw new SSLProtocolException(
86
"Invalid application_layer_protocol_negotiation: " +
87
"incorrect list length (length=" + listLen + ")");
88
}
89
90
List<String> protocolNames = new LinkedList<>();
91
while (buffer.hasRemaining()) {
92
// opaque ProtocolName<1..2^8-1>, RFC 7301.
93
byte[] bytes = Record.getBytes8(buffer);
94
if (bytes.length == 0) {
95
throw new SSLProtocolException(
96
"Invalid application_layer_protocol_negotiation " +
97
"extension: empty application protocol name");
98
}
99
100
String appProtocol = new String(bytes, StandardCharsets.UTF_8);
101
protocolNames.add(appProtocol);
102
}
103
104
this.applicationProtocols =
105
Collections.unmodifiableList(protocolNames);
106
}
107
108
@Override
109
public String toString() {
110
return applicationProtocols.toString();
111
}
112
}
113
114
private static final class AlpnStringizer implements SSLStringizer {
115
@Override
116
public String toString(ByteBuffer buffer) {
117
try {
118
return (new AlpnSpec(buffer)).toString();
119
} catch (IOException ioe) {
120
// For debug logging only, so please swallow exceptions.
121
return ioe.getMessage();
122
}
123
}
124
}
125
126
/**
127
* Network data producer of the extension in a ClientHello
128
* handshake message.
129
*/
130
private static final class CHAlpnProducer implements HandshakeProducer {
131
static final int MAX_AP_LENGTH = 255;
132
static final int MAX_AP_LIST_LENGTH = 65535;
133
134
// Prevent instantiation of this class.
135
private CHAlpnProducer() {
136
// blank
137
}
138
139
@Override
140
public byte[] produce(ConnectionContext context,
141
HandshakeMessage message) throws IOException {
142
// The producing happens in client side only.
143
ClientHandshakeContext chc = (ClientHandshakeContext)context;
144
145
// Is it a supported and enabled extension?
146
if (!chc.sslConfig.isAvailable(SSLExtension.CH_ALPN)) {
147
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
148
SSLLogger.info(
149
"Ignore client unavailable extension: " +
150
SSLExtension.CH_ALPN.name);
151
}
152
153
chc.applicationProtocol = "";
154
chc.conContext.applicationProtocol = "";
155
return null;
156
}
157
158
String[] laps = chc.sslConfig.applicationProtocols;
159
if ((laps == null) || (laps.length == 0)) {
160
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
161
SSLLogger.info(
162
"No available application protocols");
163
}
164
return null;
165
}
166
167
// Produce the extension.
168
int listLength = 0; // ProtocolNameList length
169
for (String ap : laps) {
170
int length = ap.getBytes(StandardCharsets.UTF_8).length;
171
if (length == 0) {
172
// log the configuration problem
173
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
174
SSLLogger.severe(
175
"Application protocol name cannot be empty");
176
}
177
178
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
179
"Application protocol name cannot be empty");
180
}
181
182
if (length <= MAX_AP_LENGTH) {
183
// opaque ProtocolName<1..2^8-1>, RFC 7301.
184
listLength += (length + 1);
185
} else {
186
// log the configuration problem
187
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
188
SSLLogger.severe(
189
"Application protocol name (" + ap +
190
") exceeds the size limit (" +
191
MAX_AP_LENGTH + " bytes)");
192
}
193
194
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
195
"Application protocol name (" + ap +
196
") exceeds the size limit (" +
197
MAX_AP_LENGTH + " bytes)");
198
}
199
200
if (listLength > MAX_AP_LIST_LENGTH) {
201
// log the configuration problem
202
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
203
SSLLogger.severe(
204
"The configured application protocols (" +
205
Arrays.toString(laps) +
206
") exceed the size limit (" +
207
MAX_AP_LIST_LENGTH + " bytes)");
208
}
209
210
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
211
"The configured application protocols (" +
212
Arrays.toString(laps) +
213
") exceed the size limit (" +
214
MAX_AP_LIST_LENGTH + " bytes)");
215
}
216
}
217
218
// ProtocolName protocol_name_list<2..2^16-1>, RFC 7301.
219
byte[] extData = new byte[listLength + 2];
220
ByteBuffer m = ByteBuffer.wrap(extData);
221
Record.putInt16(m, listLength);
222
for (String ap : laps) {
223
Record.putBytes8(m, ap.getBytes(StandardCharsets.UTF_8));
224
}
225
226
// Update the context.
227
chc.handshakeExtensions.put(SSLExtension.CH_ALPN,
228
new AlpnSpec(chc.sslConfig.applicationProtocols));
229
230
return extData;
231
}
232
}
233
234
/**
235
* Network data consumer of the extension in a ClientHello
236
* handshake message.
237
*/
238
private static final class CHAlpnConsumer implements ExtensionConsumer {
239
// Prevent instantiation of this class.
240
private CHAlpnConsumer() {
241
// blank
242
}
243
244
@Override
245
public void consume(ConnectionContext context,
246
HandshakeMessage message, ByteBuffer buffer) throws IOException {
247
// The consuming happens in server side only.
248
ServerHandshakeContext shc = (ServerHandshakeContext)context;
249
250
// Is it a supported and enabled extension?
251
if (!shc.sslConfig.isAvailable(SSLExtension.CH_ALPN)) {
252
shc.applicationProtocol = "";
253
shc.conContext.applicationProtocol = "";
254
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
255
SSLLogger.info(
256
"Ignore server unavailable extension: " +
257
SSLExtension.CH_ALPN.name);
258
}
259
return; // ignore the extension
260
}
261
262
// Is the extension enabled?
263
boolean noAPSelector;
264
if (shc.conContext.transport instanceof SSLEngine) {
265
noAPSelector = (shc.sslConfig.engineAPSelector == null);
266
} else {
267
noAPSelector = (shc.sslConfig.socketAPSelector == null);
268
}
269
270
boolean noAlpnProtocols =
271
shc.sslConfig.applicationProtocols == null ||
272
shc.sslConfig.applicationProtocols.length == 0;
273
if (noAPSelector && noAlpnProtocols) {
274
shc.applicationProtocol = "";
275
shc.conContext.applicationProtocol = "";
276
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
277
SSLLogger.fine(
278
"Ignore server unenabled extension: " +
279
SSLExtension.CH_ALPN.name);
280
}
281
return; // ignore the extension
282
}
283
284
// Parse the extension.
285
AlpnSpec spec;
286
try {
287
spec = new AlpnSpec(buffer);
288
} catch (IOException ioe) {
289
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
290
}
291
292
// Update the context.
293
if (noAPSelector) { // noAlpnProtocols is false
294
List<String> protocolNames = spec.applicationProtocols;
295
boolean matched = false;
296
// Use server application protocol preference order.
297
for (String ap : shc.sslConfig.applicationProtocols) {
298
if (protocolNames.contains(ap)) {
299
shc.applicationProtocol = ap;
300
shc.conContext.applicationProtocol = ap;
301
matched = true;
302
break;
303
}
304
}
305
306
if (!matched) {
307
throw shc.conContext.fatal(Alert.NO_APPLICATION_PROTOCOL,
308
"No matching application layer protocol values");
309
}
310
} // Otherwise, applicationProtocol will be set by the
311
// application selector callback later.
312
313
shc.handshakeExtensions.put(SSLExtension.CH_ALPN, spec);
314
315
// No impact on session resumption.
316
//
317
// [RFC 7301] Unlike many other TLS extensions, this extension
318
// does not establish properties of the session, only of the
319
// connection. When session resumption or session tickets are
320
// used, the previous contents of this extension are irrelevant,
321
// and only the values in the new handshake messages are
322
// considered.
323
}
324
}
325
326
/**
327
* The absence processing if the extension is not present in
328
* a ClientHello handshake message.
329
*/
330
private static final class CHAlpnAbsence implements HandshakeAbsence {
331
@Override
332
public void absent(ConnectionContext context,
333
HandshakeMessage message) throws IOException {
334
// The producing happens in server side only.
335
ServerHandshakeContext shc = (ServerHandshakeContext)context;
336
337
// Please don't use the previous negotiated application protocol.
338
shc.applicationProtocol = "";
339
shc.conContext.applicationProtocol = "";
340
}
341
}
342
343
/**
344
* Network data producer of the extension in the ServerHello
345
* handshake message.
346
*/
347
private static final class SHAlpnProducer implements HandshakeProducer {
348
// Prevent instantiation of this class.
349
private SHAlpnProducer() {
350
// blank
351
}
352
353
@Override
354
public byte[] produce(ConnectionContext context,
355
HandshakeMessage message) throws IOException {
356
// The producing happens in client side only.
357
ServerHandshakeContext shc = (ServerHandshakeContext)context;
358
359
// In response to ALPN request only
360
AlpnSpec requestedAlps =
361
(AlpnSpec)shc.handshakeExtensions.get(SSLExtension.CH_ALPN);
362
if (requestedAlps == null) {
363
// Ignore, this extension was not requested and accepted.
364
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
365
SSLLogger.fine(
366
"Ignore unavailable extension: " +
367
SSLExtension.SH_ALPN.name);
368
}
369
370
shc.applicationProtocol = "";
371
shc.conContext.applicationProtocol = "";
372
return null;
373
}
374
375
List<String> alps = requestedAlps.applicationProtocols;
376
if (shc.conContext.transport instanceof SSLEngine) {
377
if (shc.sslConfig.engineAPSelector != null) {
378
SSLEngine engine = (SSLEngine)shc.conContext.transport;
379
shc.applicationProtocol =
380
shc.sslConfig.engineAPSelector.apply(engine, alps);
381
if ((shc.applicationProtocol == null) ||
382
(!shc.applicationProtocol.isEmpty() &&
383
!alps.contains(shc.applicationProtocol))) {
384
throw shc.conContext.fatal(
385
Alert.NO_APPLICATION_PROTOCOL,
386
"No matching application layer protocol values");
387
}
388
}
389
} else {
390
if (shc.sslConfig.socketAPSelector != null) {
391
SSLSocket socket = (SSLSocket)shc.conContext.transport;
392
shc.applicationProtocol =
393
shc.sslConfig.socketAPSelector.apply(socket, alps);
394
if ((shc.applicationProtocol == null) ||
395
(!shc.applicationProtocol.isEmpty() &&
396
!alps.contains(shc.applicationProtocol))) {
397
throw shc.conContext.fatal(
398
Alert.NO_APPLICATION_PROTOCOL,
399
"No matching application layer protocol values");
400
}
401
}
402
}
403
404
if ((shc.applicationProtocol == null) ||
405
(shc.applicationProtocol.isEmpty())) {
406
// Ignore, no negotiated application layer protocol.
407
shc.applicationProtocol = "";
408
shc.conContext.applicationProtocol = "";
409
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
410
SSLLogger.warning(
411
"Ignore, no negotiated application layer protocol");
412
}
413
414
return null;
415
}
416
417
// opaque ProtocolName<1..2^8-1>, RFC 7301.
418
int listLen = shc.applicationProtocol.length() + 1;
419
// 1: length byte
420
// ProtocolName protocol_name_list<2..2^16-1>, RFC 7301.
421
byte[] extData = new byte[listLen + 2]; // 2: list length
422
ByteBuffer m = ByteBuffer.wrap(extData);
423
Record.putInt16(m, listLen);
424
Record.putBytes8(m,
425
shc.applicationProtocol.getBytes(StandardCharsets.UTF_8));
426
427
// Update the context.
428
shc.conContext.applicationProtocol = shc.applicationProtocol;
429
430
// Clean or register the extension
431
//
432
// No further use of the request and respond extension any more.
433
shc.handshakeExtensions.remove(SSLExtension.CH_ALPN);
434
435
return extData;
436
}
437
}
438
439
/**
440
* Network data consumer of the extension in the ServerHello
441
* handshake message.
442
*/
443
private static final class SHAlpnConsumer implements ExtensionConsumer {
444
// Prevent instantiation of this class.
445
private SHAlpnConsumer() {
446
// blank
447
}
448
449
@Override
450
public void consume(ConnectionContext context,
451
HandshakeMessage message, ByteBuffer buffer) throws IOException {
452
// The producing happens in client side only.
453
ClientHandshakeContext chc = (ClientHandshakeContext)context;
454
455
// In response to ALPN request only
456
AlpnSpec requestedAlps =
457
(AlpnSpec)chc.handshakeExtensions.get(SSLExtension.CH_ALPN);
458
if (requestedAlps == null ||
459
requestedAlps.applicationProtocols == null ||
460
requestedAlps.applicationProtocols.isEmpty()) {
461
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
462
"Unexpected " + SSLExtension.CH_ALPN.name + " extension");
463
}
464
465
// Parse the extension.
466
AlpnSpec spec;
467
try {
468
spec = new AlpnSpec(buffer);
469
} catch (IOException ioe) {
470
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
471
}
472
473
// Only one application protocol is allowed.
474
if (spec.applicationProtocols.size() != 1) {
475
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
476
"Invalid " + SSLExtension.CH_ALPN.name + " extension: " +
477
"Only one application protocol name " +
478
"is allowed in ServerHello message");
479
}
480
481
// The respond application protocol must be one of the requested.
482
if (!requestedAlps.applicationProtocols.containsAll(
483
spec.applicationProtocols)) {
484
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
485
"Invalid " + SSLExtension.CH_ALPN.name + " extension: " +
486
"Only client specified application protocol " +
487
"is allowed in ServerHello message");
488
}
489
490
// Update the context.
491
chc.applicationProtocol = spec.applicationProtocols.get(0);
492
chc.conContext.applicationProtocol = chc.applicationProtocol;
493
494
// Clean or register the extension
495
//
496
// No further use of the request and respond extension any more.
497
chc.handshakeExtensions.remove(SSLExtension.CH_ALPN);
498
}
499
}
500
501
/**
502
* The absence processing if the extension is not present in
503
* the ServerHello handshake message.
504
*/
505
private static final class SHAlpnAbsence implements HandshakeAbsence {
506
@Override
507
public void absent(ConnectionContext context,
508
HandshakeMessage message) throws IOException {
509
// The producing happens in client side only.
510
ClientHandshakeContext chc = (ClientHandshakeContext)context;
511
512
// Please don't use the previous negotiated application protocol.
513
chc.applicationProtocol = "";
514
chc.conContext.applicationProtocol = "";
515
}
516
}
517
}
518
519