1/* 2 * Copyright (c) 2009, 2015, 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 38import java.net.*; 39import java.util.*; 40import java.io.*; 41import javax.net.ssl.*; 42import java.security.Security; 43import java.security.KeyStore; 44import java.security.KeyFactory; 45import java.security.cert.Certificate; 46import java.security.cert.CertificateFactory; 47import java.security.spec.*; 48import java.security.interfaces.*; 49import java.math.BigInteger; 50 51import java.util.Base64; 52 53public 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 213 InputStream sslIS = sslSocket.getInputStream(); 214 OutputStream sslOS = sslSocket.getOutputStream(); 215 216 sslOS.write(280); 217 sslOS.flush(); 218 sslIS.read(); 219 220 sslSocket.close(); 221 } 222 223 // get the ssl context 224 private static SSLContext getSSLContext(String trusedCertStr, 225 String keyCertStr, String keySpecStr) throws Exception { 226 227 // generate certificate from cert string 228 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 229 230 // create a key store 231 KeyStore ks = KeyStore.getInstance("JKS"); 232 ks.load(null, null); 233 234 // import the trused cert 235 Certificate trusedCert = null; 236 ByteArrayInputStream is = null; 237 if (trusedCertStr != null) { 238 is = new ByteArrayInputStream(trusedCertStr.getBytes()); 239 trusedCert = cf.generateCertificate(is); 240 is.close(); 241 242 ks.setCertificateEntry("RSA Export Signer", trusedCert); 243 } 244 245 if (keyCertStr != null) { 246 // generate the private key. 247 PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( 248 Base64.getMimeDecoder().decode(keySpecStr)); 249 KeyFactory kf = KeyFactory.getInstance("RSA"); 250 RSAPrivateKey priKey = 251 (RSAPrivateKey)kf.generatePrivate(priKeySpec); 252 253 // generate certificate chain 254 is = new ByteArrayInputStream(keyCertStr.getBytes()); 255 Certificate keyCert = cf.generateCertificate(is); 256 is.close(); 257 258 Certificate[] chain = null; 259 if (trusedCert != null) { 260 chain = new Certificate[2]; 261 chain[0] = keyCert; 262 chain[1] = trusedCert; 263 } else { 264 chain = new Certificate[1]; 265 chain[0] = keyCert; 266 } 267 268 // import the key entry. 269 ks.setKeyEntry("Whatever", priKey, passphrase, chain); 270 } 271 272 // create SSL context 273 TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); 274 tmf.init(ks); 275 276 SSLContext ctx = SSLContext.getInstance("TLS"); 277 if (keyCertStr != null && !keyCertStr.isEmpty()) { 278 KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); 279 kmf.init(ks, passphrase); 280 281 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 282 ks = null; 283 } else { 284 ctx.init(null, tmf.getTrustManagers(), null); 285 } 286 287 return ctx; 288 } 289 290 private static String tmAlgorithm; // trust manager 291 292 private static void parseArguments(String[] args) { 293 tmAlgorithm = args[0]; 294 } 295 296 /* 297 * ============================================================= 298 * The remainder is just support stuff 299 */ 300 301 // use any free port by default 302 volatile int serverPort = 0; 303 304 volatile Exception serverException = null; 305 volatile Exception clientException = null; 306 307 public static void main(String args[]) throws Exception { 308 // MD5 is used in this test case, don't disable MD5 algorithm. 309 Security.setProperty("jdk.certpath.disabledAlgorithms", 310 "MD2, RSA keySize < 1024"); 311 Security.setProperty("jdk.tls.disabledAlgorithms", 312 "SSLv3, RC4, DH keySize < 768"); 313 314 if (debug) 315 System.setProperty("javax.net.debug", "all"); 316 317 318 /* 319 * Get the customized arguments. 320 */ 321 parseArguments(args); 322 323 /* 324 * Start the tests. 325 */ 326 new SelfIssuedCert(); 327 } 328 329 Thread clientThread = null; 330 Thread serverThread = null; 331 /* 332 * Primary constructor, used to drive remainder of the test. 333 * 334 * Fork off the other side, then do your work. 335 */ 336 SelfIssuedCert() throws Exception { 337 if (separateServerThread) { 338 startServer(true); 339 startClient(false); 340 } else { 341 startClient(true); 342 startServer(false); 343 } 344 345 /* 346 * Wait for other side to close down. 347 */ 348 if (separateServerThread) { 349 serverThread.join(); 350 } else { 351 clientThread.join(); 352 } 353 354 /* 355 * When we get here, the test is pretty much over. 356 * 357 * If the main thread excepted, that propagates back 358 * immediately. If the other thread threw an exception, we 359 * should report back. 360 */ 361 if (serverException != null) 362 throw serverException; 363 if (clientException != null) 364 throw clientException; 365 } 366 367 void startServer(boolean newThread) throws Exception { 368 if (newThread) { 369 serverThread = new Thread() { 370 public void run() { 371 try { 372 doServerSide(); 373 } catch (Exception e) { 374 /* 375 * Our server thread just died. 376 * 377 * Release the client, if not active already... 378 */ 379 System.err.println("Server died..."); 380 serverReady = true; 381 serverException = e; 382 } 383 } 384 }; 385 serverThread.start(); 386 } else { 387 doServerSide(); 388 } 389 } 390 391 void startClient(boolean newThread) throws Exception { 392 if (newThread) { 393 clientThread = new Thread() { 394 public void run() { 395 try { 396 doClientSide(); 397 } catch (Exception e) { 398 /* 399 * Our client thread just died. 400 */ 401 System.err.println("Client died..."); 402 clientException = e; 403 } 404 } 405 }; 406 clientThread.start(); 407 } else { 408 doClientSide(); 409 } 410 } 411 412} 413