1 /* 2 * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 5019096 27 * @summary Add scatter/gather APIs for SSLEngine 28 * @library /test/lib 29 * @run main/othervm Arrays SSL 30 * @run main/othervm Arrays TLS 31 * @run main/othervm Arrays SSLv3 32 * @run main/othervm Arrays TLSv1 33 * @run main/othervm Arrays TLSv1.1 34 * @run main/othervm Arrays TLSv1.2 35 * @run main/othervm Arrays TLSv1.3 36 * @run main/othervm -Djdk.tls.acknowledgeCloseNotify=true Arrays TLSv1.3 37 */ 38 39 import javax.net.ssl.*; 40 import javax.net.ssl.SSLEngineResult.*; 41 import java.io.*; 42 import java.security.*; 43 import java.nio.*; 44 45 import jdk.test.lib.security.SecurityUtils; 46 47 public class Arrays { 48 49 private static boolean debug = false; 50 private static boolean acknowledgeCloseNotify = 51 "true".equals(System.getProperty("jdk.tls.acknowledgeCloseNotify")); 52 53 private SSLContext sslc; 54 private SSLEngine ssle1; // client 55 private SSLEngine ssle2; // server 56 57 private static String pathToStores = "../etc"; 58 private static String keyStoreFile = "keystore"; 59 private static String trustStoreFile = "truststore"; 60 private static String passwd = "passphrase"; 61 62 private static String keyFilename = 63 System.getProperty("test.src", "./") + "/" + pathToStores + 64 "/" + keyStoreFile; 65 private static String trustFilename = 66 System.getProperty("test.src", "./") + "/" + pathToStores + 67 "/" + trustStoreFile; 68 69 private ByteBuffer [] appOutArray1; 70 private ByteBuffer [] appInArray1; 71 72 private ByteBuffer appOut2; // write side of ssle2 73 private ByteBuffer appIn2; // read side of ssle2 74 75 private ByteBuffer oneToTwo; // "reliable" transport ssle1->ssle2 76 private ByteBuffer twoToOne; // "reliable" transport ssle2->ssle1 77 78 /* 79 * Majority of the test case is here, setup is done below. 80 */ createSSLEngines()81 private void createSSLEngines() throws Exception { 82 ssle1 = sslc.createSSLEngine("client", 1); 83 ssle1.setUseClientMode(true); 84 85 ssle2 = sslc.createSSLEngine(); 86 ssle2.setUseClientMode(false); 87 ssle2.setNeedClientAuth(true); 88 } 89 runTest()90 private void runTest() throws Exception { 91 boolean dataDone = false; 92 93 createSSLEngines(); 94 createBuffers(); 95 96 SSLEngineResult result1; // ssle1's results from last operation 97 SSLEngineResult result2; // ssle2's results from last operation 98 99 while (!isEngineClosed(ssle1) || !isEngineClosed(ssle2)) { 100 101 log("================"); 102 103 result1 = ssle1.wrap(appOutArray1, oneToTwo); 104 result2 = ssle2.wrap(appOut2, twoToOne); 105 106 log("wrap1: " + result1); 107 log("oneToTwo = " + oneToTwo); 108 log(""); 109 110 log("wrap2: " + result2); 111 log("twoToOne = " + twoToOne); 112 113 runDelegatedTasks(result1, ssle1); 114 runDelegatedTasks(result2, ssle2); 115 116 oneToTwo.flip(); 117 twoToOne.flip(); 118 119 log("----"); 120 121 result1 = ssle1.unwrap(twoToOne, appInArray1); 122 result2 = ssle2.unwrap(oneToTwo, appIn2); 123 124 log("unwrap1: " + result1); 125 log("twoToOne = " + twoToOne); 126 log(""); 127 128 log("unwrap2: " + result2); 129 log("oneToTwo = " + oneToTwo); 130 131 runDelegatedTasks(result1, ssle1); 132 runDelegatedTasks(result2, ssle2); 133 134 oneToTwo.compact(); 135 twoToOne.compact(); 136 137 /* 138 * If we've transfered all the data between app1 and app2, 139 * we try to close and see what that gets us. 140 */ 141 if (!dataDone) { 142 boolean done = true; 143 144 for (int i = 0; i < appOutArray1.length; i++) { 145 if (appOutArray1[i].remaining() != 0) { 146 log("1st out not done"); 147 done = false; 148 } 149 } 150 151 if (appOut2.remaining() != 0) { 152 log("2nd out not done"); 153 done = false; 154 } 155 156 if (done) { 157 log("Closing ssle1's *OUTBOUND*..."); 158 for (int i = 0; i < appOutArray1.length; i++) { 159 appOutArray1[i].rewind(); 160 } 161 ssle1.closeOutbound(); 162 String protocol = ssle2.getSession().getProtocol(); 163 if (!acknowledgeCloseNotify) { 164 switch (ssle2.getSession().getProtocol()) { 165 case "SSLv3": 166 case "TLSv1": 167 case "TLSv1.1": 168 case "TLSv1.2": 169 break; 170 default: // TLSv1.3 171 // TLS 1.3, half-close only. 172 ssle2.closeOutbound(); 173 } 174 } 175 dataDone = true; 176 } 177 } 178 } 179 checkTransfer(appOutArray1, appIn2); 180 appInArray1[appInArray1.length - 1].limit( 181 appInArray1[appInArray1.length - 1].position()); 182 checkTransfer(appInArray1, appOut2); 183 } 184 185 private static String contextVersion; main(String args[])186 public static void main(String args[]) throws Exception { 187 contextVersion = args[0]; 188 // Re-enable context version if it is disabled. 189 // If context version is SSLv3, TLSv1 needs to be re-enabled. 190 if (contextVersion.equals("SSLv3")) { 191 SecurityUtils.removeFromDisabledTlsAlgs("TLSv1"); 192 } else if (contextVersion.equals("TLSv1") || 193 contextVersion.equals("TLSv1.1")) { 194 SecurityUtils.removeFromDisabledTlsAlgs(contextVersion); 195 } 196 197 Arrays test; 198 199 test = new Arrays(); 200 201 test.createSSLEngines(); 202 203 test.runTest(); 204 205 System.err.println("Test Passed."); 206 } 207 208 /* 209 * ********************************************************** 210 * Majority of the test case is above, below is just setup stuff 211 * ********************************************************** 212 */ 213 Arrays()214 public Arrays() throws Exception { 215 sslc = getSSLContext(keyFilename, trustFilename); 216 } 217 218 /* 219 * Create an initialized SSLContext to use for this test. 220 */ getSSLContext(String keyFile, String trustFile)221 private SSLContext getSSLContext(String keyFile, String trustFile) 222 throws Exception { 223 224 KeyStore ks = KeyStore.getInstance("JKS"); 225 KeyStore ts = KeyStore.getInstance("JKS"); 226 227 char[] passphrase = "passphrase".toCharArray(); 228 229 ks.load(new FileInputStream(keyFile), passphrase); 230 ts.load(new FileInputStream(trustFile), passphrase); 231 232 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 233 kmf.init(ks, passphrase); 234 235 TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 236 tmf.init(ts); 237 238 SSLContext sslCtx = SSLContext.getInstance(contextVersion); 239 240 sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 241 242 return sslCtx; 243 } 244 createBuffers()245 private void createBuffers() { 246 // Size the buffers as appropriate. 247 248 SSLSession session = ssle1.getSession(); 249 int appBufferMax = session.getApplicationBufferSize(); 250 int netBufferMax = session.getPacketBufferSize(); 251 252 appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50); 253 254 oneToTwo = ByteBuffer.allocateDirect(netBufferMax); 255 twoToOne = ByteBuffer.allocateDirect(netBufferMax); 256 257 ByteBuffer strBB = ByteBuffer.wrap( 258 "Hi Engine2, I'm SSLEngine1, So Be it" .getBytes()); 259 260 strBB.position(0); 261 strBB.limit(5); 262 ByteBuffer appOut1a = strBB.slice(); 263 264 strBB.position(5); 265 strBB.limit(15); 266 ByteBuffer appOut1b = strBB.slice(); 267 268 strBB.position(15); 269 strBB.limit(strBB.capacity()); 270 ByteBuffer appOut1c = strBB.slice(); 271 272 strBB.rewind(); 273 274 appOutArray1 = new ByteBuffer [] { appOut1a, appOut1b, appOut1c }; 275 276 appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes()); 277 278 ByteBuffer appIn1a = ByteBuffer.allocateDirect(5); 279 ByteBuffer appIn1b = ByteBuffer.allocateDirect(10); 280 ByteBuffer appIn1c = ByteBuffer.allocateDirect(appBufferMax + 50); 281 appInArray1 = new ByteBuffer [] { appIn1a, appIn1b, appIn1c }; 282 283 log("AppOut1a = " + appOut1a); 284 log("AppOut1a = " + appOut1b); 285 log("AppOut1a = " + appOut1c); 286 log("AppOut2 = " + appOut2); 287 log(""); 288 } 289 runDelegatedTasks(SSLEngineResult result, SSLEngine engine)290 private static void runDelegatedTasks(SSLEngineResult result, 291 SSLEngine engine) throws Exception { 292 293 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { 294 Runnable runnable; 295 while ((runnable = engine.getDelegatedTask()) != null) { 296 log("running delegated task..."); 297 runnable.run(); 298 } 299 } 300 } 301 isEngineClosed(SSLEngine engine)302 private static boolean isEngineClosed(SSLEngine engine) { 303 return (engine.isOutboundDone() && engine.isInboundDone()); 304 } 305 checkTransfer(ByteBuffer [] a, ByteBuffer b)306 private static void checkTransfer(ByteBuffer [] a, ByteBuffer b) 307 throws Exception { 308 309 b.flip(); 310 311 for (int i = 0; i < a.length; i++) { 312 a[i].rewind(); 313 314 b.limit(b.position() + a[i].remaining()); 315 316 if (!a[i].equals(b)) { 317 throw new Exception("Data didn't transfer cleanly"); 318 } 319 320 b.position(b.limit()); 321 } 322 323 log("Data transferred cleanly"); 324 } 325 log(String str)326 private static void log(String str) { 327 if (debug) { 328 System.err.println(str); 329 } 330 } 331 } 332