diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java b/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java index f759aac5479..43bac16f0ea 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,8 +122,11 @@ final class CertificateAuthoritiesExtension { return authorities; } + // This method will throw IllegalArgumentException if the + // X500Principal cannot be parsed. X500Principal[] getAuthorities() { X500Principal[] principals = new X500Principal[authorities.size()]; + int i = 0; for (byte[] encoded : authorities) { principals[i++] = new X500Principal(encoded); @@ -138,8 +141,12 @@ final class CertificateAuthoritiesExtension { "\"certificate authorities\": '['\n{0}']'", Locale.ENGLISH); StringBuilder builder = new StringBuilder(512); for (byte[] encoded : authorities) { - X500Principal principal = new X500Principal(encoded); - builder.append(principal.toString()); + try { + X500Principal principal = new X500Principal(encoded); + builder.append(principal.toString()); + } catch (IllegalArgumentException iae) { + builder.append("unparseable distinguished name: " + iae); + } builder.append("\n"); } Object[] messageFields = { @@ -277,7 +284,13 @@ final class CertificateAuthoritiesExtension { new CertificateAuthoritiesSpec(shc, buffer); // Update the context. - shc.peerSupportedAuthorities = spec.getAuthorities(); + try { + shc.peerSupportedAuthorities = spec.getAuthorities(); + } catch (IllegalArgumentException iae) { + shc.conContext.fatal(Alert.DECODE_ERROR, "The distinguished " + + "names of the peer's certificate authorities could " + + "not be parsed", iae); + } shc.handshakeExtensions.put( SSLExtension.CH_CERTIFICATE_AUTHORITIES, spec); @@ -398,7 +411,13 @@ final class CertificateAuthoritiesExtension { new CertificateAuthoritiesSpec(chc, buffer); // Update the context. - chc.peerSupportedAuthorities = spec.getAuthorities(); + try { + chc.peerSupportedAuthorities = spec.getAuthorities(); + } catch (IllegalArgumentException iae) { + chc.conContext.fatal(Alert.DECODE_ERROR, "The distinguished " + + "names of the peer's certificate authorities could " + + "not be parsed", iae); + } chc.handshakeExtensions.put( SSLExtension.CR_CERTIFICATE_AUTHORITIES, spec); diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index 5c96bfcd5d6..63e0ec158be 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -198,9 +198,12 @@ final class CertificateRequest { return ClientCertificateType.getKeyTypes(types); } + // This method will throw IllegalArgumentException if the + // X500Principal cannot be parsed. X500Principal[] getAuthorities() { X500Principal[] principals = new X500Principal[authorities.size()]; int i = 0; + for (byte[] encoded : authorities) { principals[i++] = new X500Principal(encoded); } @@ -254,8 +257,12 @@ final class CertificateRequest { List authorityNames = new ArrayList<>(authorities.size()); for (byte[] encoded : authorities) { - X500Principal principal = new X500Principal(encoded); - authorityNames.add(principal.toString()); + try { + X500Principal principal = new X500Principal(encoded); + authorityNames.add(principal.toString()); + } catch (IllegalArgumentException iae) { + authorityNames.add("unparseable distinguished name: " + iae); + } } Object[] messageFields = { typeNames, @@ -370,12 +377,23 @@ final class CertificateRequest { X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager(); String clientAlias = null; - if (chc.conContext.transport instanceof SSLSocketImpl) { - clientAlias = km.chooseClientAlias(crm.getKeyTypes(), - crm.getAuthorities(), (SSLSocket)chc.conContext.transport); - } else if (chc.conContext.transport instanceof SSLEngineImpl) { - clientAlias = km.chooseEngineClientAlias(crm.getKeyTypes(), - crm.getAuthorities(), (SSLEngine)chc.conContext.transport); + + try { + if (chc.conContext.transport instanceof SSLSocketImpl) { + clientAlias = km.chooseClientAlias(crm.getKeyTypes(), + crm.getAuthorities(), + (SSLSocket) chc.conContext.transport); + } else if (chc.conContext.transport instanceof SSLEngineImpl) { + clientAlias = + km.chooseEngineClientAlias(crm.getKeyTypes(), + crm.getAuthorities(), + (SSLEngine) chc.conContext.transport); + } + } catch (IllegalArgumentException iae) { + chc.conContext.fatal(Alert.DECODE_ERROR, + "The distinguished names of the peer's " + + "certificate authorities could not be parsed", + iae); } @@ -512,9 +530,12 @@ final class CertificateRequest { return ClientCertificateType.getKeyTypes(types); } + // This method will throw IllegalArgumentException if the + // X500Principal cannot be parsed. X500Principal[] getAuthorities() { X500Principal[] principals = new X500Principal[authorities.size()]; int i = 0; + for (byte[] encoded : authorities) { principals[i++] = new X500Principal(encoded); } @@ -579,8 +600,13 @@ final class CertificateRequest { List authorityNames = new ArrayList<>(authorities.size()); for (byte[] encoded : authorities) { - X500Principal principal = new X500Principal(encoded); - authorityNames.add(principal.toString()); + try { + X500Principal principal = new X500Principal(encoded); + authorityNames.add(principal.toString()); + } catch (IllegalArgumentException iae) { + authorityNames.add("unparseable distinguished name: " + + iae); + } } Object[] messageFields = { typeNames, @@ -717,8 +743,13 @@ final class CertificateRequest { chc.peerRequestedSignatureSchemes = sss; chc.peerRequestedCertSignSchemes = sss; // use the same schemes chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); - chc.peerSupportedAuthorities = crm.getAuthorities(); - + try { + chc.peerSupportedAuthorities = crm.getAuthorities(); + } catch (IllegalArgumentException iae) { + chc.conContext.fatal(Alert.DECODE_ERROR, "The " + + "distinguished names of the peer's certificate " + + "authorities could not be parsed", iae); + } // For TLS 1.2, we no longer use the certificate_types field // from the CertificateRequest message to directly determine // the SSLPossession. Instead, the choosePossession method diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA.java b/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA.java new file mode 100644 index 00000000000..06e2aa94b35 --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8294985 + * @library /test/lib + * @summary SSLEngine throws IAE during parsing of X500Principal + * @run main/othervm TestBadDNForPeerCA + * @run main/othervm -Djavax.net.debug=all TestBadDNForPeerCA + */ + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManagerFactory; +import java.io.FileInputStream; +import java.nio.ByteBuffer; +import java.security.KeyStore; +import java.util.Base64; + + +public class TestBadDNForPeerCA { + + private static final String proto = "TLSv1.3"; + + private final SSLContext sslc; + + private SSLEngine serverEngine; // server Engine + private ByteBuffer serverIn; // read side of serverEngine + + private ByteBuffer cTOs; // "reliable" transport client->server + + private static final String keyStoreFile = + System.getProperty("test.src", "./") + + "/../../../../javax/net/ssl/etc/keystore"; + + // the following ClientHello contains a certificate with an + // invalid/unparseable distinguished name + private static final byte[] payload = Base64.getDecoder().decode( + "FgMDAcsBAAHHAwPbDfeUCIStPzVIfXuGgCu56dSJOJ6xeus1W44frG5tciDEcBfYt" + + "/PN/6MFCGojEVcmPw21mVyjYInMo0UozIn4NwBiEwITARMDwCzAK8ypwDDMqMAvA" + + "J/MqgCjAJ4AosAkwCjAI8AnAGsAagBnAEDALsAywC3AMcAmCgAFKsApJcDAFMAJw" + + "BMAOQA4ADMAMsAFwA/ABMAOAJ0AnAA9ADwANgAvAP8BAAEcAAUABQEAAAAAAAoAF" + + "gAUAB0AFwAYABkAHgEAAQEBAgEDAQQACwACAQAAEQAJAAcCAAQAAAAAABcAAAAjA" + + "AAADQAsACoEAwUDBgMIBwgICAQIBQgGCAkICggLBAEFAQYBBAIDAwMBAwICAwIBA" + + "gIAKwAFBAMEAwMALQACAQEAMgAsACoEAwUDBgMIBwgICAQIBQgGCAkICggLBAEFA" + + "QYBBAIDAwMBAwICAwIBAgIALwBrAGkAHQAAAAARACAAZMUAADkwsiaOwcsWAwAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAtAAAAAAAAAAEAADAAAAA="); + + /* + * The following is to set up the keystores. + */ + private static final String passwd = "passphrase"; + + /* + * Main entry point for this demo. + */ + public static void main(String[] args) throws Exception { + + TestBadDNForPeerCA test = new TestBadDNForPeerCA(); + + try { + test.runTest(); + throw new Exception( + "TEST FAILED: Didn't generate any exception"); + } catch (SSLHandshakeException she) { + System.out.println("TEST PASSED: Caught expected exception"); + } + } + + /* + * Create an initialized SSLContext to use for this demo. + */ + + public TestBadDNForPeerCA() throws Exception { + + KeyStore ks = KeyStore.getInstance("JKS"); + KeyStore ts = KeyStore.getInstance("JKS"); + + char[] passphrase = passwd.toCharArray(); + + ks.load(new FileInputStream(keyStoreFile), passphrase); + ts.load(new FileInputStream(keyStoreFile), passphrase); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(ts); + + SSLContext sslCtx = SSLContext.getInstance(proto); + + sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + sslc = sslCtx; + } + + + private void runTest() throws Exception { + + createSSLEngines(); + createBuffers(); + + cTOs = ByteBuffer.wrap(payload); + + System.out.println("injecting client hello"); + + for (int i = 0; i < 10; i++) { //retry if survived + SSLEngineResult serverResult = serverEngine.unwrap(cTOs, serverIn); + System.out.println("server unwrap: " + serverResult); + runDelegatedTasks(serverResult, serverEngine); + } + } + + private void createSSLEngines() throws Exception { + + serverEngine = sslc.createSSLEngine(); + serverEngine.setUseClientMode(false); + serverEngine.setNeedClientAuth(true); + + } + + + private void createBuffers() { + + serverIn = ByteBuffer.allocateDirect(65536); + + cTOs = ByteBuffer.allocateDirect(65536); + + } + + private static void runDelegatedTasks(SSLEngineResult result, + SSLEngine engine) throws Exception { + + if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = engine.getDelegatedTask()) != null) { + System.out.println("\trunning delegated task..."); + runnable.run(); + } + + HandshakeStatus hsStatus = engine.getHandshakeStatus(); + if (hsStatus == HandshakeStatus.NEED_TASK) { + throw new Exception("handshake shouldn't need additional " + + "tasks"); + } + System.out.println("\tnew HandshakeStatus: " + hsStatus); + } + } + + +} diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA12.java b/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA12.java new file mode 100644 index 00000000000..701620a7502 --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA12.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8294985 + * @library /test/lib + * @summary SSLEngine throws IAE during parsing of X500Principal + * @run main/othervm TestBadDNForPeerCA12 + * @run main/othervm -Djavax.net.debug=all TestBadDNForPeerCA12 + */ + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManagerFactory; +import java.io.FileInputStream; +import java.nio.ByteBuffer; +import java.security.KeyStore; +import java.util.Base64; + +public class TestBadDNForPeerCA12 { + + // Test was originally written for TLSv1.2 + private static final String proto = "TLSv1.2"; + + private final SSLContext sslc; + + protected SSLEngine clientEngine; // client Engine + protected SSLEngine serverEngine; // server Engine + protected ByteBuffer clientOut; // write side of clientEngine + protected ByteBuffer serverOut; // write side of serverEngine + protected ByteBuffer clientIn; // read side of clientEngine + protected ByteBuffer serverIn; // read side of serverEngine + private ByteBuffer cTOs; // "reliable" transport client->server + protected ByteBuffer sTOc; // "reliable" transport server->client + + private static final String keyStoreFile = + System.getProperty("test.src", "./") + + "/../../../../javax/net/ssl/etc/keystore"; + + // this contains a server response with invalid DNs + private static final byte[] serverPayload = Base64.getDecoder().decode( + "FgMDBhICAABVAwPORrwPxSL0DOnCC+cCvQcXxeU1ugjN5XyT0r9qOrlT0iD4I0BgFq" + + "2Hbt7a9cGreNkhniEEhgQIuxa2Ur21VJr9/AA1AAANABcAAAAjAAD/AQABAAsAA1UAA1" + + "IAA08wggNLMIICMwIEVzmbhzANBgkqhkiG9w0BAQsFADBqMQswCQYDVQQGEwJVUzELMA" + + "kGA1UECAwCQ0ExEjAQBgNVBAcMCUN1cGVydGlubzEOMAwGA1UECgwFRHVtbXkxDjAMBg" + + "NVBAsMBUR1bW15MRowGAYDVQQDDBFkdW1teS5leGFtcGxlLmNvbTAeFw0xNjA1MTYxMD" + + "A2MzhaFw0yNjA1MTYxMDA2MzhaMGoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMB" + + "AGA1UEBwwJQ3VwZXJ0aW5vMQ4wDAYDVQQKDAVEdW1teTEOMAwGA1UECwwFRHVtbXkxGj" + + "AYBgNVBAMMEWR1bW15LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMI" + + "IBCgKCAQEAyRtAPlvIbvGfI5ZXN4jBu0dU96b8smVcAdxYnDPylnvmsYGdmYC2C6ddT7" + + "7I9Nlk6BhNmkz6pCGsXLZnUOL+9XOGVWlw5kHDVEGUjeza5BhpZW0G0q00QthZcRuF/F" + + "UkUGzmUuaxgm59VqwxP7dfMERG4gRRXjclMpLm23CShWBhFfooOsiPSFgDtmY4H/LkTU" + + "EbaYuxKRfRKhMKm6GBjCVY7iS9iga728dJ+6BTNAGpKITXI35B+Xf7vpTbc+Zub9vL2f" + + "czcChQvGTZedCaAFi3NWJXR/UTeuv/vte8jJ1YscHSSi2k0P5k3gi9PCmve/sjLrBuh+" + + "D466e/B/swowIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBZFaKJtN/1RkCVev7ZmYEwww" + + "42kE5RpJt7Es2zoxqEGaNx0TA5D6XnEB1XjFUQOgOG7SbUl4NfLpJejuZiQzaX27+7Pu" + + "1FK24SIz61sINpyVtb8flA52mIjH26HzpwSAGmTjFQ7m9Josj/25IqAaRM0AWuPLcwTf" + + "B9zRx3me1LxxrzGhtyZDn1Jhlv0aLS79g33Kuj1HAYMvw7UGan372ufmGiv+g5UYeVvP" + + "Yw3jeahJkSIh96Bb05aJpaogaoE5e+gQanR7E36WGGaicjfN1gIHSOyzZBibcTUhaplS" + + "Q06DfK6UjGmHcVi8X5wD+9NWWiGrlUHcOwKueQOaptTaaXDQACWANAAQIAKgQDBQMGAw" + + "gHCAgIBAgFCAYICQgKCAsEAQUBBgEEAgMDAwEDAgIDAgECAgImAGwwajELMAkRA1UEBh" + + "MCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlDdXBlcnRpbm8xDjAMBgNVBAoTBUR1bW" + + "15MQ4wDAYDVQQLEwVEdW1teTEaMBgGA1UEAxMRZHVtbXkuZXhhbXBsZS5jb20AbDBqMQ" + + "swCREDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCUN1cGVydGlubzEOMAwGA1" + + "UECgwFRHVtbXkxDjAMBgNVBAsMBUR1bW15MRowGAYDVQQDDBFkdW1teS5leGFtcGxlLm" + + "NvbQBsMGoxCzAJEQNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJQ3VwZXJ0aW" + + "5vMQ4wDAYDVQQKDAVEdW1teTEOMAwGA1UECwwFRHVtbXkxGjAYBgNVBAMMEWR1bW15Lm" + + "V4YW1wbGUuY29tAGwwajELMAkRA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEw" + + "lDdXBlcnRpbm8xDjAMBgNVBAoTBUR1bW15MQ4wDAYDVQQLEwVEdW1teTEaMBgGA1UEAx" + + "MRZHVtbXkuZXhhbXBsZS5jb20AbDBqMQswCREDVQQGEwJVUzELMAkGA1UECBMCQ0ExEj" + + "AQBgNVBAcTCUN1cGVydGlubzEOMAwGA1UEChMFRHVtbXkxDjAMBgNVBAsTBUR1bW15MR" + + "owGAYDVQQDExFkdW1teS5leGFtcGxlLmNvbQ4AAAA=" + ); + + /* + * The following is to set up the keystores. + */ + private static final String passwd = "passphrase"; + + /* + * Main entry point for this demo. + */ + public static void main(String[] args) throws Exception { + + TestBadDNForPeerCA12 test = new TestBadDNForPeerCA12(); + + try { + test.runTest(); + throw new Exception( + "TEST FAILED: Didn't generate any exception"); + } catch (SSLHandshakeException she) { + System.out.println("TEST PASSED: Caught expected exception"); + } + } + + /* + * Create an initialized SSLContext to use for this demo. + */ + + public TestBadDNForPeerCA12() throws Exception { + + KeyStore ks = KeyStore.getInstance("JKS"); + KeyStore ts = KeyStore.getInstance("JKS"); + + char[] passphrase = passwd.toCharArray(); + + ks.load(new FileInputStream(keyStoreFile), passphrase); + ts.load(new FileInputStream(keyStoreFile), passphrase); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(ts); + + SSLContext sslCtx = SSLContext.getInstance(proto); + + sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + sslc = sslCtx; + } + + + private void runTest() throws Exception { + + createSSLEngines(); + createBuffers(); + + /* + * the following was used to generate the serverPayload value + */ + // ignore output + /*SSLEngineResult clientResult = clientEngine.wrap(clientOut, cTOs); + runDelegatedTasks(clientResult, clientEngine); + cTOs.flip(); + + // ignore output + SSLEngineResult serverResult = serverEngine.unwrap(cTOs, serverIn); + runDelegatedTasks(serverResult, serverEngine); + // server hello, cert material, etc + SSLEngineResult serverWrapResult = serverEngine.wrap(serverOut, sTOc); + runDelegatedTasks(serverWrapResult, serverEngine); + sTOc.flip(); + ByteBuffer sTOcBuff = sTOc.asReadOnlyBuffer(); + byte[] serverContents = new byte[sTOcBuff.remaining()]; + sTOcBuff.get(serverContents); + System.out.println("sw: " + Base64.getEncoder().encodeToString + (serverContents));*/ + + System.out.println("sending client hello"); + SSLEngineResult clientResult = clientEngine.wrap(clientOut, cTOs); + runDelegatedTasks(clientResult, clientEngine); + + cTOs.flip(); + + sTOc = ByteBuffer.wrap(serverPayload); + + SSLEngineResult clientHelloResult = clientEngine.unwrap(sTOc, clientIn); + System.out.println("client unwrap: " + clientHelloResult); + runDelegatedTasks(clientHelloResult, clientEngine); + + SSLEngineResult clientExGen = clientEngine.wrap(clientIn, cTOs); + runDelegatedTasks(clientExGen, clientEngine); + + } + + private void createSSLEngines() { + clientEngine = sslc.createSSLEngine(); + clientEngine.setEnabledProtocols(new String[] {proto}); + clientEngine.setUseClientMode(true); + clientEngine.setEnabledCipherSuites(new String[] + {"TLS_RSA_WITH_AES_256_CBC_SHA"}); + + serverEngine = sslc.createSSLEngine(); + serverEngine.setEnabledProtocols(new String[] {proto}); + serverEngine.setUseClientMode(false); + serverEngine.setNeedClientAuth(true); + serverEngine.setEnabledCipherSuites(new String[] + {"TLS_RSA_WITH_AES_256_CBC_SHA"}); + } + + private void createBuffers() { + cTOs = ByteBuffer.allocateDirect(65536); + + clientIn = ByteBuffer.allocateDirect(65536); + + clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); + + sTOc = ByteBuffer.allocateDirect(65536); + + serverOut = ByteBuffer.wrap("Hi Client, I'm Server".getBytes()); + + serverIn = ByteBuffer.allocateDirect(65536); + } + + private static void runDelegatedTasks(SSLEngineResult result, + SSLEngine engine) throws Exception { + + if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = engine.getDelegatedTask()) != null) { + System.out.println("\trunning delegated task..."); + runnable.run(); + } + + HandshakeStatus hsStatus = engine.getHandshakeStatus(); + if (hsStatus == HandshakeStatus.NEED_TASK) { + throw new Exception("handshake shouldn't need additional " + + "tasks"); + } + System.out.println("\tnew HandshakeStatus: " + hsStatus); + } + } +}