jdk/test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java
changeset 31057 babdeee3c007
child 31728 b72007a8a888
equal deleted inserted replaced
31008:5b500c93ce48 31057:babdeee3c007
       
     1 /*
       
     2  * Copyright (c) 2015, 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.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         }
       
    93 
       
    94         final String[] ciphers;
       
    95         final String description;
       
    96     }
       
    97 
       
    98     /**
       
    99      * Enumeration used to distinguish handshake mode in
       
   100      * {@link SSLEngineTestCase#doHandshake(javax.net.ssl.SSLEngine,
       
   101      * javax.net.ssl.SSLEngine, int, SSLEngineTestCase.HandshakeMode, boolean)
       
   102      * SSLEngineTestCase.doHandshake} method.
       
   103      */
       
   104     public enum HandshakeMode {
       
   105 
       
   106         /**
       
   107          * Initial handshake done for the first time: both engines call
       
   108          * {@link SSLEngine#beginHandshake()} method.
       
   109          */
       
   110         INITIAL_HANDSHAKE,
       
   111         /**
       
   112          * Repeated handshake done by client: client engine calls
       
   113          * {@link SSLEngine#beginHandshake()} method.
       
   114          */
       
   115         REHANDSHAKE_BEGIN_CLIENT,
       
   116         /**
       
   117          * Repeated handshake done by server: server engine calls
       
   118          * {@link SSLEngine#beginHandshake()} method.
       
   119          */
       
   120         REHANDSHAKE_BEGIN_SERVER;
       
   121     }
       
   122     /**
       
   123      * Security protocol to be tested: "TLS" or "DTLS" or their versions,
       
   124      * e.g. "TLSv1", "TLSv1.1", "TLSv1.2", "DTLSv1.0", "DTLSv1.2".
       
   125      */
       
   126     public static final String TESTED_SECURITY_PROTOCOL
       
   127             = System.getProperty("test.security.protocol", "TLS");
       
   128     /**
       
   129      * Test mode: "norm", "norm_sni" or "krb".
       
   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             }
       
   207             SUPPORTED_NON_KRB_NON_SHA_CIPHERS
       
   208                     = supportedCiphersList.toArray(new String[0]);
       
   209         } catch (Exception ex) {
       
   210             throw new Error("Unexpected issue", ex);
       
   211         }
       
   212     }
       
   213 
       
   214     private static final String[] SUPPORTED_KRB_CIPHERS;
       
   215 
       
   216     static {
       
   217         try {
       
   218             String[] allSupportedCiphers = getContext()
       
   219                     .createSSLEngine().getSupportedCipherSuites();
       
   220             List<String> supportedCiphersList = new LinkedList<>();
       
   221             for (String cipher : allSupportedCiphers) {
       
   222                 if (cipher.contains("KRB5")
       
   223                         && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
       
   224                     supportedCiphersList.add(cipher);
       
   225                 }
       
   226             }
       
   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",
       
   268             "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",
       
   269             "SSL_RSA_FIPS_WITH_DES_CBC_SHA",
       
   270             "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",
       
   271             "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",
       
   272             "TLS_KRB5_WITH_IDEA_CBC_MD5",
       
   273             "TLS_KRB5_WITH_IDEA_CBC_SHA",
       
   274             "SSL_RSA_WITH_IDEA_CBC_SHA",
       
   275             "TLS_DH_RSA_WITH_AES_128_GCM_SHA256",
       
   276             "TLS_DH_RSA_WITH_AES_256_GCM_SHA384",
       
   277             "TLS_DH_DSS_WITH_AES_128_GCM_SHA256",
       
   278             "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"
       
   279     };
       
   280 
       
   281     private final int maxPacketSize;
       
   282 
       
   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();
       
   543                 break;
       
   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
       
   689                     + " tests failed!");
       
   690         }
       
   691         System.out.println("All tests passed!");
       
   692     }
       
   693 
       
   694     /**
       
   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             KeyStore ks = KeyStore.getInstance("JKS");
       
   753             KeyStore ts = KeyStore.getInstance("JKS");
       
   754             char[] passphrase = PASSWD.toCharArray();
       
   755             try (FileInputStream keyFileStream = new FileInputStream(KEY_FILE_NAME)) {
       
   756                 ks.load(keyFileStream, passphrase);
       
   757             }
       
   758             try (FileInputStream trustFileStream = new FileInputStream(TRUST_FILE_NAME)) {
       
   759                 ts.load(trustFileStream, passphrase);
       
   760             }
       
   761             KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
       
   762             kmf.init(ks, passphrase);
       
   763             TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
       
   764             tmf.init(ts);
       
   765             SSLContext sslCtx = SSLContext.getInstance(TESTED_SECURITY_PROTOCOL);
       
   766             sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
       
   767             return sslCtx;
       
   768         } catch (KeyStoreException | IOException | NoSuchAlgorithmException |
       
   769                 CertificateException | UnrecoverableKeyException |
       
   770                 KeyManagementException ex) {
       
   771             throw new Error("Unexpected exception", ex);
       
   772         }
       
   773     }
       
   774 
       
   775     /**
       
   776      * Sets up and starts kerberos KDC server.
       
   777      */
       
   778     public static void setUpAndStartKDC() {
       
   779         String servicePrincipal = "host/" + SERVER_NAME + "@" + KRB_REALM;
       
   780         Map<String, String> principals = new HashMap<>();
       
   781         principals.put(KRB_USER_PRINCIPAL, KRB_USER_PASSWORD);
       
   782         principals.put(KRBTGT_PRINCIPAL, null);
       
   783         principals.put(servicePrincipal, null);
       
   784         System.setProperty("java.security.krb5.conf", KRB5_CONF_FILENAME);
       
   785         startKDC(KRB_REALM, principals, KTAB_FILENAME);
       
   786         System.setProperty("java.security.auth.login.config",
       
   787                 TEST_SRC + FS + JAAS_CONF_FILE);
       
   788         System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
       
   789     }
       
   790 
       
   791     /**
       
   792      * Sets up and starts kerberos KDC server if SSLEngineTestCase.TEST_MODE is "krb".
       
   793      */
       
   794     public static void setUpAndStartKDCIfNeeded() {
       
   795         if (TEST_MODE.equals("krb")) {
       
   796             setUpAndStartKDC();
       
   797         }
       
   798     }
       
   799 
       
   800     /**
       
   801      * Returns client ssl engine.
       
   802      *
       
   803      * @param context - SSLContext to get SSLEngine from.
       
   804      * @param useSNI  - flag used to enable or disable using SNI extension.
       
   805      *                Needed for Kerberos.
       
   806      */
       
   807     public static SSLEngine getClientSSLEngine(SSLContext context, boolean useSNI) {
       
   808         SSLEngine clientEngine = context.createSSLEngine(HOST, 80);
       
   809         clientEngine.setUseClientMode(true);
       
   810         if (useSNI) {
       
   811             SNIHostName serverName = new SNIHostName(SERVER_NAME);
       
   812             List<SNIServerName> serverNames = new ArrayList<>();
       
   813             serverNames.add(serverName);
       
   814             SSLParameters params = clientEngine.getSSLParameters();
       
   815             params.setServerNames(serverNames);
       
   816             clientEngine.setSSLParameters(params);
       
   817         }
       
   818         return clientEngine;
       
   819     }
       
   820 
       
   821     /**
       
   822      * Returns server 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 getServerSSLEngine(SSLContext context, boolean useSNI) {
       
   829         SSLEngine serverEngine = context.createSSLEngine();
       
   830         serverEngine.setUseClientMode(false);
       
   831         if (useSNI) {
       
   832             SNIMatcher matcher = SNIHostName.createSNIMatcher(SNI_PATTERN);
       
   833             List<SNIMatcher> matchers = new ArrayList<>();
       
   834             matchers.add(matcher);
       
   835             SSLParameters params = serverEngine.getSSLParameters();
       
   836             params.setSNIMatchers(matchers);
       
   837             serverEngine.setSSLParameters(params);
       
   838         }
       
   839         return serverEngine;
       
   840     }
       
   841 
       
   842     /**
       
   843      * Runs the test case for one cipher suite.
       
   844      *
       
   845      * @param cipher - Cipher suite name.
       
   846      * @throws SSLException - If tests fails.
       
   847      */
       
   848     abstract protected void testOneCipher(String cipher)
       
   849             throws SSLException;
       
   850 
       
   851     /**
       
   852      * Iterates through an array of ciphers and runs the same test case for
       
   853      * every entry.
       
   854      *
       
   855      * @param ciphers - Array of cipher names.
       
   856      * @return - Number of tests failed.
       
   857      */
       
   858     protected int testSomeCiphers(Ciphers ciphers) {
       
   859         int failedNum = 0;
       
   860         String description = ciphers.description;
       
   861         System.out.println("==================================================="
       
   862                 + "=========");
       
   863         System.out.println(description + " ciphers testing");
       
   864         System.out.println("==================================================="
       
   865                 + "=========");
       
   866         for (String cs : ciphers.ciphers) {
       
   867             System.out.println("-----------------------------------------------"
       
   868                     + "-------------");
       
   869             System.out.println("Testing cipher suite " + cs);
       
   870             System.out.println("-----------------------------------------------"
       
   871                     + "-------------");
       
   872             Throwable error = null;
       
   873             try {
       
   874                 testOneCipher(cs);
       
   875             } catch (Throwable t) {
       
   876                 error = t;
       
   877             }
       
   878             switch (ciphers) {
       
   879                 case SUPPORTED_NON_KRB_CIPHERS:
       
   880                 case SUPPORTED_NON_KRB_NON_SHA_CIPHERS:
       
   881                 case SUPPORTED_KRB_CIPHERS:
       
   882                 case ENABLED_NON_KRB_NOT_ANON_CIPHERS:
       
   883                     if (error != null) {
       
   884                         System.out.println("Test Failed: " + cs);
       
   885                         System.err.println("Test Exception for " + cs);
       
   886                         error.printStackTrace();
       
   887                         failedNum++;
       
   888                     } else {
       
   889                         System.out.println("Test Passed: " + cs);
       
   890                     }
       
   891                     break;
       
   892                 case UNSUPPORTED_CIPHERS:
       
   893                     if (error == null) {
       
   894                         System.out.println("Test Failed: " + cs);
       
   895                         System.err.println("Test for " + cs + " should have thrown"
       
   896                                 + " IllegalArgumentException, but it has not!");
       
   897                         failedNum++;
       
   898                     } else if (!(error instanceof IllegalArgumentException)) {
       
   899                         System.out.println("Test Failed: " + cs);
       
   900                         System.err.println("Test Exception for " + cs);
       
   901                         error.printStackTrace();
       
   902                         failedNum++;
       
   903                     } else {
       
   904                         System.out.println("Test Passed: " + cs);
       
   905                     }
       
   906                     break;
       
   907                 default:
       
   908                     throw new Error("Test issue: unexpected ciphers: "
       
   909                             + ciphers.name());
       
   910             }
       
   911         }
       
   912         return failedNum;
       
   913     }
       
   914 
       
   915     /**
       
   916      * Method used for the handshake routine.
       
   917      *
       
   918      * @param wrapingEngine         - Engine that is expected to wrap data.
       
   919      * @param unwrapingEngine       - Engine that is expected to unwrap data.
       
   920      * @param maxPacketSize         - Maximum packet size for MFLN of zero for no limit.
       
   921      * @param enableReplicatedPacks - Set {@code true} to enable replicated
       
   922      *                              packet sending.
       
   923      * @throws SSLException - thrown on engine errors.
       
   924      */
       
   925     private static void handshakeProcess(SSLEngine wrapingEngine,
       
   926                                          SSLEngine unwrapingEngine,
       
   927                                          int maxPacketSize,
       
   928                                          boolean enableReplicatedPacks)
       
   929             throws SSLException {
       
   930         SSLEngineResult.HandshakeStatus wrapingHSStatus = wrapingEngine
       
   931                 .getHandshakeStatus();
       
   932         SSLEngineResult.HandshakeStatus unwrapingHSStatus = unwrapingEngine
       
   933                 .getHandshakeStatus();
       
   934         SSLEngineResult r;
       
   935         String wrapper, unwrapper;
       
   936         if (wrapingEngine.getUseClientMode()
       
   937                 && !unwrapingEngine.getUseClientMode()) {
       
   938             wrapper = "Client";
       
   939             unwrapper = "Server";
       
   940         } else if (unwrapingEngine.getUseClientMode()
       
   941                 && !wrapingEngine.getUseClientMode()) {
       
   942             wrapper = "Server";
       
   943             unwrapper = "Client";
       
   944         } else {
       
   945             throw new Error("Both engines are in the same mode");
       
   946         }
       
   947         switch (wrapingHSStatus) {
       
   948             case NEED_WRAP:
       
   949                 if (enableReplicatedPacks) {
       
   950                     if (net != null) {
       
   951                         net.flip();
       
   952                         if (net.remaining() != 0) {
       
   953                             if (wrapingEngine.getUseClientMode()) {
       
   954                                 netReplicatedServer = net;
       
   955                             } else {
       
   956                                 netReplicatedClient = net;
       
   957                             }
       
   958                         }
       
   959                     }
       
   960                 }
       
   961                 ByteBuffer app = ByteBuffer.allocate(wrapingEngine.getSession()
       
   962                         .getApplicationBufferSize());
       
   963                 net = doWrap(wrapingEngine, wrapper, maxPacketSize, app);
       
   964             case NOT_HANDSHAKING:
       
   965                 switch (unwrapingHSStatus) {
       
   966                     case NEED_TASK:
       
   967                         runDelegatedTasks(unwrapingEngine);
       
   968                     case NEED_UNWRAP:
       
   969                         doUnWrap(unwrapingEngine, unwrapper, net);
       
   970                         if (enableReplicatedPacks) {
       
   971                             System.out.println("Unwrapping replicated packet...");
       
   972                             if (unwrapingEngine.getHandshakeStatus()
       
   973                                     .equals(SSLEngineResult.HandshakeStatus.NEED_TASK)) {
       
   974                                 runDelegatedTasks(unwrapingEngine);
       
   975                             }
       
   976                             runDelegatedTasks(unwrapingEngine);
       
   977                             ByteBuffer netReplicated;
       
   978                             if (unwrapingEngine.getUseClientMode()) {
       
   979                                 netReplicated = netReplicatedClient;
       
   980                             } else {
       
   981                                 netReplicated = netReplicatedServer;
       
   982                             }
       
   983                             if (netReplicated != null) {
       
   984                                 doUnWrap(unwrapingEngine, unwrapper, netReplicated);
       
   985                             } else {
       
   986                                 net.flip();
       
   987                                 doUnWrap(unwrapingEngine, unwrapper, net);
       
   988                             }
       
   989                         }
       
   990                         break;
       
   991                     case NEED_UNWRAP_AGAIN:
       
   992                         break;
       
   993                     case NOT_HANDSHAKING:
       
   994                         if (doUnwrapForNotHandshakingStatus) {
       
   995                             doUnWrap(unwrapingEngine, unwrapper, net);
       
   996                             doUnwrapForNotHandshakingStatus = false;
       
   997                             break;
       
   998                         } else {
       
   999                             endHandshakeLoop = true;
       
  1000                         }
       
  1001                         break;
       
  1002                     default:
       
  1003                         throw new Error("Unexpected unwraping engine handshake status "
       
  1004                                 + unwrapingHSStatus.name());
       
  1005                 }
       
  1006                 break;
       
  1007             case NEED_UNWRAP:
       
  1008                 break;
       
  1009             case NEED_UNWRAP_AGAIN:
       
  1010                 net.flip();
       
  1011                 doUnWrap(wrapingEngine, wrapper, net);
       
  1012                 break;
       
  1013             case NEED_TASK:
       
  1014                 runDelegatedTasks(wrapingEngine);
       
  1015                 break;
       
  1016             default:
       
  1017                 throw new Error("Unexpected wraping engine handshake status "
       
  1018                         + wrapingHSStatus.name());
       
  1019         }
       
  1020     }
       
  1021 
       
  1022     private static void runDelegatedTasks(SSLEngine engine) {
       
  1023         Runnable runnable;
       
  1024         System.out.println("Running delegated tasks...");
       
  1025         while ((runnable = engine.getDelegatedTask()) != null) {
       
  1026             runnable.run();
       
  1027         }
       
  1028         SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
       
  1029         if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
       
  1030             throw new Error("Handshake shouldn't need additional tasks.");
       
  1031         }
       
  1032     }
       
  1033 
       
  1034     /**
       
  1035      * Start a KDC server:
       
  1036      * - create a KDC instance
       
  1037      * - create Kerberos principals
       
  1038      * - save Kerberos configuration
       
  1039      * - save keys to keytab file
       
  1040      * - no pre-auth is required
       
  1041      */
       
  1042     private static void startKDC(String realm, Map<String, String> principals,
       
  1043                                  String ktab) {
       
  1044         try {
       
  1045             KDC kdc = KDC.create(realm, HOST, 0, true);
       
  1046             kdc.setOption(KDC.Option.PREAUTH_REQUIRED, Boolean.FALSE);
       
  1047             if (principals != null) {
       
  1048                 principals.entrySet().stream().forEach((entry) -> {
       
  1049                     String name = entry.getKey();
       
  1050                     String password = entry.getValue();
       
  1051                     if (password == null || password.isEmpty()) {
       
  1052                         System.out.println("KDC: add a principal '" + name
       
  1053                                 + "' with a random password");
       
  1054                         kdc.addPrincipalRandKey(name);
       
  1055                     } else {
       
  1056                         System.out.println("KDC: add a principal '" + name
       
  1057                                 + "' with '" + password + "' password");
       
  1058                         kdc.addPrincipal(name, password.toCharArray());
       
  1059                     }
       
  1060                 });
       
  1061             }
       
  1062             KDC.saveConfig(KRB5_CONF_FILENAME, kdc);
       
  1063             if (ktab != null) {
       
  1064                 File ktabFile = new File(ktab);
       
  1065                 if (ktabFile.exists()) {
       
  1066                     System.out.println("KDC: append keys to an exising "
       
  1067                             + "keytab file " + ktab);
       
  1068                     kdc.appendKtab(ktab);
       
  1069                 } else {
       
  1070                     System.out.println("KDC: create a new keytab file "
       
  1071                             + ktab);
       
  1072                     kdc.writeKtab(ktab);
       
  1073                 }
       
  1074             }
       
  1075             System.out.println("KDC: started on " + HOST + ":" + kdc.getPort()
       
  1076                     + " with '" + realm + "' realm");
       
  1077         } catch (Exception e) {
       
  1078             throw new RuntimeException("KDC: unexpected exception", e);
       
  1079         }
       
  1080     }
       
  1081 }