1/*
2 * Copyright (c) 2003, 2013, 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 4969799
32 * @summary javax.net.ssl.SSLSocket.SSLSocket(InetAddress,int) shouldn't
33 *              throw exception
34 * @run main/othervm CloseEngineException
35 */
36
37//
38// This is making sure that starting a new handshake throws the right
39// exception.  There is a similar test for SSLSocket.
40//
41
42import javax.net.ssl.*;
43import javax.net.ssl.SSLEngineResult.*;
44import java.io.*;
45import java.security.*;
46import java.nio.*;
47
48public class CloseEngineException {
49
50    private static boolean debug = false;
51
52    private SSLContext sslc;
53    private SSLEngine ssle1;    // client
54    private SSLEngine ssle2;    // server
55
56    private static String pathToStores = "../../../../javax/net/ssl/etc";
57    private static String keyStoreFile = "keystore";
58    private static String trustStoreFile = "truststore";
59    private static String passwd = "passphrase";
60
61    private static String keyFilename =
62            System.getProperty("test.src", "./") + "/" + pathToStores +
63                "/" + keyStoreFile;
64    private static String trustFilename =
65            System.getProperty("test.src", "./") + "/" + pathToStores +
66                "/" + trustStoreFile;
67
68    private ByteBuffer appOut1;         // write side of ssle1
69    private ByteBuffer appIn1;          // read side of ssle1
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(appOut1, 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, appIn1);
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 && (appOut1.limit() == appIn2.position()) &&
140                    (appOut2.limit() == appIn1.position())) {
141
142                checkTransfer(appOut1, appIn2);
143                checkTransfer(appOut2, appIn1);
144
145                log("Closing ssle1's *OUTBOUND*...");
146                ssle1.closeOutbound();
147                dataDone = true;
148
149                try {
150                    /*
151                     * Check that closed Outbound generates.
152                     */
153                    ssle1.beginHandshake();
154                    throw new Exception(
155                        "TEST FAILED:  didn't throw Exception");
156                } catch (SSLException e) {
157                    System.out.println("PARTIAL PASS");
158                }
159            }
160        }
161
162        try {
163            /*
164             * Check that closed Inbound generates.
165             */
166            ssle2.beginHandshake();
167            throw new Exception(
168                "TEST FAILED:  didn't throw Exception");
169        } catch (SSLException e) {
170            System.out.println("TEST PASSED");
171        }
172    }
173
174    public static void main(String args[]) throws Exception {
175
176        CloseEngineException test;
177
178        test = new CloseEngineException();
179
180        test.createSSLEngines();
181
182        test.runTest();
183
184        System.out.println("Test Passed.");
185    }
186
187    /*
188     * **********************************************************
189     * Majority of the test case is above, below is just setup stuff
190     * **********************************************************
191     */
192
193    public CloseEngineException() throws Exception {
194        sslc = getSSLContext(keyFilename, trustFilename);
195    }
196
197    /*
198     * Create an initialized SSLContext to use for this test.
199     */
200    private SSLContext getSSLContext(String keyFile, String trustFile)
201            throws Exception {
202
203        KeyStore ks = KeyStore.getInstance("JKS");
204        KeyStore ts = KeyStore.getInstance("JKS");
205
206        char[] passphrase = "passphrase".toCharArray();
207
208        ks.load(new FileInputStream(keyFile), passphrase);
209        ts.load(new FileInputStream(trustFile), passphrase);
210
211        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
212        kmf.init(ks, passphrase);
213
214        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
215        tmf.init(ts);
216
217        SSLContext sslCtx = SSLContext.getInstance("TLS");
218
219        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
220
221        return sslCtx;
222    }
223
224    private void createBuffers() {
225        // Size the buffers as appropriate.
226
227        SSLSession session = ssle1.getSession();
228        int appBufferMax = session.getApplicationBufferSize();
229        int netBufferMax = session.getPacketBufferSize();
230
231        appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50);
232        appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50);
233
234        oneToTwo = ByteBuffer.allocateDirect(netBufferMax);
235        twoToOne = ByteBuffer.allocateDirect(netBufferMax);
236
237        appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes());
238        appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes());
239
240        log("AppOut1 = " + appOut1);
241        log("AppOut2 = " + appOut2);
242        log("");
243    }
244
245    private static void runDelegatedTasks(SSLEngineResult result,
246            SSLEngine engine) throws Exception {
247
248        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
249            Runnable runnable;
250            while ((runnable = engine.getDelegatedTask()) != null) {
251                log("running delegated task...");
252                runnable.run();
253            }
254        }
255    }
256
257    private static boolean isEngineClosed(SSLEngine engine) {
258        return (engine.isOutboundDone() && engine.isInboundDone());
259    }
260
261    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
262            throws Exception {
263        a.flip();
264        b.flip();
265
266        if (!a.equals(b)) {
267            throw new Exception("Data didn't transfer cleanly");
268        } else {
269            log("Data transferred cleanly");
270        }
271
272        a.position(a.limit());
273        b.position(b.limit());
274        a.limit(a.capacity());
275        b.limit(b.capacity());
276    }
277
278    private static void log(String str) {
279        if (debug) {
280            System.out.println(str);
281        }
282    }
283}
284