Path: blob/master/test/jdk/javax/net/ssl/TLSCommon/SSLEngineTestCase.java
41152 views
/*1* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import javax.net.ssl.KeyManagerFactory;24import javax.net.ssl.SNIHostName;25import javax.net.ssl.SNIMatcher;26import javax.net.ssl.SNIServerName;27import javax.net.ssl.SSLContext;28import javax.net.ssl.SSLEngine;29import javax.net.ssl.SSLSession;30import javax.net.ssl.SSLEngineResult;31import javax.net.ssl.SSLEngineResult.HandshakeStatus;32import javax.net.ssl.SSLException;33import javax.net.ssl.SSLParameters;34import javax.net.ssl.TrustManagerFactory;35import java.io.File;36import java.io.FileInputStream;37import java.io.IOException;38import java.nio.ByteBuffer;39import java.security.KeyManagementException;40import java.security.KeyStore;41import java.security.KeyStoreException;42import java.security.NoSuchAlgorithmException;43import java.security.UnrecoverableKeyException;44import java.security.cert.CertificateException;45import java.util.ArrayList;46import java.util.Arrays;47import java.util.HashMap;48import java.util.LinkedList;49import java.util.List;50import java.util.Map;5152/**53* Basic class to inherit SSLEngine test cases from it. Tests apply for54* the TLS or DTLS security protocols and their versions.55*/56abstract public class SSLEngineTestCase {5758public enum Ciphers {5960/**61* Ciphers supported by the tested SSLEngine without those with62* kerberos authentication.63*/64SUPPORTED_NON_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_NON_KRB_CIPHERS,65"Supported non kerberos"),66/**67* Ciphers supported by the tested SSLEngine without those with68* kerberos authentication and without those with SHA256 ans SHA384.69*/70SUPPORTED_NON_KRB_NON_SHA_CIPHERS(71SSLEngineTestCase.SUPPORTED_NON_KRB_NON_SHA_CIPHERS,72"Supported non kerberos non SHA256 and SHA384"),73/**74* Ciphers supported by the tested SSLEngine with kerberos75* authentication.76*/77SUPPORTED_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_KRB_CIPHERS,78"Supported kerberos"),79/**80* Ciphers enabled by default for the tested SSLEngine without kerberos81* and anon.82*/83ENABLED_NON_KRB_NOT_ANON_CIPHERS(84SSLEngineTestCase.ENABLED_NON_KRB_NOT_ANON_CIPHERS,85"Enabled by default non kerberos not anonymous"),86/**87* Ciphers supported by TLS 1.3 only.88*/89TLS13_CIPHERS(90SSLEngineTestCase.TLS13_CIPHERS,91"Supported by TLS 1.3 only"),92/**93* Ciphers unsupported by the tested SSLEngine.94*/95UNSUPPORTED_CIPHERS(SSLEngineTestCase.UNSUPPORTED_CIPHERS,96"Unsupported");9798Ciphers(String[] ciphers, String description) {99this.ciphers = ciphers;100this.description = description;101}102103final String[] ciphers;104final String description;105}106107/**108* Enumeration used to distinguish handshake mode in109* {@link SSLEngineTestCase#doHandshake(javax.net.ssl.SSLEngine,110* javax.net.ssl.SSLEngine, int, SSLEngineTestCase.HandshakeMode, boolean)111* SSLEngineTestCase.doHandshake} method.112*/113public enum HandshakeMode {114115/**116* Initial handshake done for the first time: both engines call117* {@link SSLEngine#beginHandshake()} method.118*/119INITIAL_HANDSHAKE,120/**121* Repeated handshake done by client: client engine calls122* {@link SSLEngine#beginHandshake()} method.123*/124REHANDSHAKE_BEGIN_CLIENT,125/**126* Repeated handshake done by server: server engine calls127* {@link SSLEngine#beginHandshake()} method.128*/129REHANDSHAKE_BEGIN_SERVER;130}131/**132* Security protocol to be tested: "TLS" or "DTLS" or their versions,133* e.g. "TLSv1", "TLSv1.1", "TLSv1.2", "DTLSv1.0", "DTLSv1.2".134*/135public static final String TESTED_SECURITY_PROTOCOL136= System.getProperty("test.security.protocol", "TLS");137/**138* Test mode: "norm", "norm_sni" or "krb".139* Modes "norm" and "norm_sni" are used to run140* with all supported non-kerberos ciphers.141* Mode "krb" is used to run with kerberos ciphers.142*/143public static final String TEST_MODE144= System.getProperty("test.mode", "norm");145146private static final String FS = System.getProperty("file.separator", "/");147private static final String PATH_TO_STORES = ".." + FS + "etc";148private static final String KEY_STORE_FILE = "keystore";149private static final String TRUST_STORE_FILE = "truststore";150private static final String PASSWD = "passphrase";151152private static final String KEY_FILE_NAME153= System.getProperty("test.src", ".") + FS + PATH_TO_STORES154+ FS + KEY_STORE_FILE;155private static final String TRUST_FILE_NAME156= System.getProperty("test.src", ".") + FS + PATH_TO_STORES157+ FS + TRUST_STORE_FILE;158159// Need an enhancement to use none-static mutable global variables.160private static ByteBuffer net;161private static boolean doUnwrapForNotHandshakingStatus;162private static boolean endHandshakeLoop = false;163164private static final int MAX_HANDSHAKE_LOOPS = 100;165private static final String EXCHANGE_MSG_SENT = "Hello, peer!";166private static final String TEST_SRC = System.getProperty("test.src", ".");167private static final String KTAB_FILENAME = "krb5.keytab.data";168private static final String KRB_REALM = "TEST.REALM";169private static final String KRBTGT_PRINCIPAL = "krbtgt/" + KRB_REALM;170private static final String KRB_USER = "USER";171private static final String KRB_USER_PASSWORD = "password";172private static final String KRB_USER_PRINCIPAL = KRB_USER + "@" + KRB_REALM;173private static final String KRB5_CONF_FILENAME = "krb5.conf";174private static final String PATH_TO_COMMON = ".." + FS + "TLSCommon";175private static final String JAAS_CONF_FILE = PATH_TO_COMMON176+ FS + "jaas.conf";177private static final int DELAY = 1000;178private static final String HOST = "localhost";179private static final String SERVER_NAME = "service.localhost";180private static final String SNI_PATTERN = ".*";181182private static final String[] TLS13_CIPHERS = {183"TLS_AES_256_GCM_SHA384",184"TLS_AES_128_GCM_SHA256",185"TLS_CHACHA20_POLY1305_SHA256"186};187188private static final String[] SUPPORTED_NON_KRB_CIPHERS;189190static {191try {192String[] allSupportedCiphers = getContext()193.createSSLEngine().getSupportedCipherSuites();194List<String> supportedCiphersList = new LinkedList<>();195for (String cipher : allSupportedCiphers) {196if (!cipher.contains("KRB5")197&& !isTLS13Cipher(cipher)198&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {199supportedCiphersList.add(cipher);200}201}202SUPPORTED_NON_KRB_CIPHERS =203supportedCiphersList.toArray(new String[0]);204} catch (Exception ex) {205throw new Error("Unexpected issue", ex);206}207}208209private static final String[] SUPPORTED_NON_KRB_NON_SHA_CIPHERS;210211static {212try {213String[] allSupportedCiphers = getContext()214.createSSLEngine().getSupportedCipherSuites();215List<String> supportedCiphersList = new LinkedList<>();216for (String cipher : allSupportedCiphers) {217if (!cipher.contains("KRB5")218&& !isTLS13Cipher(cipher)219&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")220&& !cipher.endsWith("_SHA256")221&& !cipher.endsWith("_SHA384")) {222supportedCiphersList.add(cipher);223}224}225SUPPORTED_NON_KRB_NON_SHA_CIPHERS226= supportedCiphersList.toArray(new String[0]);227} catch (Exception ex) {228throw new Error("Unexpected issue", ex);229}230}231232private static final String[] SUPPORTED_KRB_CIPHERS;233234static {235try {236String[] allSupportedCiphers = getContext()237.createSSLEngine().getSupportedCipherSuites();238List<String> supportedCiphersList = new LinkedList<>();239for (String cipher : allSupportedCiphers) {240if (cipher.contains("KRB5")241&& !isTLS13Cipher(cipher)242&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {243supportedCiphersList.add(cipher);244}245}246SUPPORTED_KRB_CIPHERS = supportedCiphersList.toArray(new String[0]);247} catch (Exception ex) {248throw new Error("Unexpected issue", ex);249}250}251252private static final String[] ENABLED_NON_KRB_NOT_ANON_CIPHERS;253254static {255try {256SSLEngine temporary = getContext().createSSLEngine();257temporary.setUseClientMode(true);258String[] enabledCiphers = temporary.getEnabledCipherSuites();259List<String> enabledCiphersList = new LinkedList<>();260for (String cipher : enabledCiphers) {261if (!cipher.contains("anon") && !cipher.contains("KRB5")262&& !isTLS13Cipher(cipher)263&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {264enabledCiphersList.add(cipher);265}266}267ENABLED_NON_KRB_NOT_ANON_CIPHERS =268enabledCiphersList.toArray(new String[0]);269} catch (Exception ex) {270throw new Error("Unexpected issue", ex);271}272}273274private static final String[] UNSUPPORTED_CIPHERS = {275"SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA",276"SSL_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA",277"SSL_DHE_DSS_WITH_RC4_128_SHA",278"SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",279"SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA",280"SSL_DH_DSS_WITH_DES_CBC_SHA",281"SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",282"SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA",283"SSL_DH_RSA_WITH_DES_CBC_SHA",284"SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA",285"SSL_FORTEZZA_DMS_WITH_NULL_SHA",286"SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA",287"SSL_RSA_EXPORT1024_WITH_RC4_56_SHA",288"SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",289"SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",290"SSL_RSA_FIPS_WITH_DES_CBC_SHA",291"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",292"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",293"TLS_KRB5_WITH_IDEA_CBC_MD5",294"TLS_KRB5_WITH_IDEA_CBC_SHA",295"SSL_RSA_WITH_IDEA_CBC_SHA",296"TLS_DH_RSA_WITH_AES_128_GCM_SHA256",297"TLS_DH_RSA_WITH_AES_256_GCM_SHA384",298"TLS_DH_DSS_WITH_AES_128_GCM_SHA256",299"TLS_DH_DSS_WITH_AES_256_GCM_SHA384"300};301302private final int maxPacketSize;303304/**305* Constructs test case with the given MFLN maxMacketSize.306*307* @param maxPacketSize - MLFN extension max packet size.308*/309public SSLEngineTestCase(int maxPacketSize) {310this.maxPacketSize = maxPacketSize;311}312313/**314* Constructs test case with {@code maxPacketSize = 0}.315*/316public SSLEngineTestCase() {317this.maxPacketSize = 0;318}319320private static boolean isTLS13Cipher(String cipher) {321for (String cipherSuite : TLS13_CIPHERS) {322if (cipherSuite.equals(cipher)) {323return true;324}325}326327return false;328}329330/**331* Wraps data with the specified engine.332*333* @param engine - SSLEngine that wraps data.334* @param wrapper - Set wrapper id, e.g. "server" of "client".335* Used for logging only.336* @param maxPacketSize - Max packet size to check that MFLN extension337* works or zero for no check.338* @param app - Buffer with data to wrap.339* @return - Buffer with wrapped data.340* @throws SSLException - thrown on engine errors.341*/342public static ByteBuffer doWrap(SSLEngine engine, String wrapper,343int maxPacketSize, ByteBuffer app)344throws SSLException {345return doWrap(engine, wrapper, maxPacketSize,346app, SSLEngineResult.Status.OK, null);347}348349/**350* Wraps data with the specified engine.351*352* @param engine - SSLEngine that wraps data.353* @param wrapper - Set wrapper id, e.g. "server" of "client".354* Used for logging only.355* @param maxPacketSize - Max packet size to check that MFLN extension356* works or zero for no check.357* @param app - Buffer with data to wrap.358* @param result - Array which first element will be used to359* output wrap result object.360* @return - Buffer with wrapped data.361* @throws SSLException - thrown on engine errors.362*/363public static ByteBuffer doWrap(SSLEngine engine, String wrapper,364int maxPacketSize, ByteBuffer app,365SSLEngineResult[] result)366throws SSLException {367return doWrap(engine, wrapper, maxPacketSize,368app, SSLEngineResult.Status.OK, result);369}370371/**372* Wraps data with the specified engine.373*374* @param engine - SSLEngine that wraps data.375* @param wrapper - Set wrapper id, e.g. "server" of "client".376* Used for logging only.377* @param maxPacketSize - Max packet size to check that MFLN extension378* works or zero for no check.379* @param app - Buffer with data to wrap.380* @param wantedStatus - Specifies expected result status of wrapping.381* @return - Buffer with wrapped data.382* @throws SSLException - thrown on engine errors.383*/384public static ByteBuffer doWrap(SSLEngine engine, String wrapper,385int maxPacketSize, ByteBuffer app,386SSLEngineResult.Status wantedStatus)387throws SSLException {388return doWrap(engine, wrapper, maxPacketSize,389app, wantedStatus, null);390}391392/**393* Wraps data with the specified engine.394*395* @param engine - SSLEngine that wraps data.396* @param wrapper - Set wrapper id, e.g. "server" of "client".397* Used for logging only.398* @param maxPacketSize - Max packet size to check that MFLN extension399* works or zero for no check.400* @param app - Buffer with data to wrap.401* @param wantedStatus - Specifies expected result status of wrapping.402* @param result - Array which first element will be used to output403* wrap result object.404* @return - Buffer with wrapped data.405* @throws SSLException - thrown on engine errors.406*/407public static ByteBuffer doWrap(SSLEngine engine, String wrapper,408int maxPacketSize, ByteBuffer app,409SSLEngineResult.Status wantedStatus,410SSLEngineResult[] result)411throws SSLException {412ByteBuffer net = ByteBuffer.allocate(engine.getSession()413.getPacketBufferSize());414SSLEngineResult r = engine.wrap(app, net);415net.flip();416int length = net.remaining();417System.out.println(wrapper + " wrapped " + length + " bytes.");418System.out.println(wrapper + " handshake status is "419+ engine.getHandshakeStatus() + " Result is " + r.getStatus());420if (maxPacketSize < length && maxPacketSize != 0) {421throw new AssertionError("Handshake wrapped net buffer length "422+ length + " exceeds maximum packet size "423+ maxPacketSize);424}425checkResult(r, wantedStatus);426if (result != null && result.length > 0) {427result[0] = r;428}429return net;430}431432/**433* Unwraps data with the specified engine.434*435* @param engine - SSLEngine that unwraps data.436* @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for437* logging only.438* @param net - Buffer with data to unwrap.439* @return - Buffer with unwrapped data.440* @throws SSLException - thrown on engine errors.441*/442public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,443ByteBuffer net) throws SSLException {444return doUnWrap(engine, unwrapper,445net, SSLEngineResult.Status.OK, null);446}447448/**449* Unwraps data with the specified engine.450*451* @param engine - SSLEngine that unwraps data.452* @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for453* logging only.454* @param net - Buffer with data to unwrap.455* @param result - Array which first element will be used to output wrap456* result object.457* @return - Buffer with unwrapped data.458* @throws SSLException - thrown on engine errors.459*/460public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,461ByteBuffer net, SSLEngineResult[] result) throws SSLException {462return doUnWrap(engine, unwrapper,463net, SSLEngineResult.Status.OK, result);464}465466/**467* Unwraps data with the specified engine.468*469* @param engine - SSLEngine that unwraps data.470* @param unwrapper - Set unwrapper id, e.g. "server" of "client".471* Used for logging only.472* @param net - Buffer with data to unwrap.473* @param wantedStatus - Specifies expected result status of wrapping.474* @return - Buffer with unwrapped data.475* @throws SSLException - thrown on engine errors.476*/477public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,478ByteBuffer net,479SSLEngineResult.Status wantedStatus) throws SSLException {480return doUnWrap(engine, unwrapper, net, wantedStatus, null);481}482483/**484* Unwraps data with the specified engine.485*486* @param engine - SSLEngine that unwraps data.487* @param unwrapper - Set unwrapper id, e.g. "server" of "client".488* Used for logging only.489* @param net - Buffer with data to unwrap.490* @param wantedStatus - Specifies expected result status of wrapping.491* @param result - Array which first element will be used to output492* wrap result object.493* @return - Buffer with unwrapped data.494* @throws SSLException - thrown on engine errors.495*/496public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,497ByteBuffer net, SSLEngineResult.Status wantedStatus,498SSLEngineResult[] result) throws SSLException {499500ByteBuffer app = ByteBuffer.allocate(501engine.getSession().getApplicationBufferSize());502int length = net.remaining();503System.out.println(unwrapper + " unwrapping " + length + " bytes...");504SSLEngineResult r = engine.unwrap(net, app);505app.flip();506System.out.println(unwrapper + " handshake status is "507+ engine.getHandshakeStatus() + " Result is " + r.getStatus());508checkResult(r, wantedStatus);509if (result != null && result.length > 0) {510result[0] = r;511}512return app;513}514515/**516* Does the handshake of the two specified engines according to the517* {@code mode} specified.518*519* @param clientEngine - Client SSLEngine.520* @param serverEngine - Server SSLEngine.521* @param maxPacketSize - Maximum packet size for MFLN of zero for no limit.522* @param mode - Handshake mode according to523* {@link HandshakeMode} enum.524* @throws SSLException - thrown on engine errors.525*/526public static void doHandshake(SSLEngine clientEngine,527SSLEngine serverEngine,528int maxPacketSize, HandshakeMode mode) throws SSLException {529530doHandshake(clientEngine, serverEngine, maxPacketSize, mode, false);531}532533/**534* Does the handshake of the two specified engines according to the535* {@code mode} specified.536*537* @param clientEngine - Client SSLEngine.538* @param serverEngine - Server SSLEngine.539* @param maxPacketSize - Maximum packet size for MFLN of zero540* for no limit.541* @param mode - Handshake mode according to542* {@link HandshakeMode} enum.543* @param enableReplicatedPacks - Set {@code true} to enable replicated544* packet sending.545* @throws SSLException - thrown on engine errors.546*/547public static void doHandshake(SSLEngine clientEngine,548SSLEngine serverEngine, int maxPacketSize,549HandshakeMode mode,550boolean enableReplicatedPacks) throws SSLException {551552System.out.println("=============================================");553System.out.println("Starting handshake " + mode.name());554int loop = 0;555if (maxPacketSize < 0) {556throw new Error("Test issue: maxPacketSize is less than zero!");557}558SSLParameters params = clientEngine.getSSLParameters();559params.setMaximumPacketSize(maxPacketSize);560clientEngine.setSSLParameters(params);561params = serverEngine.getSSLParameters();562params.setMaximumPacketSize(maxPacketSize);563serverEngine.setSSLParameters(params);564SSLEngine firstEngine;565SSLEngine secondEngine;566switch (mode) {567case INITIAL_HANDSHAKE:568firstEngine = clientEngine;569secondEngine = serverEngine;570doUnwrapForNotHandshakingStatus = false;571clientEngine.beginHandshake();572serverEngine.beginHandshake();573break;574case REHANDSHAKE_BEGIN_CLIENT:575firstEngine = clientEngine;576secondEngine = serverEngine;577doUnwrapForNotHandshakingStatus = true;578clientEngine.beginHandshake();579break;580case REHANDSHAKE_BEGIN_SERVER:581firstEngine = serverEngine;582secondEngine = clientEngine;583doUnwrapForNotHandshakingStatus = true;584serverEngine.beginHandshake();585break;586default:587throw new Error("Test issue: unknown handshake mode");588}589endHandshakeLoop = false;590while (!endHandshakeLoop) {591if (++loop > MAX_HANDSHAKE_LOOPS) {592throw new Error("Too much loops for handshaking");593}594System.out.println("============================================");595System.out.println("Handshake loop " + loop + ": round 1");596System.out.println("==========================");597handshakeProcess(firstEngine, secondEngine, maxPacketSize,598enableReplicatedPacks);599if (endHandshakeLoop) {600break;601}602System.out.println("Handshake loop " + loop + ": round 2");603System.out.println("==========================");604handshakeProcess(secondEngine, firstEngine, maxPacketSize,605enableReplicatedPacks);606}607}608609/**610* Routine to send application data from one SSLEngine to another.611*612* @param fromEngine - Sending engine.613* @param toEngine - Receiving engine.614* @return - Result of unwrap method of the receiving engine.615* @throws SSLException - thrown on engine errors.616*/617public static SSLEngineResult sendApplicationData(SSLEngine fromEngine,618SSLEngine toEngine)619throws SSLException {620String sender = null;621String reciever = null;622String excMsgSent = EXCHANGE_MSG_SENT;623if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) {624sender = "Client";625reciever = "Server";626excMsgSent += " Client.";627} else if (toEngine.getUseClientMode() &&628!fromEngine.getUseClientMode()) {629sender = "Server";630reciever = "Client";631excMsgSent += " Server.";632} else {633throw new Error("Test issue: both engines are in the same mode");634}635System.out.println("=============================================");636System.out.println("Trying to send application data from " + sender637+ " to " + reciever);638ByteBuffer clientAppSent639= ByteBuffer.wrap(excMsgSent.getBytes());640net = doWrap(fromEngine, sender, 0, clientAppSent);641SSLEngineResult[] r = new SSLEngineResult[1];642ByteBuffer serverAppRecv = doUnWrap(toEngine, reciever, net, r);643byte[] serverAppRecvTrunc = Arrays.copyOf(serverAppRecv.array(),644serverAppRecv.limit());645String msgRecv = new String(serverAppRecvTrunc);646if (!msgRecv.equals(excMsgSent)) {647throw new AssertionError(sender + " to " + reciever648+ ": application data"649+ " has been altered while sending."650+ " Message sent: " + "\"" + excMsgSent + "\"."651+ " Message recieved: " + "\"" + msgRecv + "\".");652}653System.out.println("Successful sending application data from " + sender654+ " to " + reciever);655return r[0];656}657658/**659* Close engines by sending "close outbound" message from one SSLEngine to660* another.661*662* @param fromEngine - Sending engine.663* @param toEngine - Receiving engine.664* @throws SSLException - thrown on engine errors.665*/666public static void closeEngines(SSLEngine fromEngine,667SSLEngine toEngine) throws SSLException {668String from = null;669String to = null;670ByteBuffer app;671if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) {672from = "Client";673to = "Server";674} else if (toEngine.getUseClientMode() &&675!fromEngine.getUseClientMode()) {676from = "Server";677to = "Client";678} else {679throw new Error("Both engines are in the same mode");680}681System.out.println("=============================================");682System.out.println(683"Trying to close engines from " + from + " to " + to);684// Sending close outbound request to peer685fromEngine.closeOutbound();686app = ByteBuffer.allocate(687fromEngine.getSession().getApplicationBufferSize());688net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);689doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);690app = ByteBuffer.allocate(691fromEngine.getSession().getApplicationBufferSize());692net = doWrap(toEngine, to, 0, app, SSLEngineResult.Status.CLOSED);693doUnWrap(fromEngine, from, net, SSLEngineResult.Status.CLOSED);694if (!toEngine.isInboundDone()) {695throw new AssertionError(from + " sent close request to " + to696+ ", but " + to + "did not close inbound.");697}698// Executing close inbound699fromEngine.closeInbound();700app = ByteBuffer.allocate(701fromEngine.getSession().getApplicationBufferSize());702net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);703doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);704if (!toEngine.isOutboundDone()) {705throw new AssertionError(from + "sent close request to " + to706+ ", but " + to + "did not close outbound.");707}708System.out.println("Successful closing from " + from + " to " + to);709}710711/**712* Runs the same test case for all given {@code ciphers}. Method counts all713* failures and throws {@code AssertionError} if one or more tests fail.714*715* @param ciphers - Ciphers that should be tested.716*/717public void runTests(Ciphers ciphers) {718int total = ciphers.ciphers.length;719int failed = testSomeCiphers(ciphers);720if (failed > 0) {721throw new AssertionError("" + failed + " of " + total722+ " tests failed!");723}724System.out.println("All tests passed!");725}726727/**728* Runs test cases for ciphers defined by the test mode.729*/730public void runTests() {731switch (TEST_MODE) {732case "norm":733case "norm_sni":734switch (TESTED_SECURITY_PROTOCOL) {735case "DTLSv1.0":736case "TLSv1":737case "TLSv1.1":738runTests(Ciphers.SUPPORTED_NON_KRB_NON_SHA_CIPHERS);739break;740case "DTLSv1.1":741case "TLSv1.2":742runTests(Ciphers.SUPPORTED_NON_KRB_CIPHERS);743break;744case "TLSv1.3":745runTests(Ciphers.TLS13_CIPHERS);746break;747}748break;749case "krb":750runTests(Ciphers.SUPPORTED_KRB_CIPHERS);751break;752default:753throw new Error(754"Test error: unexpected test mode: " + TEST_MODE);755}756}757758/**759* Returns maxPacketSize value used for MFLN extension testing760*761* @return - MLFN extension max packet size.762*/763public int getMaxPacketSize() {764return maxPacketSize;765}766767/**768* Checks that status of result {@code r} is {@code wantedStatus}.769*770* @param r - Result.771* @param wantedStatus - Wanted status of the result.772* @throws AssertionError - if status or {@code r} is not773* {@code wantedStatus}.774*/775public static void checkResult(SSLEngineResult r,776SSLEngineResult.Status wantedStatus) {777SSLEngineResult.Status rs = r.getStatus();778if (!rs.equals(wantedStatus)) {779throw new AssertionError("Unexpected status " + rs.name()780+ ", should be " + wantedStatus.name());781}782}783784/**785* Returns SSLContext with TESTED_SECURITY_PROTOCOL protocol and786* sets up keys.787*788* @return - SSLContext with a protocol specified by789* TESTED_SECURITY_PROTOCOL.790*/791public static SSLContext getContext() {792try {793java.security.Security.setProperty(794"jdk.tls.disabledAlgorithms", "");795java.security.Security.setProperty(796"jdk.certpath.disabledAlgorithms", "");797KeyStore ks = KeyStore.getInstance("JKS");798KeyStore ts = KeyStore.getInstance("JKS");799char[] passphrase = PASSWD.toCharArray();800try (FileInputStream keyFileStream =801new FileInputStream(KEY_FILE_NAME)) {802ks.load(keyFileStream, passphrase);803}804try (FileInputStream trustFileStream =805new FileInputStream(TRUST_FILE_NAME)) {806ts.load(trustFileStream, passphrase);807}808KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");809kmf.init(ks, passphrase);810TrustManagerFactory tmf =811TrustManagerFactory.getInstance("SunX509");812tmf.init(ts);813SSLContext sslCtx =814SSLContext.getInstance(TESTED_SECURITY_PROTOCOL);815sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);816return sslCtx;817} catch (KeyStoreException | IOException | NoSuchAlgorithmException |818CertificateException | UnrecoverableKeyException |819KeyManagementException ex) {820throw new Error("Unexpected exception", ex);821}822}823824/**825* Sets up and starts kerberos KDC server.826*/827public static void setUpAndStartKDC() {828String servicePrincipal = "host/" + SERVER_NAME + "@" + KRB_REALM;829Map<String, String> principals = new HashMap<>();830principals.put(KRB_USER_PRINCIPAL, KRB_USER_PASSWORD);831principals.put(KRBTGT_PRINCIPAL, null);832principals.put(servicePrincipal, null);833System.setProperty("java.security.krb5.conf", KRB5_CONF_FILENAME);834startKDC(KRB_REALM, principals, KTAB_FILENAME);835System.setProperty("java.security.auth.login.config",836TEST_SRC + FS + JAAS_CONF_FILE);837System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");838}839840/**841* Sets up and starts kerberos KDC server if842* SSLEngineTestCase.TEST_MODE is "krb".843*/844public static void setUpAndStartKDCIfNeeded() {845if (TEST_MODE.equals("krb")) {846setUpAndStartKDC();847}848}849850/**851* Returns client ssl engine.852*853* @param context - SSLContext to get SSLEngine from.854* @param useSNI - flag used to enable or disable using SNI extension.855* Needed for Kerberos.856*/857public static SSLEngine getClientSSLEngine(858SSLContext context, boolean useSNI) {859860SSLEngine clientEngine = context.createSSLEngine(HOST, 80);861clientEngine.setUseClientMode(true);862if (useSNI) {863SNIHostName serverName = new SNIHostName(SERVER_NAME);864List<SNIServerName> serverNames = new ArrayList<>();865serverNames.add(serverName);866SSLParameters params = clientEngine.getSSLParameters();867params.setServerNames(serverNames);868clientEngine.setSSLParameters(params);869}870return clientEngine;871}872873/**874* Returns server ssl engine.875*876* @param context - SSLContext to get SSLEngine from.877* @param useSNI - flag used to enable or disable using SNI extension.878* Needed for Kerberos.879*/880public static SSLEngine getServerSSLEngine(881SSLContext context, boolean useSNI) {882883SSLEngine serverEngine = context.createSSLEngine();884serverEngine.setUseClientMode(false);885if (useSNI) {886SNIMatcher matcher = SNIHostName.createSNIMatcher(SNI_PATTERN);887List<SNIMatcher> matchers = new ArrayList<>();888matchers.add(matcher);889SSLParameters params = serverEngine.getSSLParameters();890params.setSNIMatchers(matchers);891serverEngine.setSSLParameters(params);892}893return serverEngine;894}895896/**897* Runs the test case for one cipher suite.898*899* @param cipher - Cipher suite name.900* @throws SSLException - If tests fails.901*/902abstract protected void testOneCipher(String cipher)903throws SSLException;904905/**906* Iterates through an array of ciphers and runs the same test case for907* every entry.908*909* @param ciphers - Array of cipher names.910* @return - Number of tests failed.911*/912protected int testSomeCiphers(Ciphers ciphers) {913int failedNum = 0;914String description = ciphers.description;915System.out.println("===============================================");916System.out.println(description + " ciphers testing");917System.out.println("===========================================");918for (String cs : ciphers.ciphers) {919System.out.println("---------------------------------------");920System.out.println("Testing cipher suite " + cs);921System.out.println("---------------------------------------");922Throwable error = null;923924// Reset global mutable static variables925net = null;926doUnwrapForNotHandshakingStatus = false;927endHandshakeLoop = false;928929try {930testOneCipher(cs);931} catch (Throwable t) {932error = t;933}934switch (ciphers) {935case SUPPORTED_NON_KRB_CIPHERS:936case SUPPORTED_NON_KRB_NON_SHA_CIPHERS:937case SUPPORTED_KRB_CIPHERS:938case ENABLED_NON_KRB_NOT_ANON_CIPHERS:939case TLS13_CIPHERS:940if (error != null) {941System.out.println("Test Failed: " + cs);942System.err.println("Test Exception for " + cs);943error.printStackTrace();944failedNum++;945} else {946System.out.println("Test Passed: " + cs);947}948break;949case UNSUPPORTED_CIPHERS:950if (error == null) {951System.out.println("Test Failed: " + cs);952System.err.println("Test for " + cs +953" should have thrown " +954"IllegalArgumentException, but it has not!");955failedNum++;956} else if (!(error instanceof IllegalArgumentException)) {957System.out.println("Test Failed: " + cs);958System.err.println("Test Exception for " + cs);959error.printStackTrace();960failedNum++;961} else {962System.out.println("Test Passed: " + cs);963}964break;965default:966throw new Error("Test issue: unexpected ciphers: "967+ ciphers.name());968}969}970971return failedNum;972}973974/**975* Method used for the handshake routine.976*977* @param wrapingEngine - Engine that is expected to wrap data.978* @param unwrapingEngine - Engine that is expected to unwrap data.979* @param maxPacketSize - Maximum packet size for MFLN of zero980* for no limit.981* @param enableReplicatedPacks - Set {@code true} to enable replicated982* packet sending.983* @throws SSLException - thrown on engine errors.984*/985private static void handshakeProcess(SSLEngine wrapingEngine,986SSLEngine unwrapingEngine,987int maxPacketSize,988boolean enableReplicatedPacks) throws SSLException {989990HandshakeStatus wrapingHSStatus = wrapingEngine.getHandshakeStatus();991HandshakeStatus unwrapingHSStatus =992unwrapingEngine.getHandshakeStatus();993SSLEngineResult r;994String wrapper, unwrapper;995if (wrapingEngine.getUseClientMode()996&& !unwrapingEngine.getUseClientMode()) {997wrapper = "Client";998unwrapper = "Server";999} else if (unwrapingEngine.getUseClientMode()1000&& !wrapingEngine.getUseClientMode()) {1001wrapper = "Server";1002unwrapper = "Client";1003} else {1004throw new Error("Both engines are in the same mode");1005}1006System.out.println(1007wrapper + " handshake (wrap) status " + wrapingHSStatus);1008System.out.println(1009unwrapper + " handshake (unwrap) status " + unwrapingHSStatus);10101011ByteBuffer netReplicatedClient = null;1012ByteBuffer netReplicatedServer = null;1013switch (wrapingHSStatus) {1014case NEED_WRAP:1015if (enableReplicatedPacks) {1016if (net != null) {1017net.flip();1018if (net.remaining() != 0) {1019if (wrapingEngine.getUseClientMode()) {1020netReplicatedServer = net;1021} else {1022netReplicatedClient = net;1023}1024}1025}1026}1027ByteBuffer app = ByteBuffer.allocate(1028wrapingEngine.getSession().getApplicationBufferSize());1029net = doWrap(wrapingEngine, wrapper, maxPacketSize, app);1030wrapingHSStatus = wrapingEngine.getHandshakeStatus();1031// No break, falling into unwrapping.1032case NOT_HANDSHAKING:1033switch (unwrapingHSStatus) {1034case NEED_TASK:1035runDelegatedTasks(unwrapingEngine);1036case NEED_UNWRAP:1037doUnWrap(unwrapingEngine, unwrapper, net);1038if (enableReplicatedPacks) {1039System.out.println(unwrapper +1040" unwrapping replicated packet...");1041if (unwrapingEngine.getHandshakeStatus()1042.equals(HandshakeStatus.NEED_TASK)) {1043runDelegatedTasks(unwrapingEngine);1044}1045ByteBuffer netReplicated;1046if (unwrapingEngine.getUseClientMode()) {1047netReplicated = netReplicatedClient;1048} else {1049netReplicated = netReplicatedServer;1050}1051if (netReplicated != null) {1052doUnWrap(unwrapingEngine,1053unwrapper, netReplicated);1054} else {1055net.flip();1056doUnWrap(unwrapingEngine, unwrapper, net);1057}1058}1059break;1060case NEED_UNWRAP_AGAIN:1061break;1062case NOT_HANDSHAKING:1063if (doUnwrapForNotHandshakingStatus) {1064System.out.println("Not handshake status unwrap");1065doUnWrap(unwrapingEngine, unwrapper, net);1066doUnwrapForNotHandshakingStatus = false;1067break;1068} else {1069if (wrapingHSStatus ==1070HandshakeStatus.NOT_HANDSHAKING) {1071System.out.println("Handshake is completed");1072endHandshakeLoop = true;1073}1074}1075break;1076case NEED_WRAP:1077SSLSession session = unwrapingEngine.getSession();1078int bufferSize = session.getApplicationBufferSize();1079ByteBuffer b = ByteBuffer.allocate(bufferSize);1080net = doWrap(unwrapingEngine,1081unwrapper, maxPacketSize, b);1082unwrapingHSStatus =1083unwrapingEngine.getHandshakeStatus();1084if ((wrapingHSStatus ==1085HandshakeStatus.NOT_HANDSHAKING) &&1086(unwrapingHSStatus ==1087HandshakeStatus.NOT_HANDSHAKING)) {10881089System.out.println("Handshake is completed");1090endHandshakeLoop = true;1091}10921093break;1094default:1095throw new Error(1096"Unexpected unwraping engine handshake status "1097+ unwrapingHSStatus.name());1098}1099break;1100case NEED_UNWRAP:1101break;1102case NEED_UNWRAP_AGAIN:1103net.flip();1104doUnWrap(wrapingEngine, wrapper, net);1105break;1106case NEED_TASK:1107runDelegatedTasks(wrapingEngine);1108break;1109default:1110throw new Error("Unexpected wraping engine handshake status "1111+ wrapingHSStatus.name());1112}1113}11141115private static void runDelegatedTasks(SSLEngine engine) {1116Runnable runnable;1117System.out.println("Running delegated tasks...");1118while ((runnable = engine.getDelegatedTask()) != null) {1119runnable.run();1120}1121HandshakeStatus hs = engine.getHandshakeStatus();1122if (hs == HandshakeStatus.NEED_TASK) {1123throw new Error("Handshake shouldn't need additional tasks.");1124}1125}11261127/**1128* Start a KDC server:1129* - create a KDC instance1130* - create Kerberos principals1131* - save Kerberos configuration1132* - save keys to keytab file1133* - no pre-auth is required1134*/1135private static void startKDC(String realm, Map<String, String> principals,1136String ktab) {1137try {1138KDC kdc = KDC.create(realm, HOST, 0, true);1139kdc.setOption(KDC.Option.PREAUTH_REQUIRED, Boolean.FALSE);1140if (principals != null) {1141principals.entrySet().stream().forEach((entry) -> {1142String name = entry.getKey();1143String password = entry.getValue();1144if (password == null || password.isEmpty()) {1145System.out.println("KDC: add a principal '" + name1146+ "' with a random password");1147kdc.addPrincipalRandKey(name);1148} else {1149System.out.println("KDC: add a principal '" + name1150+ "' with '" + password + "' password");1151kdc.addPrincipal(name, password.toCharArray());1152}1153});1154}1155KDC.saveConfig(KRB5_CONF_FILENAME, kdc);1156if (ktab != null) {1157File ktabFile = new File(ktab);1158if (ktabFile.exists()) {1159System.out.println("KDC: append keys to an exising "1160+ "keytab file " + ktab);1161kdc.appendKtab(ktab);1162} else {1163System.out.println("KDC: create a new keytab file "1164+ ktab);1165kdc.writeKtab(ktab);1166}1167}1168System.out.println("KDC: started on " + HOST + ":" + kdc.getPort()1169+ " with '" + realm + "' realm");1170} catch (Exception e) {1171throw new RuntimeException("KDC: unexpected exception", e);1172}1173}1174}117511761177