1 /*
2  * Copyright (c) 2012, 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 7106773 8180570
27  * @summary 512 bits RSA key cannot work with SHA384 and SHA512
28  * @requires os.family == "windows"
29  * @modules java.base/sun.security.util
30  *          java.base/sun.security.tools.keytool
31  *          java.base/sun.security.x509
32  * @run main ShortRSAKeyWithinTLS 1024
33  * @run main ShortRSAKeyWithinTLS 768
34  * @run main ShortRSAKeyWithinTLS 512
35  */
36 import java.io.*;
37 import java.net.*;
38 import java.security.cert.Certificate;
39 import java.util.*;
40 import java.security.*;
41 import java.security.cert.*;
42 import javax.net.*;
43 import javax.net.ssl.*;
44 
45 import sun.security.tools.keytool.CertAndKeyGen;
46 import sun.security.util.KeyUtil;
47 import sun.security.x509.X500Name;
48 
49 public class ShortRSAKeyWithinTLS {
50 
51     /*
52      * =============================================================
53      * Set the various variables needed for the tests, then
54      * specify what tests to run on each side.
55      */
56 
57     /*
58      * Should we run the client or server in a separate thread?
59      * Both sides can throw exceptions, but do you have a preference
60      * as to which side should be the main thread.
61      */
62     static boolean separateServerThread = false;
63 
64     /*
65      * Is the server ready to serve?
66      */
67     volatile static boolean serverReady = false;
68 
69     /*
70      * Turn on SSL debugging?
71      */
72     static boolean debug = false;
73 
74     /*
75      * If the client or server is doing some kind of object creation
76      * that the other side depends on, and that thread prematurely
77      * exits, you may experience a hang.  The test harness will
78      * terminate all hung threads after its timeout has expired,
79      * currently 3 minutes by default, but you might try to be
80      * smart about it....
81      */
82 
83     /*
84      * Define the server side of the test.
85      *
86      * If the server prematurely exits, serverReady will be set to true
87      * to avoid infinite hangs.
88      */
doServerSide()89     void doServerSide() throws Exception {
90 
91         // load the key store
92         serverKS = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
93         serverKS.load(null, null);
94         System.out.println("Loaded keystore: Windows-MY");
95 
96         // check key size
97         checkKeySize(serverKS);
98 
99         // initialize the SSLContext
100         KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
101         kmf.init(serverKS, null);
102 
103         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
104         tmf.init(serverKS);
105         TrustManager[] tms = tmf.getTrustManagers();
106         if (tms == null || tms.length == 0) {
107             throw new Exception("unexpected trust manager implementation");
108         } else {
109             if (!(tms[0] instanceof X509TrustManager)) {
110                 throw new Exception("unexpected trust manager" +
111                         " implementation: " +
112                         tms[0].getClass().getCanonicalName());
113             }
114         }
115         serverTM = new MyExtendedX509TM((X509TrustManager)tms[0]);
116         tms = new TrustManager[] {serverTM};
117 
118         SSLContext ctx = SSLContext.getInstance("TLS");
119         ctx.init(kmf.getKeyManagers(), tms, null);
120 
121         ServerSocketFactory ssf = ctx.getServerSocketFactory();
122         SSLServerSocket sslServerSocket = (SSLServerSocket)
123                                 ssf.createServerSocket(serverPort);
124         sslServerSocket.setNeedClientAuth(true);
125         serverPort = sslServerSocket.getLocalPort();
126         System.out.println("serverPort = " + serverPort);
127 
128         /*
129          * Signal Client, we're ready for his connect.
130          */
131         serverReady = true;
132 
133         SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
134         InputStream sslIS = sslSocket.getInputStream();
135         OutputStream sslOS = sslSocket.getOutputStream();
136 
137         sslIS.read();
138         sslOS.write(85);
139         sslOS.flush();
140 
141         sslSocket.close();
142     }
143 
144     /*
145      * Define the client side of the test.
146      *
147      * If the server prematurely exits, serverReady will be set to true
148      * to avoid infinite hangs.
149      */
doClientSide()150     void doClientSide() throws Exception {
151 
152         /*
153          * Wait for server to get started.
154          */
155         while (!serverReady) {
156             Thread.sleep(50);
157         }
158 
159         // load the key store
160         KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
161         ks.load(null, null);
162         System.out.println("Loaded keystore: Windows-MY");
163 
164         // initialize the SSLContext
165         KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
166         kmf.init(ks, null);
167 
168         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
169         tmf.init(ks);
170 
171         SSLContext ctx = SSLContext.getInstance("TLS");
172         ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
173 
174         SSLSocketFactory sslsf = ctx.getSocketFactory();
175         SSLSocket sslSocket = (SSLSocket)
176             sslsf.createSocket("localhost", serverPort);
177 
178         if (clientProtocol != null) {
179             sslSocket.setEnabledProtocols(new String[] {clientProtocol});
180         }
181 
182         if (clientCiperSuite != null) {
183             sslSocket.setEnabledCipherSuites(new String[] {clientCiperSuite});
184         }
185 
186         InputStream sslIS = sslSocket.getInputStream();
187         OutputStream sslOS = sslSocket.getOutputStream();
188 
189         sslOS.write(280);
190         sslOS.flush();
191         sslIS.read();
192 
193         sslSocket.close();
194     }
195 
checkKeySize(KeyStore ks)196     private void checkKeySize(KeyStore ks) throws Exception {
197         PrivateKey privateKey = null;
198         PublicKey publicKey = null;
199 
200         if (ks.containsAlias(keyAlias)) {
201             System.out.println("Loaded entry: " + keyAlias);
202             privateKey = (PrivateKey)ks.getKey(keyAlias, null);
203             publicKey = (PublicKey)ks.getCertificate(keyAlias).getPublicKey();
204 
205             int privateKeySize = KeyUtil.getKeySize(privateKey);
206             if (privateKeySize != keySize) {
207                 throw new Exception("Expected key size is " + keySize +
208                         ", but the private key size is " + privateKeySize);
209             }
210 
211             int publicKeySize = KeyUtil.getKeySize(publicKey);
212             if (publicKeySize != keySize) {
213                 throw new Exception("Expected key size is " + keySize +
214                         ", but the public key size is " + publicKeySize);
215             }
216         }
217     }
218 
219     /*
220      * =============================================================
221      * The remainder is just support stuff
222      */
223 
224     // use any free port by default
225     volatile int serverPort = 0;
226 
227     volatile Exception serverException = null;
228     volatile Exception clientException = null;
229 
230     private static String keyAlias;
231     private static int keySize;
232     private static String clientProtocol = null;
233     private static String clientCiperSuite = null;
234 
main(String[] args)235     public static void main(String[] args) throws Exception {
236         if (debug) {
237             System.setProperty("javax.net.debug", "all");
238         }
239 
240         keyAlias = "7106773." + args[0];
241         keySize = Integer.parseInt(args[0]);
242 
243         KeyStore ks = KeyStore.getInstance("Windows-MY");
244         ks.load(null, null);
245         if (ks.containsAlias(keyAlias)) {
246             ks.deleteEntry(keyAlias);
247         }
248 
249         CertAndKeyGen gen = new CertAndKeyGen("RSA", "SHA256withRSA");
250         gen.generate(keySize);
251 
252         ks.setKeyEntry(keyAlias, gen.getPrivateKey(), null,
253                 new Certificate[] {
254                     gen.getSelfCertificate(new X500Name("cn=localhost,c=US"), 100)
255                 });
256 
257         clientProtocol = "TLSv1.2";
258         clientCiperSuite = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
259 
260         try {
261             new ShortRSAKeyWithinTLS();
262         } finally {
263             ks.deleteEntry(keyAlias);
264             ks.store(null, null);
265         }
266     }
267 
268     Thread clientThread = null;
269     Thread serverThread = null;
270     KeyStore serverKS;
271     MyExtendedX509TM serverTM;
272 
273     /*
274      * Primary constructor, used to drive remainder of the test.
275      *
276      * Fork off the other side, then do your work.
277      */
ShortRSAKeyWithinTLS()278     ShortRSAKeyWithinTLS() throws Exception {
279         try {
280             if (separateServerThread) {
281                 startServer(true);
282                 startClient(false);
283             } else {
284                 startClient(true);
285                 startServer(false);
286             }
287         } catch (Exception e) {
288             // swallow for now.  Show later
289         }
290 
291         /*
292          * Wait for other side to close down.
293          */
294         if (separateServerThread) {
295             serverThread.join();
296         } else {
297             clientThread.join();
298         }
299 
300         /*
301          * When we get here, the test is pretty much over.
302          * Which side threw the error?
303          */
304         Exception local;
305         Exception remote;
306         String whichRemote;
307 
308         if (separateServerThread) {
309             remote = serverException;
310             local = clientException;
311             whichRemote = "server";
312         } else {
313             remote = clientException;
314             local = serverException;
315             whichRemote = "client";
316         }
317 
318         /*
319          * If both failed, return the curthread's exception, but also
320          * print the remote side Exception
321          */
322         if ((local != null) && (remote != null)) {
323             System.out.println(whichRemote + " also threw:");
324             remote.printStackTrace();
325             System.out.println();
326             throw local;
327         }
328 
329         if (remote != null) {
330             throw remote;
331         }
332 
333         if (local != null) {
334             throw local;
335         }
336     }
337 
startServer(boolean newThread)338     void startServer(boolean newThread) throws Exception {
339         if (newThread) {
340             serverThread = new Thread() {
341                 public void run() {
342                     try {
343                         doServerSide();
344                     } catch (Exception e) {
345                         /*
346                          * Our server thread just died.
347                          *
348                          * Release the client, if not active already...
349                          */
350                         System.err.println("Server died...");
351                         serverReady = true;
352                         serverException = e;
353                     }
354                 }
355             };
356             serverThread.start();
357         } else {
358             try {
359                 doServerSide();
360             } catch (Exception e) {
361                 serverException = e;
362             } finally {
363                 serverReady = true;
364             }
365         }
366     }
367 
startClient(boolean newThread)368     void startClient(boolean newThread) throws Exception {
369         if (newThread) {
370             clientThread = new Thread() {
371                 public void run() {
372                     try {
373                         doClientSide();
374                     } catch (Exception e) {
375                         /*
376                          * Our client thread just died.
377                          */
378                         System.err.println("Client died...");
379                         clientException = e;
380                     }
381                 }
382             };
383             clientThread.start();
384         } else {
385             try {
386                 doClientSide();
387             } catch (Exception e) {
388                 clientException = e;
389             }
390         }
391     }
392 
393 
394     class MyExtendedX509TM extends X509ExtendedTrustManager
395             implements X509TrustManager {
396 
397         X509TrustManager tm;
398 
MyExtendedX509TM(X509TrustManager tm)399         MyExtendedX509TM(X509TrustManager tm) {
400             this.tm = tm;
401         }
402 
checkClientTrusted(X509Certificate chain[], String authType)403         public void checkClientTrusted(X509Certificate chain[], String authType)
404                 throws CertificateException {
405             tm.checkClientTrusted(chain, authType);
406         }
407 
checkServerTrusted(X509Certificate chain[], String authType)408         public void checkServerTrusted(X509Certificate chain[], String authType)
409                 throws CertificateException {
410             tm.checkServerTrusted(chain, authType);
411         }
412 
getAcceptedIssuers()413         public X509Certificate[] getAcceptedIssuers() {
414             List<X509Certificate> certs = new ArrayList<>();
415             try {
416                 for (X509Certificate c : tm.getAcceptedIssuers()) {
417                     if (serverKS.getCertificateAlias(c).equals(keyAlias))
418                         certs.add(c);
419                 }
420             } catch (KeyStoreException kse) {
421                 throw new RuntimeException(kse);
422             }
423             return certs.toArray(new X509Certificate[certs.size()]);
424         }
425 
checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)426         public void checkClientTrusted(X509Certificate[] chain, String authType,
427                 Socket socket) throws CertificateException {
428             tm.checkClientTrusted(chain, authType);
429         }
430 
checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)431         public void checkServerTrusted(X509Certificate[] chain, String authType,
432                 Socket socket) throws CertificateException {
433             tm.checkServerTrusted(chain, authType);
434         }
435 
checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)436         public void checkClientTrusted(X509Certificate[] chain, String authType,
437             SSLEngine engine) throws CertificateException {
438             tm.checkClientTrusted(chain, authType);
439         }
440 
checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)441         public void checkServerTrusted(X509Certificate[] chain, String authType,
442             SSLEngine engine) throws CertificateException {
443             tm.checkServerTrusted(chain, authType);
444         }
445     }
446 
447 }
448 
449