Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/javax/net/ssl/TLSCommon/SSLEngineTestCase.java
41152 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.
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
import javax.net.ssl.KeyManagerFactory;
25
import javax.net.ssl.SNIHostName;
26
import javax.net.ssl.SNIMatcher;
27
import javax.net.ssl.SNIServerName;
28
import javax.net.ssl.SSLContext;
29
import javax.net.ssl.SSLEngine;
30
import javax.net.ssl.SSLSession;
31
import javax.net.ssl.SSLEngineResult;
32
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
33
import javax.net.ssl.SSLException;
34
import javax.net.ssl.SSLParameters;
35
import javax.net.ssl.TrustManagerFactory;
36
import java.io.File;
37
import java.io.FileInputStream;
38
import java.io.IOException;
39
import java.nio.ByteBuffer;
40
import java.security.KeyManagementException;
41
import java.security.KeyStore;
42
import java.security.KeyStoreException;
43
import java.security.NoSuchAlgorithmException;
44
import java.security.UnrecoverableKeyException;
45
import java.security.cert.CertificateException;
46
import java.util.ArrayList;
47
import java.util.Arrays;
48
import java.util.HashMap;
49
import java.util.LinkedList;
50
import java.util.List;
51
import java.util.Map;
52
53
/**
54
* Basic class to inherit SSLEngine test cases from it. Tests apply for
55
* the TLS or DTLS security protocols and their versions.
56
*/
57
abstract public class SSLEngineTestCase {
58
59
public enum Ciphers {
60
61
/**
62
* Ciphers supported by the tested SSLEngine without those with
63
* kerberos authentication.
64
*/
65
SUPPORTED_NON_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_NON_KRB_CIPHERS,
66
"Supported non kerberos"),
67
/**
68
* Ciphers supported by the tested SSLEngine without those with
69
* kerberos authentication and without those with SHA256 ans SHA384.
70
*/
71
SUPPORTED_NON_KRB_NON_SHA_CIPHERS(
72
SSLEngineTestCase.SUPPORTED_NON_KRB_NON_SHA_CIPHERS,
73
"Supported non kerberos non SHA256 and SHA384"),
74
/**
75
* Ciphers supported by the tested SSLEngine with kerberos
76
* authentication.
77
*/
78
SUPPORTED_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_KRB_CIPHERS,
79
"Supported kerberos"),
80
/**
81
* Ciphers enabled by default for the tested SSLEngine without kerberos
82
* and anon.
83
*/
84
ENABLED_NON_KRB_NOT_ANON_CIPHERS(
85
SSLEngineTestCase.ENABLED_NON_KRB_NOT_ANON_CIPHERS,
86
"Enabled by default non kerberos not anonymous"),
87
/**
88
* Ciphers supported by TLS 1.3 only.
89
*/
90
TLS13_CIPHERS(
91
SSLEngineTestCase.TLS13_CIPHERS,
92
"Supported by TLS 1.3 only"),
93
/**
94
* Ciphers unsupported by the tested SSLEngine.
95
*/
96
UNSUPPORTED_CIPHERS(SSLEngineTestCase.UNSUPPORTED_CIPHERS,
97
"Unsupported");
98
99
Ciphers(String[] ciphers, String description) {
100
this.ciphers = ciphers;
101
this.description = description;
102
}
103
104
final String[] ciphers;
105
final String description;
106
}
107
108
/**
109
* Enumeration used to distinguish handshake mode in
110
* {@link SSLEngineTestCase#doHandshake(javax.net.ssl.SSLEngine,
111
* javax.net.ssl.SSLEngine, int, SSLEngineTestCase.HandshakeMode, boolean)
112
* SSLEngineTestCase.doHandshake} method.
113
*/
114
public enum HandshakeMode {
115
116
/**
117
* Initial handshake done for the first time: both engines call
118
* {@link SSLEngine#beginHandshake()} method.
119
*/
120
INITIAL_HANDSHAKE,
121
/**
122
* Repeated handshake done by client: client engine calls
123
* {@link SSLEngine#beginHandshake()} method.
124
*/
125
REHANDSHAKE_BEGIN_CLIENT,
126
/**
127
* Repeated handshake done by server: server engine calls
128
* {@link SSLEngine#beginHandshake()} method.
129
*/
130
REHANDSHAKE_BEGIN_SERVER;
131
}
132
/**
133
* Security protocol to be tested: "TLS" or "DTLS" or their versions,
134
* e.g. "TLSv1", "TLSv1.1", "TLSv1.2", "DTLSv1.0", "DTLSv1.2".
135
*/
136
public static final String TESTED_SECURITY_PROTOCOL
137
= System.getProperty("test.security.protocol", "TLS");
138
/**
139
* Test mode: "norm", "norm_sni" or "krb".
140
* Modes "norm" and "norm_sni" are used to run
141
* with all supported non-kerberos ciphers.
142
* Mode "krb" is used to run with kerberos ciphers.
143
*/
144
public static final String TEST_MODE
145
= System.getProperty("test.mode", "norm");
146
147
private static final String FS = System.getProperty("file.separator", "/");
148
private static final String PATH_TO_STORES = ".." + FS + "etc";
149
private static final String KEY_STORE_FILE = "keystore";
150
private static final String TRUST_STORE_FILE = "truststore";
151
private static final String PASSWD = "passphrase";
152
153
private static final String KEY_FILE_NAME
154
= System.getProperty("test.src", ".") + FS + PATH_TO_STORES
155
+ FS + KEY_STORE_FILE;
156
private static final String TRUST_FILE_NAME
157
= System.getProperty("test.src", ".") + FS + PATH_TO_STORES
158
+ FS + TRUST_STORE_FILE;
159
160
// Need an enhancement to use none-static mutable global variables.
161
private static ByteBuffer net;
162
private static boolean doUnwrapForNotHandshakingStatus;
163
private static boolean endHandshakeLoop = false;
164
165
private static final int MAX_HANDSHAKE_LOOPS = 100;
166
private static final String EXCHANGE_MSG_SENT = "Hello, peer!";
167
private static final String TEST_SRC = System.getProperty("test.src", ".");
168
private static final String KTAB_FILENAME = "krb5.keytab.data";
169
private static final String KRB_REALM = "TEST.REALM";
170
private static final String KRBTGT_PRINCIPAL = "krbtgt/" + KRB_REALM;
171
private static final String KRB_USER = "USER";
172
private static final String KRB_USER_PASSWORD = "password";
173
private static final String KRB_USER_PRINCIPAL = KRB_USER + "@" + KRB_REALM;
174
private static final String KRB5_CONF_FILENAME = "krb5.conf";
175
private static final String PATH_TO_COMMON = ".." + FS + "TLSCommon";
176
private static final String JAAS_CONF_FILE = PATH_TO_COMMON
177
+ FS + "jaas.conf";
178
private static final int DELAY = 1000;
179
private static final String HOST = "localhost";
180
private static final String SERVER_NAME = "service.localhost";
181
private static final String SNI_PATTERN = ".*";
182
183
private static final String[] TLS13_CIPHERS = {
184
"TLS_AES_256_GCM_SHA384",
185
"TLS_AES_128_GCM_SHA256",
186
"TLS_CHACHA20_POLY1305_SHA256"
187
};
188
189
private static final String[] SUPPORTED_NON_KRB_CIPHERS;
190
191
static {
192
try {
193
String[] allSupportedCiphers = getContext()
194
.createSSLEngine().getSupportedCipherSuites();
195
List<String> supportedCiphersList = new LinkedList<>();
196
for (String cipher : allSupportedCiphers) {
197
if (!cipher.contains("KRB5")
198
&& !isTLS13Cipher(cipher)
199
&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
200
supportedCiphersList.add(cipher);
201
}
202
}
203
SUPPORTED_NON_KRB_CIPHERS =
204
supportedCiphersList.toArray(new String[0]);
205
} catch (Exception ex) {
206
throw new Error("Unexpected issue", ex);
207
}
208
}
209
210
private static final String[] SUPPORTED_NON_KRB_NON_SHA_CIPHERS;
211
212
static {
213
try {
214
String[] allSupportedCiphers = getContext()
215
.createSSLEngine().getSupportedCipherSuites();
216
List<String> supportedCiphersList = new LinkedList<>();
217
for (String cipher : allSupportedCiphers) {
218
if (!cipher.contains("KRB5")
219
&& !isTLS13Cipher(cipher)
220
&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")
221
&& !cipher.endsWith("_SHA256")
222
&& !cipher.endsWith("_SHA384")) {
223
supportedCiphersList.add(cipher);
224
}
225
}
226
SUPPORTED_NON_KRB_NON_SHA_CIPHERS
227
= supportedCiphersList.toArray(new String[0]);
228
} catch (Exception ex) {
229
throw new Error("Unexpected issue", ex);
230
}
231
}
232
233
private static final String[] SUPPORTED_KRB_CIPHERS;
234
235
static {
236
try {
237
String[] allSupportedCiphers = getContext()
238
.createSSLEngine().getSupportedCipherSuites();
239
List<String> supportedCiphersList = new LinkedList<>();
240
for (String cipher : allSupportedCiphers) {
241
if (cipher.contains("KRB5")
242
&& !isTLS13Cipher(cipher)
243
&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
244
supportedCiphersList.add(cipher);
245
}
246
}
247
SUPPORTED_KRB_CIPHERS = supportedCiphersList.toArray(new String[0]);
248
} catch (Exception ex) {
249
throw new Error("Unexpected issue", ex);
250
}
251
}
252
253
private static final String[] ENABLED_NON_KRB_NOT_ANON_CIPHERS;
254
255
static {
256
try {
257
SSLEngine temporary = getContext().createSSLEngine();
258
temporary.setUseClientMode(true);
259
String[] enabledCiphers = temporary.getEnabledCipherSuites();
260
List<String> enabledCiphersList = new LinkedList<>();
261
for (String cipher : enabledCiphers) {
262
if (!cipher.contains("anon") && !cipher.contains("KRB5")
263
&& !isTLS13Cipher(cipher)
264
&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
265
enabledCiphersList.add(cipher);
266
}
267
}
268
ENABLED_NON_KRB_NOT_ANON_CIPHERS =
269
enabledCiphersList.toArray(new String[0]);
270
} catch (Exception ex) {
271
throw new Error("Unexpected issue", ex);
272
}
273
}
274
275
private static final String[] UNSUPPORTED_CIPHERS = {
276
"SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA",
277
"SSL_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA",
278
"SSL_DHE_DSS_WITH_RC4_128_SHA",
279
"SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
280
"SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA",
281
"SSL_DH_DSS_WITH_DES_CBC_SHA",
282
"SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
283
"SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA",
284
"SSL_DH_RSA_WITH_DES_CBC_SHA",
285
"SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA",
286
"SSL_FORTEZZA_DMS_WITH_NULL_SHA",
287
"SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA",
288
"SSL_RSA_EXPORT1024_WITH_RC4_56_SHA",
289
"SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
290
"SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",
291
"SSL_RSA_FIPS_WITH_DES_CBC_SHA",
292
"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",
293
"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",
294
"TLS_KRB5_WITH_IDEA_CBC_MD5",
295
"TLS_KRB5_WITH_IDEA_CBC_SHA",
296
"SSL_RSA_WITH_IDEA_CBC_SHA",
297
"TLS_DH_RSA_WITH_AES_128_GCM_SHA256",
298
"TLS_DH_RSA_WITH_AES_256_GCM_SHA384",
299
"TLS_DH_DSS_WITH_AES_128_GCM_SHA256",
300
"TLS_DH_DSS_WITH_AES_256_GCM_SHA384"
301
};
302
303
private final int maxPacketSize;
304
305
/**
306
* Constructs test case with the given MFLN maxMacketSize.
307
*
308
* @param maxPacketSize - MLFN extension max packet size.
309
*/
310
public SSLEngineTestCase(int maxPacketSize) {
311
this.maxPacketSize = maxPacketSize;
312
}
313
314
/**
315
* Constructs test case with {@code maxPacketSize = 0}.
316
*/
317
public SSLEngineTestCase() {
318
this.maxPacketSize = 0;
319
}
320
321
private static boolean isTLS13Cipher(String cipher) {
322
for (String cipherSuite : TLS13_CIPHERS) {
323
if (cipherSuite.equals(cipher)) {
324
return true;
325
}
326
}
327
328
return false;
329
}
330
331
/**
332
* Wraps data with the specified engine.
333
*
334
* @param engine - SSLEngine that wraps data.
335
* @param wrapper - Set wrapper id, e.g. "server" of "client".
336
* Used for logging only.
337
* @param maxPacketSize - Max packet size to check that MFLN extension
338
* works or zero for no check.
339
* @param app - Buffer with data to wrap.
340
* @return - Buffer with wrapped data.
341
* @throws SSLException - thrown on engine errors.
342
*/
343
public static ByteBuffer doWrap(SSLEngine engine, String wrapper,
344
int maxPacketSize, ByteBuffer app)
345
throws SSLException {
346
return doWrap(engine, wrapper, maxPacketSize,
347
app, SSLEngineResult.Status.OK, null);
348
}
349
350
/**
351
* Wraps data with the specified engine.
352
*
353
* @param engine - SSLEngine that wraps data.
354
* @param wrapper - Set wrapper id, e.g. "server" of "client".
355
* Used for logging only.
356
* @param maxPacketSize - Max packet size to check that MFLN extension
357
* works or zero for no check.
358
* @param app - Buffer with data to wrap.
359
* @param result - Array which first element will be used to
360
* output wrap result object.
361
* @return - Buffer with wrapped data.
362
* @throws SSLException - thrown on engine errors.
363
*/
364
public static ByteBuffer doWrap(SSLEngine engine, String wrapper,
365
int maxPacketSize, ByteBuffer app,
366
SSLEngineResult[] result)
367
throws SSLException {
368
return doWrap(engine, wrapper, maxPacketSize,
369
app, SSLEngineResult.Status.OK, result);
370
}
371
372
/**
373
* Wraps data with the specified engine.
374
*
375
* @param engine - SSLEngine that wraps data.
376
* @param wrapper - Set wrapper id, e.g. "server" of "client".
377
* Used for logging only.
378
* @param maxPacketSize - Max packet size to check that MFLN extension
379
* works or zero for no check.
380
* @param app - Buffer with data to wrap.
381
* @param wantedStatus - Specifies expected result status of wrapping.
382
* @return - Buffer with wrapped data.
383
* @throws SSLException - thrown on engine errors.
384
*/
385
public static ByteBuffer doWrap(SSLEngine engine, String wrapper,
386
int maxPacketSize, ByteBuffer app,
387
SSLEngineResult.Status wantedStatus)
388
throws SSLException {
389
return doWrap(engine, wrapper, maxPacketSize,
390
app, wantedStatus, null);
391
}
392
393
/**
394
* Wraps data with the specified engine.
395
*
396
* @param engine - SSLEngine that wraps data.
397
* @param wrapper - Set wrapper id, e.g. "server" of "client".
398
* Used for logging only.
399
* @param maxPacketSize - Max packet size to check that MFLN extension
400
* works or zero for no check.
401
* @param app - Buffer with data to wrap.
402
* @param wantedStatus - Specifies expected result status of wrapping.
403
* @param result - Array which first element will be used to output
404
* wrap result object.
405
* @return - Buffer with wrapped data.
406
* @throws SSLException - thrown on engine errors.
407
*/
408
public static ByteBuffer doWrap(SSLEngine engine, String wrapper,
409
int maxPacketSize, ByteBuffer app,
410
SSLEngineResult.Status wantedStatus,
411
SSLEngineResult[] result)
412
throws SSLException {
413
ByteBuffer net = ByteBuffer.allocate(engine.getSession()
414
.getPacketBufferSize());
415
SSLEngineResult r = engine.wrap(app, net);
416
net.flip();
417
int length = net.remaining();
418
System.out.println(wrapper + " wrapped " + length + " bytes.");
419
System.out.println(wrapper + " handshake status is "
420
+ engine.getHandshakeStatus() + " Result is " + r.getStatus());
421
if (maxPacketSize < length && maxPacketSize != 0) {
422
throw new AssertionError("Handshake wrapped net buffer length "
423
+ length + " exceeds maximum packet size "
424
+ maxPacketSize);
425
}
426
checkResult(r, wantedStatus);
427
if (result != null && result.length > 0) {
428
result[0] = r;
429
}
430
return net;
431
}
432
433
/**
434
* Unwraps data with the specified engine.
435
*
436
* @param engine - SSLEngine that unwraps data.
437
* @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for
438
* logging only.
439
* @param net - Buffer with data to unwrap.
440
* @return - Buffer with unwrapped data.
441
* @throws SSLException - thrown on engine errors.
442
*/
443
public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
444
ByteBuffer net) throws SSLException {
445
return doUnWrap(engine, unwrapper,
446
net, SSLEngineResult.Status.OK, null);
447
}
448
449
/**
450
* Unwraps data with the specified engine.
451
*
452
* @param engine - SSLEngine that unwraps data.
453
* @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for
454
* logging only.
455
* @param net - Buffer with data to unwrap.
456
* @param result - Array which first element will be used to output wrap
457
* result object.
458
* @return - Buffer with unwrapped data.
459
* @throws SSLException - thrown on engine errors.
460
*/
461
public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
462
ByteBuffer net, SSLEngineResult[] result) throws SSLException {
463
return doUnWrap(engine, unwrapper,
464
net, SSLEngineResult.Status.OK, result);
465
}
466
467
/**
468
* Unwraps data with the specified engine.
469
*
470
* @param engine - SSLEngine that unwraps data.
471
* @param unwrapper - Set unwrapper id, e.g. "server" of "client".
472
* Used for logging only.
473
* @param net - Buffer with data to unwrap.
474
* @param wantedStatus - Specifies expected result status of wrapping.
475
* @return - Buffer with unwrapped data.
476
* @throws SSLException - thrown on engine errors.
477
*/
478
public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
479
ByteBuffer net,
480
SSLEngineResult.Status wantedStatus) throws SSLException {
481
return doUnWrap(engine, unwrapper, net, wantedStatus, null);
482
}
483
484
/**
485
* Unwraps data with the specified engine.
486
*
487
* @param engine - SSLEngine that unwraps data.
488
* @param unwrapper - Set unwrapper id, e.g. "server" of "client".
489
* Used for logging only.
490
* @param net - Buffer with data to unwrap.
491
* @param wantedStatus - Specifies expected result status of wrapping.
492
* @param result - Array which first element will be used to output
493
* wrap result object.
494
* @return - Buffer with unwrapped data.
495
* @throws SSLException - thrown on engine errors.
496
*/
497
public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
498
ByteBuffer net, SSLEngineResult.Status wantedStatus,
499
SSLEngineResult[] result) throws SSLException {
500
501
ByteBuffer app = ByteBuffer.allocate(
502
engine.getSession().getApplicationBufferSize());
503
int length = net.remaining();
504
System.out.println(unwrapper + " unwrapping " + length + " bytes...");
505
SSLEngineResult r = engine.unwrap(net, app);
506
app.flip();
507
System.out.println(unwrapper + " handshake status is "
508
+ engine.getHandshakeStatus() + " Result is " + r.getStatus());
509
checkResult(r, wantedStatus);
510
if (result != null && result.length > 0) {
511
result[0] = r;
512
}
513
return app;
514
}
515
516
/**
517
* Does the handshake of the two specified engines according to the
518
* {@code mode} specified.
519
*
520
* @param clientEngine - Client SSLEngine.
521
* @param serverEngine - Server SSLEngine.
522
* @param maxPacketSize - Maximum packet size for MFLN of zero for no limit.
523
* @param mode - Handshake mode according to
524
* {@link HandshakeMode} enum.
525
* @throws SSLException - thrown on engine errors.
526
*/
527
public static void doHandshake(SSLEngine clientEngine,
528
SSLEngine serverEngine,
529
int maxPacketSize, HandshakeMode mode) throws SSLException {
530
531
doHandshake(clientEngine, serverEngine, maxPacketSize, mode, false);
532
}
533
534
/**
535
* Does the handshake of the two specified engines according to the
536
* {@code mode} specified.
537
*
538
* @param clientEngine - Client SSLEngine.
539
* @param serverEngine - Server SSLEngine.
540
* @param maxPacketSize - Maximum packet size for MFLN of zero
541
* for no limit.
542
* @param mode - Handshake mode according to
543
* {@link HandshakeMode} enum.
544
* @param enableReplicatedPacks - Set {@code true} to enable replicated
545
* packet sending.
546
* @throws SSLException - thrown on engine errors.
547
*/
548
public static void doHandshake(SSLEngine clientEngine,
549
SSLEngine serverEngine, int maxPacketSize,
550
HandshakeMode mode,
551
boolean enableReplicatedPacks) throws SSLException {
552
553
System.out.println("=============================================");
554
System.out.println("Starting handshake " + mode.name());
555
int loop = 0;
556
if (maxPacketSize < 0) {
557
throw new Error("Test issue: maxPacketSize is less than zero!");
558
}
559
SSLParameters params = clientEngine.getSSLParameters();
560
params.setMaximumPacketSize(maxPacketSize);
561
clientEngine.setSSLParameters(params);
562
params = serverEngine.getSSLParameters();
563
params.setMaximumPacketSize(maxPacketSize);
564
serverEngine.setSSLParameters(params);
565
SSLEngine firstEngine;
566
SSLEngine secondEngine;
567
switch (mode) {
568
case INITIAL_HANDSHAKE:
569
firstEngine = clientEngine;
570
secondEngine = serverEngine;
571
doUnwrapForNotHandshakingStatus = false;
572
clientEngine.beginHandshake();
573
serverEngine.beginHandshake();
574
break;
575
case REHANDSHAKE_BEGIN_CLIENT:
576
firstEngine = clientEngine;
577
secondEngine = serverEngine;
578
doUnwrapForNotHandshakingStatus = true;
579
clientEngine.beginHandshake();
580
break;
581
case REHANDSHAKE_BEGIN_SERVER:
582
firstEngine = serverEngine;
583
secondEngine = clientEngine;
584
doUnwrapForNotHandshakingStatus = true;
585
serverEngine.beginHandshake();
586
break;
587
default:
588
throw new Error("Test issue: unknown handshake mode");
589
}
590
endHandshakeLoop = false;
591
while (!endHandshakeLoop) {
592
if (++loop > MAX_HANDSHAKE_LOOPS) {
593
throw new Error("Too much loops for handshaking");
594
}
595
System.out.println("============================================");
596
System.out.println("Handshake loop " + loop + ": round 1");
597
System.out.println("==========================");
598
handshakeProcess(firstEngine, secondEngine, maxPacketSize,
599
enableReplicatedPacks);
600
if (endHandshakeLoop) {
601
break;
602
}
603
System.out.println("Handshake loop " + loop + ": round 2");
604
System.out.println("==========================");
605
handshakeProcess(secondEngine, firstEngine, maxPacketSize,
606
enableReplicatedPacks);
607
}
608
}
609
610
/**
611
* Routine to send application data from one SSLEngine to another.
612
*
613
* @param fromEngine - Sending engine.
614
* @param toEngine - Receiving engine.
615
* @return - Result of unwrap method of the receiving engine.
616
* @throws SSLException - thrown on engine errors.
617
*/
618
public static SSLEngineResult sendApplicationData(SSLEngine fromEngine,
619
SSLEngine toEngine)
620
throws SSLException {
621
String sender = null;
622
String reciever = null;
623
String excMsgSent = EXCHANGE_MSG_SENT;
624
if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) {
625
sender = "Client";
626
reciever = "Server";
627
excMsgSent += " Client.";
628
} else if (toEngine.getUseClientMode() &&
629
!fromEngine.getUseClientMode()) {
630
sender = "Server";
631
reciever = "Client";
632
excMsgSent += " Server.";
633
} else {
634
throw new Error("Test issue: both engines are in the same mode");
635
}
636
System.out.println("=============================================");
637
System.out.println("Trying to send application data from " + sender
638
+ " to " + reciever);
639
ByteBuffer clientAppSent
640
= ByteBuffer.wrap(excMsgSent.getBytes());
641
net = doWrap(fromEngine, sender, 0, clientAppSent);
642
SSLEngineResult[] r = new SSLEngineResult[1];
643
ByteBuffer serverAppRecv = doUnWrap(toEngine, reciever, net, r);
644
byte[] serverAppRecvTrunc = Arrays.copyOf(serverAppRecv.array(),
645
serverAppRecv.limit());
646
String msgRecv = new String(serverAppRecvTrunc);
647
if (!msgRecv.equals(excMsgSent)) {
648
throw new AssertionError(sender + " to " + reciever
649
+ ": application data"
650
+ " has been altered while sending."
651
+ " Message sent: " + "\"" + excMsgSent + "\"."
652
+ " Message recieved: " + "\"" + msgRecv + "\".");
653
}
654
System.out.println("Successful sending application data from " + sender
655
+ " to " + reciever);
656
return r[0];
657
}
658
659
/**
660
* Close engines by sending "close outbound" message from one SSLEngine to
661
* another.
662
*
663
* @param fromEngine - Sending engine.
664
* @param toEngine - Receiving engine.
665
* @throws SSLException - thrown on engine errors.
666
*/
667
public static void closeEngines(SSLEngine fromEngine,
668
SSLEngine toEngine) throws SSLException {
669
String from = null;
670
String to = null;
671
ByteBuffer app;
672
if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) {
673
from = "Client";
674
to = "Server";
675
} else if (toEngine.getUseClientMode() &&
676
!fromEngine.getUseClientMode()) {
677
from = "Server";
678
to = "Client";
679
} else {
680
throw new Error("Both engines are in the same mode");
681
}
682
System.out.println("=============================================");
683
System.out.println(
684
"Trying to close engines from " + from + " to " + to);
685
// Sending close outbound request to peer
686
fromEngine.closeOutbound();
687
app = ByteBuffer.allocate(
688
fromEngine.getSession().getApplicationBufferSize());
689
net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);
690
doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);
691
app = ByteBuffer.allocate(
692
fromEngine.getSession().getApplicationBufferSize());
693
net = doWrap(toEngine, to, 0, app, SSLEngineResult.Status.CLOSED);
694
doUnWrap(fromEngine, from, net, SSLEngineResult.Status.CLOSED);
695
if (!toEngine.isInboundDone()) {
696
throw new AssertionError(from + " sent close request to " + to
697
+ ", but " + to + "did not close inbound.");
698
}
699
// Executing close inbound
700
fromEngine.closeInbound();
701
app = ByteBuffer.allocate(
702
fromEngine.getSession().getApplicationBufferSize());
703
net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);
704
doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);
705
if (!toEngine.isOutboundDone()) {
706
throw new AssertionError(from + "sent close request to " + to
707
+ ", but " + to + "did not close outbound.");
708
}
709
System.out.println("Successful closing from " + from + " to " + to);
710
}
711
712
/**
713
* Runs the same test case for all given {@code ciphers}. Method counts all
714
* failures and throws {@code AssertionError} if one or more tests fail.
715
*
716
* @param ciphers - Ciphers that should be tested.
717
*/
718
public void runTests(Ciphers ciphers) {
719
int total = ciphers.ciphers.length;
720
int failed = testSomeCiphers(ciphers);
721
if (failed > 0) {
722
throw new AssertionError("" + failed + " of " + total
723
+ " tests failed!");
724
}
725
System.out.println("All tests passed!");
726
}
727
728
/**
729
* Runs test cases for ciphers defined by the test mode.
730
*/
731
public void runTests() {
732
switch (TEST_MODE) {
733
case "norm":
734
case "norm_sni":
735
switch (TESTED_SECURITY_PROTOCOL) {
736
case "DTLSv1.0":
737
case "TLSv1":
738
case "TLSv1.1":
739
runTests(Ciphers.SUPPORTED_NON_KRB_NON_SHA_CIPHERS);
740
break;
741
case "DTLSv1.1":
742
case "TLSv1.2":
743
runTests(Ciphers.SUPPORTED_NON_KRB_CIPHERS);
744
break;
745
case "TLSv1.3":
746
runTests(Ciphers.TLS13_CIPHERS);
747
break;
748
}
749
break;
750
case "krb":
751
runTests(Ciphers.SUPPORTED_KRB_CIPHERS);
752
break;
753
default:
754
throw new Error(
755
"Test error: unexpected test mode: " + TEST_MODE);
756
}
757
}
758
759
/**
760
* Returns maxPacketSize value used for MFLN extension testing
761
*
762
* @return - MLFN extension max packet size.
763
*/
764
public int getMaxPacketSize() {
765
return maxPacketSize;
766
}
767
768
/**
769
* Checks that status of result {@code r} is {@code wantedStatus}.
770
*
771
* @param r - Result.
772
* @param wantedStatus - Wanted status of the result.
773
* @throws AssertionError - if status or {@code r} is not
774
* {@code wantedStatus}.
775
*/
776
public static void checkResult(SSLEngineResult r,
777
SSLEngineResult.Status wantedStatus) {
778
SSLEngineResult.Status rs = r.getStatus();
779
if (!rs.equals(wantedStatus)) {
780
throw new AssertionError("Unexpected status " + rs.name()
781
+ ", should be " + wantedStatus.name());
782
}
783
}
784
785
/**
786
* Returns SSLContext with TESTED_SECURITY_PROTOCOL protocol and
787
* sets up keys.
788
*
789
* @return - SSLContext with a protocol specified by
790
* TESTED_SECURITY_PROTOCOL.
791
*/
792
public static SSLContext getContext() {
793
try {
794
java.security.Security.setProperty(
795
"jdk.tls.disabledAlgorithms", "");
796
java.security.Security.setProperty(
797
"jdk.certpath.disabledAlgorithms", "");
798
KeyStore ks = KeyStore.getInstance("JKS");
799
KeyStore ts = KeyStore.getInstance("JKS");
800
char[] passphrase = PASSWD.toCharArray();
801
try (FileInputStream keyFileStream =
802
new FileInputStream(KEY_FILE_NAME)) {
803
ks.load(keyFileStream, passphrase);
804
}
805
try (FileInputStream trustFileStream =
806
new FileInputStream(TRUST_FILE_NAME)) {
807
ts.load(trustFileStream, passphrase);
808
}
809
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
810
kmf.init(ks, passphrase);
811
TrustManagerFactory tmf =
812
TrustManagerFactory.getInstance("SunX509");
813
tmf.init(ts);
814
SSLContext sslCtx =
815
SSLContext.getInstance(TESTED_SECURITY_PROTOCOL);
816
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
817
return sslCtx;
818
} catch (KeyStoreException | IOException | NoSuchAlgorithmException |
819
CertificateException | UnrecoverableKeyException |
820
KeyManagementException ex) {
821
throw new Error("Unexpected exception", ex);
822
}
823
}
824
825
/**
826
* Sets up and starts kerberos KDC server.
827
*/
828
public static void setUpAndStartKDC() {
829
String servicePrincipal = "host/" + SERVER_NAME + "@" + KRB_REALM;
830
Map<String, String> principals = new HashMap<>();
831
principals.put(KRB_USER_PRINCIPAL, KRB_USER_PASSWORD);
832
principals.put(KRBTGT_PRINCIPAL, null);
833
principals.put(servicePrincipal, null);
834
System.setProperty("java.security.krb5.conf", KRB5_CONF_FILENAME);
835
startKDC(KRB_REALM, principals, KTAB_FILENAME);
836
System.setProperty("java.security.auth.login.config",
837
TEST_SRC + FS + JAAS_CONF_FILE);
838
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
839
}
840
841
/**
842
* Sets up and starts kerberos KDC server if
843
* SSLEngineTestCase.TEST_MODE is "krb".
844
*/
845
public static void setUpAndStartKDCIfNeeded() {
846
if (TEST_MODE.equals("krb")) {
847
setUpAndStartKDC();
848
}
849
}
850
851
/**
852
* Returns client ssl engine.
853
*
854
* @param context - SSLContext to get SSLEngine from.
855
* @param useSNI - flag used to enable or disable using SNI extension.
856
* Needed for Kerberos.
857
*/
858
public static SSLEngine getClientSSLEngine(
859
SSLContext context, boolean useSNI) {
860
861
SSLEngine clientEngine = context.createSSLEngine(HOST, 80);
862
clientEngine.setUseClientMode(true);
863
if (useSNI) {
864
SNIHostName serverName = new SNIHostName(SERVER_NAME);
865
List<SNIServerName> serverNames = new ArrayList<>();
866
serverNames.add(serverName);
867
SSLParameters params = clientEngine.getSSLParameters();
868
params.setServerNames(serverNames);
869
clientEngine.setSSLParameters(params);
870
}
871
return clientEngine;
872
}
873
874
/**
875
* Returns server ssl engine.
876
*
877
* @param context - SSLContext to get SSLEngine from.
878
* @param useSNI - flag used to enable or disable using SNI extension.
879
* Needed for Kerberos.
880
*/
881
public static SSLEngine getServerSSLEngine(
882
SSLContext context, boolean useSNI) {
883
884
SSLEngine serverEngine = context.createSSLEngine();
885
serverEngine.setUseClientMode(false);
886
if (useSNI) {
887
SNIMatcher matcher = SNIHostName.createSNIMatcher(SNI_PATTERN);
888
List<SNIMatcher> matchers = new ArrayList<>();
889
matchers.add(matcher);
890
SSLParameters params = serverEngine.getSSLParameters();
891
params.setSNIMatchers(matchers);
892
serverEngine.setSSLParameters(params);
893
}
894
return serverEngine;
895
}
896
897
/**
898
* Runs the test case for one cipher suite.
899
*
900
* @param cipher - Cipher suite name.
901
* @throws SSLException - If tests fails.
902
*/
903
abstract protected void testOneCipher(String cipher)
904
throws SSLException;
905
906
/**
907
* Iterates through an array of ciphers and runs the same test case for
908
* every entry.
909
*
910
* @param ciphers - Array of cipher names.
911
* @return - Number of tests failed.
912
*/
913
protected int testSomeCiphers(Ciphers ciphers) {
914
int failedNum = 0;
915
String description = ciphers.description;
916
System.out.println("===============================================");
917
System.out.println(description + " ciphers testing");
918
System.out.println("===========================================");
919
for (String cs : ciphers.ciphers) {
920
System.out.println("---------------------------------------");
921
System.out.println("Testing cipher suite " + cs);
922
System.out.println("---------------------------------------");
923
Throwable error = null;
924
925
// Reset global mutable static variables
926
net = null;
927
doUnwrapForNotHandshakingStatus = false;
928
endHandshakeLoop = false;
929
930
try {
931
testOneCipher(cs);
932
} catch (Throwable t) {
933
error = t;
934
}
935
switch (ciphers) {
936
case SUPPORTED_NON_KRB_CIPHERS:
937
case SUPPORTED_NON_KRB_NON_SHA_CIPHERS:
938
case SUPPORTED_KRB_CIPHERS:
939
case ENABLED_NON_KRB_NOT_ANON_CIPHERS:
940
case TLS13_CIPHERS:
941
if (error != null) {
942
System.out.println("Test Failed: " + cs);
943
System.err.println("Test Exception for " + cs);
944
error.printStackTrace();
945
failedNum++;
946
} else {
947
System.out.println("Test Passed: " + cs);
948
}
949
break;
950
case UNSUPPORTED_CIPHERS:
951
if (error == null) {
952
System.out.println("Test Failed: " + cs);
953
System.err.println("Test for " + cs +
954
" should have thrown " +
955
"IllegalArgumentException, but it has not!");
956
failedNum++;
957
} else if (!(error instanceof IllegalArgumentException)) {
958
System.out.println("Test Failed: " + cs);
959
System.err.println("Test Exception for " + cs);
960
error.printStackTrace();
961
failedNum++;
962
} else {
963
System.out.println("Test Passed: " + cs);
964
}
965
break;
966
default:
967
throw new Error("Test issue: unexpected ciphers: "
968
+ ciphers.name());
969
}
970
}
971
972
return failedNum;
973
}
974
975
/**
976
* Method used for the handshake routine.
977
*
978
* @param wrapingEngine - Engine that is expected to wrap data.
979
* @param unwrapingEngine - Engine that is expected to unwrap data.
980
* @param maxPacketSize - Maximum packet size for MFLN of zero
981
* for no limit.
982
* @param enableReplicatedPacks - Set {@code true} to enable replicated
983
* packet sending.
984
* @throws SSLException - thrown on engine errors.
985
*/
986
private static void handshakeProcess(SSLEngine wrapingEngine,
987
SSLEngine unwrapingEngine,
988
int maxPacketSize,
989
boolean enableReplicatedPacks) throws SSLException {
990
991
HandshakeStatus wrapingHSStatus = wrapingEngine.getHandshakeStatus();
992
HandshakeStatus unwrapingHSStatus =
993
unwrapingEngine.getHandshakeStatus();
994
SSLEngineResult r;
995
String wrapper, unwrapper;
996
if (wrapingEngine.getUseClientMode()
997
&& !unwrapingEngine.getUseClientMode()) {
998
wrapper = "Client";
999
unwrapper = "Server";
1000
} else if (unwrapingEngine.getUseClientMode()
1001
&& !wrapingEngine.getUseClientMode()) {
1002
wrapper = "Server";
1003
unwrapper = "Client";
1004
} else {
1005
throw new Error("Both engines are in the same mode");
1006
}
1007
System.out.println(
1008
wrapper + " handshake (wrap) status " + wrapingHSStatus);
1009
System.out.println(
1010
unwrapper + " handshake (unwrap) status " + unwrapingHSStatus);
1011
1012
ByteBuffer netReplicatedClient = null;
1013
ByteBuffer netReplicatedServer = null;
1014
switch (wrapingHSStatus) {
1015
case NEED_WRAP:
1016
if (enableReplicatedPacks) {
1017
if (net != null) {
1018
net.flip();
1019
if (net.remaining() != 0) {
1020
if (wrapingEngine.getUseClientMode()) {
1021
netReplicatedServer = net;
1022
} else {
1023
netReplicatedClient = net;
1024
}
1025
}
1026
}
1027
}
1028
ByteBuffer app = ByteBuffer.allocate(
1029
wrapingEngine.getSession().getApplicationBufferSize());
1030
net = doWrap(wrapingEngine, wrapper, maxPacketSize, app);
1031
wrapingHSStatus = wrapingEngine.getHandshakeStatus();
1032
// No break, falling into unwrapping.
1033
case NOT_HANDSHAKING:
1034
switch (unwrapingHSStatus) {
1035
case NEED_TASK:
1036
runDelegatedTasks(unwrapingEngine);
1037
case NEED_UNWRAP:
1038
doUnWrap(unwrapingEngine, unwrapper, net);
1039
if (enableReplicatedPacks) {
1040
System.out.println(unwrapper +
1041
" unwrapping replicated packet...");
1042
if (unwrapingEngine.getHandshakeStatus()
1043
.equals(HandshakeStatus.NEED_TASK)) {
1044
runDelegatedTasks(unwrapingEngine);
1045
}
1046
ByteBuffer netReplicated;
1047
if (unwrapingEngine.getUseClientMode()) {
1048
netReplicated = netReplicatedClient;
1049
} else {
1050
netReplicated = netReplicatedServer;
1051
}
1052
if (netReplicated != null) {
1053
doUnWrap(unwrapingEngine,
1054
unwrapper, netReplicated);
1055
} else {
1056
net.flip();
1057
doUnWrap(unwrapingEngine, unwrapper, net);
1058
}
1059
}
1060
break;
1061
case NEED_UNWRAP_AGAIN:
1062
break;
1063
case NOT_HANDSHAKING:
1064
if (doUnwrapForNotHandshakingStatus) {
1065
System.out.println("Not handshake status unwrap");
1066
doUnWrap(unwrapingEngine, unwrapper, net);
1067
doUnwrapForNotHandshakingStatus = false;
1068
break;
1069
} else {
1070
if (wrapingHSStatus ==
1071
HandshakeStatus.NOT_HANDSHAKING) {
1072
System.out.println("Handshake is completed");
1073
endHandshakeLoop = true;
1074
}
1075
}
1076
break;
1077
case NEED_WRAP:
1078
SSLSession session = unwrapingEngine.getSession();
1079
int bufferSize = session.getApplicationBufferSize();
1080
ByteBuffer b = ByteBuffer.allocate(bufferSize);
1081
net = doWrap(unwrapingEngine,
1082
unwrapper, maxPacketSize, b);
1083
unwrapingHSStatus =
1084
unwrapingEngine.getHandshakeStatus();
1085
if ((wrapingHSStatus ==
1086
HandshakeStatus.NOT_HANDSHAKING) &&
1087
(unwrapingHSStatus ==
1088
HandshakeStatus.NOT_HANDSHAKING)) {
1089
1090
System.out.println("Handshake is completed");
1091
endHandshakeLoop = true;
1092
}
1093
1094
break;
1095
default:
1096
throw new Error(
1097
"Unexpected unwraping engine handshake status "
1098
+ unwrapingHSStatus.name());
1099
}
1100
break;
1101
case NEED_UNWRAP:
1102
break;
1103
case NEED_UNWRAP_AGAIN:
1104
net.flip();
1105
doUnWrap(wrapingEngine, wrapper, net);
1106
break;
1107
case NEED_TASK:
1108
runDelegatedTasks(wrapingEngine);
1109
break;
1110
default:
1111
throw new Error("Unexpected wraping engine handshake status "
1112
+ wrapingHSStatus.name());
1113
}
1114
}
1115
1116
private static void runDelegatedTasks(SSLEngine engine) {
1117
Runnable runnable;
1118
System.out.println("Running delegated tasks...");
1119
while ((runnable = engine.getDelegatedTask()) != null) {
1120
runnable.run();
1121
}
1122
HandshakeStatus hs = engine.getHandshakeStatus();
1123
if (hs == HandshakeStatus.NEED_TASK) {
1124
throw new Error("Handshake shouldn't need additional tasks.");
1125
}
1126
}
1127
1128
/**
1129
* Start a KDC server:
1130
* - create a KDC instance
1131
* - create Kerberos principals
1132
* - save Kerberos configuration
1133
* - save keys to keytab file
1134
* - no pre-auth is required
1135
*/
1136
private static void startKDC(String realm, Map<String, String> principals,
1137
String ktab) {
1138
try {
1139
KDC kdc = KDC.create(realm, HOST, 0, true);
1140
kdc.setOption(KDC.Option.PREAUTH_REQUIRED, Boolean.FALSE);
1141
if (principals != null) {
1142
principals.entrySet().stream().forEach((entry) -> {
1143
String name = entry.getKey();
1144
String password = entry.getValue();
1145
if (password == null || password.isEmpty()) {
1146
System.out.println("KDC: add a principal '" + name
1147
+ "' with a random password");
1148
kdc.addPrincipalRandKey(name);
1149
} else {
1150
System.out.println("KDC: add a principal '" + name
1151
+ "' with '" + password + "' password");
1152
kdc.addPrincipal(name, password.toCharArray());
1153
}
1154
});
1155
}
1156
KDC.saveConfig(KRB5_CONF_FILENAME, kdc);
1157
if (ktab != null) {
1158
File ktabFile = new File(ktab);
1159
if (ktabFile.exists()) {
1160
System.out.println("KDC: append keys to an exising "
1161
+ "keytab file " + ktab);
1162
kdc.appendKtab(ktab);
1163
} else {
1164
System.out.println("KDC: create a new keytab file "
1165
+ ktab);
1166
kdc.writeKtab(ktab);
1167
}
1168
}
1169
System.out.println("KDC: started on " + HOST + ":" + kdc.getPort()
1170
+ " with '" + realm + "' realm");
1171
} catch (Exception e) {
1172
throw new RuntimeException("KDC: unexpected exception", e);
1173
}
1174
}
1175
}
1176
1177