1/*
2 * Copyright (c) 2011, 2016, 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// SunJSSE does not support dynamic system properties, no way to re-use
26// system properties in samevm/agentvm mode.
27//
28
29/*
30 * @test
31 * @bug 7031830
32 * @summary bad_record_mac failure on TLSv1.2 enabled connection with SSLEngine
33 * @run main/othervm SSLEngineBadBufferArrayAccess
34 */
35
36/**
37 * A SSLSocket/SSLEngine interop test case.  This is not the way to
38 * code SSLEngine-based servers, but works for what we need to do here,
39 * which is to make sure that SSLEngine/SSLSockets can talk to each other.
40 * SSLEngines can use direct or indirect buffers, and different code
41 * is used to get at the buffer contents internally, so we test that here.
42 *
43 * The test creates one SSLSocket (client) and one SSLEngine (server).
44 * The SSLSocket talks to a raw ServerSocket, and the server code
45 * does the translation between byte [] and ByteBuffers that the SSLEngine
46 * can use.  The "transport" layer consists of a Socket Input/OutputStream
47 * and two byte buffers for the SSLEngines:  think of them
48 * as directly connected pipes.
49 *
50 * Again, this is a *very* simple example: real code will be much more
51 * involved.  For example, different threading and I/O models could be
52 * used, transport mechanisms could close unexpectedly, and so on.
53 *
54 * When this application runs, notice that several messages
55 * (wrap/unwrap) pass before any application data is consumed or
56 * produced.  (For more information, please see the SSL/TLS
57 * specifications.)  There may several steps for a successful handshake,
58 * so it's typical to see the following series of operations:
59 *
60 *      client          server          message
61 *      ======          ======          =======
62 *      write()         ...             ClientHello
63 *      ...             unwrap()        ClientHello
64 *      ...             wrap()          ServerHello/Certificate
65 *      read()         ...             ServerHello/Certificate
66 *      write()         ...             ClientKeyExchange
67 *      write()         ...             ChangeCipherSpec
68 *      write()         ...             Finished
69 *      ...             unwrap()        ClientKeyExchange
70 *      ...             unwrap()        ChangeCipherSpec
71 *      ...             unwrap()        Finished
72 *      ...             wrap()          ChangeCipherSpec
73 *      ...             wrap()          Finished
74 *      read()          ...             ChangeCipherSpec
75 *      read()          ...             Finished
76 *
77 * This particular bug had a problem where byte buffers backed by an
78 * array didn't offset correctly, and we got bad MAC errors.
79 */
80import javax.net.ssl.*;
81import javax.net.ssl.SSLEngineResult.*;
82import java.io.*;
83import java.net.*;
84import java.security.*;
85import java.nio.*;
86import java.util.concurrent.CountDownLatch;
87import java.util.concurrent.TimeUnit;
88
89public class SSLEngineBadBufferArrayAccess {
90
91    /*
92     * Enables logging of the SSL/TLS operations.
93     */
94    private static boolean logging = true;
95
96    /*
97     * Enables the JSSE system debugging system property:
98     *
99     *     -Djavax.net.debug=all
100     *
101     * This gives a lot of low-level information about operations underway,
102     * including specific handshake messages, and might be best examined
103     * after gaining some familiarity with this application.
104     */
105    private static boolean debug = false;
106    private SSLContext sslc;
107    private SSLEngine serverEngine;     // server-side SSLEngine
108
109    private final byte[] serverMsg = "Hi there Client, I'm a Server".getBytes();
110    private final byte[] clientMsg = "Hello Server, I'm a Client".getBytes();
111
112    private ByteBuffer serverOut;       // write side of serverEngine
113    private ByteBuffer serverIn;        // read side of serverEngine
114
115    private volatile Exception clientException;
116    private volatile Exception serverException;
117
118    /*
119     * For data transport, this example uses local ByteBuffers.
120     */
121    private ByteBuffer cTOs;            // "reliable" transport client->server
122    private ByteBuffer sTOc;            // "reliable" transport server->client
123
124    /*
125     * The following is to set up the keystores/trust material.
126     */
127    private static final String pathToStores = "../../../../javax/net/ssl/etc";
128    private static final String keyStoreFile = "keystore";
129    private static final String trustStoreFile = "truststore";
130    private static final String passwd = "passphrase";
131    private static String keyFilename =
132            System.getProperty("test.src", ".") + "/" + pathToStores
133            + "/" + keyStoreFile;
134    private static String trustFilename =
135            System.getProperty("test.src", ".") + "/" + pathToStores
136            + "/" + trustStoreFile;
137
138    /*
139     * Is the server ready to serve?
140     */
141    private static final CountDownLatch serverCondition = new CountDownLatch(1);
142
143    /*
144     * Is the client ready to handshake?
145     */
146    private static final CountDownLatch clientCondition = new CountDownLatch(1);
147
148    /*
149     * What's the server port?  Use any free port by default
150     */
151    private volatile int serverPort = 0;
152
153    /*
154     * Main entry point for this test.
155     */
156    public static void main(String args[]) throws Exception {
157        if (debug) {
158            System.setProperty("javax.net.debug", "all");
159        }
160
161        String [] protocols = new String [] {
162            "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" };
163
164        for (String protocol : protocols) {
165            /*
166             * Run the tests with direct and indirect buffers.
167             */
168            log("Testing " + protocol + ":true");
169            new SSLEngineBadBufferArrayAccess(protocol).runTest(true);
170
171            log("Testing " + protocol + ":false");
172            new SSLEngineBadBufferArrayAccess(protocol).runTest(false);
173        }
174
175        System.out.println("Test Passed.");
176    }
177
178    /*
179     * Create an initialized SSLContext to use for these tests.
180     */
181    public SSLEngineBadBufferArrayAccess(String protocol) throws Exception {
182
183        KeyStore ks = KeyStore.getInstance("JKS");
184        KeyStore ts = KeyStore.getInstance("JKS");
185
186        char[] passphrase = "passphrase".toCharArray();
187
188        try (FileInputStream fis = new FileInputStream(keyFilename)) {
189            ks.load(fis, passphrase);
190        }
191
192        try (FileInputStream fis = new FileInputStream(trustFilename)) {
193            ts.load(fis, passphrase);
194        }
195
196        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
197        kmf.init(ks, passphrase);
198
199        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
200        tmf.init(ts);
201
202        SSLContext sslCtx = SSLContext.getInstance(protocol);
203
204        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
205
206        sslc = sslCtx;
207    }
208
209    /*
210     * Run the test.
211     *
212     * Sit in a tight loop, with the server engine calling wrap/unwrap
213     * regardless of whether data is available or not.  We do this until
214     * we get the application data.  Then we shutdown and go to the next one.
215     *
216     * The main loop handles all of the I/O phases of the SSLEngine's
217     * lifetime:
218     *
219     *     initial handshaking
220     *     application data transfer
221     *     engine closing
222     *
223     * One could easily separate these phases into separate
224     * sections of code.
225     */
226    private void runTest(boolean direct) throws Exception {
227        boolean serverClose = direct;
228
229        ServerSocket serverSocket = new ServerSocket(0);
230        serverPort = serverSocket.getLocalPort();
231
232        // Signal the client, the server is ready to accept connection.
233        serverCondition.countDown();
234
235        Thread clientThread = runClient(serverClose);
236
237        // Try to accept a connection in 30 seconds.
238        Socket socket;
239        try {
240            serverSocket.setSoTimeout(30000);
241            socket = (Socket) serverSocket.accept();
242        } catch (SocketTimeoutException ste) {
243            serverSocket.close();
244
245            // Ignore the test case if no connection within 30 seconds.
246            System.out.println(
247                "No incoming client connection in 30 seconds. " +
248                "Ignore in server side.");
249            return;
250        }
251
252        // handle the connection
253        try {
254            // Is it the expected client connection?
255            //
256            // Naughty test cases or third party routines may try to
257            // connection to this server port unintentionally.  In
258            // order to mitigate the impact of unexpected client
259            // connections and avoid intermittent failure, it should
260            // be checked that the accepted connection is really linked
261            // to the expected client.
262            boolean clientIsReady =
263                    clientCondition.await(30L, TimeUnit.SECONDS);
264
265            if (clientIsReady) {
266                // Run the application in server side.
267                runServerApplication(socket, direct, serverClose);
268            } else {    // Otherwise, ignore
269                // We don't actually care about plain socket connections
270                // for TLS communication testing generally.  Just ignore
271                // the test if the accepted connection is not linked to
272                // the expected client or the client connection timeout
273                // in 30 seconds.
274                System.out.println(
275                        "The client is not the expected one or timeout. " +
276                        "Ignore in server side.");
277            }
278        } catch (Exception e) {
279            System.out.println("Server died ...");
280            e.printStackTrace(System.out);
281            serverException = e;
282        } finally {
283            socket.close();
284            serverSocket.close();
285        }
286
287        clientThread.join();
288
289        if (clientException != null || serverException != null) {
290            throw new RuntimeException("Test failed");
291        }
292    }
293
294    /*
295     * Define the server side application of the test for the specified socket.
296     */
297    void runServerApplication(Socket socket, boolean direct,
298            boolean serverClose) throws Exception {
299
300        socket.setSoTimeout(500);
301
302        createSSLEngine();
303        createBuffers(direct);
304
305        boolean closed = false;
306
307        InputStream is = socket.getInputStream();
308        OutputStream os = socket.getOutputStream();
309
310        SSLEngineResult serverResult;   // results from last operation
311
312        /*
313         * Examining the SSLEngineResults could be much more involved,
314         * and may alter the overall flow of the application.
315         *
316         * For example, if we received a BUFFER_OVERFLOW when trying
317         * to write to the output pipe, we could reallocate a larger
318         * pipe, but instead we wait for the peer to drain it.
319         */
320        byte[] inbound = new byte[8192];
321        byte[] outbound = new byte[8192];
322
323        while (!isEngineClosed(serverEngine)) {
324            int len = 0;
325
326            // Inbound data
327            log("================");
328
329            // Read from the Client side.
330            try {
331                len = is.read(inbound);
332                if (len == -1) {
333                    throw new Exception("Unexpected EOF");
334                }
335                cTOs.put(inbound, 0, len);
336            } catch (SocketTimeoutException ste) {
337                // swallow.  Nothing yet, probably waiting on us.
338                System.out.println("Warning: " + ste);
339            }
340
341            cTOs.flip();
342
343            serverResult = serverEngine.unwrap(cTOs, serverIn);
344            log("server unwrap: ", serverResult);
345            runDelegatedTasks(serverResult, serverEngine);
346            cTOs.compact();
347
348            // Outbound data
349            log("----");
350
351            serverResult = serverEngine.wrap(serverOut, sTOc);
352            log("server wrap: ", serverResult);
353            runDelegatedTasks(serverResult, serverEngine);
354
355            sTOc.flip();
356
357            if ((len = sTOc.remaining()) != 0) {
358                sTOc.get(outbound, 0, len);
359                os.write(outbound, 0, len);
360                // Give the other side a chance to process
361            }
362
363            sTOc.compact();
364
365            if (!closed && (serverOut.remaining() == 0)) {
366                closed = true;
367
368                /*
369                 * We'll alternate initiatating the shutdown.
370                 * When the server initiates, it will take one more
371                 * loop, but tests the orderly shutdown.
372                 */
373                if (serverClose) {
374                    serverEngine.closeOutbound();
375                }
376            }
377
378            if (closed && isEngineClosed(serverEngine)) {
379                serverIn.flip();
380
381                /*
382                 * A sanity check to ensure we got what was sent.
383                 */
384                if (serverIn.remaining() != clientMsg.length) {
385                    throw new Exception("Client: Data length error -" +
386                        " IF THIS FAILS, PLEASE REPORT THIS TO THE" +
387                        " SECURITY TEAM.  WE HAVE BEEN UNABLE TO" +
388                        " RELIABLY DUPLICATE.");
389                }
390
391                for (int i = 0; i < clientMsg.length; i++) {
392                    if (clientMsg[i] != serverIn.get()) {
393                        throw new Exception("Client: Data content error -" +
394                        " IF THIS FAILS, PLEASE REPORT THIS TO THE" +
395                        " SECURITY TEAM.  WE HAVE BEEN UNABLE TO" +
396                        " RELIABLY DUPLICATE.");
397                    }
398                }
399                serverIn.compact();
400            }
401        }
402    }
403
404    /*
405     * Create a client thread which does simple SSLSocket operations.
406     * We'll write and read one data packet.
407     */
408    private Thread runClient(final boolean serverClose)
409            throws Exception {
410
411        Thread t = new Thread("ClientThread") {
412
413            @Override
414            public void run() {
415                try {
416                    doClientSide(serverClose);
417                } catch (Exception e) {
418                    System.out.println("Client died ...");
419                    e.printStackTrace(System.out);
420                    clientException = e;
421                }
422            }
423        };
424
425        t.start();
426        return t;
427    }
428
429    /*
430     * Define the client side of the test.
431     */
432    void doClientSide(boolean serverClose) throws Exception {
433        // Wait for server to get started.
434        //
435        // The server side takes care of the issue if the server cannot
436        // get started in 90 seconds.  The client side would just ignore
437        // the test case if the serer is not ready.
438        boolean serverIsReady =
439                serverCondition.await(90L, TimeUnit.SECONDS);
440        if (!serverIsReady) {
441            System.out.println(
442                    "The server is not ready yet in 90 seconds. " +
443                    "Ignore in client side.");
444            return;
445        }
446
447        SSLSocketFactory sslsf = sslc.getSocketFactory();
448        try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) {
449            try {
450                sslSocket.connect(
451                        new InetSocketAddress("localhost", serverPort), 15000);
452            } catch (IOException ioe) {
453                // The server side may be impacted by naughty test cases or
454                // third party routines, and cannot accept connections.
455                //
456                // Just ignore the test if the connection cannot be
457                // established.
458                System.out.println(
459                        "Cannot make a connection in 15 seconds. " +
460                        "Ignore in client side.");
461                return;
462            }
463
464            // OK, here the client and server get connected.
465
466            // Signal the server, the client is ready to communicate.
467            clientCondition.countDown();
468
469            // There is still a chance in theory that the server thread may
470            // wait client-ready timeout and then quit.  The chance should
471            // be really rare so we don't consider it until it becomes a
472            // real problem.
473
474            // Run the application in client side.
475            runClientApplication(sslSocket, serverClose);
476        }
477    }
478
479    /*
480     * Define the server side application of the test for the specified socket.
481     */
482    void runClientApplication(SSLSocket sslSocket, boolean serverClose)
483            throws Exception {
484
485        OutputStream os = sslSocket.getOutputStream();
486        InputStream is = sslSocket.getInputStream();
487
488        // write(byte[]) goes in one shot.
489        os.write(clientMsg);
490
491        byte[] inbound = new byte[2048];
492        int pos = 0;
493
494        int len;
495        while ((len = is.read(inbound, pos, 2048 - pos)) != -1) {
496            pos += len;
497            // Let the client do the closing.
498            if ((pos == serverMsg.length) && !serverClose) {
499                sslSocket.close();
500                break;
501            }
502        }
503
504        if (pos != serverMsg.length) {
505            throw new Exception("Client:  Data length error");
506        }
507
508        for (int i = 0; i < serverMsg.length; i++) {
509            if (inbound[i] != serverMsg[i]) {
510                throw new Exception("Client:  Data content error");
511            }
512        }
513    }
514
515    /*
516     * Using the SSLContext created during object creation,
517     * create/configure the SSLEngines we'll use for this test.
518     */
519    private void createSSLEngine() throws Exception {
520        /*
521         * Configure the serverEngine to act as a server in the SSL/TLS
522         * handshake.
523         */
524        serverEngine = sslc.createSSLEngine();
525        serverEngine.setUseClientMode(false);
526        serverEngine.getNeedClientAuth();
527    }
528
529    /*
530     * Create and size the buffers appropriately.
531     */
532    private void createBuffers(boolean direct) {
533
534        SSLSession session = serverEngine.getSession();
535        int appBufferMax = session.getApplicationBufferSize();
536        int netBufferMax = session.getPacketBufferSize();
537
538        /*
539         * We'll make the input buffers a bit bigger than the max needed
540         * size, so that unwrap()s following a successful data transfer
541         * won't generate BUFFER_OVERFLOWS.
542         *
543         * We'll use a mix of direct and indirect ByteBuffers for
544         * tutorial purposes only.  In reality, only use direct
545         * ByteBuffers when they give a clear performance enhancement.
546         */
547        if (direct) {
548            serverIn = ByteBuffer.allocateDirect(appBufferMax + 50);
549            cTOs = ByteBuffer.allocateDirect(netBufferMax);
550            sTOc = ByteBuffer.allocateDirect(netBufferMax);
551        } else {
552            serverIn = ByteBuffer.allocate(appBufferMax + 50);
553            cTOs = ByteBuffer.allocate(netBufferMax);
554            sTOc = ByteBuffer.allocate(netBufferMax);
555        }
556
557        serverOut = ByteBuffer.wrap(serverMsg);
558    }
559
560    /*
561     * If the result indicates that we have outstanding tasks to do,
562     * go ahead and run them in this thread.
563     */
564    private static void runDelegatedTasks(SSLEngineResult result,
565            SSLEngine engine) throws Exception {
566
567        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
568            Runnable runnable;
569            while ((runnable = engine.getDelegatedTask()) != null) {
570                log("\trunning delegated task...");
571                runnable.run();
572            }
573            HandshakeStatus hsStatus = engine.getHandshakeStatus();
574            if (hsStatus == HandshakeStatus.NEED_TASK) {
575                throw new Exception(
576                        "handshake shouldn't need additional tasks");
577            }
578            log("\tnew HandshakeStatus: " + hsStatus);
579        }
580    }
581
582    private static boolean isEngineClosed(SSLEngine engine) {
583        return (engine.isOutboundDone() && engine.isInboundDone());
584    }
585
586    /*
587     * Logging code
588     */
589    private static boolean resultOnce = true;
590
591    private static void log(String str, SSLEngineResult result) {
592        if (!logging) {
593            return;
594        }
595        if (resultOnce) {
596            resultOnce = false;
597            System.out.println("The format of the SSLEngineResult is: \n"
598                    + "\t\"getStatus() / getHandshakeStatus()\" +\n"
599                    + "\t\"bytesConsumed() / bytesProduced()\"\n");
600        }
601        HandshakeStatus hsStatus = result.getHandshakeStatus();
602        log(str
603                + result.getStatus() + "/" + hsStatus + ", "
604                + result.bytesConsumed() + "/" + result.bytesProduced()
605                + " bytes");
606        if (hsStatus == HandshakeStatus.FINISHED) {
607            log("\t...ready for application data");
608        }
609    }
610
611    private static void log(String str) {
612        if (logging) {
613            System.out.println(str);
614        }
615    }
616}
617