Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/javax/net/ssl/ALPN/SSLEngineAlpnTest.java
41152 views
1
/*
2
* Copyright (c) 2003, 2016, 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.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
// SunJSSE does not support dynamic system properties, no way to re-use
25
// system properties in samevm/agentvm mode.
26
27
/*
28
* @test
29
* @bug 8051498 8145849 8170282
30
* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
31
* @compile MyX509ExtendedKeyManager.java
32
*
33
* @run main/othervm SSLEngineAlpnTest h2 UNUSED h2 h2
34
* @run main/othervm SSLEngineAlpnTest h2 UNUSED h2,http/1.1 h2
35
* @run main/othervm SSLEngineAlpnTest h2,http/1.1 UNUSED h2,http/1.1 h2
36
* @run main/othervm SSLEngineAlpnTest http/1.1,h2 UNUSED h2,http/1.1 http/1.1
37
* @run main/othervm SSLEngineAlpnTest h4,h3,h2 UNUSED h1,h2 h2
38
* @run main/othervm SSLEngineAlpnTest EMPTY UNUSED h2,http/1.1 NONE
39
* @run main/othervm SSLEngineAlpnTest h2 UNUSED EMPTY NONE
40
* @run main/othervm SSLEngineAlpnTest H2 UNUSED h2 ERROR
41
* @run main/othervm SSLEngineAlpnTest h2 UNUSED http/1.1 ERROR
42
*
43
* @run main/othervm SSLEngineAlpnTest UNUSED h2 h2 h2
44
* @run main/othervm SSLEngineAlpnTest UNUSED h2 h2,http/1.1 h2
45
* @run main/othervm SSLEngineAlpnTest UNUSED h2 http/1.1,h2 h2
46
* @run main/othervm SSLEngineAlpnTest UNUSED http/1.1 h2,http/1.1 http/1.1
47
* @run main/othervm SSLEngineAlpnTest UNUSED EMPTY h2,http/1.1 NONE
48
* @run main/othervm SSLEngineAlpnTest UNUSED h2 EMPTY NONE
49
* @run main/othervm SSLEngineAlpnTest UNUSED H2 h2 ERROR
50
* @run main/othervm SSLEngineAlpnTest UNUSED h2 http/1.1 ERROR
51
*
52
* @run main/othervm SSLEngineAlpnTest h2 h2 h2 h2
53
* @run main/othervm SSLEngineAlpnTest H2 h2 h2,http/1.1 h2
54
* @run main/othervm SSLEngineAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
55
* @run main/othervm SSLEngineAlpnTest http/1.1,h2 h2 h2,http/1.1 h2
56
* @run main/othervm SSLEngineAlpnTest EMPTY h2 h2 h2
57
* @run main/othervm SSLEngineAlpnTest h2,http/1.1 EMPTY http/1.1 NONE
58
* @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2 EMPTY NONE
59
* @run main/othervm SSLEngineAlpnTest UNUSED UNUSED http/1.1,h2 NONE
60
* @run main/othervm SSLEngineAlpnTest h2 h2 http/1.1 ERROR
61
* @run main/othervm SSLEngineAlpnTest h2,http/1.1 H2 http/1.1 ERROR
62
*/
63
/**
64
* A simple SSLEngine-based client/server that demonstrates the proposed API
65
* changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
66
*
67
* Usage:
68
* java SSLEngineAlpnTest <server-APs> <callback-AP> <client-APs> <result>
69
*
70
* where:
71
* EMPTY indicates that ALPN is disabled
72
* UNUSED indicates that no ALPN values are supplied (server-side only)
73
* ERROR indicates that an exception is expected
74
* NONE indicates that no ALPN is expected
75
*
76
* This example is based on our standard SSLEngineTemplate.
77
*
78
* The immediate consumer of ALPN will be HTTP/2 (RFC 7540), aka H2. The H2 IETF
79
* Working Group wanted to use TLSv1.3+ as the secure transport mechanism, but
80
* TLSv1.3 wasn't ready. The H2 folk agreed to a compromise that only TLSv1.2+
81
* can be used, and that if TLSv1.2 was selected, non-TLSv.1.3-approved
82
* ciphersuites would be blacklisted and their use discouraged.
83
*
84
* In order to support connections that might negotiate either HTTP/1.1 and H2,
85
* the guidance from the IETF Working Group is that the H2 ciphersuites be
86
* prioritized/tried first.
87
*/
88
89
/*
90
* The original SSLEngineTemplate comments follow.
91
*
92
* A SSLEngine usage example which simplifies the presentation
93
* by removing the I/O and multi-threading concerns.
94
*
95
* The test creates two SSLEngines, simulating a client and server.
96
* The "transport" layer consists two byte buffers: think of them
97
* as directly connected pipes.
98
*
99
* Note, this is a *very* simple example: real code will be much more
100
* involved. For example, different threading and I/O models could be
101
* used, transport mechanisms could close unexpectedly, and so on.
102
*
103
* When this application runs, notice that several messages
104
* (wrap/unwrap) pass before any application data is consumed or
105
* produced. (For more information, please see the SSL/TLS
106
* specifications.) There may several steps for a successful handshake,
107
* so it's typical to see the following series of operations:
108
*
109
* client server message
110
* ====== ====== =======
111
* wrap() ... ClientHello
112
* ... unwrap() ClientHello
113
* ... wrap() ServerHello/Certificate
114
* unwrap() ... ServerHello/Certificate
115
* wrap() ... ClientKeyExchange
116
* wrap() ... ChangeCipherSpec
117
* wrap() ... Finished
118
* ... unwrap() ClientKeyExchange
119
* ... unwrap() ChangeCipherSpec
120
* ... unwrap() Finished
121
* ... wrap() ChangeCipherSpec
122
* ... wrap() Finished
123
* unwrap() ... ChangeCipherSpec
124
* unwrap() ... Finished
125
*/
126
import javax.net.ssl.*;
127
import javax.net.ssl.SSLEngineResult.*;
128
import java.io.*;
129
import java.security.*;
130
import java.nio.*;
131
import java.util.Arrays;
132
133
public class SSLEngineAlpnTest {
134
135
/*
136
* Enables logging of the SSLEngine operations.
137
*/
138
private static final boolean logging = true;
139
140
/*
141
* Enables the JSSE system debugging system property:
142
*
143
* -Djavax.net.debug=all
144
*
145
* This gives a lot of low-level information about operations underway,
146
* including specific handshake messages, and might be best examined
147
* after gaining some familiarity with this application.
148
*/
149
private static final boolean debug = false;
150
151
private static boolean hasServerAPs; // whether server APs are present
152
private static boolean hasCallback; // whether a callback is present
153
154
private final SSLContext sslc;
155
156
private SSLEngine clientEngine; // client Engine
157
private ByteBuffer clientOut; // write side of clientEngine
158
private ByteBuffer clientIn; // read side of clientEngine
159
160
private SSLEngine serverEngine; // server Engine
161
private ByteBuffer serverOut; // write side of serverEngine
162
private ByteBuffer serverIn; // read side of serverEngine
163
164
/*
165
* For data transport, this example uses local ByteBuffers. This
166
* isn't really useful, but the purpose of this example is to show
167
* SSLEngine concepts, not how to do network transport.
168
*/
169
private ByteBuffer cTOs; // "reliable" transport client->server
170
private ByteBuffer sTOc; // "reliable" transport server->client
171
172
/*
173
* The following is to set up the keystores.
174
*/
175
private static final String pathToStores = "../etc";
176
private static final String keyStoreFile = "keystore";
177
private static final String trustStoreFile = "truststore";
178
private static final String passwd = "passphrase";
179
180
private static final String keyFilename
181
= System.getProperty("test.src", ".") + "/" + pathToStores
182
+ "/" + keyStoreFile;
183
private static final String trustFilename
184
= System.getProperty("test.src", ".") + "/" + pathToStores
185
+ "/" + trustStoreFile;
186
187
/*
188
* Main entry point for this test.
189
*/
190
public static void main(String args[]) throws Exception {
191
if (debug) {
192
System.setProperty("javax.net.debug", "all");
193
}
194
System.setProperty("jdk.tls.acknowledgeCloseNotify", "true");
195
System.out.println("Test args: " + Arrays.toString(args));
196
197
// Validate parameters
198
if (args.length != 4) {
199
throw new Exception("Invalid number of test parameters");
200
}
201
202
hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
203
hasCallback = !args[1].equals("UNUSED"); // is callback being used?
204
205
SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[3]);
206
try {
207
test.runTest(convert(args[0]), args[1], convert(args[2]), args[3]);
208
} catch (SSLHandshakeException she) {
209
if (args[3].equals("ERROR")) {
210
System.out.println("Caught the expected exception: " + she);
211
} else {
212
throw she;
213
}
214
}
215
216
System.out.println("Test Passed.");
217
}
218
219
/*
220
* Create an initialized SSLContext to use for these tests.
221
*/
222
public SSLEngineAlpnTest(String expectedAP) throws Exception {
223
224
KeyStore ks = KeyStore.getInstance("JKS");
225
KeyStore ts = KeyStore.getInstance("JKS");
226
227
char[] passphrase = "passphrase".toCharArray();
228
229
ks.load(new FileInputStream(keyFilename), passphrase);
230
ts.load(new FileInputStream(trustFilename), passphrase);
231
232
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
233
kmf.init(ks, passphrase);
234
235
KeyManager [] kms = kmf.getKeyManagers();
236
if (!(kms[0] instanceof X509ExtendedKeyManager)) {
237
throw new Exception("kms[0] not X509ExtendedKeyManager");
238
}
239
240
kms = new KeyManager[] { new MyX509ExtendedKeyManager(
241
(X509ExtendedKeyManager) kms[0], expectedAP,
242
!hasCallback && hasServerAPs) };
243
244
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
245
tmf.init(ts);
246
247
SSLContext sslCtx = SSLContext.getInstance("TLS");
248
249
sslCtx.init(kms, tmf.getTrustManagers(), null);
250
251
sslc = sslCtx;
252
}
253
254
/*
255
* Convert a comma-separated list into an array of strings.
256
*/
257
private static String[] convert(String list) {
258
if (list.equals("UNUSED")) {
259
return null;
260
}
261
262
if (list.equals("EMPTY")) {
263
return new String[0];
264
}
265
266
String[] strings;
267
if (list.indexOf(',') > 0) {
268
strings = list.split(",");
269
} else {
270
strings = new String[]{ list };
271
}
272
273
return strings;
274
}
275
276
/*
277
* Run the test.
278
*
279
* Sit in a tight loop, both engines calling wrap/unwrap regardless
280
* of whether data is available or not. We do this until both engines
281
* report back they are closed.
282
*
283
* The main loop handles all of the I/O phases of the SSLEngine's
284
* lifetime:
285
*
286
* initial handshaking
287
* application data transfer
288
* engine closing
289
*
290
* One could easily separate these phases into separate
291
* sections of code.
292
*/
293
private void runTest(String[] serverAPs, String callbackAP,
294
String[] clientAPs, String expectedAP) throws Exception {
295
296
boolean dataDone = false;
297
298
createSSLEngines(serverAPs, callbackAP, clientAPs);
299
createBuffers();
300
301
SSLEngineResult clientResult; // results from client's last operation
302
SSLEngineResult serverResult; // results from server's last operation
303
304
/*
305
* Examining the SSLEngineResults could be much more involved,
306
* and may alter the overall flow of the application.
307
*
308
* For example, if we received a BUFFER_OVERFLOW when trying
309
* to write to the output pipe, we could reallocate a larger
310
* pipe, but instead we wait for the peer to drain it.
311
*/
312
while (!isEngineClosed(clientEngine)
313
|| !isEngineClosed(serverEngine)) {
314
315
log("================");
316
317
clientResult = clientEngine.wrap(clientOut, cTOs);
318
log("client wrap: ", clientResult);
319
runDelegatedTasks(clientResult, clientEngine);
320
checkAPResult(clientEngine, clientResult, expectedAP);
321
322
serverResult = serverEngine.wrap(serverOut, sTOc);
323
log("server wrap: ", serverResult);
324
runDelegatedTasks(serverResult, serverEngine);
325
checkAPResult(serverEngine, serverResult, expectedAP);
326
327
cTOs.flip();
328
sTOc.flip();
329
330
log("----");
331
332
clientResult = clientEngine.unwrap(sTOc, clientIn);
333
log("client unwrap: ", clientResult);
334
runDelegatedTasks(clientResult, clientEngine);
335
checkAPResult(clientEngine, clientResult, expectedAP);
336
337
serverResult = serverEngine.unwrap(cTOs, serverIn);
338
log("server unwrap: ", serverResult);
339
runDelegatedTasks(serverResult, serverEngine);
340
checkAPResult(serverEngine, serverResult, expectedAP);
341
342
cTOs.compact();
343
sTOc.compact();
344
345
/*
346
* After we've transfered all application data between the client
347
* and server, we close the clientEngine's outbound stream.
348
* This generates a close_notify handshake message, which the
349
* server engine receives and responds by closing itself.
350
*/
351
if (!dataDone && (clientOut.limit() == serverIn.position())
352
&& (serverOut.limit() == clientIn.position())) {
353
354
/*
355
* A sanity check to ensure we got what was sent.
356
*/
357
checkTransfer(serverOut, clientIn);
358
checkTransfer(clientOut, serverIn);
359
360
log("\tClosing clientEngine's *OUTBOUND*...");
361
clientEngine.closeOutbound();
362
// serverEngine.closeOutbound();
363
dataDone = true;
364
}
365
}
366
}
367
368
/*
369
* Check that the resulting connection meets our defined ALPN
370
* criteria. If we were connecting to a non-JSSE implementation,
371
* the server might have negotiated something we shouldn't accept.
372
*
373
* If we were expecting an ALPN value from server, let's make sure
374
* the conditions match.
375
*/
376
private static void checkAPResult(SSLEngine engine, SSLEngineResult result,
377
String expectedAP) throws Exception {
378
379
if (result.getHandshakeStatus() != HandshakeStatus.FINISHED) {
380
return;
381
}
382
383
if (engine.getHandshakeApplicationProtocol() != null) {
384
throw new Exception ("getHandshakeApplicationProtocol() should "
385
+ "return null after the handshake is completed");
386
}
387
388
String ap = engine.getApplicationProtocol();
389
System.out.println("Application Protocol: \"" + ap + "\"");
390
391
if (ap == null) {
392
throw new Exception(
393
"Handshake was completed but null was received");
394
}
395
if (expectedAP.equals("NONE")) {
396
if (!ap.isEmpty()) {
397
throw new Exception("Expected no ALPN value");
398
} else {
399
System.out.println("No ALPN value negotiated, as expected");
400
}
401
} else if (!expectedAP.equals(ap)) {
402
throw new Exception(expectedAP +
403
" ALPN value not available on negotiated connection");
404
}
405
}
406
407
/*
408
* Using the SSLContext created during object creation,
409
* create/configure the SSLEngines we'll use for this test.
410
*/
411
private void createSSLEngines(String[] serverAPs, String callbackAP,
412
String[] clientAPs) throws Exception {
413
/*
414
* Configure the serverEngine to act as a server in the SSL/TLS
415
* handshake. Also, require SSL client authentication.
416
*/
417
serverEngine = sslc.createSSLEngine();
418
serverEngine.setUseClientMode(false);
419
420
SSLParameters sslp = serverEngine.getSSLParameters();
421
422
sslp.setNeedClientAuth(true);
423
424
/*
425
* The default ciphersuite ordering from the SSLContext may not
426
* reflect "h2" ciphersuites as being preferred, additionally the
427
* client may not send them in an appropriate order. We could resort
428
* the suite list if so desired.
429
*/
430
String[] suites = sslp.getCipherSuites();
431
sslp.setCipherSuites(suites);
432
if (serverAPs != null) {
433
sslp.setApplicationProtocols(serverAPs);
434
}
435
sslp.setUseCipherSuitesOrder(true); // Set server side order
436
437
serverEngine.setSSLParameters(sslp);
438
439
// check that no callback has been registered
440
if (serverEngine.getHandshakeApplicationProtocolSelector() != null) {
441
throw new Exception("getHandshakeApplicationProtocolSelector() " +
442
"should return null");
443
}
444
445
if (hasCallback) {
446
serverEngine.setHandshakeApplicationProtocolSelector(
447
(sslEngine, clientProtocols) -> {
448
return callbackAP.equals("EMPTY") ? "" : callbackAP;
449
});
450
451
// check that the callback can be retrieved
452
if (serverEngine.getHandshakeApplicationProtocolSelector()
453
== null) {
454
throw new Exception("getHandshakeApplicationProtocolSelector()"
455
+ " should return non-null");
456
}
457
}
458
459
/*
460
* Similar to above, but using client mode instead.
461
*/
462
clientEngine = sslc.createSSLEngine("client", 80);
463
clientEngine.setUseClientMode(true);
464
sslp = clientEngine.getSSLParameters();
465
if (clientAPs != null) {
466
sslp.setApplicationProtocols(clientAPs);
467
}
468
clientEngine.setSSLParameters(sslp);
469
470
if ((clientEngine.getHandshakeApplicationProtocol() != null) ||
471
(serverEngine.getHandshakeApplicationProtocol() != null)) {
472
throw new Exception ("getHandshakeApplicationProtocol() should "
473
+ "return null before the handshake starts");
474
}
475
}
476
477
/*
478
* Create and size the buffers appropriately.
479
*/
480
private void createBuffers() {
481
482
/*
483
* We'll assume the buffer sizes are the same
484
* between client and server.
485
*/
486
SSLSession session = clientEngine.getSession();
487
int appBufferMax = session.getApplicationBufferSize();
488
int netBufferMax = session.getPacketBufferSize();
489
490
/*
491
* We'll make the input buffers a bit bigger than the max needed
492
* size, so that unwrap()s following a successful data transfer
493
* won't generate BUFFER_OVERFLOWS.
494
*
495
* We'll use a mix of direct and indirect ByteBuffers for
496
* tutorial purposes only. In reality, only use direct
497
* ByteBuffers when they give a clear performance enhancement.
498
*/
499
clientIn = ByteBuffer.allocate(appBufferMax + 50);
500
serverIn = ByteBuffer.allocate(appBufferMax + 50);
501
502
cTOs = ByteBuffer.allocateDirect(netBufferMax);
503
sTOc = ByteBuffer.allocateDirect(netBufferMax);
504
505
clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
506
serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
507
}
508
509
/*
510
* If the result indicates that we have outstanding tasks to do,
511
* go ahead and run them in this thread.
512
*/
513
private static void runDelegatedTasks(SSLEngineResult result,
514
SSLEngine engine) throws Exception {
515
516
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
517
Runnable runnable;
518
while ((runnable = engine.getDelegatedTask()) != null) {
519
log("\trunning delegated task...");
520
runnable.run();
521
}
522
HandshakeStatus hsStatus = engine.getHandshakeStatus();
523
if (hsStatus == HandshakeStatus.NEED_TASK) {
524
throw new Exception(
525
"handshake shouldn't need additional tasks");
526
}
527
log("\tnew HandshakeStatus: " + hsStatus);
528
}
529
}
530
531
private static boolean isEngineClosed(SSLEngine engine) {
532
return (engine.isOutboundDone() && engine.isInboundDone());
533
}
534
535
/*
536
* Simple check to make sure everything came across as expected.
537
*/
538
private static void checkTransfer(ByteBuffer a, ByteBuffer b)
539
throws Exception {
540
a.flip();
541
b.flip();
542
543
if (!a.equals(b)) {
544
throw new Exception("Data didn't transfer cleanly");
545
} else {
546
log("\tData transferred cleanly");
547
}
548
549
a.position(a.limit());
550
b.position(b.limit());
551
a.limit(a.capacity());
552
b.limit(b.capacity());
553
}
554
555
/*
556
* Logging code
557
*/
558
private static boolean resultOnce = true;
559
560
private static void log(String str, SSLEngineResult result) {
561
if (!logging) {
562
return;
563
}
564
if (resultOnce) {
565
resultOnce = false;
566
System.out.println("The format of the SSLEngineResult is: \n"
567
+ "\t\"getStatus() / getHandshakeStatus()\" +\n"
568
+ "\t\"bytesConsumed() / bytesProduced()\"\n");
569
}
570
HandshakeStatus hsStatus = result.getHandshakeStatus();
571
log(str
572
+ result.getStatus() + "/" + hsStatus + ", "
573
+ result.bytesConsumed() + "/" + result.bytesProduced()
574
+ " bytes");
575
if (hsStatus == HandshakeStatus.FINISHED) {
576
log("\t...ready for application data");
577
}
578
}
579
580
private static void log(String str) {
581
if (logging) {
582
System.out.println(str);
583
}
584
}
585
}
586
587