1 /* 2 * Copyright (c) 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * @test 28 * @bug 7113275 29 * @summary compatibility issue with MD2 trust anchor and old X509TrustManager 30 * 31 * SunJSSE does not support dynamic system properties, no way to re-use 32 * system properties in samevm/agentvm mode. 33 * @run main/othervm TrustTrustedCert PKIX TLSv1.1 34 * @run main/othervm TrustTrustedCert SunX509 TLSv1.1 35 * @run main/othervm TrustTrustedCert PKIX TLSv1.2 36 * @run main/othervm TrustTrustedCert SunX509 TLSv1.2 37 */ 38 39 import java.net.*; 40 import java.util.*; 41 import java.io.*; 42 import javax.net.ssl.*; 43 import java.security.*; 44 import java.security.cert.*; 45 import java.security.spec.*; 46 import java.security.interfaces.*; 47 import sun.misc.BASE64Decoder; 48 49 50 public class TrustTrustedCert { 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 = false; 64 65 /* 66 * Certificates and key used in the test. 67 */ 68 69 // It's a trust anchor signed with MD2 hash function. 70 static String trustedCertStr = 71 "-----BEGIN CERTIFICATE-----\n" + 72 "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" + 73 "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + 74 "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + 75 "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + 76 "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" + 77 "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" + 78 "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" + 79 "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" + 80 "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" + 81 "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + 82 "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" + 83 "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" + 84 "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" + 85 "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" + 86 "-----END CERTIFICATE-----"; 87 88 // The certificate issued by above trust anchor, signed with MD5 89 static String targetCertStr = 90 "-----BEGIN CERTIFICATE-----\n" + 91 "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + 92 "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + 93 "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" + 94 "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + 95 "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" + 96 "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" + 97 "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" + 98 "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" + 99 "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" + 100 "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + 101 "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" + 102 "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" + 103 "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" + 104 "yvudOlX4BkVR0l1K\n" + 105 "-----END CERTIFICATE-----"; 106 107 // Private key in the format of PKCS#8. 108 static String targetPrivateKey = 109 "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" + 110 "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" + 111 "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" + 112 "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" + 113 "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" + 114 "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" + 115 "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" + 116 "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" + 117 "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" + 118 "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" + 119 "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" + 120 "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" + 121 "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" + 122 "njWHoKY3axDQ8OU=\n"; 123 124 125 static char passphrase[] = "passphrase".toCharArray(); 126 127 /* 128 * Is the server ready to serve? 129 */ 130 volatile static boolean serverReady = false; 131 132 /* 133 * Turn on SSL debugging? 134 */ 135 static boolean debug = false; 136 137 /* 138 * Define the server side of the test. 139 * 140 * If the server prematurely exits, serverReady will be set to true 141 * to avoid infinite hangs. 142 */ 143 void doServerSide() throws Exception { 144 SSLContext context = generateSSLContext(); 145 SSLServerSocketFactory sslssf = context.getServerSocketFactory(); 146 SSLServerSocket sslServerSocket = 147 (SSLServerSocket)sslssf.createServerSocket(serverPort); 148 sslServerSocket.setNeedClientAuth(true); 149 serverPort = sslServerSocket.getLocalPort(); 150 151 /* 152 * Signal Client, we're ready for his connect. 153 */ 154 serverReady = true; 155 156 SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept(); 157 InputStream sslIS = sslSocket.getInputStream(); 158 OutputStream sslOS = sslSocket.getOutputStream(); 159 160 sslIS.read(); 161 sslOS.write('A'); 162 sslOS.flush(); 163 164 sslSocket.close(); 165 } 166 167 /* 168 * Define the client side of the test. 169 * 170 * If the server prematurely exits, serverReady will be set to true 171 * to avoid infinite hangs. 172 */ 173 void doClientSide() throws Exception { 174 175 /* 176 * Wait for server to get started. 177 */ 178 while (!serverReady) { 179 Thread.sleep(50); 180 } 181 182 SSLContext context = generateSSLContext(); 183 SSLSocketFactory sslsf = context.getSocketFactory(); 184 185 SSLSocket sslSocket = 186 (SSLSocket)sslsf.createSocket("localhost", serverPort); 187 188 // enable the specified TLS protocol 189 sslSocket.setEnabledProtocols(new String[] {tlsProtocol}); 190 191 InputStream sslIS = sslSocket.getInputStream(); 192 OutputStream sslOS = sslSocket.getOutputStream(); 193 194 sslOS.write('B'); 195 sslOS.flush(); 196 sslIS.read(); 197 198 sslSocket.close(); 199 } 200 201 /* 202 * ============================================================= 203 * The remainder is just support stuff 204 */ 205 private static String tmAlgorithm; // trust manager 206 private static String tlsProtocol; // trust manager 207 208 private static void parseArguments(String[] args) { 209 tmAlgorithm = args[0]; 210 tlsProtocol = args[1]; 211 } 212 213 private static SSLContext generateSSLContext() throws Exception { 214 215 // generate certificate from cert string 216 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 217 218 // create a key store 219 KeyStore ks = KeyStore.getInstance("JKS"); 220 ks.load(null, null); 221 222 // import the trused cert 223 X509Certificate trusedCert = null; 224 ByteArrayInputStream is = 225 new ByteArrayInputStream(trustedCertStr.getBytes()); 226 trusedCert = (X509Certificate)cf.generateCertificate(is); 227 is.close(); 228 229 ks.setCertificateEntry("Trusted RSA Signer", trusedCert); 230 231 // generate the private key. 232 PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( 233 new BASE64Decoder().decodeBuffer(targetPrivateKey)); 234 KeyFactory kf = KeyFactory.getInstance("RSA"); 235 RSAPrivateKey priKey = 236 (RSAPrivateKey)kf.generatePrivate(priKeySpec); 237 238 // generate certificate chain 239 is = new ByteArrayInputStream(targetCertStr.getBytes()); 240 X509Certificate keyCert = (X509Certificate)cf.generateCertificate(is); 241 is.close(); 242 243 X509Certificate[] chain = new X509Certificate[2]; 244 chain[0] = keyCert; 245 chain[1] = trusedCert; 246 247 // import the key entry and the chain 248 ks.setKeyEntry("TheKey", priKey, passphrase, chain); 249 250 // create SSL context 251 TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); 252 tmf.init(ks); 253 254 // create the customized KM and TM 255 NoneExtendedX509TM myTM = 256 new NoneExtendedX509TM(tmf.getTrustManagers()[0]); 257 NoneExtendedX509KM myKM = 258 new NoneExtendedX509KM("TheKey", chain, priKey); 259 260 SSLContext ctx = SSLContext.getInstance(tlsProtocol); 261 // KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); 262 // kmf.init(ks, passphrase); 263 // ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 264 ctx.init(new KeyManager[]{myKM}, new TrustManager[]{myTM}, null); 265 ks = null; 266 267 return ctx; 268 } 269 270 static class NoneExtendedX509TM implements X509TrustManager { 271 X509TrustManager tm; 272 273 NoneExtendedX509TM(TrustManager tm) { 274 this.tm = (X509TrustManager)tm; 275 } 276 277 public void checkClientTrusted(X509Certificate chain[], String authType) 278 throws CertificateException { 279 tm.checkClientTrusted(chain, authType); 280 } 281 282 public void checkServerTrusted(X509Certificate chain[], String authType) 283 throws CertificateException { 284 tm.checkServerTrusted(chain, authType); 285 } 286 287 public X509Certificate[] getAcceptedIssuers() { 288 return tm.getAcceptedIssuers(); 289 } 290 } 291 292 static class NoneExtendedX509KM implements X509KeyManager { 293 private String keyAlias; 294 private X509Certificate[] chain; 295 private PrivateKey privateKey; 296 297 NoneExtendedX509KM(String keyAlias, X509Certificate[] chain, 298 PrivateKey privateKey) { 299 this.keyAlias = keyAlias; 300 this.chain = chain; 301 this.privateKey = privateKey; 302 } 303 304 public String[] getClientAliases(String keyType, Principal[] issuers) { 305 return new String[] {keyAlias}; 306 } 307 308 public String chooseClientAlias(String[] keyType, Principal[] issuers, 309 Socket socket) { 310 return keyAlias; 311 } 312 313 public String[] getServerAliases(String keyType, Principal[] issuers) { 314 return new String[] {keyAlias}; 315 } 316 317 public String chooseServerAlias(String keyType, Principal[] issuers, 318 Socket socket) { 319 return keyAlias; 320 } 321 322 public X509Certificate[] getCertificateChain(String alias) { 323 return chain; 324 } 325 326 public PrivateKey getPrivateKey(String alias) { 327 return privateKey; 328 } 329 } 330 331 332 // use any free port by default 333 volatile int serverPort = 0; 334 335 volatile Exception serverException = null; 336 volatile Exception clientException = null; 337 338 public static void main(String[] args) throws Exception { 339 if (debug) 340 System.setProperty("javax.net.debug", "all"); 341 342 /* 343 * Get the customized arguments. 344 */ 345 parseArguments(args); 346 347 /* 348 * Start the tests. 349 */ 350 new TrustTrustedCert(); 351 } 352 353 Thread clientThread = null; 354 Thread serverThread = null; 355 356 /* 357 * Primary constructor, used to drive remainder of the test. 358 * 359 * Fork off the other side, then do your work. 360 */ 361 TrustTrustedCert() throws Exception { 362 try { 363 if (separateServerThread) { 364 startServer(true); 365 startClient(false); 366 } else { 367 startClient(true); 368 startServer(false); 369 } 370 } catch (Exception e) { 371 // swallow for now. Show later 372 } 373 374 /* 375 * Wait for other side to close down. 376 */ 377 if (separateServerThread) { 378 serverThread.join(); 379 } else { 380 clientThread.join(); 381 } 382 383 /* 384 * When we get here, the test is pretty much over. 385 * Which side threw the error? 386 */ 387 Exception local; 388 Exception remote; 389 String whichRemote; 390 391 if (separateServerThread) { 392 remote = serverException; 393 local = clientException; 394 whichRemote = "server"; 395 } else { 396 remote = clientException; 397 local = serverException; 398 whichRemote = "client"; 399 } 400 401 /* 402 * If both failed, return the curthread's exception, but also 403 * print the remote side Exception 404 */ 405 if ((local != null) && (remote != null)) { 406 System.out.println(whichRemote + " also threw:"); 407 remote.printStackTrace(); 408 System.out.println(); 409 throw local; 410 } 411 412 if (remote != null) { 413 throw remote; 414 } 415 416 if (local != null) { 417 throw local; 418 } 419 } 420 421 void startServer(boolean newThread) throws Exception { 422 if (newThread) { 423 serverThread = new Thread() { 424 public void run() { 425 try { 426 doServerSide(); 427 } catch (Exception e) { 428 /* 429 * Our server thread just died. 430 * 431 * Release the client, if not active already... 432 */ 433 System.err.println("Server died..."); 434 serverReady = true; 435 serverException = e; 436 } 437 } 438 }; 439 serverThread.start(); 440 } else { 441 try { 442 doServerSide(); 443 } catch (Exception e) { 444 serverException = e; 445 } finally { 446 serverReady = true; 447 } 448 } 449 } 450 451 void startClient(boolean newThread) throws Exception { 452 if (newThread) { 453 clientThread = new Thread() { 454 public void run() { 455 try { 456 doClientSide(); 457 } catch (Exception e) { 458 /* 459 * Our client thread just died. 460 */ 461 System.err.println("Client died..."); 462 clientException = e; 463 } 464 } 465 }; 466 clientThread.start(); 467 } else { 468 try { 469 doClientSide(); 470 } catch (Exception e) { 471 clientException = e; 472 } 473 } 474 } 475 }