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