1 /* 2 * Copyright (c) 2017, 2020, 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 * @test 26 * @bug 8171319 8177569 8182879 8172404 27 * @summary keytool should print out warnings when reading or generating 28 * cert/cert req using weak algorithms 29 * @library /test/lib 30 * @modules java.base/sun.security.tools.keytool 31 * java.base/sun.security.tools 32 * java.base/sun.security.util 33 * @build jdk.test.lib.SecurityTools 34 * jdk.test.lib.Utils 35 * jdk.test.lib.Asserts 36 * jdk.test.lib.JDKToolFinder 37 * jdk.test.lib.JDKToolLauncher 38 * jdk.test.lib.Platform 39 * jdk.test.lib.process.* 40 * @run main/othervm/timeout=600 -Duser.language=en -Duser.country=US WeakAlg 41 */ 42 43 import jdk.test.lib.Asserts; 44 import jdk.test.lib.SecurityTools; 45 import jdk.test.lib.process.OutputAnalyzer; 46 import sun.security.tools.KeyStoreUtil; 47 import sun.security.util.DisabledAlgorithmConstraints; 48 49 import java.io.ByteArrayInputStream; 50 import java.io.ByteArrayOutputStream; 51 import java.io.File; 52 import java.io.IOException; 53 import java.io.InputStream; 54 import java.io.PrintStream; 55 import java.nio.file.Files; 56 import java.nio.file.Paths; 57 import java.nio.file.StandardCopyOption; 58 import java.security.CryptoPrimitive; 59 import java.security.KeyStore; 60 import java.security.cert.X509Certificate; 61 import java.util.Collections; 62 import java.util.EnumSet; 63 import java.util.Set; 64 import java.util.stream.Collectors; 65 import java.util.stream.Stream; 66 67 public class WeakAlg { 68 main(String[] args)69 public static void main(String[] args) throws Throwable { 70 71 rm("ks"); 72 73 // Tests for "disabled" algorithms 74 // -genkeypair, and -printcert, -list -alias, -exportcert 75 // (w/ different formats) 76 checkDisabledGenKeyPair("a", "-keyalg RSA -sigalg MD5withRSA", "MD5withRSA"); 77 checkDisabledGenKeyPair("b", "-keyalg RSA -keysize 512", "512-bit RSA key"); 78 checkDisabledGenKeyPair("c", "-keyalg RSA", null); 79 80 kt("-list") 81 .shouldContain("Warning:") 82 .shouldMatch("<a>.*MD5withRSA.*is disabled") 83 .shouldMatch("<b>.*512-bit RSA key.*is disabled"); 84 kt("-list -v") 85 .shouldContain("Warning:") 86 .shouldMatch("<a>.*MD5withRSA.*is disabled") 87 .shouldContain("MD5withRSA (disabled)") 88 .shouldMatch("<b>.*512-bit RSA key.*is disabled") 89 .shouldContain("512-bit RSA key (disabled)"); 90 91 // Multiple warnings for multiple cert in -printcert 92 // or -list or -exportcert 93 94 // -certreq, -printcertreq, -gencert 95 checkDisabledCertReq("a", "", null); 96 gencert("c-a", "") 97 .shouldNotContain("Warning"); // new sigalg is not weak 98 gencert("c-a", "-sigalg MD2withRSA") 99 .shouldContain("Warning:") 100 .shouldMatch("The generated certificate.*MD2withRSA.*is disabled"); 101 102 checkDisabledCertReq("a", "-sigalg MD5withRSA", "MD5withRSA"); 103 gencert("c-a", "") 104 .shouldContain("Warning:") 105 .shouldMatch("The certificate request.*MD5withRSA.*is disabled"); 106 gencert("c-a", "-sigalg MD2withRSA") 107 .shouldContain("Warning:") 108 .shouldMatch("The certificate request.*MD5withRSA.*is disabled") 109 .shouldMatch("The generated certificate.*MD2withRSA.*is disabled"); 110 111 checkDisabledCertReq("b", "", "512-bit RSA key"); 112 gencert("c-b", "") 113 .shouldContain("Warning:") 114 .shouldMatch("The certificate request.*512-bit RSA key.*is disabled") 115 .shouldMatch("The generated certificate.*512-bit RSA key.*is disabled"); 116 117 checkDisabledCertReq("c", "", null); 118 gencert("a-c", "") 119 .shouldContain("Warning:") 120 .shouldMatch("The issuer.*MD5withRSA.*is disabled"); 121 122 // but the new cert is not weak 123 kt("-printcert -file a-c.cert") 124 .shouldNotContain("Warning") 125 .shouldNotContain("(disabled)"); 126 127 gencert("b-c", "") 128 .shouldContain("Warning:") 129 .shouldMatch("The issuer.*512-bit RSA key.*is disabled"); 130 131 // -importcert 132 checkImport(); 133 134 // -importkeystore 135 checkImportKeyStore(); 136 137 // -gencrl, -printcrl 138 139 checkDisabledGenCRL("a", "", null); 140 checkDisabledGenCRL("a", "-sigalg MD5withRSA", "MD5withRSA"); 141 checkDisabledGenCRL("b", "", "512-bit RSA key"); 142 checkDisabledGenCRL("c", "", null); 143 144 kt("-delete -alias b"); 145 kt("-printcrl -file b.crl") 146 .shouldContain("WARNING: not verified"); 147 148 jksTypeCheck(); 149 150 checkInplaceImportKeyStore(); 151 152 rm("ks"); 153 154 // Tests for "legacy" algorithms 155 // -genkeypair, and -printcert, -list -alias, -exportcert 156 // (w/ different formats) 157 checkWeakGenKeyPair("x", "-keyalg RSA -sigalg SHA1withRSA", "SHA1withRSA"); 158 checkWeakGenKeyPair("y", "-keyalg RSA -keysize 1024", "1024-bit RSA key"); 159 checkWeakGenKeyPair("z", "-keyalg RSA", null); 160 161 kt("-list") 162 .shouldContain("Warning:") 163 .shouldMatch("<x>.*SHA1withRSA.*will be disabled") 164 .shouldMatch("<y>.*1024-bit RSA key.*will be disabled"); 165 kt("-list -v") 166 .shouldContain("Warning:") 167 .shouldMatch("<x>.*SHA1withRSA.*will be disabled") 168 .shouldContain("SHA1withRSA (weak)") 169 .shouldMatch("<y>.*1024-bit RSA key.*will be disabled") 170 .shouldContain("1024-bit RSA key (weak)"); 171 172 // Multiple warnings for multiple cert in -printcert 173 // or -list or -exportcert 174 175 // -certreq, -printcertreq, -gencert 176 checkWeakCertReq("x", "", null); 177 gencert("z-x", "") 178 .shouldNotContain("Warning"); // new sigalg is not weak 179 gencert("z-x", "-sigalg SHA1withRSA") 180 .shouldContain("Warning:") 181 .shouldMatch("The generated certificate.*SHA1withRSA.*will be disabled"); 182 183 checkWeakCertReq("x", "-sigalg SHA1withRSA", "SHA1withRSA"); 184 gencert("z-x", "") 185 .shouldContain("Warning:") 186 .shouldMatch("The certificate request.*SHA1withRSA.*will be disabled"); 187 gencert("z-x", "-sigalg SHA1withRSA") 188 .shouldContain("Warning:") 189 .shouldMatch("The certificate request.*SHA1withRSA.*will be disabled") 190 .shouldMatch("The generated certificate.*SHA1withRSA.*will be disabled"); 191 192 checkWeakCertReq("y", "", "1024-bit RSA key"); 193 gencert("z-y", "") 194 .shouldContain("Warning:") 195 .shouldMatch("The certificate request.*1024-bit RSA key.*will be disabled") 196 .shouldMatch("The generated certificate.*1024-bit RSA key.*will be disabled"); 197 198 checkWeakCertReq("z", "", null); 199 gencert("x-z", "") 200 .shouldContain("Warning:") 201 .shouldMatch("The issuer.*SHA1withRSA.*will be disabled"); 202 203 // but the new cert is not weak 204 kt("-printcert -file x-z.cert") 205 .shouldNotContain("Warning") 206 .shouldNotContain("weak"); 207 208 gencert("y-z", "") 209 .shouldContain("Warning:") 210 .shouldMatch("The issuer.*1024-bit RSA key.*will be disabled"); 211 212 // -gencrl, -printcrl 213 checkWeakGenCRL("x", "", null); 214 checkWeakGenCRL("x", "-sigalg SHA1withRSA", "SHA1withRSA"); 215 checkWeakGenCRL("y", "", "1024-bit RSA key"); 216 checkWeakGenCRL("z", "", null); 217 218 kt("-delete -alias y"); 219 kt("-printcrl -file y.crl") 220 .shouldContain("WARNING: not verified"); 221 222 jksTypeCheck(); 223 } 224 jksTypeCheck()225 static void jksTypeCheck() throws Exception { 226 227 // No warning for cacerts, all certs 228 kt0("-cacerts -list -storepass changeit") 229 .shouldNotContain("proprietary format"); 230 231 rm("ks"); 232 rm("ks2"); 233 234 kt("-genkeypair -alias a -dname CN=A") 235 .shouldNotContain("Warning:"); 236 kt("-list") 237 .shouldNotContain("Warning:"); 238 kt("-list -storetype jks") // no warning if PKCS12 used as JKS 239 .shouldNotContain("Warning:"); 240 kt("-exportcert -alias a -file a.crt") 241 .shouldNotContain("Warning:"); 242 243 // warn if migrating to JKS 244 importkeystore("ks", "ks2", "-deststoretype jks") 245 .shouldContain("JKS keystore uses a proprietary format"); 246 247 rm("ks"); 248 rm("ks2"); 249 rm("ks3"); 250 251 // no warning if all certs 252 kt("-importcert -alias b -file a.crt -storetype jks -noprompt") 253 .shouldNotContain("Warning:"); 254 kt("-genkeypair -alias a -dname CN=A") 255 .shouldContain("JKS keystore uses a proprietary format"); 256 kt("-list") 257 .shouldContain("JKS keystore uses a proprietary format"); 258 kt("-list -storetype pkcs12") // warn if JKS used as PKCS12 259 .shouldContain("JKS keystore uses a proprietary format"); 260 kt("-exportcert -alias a -file a.crt") 261 .shouldContain("JKS keystore uses a proprietary format"); 262 kt("-printcert -file a.crt") // no warning if keystore not touched 263 .shouldNotContain("Warning:"); 264 kt("-certreq -alias a -file a.req") 265 .shouldContain("JKS keystore uses a proprietary format"); 266 kt("-printcertreq -file a.req") // no warning if keystore not touched 267 .shouldNotContain("Warning:"); 268 269 // No warning if migrating from JKS 270 importkeystore("ks", "ks2", "") 271 .shouldNotContain("Warning:"); 272 273 importkeystore("ks", "ks3", "-deststoretype pkcs12") 274 .shouldNotContain("Warning:"); 275 276 rm("ks"); 277 278 kt("-genkeypair -alias a -dname CN=A -storetype jceks") 279 .shouldContain("JCEKS keystore uses a proprietary format"); 280 kt("-list") 281 .shouldContain("JCEKS keystore uses a proprietary format"); 282 kt("-importcert -alias b -file a.crt -noprompt") 283 .shouldContain("JCEKS keystore uses a proprietary format"); 284 kt("-exportcert -alias a -file a.crt") 285 .shouldContain("JCEKS keystore uses a proprietary format"); 286 kt("-printcert -file a.crt") 287 .shouldNotContain("Warning:"); 288 kt("-certreq -alias a -file a.req") 289 .shouldContain("JCEKS keystore uses a proprietary format"); 290 kt("-printcertreq -file a.req") 291 .shouldNotContain("Warning:"); 292 kt("-genseckey -alias c -keyalg AES -keysize 128") 293 .shouldContain("JCEKS keystore uses a proprietary format"); 294 } 295 checkImportKeyStore()296 static void checkImportKeyStore() throws Exception { 297 298 rm("ks2"); 299 rm("ks3"); 300 301 importkeystore("ks", "ks2", "") 302 .shouldContain("3 entries successfully imported") 303 .shouldContain("Warning") 304 .shouldMatch("<b>.*512-bit RSA key.*is disabled") 305 .shouldMatch("<a>.*MD5withRSA.*is disabled"); 306 307 importkeystore("ks", "ks3", "-srcalias a") 308 .shouldContain("Warning") 309 .shouldMatch("<a>.*MD5withRSA.*is disabled"); 310 } 311 checkInplaceImportKeyStore()312 static void checkInplaceImportKeyStore() throws Exception { 313 314 rm("ks"); 315 genkeypair("a", ""); 316 317 // Same type backup 318 importkeystore("ks", "ks", "") 319 .shouldContain("Warning:") 320 .shouldMatch("original.*ks.old"); 321 322 importkeystore("ks", "ks", "") 323 .shouldContain("Warning:") 324 .shouldMatch("original.*ks.old2"); 325 326 importkeystore("ks", "ks", "-srcstoretype jks") // it knows real type 327 .shouldContain("Warning:") 328 .shouldMatch("original.*ks.old3"); 329 330 String cPath = new File("ks").getCanonicalPath(); 331 332 importkeystore("ks", cPath, "") 333 .shouldContain("Warning:") 334 .shouldMatch("original.*ks.old4"); 335 336 // Migration 337 importkeystore("ks", "ks", "-deststoretype jks") 338 .shouldContain("Warning:") 339 .shouldContain("JKS keystore uses a proprietary format") 340 .shouldMatch("Migrated.*JKS.*PKCS12.*ks.old5"); 341 342 Asserts.assertEQ( 343 KeyStore.getInstance( 344 new File("ks"), "changeit".toCharArray()).getType(), 345 "JKS"); 346 347 importkeystore("ks", "ks", "-srcstoretype PKCS12") 348 .shouldContain("Warning:") 349 .shouldNotContain("proprietary format") 350 .shouldMatch("Migrated.*PKCS12.*JKS.*ks.old6"); 351 352 Asserts.assertEQ( 353 KeyStore.getInstance( 354 new File("ks"), "changeit".toCharArray()).getType(), 355 "PKCS12"); 356 357 Asserts.assertEQ( 358 KeyStore.getInstance( 359 new File("ks.old6"), "changeit".toCharArray()).getType(), 360 "JKS"); 361 362 // One password prompt is enough for migration 363 kt0("-importkeystore -srckeystore ks -destkeystore ks", "changeit") 364 .shouldMatch("original.*ks.old7"); 365 366 // But three if importing to a different keystore 367 rm("ks2"); 368 kt0("-importkeystore -srckeystore ks -destkeystore ks2", 369 "changeit") 370 .shouldContain("Keystore password is too short"); 371 372 kt0("-importkeystore -srckeystore ks -destkeystore ks2", 373 "changeit", "changeit", "changeit") 374 .shouldContain("Importing keystore ks to ks2...") 375 .shouldNotContain("original") 376 .shouldNotContain("Migrated"); 377 } 378 checkImport()379 static void checkImport() throws Exception { 380 381 saveStore(); 382 383 // add trusted cert 384 385 // cert already in 386 kt("-importcert -alias d -file a.cert", "no") 387 .shouldContain("Certificate already exists in keystore") 388 .shouldContain("Warning") 389 .shouldMatch("The input.*MD5withRSA.*is disabled") 390 .shouldContain("Do you still want to add it?"); 391 kt("-importcert -alias d -file a.cert -noprompt") 392 .shouldContain("Warning") 393 .shouldMatch("The input.*MD5withRSA.*is disabled") 394 .shouldNotContain("[no]"); 395 396 // cert is self-signed 397 kt("-delete -alias a"); 398 kt("-delete -alias d"); 399 kt("-importcert -alias d -file a.cert", "no") 400 .shouldContain("Warning") 401 .shouldContain("MD5withRSA (disabled)") 402 .shouldMatch("The input.*MD5withRSA.*is disabled") 403 .shouldContain("Trust this certificate?"); 404 kt("-importcert -alias d -file a.cert -noprompt") 405 .shouldContain("Warning") 406 .shouldMatch("The input.*MD5withRSA.*is disabled") 407 .shouldNotContain("[no]"); 408 409 // JDK-8177569: no warning for sigalg of trusted cert 410 String weakSigAlgCA = null; 411 KeyStore ks = KeyStoreUtil.getCacertsKeyStore(); 412 if (ks != null) { 413 DisabledAlgorithmConstraints disabledCheck = 414 new DisabledAlgorithmConstraints( 415 DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS); 416 Set<CryptoPrimitive> sigPrimitiveSet = Collections 417 .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); 418 419 for (String s : Collections.list(ks.aliases())) { 420 if (ks.isCertificateEntry(s)) { 421 X509Certificate c = (X509Certificate)ks.getCertificate(s); 422 String sigAlg = c.getSigAlgName(); 423 if (!disabledCheck.permits(sigPrimitiveSet, sigAlg, null)) { 424 weakSigAlgCA = sigAlg; 425 Files.write(Paths.get("ca.cert"), 426 ks.getCertificate(s).getEncoded()); 427 break; 428 } 429 } 430 } 431 } 432 if (weakSigAlgCA != null) { 433 // The following 2 commands still have a warning on why not using 434 // the -cacerts option directly. 435 kt("-list -keystore " + KeyStoreUtil.getCacerts()) 436 .shouldNotContain("risk"); 437 kt("-list -v -keystore " + KeyStoreUtil.getCacerts()) 438 .shouldNotContain("risk"); 439 440 // -printcert will always show warnings 441 kt("-printcert -file ca.cert") 442 .shouldContain("name: " + weakSigAlgCA + " (disabled)") 443 .shouldContain("Warning") 444 .shouldMatch("The certificate.*" + weakSigAlgCA + ".*is disabled"); 445 kt("-printcert -file ca.cert -trustcacerts") // -trustcacerts useless 446 .shouldContain("name: " + weakSigAlgCA + " (disabled)") 447 .shouldContain("Warning") 448 .shouldMatch("The certificate.*" + weakSigAlgCA + ".*is disabled"); 449 450 // Importing with -trustcacerts ignore CA cert's sig alg 451 kt("-delete -alias d"); 452 kt("-importcert -alias d -trustcacerts -file ca.cert", "no") 453 .shouldContain("Certificate already exists in system-wide CA") 454 .shouldNotContain("risk") 455 .shouldContain("Do you still want to add it to your own keystore?"); 456 kt("-importcert -alias d -trustcacerts -file ca.cert -noprompt") 457 .shouldNotContain("risk") 458 .shouldNotContain("[no]"); 459 460 // but not without -trustcacerts 461 kt("-delete -alias d"); 462 kt("-importcert -alias d -file ca.cert", "no") 463 .shouldContain("name: " + weakSigAlgCA + " (disabled)") 464 .shouldContain("Warning") 465 .shouldMatch("The input.*" + weakSigAlgCA + ".*is disabled") 466 .shouldContain("Trust this certificate?"); 467 kt("-importcert -alias d -file ca.cert -noprompt") 468 .shouldContain("Warning") 469 .shouldMatch("The input.*" + weakSigAlgCA + ".*is disabled") 470 .shouldNotContain("[no]"); 471 } 472 473 // a non self-signed weak cert 474 reStore(); 475 certreq("b", ""); 476 gencert("c-b", ""); 477 kt("-importcert -alias d -file c-b.cert") // weak only, no prompt 478 .shouldContain("Warning") 479 .shouldNotContain("512-bit RSA key (disabled)") 480 .shouldMatch("The input.*512-bit RSA key.*is disabled") 481 .shouldNotContain("[no]"); 482 483 kt("-delete -alias b"); 484 kt("-delete -alias c"); 485 kt("-delete -alias d"); 486 487 kt("-importcert -alias d -file c-b.cert", "no") // weak and not trusted 488 .shouldContain("Warning") 489 .shouldContain("512-bit RSA key (disabled)") 490 .shouldMatch("The input.*512-bit RSA key.*is disabled") 491 .shouldContain("Trust this certificate?"); 492 kt("-importcert -alias d -file c-b.cert -noprompt") 493 .shouldContain("Warning") 494 .shouldMatch("The input.*512-bit RSA key.*is disabled") 495 .shouldNotContain("[no]"); 496 497 // a non self-signed strong cert 498 reStore(); 499 certreq("a", ""); 500 gencert("c-a", ""); 501 kt("-importcert -alias d -file c-a.cert") // trusted 502 .shouldNotContain("Warning") 503 .shouldNotContain("[no]"); 504 505 kt("-delete -alias a"); 506 kt("-delete -alias c"); 507 kt("-delete -alias d"); 508 509 kt("-importcert -alias d -file c-a.cert", "no") // not trusted 510 .shouldNotContain("Warning") 511 .shouldContain("Trust this certificate?"); 512 kt("-importcert -alias d -file c-a.cert -noprompt") 513 .shouldNotContain("Warning") 514 .shouldNotContain("[no]"); 515 516 // install reply 517 518 reStore(); 519 certreq("c", ""); 520 gencert("a-c", ""); 521 kt("-importcert -alias c -file a-c.cert") 522 .shouldContain("Warning") 523 .shouldMatch("Issuer <a>.*MD5withRSA.*is disabled"); 524 525 // JDK-8177569: no warning for sigalg of trusted cert 526 reStore(); 527 // Change a into a TrustedCertEntry 528 kt("-exportcert -alias a -file a.cert"); 529 kt("-delete -alias a"); 530 kt("-importcert -alias a -file a.cert -noprompt"); 531 kt("-list -alias a -v") 532 .shouldNotContain("disabled") 533 .shouldNotContain("Warning"); 534 // This time a is trusted and no warning on its weak sig alg 535 kt("-importcert -alias c -file a-c.cert") 536 .shouldNotContain("Warning"); 537 538 reStore(); 539 540 gencert("a-b", ""); 541 gencert("b-c", ""); 542 543 // Full chain with root 544 cat("a-a-b-c.cert", "b-c.cert", "a-b.cert", "a.cert"); 545 kt("-importcert -alias c -file a-a-b-c.cert") // only weak 546 .shouldContain("Warning") 547 .shouldMatch("Reply #2 of 3.*512-bit RSA key.*is disabled") 548 .shouldMatch("Reply #3 of 3.*MD5withRSA.*is disabled") 549 .shouldNotContain("[no]"); 550 551 // Without root 552 cat("a-b-c.cert", "b-c.cert", "a-b.cert"); 553 kt("-importcert -alias c -file a-b-c.cert") // only weak 554 .shouldContain("Warning") 555 .shouldMatch("Reply #2 of 2.*512-bit RSA key.*is disabled") 556 .shouldMatch("Issuer <a>.*MD5withRSA.*is disabled") 557 .shouldNotContain("[no]"); 558 559 reStore(); 560 gencert("b-a", ""); 561 562 kt("-importcert -alias a -file b-a.cert") 563 .shouldContain("Warning") 564 .shouldMatch("Issuer <b>.*512-bit RSA key.*is disabled") 565 .shouldNotContain("[no]"); 566 567 kt("-importcert -alias a -file c-a.cert") 568 .shouldNotContain("Warning"); 569 570 kt("-importcert -alias b -file c-b.cert") 571 .shouldContain("Warning") 572 .shouldMatch("The input.*512-bit RSA key.*is disabled") 573 .shouldNotContain("[no]"); 574 575 reStore(); 576 gencert("b-a", ""); 577 578 cat("c-b-a.cert", "b-a.cert", "c-b.cert"); 579 580 kt("-printcert -file c-b-a.cert") 581 .shouldContain("Warning") 582 .shouldMatch("The certificate #2 of 2.*512-bit RSA key.*is disabled"); 583 584 kt("-delete -alias b"); 585 586 kt("-importcert -alias a -file c-b-a.cert") 587 .shouldContain("Warning") 588 .shouldMatch("Reply #2 of 2.*512-bit RSA key.*is disabled") 589 .shouldNotContain("[no]"); 590 591 kt("-delete -alias c"); 592 kt("-importcert -alias a -file c-b-a.cert", "no") 593 .shouldContain("Top-level certificate in reply:") 594 .shouldContain("512-bit RSA key (disabled)") 595 .shouldContain("Warning") 596 .shouldMatch("Reply #2 of 2.*512-bit RSA key.*is disabled") 597 .shouldContain("Install reply anyway?"); 598 kt("-importcert -alias a -file c-b-a.cert -noprompt") 599 .shouldContain("Warning") 600 .shouldMatch("Reply #2 of 2.*512-bit RSA key.*is disabled") 601 .shouldNotContain("[no]"); 602 603 reStore(); 604 } 605 cat(String dest, String... src)606 private static void cat(String dest, String... src) throws IOException { 607 System.out.println("---------------------------------------------"); 608 System.out.printf("$ cat "); 609 610 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 611 for (String s : src) { 612 System.out.printf(s + " "); 613 bout.write(Files.readAllBytes(Paths.get(s))); 614 } 615 Files.write(Paths.get(dest), bout.toByteArray()); 616 System.out.println("> " + dest); 617 } 618 checkDisabledGenCRL(String alias, String options, String bad)619 static void checkDisabledGenCRL(String alias, String options, String bad) { 620 621 OutputAnalyzer oa = kt("-gencrl -alias " + alias 622 + " -id 1 -file " + alias + ".crl " + options); 623 if (bad == null) { 624 oa.shouldNotContain("Warning"); 625 } else { 626 oa.shouldContain("Warning") 627 .shouldMatch("The generated CRL.*" + bad + ".*is disabled"); 628 } 629 630 oa = kt("-printcrl -file " + alias + ".crl"); 631 if (bad == null) { 632 oa.shouldNotContain("Warning") 633 .shouldContain("Verified by " + alias + " in keystore") 634 .shouldNotContain("(disabled"); 635 } else { 636 oa.shouldContain("Warning:") 637 .shouldMatch("The CRL.*" + bad + ".*is disabled") 638 .shouldContain("Verified by " + alias + " in keystore") 639 .shouldContain(bad + " (disabled)"); 640 } 641 } 642 checkDisabledCertReq( String alias, String options, String bad)643 static void checkDisabledCertReq( 644 String alias, String options, String bad) { 645 646 OutputAnalyzer oa = certreq(alias, options); 647 if (bad == null) { 648 oa.shouldNotContain("Warning"); 649 } else { 650 oa.shouldContain("Warning") 651 .shouldMatch("The generated certificate request.*" + bad + ".*is disabled"); 652 } 653 654 oa = kt("-printcertreq -file " + alias + ".req"); 655 if (bad == null) { 656 oa.shouldNotContain("Warning") 657 .shouldNotContain("(disabled)"); 658 } else { 659 oa.shouldContain("Warning") 660 .shouldMatch("The certificate request.*" + bad + ".*is disabled") 661 .shouldContain(bad + " (disabled)"); 662 } 663 } 664 checkDisabledGenKeyPair( String alias, String options, String bad)665 static void checkDisabledGenKeyPair( 666 String alias, String options, String bad) { 667 668 OutputAnalyzer oa = genkeypair(alias, options); 669 if (bad == null) { 670 oa.shouldNotContain("Warning"); 671 } else { 672 oa.shouldContain("Warning") 673 .shouldMatch("The generated certificate.*" + bad + ".*is disabled"); 674 } 675 676 oa = kt("-exportcert -alias " + alias + " -file " + alias + ".cert"); 677 if (bad == null) { 678 oa.shouldNotContain("Warning"); 679 } else { 680 oa.shouldContain("Warning") 681 .shouldMatch("The certificate.*" + bad + ".*is disabled"); 682 } 683 684 oa = kt("-exportcert -rfc -alias " + alias + " -file " + alias + ".cert"); 685 if (bad == null) { 686 oa.shouldNotContain("Warning"); 687 } else { 688 oa.shouldContain("Warning") 689 .shouldMatch("The certificate.*" + bad + ".*is disabled"); 690 } 691 692 oa = kt("-printcert -rfc -file " + alias + ".cert"); 693 if (bad == null) { 694 oa.shouldNotContain("Warning"); 695 } else { 696 oa.shouldContain("Warning") 697 .shouldMatch("The certificate.*" + bad + ".*is disabled"); 698 } 699 700 oa = kt("-list -alias " + alias); 701 if (bad == null) { 702 oa.shouldNotContain("Warning"); 703 } else { 704 oa.shouldContain("Warning") 705 .shouldMatch("The certificate.*" + bad + ".*is disabled"); 706 } 707 708 // With cert content 709 710 oa = kt("-printcert -file " + alias + ".cert"); 711 if (bad == null) { 712 oa.shouldNotContain("Warning"); 713 } else { 714 oa.shouldContain("Warning") 715 .shouldContain(bad + " (disabled)") 716 .shouldMatch("The certificate.*" + bad + ".*is disabled"); 717 } 718 719 oa = kt("-list -v -alias " + alias); 720 if (bad == null) { 721 oa.shouldNotContain("Warning"); 722 } else { 723 oa.shouldContain("Warning") 724 .shouldContain(bad + " (disabled)") 725 .shouldMatch("The certificate.*" + bad + ".*is disabled"); 726 } 727 } 728 checkWeakGenKeyPair( String alias, String options, String bad)729 static void checkWeakGenKeyPair( 730 String alias, String options, String bad) { 731 732 OutputAnalyzer oa = genkeypair(alias, options); 733 if (bad == null) { 734 oa.shouldNotContain("Warning"); 735 } else { 736 oa.shouldContain("Warning") 737 .shouldMatch("The generated certificate.*" + bad + ".*will be disabled"); 738 } 739 740 oa = kt("-exportcert -alias " + alias + " -file " + alias + ".cert"); 741 if (bad == null) { 742 oa.shouldNotContain("Warning"); 743 } else { 744 oa.shouldContain("Warning") 745 .shouldMatch("The certificate.*" + bad + ".*will be disabled"); 746 } 747 748 oa = kt("-exportcert -rfc -alias " + alias + " -file " + alias + ".cert"); 749 if (bad == null) { 750 oa.shouldNotContain("Warning"); 751 } else { 752 oa.shouldContain("Warning") 753 .shouldMatch("The certificate.*" + bad + ".*will be disabled"); 754 } 755 756 oa = kt("-printcert -rfc -file " + alias + ".cert"); 757 if (bad == null) { 758 oa.shouldNotContain("Warning"); 759 } else { 760 oa.shouldContain("Warning") 761 .shouldMatch("The certificate.*" + bad + ".*will be disabled"); 762 } 763 764 oa = kt("-list -alias " + alias); 765 if (bad == null) { 766 oa.shouldNotContain("Warning"); 767 } else { 768 oa.shouldContain("Warning") 769 .shouldMatch("The certificate.*" + bad + ".*will be disabled"); 770 } 771 772 // With cert content 773 774 oa = kt("-printcert -file " + alias + ".cert"); 775 if (bad == null) { 776 oa.shouldNotContain("Warning"); 777 } else { 778 oa.shouldContain("Warning") 779 .shouldContain(bad + " (weak)") 780 .shouldMatch("The certificate.*" + bad + ".*will be disabled"); 781 } 782 783 oa = kt("-list -v -alias " + alias); 784 if (bad == null) { 785 oa.shouldNotContain("Warning"); 786 } else { 787 oa.shouldContain("Warning") 788 .shouldContain(bad + " (weak)") 789 .shouldMatch("The certificate.*" + bad + ".*will be disabled"); 790 } 791 } 792 793 checkWeakGenCRL(String alias, String options, String bad)794 static void checkWeakGenCRL(String alias, String options, String bad) { 795 796 OutputAnalyzer oa = kt("-gencrl -alias " + alias 797 + " -id 1 -file " + alias + ".crl " + options); 798 if (bad == null) { 799 oa.shouldNotContain("Warning"); 800 } else { 801 oa.shouldContain("Warning") 802 .shouldMatch("The generated CRL.*" + bad + ".*will be disabled"); 803 } 804 805 oa = kt("-printcrl -file " + alias + ".crl"); 806 if (bad == null) { 807 oa.shouldNotContain("Warning") 808 .shouldContain("Verified by " + alias + " in keystore") 809 .shouldNotContain("(weak"); 810 } else { 811 oa.shouldContain("Warning:") 812 .shouldMatch("The CRL.*" + bad + ".*will be disabled") 813 .shouldContain("Verified by " + alias + " in keystore") 814 .shouldContain(bad + " (weak)"); 815 } 816 } 817 checkWeakCertReq( String alias, String options, String bad)818 static void checkWeakCertReq( 819 String alias, String options, String bad) { 820 821 OutputAnalyzer oa = certreq(alias, options); 822 if (bad == null) { 823 oa.shouldNotContain("Warning"); 824 } else { 825 oa.shouldContain("Warning") 826 .shouldMatch("The generated certificate request.*" + bad + ".*will be disabled"); 827 } 828 829 oa = kt("-printcertreq -file " + alias + ".req"); 830 if (bad == null) { 831 oa.shouldNotContain("Warning") 832 .shouldNotContain("(weak)"); 833 } else { 834 oa.shouldContain("Warning") 835 .shouldMatch("The certificate request.*" + bad + ".*will be disabled") 836 .shouldContain(bad + " (weak)"); 837 } 838 } 839 840 // This is slow, but real keytool process is launched. kt1(String cmd, String... input)841 static OutputAnalyzer kt1(String cmd, String... input) { 842 cmd = "-keystore ks -storepass changeit " + 843 "-keypass changeit " + cmd; 844 System.out.println("---------------------------------------------"); 845 try { 846 SecurityTools.setResponse(input); 847 return SecurityTools.keytool(cmd); 848 } catch (Throwable e) { 849 throw new RuntimeException(e); 850 } 851 } 852 kt(String cmd, String... input)853 static OutputAnalyzer kt(String cmd, String... input) { 854 return kt0("-keystore ks -storepass changeit " + 855 "-keypass changeit " + cmd, input); 856 } 857 858 // Fast keytool execution by directly calling its main() method kt0(String cmd, String... input)859 static OutputAnalyzer kt0(String cmd, String... input) { 860 PrintStream out = System.out; 861 PrintStream err = System.err; 862 InputStream ins = System.in; 863 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 864 ByteArrayOutputStream berr = new ByteArrayOutputStream(); 865 boolean succeed = true; 866 String sout; 867 String serr; 868 try { 869 System.out.println("---------------------------------------------"); 870 System.out.println("$ keytool " + cmd); 871 System.out.println(); 872 String feed = ""; 873 if (input.length > 0) { 874 feed = Stream.of(input).collect(Collectors.joining("\n")) + "\n"; 875 } 876 System.setIn(new ByteArrayInputStream(feed.getBytes())); 877 System.setOut(new PrintStream(bout)); 878 System.setErr(new PrintStream(berr)); 879 sun.security.tools.keytool.Main.main( 880 cmd.trim().split("\\s+")); 881 } catch (Exception e) { 882 // Might be a normal exception when -debug is on or 883 // SecurityException (thrown by jtreg) when System.exit() is called 884 if (!(e instanceof SecurityException)) { 885 e.printStackTrace(); 886 } 887 succeed = false; 888 } finally { 889 System.setOut(out); 890 System.setErr(err); 891 System.setIn(ins); 892 sout = new String(bout.toByteArray()); 893 serr = new String(berr.toByteArray()); 894 System.out.println("STDOUT:\n" + sout + "\nSTDERR:\n" + serr); 895 } 896 if (!succeed) { 897 throw new RuntimeException(); 898 } 899 return new OutputAnalyzer(sout, serr); 900 } 901 importkeystore(String src, String dest, String options)902 static OutputAnalyzer importkeystore(String src, String dest, 903 String options) { 904 return kt0("-importkeystore " 905 + "-srckeystore " + src + " -destkeystore " + dest 906 + " -srcstorepass changeit -deststorepass changeit " + options); 907 } 908 genkeypair(String alias, String options)909 static OutputAnalyzer genkeypair(String alias, String options) { 910 return kt("-genkeypair -alias " + alias + " -dname CN=" + alias 911 + " -storetype PKCS12 " + options); 912 } 913 certreq(String alias, String options)914 static OutputAnalyzer certreq(String alias, String options) { 915 return kt("-certreq -alias " + alias 916 + " -file " + alias + ".req " + options); 917 } 918 exportcert(String alias)919 static OutputAnalyzer exportcert(String alias) { 920 return kt("-exportcert -alias " + alias + " -file " + alias + ".cert"); 921 } 922 gencert(String relation, String options)923 static OutputAnalyzer gencert(String relation, String options) { 924 int pos = relation.indexOf("-"); 925 String issuer = relation.substring(0, pos); 926 String subject = relation.substring(pos + 1); 927 return kt(" -gencert -alias " + issuer + " -infile " + subject 928 + ".req -outfile " + relation + ".cert " + options); 929 } 930 saveStore()931 static void saveStore() throws IOException { 932 System.out.println("---------------------------------------------"); 933 System.out.println("$ cp ks ks2"); 934 Files.copy(Paths.get("ks"), Paths.get("ks2"), 935 StandardCopyOption.REPLACE_EXISTING); 936 } 937 reStore()938 static void reStore() throws IOException { 939 System.out.println("---------------------------------------------"); 940 System.out.println("$ cp ks2 ks"); 941 Files.copy(Paths.get("ks2"), Paths.get("ks"), 942 StandardCopyOption.REPLACE_EXISTING); 943 } 944 rm(String s)945 static void rm(String s) throws IOException { 946 System.out.println("---------------------------------------------"); 947 System.out.println("$ rm " + s); 948 Files.deleteIfExists(Paths.get(s)); 949 } 950 } 951