1 /* 2 * Copyright (c) 2004, 2007, 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 * @run main/othervm Arrays SSL 29 * @run main/othervm Arrays TLS 30 * @run main/othervm Arrays SSLv3 31 * @run main/othervm Arrays TLSv1 32 * @run main/othervm Arrays TLSv1.1 33 * @run main/othervm Arrays TLSv1.2 34 * @run main/othervm Arrays TLSv1.3 35 * @run main/othervm -Djdk.tls.acknowledgeCloseNotify=true Arrays TLSv1.3 36 */ 37 38 import javax.net.ssl.*; 39 import javax.net.ssl.SSLEngineResult.*; 40 import java.io.*; 41 import java.security.*; 42 import java.nio.*; 43 44 public class Arrays { 45 46 private static boolean debug = false; 47 private static boolean acknowledgeCloseNotify = 48 "true".equals(System.getProperty("jdk.tls.acknowledgeCloseNotify")); 49 50 private SSLContext sslc; 51 private SSLEngine ssle1; // client 52 private SSLEngine ssle2; // server 53 54 private static String pathToStores = "../etc"; 55 private static String keyStoreFile = "keystore"; 56 private static String trustStoreFile = "truststore"; 57 private static String passwd = "passphrase"; 58 59 private static String keyFilename = 60 System.getProperty("test.src", "./") + "/" + pathToStores + 61 "/" + keyStoreFile; 62 private static String trustFilename = 63 System.getProperty("test.src", "./") + "/" + pathToStores + 64 "/" + trustStoreFile; 65 66 private ByteBuffer [] appOutArray1; 67 private ByteBuffer [] appInArray1; 68 69 private ByteBuffer appOut2; // write side of ssle2 70 private ByteBuffer appIn2; // read side of ssle2 71 72 private ByteBuffer oneToTwo; // "reliable" transport ssle1->ssle2 73 private ByteBuffer twoToOne; // "reliable" transport ssle2->ssle1 74 75 /* 76 * Majority of the test case is here, setup is done below. 77 */ 78 private void createSSLEngines() throws Exception { 79 ssle1 = sslc.createSSLEngine("client", 1); 80 ssle1.setUseClientMode(true); 81 82 ssle2 = sslc.createSSLEngine(); 83 ssle2.setUseClientMode(false); 84 ssle2.setNeedClientAuth(true); 85 } 86 87 private void runTest() throws Exception { 88 boolean dataDone = false; 89 90 createSSLEngines(); 91 createBuffers(); 92 93 SSLEngineResult result1; // ssle1's results from last operation 94 SSLEngineResult result2; // ssle2's results from last operation 95 96 while (!isEngineClosed(ssle1) || !isEngineClosed(ssle2)) { 97 98 log("================"); 99 100 result1 = ssle1.wrap(appOutArray1, oneToTwo); 101 result2 = ssle2.wrap(appOut2, twoToOne); 102 103 log("wrap1: " + result1); 104 log("oneToTwo = " + oneToTwo); 105 log(""); 106 107 log("wrap2: " + result2); 108 log("twoToOne = " + twoToOne); 109 110 runDelegatedTasks(result1, ssle1); 111 runDelegatedTasks(result2, ssle2); 112 113 oneToTwo.flip(); 114 twoToOne.flip(); 115 116 log("----"); 117 118 result1 = ssle1.unwrap(twoToOne, appInArray1); 119 result2 = ssle2.unwrap(oneToTwo, appIn2); 120 121 log("unwrap1: " + result1); 122 log("twoToOne = " + twoToOne); 123 log(""); 124 125 log("unwrap2: " + result2); 126 log("oneToTwo = " + oneToTwo); 127 128 runDelegatedTasks(result1, ssle1); 129 runDelegatedTasks(result2, ssle2); 130 131 oneToTwo.compact(); 132 twoToOne.compact(); 133 134 /* 135 * If we've transfered all the data between app1 and app2, 136 * we try to close and see what that gets us. 137 */ 138 if (!dataDone) { 139 boolean done = true; 140 141 for (int i = 0; i < appOutArray1.length; i++) { 142 if (appOutArray1[i].remaining() != 0) { 143 log("1st out not done"); 144 done = false; 145 } 146 } 147 148 if (appOut2.remaining() != 0) { 149 log("2nd out not done"); 150 done = false; 151 } 152 153 if (done) { 154 log("Closing ssle1's *OUTBOUND*..."); 155 for (int i = 0; i < appOutArray1.length; i++) { 156 appOutArray1[i].rewind(); 157 } 158 ssle1.closeOutbound(); 159 String protocol = ssle2.getSession().getProtocol(); 160 if (!acknowledgeCloseNotify) { 161 switch (ssle2.getSession().getProtocol()) { 162 case "SSLv3": 163 case "TLSv1": 164 case "TLSv1.1": 165 case "TLSv1.2": 166 break; 167 default: // TLSv1.3 168 // TLS 1.3, half-close only. 169 ssle2.closeOutbound(); 170 } 171 } 172 dataDone = true; 173 } 174 } 175 } 176 checkTransfer(appOutArray1, appIn2); 177 appInArray1[appInArray1.length - 1].limit( 178 appInArray1[appInArray1.length - 1].position()); 179 checkTransfer(appInArray1, appOut2); 180 } 181 182 private static String contextVersion; 183 public static void main(String args[]) throws Exception { 184 contextVersion = args[0]; 185 186 Arrays test; 187 188 test = new Arrays(); 189 190 test.createSSLEngines(); 191 192 test.runTest(); 193 194 System.err.println("Test Passed."); 195 } 196 197 /* 198 * ********************************************************** 199 * Majority of the test case is above, below is just setup stuff 200 * ********************************************************** 201 */ 202 203 public Arrays() throws Exception { 204 sslc = getSSLContext(keyFilename, trustFilename); 205 } 206 207 /* 208 * Create an initialized SSLContext to use for this test. 209 */ 210 private SSLContext getSSLContext(String keyFile, String trustFile) 211 throws Exception { 212 213 KeyStore ks = KeyStore.getInstance("JKS"); 214 KeyStore ts = KeyStore.getInstance("JKS"); 215 216 char[] passphrase = "passphrase".toCharArray(); 217 218 ks.load(new FileInputStream(keyFile), passphrase); 219 ts.load(new FileInputStream(trustFile), passphrase); 220 221 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 222 kmf.init(ks, passphrase); 223 224 TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 225 tmf.init(ts); 226 227 SSLContext sslCtx = SSLContext.getInstance(contextVersion); 228 229 sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 230 231 return sslCtx; 232 } 233 234 private void createBuffers() { 235 // Size the buffers as appropriate. 236 237 SSLSession session = ssle1.getSession(); 238 int appBufferMax = session.getApplicationBufferSize(); 239 int netBufferMax = session.getPacketBufferSize(); 240 241 appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50); 242 243 oneToTwo = ByteBuffer.allocateDirect(netBufferMax); 244 twoToOne = ByteBuffer.allocateDirect(netBufferMax); 245 246 ByteBuffer strBB = ByteBuffer.wrap( 247 "Hi Engine2, I'm SSLEngine1, So Be it" .getBytes()); 248 249 strBB.position(0); 250 strBB.limit(5); 251 ByteBuffer appOut1a = strBB.slice(); 252 253 strBB.position(5); 254 strBB.limit(15); 255 ByteBuffer appOut1b = strBB.slice(); 256 257 strBB.position(15); 258 strBB.limit(strBB.capacity()); 259 ByteBuffer appOut1c = strBB.slice(); 260 261 strBB.rewind(); 262 263 appOutArray1 = new ByteBuffer [] { appOut1a, appOut1b, appOut1c }; 264 265 appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes()); 266 267 ByteBuffer appIn1a = ByteBuffer.allocateDirect(5); 268 ByteBuffer appIn1b = ByteBuffer.allocateDirect(10); 269 ByteBuffer appIn1c = ByteBuffer.allocateDirect(appBufferMax + 50); 270 appInArray1 = new ByteBuffer [] { appIn1a, appIn1b, appIn1c }; 271 272 log("AppOut1a = " + appOut1a); 273 log("AppOut1a = " + appOut1b); 274 log("AppOut1a = " + appOut1c); 275 log("AppOut2 = " + appOut2); 276 log(""); 277 } 278 279 private static void runDelegatedTasks(SSLEngineResult result, 280 SSLEngine engine) throws Exception { 281 282 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { 283 Runnable runnable; 284 while ((runnable = engine.getDelegatedTask()) != null) { 285 log("running delegated task..."); 286 runnable.run(); 287 } 288 } 289 } 290 291 private static boolean isEngineClosed(SSLEngine engine) { 292 return (engine.isOutboundDone() && engine.isInboundDone()); 293 } 294 295 private static void checkTransfer(ByteBuffer [] a, ByteBuffer b) 296 throws Exception { 297 298 b.flip(); 299 300 for (int i = 0; i < a.length; i++) { 301 a[i].rewind(); 302 303 b.limit(b.position() + a[i].remaining()); 304 305 if (!a[i].equals(b)) { 306 throw new Exception("Data didn't transfer cleanly"); 307 } 308 309 b.position(b.limit()); 310 } 311 312 log("Data transferred cleanly"); 313 } 314 315 private static void log(String str) { 316 if (debug) { 317 System.err.println(str); 318 } 319 } 320 }