1 /* 2 * Copyright (c) 2018, 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 8164879 27 * @library /lib/testlibrary ../../ 28 * @summary Verify AES/GCM's limits set in the jdk.tls.keyLimits property 29 * start a new handshake sequence to renegotiate the symmetric key with an 30 * SSLSocket connection. This test verifies the handshake method was called 31 * via debugging info. It does not verify the renegotiation was successful 32 * as that is very hard. 33 * 34 * @run main SSLEngineKeyLimit 0 server AES/GCM/NoPadding keyupdate 1050000 35 * @run main SSLEngineKeyLimit 1 client AES/GCM/NoPadding keyupdate 2^22 36 */ 37 38 /* 39 * This test runs in another process so we can monitor the debug 40 * results. The OutputAnalyzer must see correct debug output to return a 41 * success. 42 */ 43 44 import javax.net.ssl.KeyManagerFactory; 45 import javax.net.ssl.SSLContext; 46 import javax.net.ssl.SSLEngine; 47 import javax.net.ssl.SSLEngineResult; 48 import javax.net.ssl.TrustManagerFactory; 49 import java.io.File; 50 import java.io.PrintWriter; 51 import java.nio.ByteBuffer; 52 import java.security.KeyStore; 53 import java.security.SecureRandom; 54 import java.util.Arrays; 55 56 import jdk.testlibrary.ProcessTools; 57 import jdk.testlibrary.Utils; 58 import jdk.testlibrary.OutputAnalyzer; 59 60 public class SSLEngineKeyLimit { 61 62 SSLEngine eng; 63 static ByteBuffer cTos; 64 static ByteBuffer sToc; 65 static ByteBuffer outdata; 66 ByteBuffer buf; 67 static boolean ready = false; 68 69 static String pathToStores = "../../../../javax/net/ssl/etc/"; 70 static String keyStoreFile = "keystore"; 71 static String trustStoreFile = "truststore"; 72 static String passwd = "passphrase"; 73 static String keyFilename; 74 static int dataLen = 10240; 75 static boolean serverwrite = true; 76 int totalDataLen = 0; 77 static boolean sc = true; 78 static boolean debug = false; 79 int delay = 1; 80 81 SSLEngineKeyLimit() { 82 buf = ByteBuffer.allocate(dataLen*4); 83 } 84 85 /** 86 * args should have two values: server|client, <limit size> 87 * Prepending 'p' is for internal use only. 88 */ 89 public static void main(String args[]) throws Exception { 90 91 for (int i = 0; i < args.length; i++) { 92 System.out.print(" " + args[i]); 93 } 94 System.out.println(); 95 if (args[0].compareTo("p") != 0) { 96 boolean expectedFail = (Integer.parseInt(args[0]) == 1); 97 if (expectedFail) { 98 System.out.println("Test expected to not find updated msg"); 99 } 100 101 // Write security property file to overwrite default 102 File f = new File("keyusage."+ System.nanoTime()); 103 PrintWriter p = new PrintWriter(f); 104 p.write("jdk.tls.keyLimits="); 105 for (int i = 2; i < args.length; i++) { 106 p.write(" "+ args[i]); 107 } 108 p.close(); 109 110 System.setProperty("test.java.opts", 111 "-Dtest.src=" + System.getProperty("test.src") + 112 " -Dtest.jdk=" + System.getProperty("test.jdk") + 113 " -Djavax.net.debug=ssl" + 114 " -Djava.security.properties=" + f.getName()); 115 116 System.out.println("test.java.opts: " + 117 System.getProperty("test.java.opts")); 118 119 ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, 120 Utils.addTestJavaOpts("SSLEngineKeyLimit", "p", args[1])); 121 122 OutputAnalyzer output = ProcessTools.executeProcess(pb); 123 try { 124 if (expectedFail) { 125 output.shouldNotContain("KeyUpdate: write key updated"); 126 output.shouldNotContain("KeyUpdate: read key updated"); 127 } else { 128 output.shouldContain("KeyUpdate: write key updated"); 129 output.shouldContain("KeyUpdate: read key updated"); 130 } 131 } catch (Exception e) { 132 throw e; 133 } finally { 134 System.out.println("-- BEGIN Stdout:"); 135 System.out.println(output.getStdout()); 136 System.out.println("-- END Stdout"); 137 System.out.println("-- BEGIN Stderr:"); 138 System.out.println(output.getStderr()); 139 System.out.println("-- END Stderr"); 140 } 141 return; 142 } 143 144 if (args[0].compareTo("p") != 0) { 145 throw new Exception ("Tried to run outside of a spawned process"); 146 } 147 148 if (args[1].compareTo("client") == 0) { 149 serverwrite = false; 150 } 151 152 cTos = ByteBuffer.allocateDirect(dataLen*4); 153 keyFilename = 154 System.getProperty("test.src", "./") + "/" + pathToStores + 155 "/" + keyStoreFile; 156 157 System.setProperty("javax.net.ssl.keyStore", keyFilename); 158 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 159 160 sToc = ByteBuffer.allocateDirect(dataLen*4); 161 outdata = ByteBuffer.allocateDirect(dataLen); 162 163 byte[] data = new byte[dataLen]; 164 Arrays.fill(data, (byte)0x0A); 165 outdata.put(data); 166 outdata.flip(); 167 cTos.clear(); 168 sToc.clear(); 169 170 Thread ts = new Thread(serverwrite ? new Client() : new Server()); 171 ts.start(); 172 (serverwrite ? new Server() : new Client()).run(); 173 ts.interrupt(); 174 ts.join(); 175 } 176 177 private static void doTask(SSLEngineResult result, 178 SSLEngine engine) throws Exception { 179 180 if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) { 181 Runnable runnable; 182 while ((runnable = engine.getDelegatedTask()) != null) { 183 System.out.println("\trunning delegated task..."); 184 runnable.run(); 185 } 186 SSLEngineResult.HandshakeStatus hsStatus = engine.getHandshakeStatus(); 187 if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) { 188 throw new Exception( 189 "handshake shouldn't need additional tasks"); 190 } 191 print("\tnew HandshakeStatus: " + hsStatus); 192 } 193 } 194 195 static void print(String s) { 196 if (debug) { 197 System.out.println(s); 198 } 199 } 200 201 static void log(String s, SSLEngineResult r) { 202 if (!debug) { 203 return; 204 } 205 System.out.println(s + ": " + 206 r.getStatus() + "/" + r.getHandshakeStatus()+ " " + 207 r.bytesConsumed() + "/" + r.bytesProduced() + " "); 208 209 } 210 211 void write() throws Exception { 212 int i = 0; 213 SSLEngineResult r; 214 boolean again = true; 215 216 while (!ready) { 217 Thread.sleep(delay); 218 } 219 print("Write-side. "); 220 221 while (i++ < 120) { 222 while (sc) { 223 Thread.sleep(delay); 224 } 225 226 outdata.rewind(); 227 print("write wrap"); 228 229 while (true) { 230 r = eng.wrap(outdata, getWriteBuf()); 231 log("write wrap", r); 232 if (debug && r.getStatus() != SSLEngineResult.Status.OK) { 233 System.out.println("outdata pos: " + outdata.position() + 234 " rem: " + outdata.remaining() + 235 " lim: " + outdata.limit() + 236 " cap: " + outdata.capacity()); 237 System.out.println("writebuf pos: " + getWriteBuf().position() + 238 " rem: " + getWriteBuf().remaining() + 239 " lim: " + getWriteBuf().limit() + 240 " cap: " + getWriteBuf().capacity()); 241 } 242 if (again && r.getStatus() == SSLEngineResult.Status.OK && 243 r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP) { 244 print("again"); 245 again = false; 246 continue; 247 } 248 break; 249 } 250 doTask(r, eng); 251 getWriteBuf().flip(); 252 sc = true; 253 while (sc) { 254 Thread.sleep(delay); 255 } 256 257 while (true) { 258 buf.clear(); 259 r = eng.unwrap(getReadBuf(), buf); 260 log("write unwrap", r); 261 if (debug && r.getStatus() != SSLEngineResult.Status.OK) { 262 System.out.println("buf pos: " + buf.position() + 263 " rem: " + buf.remaining() + 264 " lim: " + buf.limit() + 265 " cap: " + buf.capacity()); 266 System.out.println("readbuf pos: " + getReadBuf().position() + 267 " rem: " + getReadBuf().remaining() + 268 " lim: " + getReadBuf().limit() + 269 " cap:" + getReadBuf().capacity()); 270 } 271 break; 272 } 273 doTask(r, eng); 274 getReadBuf().compact(); 275 print("compacted readbuf pos: " + getReadBuf().position() + 276 " rem: " + getReadBuf().remaining() + 277 " lim: " + getReadBuf().limit() + 278 " cap: " + getReadBuf().capacity()); 279 sc = true; 280 } 281 } 282 283 void read() throws Exception { 284 byte b = 0x0B; 285 ByteBuffer buf2 = ByteBuffer.allocateDirect(dataLen); 286 SSLEngineResult r = null; 287 boolean exit, again = true; 288 289 while (eng == null) { 290 Thread.sleep(delay); 291 } 292 293 try { 294 System.out.println("connected"); 295 print("entering read loop"); 296 ready = true; 297 while (true) { 298 299 while (!sc) { 300 Thread.sleep(delay); 301 } 302 303 print("read wrap"); 304 exit = false; 305 while (!exit) { 306 buf2.put(b); 307 buf2.flip(); 308 r = eng.wrap(buf2, getWriteBuf()); 309 log("read wrap", r); 310 if (debug ) { //&& r.getStatus() != SSLEngineResult.Status.OK) { 311 System.out.println("buf2 pos: " + buf2.position() + 312 " rem: " + buf2.remaining() + 313 " cap: " + buf2.capacity()); 314 System.out.println("writebuf pos: " + getWriteBuf().position() + 315 " rem: " + getWriteBuf().remaining() + 316 " cap: " + getWriteBuf().capacity()); 317 } 318 if (again && r.getStatus() == SSLEngineResult.Status.OK && 319 r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP) { 320 buf2.compact(); 321 again = false; 322 continue; 323 } 324 exit = true; 325 } 326 doTask(r, eng); 327 buf2.clear(); 328 getWriteBuf().flip(); 329 330 sc = false; 331 332 while (!sc) { 333 Thread.sleep(delay); 334 } 335 336 while (true) { 337 buf.clear(); 338 r = eng.unwrap(getReadBuf(), buf); 339 log("read unwrap", r); 340 if (debug && r.getStatus() != SSLEngineResult.Status.OK) { 341 System.out.println("buf pos " + buf.position() + 342 " rem: " + buf.remaining() + 343 " lim: " + buf.limit() + 344 " cap: " + buf.capacity()); 345 System.out.println("readbuf pos: " + getReadBuf().position() + 346 " rem: " + getReadBuf().remaining() + 347 " lim: " + getReadBuf().limit() + 348 " cap: " + getReadBuf().capacity()); 349 doTask(r, eng); 350 } 351 352 if (again && r.getStatus() == SSLEngineResult.Status.OK && 353 r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) { 354 buf.clear(); 355 print("again"); 356 again = false; 357 continue; 358 359 } 360 break; 361 } 362 buf.clear(); 363 getReadBuf().compact(); 364 365 totalDataLen += r.bytesProduced(); 366 sc = false; 367 } 368 } catch (Exception e) { 369 System.out.println(e.getMessage()); 370 e.printStackTrace(); 371 } 372 print("TotalDataLen = " + totalDataLen); 373 } 374 375 ByteBuffer getReadBuf() { 376 return null; 377 } 378 379 ByteBuffer getWriteBuf() { 380 return null; 381 } 382 383 384 SSLContext initContext() throws Exception { 385 SSLContext sc = SSLContext.getInstance("TLSv1.3"); 386 KeyStore ks = KeyStore.getInstance( 387 new File(System.getProperty("javax.net.ssl.keyStore")), 388 passwd.toCharArray()); 389 KeyManagerFactory kmf = 390 KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 391 kmf.init(ks, passwd.toCharArray()); 392 TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 393 tmf.init(ks); 394 sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); 395 return sc; 396 } 397 398 static class Server extends SSLEngineKeyLimit implements Runnable { 399 Server() throws Exception { 400 super(); 401 eng = initContext().createSSLEngine(); 402 eng.setUseClientMode(false); 403 eng.setNeedClientAuth(true); 404 } 405 406 public void run() { 407 try { 408 if (serverwrite) { 409 write(); 410 } else { 411 read(); 412 } 413 414 } catch (Exception e) { 415 System.out.println("server: " + e.getMessage()); 416 e.printStackTrace(); 417 } 418 System.out.println("Server closed"); 419 } 420 421 @Override 422 ByteBuffer getWriteBuf() { 423 return sToc; 424 } 425 @Override 426 ByteBuffer getReadBuf() { 427 return cTos; 428 } 429 } 430 431 432 static class Client extends SSLEngineKeyLimit implements Runnable { 433 Client() throws Exception { 434 super(); 435 eng = initContext().createSSLEngine("client", 80); 436 eng.setUseClientMode(true); 437 } 438 439 public void run() { 440 try { 441 if (!serverwrite) { 442 write(); 443 } else { 444 read(); 445 } 446 } catch (Exception e) { 447 System.out.println("client: " + e.getMessage()); 448 e.printStackTrace(); 449 } 450 } 451 @Override 452 ByteBuffer getWriteBuf() { 453 return cTos; 454 } 455 @Override 456 ByteBuffer getReadBuf() { 457 return sToc; 458 } 459 } 460 }