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 MD2InTrustAnchor PKIX TLSv1.1 34 * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.1 35 * @run main/othervm MD2InTrustAnchor PKIX TLSv1.2 36 * @run main/othervm MD2InTrustAnchor 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.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 sun.misc.BASE64Decoder; 50 51 52 public class MD2InTrustAnchor { 53 54 /* 55 * ============================================================= 56 * Set the various variables needed for the tests, then 57 * specify what tests to run on each side. 58 */ 59 60 /* 61 * Should we run the client or server in a separate thread? 62 * Both sides can throw exceptions, but do you have a preference 63 * as to which side should be the main thread. 64 */ 65 static boolean separateServerThread = false; 66 67 /* 68 * Certificates and key used in the test. 69 */ 70 71 // It's a trust anchor signed with MD2 hash function. 72 static String trustedCertStr = 73 "-----BEGIN CERTIFICATE-----\n" + 74 "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" + 75 "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + 76 "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + 77 "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + 78 "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" + 79 "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" + 80 "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" + 81 "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" + 82 "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" + 83 "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + 84 "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" + 85 "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" + 86 "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" + 87 "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" + 88 "-----END CERTIFICATE-----"; 89 90 // The certificate issued by above trust anchor, signed with MD5 91 static String targetCertStr = 92 "-----BEGIN CERTIFICATE-----\n" + 93 "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + 94 "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + 95 "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" + 96 "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + 97 "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" + 98 "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" + 99 "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" + 100 "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" + 101 "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" + 102 "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + 103 "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" + 104 "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" + 105 "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" + 106 "yvudOlX4BkVR0l1K\n" + 107 "-----END CERTIFICATE-----"; 108 109 // Private key in the format of PKCS#8. 110 static String targetPrivateKey = 111 "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" + 112 "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" + 113 "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" + 114 "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" + 115 "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" + 116 "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" + 117 "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" + 118 "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" + 119 "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" + 120 "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" + 121 "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" + 122 "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" + 123 "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" + 124 "njWHoKY3axDQ8OU=\n"; 125 126 127 static char passphrase[] = "passphrase".toCharArray(); 128 129 /* 130 * Is the server ready to serve? 131 */ 132 volatile static boolean serverReady = false; 133 134 /* 135 * Turn on SSL debugging? 136 */ 137 static boolean debug = false; 138 139 /* 140 * Define the server side of the test. 141 * 142 * If the server prematurely exits, serverReady will be set to true 143 * to avoid infinite hangs. 144 */ 145 void doServerSide() throws Exception { 146 SSLContext context = generateSSLContext(trustedCertStr, targetCertStr, 147 targetPrivateKey); 148 SSLServerSocketFactory sslssf = context.getServerSocketFactory(); 149 SSLServerSocket sslServerSocket = 150 (SSLServerSocket)sslssf.createServerSocket(serverPort); 151 sslServerSocket.setNeedClientAuth(true); 152 serverPort = sslServerSocket.getLocalPort(); 153 154 /* 155 * Signal Client, we're ready for his connect. 156 */ 157 serverReady = true; 158 159 SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept(); 160 InputStream sslIS = sslSocket.getInputStream(); 161 OutputStream sslOS = sslSocket.getOutputStream(); 162 163 sslIS.read(); 164 sslOS.write('A'); 165 sslOS.flush(); 166 167 sslSocket.close(); 168 } 169 170 /* 171 * Define the client side of the test. 172 * 173 * If the server prematurely exits, serverReady will be set to true 174 * to avoid infinite hangs. 175 */ 176 void doClientSide() throws Exception { 177 178 /* 179 * Wait for server to get started. 180 */ 181 while (!serverReady) { 182 Thread.sleep(50); 183 } 184 185 SSLContext context = generateSSLContext(trustedCertStr, targetCertStr, 186 targetPrivateKey); 187 SSLSocketFactory sslsf = context.getSocketFactory(); 188 189 SSLSocket sslSocket = 190 (SSLSocket)sslsf.createSocket("localhost", serverPort); 191 192 // enable the specified TLS protocol 193 sslSocket.setEnabledProtocols(new String[] {tlsProtocol}); 194 195 InputStream sslIS = sslSocket.getInputStream(); 196 OutputStream sslOS = sslSocket.getOutputStream(); 197 198 sslOS.write('B'); 199 sslOS.flush(); 200 sslIS.read(); 201 202 sslSocket.close(); 203 } 204 205 /* 206 * ============================================================= 207 * The remainder is just support stuff 208 */ 209 private static String tmAlgorithm; // trust manager 210 private static String tlsProtocol; // trust manager 211 212 private static void parseArguments(String[] args) { 213 tmAlgorithm = args[0]; 214 tlsProtocol = args[1]; 215 } 216 217 private static SSLContext generateSSLContext(String trustedCertStr, 218 String keyCertStr, String keySpecStr) throws Exception { 219 220 // generate certificate from cert string 221 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 222 223 // create a key store 224 KeyStore ks = KeyStore.getInstance("JKS"); 225 ks.load(null, null); 226 227 // import the trused cert 228 Certificate trusedCert = null; 229 ByteArrayInputStream is = null; 230 if (trustedCertStr != null) { 231 is = new ByteArrayInputStream(trustedCertStr.getBytes()); 232 trusedCert = cf.generateCertificate(is); 233 is.close(); 234 235 ks.setCertificateEntry("RSA Export Signer", trusedCert); 236 } 237 238 if (keyCertStr != null) { 239 // generate the private key. 240 PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( 241 new BASE64Decoder().decodeBuffer(keySpecStr)); 242 KeyFactory kf = KeyFactory.getInstance("RSA"); 243 RSAPrivateKey priKey = 244 (RSAPrivateKey)kf.generatePrivate(priKeySpec); 245 246 // generate certificate chain 247 is = new ByteArrayInputStream(keyCertStr.getBytes()); 248 Certificate keyCert = cf.generateCertificate(is); 249 is.close(); 250 251 // It's not allowed to send MD2 signed certificate to peer, 252 // even it may be a trusted certificate. Then we will not 253 // place the trusted certficate in the chain. 254 Certificate[] chain = new Certificate[1]; 255 chain[0] = keyCert; 256 257 // import the key entry. 258 ks.setKeyEntry("Whatever", priKey, passphrase, chain); 259 } 260 261 // create SSL context 262 TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); 263 tmf.init(ks); 264 265 SSLContext ctx = SSLContext.getInstance(tlsProtocol); 266 if (keyCertStr != null && !keyCertStr.isEmpty()) { 267 KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); 268 kmf.init(ks, passphrase); 269 270 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 271 ks = null; 272 } else { 273 ctx.init(null, tmf.getTrustManagers(), null); 274 } 275 276 return ctx; 277 } 278 279 280 // use any free port by default 281 volatile int serverPort = 0; 282 283 volatile Exception serverException = null; 284 volatile Exception clientException = null; 285 286 public static void main(String[] args) throws Exception { 287 if (debug) 288 System.setProperty("javax.net.debug", "all"); 289 290 /* 291 * Get the customized arguments. 292 */ 293 parseArguments(args); 294 295 /* 296 * Start the tests. 297 */ 298 new MD2InTrustAnchor(); 299 } 300 301 Thread clientThread = null; 302 Thread serverThread = null; 303 304 /* 305 * Primary constructor, used to drive remainder of the test. 306 * 307 * Fork off the other side, then do your work. 308 */ 309 MD2InTrustAnchor() throws Exception { 310 try { 311 if (separateServerThread) { 312 startServer(true); 313 startClient(false); 314 } else { 315 startClient(true); 316 startServer(false); 317 } 318 } catch (Exception e) { 319 // swallow for now. Show later 320 } 321 322 /* 323 * Wait for other side to close down. 324 */ 325 if (separateServerThread) { 326 serverThread.join(); 327 } else { 328 clientThread.join(); 329 } 330 331 /* 332 * When we get here, the test is pretty much over. 333 * Which side threw the error? 334 */ 335 Exception local; 336 Exception remote; 337 String whichRemote; 338 339 if (separateServerThread) { 340 remote = serverException; 341 local = clientException; 342 whichRemote = "server"; 343 } else { 344 remote = clientException; 345 local = serverException; 346 whichRemote = "client"; 347 } 348 349 /* 350 * If both failed, return the curthread's exception, but also 351 * print the remote side Exception 352 */ 353 if ((local != null) && (remote != null)) { 354 System.out.println(whichRemote + " also threw:"); 355 remote.printStackTrace(); 356 System.out.println(); 357 throw local; 358 } 359 360 if (remote != null) { 361 throw remote; 362 } 363 364 if (local != null) { 365 throw local; 366 } 367 } 368 369 void startServer(boolean newThread) throws Exception { 370 if (newThread) { 371 serverThread = new Thread() { 372 public void run() { 373 try { 374 doServerSide(); 375 } catch (Exception e) { 376 /* 377 * Our server thread just died. 378 * 379 * Release the client, if not active already... 380 */ 381 System.err.println("Server died..."); 382 serverReady = true; 383 serverException = e; 384 } 385 } 386 }; 387 serverThread.start(); 388 } else { 389 try { 390 doServerSide(); 391 } catch (Exception e) { 392 serverException = e; 393 } finally { 394 serverReady = true; 395 } 396 } 397 } 398 399 void startClient(boolean newThread) throws Exception { 400 if (newThread) { 401 clientThread = new Thread() { 402 public void run() { 403 try { 404 doClientSide(); 405 } catch (Exception e) { 406 /* 407 * Our client thread just died. 408 */ 409 System.err.println("Client died..."); 410 clientException = e; 411 } 412 } 413 }; 414 clientThread.start(); 415 } else { 416 try { 417 doClientSide(); 418 } catch (Exception e) { 419 clientException = e; 420 } 421 } 422 } 423 }