1 /* 2 * Copyright (c) 2011, 2016, 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 // SunJSSE does not support dynamic system properties, no way to re-use 28 // system properties in samevm/agentvm mode. 29 // 30 31 /* 32 * @test 33 * @bug 7113275 8164846 34 * @summary compatibility issue with MD2 trust anchor and old X509TrustManager 35 * @library /javax/net/ssl/templates 36 * @run main/othervm TrustTrustedCert PKIX TLSv1.1 true 37 * @run main/othervm TrustTrustedCert PKIX TLSv1.1 false 38 * @run main/othervm TrustTrustedCert SunX509 TLSv1.1 false 39 * @run main/othervm TrustTrustedCert PKIX TLSv1.2 false 40 * @run main/othervm TrustTrustedCert SunX509 TLSv1.2 false 41 */ 42 43 import java.net.*; 44 import java.io.*; 45 import javax.net.ssl.*; 46 import java.security.*; 47 import java.security.cert.*; 48 import java.security.spec.*; 49 import java.security.interfaces.*; 50 import java.util.Base64; 51 52 public class TrustTrustedCert extends SSLSocketTemplate { 53 54 /* 55 * Certificates and key used in the test. 56 */ 57 58 // It's a trust anchor signed with MD2 hash function. 59 static String trustedCertStr = 60 "-----BEGIN CERTIFICATE-----\n" + 61 "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" + 62 "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + 63 "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + 64 "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + 65 "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" + 66 "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" + 67 "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" + 68 "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" + 69 "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" + 70 "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + 71 "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" + 72 "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" + 73 "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" + 74 "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" + 75 "-----END CERTIFICATE-----"; 76 77 // The certificate issued by above trust anchor, signed with MD5 78 static String targetCertStr = 79 "-----BEGIN CERTIFICATE-----\n" + 80 "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + 81 "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + 82 "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" + 83 "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + 84 "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" + 85 "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" + 86 "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" + 87 "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" + 88 "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" + 89 "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + 90 "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" + 91 "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" + 92 "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" + 93 "yvudOlX4BkVR0l1K\n" + 94 "-----END CERTIFICATE-----"; 95 96 // Private key in the format of PKCS#8. 97 static String targetPrivateKey = 98 "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" + 99 "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" + 100 "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" + 101 "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" + 102 "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" + 103 "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" + 104 "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" + 105 "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" + 106 "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" + 107 "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" + 108 "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" + 109 "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" + 110 "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" + 111 "njWHoKY3axDQ8OU=\n"; 112 113 static char passphrase[] = "passphrase".toCharArray(); 114 115 @Override 116 protected SSLContext createServerSSLContext() throws Exception { 117 return generateSSLContext(); 118 } 119 120 @Override 121 protected void configureServerSocket(SSLServerSocket socket) { 122 socket.setNeedClientAuth(true); 123 } 124 125 @Override 126 protected void runServerApplication(SSLSocket socket) throws Exception { 127 InputStream sslIS = socket.getInputStream(); 128 OutputStream sslOS = socket.getOutputStream(); 129 130 try { 131 sslIS.read(); 132 sslOS.write('A'); 133 sslOS.flush(); 134 } catch (SSLHandshakeException e) { 135 if (expectFail && !e.toString().contains("certificate_unknown")) { 136 throw new RuntimeException( 137 "Expected to see certificate_unknown in exception output", 138 e); 139 } 140 } 141 } 142 143 @Override 144 protected SSLContext createClientSSLContext() throws Exception { 145 return generateSSLContext(); 146 } 147 148 @Override 149 protected void runClientApplication(SSLSocket socket) throws Exception { 150 // enable the specified TLS protocol 151 socket.setEnabledProtocols(new String[] { tlsProtocol }); 152 153 InputStream sslIS = socket.getInputStream(); 154 OutputStream sslOS = socket.getOutputStream(); 155 156 try { 157 sslOS.write('B'); 158 sslOS.flush(); 159 sslIS.read(); 160 } catch (SSLHandshakeException e) { 161 // focus on the CertPathValidatorException 162 Throwable t = e.getCause().getCause(); 163 if ((t == null) 164 || (expectFail && !t.toString().contains("MD5withRSA"))) { 165 throw new RuntimeException( 166 "Expected to see MD5withRSA in exception output", t); 167 } 168 } 169 } 170 171 /* 172 * ============================================================= 173 * The remainder is just support stuff 174 */ 175 private static String tmAlgorithm; // trust manager 176 private static String tlsProtocol; // trust manager 177 // set this flag to test context of CertificateException 178 private static boolean expectFail; 179 180 private static void parseArguments(String[] args) { 181 tmAlgorithm = args[0]; 182 tlsProtocol = args[1]; 183 expectFail = Boolean.parseBoolean(args[2]); 184 } 185 186 private static SSLContext generateSSLContext() throws Exception { 187 188 // generate certificate from cert string 189 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 190 191 // create a key store 192 KeyStore ks = KeyStore.getInstance("JKS"); 193 ks.load(null, null); 194 195 // import the trused cert 196 X509Certificate trusedCert = null; 197 ByteArrayInputStream is = 198 new ByteArrayInputStream(trustedCertStr.getBytes()); 199 trusedCert = (X509Certificate)cf.generateCertificate(is); 200 is.close(); 201 202 ks.setCertificateEntry("Trusted RSA Signer", trusedCert); 203 204 // generate the private key. 205 PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( 206 Base64.getMimeDecoder().decode(targetPrivateKey)); 207 KeyFactory kf = KeyFactory.getInstance("RSA"); 208 RSAPrivateKey priKey = 209 (RSAPrivateKey)kf.generatePrivate(priKeySpec); 210 211 // generate certificate chain 212 is = new ByteArrayInputStream(targetCertStr.getBytes()); 213 X509Certificate keyCert = (X509Certificate)cf.generateCertificate(is); 214 is.close(); 215 216 X509Certificate[] chain = new X509Certificate[2]; 217 chain[0] = keyCert; 218 chain[1] = trusedCert; 219 220 // import the key entry and the chain 221 ks.setKeyEntry("TheKey", priKey, passphrase, chain); 222 223 // create SSL context 224 TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); 225 tmf.init(ks); 226 227 // create the customized KM and TM 228 NoneExtendedX509TM myTM = 229 new NoneExtendedX509TM(tmf.getTrustManagers()[0]); 230 NoneExtendedX509KM myKM = 231 new NoneExtendedX509KM("TheKey", chain, priKey); 232 233 SSLContext ctx = SSLContext.getInstance(tlsProtocol); 234 // KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); 235 // kmf.init(ks, passphrase); 236 // ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 237 ctx.init(new KeyManager[]{myKM}, new TrustManager[]{myTM}, null); 238 ks = null; 239 240 return ctx; 241 } 242 243 static class NoneExtendedX509TM implements X509TrustManager { 244 X509TrustManager tm; 245 246 NoneExtendedX509TM(TrustManager tm) { 247 this.tm = (X509TrustManager)tm; 248 } 249 250 public void checkClientTrusted(X509Certificate chain[], String authType) 251 throws CertificateException { 252 tm.checkClientTrusted(chain, authType); 253 } 254 255 public void checkServerTrusted(X509Certificate chain[], String authType) 256 throws CertificateException { 257 tm.checkServerTrusted(chain, authType); 258 } 259 260 public X509Certificate[] getAcceptedIssuers() { 261 return tm.getAcceptedIssuers(); 262 } 263 } 264 265 static class NoneExtendedX509KM implements X509KeyManager { 266 private String keyAlias; 267 private X509Certificate[] chain; 268 private PrivateKey privateKey; 269 270 NoneExtendedX509KM(String keyAlias, X509Certificate[] chain, 271 PrivateKey privateKey) { 272 this.keyAlias = keyAlias; 273 this.chain = chain; 274 this.privateKey = privateKey; 275 } 276 277 public String[] getClientAliases(String keyType, Principal[] issuers) { 278 return new String[] {keyAlias}; 279 } 280 281 public String chooseClientAlias(String[] keyType, Principal[] issuers, 282 Socket socket) { 283 return keyAlias; 284 } 285 286 public String[] getServerAliases(String keyType, Principal[] issuers) { 287 return new String[] {keyAlias}; 288 } 289 290 public String chooseServerAlias(String keyType, Principal[] issuers, 291 Socket socket) { 292 return keyAlias; 293 } 294 295 public X509Certificate[] getCertificateChain(String alias) { 296 return chain; 297 } 298 299 public PrivateKey getPrivateKey(String alias) { 300 return privateKey; 301 } 302 } 303 304 public static void main(String[] args) throws Exception { 305 /* 306 * Get the customized arguments. 307 */ 308 parseArguments(args); 309 310 /* 311 * MD5 is used in this test case, don't disable MD5 algorithm. 312 * if expectFail is set, we're testing exception message 313 */ 314 if (!expectFail) { 315 Security.setProperty("jdk.certpath.disabledAlgorithms", 316 "MD2, RSA keySize < 1024"); 317 } 318 Security.setProperty("jdk.tls.disabledAlgorithms", 319 "SSLv3, RC4, DH keySize < 768"); 320 321 /* 322 * Start the tests. 323 */ 324 new TrustTrustedCert().run(); 325 } 326 }