Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/security/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java
38853 views
1
/*
2
* Copyright (c) 2011, 2020, 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
//
25
// SunJSSE does not support dynamic system properties, no way to re-use
26
// system properties in samevm/agentvm mode.
27
//
28
29
/*
30
* @test
31
* @bug 7031830
32
* @summary bad_record_mac failure on TLSv1.2 enabled connection with SSLEngine
33
* @library /lib/security
34
* @run main/othervm SSLEngineBadBufferArrayAccess
35
*/
36
37
/**
38
* A SSLSocket/SSLEngine interop test case. This is not the way to
39
* code SSLEngine-based servers, but works for what we need to do here,
40
* which is to make sure that SSLEngine/SSLSockets can talk to each other.
41
* SSLEngines can use direct or indirect buffers, and different code
42
* is used to get at the buffer contents internally, so we test that here.
43
*
44
* The test creates one SSLSocket (client) and one SSLEngine (server).
45
* The SSLSocket talks to a raw ServerSocket, and the server code
46
* does the translation between byte [] and ByteBuffers that the SSLEngine
47
* can use. The "transport" layer consists of a Socket Input/OutputStream
48
* and two byte buffers for the SSLEngines: think of them
49
* as directly connected pipes.
50
*
51
* Again, this is a *very* simple example: real code will be much more
52
* involved. For example, different threading and I/O models could be
53
* used, transport mechanisms could close unexpectedly, and so on.
54
*
55
* When this application runs, notice that several messages
56
* (wrap/unwrap) pass before any application data is consumed or
57
* produced. (For more information, please see the SSL/TLS
58
* specifications.) There may several steps for a successful handshake,
59
* so it's typical to see the following series of operations:
60
*
61
* client server message
62
* ====== ====== =======
63
* write() ... ClientHello
64
* ... unwrap() ClientHello
65
* ... wrap() ServerHello/Certificate
66
* read() ... ServerHello/Certificate
67
* write() ... ClientKeyExchange
68
* write() ... ChangeCipherSpec
69
* write() ... Finished
70
* ... unwrap() ClientKeyExchange
71
* ... unwrap() ChangeCipherSpec
72
* ... unwrap() Finished
73
* ... wrap() ChangeCipherSpec
74
* ... wrap() Finished
75
* read() ... ChangeCipherSpec
76
* read() ... Finished
77
*
78
* This particular bug had a problem where byte buffers backed by an
79
* array didn't offset correctly, and we got bad MAC errors.
80
*/
81
import javax.net.ssl.*;
82
import javax.net.ssl.SSLEngineResult.*;
83
import java.io.*;
84
import java.net.*;
85
import java.security.*;
86
import java.nio.*;
87
import java.util.concurrent.CountDownLatch;
88
import java.util.concurrent.TimeUnit;
89
90
public class SSLEngineBadBufferArrayAccess {
91
92
/*
93
* Enables logging of the SSL/TLS operations.
94
*/
95
private static boolean logging = true;
96
97
/*
98
* Enables the JSSE system debugging system property:
99
*
100
* -Djavax.net.debug=all
101
*
102
* This gives a lot of low-level information about operations underway,
103
* including specific handshake messages, and might be best examined
104
* after gaining some familiarity with this application.
105
*/
106
private static boolean debug = false;
107
private SSLContext sslc;
108
private SSLEngine serverEngine; // server-side SSLEngine
109
110
private final byte[] serverMsg = "Hi there Client, I'm a Server".getBytes();
111
private final byte[] clientMsg = "Hello Server, I'm a Client".getBytes();
112
113
private ByteBuffer serverOut; // write side of serverEngine
114
private ByteBuffer serverIn; // read side of serverEngine
115
116
private volatile Exception clientException;
117
private volatile Exception serverException;
118
119
/*
120
* For data transport, this example uses local ByteBuffers.
121
*/
122
private ByteBuffer cTOs; // "reliable" transport client->server
123
private ByteBuffer sTOc; // "reliable" transport server->client
124
125
/*
126
* The following is to set up the keystores/trust material.
127
*/
128
private static final String pathToStores = "../../../../javax/net/ssl/etc";
129
private static final String keyStoreFile = "keystore";
130
private static final String trustStoreFile = "truststore";
131
private static final String passwd = "passphrase";
132
private static String keyFilename =
133
System.getProperty("test.src", ".") + "/" + pathToStores
134
+ "/" + keyStoreFile;
135
private static String trustFilename =
136
System.getProperty("test.src", ".") + "/" + pathToStores
137
+ "/" + trustStoreFile;
138
139
/*
140
* Is the server ready to serve?
141
*/
142
private static final CountDownLatch serverCondition = new CountDownLatch(1);
143
144
/*
145
* Is the client ready to handshake?
146
*/
147
private static final CountDownLatch clientCondition = new CountDownLatch(1);
148
149
/*
150
* What's the server port? Use any free port by default
151
*/
152
private volatile int serverPort = 0;
153
154
/*
155
* Main entry point for this test.
156
*/
157
public static void main(String args[]) throws Exception {
158
if (debug) {
159
System.setProperty("javax.net.debug", "all");
160
}
161
162
// Re-enable TLSv1 and TLSv1.1 since test depends on them.
163
SecurityUtils.removeFromDisabledTlsAlgs("TLSv1", "TLSv1.1");
164
165
String [] protocols = new String [] {
166
"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" };
167
168
for (String protocol : protocols) {
169
/*
170
* Run the tests with direct and indirect buffers.
171
*/
172
log("Testing " + protocol + ":true");
173
new SSLEngineBadBufferArrayAccess(protocol).runTest(true);
174
175
log("Testing " + protocol + ":false");
176
new SSLEngineBadBufferArrayAccess(protocol).runTest(false);
177
}
178
179
System.out.println("Test Passed.");
180
}
181
182
/*
183
* Create an initialized SSLContext to use for these tests.
184
*/
185
public SSLEngineBadBufferArrayAccess(String protocol) throws Exception {
186
187
KeyStore ks = KeyStore.getInstance("JKS");
188
KeyStore ts = KeyStore.getInstance("JKS");
189
190
char[] passphrase = "passphrase".toCharArray();
191
192
try (FileInputStream fis = new FileInputStream(keyFilename)) {
193
ks.load(fis, passphrase);
194
}
195
196
try (FileInputStream fis = new FileInputStream(trustFilename)) {
197
ts.load(fis, passphrase);
198
}
199
200
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
201
kmf.init(ks, passphrase);
202
203
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
204
tmf.init(ts);
205
206
SSLContext sslCtx = SSLContext.getInstance(protocol);
207
208
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
209
210
sslc = sslCtx;
211
}
212
213
/*
214
* Run the test.
215
*
216
* Sit in a tight loop, with the server engine calling wrap/unwrap
217
* regardless of whether data is available or not. We do this until
218
* we get the application data. Then we shutdown and go to the next one.
219
*
220
* The main loop handles all of the I/O phases of the SSLEngine's
221
* lifetime:
222
*
223
* initial handshaking
224
* application data transfer
225
* engine closing
226
*
227
* One could easily separate these phases into separate
228
* sections of code.
229
*/
230
private void runTest(boolean direct) throws Exception {
231
boolean serverClose = direct;
232
233
ServerSocket serverSocket = new ServerSocket(0);
234
serverPort = serverSocket.getLocalPort();
235
236
// Signal the client, the server is ready to accept connection.
237
serverCondition.countDown();
238
239
Thread clientThread = runClient(serverClose);
240
241
// Try to accept a connection in 30 seconds.
242
Socket socket;
243
try {
244
serverSocket.setSoTimeout(30000);
245
socket = (Socket) serverSocket.accept();
246
} catch (SocketTimeoutException ste) {
247
serverSocket.close();
248
249
// Ignore the test case if no connection within 30 seconds.
250
System.out.println(
251
"No incoming client connection in 30 seconds. " +
252
"Ignore in server side.");
253
return;
254
}
255
256
// handle the connection
257
try {
258
// Is it the expected client connection?
259
//
260
// Naughty test cases or third party routines may try to
261
// connection to this server port unintentionally. In
262
// order to mitigate the impact of unexpected client
263
// connections and avoid intermittent failure, it should
264
// be checked that the accepted connection is really linked
265
// to the expected client.
266
boolean clientIsReady =
267
clientCondition.await(30L, TimeUnit.SECONDS);
268
269
if (clientIsReady) {
270
// Run the application in server side.
271
runServerApplication(socket, direct, serverClose);
272
} else { // Otherwise, ignore
273
// We don't actually care about plain socket connections
274
// for TLS communication testing generally. Just ignore
275
// the test if the accepted connection is not linked to
276
// the expected client or the client connection timeout
277
// in 30 seconds.
278
System.out.println(
279
"The client is not the expected one or timeout. " +
280
"Ignore in server side.");
281
}
282
} catch (Exception e) {
283
System.out.println("Server died ...");
284
e.printStackTrace(System.out);
285
serverException = e;
286
} finally {
287
socket.close();
288
serverSocket.close();
289
}
290
291
clientThread.join();
292
293
if (clientException != null || serverException != null) {
294
throw new RuntimeException("Test failed");
295
}
296
}
297
298
/*
299
* Define the server side application of the test for the specified socket.
300
*/
301
void runServerApplication(Socket socket, boolean direct,
302
boolean serverClose) throws Exception {
303
304
socket.setSoTimeout(500);
305
306
createSSLEngine();
307
createBuffers(direct);
308
309
boolean closed = false;
310
311
InputStream is = socket.getInputStream();
312
OutputStream os = socket.getOutputStream();
313
314
SSLEngineResult serverResult; // results from last operation
315
316
/*
317
* Examining the SSLEngineResults could be much more involved,
318
* and may alter the overall flow of the application.
319
*
320
* For example, if we received a BUFFER_OVERFLOW when trying
321
* to write to the output pipe, we could reallocate a larger
322
* pipe, but instead we wait for the peer to drain it.
323
*/
324
byte[] inbound = new byte[8192];
325
byte[] outbound = new byte[8192];
326
327
while (!isEngineClosed(serverEngine)) {
328
int len = 0;
329
330
// Inbound data
331
log("================");
332
333
// Read from the Client side.
334
try {
335
len = is.read(inbound);
336
if (len == -1) {
337
throw new Exception("Unexpected EOF");
338
}
339
cTOs.put(inbound, 0, len);
340
} catch (SocketTimeoutException ste) {
341
// swallow. Nothing yet, probably waiting on us.
342
System.out.println("Warning: " + ste);
343
}
344
345
cTOs.flip();
346
347
serverResult = serverEngine.unwrap(cTOs, serverIn);
348
log("server unwrap: ", serverResult);
349
runDelegatedTasks(serverResult, serverEngine);
350
cTOs.compact();
351
352
// Outbound data
353
log("----");
354
355
serverResult = serverEngine.wrap(serverOut, sTOc);
356
log("server wrap: ", serverResult);
357
runDelegatedTasks(serverResult, serverEngine);
358
359
sTOc.flip();
360
361
if ((len = sTOc.remaining()) != 0) {
362
sTOc.get(outbound, 0, len);
363
os.write(outbound, 0, len);
364
// Give the other side a chance to process
365
}
366
367
sTOc.compact();
368
369
if (!closed && (serverOut.remaining() == 0)) {
370
closed = true;
371
372
/*
373
* We'll alternate initiatating the shutdown.
374
* When the server initiates, it will take one more
375
* loop, but tests the orderly shutdown.
376
*/
377
if (serverClose) {
378
serverEngine.closeOutbound();
379
}
380
}
381
382
if (closed && isEngineClosed(serverEngine)) {
383
serverIn.flip();
384
385
/*
386
* A sanity check to ensure we got what was sent.
387
*/
388
if (serverIn.remaining() != clientMsg.length) {
389
throw new Exception("Client: Data length error -" +
390
" IF THIS FAILS, PLEASE REPORT THIS TO THE" +
391
" SECURITY TEAM. WE HAVE BEEN UNABLE TO" +
392
" RELIABLY DUPLICATE.");
393
}
394
395
for (int i = 0; i < clientMsg.length; i++) {
396
if (clientMsg[i] != serverIn.get()) {
397
throw new Exception("Client: Data content error -" +
398
" IF THIS FAILS, PLEASE REPORT THIS TO THE" +
399
" SECURITY TEAM. WE HAVE BEEN UNABLE TO" +
400
" RELIABLY DUPLICATE.");
401
}
402
}
403
serverIn.compact();
404
}
405
}
406
}
407
408
/*
409
* Create a client thread which does simple SSLSocket operations.
410
* We'll write and read one data packet.
411
*/
412
private Thread runClient(final boolean serverClose)
413
throws Exception {
414
415
Thread t = new Thread("ClientThread") {
416
417
@Override
418
public void run() {
419
try {
420
doClientSide(serverClose);
421
} catch (Exception e) {
422
System.out.println("Client died ...");
423
e.printStackTrace(System.out);
424
clientException = e;
425
}
426
}
427
};
428
429
t.start();
430
return t;
431
}
432
433
/*
434
* Define the client side of the test.
435
*/
436
void doClientSide(boolean serverClose) throws Exception {
437
// Wait for server to get started.
438
//
439
// The server side takes care of the issue if the server cannot
440
// get started in 90 seconds. The client side would just ignore
441
// the test case if the serer is not ready.
442
boolean serverIsReady =
443
serverCondition.await(90L, TimeUnit.SECONDS);
444
if (!serverIsReady) {
445
System.out.println(
446
"The server is not ready yet in 90 seconds. " +
447
"Ignore in client side.");
448
return;
449
}
450
451
SSLSocketFactory sslsf = sslc.getSocketFactory();
452
try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) {
453
try {
454
sslSocket.connect(
455
new InetSocketAddress("localhost", serverPort), 15000);
456
} catch (IOException ioe) {
457
// The server side may be impacted by naughty test cases or
458
// third party routines, and cannot accept connections.
459
//
460
// Just ignore the test if the connection cannot be
461
// established.
462
System.out.println(
463
"Cannot make a connection in 15 seconds. " +
464
"Ignore in client side.");
465
return;
466
}
467
468
// OK, here the client and server get connected.
469
470
// Signal the server, the client is ready to communicate.
471
clientCondition.countDown();
472
473
// There is still a chance in theory that the server thread may
474
// wait client-ready timeout and then quit. The chance should
475
// be really rare so we don't consider it until it becomes a
476
// real problem.
477
478
// Run the application in client side.
479
runClientApplication(sslSocket, serverClose);
480
}
481
}
482
483
/*
484
* Define the server side application of the test for the specified socket.
485
*/
486
void runClientApplication(SSLSocket sslSocket, boolean serverClose)
487
throws Exception {
488
489
OutputStream os = sslSocket.getOutputStream();
490
InputStream is = sslSocket.getInputStream();
491
492
// write(byte[]) goes in one shot.
493
os.write(clientMsg);
494
495
byte[] inbound = new byte[2048];
496
int pos = 0;
497
498
int len;
499
while ((len = is.read(inbound, pos, 2048 - pos)) != -1) {
500
pos += len;
501
// Let the client do the closing.
502
if ((pos == serverMsg.length) && !serverClose) {
503
sslSocket.close();
504
break;
505
}
506
}
507
508
if (pos != serverMsg.length) {
509
throw new Exception("Client: Data length error");
510
}
511
512
for (int i = 0; i < serverMsg.length; i++) {
513
if (inbound[i] != serverMsg[i]) {
514
throw new Exception("Client: Data content error");
515
}
516
}
517
}
518
519
/*
520
* Using the SSLContext created during object creation,
521
* create/configure the SSLEngines we'll use for this test.
522
*/
523
private void createSSLEngine() throws Exception {
524
/*
525
* Configure the serverEngine to act as a server in the SSL/TLS
526
* handshake.
527
*/
528
serverEngine = sslc.createSSLEngine();
529
serverEngine.setUseClientMode(false);
530
serverEngine.getNeedClientAuth();
531
}
532
533
/*
534
* Create and size the buffers appropriately.
535
*/
536
private void createBuffers(boolean direct) {
537
538
SSLSession session = serverEngine.getSession();
539
int appBufferMax = session.getApplicationBufferSize();
540
int netBufferMax = session.getPacketBufferSize();
541
542
/*
543
* We'll make the input buffers a bit bigger than the max needed
544
* size, so that unwrap()s following a successful data transfer
545
* won't generate BUFFER_OVERFLOWS.
546
*
547
* We'll use a mix of direct and indirect ByteBuffers for
548
* tutorial purposes only. In reality, only use direct
549
* ByteBuffers when they give a clear performance enhancement.
550
*/
551
if (direct) {
552
serverIn = ByteBuffer.allocateDirect(appBufferMax + 50);
553
cTOs = ByteBuffer.allocateDirect(netBufferMax);
554
sTOc = ByteBuffer.allocateDirect(netBufferMax);
555
} else {
556
serverIn = ByteBuffer.allocate(appBufferMax + 50);
557
cTOs = ByteBuffer.allocate(netBufferMax);
558
sTOc = ByteBuffer.allocate(netBufferMax);
559
}
560
561
serverOut = ByteBuffer.wrap(serverMsg);
562
}
563
564
/*
565
* If the result indicates that we have outstanding tasks to do,
566
* go ahead and run them in this thread.
567
*/
568
private static void runDelegatedTasks(SSLEngineResult result,
569
SSLEngine engine) throws Exception {
570
571
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
572
Runnable runnable;
573
while ((runnable = engine.getDelegatedTask()) != null) {
574
log("\trunning delegated task...");
575
runnable.run();
576
}
577
HandshakeStatus hsStatus = engine.getHandshakeStatus();
578
if (hsStatus == HandshakeStatus.NEED_TASK) {
579
throw new Exception(
580
"handshake shouldn't need additional tasks");
581
}
582
log("\tnew HandshakeStatus: " + hsStatus);
583
}
584
}
585
586
private static boolean isEngineClosed(SSLEngine engine) {
587
return (engine.isOutboundDone() && engine.isInboundDone());
588
}
589
590
/*
591
* Logging code
592
*/
593
private static boolean resultOnce = true;
594
595
private static void log(String str, SSLEngineResult result) {
596
if (!logging) {
597
return;
598
}
599
if (resultOnce) {
600
resultOnce = false;
601
System.out.println("The format of the SSLEngineResult is: \n"
602
+ "\t\"getStatus() / getHandshakeStatus()\" +\n"
603
+ "\t\"bytesConsumed() / bytesProduced()\"\n");
604
}
605
HandshakeStatus hsStatus = result.getHandshakeStatus();
606
log(str
607
+ result.getStatus() + "/" + hsStatus + ", "
608
+ result.bytesConsumed() + "/" + result.bytesProduced()
609
+ " bytes");
610
if (hsStatus == HandshakeStatus.FINISHED) {
611
log("\t...ready for application data");
612
}
613
}
614
615
private static void log(String str) {
616
if (logging) {
617
System.out.println(str);
618
}
619
}
620
}
621
622