1 /*
   2  * Copyright (c) 2009, 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 6822460
  32  * @summary support self-issued certificate
  33  * @run main/othervm SelfIssuedCert PKIX
  34  * @run main/othervm SelfIssuedCert SunX509
  35  * @author Xuelei Fan
  36  */
  37 
  38 import java.net.*;
  39 import java.util.*;
  40 import java.io.*;
  41 import javax.net.ssl.*;
  42 import java.security.Security;
  43 import java.security.KeyStore;
  44 import java.security.KeyFactory;
  45 import java.security.cert.Certificate;
  46 import java.security.cert.CertificateFactory;
  47 import java.security.spec.*;
  48 import java.security.interfaces.*;
  49 import java.math.BigInteger;
  50 
  51 import java.util.Base64;
  52 
  53 public class SelfIssuedCert {
  54 
  55     /*
  56      * =============================================================
  57      * Set the various variables needed for the tests, then
  58      * specify what tests to run on each side.
  59      */
  60 
  61     /*
  62      * Should we run the client or server in a separate thread?
  63      * Both sides can throw exceptions, but do you have a preference
  64      * as to which side should be the main thread.
  65      */
  66     static boolean separateServerThread = true;
  67 
  68     /*
  69      * Where do we find the keystores?
  70      */
  71     // Certificate information:
  72     // Issuer: C=US, O=Example, CN=localhost
  73     // Validity
  74     //     Not Before: May 25 00:35:58 2009 GMT
  75     //     Not After : May  5 00:35:58 2030 GMT
  76     // Subject: C=US, O=Example, CN=localhost
  77     // X509v3 Subject Key Identifier:
  78     //     56:AB:FE:15:4C:9C:4A:70:90:DC:0B:9B:EB:BE:DC:03:CC:7F:CE:CF
  79     // X509v3 Authority Key Identifier:
  80     //     keyid:56:AB:FE:15:4C:9C:4A:70:90:DC:0B:9B:EB:BE:DC:03:CC:7F:CE:CF
  81     //     DirName:/C=US/O=Example/CN=localhost
  82     //     serial:00
  83     static String trusedCertStr =
  84         "-----BEGIN CERTIFICATE-----\n" +
  85         "MIICejCCAeOgAwIBAgIBADANBgkqhkiG9w0BAQQFADAzMQswCQYDVQQGEwJVUzEQ\n" +
  86         "MA4GA1UEChMHRXhhbXBsZTESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTA5MDUyNTAw\n" +
  87         "MDQ0M1oXDTMwMDUwNTAwMDQ0M1owMzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4\n" +
  88         "YW1wbGUxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" +
  89         "gYkCgYEA0Wvh3FHYGQ3vvw59yTjUxT6QuY0fzwCGQTM9evXr/V9+pjWmaTkNDW+7\n" +
  90         "S/LErlWz64gOWTgcMZN162sVgx4ct/q27brY+SlUO5eSud1fSac6SfefhOPBa965\n" +
  91         "Xc4mnpDt5sgQPMDCuFK7Le6A+/S9J42BO2WYmNcmvcwWWrv+ehcCAwEAAaOBnTCB\n" +
  92         "mjAdBgNVHQ4EFgQUq3q5fYEibdvLpab+JY4pmifj2vYwWwYDVR0jBFQwUoAUq3q5\n" +
  93         "fYEibdvLpab+JY4pmifj2vahN6Q1MDMxCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdF\n" +
  94         "eGFtcGxlMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAwDwYDVR0TAQH/BAUwAwEB/zAL\n" +
  95         "BgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEEBQADgYEAHL8BSwtX6s8WPPG2FbQBX+K8\n" +
  96         "GquAyQNtgfJNm60B4i+fVBkJiQJtLmE0emvHx/3sIaHmB0Gd0HKnk/cIQXY304vr\n" +
  97         "QpqwudKcIZuzmj+pa7807joV+WzRDVIlt4HpYg7tiUvEoyw+X8jwY2lgiGR7mWu6\n" +
  98         "jQU8PN/06+qgtvSGFpo=\n" +
  99         "-----END CERTIFICATE-----";
 100 
 101     // Certificate information:
 102     // Issuer: C=US, O=Example, CN=localhost
 103     // Validity
 104     //     Not Before: May 25 00:35:58 2009 GMT
 105     //     Not After : May  5 00:35:58 2030 GMT
 106     // Subject: C=US, O=Example, CN=localhost
 107     // X509v3 Subject Key Identifier:
 108     //     0D:30:76:22:D6:9D:75:EF:FD:83:50:31:18:08:83:CD:01:4E:6A:C4
 109     // X509v3 Authority Key Identifier:
 110     //     keyid:56:AB:FE:15:4C:9C:4A:70:90:DC:0B:9B:EB:BE:DC:03:CC:7F:CE:CF
 111     //     DirName:/C=US/O=Example/CN=localhost
 112     //     serial:00
 113     static String targetCertStr =
 114         "-----BEGIN CERTIFICATE-----\n" +
 115         "MIICaTCCAdKgAwIBAgIBAjANBgkqhkiG9w0BAQQFADAzMQswCQYDVQQGEwJVUzEQ\n" +
 116         "MA4GA1UEChMHRXhhbXBsZTESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTA5MDUyNTAw\n" +
 117         "MDQ0M1oXDTI5MDIwOTAwMDQ0M1owMzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4\n" +
 118         "YW1wbGUxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" +
 119         "gYkCgYEAzmPahrH9LTQv3HEWsua+hIpzyU1ACooSd5BtDjc7XnVzSdGW8QD9R8EA\n" +
 120         "xko7TvfJo6IH6wwgHBspySwsl+6xvHhbwQjgtWlT71ksrUbqcUzmvSvcycQYA8RC\n" +
 121         "yk9HK5pEJQgSxldpR3Kmy0V6CHC4dCm15trnJYWisTuezY3fjXECAwEAAaOBjDCB\n" +
 122         "iTAdBgNVHQ4EFgQUQkiWFRkjKsfwFo7UMQfGEzNNW60wWwYDVR0jBFQwUoAUq3q5\n" +
 123         "fYEibdvLpab+JY4pmifj2vahN6Q1MDMxCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdF\n" +
 124         "eGFtcGxlMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAwCwYDVR0PBAQDAgPoMA0GCSqG\n" +
 125         "SIb3DQEBBAUAA4GBAIMz7c1R+6KEO7FmH4rnv9XE62xkg03ff0vKXLZMjjs0CX2z\n" +
 126         "ybRttuTFafHA6/JS+Wz0G83FCRVeiw2WPU6BweMwwejzzIrQ/K6mbp6w6sRFcbNa\n" +
 127         "eLBtzkjEtI/htOSSq3/0mbKmWn5uVJckO4QiB8kUR4F7ngM9l1uuI46ZfUsk\n" +
 128         "-----END CERTIFICATE-----";
 129 
 130     // Private key in the format of PKCS#8
 131     static String targetPrivateKey =
 132         "MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAM5j2oax/S00L9xx\n" +
 133         "FrLmvoSKc8lNQAqKEneQbQ43O151c0nRlvEA/UfBAMZKO073yaOiB+sMIBwbKcks\n" +
 134         "LJfusbx4W8EI4LVpU+9ZLK1G6nFM5r0r3MnEGAPEQspPRyuaRCUIEsZXaUdypstF\n" +
 135         "eghwuHQpteba5yWForE7ns2N341xAgMBAAECgYEAgZ8k98OBhopoJMLBxso0jXmH\n" +
 136         "Dr59oiDlSEJku7DkkIajSZFggyxj5lTI78BfT1FASozQ/EY5RG2q6LXdq+41oU/U\n" +
 137         "JVEQWhdIE1mQDwE0vgaYdjzMaVIsC3cZYOCOmCYvNxCiTt7e/z8yBMmAE5udqJMB\n" +
 138         "pim4WXDfpy0ssK81oCECQQDwMC4xu+kn0yD/Qyi9Zn26gIRDv4bjzDQoJfSvMhrY\n" +
 139         "a4duxLzh9u4gCDd0+wHxpPQvNxGCk0c1JUxBJ2rb4G3HAkEA2/oVRV6+xiRXUnoo\n" +
 140         "bdPEO27zEJmdpE42yU/JLIy6DPu2IUhEqY45fU2ZERmwMdhpiK/vsf/CZKJ2j/ZU\n" +
 141         "PdMLBwJBAJIYTFDWAqjFpCGAASzLRZiGiW0H941h7Suqgp159ZhEN5mps1Yis47q\n" +
 142         "UIkoEHOiKSD69vychsiNykcrKbVaWosCQQC1UrYX4Vo1r5z/EkyjAwzcxL68rzM/\n" +
 143         "TW1hkU/NVg7CRvXBB3X5oY+H1t/WNauD2tRa5FMbESwmkbhTQIP+FikfAkEA4goD\n" +
 144         "HCxUn0Z1OQq9QL6y1Yoof6sHxicUwABosuCLJnDJmA5vhpemvdXQTzFII8g1hyQf\n" +
 145         "z1yyDoxhddcleKlJvQ==";
 146 
 147     static char passphrase[] = "passphrase".toCharArray();
 148 
 149     /*
 150      * Is the server ready to serve?
 151      */
 152     volatile static boolean serverReady = false;
 153 
 154     /*
 155      * Turn on SSL debugging?
 156      */
 157     static boolean debug = false;
 158 
 159     /*
 160      * Define the server side of the test.
 161      *
 162      * If the server prematurely exits, serverReady will be set to true
 163      * to avoid infinite hangs.
 164      */
 165     void doServerSide() throws Exception {
 166         SSLContext context = getSSLContext(null, targetCertStr,
 167                                             targetPrivateKey);
 168         SSLServerSocketFactory sslssf = context.getServerSocketFactory();
 169 
 170         SSLServerSocket sslServerSocket =
 171             (SSLServerSocket)sslssf.createServerSocket(serverPort);
 172         serverPort = sslServerSocket.getLocalPort();
 173 
 174         /*
 175          * Signal Client, we're ready for his connect.
 176          */
 177         serverReady = true;
 178 
 179         SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
 180         sslSocket.setNeedClientAuth(false);
 181 
 182         InputStream sslIS = sslSocket.getInputStream();
 183         OutputStream sslOS = sslSocket.getOutputStream();
 184 
 185         sslIS.read();
 186         sslOS.write(85);
 187         sslOS.flush();
 188 
 189         sslSocket.close();
 190 
 191     }
 192 
 193     /*
 194      * Define the client side of the test.
 195      *
 196      * If the server prematurely exits, serverReady will be set to true
 197      * to avoid infinite hangs.
 198      */
 199     void doClientSide() throws Exception {
 200         /*
 201          * Wait for server to get started.
 202          */
 203         while (!serverReady) {
 204             Thread.sleep(50);
 205         }
 206 
 207         SSLContext context = getSSLContext(trusedCertStr, null, null);
 208         SSLSocketFactory sslsf = context.getSocketFactory();
 209 
 210         SSLSocket sslSocket =
 211             (SSLSocket)sslsf.createSocket("localhost", serverPort);
 212         sslSocket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" });
 213 
 214         InputStream sslIS = sslSocket.getInputStream();
 215         OutputStream sslOS = sslSocket.getOutputStream();
 216 
 217         sslOS.write(280);
 218         sslOS.flush();
 219         sslIS.read();
 220 
 221         sslSocket.close();
 222     }
 223 
 224     // get the ssl context
 225     private static SSLContext getSSLContext(String trusedCertStr,
 226             String keyCertStr, String keySpecStr) throws Exception {
 227 
 228         // generate certificate from cert string
 229         CertificateFactory cf = CertificateFactory.getInstance("X.509");
 230 
 231         // create a key store
 232         KeyStore ks = KeyStore.getInstance("JKS");
 233         ks.load(null, null);
 234 
 235         // import the trused cert
 236         Certificate trusedCert = null;
 237         ByteArrayInputStream is = null;
 238         if (trusedCertStr != null) {
 239             is = new ByteArrayInputStream(trusedCertStr.getBytes());
 240             trusedCert = cf.generateCertificate(is);
 241             is.close();
 242 
 243             ks.setCertificateEntry("RSA Export Signer", trusedCert);
 244         }
 245 
 246         if (keyCertStr != null) {
 247             // generate the private key.
 248             PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
 249                                 Base64.getMimeDecoder().decode(keySpecStr));
 250             KeyFactory kf = KeyFactory.getInstance("RSA");
 251             RSAPrivateKey priKey =
 252                     (RSAPrivateKey)kf.generatePrivate(priKeySpec);
 253 
 254             // generate certificate chain
 255             is = new ByteArrayInputStream(keyCertStr.getBytes());
 256             Certificate keyCert = cf.generateCertificate(is);
 257             is.close();
 258 
 259             Certificate[] chain = null;
 260             if (trusedCert != null) {
 261                 chain = new Certificate[2];
 262                 chain[0] = keyCert;
 263                 chain[1] = trusedCert;
 264             } else {
 265                 chain = new Certificate[1];
 266                 chain[0] = keyCert;
 267             }
 268 
 269             // import the key entry.
 270             ks.setKeyEntry("Whatever", priKey, passphrase, chain);
 271         }
 272 
 273         // create SSL context
 274         TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
 275         tmf.init(ks);
 276 
 277         SSLContext ctx = SSLContext.getInstance("TLS");
 278         if (keyCertStr != null && !keyCertStr.isEmpty()) {
 279             KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
 280             kmf.init(ks, passphrase);
 281 
 282             ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 283             ks = null;
 284         } else {
 285             ctx.init(null, tmf.getTrustManagers(), null);
 286         }
 287 
 288         return ctx;
 289     }
 290 
 291     private static String tmAlgorithm;        // trust manager
 292 
 293     private static void parseArguments(String[] args) {
 294         tmAlgorithm = args[0];
 295     }
 296 
 297     /*
 298      * =============================================================
 299      * The remainder is just support stuff
 300      */
 301 
 302     // use any free port by default
 303     volatile int serverPort = 0;
 304 
 305     volatile Exception serverException = null;
 306     volatile Exception clientException = null;
 307 
 308     public static void main(String args[]) throws Exception {
 309         // MD5 is used in this test case, don't disable MD5 algorithm.
 310         Security.setProperty("jdk.certpath.disabledAlgorithms",
 311                 "MD2, RSA keySize < 1024");
 312         Security.setProperty("jdk.tls.disabledAlgorithms",
 313                 "SSLv3, RC4, DH keySize < 768");
 314 
 315         if (debug)
 316             System.setProperty("javax.net.debug", "all");
 317 
 318 
 319         /*
 320          * Get the customized arguments.
 321          */
 322         parseArguments(args);
 323 
 324         /*
 325          * Start the tests.
 326          */
 327         new SelfIssuedCert();
 328     }
 329 
 330     Thread clientThread = null;
 331     Thread serverThread = null;
 332     /*
 333      * Primary constructor, used to drive remainder of the test.
 334      *
 335      * Fork off the other side, then do your work.
 336      */
 337     SelfIssuedCert() throws Exception {
 338         if (separateServerThread) {
 339             startServer(true);
 340             startClient(false);
 341         } else {
 342             startClient(true);
 343             startServer(false);
 344         }
 345 
 346         /*
 347          * Wait for other side to close down.
 348          */
 349         if (separateServerThread) {
 350             serverThread.join();
 351         } else {
 352             clientThread.join();
 353         }
 354 
 355         /*
 356          * When we get here, the test is pretty much over.
 357          *
 358          * If the main thread excepted, that propagates back
 359          * immediately.  If the other thread threw an exception, we
 360          * should report back.
 361          */
 362         if (serverException != null)
 363             throw serverException;
 364         if (clientException != null)
 365             throw clientException;
 366     }
 367 
 368     void startServer(boolean newThread) throws Exception {
 369         if (newThread) {
 370             serverThread = new Thread() {
 371                 public void run() {
 372                     try {
 373                         doServerSide();
 374                     } catch (Exception e) {
 375                         /*
 376                          * Our server thread just died.
 377                          *
 378                          * Release the client, if not active already...
 379                          */
 380                         System.err.println("Server died...");
 381                         serverReady = true;
 382                         serverException = e;
 383                     }
 384                 }
 385             };
 386             serverThread.start();
 387         } else {
 388             doServerSide();
 389         }
 390     }
 391 
 392     void startClient(boolean newThread) throws Exception {
 393         if (newThread) {
 394             clientThread = new Thread() {
 395                 public void run() {
 396                     try {
 397                         doClientSide();
 398                     } catch (Exception e) {
 399                         /*
 400                          * Our client thread just died.
 401                          */
 402                         System.err.println("Client died...");
 403                         clientException = e;
 404                     }
 405                 }
 406             };
 407             clientThread.start();
 408         } else {
 409             doClientSide();
 410         }
 411     }
 412 
 413 }