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