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