Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java
38853 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.lang.reflect.Field;39import java.nio.ByteBuffer;40import java.security.KeyManagementException;41import java.security.KeyStore;42import java.security.KeyStoreException;43import java.security.NoSuchAlgorithmException;44import java.security.UnrecoverableKeyException;45import java.security.cert.CertificateException;46import java.util.ArrayList;47import java.util.Arrays;48import java.util.HashMap;49import java.util.LinkedList;50import java.util.List;51import java.util.Map;5253/**54* Basic class to inherit SSLEngine test cases from it. Tests apply for55* the TLS security protocols and their versions.56*/57abstract public class SSLEngineTestCase {5859public enum Ciphers {6061/**62* Ciphers supported by the tested SSLEngine without those with63* kerberos authentication.64*/65SUPPORTED_NON_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_NON_KRB_CIPHERS,66"Supported non kerberos"),67/**68* Ciphers supported by the tested SSLEngine without those with69* kerberos authentication and without those with SHA256 ans SHA384.70*/71SUPPORTED_NON_KRB_NON_SHA_CIPHERS(72SSLEngineTestCase.SUPPORTED_NON_KRB_NON_SHA_CIPHERS,73"Supported non kerberos non SHA256 and SHA384"),74/**75* Ciphers supported by the tested SSLEngine with kerberos76* authentication.77*/78SUPPORTED_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_KRB_CIPHERS,79"Supported kerberos"),80/**81* Ciphers enabled by default for the tested SSLEngine without kerberos82* and anon.83*/84ENABLED_NON_KRB_NOT_ANON_CIPHERS(85SSLEngineTestCase.ENABLED_NON_KRB_NOT_ANON_CIPHERS,86"Enabled by default non kerberos not anonymous"),87/**88* Ciphers supported by TLS 1.3 only.89*/90TLS13_CIPHERS(91SSLEngineTestCase.TLS13_CIPHERS,92"Supported by TLS 1.3 only"),93/**94* Ciphers unsupported by the tested SSLEngine.95*/96UNSUPPORTED_CIPHERS(SSLEngineTestCase.UNSUPPORTED_CIPHERS,97"Unsupported");9899Ciphers(String[] ciphers, String description) {100this.ciphers = ciphers;101this.description = description;102}103104final String[] ciphers;105final String description;106}107108/**109* Enumeration used to distinguish handshake mode in110* {@link SSLEngineTestCase#doHandshake(javax.net.ssl.SSLEngine,111* javax.net.ssl.SSLEngine, int, SSLEngineTestCase.HandshakeMode, boolean)112* SSLEngineTestCase.doHandshake} method.113*/114public enum HandshakeMode {115116/**117* Initial handshake done for the first time: both engines call118* {@link SSLEngine#beginHandshake()} method.119*/120INITIAL_HANDSHAKE,121/**122* Repeated handshake done by client: client engine calls123* {@link SSLEngine#beginHandshake()} method.124*/125REHANDSHAKE_BEGIN_CLIENT,126/**127* Repeated handshake done by server: server engine calls128* {@link SSLEngine#beginHandshake()} method.129*/130REHANDSHAKE_BEGIN_SERVER;131}132/**133* Security protocol to be tested: "TLS" or their versions,134* e.g. "TLSv1", "TLSv1.1", "TLSv1.2".135*/136public static final String TESTED_SECURITY_PROTOCOL137= System.getProperty("test.security.protocol", "TLS");138/**139* Test mode: "norm", "norm_sni" or "krb".140* Modes "norm" and "norm_sni" are used to run141* with all supported non-kerberos ciphers.142* Mode "krb" is used to run with kerberos ciphers.143*/144public static final String TEST_MODE145= System.getProperty("test.mode", "norm");146147private static final String FS = System.getProperty("file.separator", "/");148private static final String PATH_TO_STORES = ".." + FS + "etc";149private static final String KEY_STORE_FILE = "keystore";150private static final String TRUST_STORE_FILE = "truststore";151private static final String PASSWD = "passphrase";152153private static final String KEY_FILE_NAME154= System.getProperty("test.src", ".") + FS + PATH_TO_STORES155+ FS + KEY_STORE_FILE;156private static final String TRUST_FILE_NAME157= System.getProperty("test.src", ".") + FS + PATH_TO_STORES158+ FS + TRUST_STORE_FILE;159160// Need an enhancement to use none-static mutable global variables.161private static ByteBuffer net;162private static boolean doUnwrapForNotHandshakingStatus;163private static boolean endHandshakeLoop = false;164165private static final int MAX_HANDSHAKE_LOOPS = 100;166private static final String EXCHANGE_MSG_SENT = "Hello, peer!";167private static final String TEST_SRC = System.getProperty("test.src", ".");168private static final String KTAB_FILENAME = "krb5.keytab.data";169private static final String KRB_REALM = "TEST.REALM";170private static final String KRBTGT_PRINCIPAL = "krbtgt/" + KRB_REALM;171private static final String KRB_USER = "USER";172private static final String KRB_USER_PASSWORD = "password";173private static final String KRB_USER_PRINCIPAL = KRB_USER + "@" + KRB_REALM;174private static final String KRB5_CONF_FILENAME = "krb5.conf";175private static final String PATH_TO_COMMON = ".." + FS + "TLSCommon";176private static final String JAAS_CONF_FILE = PATH_TO_COMMON177+ FS + "jaas.conf";178private static final int DELAY = 1000;179private static final String HOST = "localhost";180private static final String SERVER_NAME = "service.localhost";181private static final String SNI_PATTERN = ".*";182183private static final String[] TLS13_CIPHERS = {184"TLS_AES_256_GCM_SHA384",185"TLS_AES_128_GCM_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// to access maximumPacketSize and packetSize protected fields305static Class<?> sslEngineImplClz;306static Class<?> transportContextClz;307static Class<?> sslConfigurationClz;308static Class<?> outputRecordClz;309static Field conContextFld;310static Field sslConfigFld;311static Field maximumPacketSizeFld;312static Field outputRecordFld;313static Field packetSizeFld;314315static {316try {317sslEngineImplClz = Class.forName("sun.security.ssl.SSLEngineImpl");318transportContextClz = Class.forName("sun.security.ssl.TransportContext");319sslConfigurationClz = Class.forName("sun.security.ssl.SSLConfiguration");320outputRecordClz = Class.forName("sun.security.ssl.OutputRecord");321322conContextFld = sslEngineImplClz.getDeclaredField("conContext");323sslConfigFld = transportContextClz.getDeclaredField("sslConfig");324outputRecordFld = transportContextClz.getDeclaredField("outputRecord");325maximumPacketSizeFld = sslConfigurationClz.getDeclaredField("maximumPacketSize");326packetSizeFld = outputRecordClz.getDeclaredField("packetSize");327328conContextFld.setAccessible(true);329sslConfigFld.setAccessible(true);330outputRecordFld.setAccessible(true);331maximumPacketSizeFld.setAccessible(true);332packetSizeFld.setAccessible(true);333} catch (Exception x) {334throw new RuntimeException(x);335}336}337338public static void setMaxPacketSize(SSLEngine sslEngine, int maxPacketSize) {339try {340Object conContext = conContextFld.get(sslEngine);341Object sslConfig = sslConfigFld.get(conContext);342maximumPacketSizeFld.setInt(sslConfig, maxPacketSize);343344if (maxPacketSize != 0) {345Object outputRecord = outputRecordFld.get(conContext);346packetSizeFld.setInt(outputRecord, maxPacketSize);347}348} catch(IllegalAccessException | IllegalArgumentException iae) {349throw new RuntimeException(iae);350}351}352353/**354* Constructs test case with the given MFLN maxMacketSize.355*356* @param maxPacketSize - MLFN extension max packet size.357*/358public SSLEngineTestCase(int maxPacketSize) {359this.maxPacketSize = maxPacketSize;360}361362/**363* Constructs test case with {@code maxPacketSize = 0}.364*/365public SSLEngineTestCase() {366this.maxPacketSize = 0;367}368369private static boolean isTLS13Cipher(String cipher) {370for (String cipherSuite : TLS13_CIPHERS) {371if (cipherSuite.equals(cipher)) {372return true;373}374}375376return false;377}378379/**380* Wraps data with the specified engine.381*382* @param engine - SSLEngine that wraps data.383* @param wrapper - Set wrapper id, e.g. "server" of "client".384* Used for logging only.385* @param maxPacketSize - Max packet size to check that MFLN extension386* works or zero for no check.387* @param app - Buffer with data to wrap.388* @return - Buffer with wrapped data.389* @throws SSLException - thrown on engine errors.390*/391public static ByteBuffer doWrap(SSLEngine engine, String wrapper,392int maxPacketSize, ByteBuffer app)393throws SSLException {394return doWrap(engine, wrapper, maxPacketSize,395app, SSLEngineResult.Status.OK, null);396}397398/**399* Wraps data with the specified engine.400*401* @param engine - SSLEngine that wraps data.402* @param wrapper - Set wrapper id, e.g. "server" of "client".403* Used for logging only.404* @param maxPacketSize - Max packet size to check that MFLN extension405* works or zero for no check.406* @param app - Buffer with data to wrap.407* @param result - Array which first element will be used to408* output wrap result object.409* @return - Buffer with wrapped data.410* @throws SSLException - thrown on engine errors.411*/412public static ByteBuffer doWrap(SSLEngine engine, String wrapper,413int maxPacketSize, ByteBuffer app,414SSLEngineResult[] result)415throws SSLException {416return doWrap(engine, wrapper, maxPacketSize,417app, SSLEngineResult.Status.OK, result);418}419420/**421* Wraps data with the specified engine.422*423* @param engine - SSLEngine that wraps data.424* @param wrapper - Set wrapper id, e.g. "server" of "client".425* Used for logging only.426* @param maxPacketSize - Max packet size to check that MFLN extension427* works or zero for no check.428* @param app - Buffer with data to wrap.429* @param wantedStatus - Specifies expected result status of wrapping.430* @return - Buffer with wrapped data.431* @throws SSLException - thrown on engine errors.432*/433public static ByteBuffer doWrap(SSLEngine engine, String wrapper,434int maxPacketSize, ByteBuffer app,435SSLEngineResult.Status wantedStatus)436throws SSLException {437return doWrap(engine, wrapper, maxPacketSize,438app, wantedStatus, null);439}440441/**442* Wraps data with the specified engine.443*444* @param engine - SSLEngine that wraps data.445* @param wrapper - Set wrapper id, e.g. "server" of "client".446* Used for logging only.447* @param maxPacketSize - Max packet size to check that MFLN extension448* works or zero for no check.449* @param app - Buffer with data to wrap.450* @param wantedStatus - Specifies expected result status of wrapping.451* @param result - Array which first element will be used to output452* wrap result object.453* @return - Buffer with wrapped data.454* @throws SSLException - thrown on engine errors.455*/456public static ByteBuffer doWrap(SSLEngine engine, String wrapper,457int maxPacketSize, ByteBuffer app,458SSLEngineResult.Status wantedStatus,459SSLEngineResult[] result)460throws SSLException {461ByteBuffer net = ByteBuffer.allocate(engine.getSession()462.getPacketBufferSize());463SSLEngineResult r = engine.wrap(app, net);464net.flip();465int length = net.remaining();466System.out.println(wrapper + " wrapped " + length + " bytes.");467System.out.println(wrapper + " handshake status is "468+ engine.getHandshakeStatus() + " Result is " + r.getStatus());469if (maxPacketSize < length && maxPacketSize != 0) {470throw new AssertionError("Handshake wrapped net buffer length "471+ length + " exceeds maximum packet size "472+ maxPacketSize);473}474checkResult(r, wantedStatus);475if (result != null && result.length > 0) {476result[0] = r;477}478return net;479}480481/**482* Unwraps data with the specified engine.483*484* @param engine - SSLEngine that unwraps data.485* @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for486* logging only.487* @param net - Buffer with data to unwrap.488* @return - Buffer with unwrapped data.489* @throws SSLException - thrown on engine errors.490*/491public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,492ByteBuffer net) throws SSLException {493return doUnWrap(engine, unwrapper,494net, SSLEngineResult.Status.OK, null);495}496497/**498* Unwraps data with the specified engine.499*500* @param engine - SSLEngine that unwraps data.501* @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for502* logging only.503* @param net - Buffer with data to unwrap.504* @param result - Array which first element will be used to output wrap505* result object.506* @return - Buffer with unwrapped data.507* @throws SSLException - thrown on engine errors.508*/509public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,510ByteBuffer net, SSLEngineResult[] result) throws SSLException {511return doUnWrap(engine, unwrapper,512net, SSLEngineResult.Status.OK, result);513}514515/**516* Unwraps data with the specified engine.517*518* @param engine - SSLEngine that unwraps data.519* @param unwrapper - Set unwrapper id, e.g. "server" of "client".520* Used for logging only.521* @param net - Buffer with data to unwrap.522* @param wantedStatus - Specifies expected result status of wrapping.523* @return - Buffer with unwrapped data.524* @throws SSLException - thrown on engine errors.525*/526public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,527ByteBuffer net,528SSLEngineResult.Status wantedStatus) throws SSLException {529return doUnWrap(engine, unwrapper, net, wantedStatus, null);530}531532/**533* Unwraps data with the specified engine.534*535* @param engine - SSLEngine that unwraps data.536* @param unwrapper - Set unwrapper id, e.g. "server" of "client".537* Used for logging only.538* @param net - Buffer with data to unwrap.539* @param wantedStatus - Specifies expected result status of wrapping.540* @param result - Array which first element will be used to output541* wrap result object.542* @return - Buffer with unwrapped data.543* @throws SSLException - thrown on engine errors.544*/545public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,546ByteBuffer net, SSLEngineResult.Status wantedStatus,547SSLEngineResult[] result) throws SSLException {548549ByteBuffer app = ByteBuffer.allocate(550engine.getSession().getApplicationBufferSize());551int length = net.remaining();552System.out.println(unwrapper + " unwrapping " + length + " bytes...");553SSLEngineResult r = engine.unwrap(net, app);554app.flip();555System.out.println(unwrapper + " handshake status is "556+ engine.getHandshakeStatus() + " Result is " + r.getStatus());557checkResult(r, wantedStatus);558if (result != null && result.length > 0) {559result[0] = r;560}561return app;562}563564/**565* Does the handshake of the two specified engines according to the566* {@code mode} specified.567*568* @param clientEngine - Client SSLEngine.569* @param serverEngine - Server SSLEngine.570* @param maxPacketSize - Maximum packet size for MFLN of zero for no limit.571* @param mode - Handshake mode according to572* {@link HandshakeMode} enum.573* @throws SSLException - thrown on engine errors.574*/575public static void doHandshake(SSLEngine clientEngine,576SSLEngine serverEngine,577int maxPacketSize, HandshakeMode mode) throws SSLException {578579doHandshake(clientEngine, serverEngine, maxPacketSize, mode, false);580}581582/**583* Does the handshake of the two specified engines according to the584* {@code mode} specified.585*586* @param clientEngine - Client SSLEngine.587* @param serverEngine - Server SSLEngine.588* @param maxPacketSize - Maximum packet size for MFLN of zero589* for no limit.590* @param mode - Handshake mode according to591* {@link HandshakeMode} enum.592* @param enableReplicatedPacks - Set {@code true} to enable replicated593* packet sending.594* @throws SSLException - thrown on engine errors.595*/596public static void doHandshake(SSLEngine clientEngine,597SSLEngine serverEngine, int maxPacketSize,598HandshakeMode mode,599boolean enableReplicatedPacks) throws SSLException {600601System.out.println("=============================================");602System.out.println("Starting handshake " + mode.name());603int loop = 0;604if (maxPacketSize < 0) {605throw new Error("Test issue: maxPacketSize is less than zero!");606}607setMaxPacketSize(clientEngine, maxPacketSize);608setMaxPacketSize(serverEngine, maxPacketSize);609SSLEngine firstEngine;610SSLEngine secondEngine;611switch (mode) {612case INITIAL_HANDSHAKE:613firstEngine = clientEngine;614secondEngine = serverEngine;615doUnwrapForNotHandshakingStatus = false;616clientEngine.beginHandshake();617serverEngine.beginHandshake();618break;619case REHANDSHAKE_BEGIN_CLIENT:620firstEngine = clientEngine;621secondEngine = serverEngine;622doUnwrapForNotHandshakingStatus = true;623clientEngine.beginHandshake();624break;625case REHANDSHAKE_BEGIN_SERVER:626firstEngine = serverEngine;627secondEngine = clientEngine;628doUnwrapForNotHandshakingStatus = true;629serverEngine.beginHandshake();630break;631default:632throw new Error("Test issue: unknown handshake mode");633}634endHandshakeLoop = false;635while (!endHandshakeLoop) {636if (++loop > MAX_HANDSHAKE_LOOPS) {637throw new Error("Too much loops for handshaking");638}639System.out.println("============================================");640System.out.println("Handshake loop " + loop + ": round 1");641System.out.println("==========================");642handshakeProcess(firstEngine, secondEngine, maxPacketSize,643enableReplicatedPacks);644if (endHandshakeLoop) {645break;646}647System.out.println("Handshake loop " + loop + ": round 2");648System.out.println("==========================");649handshakeProcess(secondEngine, firstEngine, maxPacketSize,650enableReplicatedPacks);651}652}653654/**655* Routine to send application data from one SSLEngine to another.656*657* @param fromEngine - Sending engine.658* @param toEngine - Receiving engine.659* @return - Result of unwrap method of the receiving engine.660* @throws SSLException - thrown on engine errors.661*/662public static SSLEngineResult sendApplicationData(SSLEngine fromEngine,663SSLEngine toEngine)664throws SSLException {665String sender = null;666String reciever = null;667String excMsgSent = EXCHANGE_MSG_SENT;668if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) {669sender = "Client";670reciever = "Server";671excMsgSent += " Client.";672} else if (toEngine.getUseClientMode() &&673!fromEngine.getUseClientMode()) {674sender = "Server";675reciever = "Client";676excMsgSent += " Server.";677} else {678throw new Error("Test issue: both engines are in the same mode");679}680System.out.println("=============================================");681System.out.println("Trying to send application data from " + sender682+ " to " + reciever);683ByteBuffer clientAppSent684= ByteBuffer.wrap(excMsgSent.getBytes());685net = doWrap(fromEngine, sender, 0, clientAppSent);686SSLEngineResult[] r = new SSLEngineResult[1];687ByteBuffer serverAppRecv = doUnWrap(toEngine, reciever, net, r);688byte[] serverAppRecvTrunc = Arrays.copyOf(serverAppRecv.array(),689serverAppRecv.limit());690String msgRecv = new String(serverAppRecvTrunc);691if (!msgRecv.equals(excMsgSent)) {692throw new AssertionError(sender + " to " + reciever693+ ": application data"694+ " has been altered while sending."695+ " Message sent: " + "\"" + excMsgSent + "\"."696+ " Message recieved: " + "\"" + msgRecv + "\".");697}698System.out.println("Successful sending application data from " + sender699+ " to " + reciever);700return r[0];701}702703/**704* Close engines by sending "close outbound" message from one SSLEngine to705* another.706*707* @param fromEngine - Sending engine.708* @param toEngine - Receiving engine.709* @throws SSLException - thrown on engine errors.710*/711public static void closeEngines(SSLEngine fromEngine,712SSLEngine toEngine) throws SSLException {713String from = null;714String to = null;715ByteBuffer app;716if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) {717from = "Client";718to = "Server";719} else if (toEngine.getUseClientMode() &&720!fromEngine.getUseClientMode()) {721from = "Server";722to = "Client";723} else {724throw new Error("Both engines are in the same mode");725}726System.out.println("=============================================");727System.out.println(728"Trying to close engines from " + from + " to " + to);729// Sending close outbound request to peer730fromEngine.closeOutbound();731app = ByteBuffer.allocate(732fromEngine.getSession().getApplicationBufferSize());733net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);734doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);735app = ByteBuffer.allocate(736fromEngine.getSession().getApplicationBufferSize());737net = doWrap(toEngine, to, 0, app, SSLEngineResult.Status.CLOSED);738doUnWrap(fromEngine, from, net, SSLEngineResult.Status.CLOSED);739if (!toEngine.isInboundDone()) {740throw new AssertionError(from + " sent close request to " + to741+ ", but " + to + "did not close inbound.");742}743// Executing close inbound744fromEngine.closeInbound();745app = ByteBuffer.allocate(746fromEngine.getSession().getApplicationBufferSize());747net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);748doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);749if (!toEngine.isOutboundDone()) {750throw new AssertionError(from + "sent close request to " + to751+ ", but " + to + "did not close outbound.");752}753System.out.println("Successful closing from " + from + " to " + to);754}755756/**757* Runs the same test case for all given {@code ciphers}. Method counts all758* failures and throws {@code AssertionError} if one or more tests fail.759*760* @param ciphers - Ciphers that should be tested.761*/762public void runTests(Ciphers ciphers) {763int total = ciphers.ciphers.length;764int failed = testSomeCiphers(ciphers);765if (failed > 0) {766throw new AssertionError("" + failed + " of " + total767+ " tests failed!");768}769System.out.println("All tests passed!");770}771772/**773* Runs test cases for ciphers defined by the test mode.774*/775public void runTests() {776switch (TEST_MODE) {777case "norm":778case "norm_sni":779switch (TESTED_SECURITY_PROTOCOL) {780case "TLSv1":781case "TLSv1.1":782runTests(Ciphers.SUPPORTED_NON_KRB_NON_SHA_CIPHERS);783break;784case "TLSv1.2":785runTests(Ciphers.SUPPORTED_NON_KRB_CIPHERS);786break;787case "TLSv1.3":788runTests(Ciphers.TLS13_CIPHERS);789break;790}791break;792case "krb":793runTests(Ciphers.SUPPORTED_KRB_CIPHERS);794break;795default:796throw new Error(797"Test error: unexpected test mode: " + TEST_MODE);798}799}800801/**802* Returns maxPacketSize value used for MFLN extension testing803*804* @return - MLFN extension max packet size.805*/806public int getMaxPacketSize() {807return maxPacketSize;808}809810/**811* Checks that status of result {@code r} is {@code wantedStatus}.812*813* @param r - Result.814* @param wantedStatus - Wanted status of the result.815* @throws AssertionError - if status or {@code r} is not816* {@code wantedStatus}.817*/818public static void checkResult(SSLEngineResult r,819SSLEngineResult.Status wantedStatus) {820SSLEngineResult.Status rs = r.getStatus();821if (!rs.equals(wantedStatus)) {822throw new AssertionError("Unexpected status " + rs.name()823+ ", should be " + wantedStatus.name());824}825}826827/**828* Returns SSLContext with TESTED_SECURITY_PROTOCOL protocol and829* sets up keys.830*831* @return - SSLContext with a protocol specified by832* TESTED_SECURITY_PROTOCOL.833*/834public static SSLContext getContext() {835try {836java.security.Security.setProperty(837"jdk.tls.disabledAlgorithms", "");838java.security.Security.setProperty(839"jdk.certpath.disabledAlgorithms", "");840KeyStore ks = KeyStore.getInstance("JKS");841KeyStore ts = KeyStore.getInstance("JKS");842char[] passphrase = PASSWD.toCharArray();843try (FileInputStream keyFileStream =844new FileInputStream(KEY_FILE_NAME)) {845ks.load(keyFileStream, passphrase);846}847try (FileInputStream trustFileStream =848new FileInputStream(TRUST_FILE_NAME)) {849ts.load(trustFileStream, passphrase);850}851KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");852kmf.init(ks, passphrase);853TrustManagerFactory tmf =854TrustManagerFactory.getInstance("SunX509");855tmf.init(ts);856SSLContext sslCtx =857SSLContext.getInstance(TESTED_SECURITY_PROTOCOL);858sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);859return sslCtx;860} catch (KeyStoreException | IOException | NoSuchAlgorithmException |861CertificateException | UnrecoverableKeyException |862KeyManagementException ex) {863throw new Error("Unexpected exception", ex);864}865}866867/**868* Sets up and starts kerberos KDC server.869*/870public static void setUpAndStartKDC() {871String servicePrincipal = "host/" + SERVER_NAME + "@" + KRB_REALM;872Map<String, String> principals = new HashMap<>();873principals.put(KRB_USER_PRINCIPAL, KRB_USER_PASSWORD);874principals.put(KRBTGT_PRINCIPAL, null);875principals.put(servicePrincipal, null);876System.setProperty("java.security.krb5.conf", KRB5_CONF_FILENAME);877startKDC(KRB_REALM, principals, KTAB_FILENAME);878System.setProperty("java.security.auth.login.config",879TEST_SRC + FS + JAAS_CONF_FILE);880System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");881}882883/**884* Sets up and starts kerberos KDC server if885* SSLEngineTestCase.TEST_MODE is "krb".886*/887public static void setUpAndStartKDCIfNeeded() {888if (TEST_MODE.equals("krb")) {889setUpAndStartKDC();890}891}892893/**894* Returns client ssl engine.895*896* @param context - SSLContext to get SSLEngine from.897* @param useSNI - flag used to enable or disable using SNI extension.898* Needed for Kerberos.899*/900public static SSLEngine getClientSSLEngine(901SSLContext context, boolean useSNI) {902903SSLEngine clientEngine = context.createSSLEngine(HOST, 80);904clientEngine.setUseClientMode(true);905if (useSNI) {906SNIHostName serverName = new SNIHostName(SERVER_NAME);907List<SNIServerName> serverNames = new ArrayList<>();908serverNames.add(serverName);909SSLParameters params = clientEngine.getSSLParameters();910params.setServerNames(serverNames);911clientEngine.setSSLParameters(params);912}913return clientEngine;914}915916/**917* Returns server ssl engine.918*919* @param context - SSLContext to get SSLEngine from.920* @param useSNI - flag used to enable or disable using SNI extension.921* Needed for Kerberos.922*/923public static SSLEngine getServerSSLEngine(924SSLContext context, boolean useSNI) {925926SSLEngine serverEngine = context.createSSLEngine();927serverEngine.setUseClientMode(false);928if (useSNI) {929SNIMatcher matcher = SNIHostName.createSNIMatcher(SNI_PATTERN);930List<SNIMatcher> matchers = new ArrayList<>();931matchers.add(matcher);932SSLParameters params = serverEngine.getSSLParameters();933params.setSNIMatchers(matchers);934serverEngine.setSSLParameters(params);935}936return serverEngine;937}938939/**940* Runs the test case for one cipher suite.941*942* @param cipher - Cipher suite name.943* @throws SSLException - If tests fails.944*/945abstract protected void testOneCipher(String cipher)946throws SSLException;947948/**949* Iterates through an array of ciphers and runs the same test case for950* every entry.951*952* @param ciphers - Array of cipher names.953* @return - Number of tests failed.954*/955protected int testSomeCiphers(Ciphers ciphers) {956int failedNum = 0;957String description = ciphers.description;958System.out.println("===============================================");959System.out.println(description + " ciphers testing");960System.out.println("===========================================");961for (String cs : ciphers.ciphers) {962System.out.println("---------------------------------------");963System.out.println("Testing cipher suite " + cs);964System.out.println("---------------------------------------");965Throwable error = null;966967// Reset global mutable static variables968net = null;969doUnwrapForNotHandshakingStatus = false;970endHandshakeLoop = false;971972try {973testOneCipher(cs);974} catch (Throwable t) {975error = t;976}977switch (ciphers) {978case SUPPORTED_NON_KRB_CIPHERS:979case SUPPORTED_NON_KRB_NON_SHA_CIPHERS:980case SUPPORTED_KRB_CIPHERS:981case ENABLED_NON_KRB_NOT_ANON_CIPHERS:982case TLS13_CIPHERS:983if (error != null) {984System.out.println("Test Failed: " + cs);985System.err.println("Test Exception for " + cs);986error.printStackTrace();987failedNum++;988} else {989System.out.println("Test Passed: " + cs);990}991break;992case UNSUPPORTED_CIPHERS:993if (error == null) {994System.out.println("Test Failed: " + cs);995System.err.println("Test for " + cs +996" should have thrown " +997"IllegalArgumentException, but it has not!");998failedNum++;999} else if (!(error instanceof IllegalArgumentException)) {1000System.out.println("Test Failed: " + cs);1001System.err.println("Test Exception for " + cs);1002error.printStackTrace();1003failedNum++;1004} else {1005System.out.println("Test Passed: " + cs);1006}1007break;1008default:1009throw new Error("Test issue: unexpected ciphers: "1010+ ciphers.name());1011}1012}10131014return failedNum;1015}10161017/**1018* Method used for the handshake routine.1019*1020* @param wrapingEngine - Engine that is expected to wrap data.1021* @param unwrapingEngine - Engine that is expected to unwrap data.1022* @param maxPacketSize - Maximum packet size for MFLN of zero1023* for no limit.1024* @param enableReplicatedPacks - Set {@code true} to enable replicated1025* packet sending.1026* @throws SSLException - thrown on engine errors.1027*/1028private static void handshakeProcess(SSLEngine wrapingEngine,1029SSLEngine unwrapingEngine,1030int maxPacketSize,1031boolean enableReplicatedPacks) throws SSLException {10321033HandshakeStatus wrapingHSStatus = wrapingEngine.getHandshakeStatus();1034HandshakeStatus unwrapingHSStatus =1035unwrapingEngine.getHandshakeStatus();1036SSLEngineResult r;1037String wrapper, unwrapper;1038if (wrapingEngine.getUseClientMode()1039&& !unwrapingEngine.getUseClientMode()) {1040wrapper = "Client";1041unwrapper = "Server";1042} else if (unwrapingEngine.getUseClientMode()1043&& !wrapingEngine.getUseClientMode()) {1044wrapper = "Server";1045unwrapper = "Client";1046} else {1047throw new Error("Both engines are in the same mode");1048}1049System.out.println(1050wrapper + " handshake (wrap) status " + wrapingHSStatus);1051System.out.println(1052unwrapper + " handshake (unwrap) status " + unwrapingHSStatus);10531054ByteBuffer netReplicatedClient = null;1055ByteBuffer netReplicatedServer = null;1056switch (wrapingHSStatus) {1057case NEED_WRAP:1058if (enableReplicatedPacks) {1059if (net != null) {1060net.flip();1061if (net.remaining() != 0) {1062if (wrapingEngine.getUseClientMode()) {1063netReplicatedServer = net;1064} else {1065netReplicatedClient = net;1066}1067}1068}1069}1070ByteBuffer app = ByteBuffer.allocate(1071wrapingEngine.getSession().getApplicationBufferSize());1072net = doWrap(wrapingEngine, wrapper, maxPacketSize, app);1073wrapingHSStatus = wrapingEngine.getHandshakeStatus();1074// No break, falling into unwrapping.1075case NOT_HANDSHAKING:1076switch (unwrapingHSStatus) {1077case NEED_TASK:1078runDelegatedTasks(unwrapingEngine);1079case NEED_UNWRAP:1080doUnWrap(unwrapingEngine, unwrapper, net);1081if (enableReplicatedPacks) {1082System.out.println(unwrapper +1083" unwrapping replicated packet...");1084if (unwrapingEngine.getHandshakeStatus()1085.equals(HandshakeStatus.NEED_TASK)) {1086runDelegatedTasks(unwrapingEngine);1087}1088ByteBuffer netReplicated;1089if (unwrapingEngine.getUseClientMode()) {1090netReplicated = netReplicatedClient;1091} else {1092netReplicated = netReplicatedServer;1093}1094if (netReplicated != null) {1095doUnWrap(unwrapingEngine,1096unwrapper, netReplicated);1097} else {1098net.flip();1099doUnWrap(unwrapingEngine, unwrapper, net);1100}1101}1102break;1103case NOT_HANDSHAKING:1104if (doUnwrapForNotHandshakingStatus) {1105System.out.println("Not handshake status unwrap");1106doUnWrap(unwrapingEngine, unwrapper, net);1107doUnwrapForNotHandshakingStatus = false;1108break;1109} else {1110if (wrapingHSStatus ==1111HandshakeStatus.NOT_HANDSHAKING) {1112System.out.println("Handshake is completed");1113endHandshakeLoop = true;1114}1115}1116break;1117case NEED_WRAP:1118SSLSession session = unwrapingEngine.getSession();1119int bufferSize = session.getApplicationBufferSize();1120ByteBuffer b = ByteBuffer.allocate(bufferSize);1121net = doWrap(unwrapingEngine,1122unwrapper, maxPacketSize, b);1123unwrapingHSStatus =1124unwrapingEngine.getHandshakeStatus();1125if ((wrapingHSStatus ==1126HandshakeStatus.NOT_HANDSHAKING) &&1127(unwrapingHSStatus ==1128HandshakeStatus.NOT_HANDSHAKING)) {11291130System.out.println("Handshake is completed");1131endHandshakeLoop = true;1132}11331134break;1135default:1136throw new Error(1137"Unexpected unwraping engine handshake status "1138+ unwrapingHSStatus.name());1139}1140break;1141case NEED_UNWRAP:1142break;1143case NEED_TASK:1144runDelegatedTasks(wrapingEngine);1145break;1146default:1147throw new Error("Unexpected wraping engine handshake status "1148+ wrapingHSStatus.name());1149}1150}11511152private static void runDelegatedTasks(SSLEngine engine) {1153Runnable runnable;1154System.out.println("Running delegated tasks...");1155while ((runnable = engine.getDelegatedTask()) != null) {1156runnable.run();1157}1158HandshakeStatus hs = engine.getHandshakeStatus();1159if (hs == HandshakeStatus.NEED_TASK) {1160throw new Error("Handshake shouldn't need additional tasks.");1161}1162}11631164/**1165* Start a KDC server:1166* - create a KDC instance1167* - create Kerberos principals1168* - save Kerberos configuration1169* - save keys to keytab file1170* - no pre-auth is required1171*/1172private static void startKDC(String realm, Map<String, String> principals,1173String ktab) {1174try {1175KDC kdc = KDC.create(realm, HOST, 0, true);1176kdc.setOption(KDC.Option.PREAUTH_REQUIRED, Boolean.FALSE);1177if (principals != null) {1178principals.entrySet().stream().forEach((entry) -> {1179String name = entry.getKey();1180String password = entry.getValue();1181if (password == null || password.isEmpty()) {1182System.out.println("KDC: add a principal '" + name1183+ "' with a random password");1184kdc.addPrincipalRandKey(name);1185} else {1186System.out.println("KDC: add a principal '" + name1187+ "' with '" + password + "' password");1188kdc.addPrincipal(name, password.toCharArray());1189}1190});1191}1192KDC.saveConfig(KRB5_CONF_FILENAME, kdc);1193if (ktab != null) {1194File ktabFile = new File(ktab);1195if (ktabFile.exists()) {1196System.out.println("KDC: append keys to an exising "1197+ "keytab file " + ktab);1198kdc.appendKtab(ktab);1199} else {1200System.out.println("KDC: create a new keytab file "1201+ ktab);1202kdc.writeKtab(ktab);1203}1204}1205System.out.println("KDC: started on " + HOST + ":" + kdc.getPort()1206+ " with '" + realm + "' realm");1207} catch (Exception e) {1208throw new RuntimeException("KDC: unexpected exception", e);1209}1210}1211}121212131214