1 /*
2  * Copyright (c) 2003, 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 // 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 
42 import javax.net.ssl.*;
43 import javax.net.ssl.SSLEngineResult.*;
44 import java.io.*;
45 import java.security.*;
46 import java.nio.*;
47 
48 // Note that this test case depends on JSSE provider implementation details.
49 public class CloseEngineException {
50 
51     private static boolean debug = true;
52 
53     private SSLContext sslc;
54     private SSLEngine ssle1;    // client
55     private SSLEngine ssle2;    // server
56 
57     private static String pathToStores = "../../../../javax/net/ssl/etc";
58     private static String keyStoreFile = "keystore";
59     private static String trustStoreFile = "truststore";
60     private static String passwd = "passphrase";
61 
62     private static String keyFilename =
63             System.getProperty("test.src", "./") + "/" + pathToStores +
64                 "/" + keyStoreFile;
65     private static String trustFilename =
66             System.getProperty("test.src", "./") + "/" + pathToStores +
67                 "/" + trustStoreFile;
68 
69     private ByteBuffer appOut1;         // write side of ssle1
70     private ByteBuffer appIn1;          // read side of ssle1
71     private ByteBuffer appOut2;         // write side of ssle2
72     private ByteBuffer appIn2;          // read side of ssle2
73 
74     private ByteBuffer oneToTwo;        // "reliable" transport ssle1->ssle2
75     private ByteBuffer twoToOne;        // "reliable" transport ssle2->ssle1
76 
77     /*
78      * Majority of the test case is here, setup is done below.
79      */
createSSLEngines()80     private void createSSLEngines() throws Exception {
81         ssle1 = sslc.createSSLEngine("client", 1);
82         ssle1.setUseClientMode(true);
83 
84         ssle2 = sslc.createSSLEngine();
85         ssle2.setUseClientMode(false);
86         ssle2.setNeedClientAuth(true);
87     }
88 
runTest()89     private void runTest() throws Exception {
90         boolean dataDone = false;
91 
92         createSSLEngines();
93         createBuffers();
94 
95         SSLEngineResult result1;        // ssle1's results from last operation
96         SSLEngineResult result2;        // ssle2's results from last operation
97 
98         while (!isEngineClosed(ssle1) && !isEngineClosed(ssle2)) {
99 
100             log("================");
101 
102             if (!isEngineClosed(ssle1)) {
103                 result1 = ssle1.wrap(appOut1, oneToTwo);
104                 runDelegatedTasks(result1, ssle1);
105 
106                 log("wrap1:  " + result1);
107                 log("oneToTwo  = " + oneToTwo);
108                 log("");
109 
110                 oneToTwo.flip();
111             }
112             if (!isEngineClosed(ssle2)) {
113                 result2 = ssle2.wrap(appOut2, twoToOne);
114                 runDelegatedTasks(result2, ssle2);
115 
116                 log("wrap2:  " + result2);
117                 log("twoToOne  = " + twoToOne);
118 
119                 twoToOne.flip();
120             }
121 
122             log("----");
123 
124             if (!isEngineClosed(ssle1) && !dataDone) {
125             log("--");
126                 result1 = ssle1.unwrap(twoToOne, appIn1);
127                 runDelegatedTasks(result1, ssle1);
128 
129                 log("unwrap1: " + result1);
130                 log("twoToOne  = " + twoToOne);
131                 log("");
132 
133                 twoToOne.compact();
134             }
135             if (!isEngineClosed(ssle2)) {
136             log("---");
137                 result2 = ssle2.unwrap(oneToTwo, appIn2);
138                 runDelegatedTasks(result2, ssle2);
139 
140                 log("unwrap2: " + result2);
141                 log("oneToTwo  = " + oneToTwo);
142 
143                 oneToTwo.compact();
144             }
145 
146             /*
147              * If we've transfered all the data between app1 and app2,
148              * we try to close and see what that gets us.
149              */
150             if (!dataDone && (appOut1.limit() == appIn2.position()) &&
151                     (appOut2.limit() == appIn1.position())) {
152 
153                 checkTransfer(appOut1, appIn2);
154                 checkTransfer(appOut2, appIn1);
155 
156                 log("Closing ssle1's *OUTBOUND*...");
157                 ssle1.closeOutbound();
158                 dataDone = true;
159 
160                 try {
161                     /*
162                      * Check that closed Outbound generates.
163                      */
164                     ssle1.beginHandshake();
165                     throw new Exception(
166                         "TEST FAILED:  didn't throw Exception");
167                 } catch (SSLException e) {
168                     System.err.println("PARTIAL PASS");
169                 }
170             }
171         }
172 
173         try {
174             /*
175              * Check that closed Inbound generates.
176              */
177             ssle2.beginHandshake();
178             throw new Exception(
179                 "TEST FAILED:  didn't throw Exception");
180         } catch (SSLException e) {
181             System.err.println("TEST PASSED");
182         }
183     }
184 
main(String args[])185     public static void main(String args[]) throws Exception {
186 
187         CloseEngineException test;
188 
189         test = new CloseEngineException();
190 
191         test.createSSLEngines();
192 
193         test.runTest();
194 
195         System.err.println("Test Passed.");
196     }
197 
198     /*
199      * **********************************************************
200      * Majority of the test case is above, below is just setup stuff
201      * **********************************************************
202      */
203 
CloseEngineException()204     public CloseEngineException() throws Exception {
205         sslc = getSSLContext(keyFilename, trustFilename);
206     }
207 
208     /*
209      * Create an initialized SSLContext to use for this test.
210      */
getSSLContext(String keyFile, String trustFile)211     private SSLContext getSSLContext(String keyFile, String trustFile)
212             throws Exception {
213 
214         KeyStore ks = KeyStore.getInstance("JKS");
215         KeyStore ts = KeyStore.getInstance("JKS");
216 
217         char[] passphrase = "passphrase".toCharArray();
218 
219         ks.load(new FileInputStream(keyFile), passphrase);
220         ts.load(new FileInputStream(trustFile), passphrase);
221 
222         KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
223         kmf.init(ks, passphrase);
224 
225         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
226         tmf.init(ts);
227 
228         SSLContext sslCtx = SSLContext.getInstance("TLS");
229 
230         sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
231 
232         return sslCtx;
233     }
234 
createBuffers()235     private void createBuffers() {
236         // Size the buffers as appropriate.
237 
238         SSLSession session = ssle1.getSession();
239         int appBufferMax = session.getApplicationBufferSize();
240         int netBufferMax = session.getPacketBufferSize();
241 
242         appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50);
243         appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50);
244 
245         oneToTwo = ByteBuffer.allocateDirect(netBufferMax);
246         twoToOne = ByteBuffer.allocateDirect(netBufferMax);
247 
248         appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes());
249         appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes());
250 
251         log("AppOut1 = " + appOut1);
252         log("AppOut2 = " + appOut2);
253         log("");
254     }
255 
runDelegatedTasks(SSLEngineResult result, SSLEngine engine)256     private static void runDelegatedTasks(SSLEngineResult result,
257             SSLEngine engine) throws Exception {
258 
259         if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
260             Runnable runnable;
261             while ((runnable = engine.getDelegatedTask()) != null) {
262                 log("running delegated task...");
263                 runnable.run();
264             }
265         }
266     }
267 
isEngineClosed(SSLEngine engine)268     private static boolean isEngineClosed(SSLEngine engine) {
269         return (engine.isOutboundDone() && engine.isInboundDone());
270     }
271 
checkTransfer(ByteBuffer a, ByteBuffer b)272     private static void checkTransfer(ByteBuffer a, ByteBuffer b)
273             throws Exception {
274         a.flip();
275         b.flip();
276 
277         if (!a.equals(b)) {
278             throw new Exception("Data didn't transfer cleanly");
279         } else {
280             log("Data transferred cleanly");
281         }
282 
283         a.position(a.limit());
284         b.position(b.limit());
285         a.limit(a.capacity());
286         b.limit(b.capacity());
287     }
288 
log(String str)289     private static void log(String str) {
290         if (debug) {
291             System.err.println(str);
292         }
293     }
294 }
295