1 /* 2 * Copyright (c) 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 // SunJSSE does not support dynamic system properties, no way to re-use 27 // system properties in samevm/agentvm mode. 28 29 /* 30 * @test 31 * @bug 8139565 32 * @summary Restrict certificates with DSA keys less than 1024 bits 33 * 34 * @run main/othervm DisabledShortDSAKeys PKIX TLSv1.2 35 * @run main/othervm DisabledShortDSAKeys SunX509 TLSv1.2 36 * @run main/othervm DisabledShortDSAKeys PKIX TLSv1.1 37 * @run main/othervm DisabledShortDSAKeys SunX509 TLSv1.1 38 * @run main/othervm DisabledShortDSAKeys PKIX TLSv1 39 * @run main/othervm DisabledShortDSAKeys SunX509 TLSv1 40 * @run main/othervm DisabledShortDSAKeys PKIX SSLv3 41 * @run main/othervm DisabledShortDSAKeys SunX509 SSLv3 42 */ 43 44 import java.net.*; 45 import java.util.*; 46 import java.io.*; 47 import javax.net.ssl.*; 48 import java.security.Security; 49 import java.security.KeyStore; 50 import java.security.KeyFactory; 51 import java.security.cert.Certificate; 52 import java.security.cert.CertificateFactory; 53 import java.security.spec.*; 54 import java.security.interfaces.*; 55 import java.util.Base64; 56 57 58 public class DisabledShortDSAKeys { 59 60 /* 61 * ============================================================= 62 * Set the various variables needed for the tests, then 63 * specify what tests to run on each side. 64 */ 65 66 /* 67 * Should we run the client or server in a separate thread? 68 * Both sides can throw exceptions, but do you have a preference 69 * as to which side should be the main thread. 70 */ 71 static boolean separateServerThread = true; 72 73 /* 74 * Where do we find the keystores? 75 */ 76 // Certificates and key used in the test. 77 static String trustedCertStr = 78 "-----BEGIN CERTIFICATE-----\n" + 79 "MIIDDjCCAs2gAwIBAgIJAO5/hbm1ByJOMAkGByqGSM44BAMwHzELMAkGA1UEBhMC\n" + 80 "VVMxEDAOBgNVBAoTB0V4YW1wbGUwHhcNMTYwMjE2MDQzNTQ2WhcNMzcwMTI2MDQz\n" + 81 "NTQ2WjAfMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXhhbXBsZTCCAbgwggEsBgcq\n" + 82 "hkjOOAQBMIIBHwKBgQC4aSK8nBYdWJtuBkz6yoDyjZnNuGFSpDmx1ggKpLpcnPuw\n" + 83 "YKAbUhqdYhZtaIqQ4aO0T1ZS/HuOM0zvddnMUidFNX3RUvDkvdD/JYOnjqzCm+xW\n" + 84 "U0NFuPHZdapQY5KFk3ugkqZpHLY1StZbu0qugZOZjbBOMwB7cHAbMDuVpEr8DQIV\n" + 85 "AOi+ig+h3okFbWEE9MztiI2+DqNrAoGBAKh2EZbuWU9NoHglhVzfDUoz8CeyW6W6\n" + 86 "rUZuIOQsjWaYOeRPWX0UVAGq9ykIOfamEpurKt4H8ge/pHaL9iazJjonMHOXG12A\n" + 87 "0lALsMDGv22zVaJzXjOBvdPzc87opr0LIVgHASKOcDYjsICKNYPlS2cL3MJoD+bj\n" + 88 "NAR67b90VBbEA4GFAAKBgQCGrkRp2tdj2mZF7Qz0tO6p3xSysbEfN6QZxOJYPTvM\n" + 89 "yIYfLV9Yoy7XaRd/mCpJo/dqmsZMzowtyi+u+enuVpOLKiq/lyCktL+xUzZAjLT+\n" + 90 "9dafHlS1wR3pDSa1spo9xTEi4Ff/DQDHcdGalBxSXX/UdRtSecIYAp5/fkt3QZ5v\n" + 91 "0aOBkTCBjjAdBgNVHQ4EFgQUX4qbP5PgBx1J8BJ8qEgfoKVLSnQwTwYDVR0jBEgw\n" + 92 "RoAUX4qbP5PgBx1J8BJ8qEgfoKVLSnShI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + 93 "VQQKEwdFeGFtcGxlggkA7n+FubUHIk4wDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8E\n" + 94 "BAMCAgQwCQYHKoZIzjgEAwMwADAtAhUAkr5bINXyy/McAx6qwhb6r0/QJUgCFFUP\n" + 95 "CZokA4/NqJIgq8ThpTQAE8SB\n" + 96 "-----END CERTIFICATE-----"; 97 98 static String targetCertStr = 99 "-----BEGIN CERTIFICATE-----\n" + 100 "MIICUjCCAhGgAwIBAgIJAIiDrs/4W8rtMAkGByqGSM44BAMwHzELMAkGA1UEBhMC\n" + 101 "VVMxEDAOBgNVBAoTB0V4YW1wbGUwHhcNMTYwMjE2MDQzNTQ2WhcNMzUxMTAzMDQz\n" + 102 "NTQ2WjA5MQswCQYDVQQGEwJVUzEQMA4GA1UECgwHRXhhbXBsZTEYMBYGA1UEAwwP\n" + 103 "d3d3LmV4YW1wbGUuY29tMIHwMIGoBgcqhkjOOAQBMIGcAkEAs6A0p3TysTtVXGSv\n" + 104 "ThR/8GHpbL49KyWRJBMIlmLc5jl/wxJgnL1t07p4YTOEa6ecyTFos04Z8n2GARmp\n" + 105 "zYlUywIVAJLDcf4JXhZbguRFSQdWwWhZkh+LAkBLCzh3Xvpmc/5CDqU+QHqDcuSk\n" + 106 "5B8+ZHaHRi2KQ00ejilpF2qZpW5JdHe4m3Pggh0MIuaAGX+leM4JKlnObj14A0MA\n" + 107 "AkAYb+DYlFgStFhF1ip7rFzY8K6i/3ellkXI2umI/XVwxUQTHSlk5nFOep5Dfzm9\n" + 108 "pADJwuSe1qGHsHB5LpMZPVpto4GEMIGBMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgPo\n" + 109 "MB0GA1UdDgQWBBT8nsFyccF4q1dtpWE1dkNK5UiXtTAfBgNVHSMEGDAWgBRfips/\n" + 110 "k+AHHUnwEnyoSB+gpUtKdDAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + 111 "CCsGAQUFBwMDMAkGByqGSM44BAMDMAAwLQIUIcIlxpIwaZXdpMC+U076unR1Mp8C\n" + 112 "FQCD/NE8O0xwq57nwFfp7tUvUHYMMA==\n" + 113 "-----END CERTIFICATE-----"; 114 115 // Private key in the format of PKCS#8, key size is 512 bits. 116 static String targetPrivateKey = 117 "MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEAs6A0p3TysTtVXGSvThR/8GHpbL49KyWR\n" + 118 "JBMIlmLc5jl/wxJgnL1t07p4YTOEa6ecyTFos04Z8n2GARmpzYlUywIVAJLDcf4J\n" + 119 "XhZbguRFSQdWwWhZkh+LAkBLCzh3Xvpmc/5CDqU+QHqDcuSk5B8+ZHaHRi2KQ00e\n" + 120 "jilpF2qZpW5JdHe4m3Pggh0MIuaAGX+leM4JKlnObj14BBYCFHB2Wek2g5hpNj5y\n" + 121 "RQfCc6CFO0dv"; 122 123 static char passphrase[] = "passphrase".toCharArray(); 124 125 /* 126 * Is the server ready to serve? 127 */ 128 volatile static boolean serverReady = false; 129 130 /* 131 * Turn on SSL debugging? 132 */ 133 static boolean debug = false; 134 135 /* 136 * Define the server side of the test. 137 * 138 * If the server prematurely exits, serverReady will be set to true 139 * to avoid infinite hangs. 140 */ 141 void doServerSide() throws Exception { 142 SSLContext context = generateSSLContext(null, targetCertStr, 143 targetPrivateKey); 144 SSLServerSocketFactory sslssf = context.getServerSocketFactory(); 145 SSLServerSocket sslServerSocket = 146 (SSLServerSocket)sslssf.createServerSocket(serverPort); 147 serverPort = sslServerSocket.getLocalPort(); 148 149 /* 150 * Signal Client, we're ready for his connect. 151 */ 152 serverReady = true; 153 154 try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) { 155 try (InputStream sslIS = sslSocket.getInputStream()) { 156 sslIS.read(); 157 } 158 159 throw new Exception( 160 "DSA keys shorter than 1024 bits should be disabled"); 161 } catch (SSLHandshakeException sslhe) { 162 // the expected exception, ignore 163 } 164 } 165 166 /* 167 * Define the client side of the test. 168 * 169 * If the server prematurely exits, serverReady will be set to true 170 * to avoid infinite hangs. 171 */ 172 void doClientSide() throws Exception { 173 174 /* 175 * Wait for server to get started. 176 */ 177 while (!serverReady) { 178 Thread.sleep(50); 179 } 180 181 SSLContext context = generateSSLContext(trustedCertStr, null, null); 182 SSLSocketFactory sslsf = context.getSocketFactory(); 183 184 try (SSLSocket sslSocket = 185 (SSLSocket)sslsf.createSocket("localhost", serverPort)) { 186 187 // only enable the target protocol 188 sslSocket.setEnabledProtocols(new String[] {enabledProtocol}); 189 190 // enable a block cipher 191 sslSocket.setEnabledCipherSuites( 192 new String[] {"TLS_DHE_DSS_WITH_AES_128_CBC_SHA"}); 193 194 try (OutputStream sslOS = sslSocket.getOutputStream()) { 195 sslOS.write('B'); 196 sslOS.flush(); 197 } 198 199 throw new Exception( 200 "DSA keys shorter than 1024 bits should be disabled"); 201 } catch (SSLHandshakeException sslhe) { 202 // the expected exception, ignore 203 } 204 } 205 206 /* 207 * ============================================================= 208 * The remainder is just support stuff 209 */ 210 private static String tmAlgorithm; // trust manager 211 private static String enabledProtocol; // the target protocol 212 213 private static void parseArguments(String[] args) { 214 tmAlgorithm = args[0]; 215 enabledProtocol = args[1]; 216 } 217 218 private static SSLContext generateSSLContext(String trustedCertStr, 219 String keyCertStr, String keySpecStr) throws Exception { 220 221 // generate certificate from cert string 222 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 223 224 // create a key store 225 KeyStore ks = KeyStore.getInstance("JKS"); 226 ks.load(null, null); 227 228 // import the trused cert 229 Certificate trusedCert = null; 230 ByteArrayInputStream is = null; 231 if (trustedCertStr != null) { 232 is = new ByteArrayInputStream(trustedCertStr.getBytes()); 233 trusedCert = cf.generateCertificate(is); 234 is.close(); 235 236 ks.setCertificateEntry("DSA Export Signer", trusedCert); 237 } 238 239 if (keyCertStr != null) { 240 // generate the private key. 241 PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( 242 Base64.getMimeDecoder().decode(keySpecStr)); 243 KeyFactory kf = KeyFactory.getInstance("DSA"); 244 DSAPrivateKey priKey = 245 (DSAPrivateKey)kf.generatePrivate(priKeySpec); 246 247 // generate certificate chain 248 is = new ByteArrayInputStream(keyCertStr.getBytes()); 249 Certificate keyCert = cf.generateCertificate(is); 250 is.close(); 251 252 Certificate[] chain = null; 253 if (trusedCert != null) { 254 chain = new Certificate[2]; 255 chain[0] = keyCert; 256 chain[1] = trusedCert; 257 } else { 258 chain = new Certificate[1]; 259 chain[0] = keyCert; 260 } 261 262 // import the key entry. 263 ks.setKeyEntry("Whatever", priKey, passphrase, chain); 264 } 265 266 // create SSL context 267 TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); 268 tmf.init(ks); 269 270 SSLContext ctx = SSLContext.getInstance("TLS"); 271 if (keyCertStr != null && !keyCertStr.isEmpty()) { 272 KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); 273 kmf.init(ks, passphrase); 274 275 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 276 ks = null; 277 } else { 278 ctx.init(null, tmf.getTrustManagers(), null); 279 } 280 281 return ctx; 282 } 283 284 285 // use any free port by default 286 volatile int serverPort = 0; 287 288 volatile Exception serverException = null; 289 volatile Exception clientException = null; 290 291 public static void main(String[] args) throws Exception { 292 if (debug) 293 System.setProperty("javax.net.debug", "all"); 294 295 /* 296 * Get the customized arguments. 297 */ 298 parseArguments(args); 299 300 /* 301 * Start the tests. 302 */ 303 new DisabledShortDSAKeys(); 304 } 305 306 Thread clientThread = null; 307 Thread serverThread = null; 308 309 /* 310 * Primary constructor, used to drive remainder of the test. 311 * 312 * Fork off the other side, then do your work. 313 */ 314 DisabledShortDSAKeys() throws Exception { 315 Exception startException = null; 316 try { 317 if (separateServerThread) { 318 startServer(true); 319 startClient(false); 320 } else { 321 startClient(true); 322 startServer(false); 323 } 324 } catch (Exception e) { 325 startException = e; 326 } 327 328 /* 329 * Wait for other side to close down. 330 */ 331 if (separateServerThread) { 332 if (serverThread != null) { 333 serverThread.join(); 334 } 335 } else { 336 if (clientThread != null) { 337 clientThread.join(); 338 } 339 } 340 341 /* 342 * When we get here, the test is pretty much over. 343 * Which side threw the error? 344 */ 345 Exception local; 346 Exception remote; 347 348 if (separateServerThread) { 349 remote = serverException; 350 local = clientException; 351 } else { 352 remote = clientException; 353 local = serverException; 354 } 355 356 Exception exception = null; 357 358 /* 359 * Check various exception conditions. 360 */ 361 if ((local != null) && (remote != null)) { 362 // If both failed, return the curthread's exception. 363 local.initCause(remote); 364 exception = local; 365 } else if (local != null) { 366 exception = local; 367 } else if (remote != null) { 368 exception = remote; 369 } else if (startException != null) { 370 exception = startException; 371 } 372 373 /* 374 * If there was an exception *AND* a startException, 375 * output it. 376 */ 377 if (exception != null) { 378 if (exception != startException && startException != null) { 379 exception.addSuppressed(startException); 380 } 381 throw exception; 382 } 383 384 // Fall-through: no exception to throw! 385 } 386 387 void startServer(boolean newThread) throws Exception { 388 if (newThread) { 389 serverThread = new Thread() { 390 public void run() { 391 try { 392 doServerSide(); 393 } catch (Exception e) { 394 /* 395 * Our server thread just died. 396 * 397 * Release the client, if not active already... 398 */ 399 System.err.println("Server died..."); 400 serverReady = true; 401 serverException = e; 402 } 403 } 404 }; 405 serverThread.start(); 406 } else { 407 try { 408 doServerSide(); 409 } catch (Exception e) { 410 serverException = e; 411 } finally { 412 serverReady = true; 413 } 414 } 415 } 416 417 void startClient(boolean newThread) throws Exception { 418 if (newThread) { 419 clientThread = new Thread() { 420 public void run() { 421 try { 422 doClientSide(); 423 } catch (Exception e) { 424 /* 425 * Our client thread just died. 426 */ 427 System.err.println("Client died..."); 428 clientException = e; 429 } 430 } 431 }; 432 clientThread.start(); 433 } else { 434 try { 435 doClientSide(); 436 } catch (Exception e) { 437 clientException = e; 438 } 439 } 440 } 441 }