1 /*
   2  * Copyright (c) 2003, 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 7126889
  27  * @summary Incorrect SSLEngine debug output
  28  * @library /lib /lib/security
  29  * @run main DebugReportsOneExtraByte
  30  */
  31 /*
  32  * Debug output was reporting n+1 bytes of data was written when it was
  33  * really was n.
  34  *
  35  *     SunJSSE does not support dynamic system properties, no way to re-use
  36  *     system properties in samevm/agentvm mode.
  37  */
  38 
  39 /**
  40  * A SSLEngine usage example which simplifies the presentation
  41  * by removing the I/O and multi-threading concerns.
  42  *
  43  * The test creates two SSLEngines, simulating a client and server.
  44  * The "transport" layer consists two byte buffers:  think of them
  45  * as directly connected pipes.
  46  *
  47  * Note, this is a *very* simple example: real code will be much more
  48  * involved.  For example, different threading and I/O models could be
  49  * used, transport mechanisms could close unexpectedly, and so on.
  50  *
  51  * When this application runs, notice that several messages
  52  * (wrap/unwrap) pass before any application data is consumed or
  53  * produced.  (For more information, please see the SSL/TLS
  54  * specifications.)  There may several steps for a successful handshake,
  55  * so it's typical to see the following series of operations:
  56  *
  57  *      client          server          message
  58  *      ======          ======          =======
  59  *      wrap()          ...             ClientHello
  60  *      ...             unwrap()        ClientHello
  61  *      ...             wrap()          ServerHello/Certificate
  62  *      unwrap()        ...             ServerHello/Certificate
  63  *      wrap()          ...             ClientKeyExchange
  64  *      wrap()          ...             ChangeCipherSpec
  65  *      wrap()          ...             Finished
  66  *      ...             unwrap()        ClientKeyExchange
  67  *      ...             unwrap()        ChangeCipherSpec
  68  *      ...             unwrap()        Finished
  69  *      ...             wrap()          ChangeCipherSpec
  70  *      ...             wrap()          Finished
  71  *      unwrap()        ...             ChangeCipherSpec
  72  *      unwrap()        ...             Finished
  73  */
  74 
  75 import javax.net.ssl.*;
  76 import javax.net.ssl.SSLEngineResult.*;
  77 import java.io.*;
  78 import java.security.*;
  79 import java.nio.*;
  80 
  81 import jdk.test.lib.process.OutputAnalyzer;
  82 import jdk.test.lib.process.ProcessTools;
  83 
  84 public class DebugReportsOneExtraByte {
  85 
  86     /*
  87      * Enables logging of the SSLEngine operations.
  88      */
  89     private static boolean logging = true;
  90 
  91     private SSLContext sslc;
  92 
  93     private SSLEngine clientEngine;     // client Engine
  94     private ByteBuffer clientOut;       // write side of clientEngine
  95     private ByteBuffer clientIn;        // read side of clientEngine
  96 
  97     private SSLEngine serverEngine;     // server Engine
  98     private ByteBuffer serverOut;       // write side of serverEngine
  99     private ByteBuffer serverIn;        // read side of serverEngine
 100 
 101     /*
 102      * For data transport, this example uses local ByteBuffers.  This
 103      * isn't really useful, but the purpose of this example is to show
 104      * SSLEngine concepts, not how to do network transport.
 105      */
 106     private ByteBuffer cTOs;            // "reliable" transport client->server
 107     private ByteBuffer sTOc;            // "reliable" transport server->client
 108 
 109     /*
 110      * The following is to set up the keystores.
 111      */
 112     private static String pathToStores = "../../../../javax/net/ssl/etc";
 113     private static String keyStoreFile = "keystore";
 114     private static String trustStoreFile = "truststore";
 115     private static String passwd = "passphrase";
 116 
 117     private static String keyFilename =
 118             System.getProperty("test.src", ".") + "/" + pathToStores +
 119                 "/" + keyStoreFile;
 120     private static String trustFilename =
 121             System.getProperty("test.src", ".") + "/" + pathToStores +
 122                 "/" + trustStoreFile;
 123 
 124     /*
 125      * Main entry point for this test.
 126      */
 127     public static void main(String args[]) throws Exception {
 128 
 129         if (args.length == 0) {
 130             OutputAnalyzer output = ProcessTools.executeTestJvm(
 131                 "-Dtest.src=" + System.getProperty("test.src"),
 132                 "-Djavax.net.debug=all", "DebugReportsOneExtraByte", "p");
 133             output.shouldContain("WRITE: TLS10 application_data, length = 8");
 134 
 135             System.out.println("Test Passed.");
 136         } else {
 137             // Re-enable TLSv1 since test depends on it
 138             SecurityUtils.removeFromDisabledTlsAlgs("TLSv1");
 139 
 140             DebugReportsOneExtraByte test = new DebugReportsOneExtraByte();
 141             test.runTest();
 142         }
 143     }
 144 
 145     /*
 146      * Create an initialized SSLContext to use for these tests.
 147      */
 148     public DebugReportsOneExtraByte() throws Exception {
 149 
 150         KeyStore ks = KeyStore.getInstance("JKS");
 151         KeyStore ts = KeyStore.getInstance("JKS");
 152 
 153         char[] passphrase = "passphrase".toCharArray();
 154 
 155         ks.load(new FileInputStream(keyFilename), passphrase);
 156         ts.load(new FileInputStream(trustFilename), passphrase);
 157 
 158         KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
 159         kmf.init(ks, passphrase);
 160 
 161         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
 162         tmf.init(ts);
 163 
 164         SSLContext sslCtx = SSLContext.getInstance("TLSv1");
 165 
 166         sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 167 
 168         sslc = sslCtx;
 169     }
 170 
 171     /*
 172      * Run the test.
 173      *
 174      * Sit in a tight loop, both engines calling wrap/unwrap regardless
 175      * of whether data is available or not.  We do this until both engines
 176      * report back they are closed.
 177      *
 178      * The main loop handles all of the I/O phases of the SSLEngine's
 179      * lifetime:
 180      *
 181      *     initial handshaking
 182      *     application data transfer
 183      *     engine closing
 184      *
 185      * One could easily separate these phases into separate
 186      * sections of code.
 187      */
 188     private void runTest() throws Exception {
 189         boolean dataDone = false;
 190 
 191         createSSLEngines();
 192         createBuffers();
 193 
 194         SSLEngineResult clientResult;   // results from client's last operation
 195         SSLEngineResult serverResult;   // results from server's last operation
 196 
 197         /*
 198          * Examining the SSLEngineResults could be much more involved,
 199          * and may alter the overall flow of the application.
 200          *
 201          * For example, if we received a BUFFER_OVERFLOW when trying
 202          * to write to the output pipe, we could reallocate a larger
 203          * pipe, but instead we wait for the peer to drain it.
 204          */
 205 
 206         /*
 207          * Write one byte in first application packet, the rest
 208          * will come later.
 209          */
 210         serverOut.limit(1);
 211 
 212         while (!isEngineClosed(clientEngine) ||
 213                 !isEngineClosed(serverEngine)) {
 214 
 215             log("================");
 216 
 217             clientResult = clientEngine.wrap(clientOut, cTOs);
 218             log("client wrap: ", clientResult);
 219             runDelegatedTasks(clientResult, clientEngine);
 220 
 221             serverResult = serverEngine.wrap(serverOut, sTOc);
 222             log("server wrap: ", serverResult);
 223             runDelegatedTasks(serverResult, serverEngine);
 224 
 225             // Next wrap will split.
 226             if (serverOut.position() == 1) {
 227                 serverOut.limit(serverOut.capacity());
 228             }
 229 
 230             cTOs.flip();
 231             sTOc.flip();
 232 
 233             log("----");
 234 
 235             clientResult = clientEngine.unwrap(sTOc, clientIn);
 236             log("client unwrap: ", clientResult);
 237             runDelegatedTasks(clientResult, clientEngine);
 238 
 239             serverResult = serverEngine.unwrap(cTOs, serverIn);
 240             log("server unwrap: ", serverResult);
 241             runDelegatedTasks(serverResult, serverEngine);
 242 
 243             cTOs.compact();
 244             sTOc.compact();
 245 
 246             /*
 247              * After we've transfered all application data between the client
 248              * and server, we close the clientEngine's outbound stream.
 249              * This generates a close_notify handshake message, which the
 250              * server engine receives and responds by closing itself.
 251              */
 252             if (!dataDone && (clientOut.limit() == serverIn.position()) &&
 253                     (serverOut.limit() == clientIn.position())) {
 254 
 255                 /*
 256                  * A sanity check to ensure we got what was sent.
 257                  */
 258                 checkTransfer(serverOut, clientIn);
 259                 checkTransfer(clientOut, serverIn);
 260 
 261                 log("\tClosing clientEngine's *OUTBOUND*...");
 262                 clientEngine.closeOutbound();
 263                 dataDone = true;
 264             }
 265         }
 266     }
 267 
 268     /*
 269      * Using the SSLContext created during object creation,
 270      * create/configure the SSLEngines we'll use for this test.
 271      */
 272     private void createSSLEngines() throws Exception {
 273         /*
 274          * Configure the serverEngine to act as a server in the SSL/TLS
 275          * handshake.  Also, require SSL client authentication.
 276          */
 277         serverEngine = sslc.createSSLEngine();
 278         serverEngine.setUseClientMode(false);
 279         serverEngine.setNeedClientAuth(true);
 280 
 281         // Force a block-oriented ciphersuite.
 282         serverEngine.setEnabledCipherSuites(
 283             new String [] {"TLS_RSA_WITH_AES_128_CBC_SHA"});
 284 
 285         /*
 286          * Similar to above, but using client mode instead.
 287          */
 288         clientEngine = sslc.createSSLEngine("client", 80);
 289         clientEngine.setUseClientMode(true);
 290     }
 291 
 292     /*
 293      * Create and size the buffers appropriately.
 294      */
 295     private void createBuffers() {
 296 
 297         /*
 298          * We'll assume the buffer sizes are the same
 299          * between client and server.
 300          */
 301         SSLSession session = clientEngine.getSession();
 302         int appBufferMax = session.getApplicationBufferSize();
 303         int netBufferMax = session.getPacketBufferSize();
 304 
 305         /*
 306          * We'll make the input buffers a bit bigger than the max needed
 307          * size, so that unwrap()s following a successful data transfer
 308          * won't generate BUFFER_OVERFLOWS.
 309          *
 310          * We'll use a mix of direct and indirect ByteBuffers for
 311          * tutorial purposes only.  In reality, only use direct
 312          * ByteBuffers when they give a clear performance enhancement.
 313          */
 314         clientIn = ByteBuffer.allocate(appBufferMax + 50);
 315         serverIn = ByteBuffer.allocate(appBufferMax + 50);
 316 
 317         cTOs = ByteBuffer.allocateDirect(netBufferMax);
 318         sTOc = ByteBuffer.allocateDirect(netBufferMax);
 319 
 320         // No need to write anything on the client side, it will
 321         // just confuse the output.
 322         clientOut = ByteBuffer.wrap("".getBytes());
 323         // 10 bytes long
 324         serverOut = ByteBuffer.wrap("Hi Client!".getBytes());
 325     }
 326 
 327     /*
 328      * If the result indicates that we have outstanding tasks to do,
 329      * go ahead and run them in this thread.
 330      */
 331     private static void runDelegatedTasks(SSLEngineResult result,
 332             SSLEngine engine) throws Exception {
 333 
 334         if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
 335             Runnable runnable;
 336             while ((runnable = engine.getDelegatedTask()) != null) {
 337                 log("\trunning delegated task...");
 338                 runnable.run();
 339             }
 340             HandshakeStatus hsStatus = engine.getHandshakeStatus();
 341             if (hsStatus == HandshakeStatus.NEED_TASK) {
 342                 throw new Exception(
 343                     "handshake shouldn't need additional tasks");
 344             }
 345             log("\tnew HandshakeStatus: " + hsStatus);
 346         }
 347     }
 348 
 349     private static boolean isEngineClosed(SSLEngine engine) {
 350         return (engine.isOutboundDone() && engine.isInboundDone());
 351     }
 352 
 353     /*
 354      * Simple check to make sure everything came across as expected.
 355      */
 356     private static void checkTransfer(ByteBuffer a, ByteBuffer b)
 357             throws Exception {
 358         a.flip();
 359         b.flip();
 360 
 361         if (!a.equals(b)) {
 362             throw new Exception("Data didn't transfer cleanly");
 363         } else {
 364             log("\tData transferred cleanly");
 365         }
 366 
 367         a.position(a.limit());
 368         b.position(b.limit());
 369         a.limit(a.capacity());
 370         b.limit(b.capacity());
 371     }
 372 
 373     /*
 374      * Logging code
 375      */
 376     private static boolean resultOnce = true;
 377 
 378     private static void log(String str, SSLEngineResult result) {
 379         if (!logging) {
 380             return;
 381         }
 382         if (resultOnce) {
 383             resultOnce = false;
 384             System.out.println("The format of the SSLEngineResult is: \n" +
 385                 "\t\"getStatus() / getHandshakeStatus()\" +\n" +
 386                 "\t\"bytesConsumed() / bytesProduced()\"\n");
 387         }
 388         HandshakeStatus hsStatus = result.getHandshakeStatus();
 389         log(str +
 390             result.getStatus() + "/" + hsStatus + ", " +
 391             result.bytesConsumed() + "/" + result.bytesProduced() +
 392             " bytes");
 393         if (hsStatus == HandshakeStatus.FINISHED) {
 394             log("\t...ready for application data");
 395         }
 396     }
 397 
 398     private static void log(String str) {
 399         if (logging) {
 400             System.out.println(str);
 401         }
 402     }
 403 }