1 /* 2 * Copyright (c) 1997, 2015, 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 package sun.security.tools.keytool; 27 28 import java.io.*; 29 import java.security.CodeSigner; 30 import java.security.KeyStore; 31 import java.security.KeyStoreException; 32 import java.security.MessageDigest; 33 import java.security.Key; 34 import java.security.PublicKey; 35 import java.security.PrivateKey; 36 import java.security.Security; 37 import java.security.Signature; 38 import java.security.Timestamp; 39 import java.security.UnrecoverableEntryException; 40 import java.security.UnrecoverableKeyException; 41 import java.security.Principal; 42 import java.security.Provider; 43 import java.security.cert.Certificate; 44 import java.security.cert.CertificateFactory; 45 import java.security.cert.CertStoreException; 46 import java.security.cert.CRL; 47 import java.security.cert.X509Certificate; 48 import java.security.cert.CertificateException; 49 import java.security.cert.URICertStoreParameters; 50 51 52 import java.text.Collator; 53 import java.text.MessageFormat; 54 import java.util.*; 55 import java.util.jar.JarEntry; 56 import java.util.jar.JarFile; 57 import java.lang.reflect.Constructor; 58 import java.math.BigInteger; 59 import java.net.URI; 60 import java.net.URL; 61 import java.net.URLClassLoader; 62 import java.security.cert.CertStore; 63 64 import java.security.cert.X509CRL; 65 import java.security.cert.X509CRLEntry; 66 import java.security.cert.X509CRLSelector; 67 import javax.security.auth.x500.X500Principal; 68 import java.util.Base64; 69 70 import sun.security.util.KeyUtil; 71 import sun.security.util.ObjectIdentifier; 72 import sun.security.pkcs10.PKCS10; 73 import sun.security.pkcs10.PKCS10Attribute; 74 import sun.security.provider.X509Factory; 75 import sun.security.provider.certpath.ssl.SSLServerCertStore; 76 import sun.security.util.Password; 77 import javax.crypto.KeyGenerator; 78 import javax.crypto.SecretKey; 79 import javax.crypto.SecretKeyFactory; 80 import javax.crypto.spec.PBEKeySpec; 81 82 import sun.security.pkcs.PKCS9Attribute; 83 import sun.security.tools.KeyStoreUtil; 84 import sun.security.tools.PathList; 85 import sun.security.util.DerValue; 86 import sun.security.util.Pem; 87 import sun.security.x509.*; 88 89 import static java.security.KeyStore.*; 90 import static sun.security.tools.keytool.Main.Command.*; 91 import static sun.security.tools.keytool.Main.Option.*; 92 93 /** 94 * This tool manages keystores. 95 * 96 * @author Jan Luehe 97 * 98 * 99 * @see java.security.KeyStore 100 * @see sun.security.provider.KeyProtector 101 * @see sun.security.provider.JavaKeyStore 102 * 103 * @since 1.2 104 */ 105 public final class Main { 106 107 private static final byte[] CRLF = new byte[] {'\r', '\n'}; 108 109 private boolean debug = false; 110 private Command command = null; 111 private String sigAlgName = null; 112 private String keyAlgName = null; 113 private boolean verbose = false; 114 private int keysize = -1; 115 private boolean rfc = false; 116 private long validity = (long)90; 117 private String alias = null; 118 private String dname = null; 119 private String dest = null; 120 private String filename = null; 121 private String infilename = null; 122 private String outfilename = null; 123 private String srcksfname = null; 124 125 // User-specified providers are added before any command is called. 126 // However, they are not removed before the end of the main() method. 127 // If you're calling KeyTool.main() directly in your own Java program, 128 // please programtically add any providers you need and do not specify 129 // them through the command line. 130 131 private Set<Pair <String, String>> providers = null; 132 private String storetype = null; 133 private boolean hasStoretypeOption = false; 134 private String srcProviderName = null; 135 private String providerName = null; 136 private String pathlist = null; 137 private char[] storePass = null; 138 private char[] storePassNew = null; 139 private char[] keyPass = null; 140 private char[] keyPassNew = null; 141 private char[] newPass = null; 142 private char[] destKeyPass = null; 143 private char[] srckeyPass = null; 144 private String ksfname = null; 145 private File ksfile = null; 146 private InputStream ksStream = null; // keystore stream 147 private String sslserver = null; 148 private String jarfile = null; 149 private KeyStore keyStore = null; 150 private boolean token = false; 151 private boolean nullStream = false; 152 private boolean kssave = false; 153 private boolean noprompt = false; 154 private boolean trustcacerts = false; 155 private boolean protectedPath = false; 156 private boolean srcprotectedPath = false; 157 private CertificateFactory cf = null; 158 private KeyStore caks = null; // "cacerts" keystore 159 private char[] srcstorePass = null; 160 private String srcstoretype = null; 161 private Set<char[]> passwords = new HashSet<>(); 162 private String startDate = null; 163 164 private List<String> ids = new ArrayList<>(); // used in GENCRL 165 private List<String> v3ext = new ArrayList<>(); 166 167 enum Command { 168 CERTREQ("Generates.a.certificate.request", 169 ALIAS, SIGALG, FILEOUT, KEYPASS, KEYSTORE, DNAME, 170 STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, 171 PROVIDERARG, PROVIDERPATH, V, PROTECTED), 172 CHANGEALIAS("Changes.an.entry.s.alias", 173 ALIAS, DESTALIAS, KEYPASS, KEYSTORE, STOREPASS, 174 STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, 175 PROVIDERPATH, V, PROTECTED), 176 DELETE("Deletes.an.entry", 177 ALIAS, KEYSTORE, STOREPASS, STORETYPE, 178 PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, 179 PROVIDERPATH, V, PROTECTED), 180 EXPORTCERT("Exports.certificate", 181 RFC, ALIAS, FILEOUT, KEYSTORE, STOREPASS, 182 STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, 183 PROVIDERPATH, V, PROTECTED), 184 GENKEYPAIR("Generates.a.key.pair", 185 ALIAS, KEYALG, KEYSIZE, SIGALG, DESTALIAS, DNAME, 186 STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE, 187 STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, 188 PROVIDERARG, PROVIDERPATH, V, PROTECTED), 189 GENSECKEY("Generates.a.secret.key", 190 ALIAS, KEYPASS, KEYALG, KEYSIZE, KEYSTORE, 191 STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, 192 PROVIDERARG, PROVIDERPATH, V, PROTECTED), 193 GENCERT("Generates.certificate.from.a.certificate.request", 194 RFC, INFILE, OUTFILE, ALIAS, SIGALG, DNAME, 195 STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE, 196 STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, 197 PROVIDERARG, PROVIDERPATH, V, PROTECTED), 198 IMPORTCERT("Imports.a.certificate.or.a.certificate.chain", 199 NOPROMPT, TRUSTCACERTS, PROTECTED, ALIAS, FILEIN, 200 KEYPASS, KEYSTORE, STOREPASS, STORETYPE, 201 PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, 202 PROVIDERPATH, V), 203 IMPORTPASS("Imports.a.password", 204 ALIAS, KEYPASS, KEYALG, KEYSIZE, KEYSTORE, 205 STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, 206 PROVIDERARG, PROVIDERPATH, V, PROTECTED), 207 IMPORTKEYSTORE("Imports.one.or.all.entries.from.another.keystore", 208 SRCKEYSTORE, DESTKEYSTORE, SRCSTORETYPE, 209 DESTSTORETYPE, SRCSTOREPASS, DESTSTOREPASS, 210 SRCPROTECTED, SRCPROVIDERNAME, DESTPROVIDERNAME, 211 SRCALIAS, DESTALIAS, SRCKEYPASS, DESTKEYPASS, 212 NOPROMPT, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, 213 V), 214 KEYPASSWD("Changes.the.key.password.of.an.entry", 215 ALIAS, KEYPASS, NEW, KEYSTORE, STOREPASS, 216 STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, 217 PROVIDERPATH, V), 218 LIST("Lists.entries.in.a.keystore", 219 RFC, ALIAS, KEYSTORE, STOREPASS, STORETYPE, 220 PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, 221 PROVIDERPATH, V, PROTECTED), 222 PRINTCERT("Prints.the.content.of.a.certificate", 223 RFC, FILEIN, SSLSERVER, JARFILE, V), 224 PRINTCERTREQ("Prints.the.content.of.a.certificate.request", 225 FILEIN, V), 226 PRINTCRL("Prints.the.content.of.a.CRL.file", 227 FILEIN, V), 228 STOREPASSWD("Changes.the.store.password.of.a.keystore", 229 NEW, KEYSTORE, STOREPASS, STORETYPE, PROVIDERNAME, 230 PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V), 231 232 // Undocumented start here, KEYCLONE is used a marker in -help; 233 234 KEYCLONE("Clones.a.key.entry", 235 ALIAS, DESTALIAS, KEYPASS, NEW, STORETYPE, 236 KEYSTORE, STOREPASS, PROVIDERNAME, PROVIDERCLASS, 237 PROVIDERARG, PROVIDERPATH, V), 238 SELFCERT("Generates.a.self.signed.certificate", 239 ALIAS, SIGALG, DNAME, STARTDATE, VALIDITY, KEYPASS, 240 STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME, 241 PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V), 242 GENCRL("Generates.CRL", 243 RFC, FILEOUT, ID, 244 ALIAS, SIGALG, EXT, KEYPASS, KEYSTORE, 245 STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, 246 PROVIDERARG, PROVIDERPATH, V, PROTECTED), 247 IDENTITYDB("Imports.entries.from.a.JDK.1.1.x.style.identity.database", 248 FILEIN, STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME, 249 PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V); 250 251 final String description; 252 final Option[] options; 253 final String name; 254 255 String altName; // "genkey" is altName for "genkeypair" 256 257 Command(String d, Option... o) { 258 description = d; 259 options = o; 260 name = "-" + name().toLowerCase(Locale.ENGLISH); 261 } 262 @Override 263 public String toString() { 264 return name; 265 } 266 public String getAltName() { 267 return altName; 268 } 269 public void setAltName(String altName) { 270 this.altName = altName; 271 } 272 public static Command getCommand(String cmd) { 273 for (Command c: Command.values()) { 274 if (collator.compare(cmd, c.name) == 0 275 || (c.altName != null 276 && collator.compare(cmd, c.altName) == 0)) { 277 return c; 278 } 279 } 280 return null; 281 } 282 }; 283 284 static { 285 Command.GENKEYPAIR.setAltName("-genkey"); 286 Command.IMPORTCERT.setAltName("-import"); 287 Command.EXPORTCERT.setAltName("-export"); 288 Command.IMPORTPASS.setAltName("-importpassword"); 289 } 290 291 enum Option { 292 ALIAS("alias", "<alias>", "alias.name.of.the.entry.to.process"), 293 DESTALIAS("destalias", "<destalias>", "destination.alias"), 294 DESTKEYPASS("destkeypass", "<arg>", "destination.key.password"), 295 DESTKEYSTORE("destkeystore", "<destkeystore>", "destination.keystore.name"), 296 DESTPROTECTED("destprotected", null, "destination.keystore.password.protected"), 297 DESTPROVIDERNAME("destprovidername", "<destprovidername>", "destination.keystore.provider.name"), 298 DESTSTOREPASS("deststorepass", "<arg>", "destination.keystore.password"), 299 DESTSTORETYPE("deststoretype", "<deststoretype>", "destination.keystore.type"), 300 DNAME("dname", "<dname>", "distinguished.name"), 301 EXT("ext", "<value>", "X.509.extension"), 302 FILEOUT("file", "<filename>", "output.file.name"), 303 FILEIN("file", "<filename>", "input.file.name"), 304 ID("id", "<id:reason>", "Serial.ID.of.cert.to.revoke"), 305 INFILE("infile", "<filename>", "input.file.name"), 306 KEYALG("keyalg", "<keyalg>", "key.algorithm.name"), 307 KEYPASS("keypass", "<arg>", "key.password"), 308 KEYSIZE("keysize", "<keysize>", "key.bit.size"), 309 KEYSTORE("keystore", "<keystore>", "keystore.name"), 310 NEW("new", "<arg>", "new.password"), 311 NOPROMPT("noprompt", null, "do.not.prompt"), 312 OUTFILE("outfile", "<filename>", "output.file.name"), 313 PROTECTED("protected", null, "password.through.protected.mechanism"), 314 PROVIDERARG("providerarg", "<arg>", "provider.argument"), 315 PROVIDERCLASS("providerclass", "<providerclass>", "provider.class.name"), 316 PROVIDERNAME("providername", "<providername>", "provider.name"), 317 PROVIDERPATH("providerpath", "<pathlist>", "provider.classpath"), 318 RFC("rfc", null, "output.in.RFC.style"), 319 SIGALG("sigalg", "<sigalg>", "signature.algorithm.name"), 320 SRCALIAS("srcalias", "<srcalias>", "source.alias"), 321 SRCKEYPASS("srckeypass", "<arg>", "source.key.password"), 322 SRCKEYSTORE("srckeystore", "<srckeystore>", "source.keystore.name"), 323 SRCPROTECTED("srcprotected", null, "source.keystore.password.protected"), 324 SRCPROVIDERNAME("srcprovidername", "<srcprovidername>", "source.keystore.provider.name"), 325 SRCSTOREPASS("srcstorepass", "<arg>", "source.keystore.password"), 326 SRCSTORETYPE("srcstoretype", "<srcstoretype>", "source.keystore.type"), 327 SSLSERVER("sslserver", "<server[:port]>", "SSL.server.host.and.port"), 328 JARFILE("jarfile", "<filename>", "signed.jar.file"), 329 STARTDATE("startdate", "<startdate>", "certificate.validity.start.date.time"), 330 STOREPASS("storepass", "<arg>", "keystore.password"), 331 STORETYPE("storetype", "<storetype>", "keystore.type"), 332 TRUSTCACERTS("trustcacerts", null, "trust.certificates.from.cacerts"), 333 V("v", null, "verbose.output"), 334 VALIDITY("validity", "<valDays>", "validity.number.of.days"); 335 336 final String name, arg, description; 337 Option(String name, String arg, String description) { 338 this.name = name; 339 this.arg = arg; 340 this.description = description; 341 } 342 @Override 343 public String toString() { 344 return "-" + name; 345 } 346 }; 347 348 private static final Class<?>[] PARAM_STRING = { String.class }; 349 350 private static final String NONE = "NONE"; 351 private static final String P11KEYSTORE = "PKCS11"; 352 private static final String P12KEYSTORE = "PKCS12"; 353 private final String keyAlias = "mykey"; 354 355 // for i18n 356 private static final java.util.ResourceBundle rb = 357 java.util.ResourceBundle.getBundle( 358 "sun.security.tools.keytool.Resources"); 359 private static final Collator collator = Collator.getInstance(); 360 static { 361 // this is for case insensitive string comparisons 362 collator.setStrength(Collator.PRIMARY); 363 }; 364 365 private Main() { } 366 367 public static void main(String[] args) throws Exception { 368 Main kt = new Main(); 369 kt.run(args, System.out); 370 } 371 372 private void run(String[] args, PrintStream out) throws Exception { 373 try { 374 args = parseArgs(args); 375 if (command != null) { 376 doCommands(out); 377 } 378 } catch (Exception e) { 379 System.out.println(rb.getString("keytool.error.") + e); 380 if (verbose) { 381 e.printStackTrace(System.out); 382 } 383 if (!debug) { 384 System.exit(1); 385 } else { 386 throw e; 387 } 388 } finally { 389 for (char[] pass : passwords) { 390 if (pass != null) { 391 Arrays.fill(pass, ' '); 392 pass = null; 393 } 394 } 395 396 if (ksStream != null) { 397 ksStream.close(); 398 } 399 } 400 } 401 402 /** 403 * Parse command line arguments. 404 */ 405 String[] parseArgs(String[] args) throws Exception { 406 407 int i=0; 408 boolean help = args.length == 0; 409 410 String confFile = null; 411 412 for (i=0; i < args.length; i++) { 413 String flags = args[i]; 414 if (flags.startsWith("-")) { 415 if (collator.compare(flags, "-conf") == 0) { 416 if (i == args.length - 1) { 417 errorNeedArgument(flags); 418 } 419 confFile = args[++i]; 420 } else { 421 Command c = Command.getCommand(flags); 422 if (c != null) command = c; 423 } 424 } 425 } 426 427 if (confFile != null && command != null) { 428 args = KeyStoreUtil.expandArgs("keytool", confFile, 429 command.toString(), 430 command.getAltName(), args); 431 } 432 433 debug = Arrays.stream(args).anyMatch( 434 x -> collator.compare(x, "-debug") == 0); 435 436 if (debug) { 437 // No need to localize debug output 438 System.out.println("Command line args: " + 439 Arrays.toString(args)); 440 } 441 442 for (i=0; (i < args.length) && args[i].startsWith("-"); i++) { 443 444 String flags = args[i]; 445 446 // Check if the last option needs an arg 447 if (i == args.length - 1) { 448 for (Option option: Option.values()) { 449 // Only options with an arg need to be checked 450 if (collator.compare(flags, option.toString()) == 0) { 451 if (option.arg != null) errorNeedArgument(flags); 452 break; 453 } 454 } 455 } 456 457 /* 458 * Check modifiers 459 */ 460 String modifier = null; 461 int pos = flags.indexOf(':'); 462 if (pos > 0) { 463 modifier = flags.substring(pos+1); 464 flags = flags.substring(0, pos); 465 } 466 467 /* 468 * command modes 469 */ 470 Command c = Command.getCommand(flags); 471 472 if (c != null) { 473 command = c; 474 } else if (collator.compare(flags, "-help") == 0) { 475 help = true; 476 } else if (collator.compare(flags, "-conf") == 0) { 477 i++; 478 } 479 480 /* 481 * specifiers 482 */ 483 else if (collator.compare(flags, "-keystore") == 0 || 484 collator.compare(flags, "-destkeystore") == 0) { 485 ksfname = args[++i]; 486 } else if (collator.compare(flags, "-storepass") == 0 || 487 collator.compare(flags, "-deststorepass") == 0) { 488 storePass = getPass(modifier, args[++i]); 489 passwords.add(storePass); 490 } else if (collator.compare(flags, "-storetype") == 0 || 491 collator.compare(flags, "-deststoretype") == 0) { 492 storetype = args[++i]; 493 hasStoretypeOption = true; 494 } else if (collator.compare(flags, "-srcstorepass") == 0) { 495 srcstorePass = getPass(modifier, args[++i]); 496 passwords.add(srcstorePass); 497 } else if (collator.compare(flags, "-srcstoretype") == 0) { 498 srcstoretype = args[++i]; 499 hasStoretypeOption = true; 500 } else if (collator.compare(flags, "-srckeypass") == 0) { 501 srckeyPass = getPass(modifier, args[++i]); 502 passwords.add(srckeyPass); 503 } else if (collator.compare(flags, "-srcprovidername") == 0) { 504 srcProviderName = args[++i]; 505 } else if (collator.compare(flags, "-providername") == 0 || 506 collator.compare(flags, "-destprovidername") == 0) { 507 providerName = args[++i]; 508 } else if (collator.compare(flags, "-providerpath") == 0) { 509 pathlist = args[++i]; 510 } else if (collator.compare(flags, "-keypass") == 0) { 511 keyPass = getPass(modifier, args[++i]); 512 passwords.add(keyPass); 513 } else if (collator.compare(flags, "-new") == 0) { 514 newPass = getPass(modifier, args[++i]); 515 passwords.add(newPass); 516 } else if (collator.compare(flags, "-destkeypass") == 0) { 517 destKeyPass = getPass(modifier, args[++i]); 518 passwords.add(destKeyPass); 519 } else if (collator.compare(flags, "-alias") == 0 || 520 collator.compare(flags, "-srcalias") == 0) { 521 alias = args[++i]; 522 } else if (collator.compare(flags, "-dest") == 0 || 523 collator.compare(flags, "-destalias") == 0) { 524 dest = args[++i]; 525 } else if (collator.compare(flags, "-dname") == 0) { 526 dname = args[++i]; 527 } else if (collator.compare(flags, "-keysize") == 0) { 528 keysize = Integer.parseInt(args[++i]); 529 } else if (collator.compare(flags, "-keyalg") == 0) { 530 keyAlgName = args[++i]; 531 } else if (collator.compare(flags, "-sigalg") == 0) { 532 sigAlgName = args[++i]; 533 } else if (collator.compare(flags, "-startdate") == 0) { 534 startDate = args[++i]; 535 } else if (collator.compare(flags, "-validity") == 0) { 536 validity = Long.parseLong(args[++i]); 537 } else if (collator.compare(flags, "-ext") == 0) { 538 v3ext.add(args[++i]); 539 } else if (collator.compare(flags, "-id") == 0) { 540 ids.add(args[++i]); 541 } else if (collator.compare(flags, "-file") == 0) { 542 filename = args[++i]; 543 } else if (collator.compare(flags, "-infile") == 0) { 544 infilename = args[++i]; 545 } else if (collator.compare(flags, "-outfile") == 0) { 546 outfilename = args[++i]; 547 } else if (collator.compare(flags, "-sslserver") == 0) { 548 sslserver = args[++i]; 549 } else if (collator.compare(flags, "-jarfile") == 0) { 550 jarfile = args[++i]; 551 } else if (collator.compare(flags, "-srckeystore") == 0) { 552 srcksfname = args[++i]; 553 } else if ((collator.compare(flags, "-provider") == 0) || 554 (collator.compare(flags, "-providerclass") == 0)) { 555 if (providers == null) { 556 providers = new HashSet<Pair <String, String>> (3); 557 } 558 String providerClass = args[++i]; 559 String providerArg = null; 560 561 if (args.length > (i+1)) { 562 flags = args[i+1]; 563 if (collator.compare(flags, "-providerarg") == 0) { 564 if (args.length == (i+2)) errorNeedArgument(flags); 565 providerArg = args[i+2]; 566 i += 2; 567 } 568 } 569 providers.add( 570 Pair.of(providerClass, providerArg)); 571 } 572 573 /* 574 * options 575 */ 576 else if (collator.compare(flags, "-v") == 0) { 577 verbose = true; 578 } else if (collator.compare(flags, "-debug") == 0) { 579 // Already processed 580 } else if (collator.compare(flags, "-rfc") == 0) { 581 rfc = true; 582 } else if (collator.compare(flags, "-noprompt") == 0) { 583 noprompt = true; 584 } else if (collator.compare(flags, "-trustcacerts") == 0) { 585 trustcacerts = true; 586 } else if (collator.compare(flags, "-protected") == 0 || 587 collator.compare(flags, "-destprotected") == 0) { 588 protectedPath = true; 589 } else if (collator.compare(flags, "-srcprotected") == 0) { 590 srcprotectedPath = true; 591 } else { 592 System.err.println(rb.getString("Illegal.option.") + flags); 593 tinyHelp(); 594 } 595 } 596 597 if (i<args.length) { 598 System.err.println(rb.getString("Illegal.option.") + args[i]); 599 tinyHelp(); 600 } 601 602 if (command == null) { 603 if (help) { 604 usage(); 605 } else { 606 System.err.println(rb.getString("Usage.error.no.command.provided")); 607 tinyHelp(); 608 } 609 } else if (help) { 610 usage(); 611 command = null; 612 } 613 614 return args; 615 } 616 617 boolean isKeyStoreRelated(Command cmd) { 618 return cmd != PRINTCERT && cmd != PRINTCERTREQ; 619 } 620 621 622 /** 623 * Execute the commands. 624 */ 625 void doCommands(PrintStream out) throws Exception { 626 if (storetype == null) { 627 storetype = KeyStore.getDefaultType(); 628 } 629 storetype = KeyStoreUtil.niceStoreTypeName(storetype); 630 631 if (srcstoretype == null) { 632 srcstoretype = KeyStore.getDefaultType(); 633 } 634 srcstoretype = KeyStoreUtil.niceStoreTypeName(srcstoretype); 635 636 if (P11KEYSTORE.equalsIgnoreCase(storetype) || 637 KeyStoreUtil.isWindowsKeyStore(storetype)) { 638 token = true; 639 if (ksfname == null) { 640 ksfname = NONE; 641 } 642 } 643 if (NONE.equals(ksfname)) { 644 nullStream = true; 645 } 646 647 if (token && !nullStream) { 648 System.err.println(MessageFormat.format(rb.getString 649 (".keystore.must.be.NONE.if.storetype.is.{0}"), storetype)); 650 System.err.println(); 651 tinyHelp(); 652 } 653 654 if (token && 655 (command == KEYPASSWD || command == STOREPASSWD)) { 656 throw new UnsupportedOperationException(MessageFormat.format(rb.getString 657 (".storepasswd.and.keypasswd.commands.not.supported.if.storetype.is.{0}"), storetype)); 658 } 659 660 if (P12KEYSTORE.equalsIgnoreCase(storetype) && command == KEYPASSWD) { 661 throw new UnsupportedOperationException(rb.getString 662 (".keypasswd.commands.not.supported.if.storetype.is.PKCS12")); 663 } 664 665 if (token && (keyPass != null || newPass != null || destKeyPass != null)) { 666 throw new IllegalArgumentException(MessageFormat.format(rb.getString 667 (".keypass.and.new.can.not.be.specified.if.storetype.is.{0}"), storetype)); 668 } 669 670 if (protectedPath) { 671 if (storePass != null || keyPass != null || 672 newPass != null || destKeyPass != null) { 673 throw new IllegalArgumentException(rb.getString 674 ("if.protected.is.specified.then.storepass.keypass.and.new.must.not.be.specified")); 675 } 676 } 677 678 if (srcprotectedPath) { 679 if (srcstorePass != null || srckeyPass != null) { 680 throw new IllegalArgumentException(rb.getString 681 ("if.srcprotected.is.specified.then.srcstorepass.and.srckeypass.must.not.be.specified")); 682 } 683 } 684 685 if (KeyStoreUtil.isWindowsKeyStore(storetype)) { 686 if (storePass != null || keyPass != null || 687 newPass != null || destKeyPass != null) { 688 throw new IllegalArgumentException(rb.getString 689 ("if.keystore.is.not.password.protected.then.storepass.keypass.and.new.must.not.be.specified")); 690 } 691 } 692 693 if (KeyStoreUtil.isWindowsKeyStore(srcstoretype)) { 694 if (srcstorePass != null || srckeyPass != null) { 695 throw new IllegalArgumentException(rb.getString 696 ("if.source.keystore.is.not.password.protected.then.srcstorepass.and.srckeypass.must.not.be.specified")); 697 } 698 } 699 700 if (validity <= (long)0) { 701 throw new Exception 702 (rb.getString("Validity.must.be.greater.than.zero")); 703 } 704 705 // Try to load and install specified provider 706 if (providers != null) { 707 ClassLoader cl = null; 708 if (pathlist != null) { 709 String path = null; 710 path = PathList.appendPath( 711 path, System.getProperty("java.class.path")); 712 path = PathList.appendPath( 713 path, System.getProperty("env.class.path")); 714 path = PathList.appendPath(path, pathlist); 715 716 URL[] urls = PathList.pathToURLs(path); 717 cl = new URLClassLoader(urls); 718 } else { 719 cl = ClassLoader.getSystemClassLoader(); 720 } 721 722 for (Pair <String, String> provider: providers) { 723 String provName = provider.fst; 724 Class<?> provClass; 725 if (cl != null) { 726 provClass = cl.loadClass(provName); 727 } else { 728 provClass = Class.forName(provName); 729 } 730 731 @SuppressWarnings("deprecation") 732 Object obj = provClass.newInstance(); 733 if (!(obj instanceof Provider)) { 734 MessageFormat form = new MessageFormat 735 (rb.getString("provName.not.a.provider")); 736 Object[] source = {provName}; 737 throw new Exception(form.format(source)); 738 } 739 Provider p = (Provider) obj; 740 String provArg = provider.snd; 741 if (provArg != null) { 742 p = p.configure(provArg); 743 } 744 Security.addProvider(p); 745 } 746 } 747 748 if (command == LIST && verbose && rfc) { 749 System.err.println(rb.getString 750 ("Must.not.specify.both.v.and.rfc.with.list.command")); 751 tinyHelp(); 752 } 753 754 // Make sure provided passwords are at least 6 characters long 755 if (command == GENKEYPAIR && keyPass!=null && keyPass.length < 6) { 756 throw new Exception(rb.getString 757 ("Key.password.must.be.at.least.6.characters")); 758 } 759 if (newPass != null && newPass.length < 6) { 760 throw new Exception(rb.getString 761 ("New.password.must.be.at.least.6.characters")); 762 } 763 if (destKeyPass != null && destKeyPass.length < 6) { 764 throw new Exception(rb.getString 765 ("New.password.must.be.at.least.6.characters")); 766 } 767 768 // Check if keystore exists. 769 // If no keystore has been specified at the command line, try to use 770 // the default, which is located in $HOME/.keystore. 771 // If the command is "genkey", "identitydb", "import", or "printcert", 772 // it is OK not to have a keystore. 773 if (isKeyStoreRelated(command)) { 774 if (ksfname == null) { 775 ksfname = System.getProperty("user.home") + File.separator 776 + ".keystore"; 777 } 778 779 if (!nullStream) { 780 try { 781 ksfile = new File(ksfname); 782 // Check if keystore file is empty 783 if (ksfile.exists() && ksfile.length() == 0) { 784 throw new Exception(rb.getString 785 ("Keystore.file.exists.but.is.empty.") + ksfname); 786 } 787 ksStream = new FileInputStream(ksfile); 788 } catch (FileNotFoundException e) { 789 if (command != GENKEYPAIR && 790 command != GENSECKEY && 791 command != IDENTITYDB && 792 command != IMPORTCERT && 793 command != IMPORTPASS && 794 command != IMPORTKEYSTORE && 795 command != PRINTCRL) { 796 throw new Exception(rb.getString 797 ("Keystore.file.does.not.exist.") + ksfname); 798 } 799 } 800 } 801 } 802 803 if ((command == KEYCLONE || command == CHANGEALIAS) 804 && dest == null) { 805 dest = getAlias("destination"); 806 if ("".equals(dest)) { 807 throw new Exception(rb.getString 808 ("Must.specify.destination.alias")); 809 } 810 } 811 812 if (command == DELETE && alias == null) { 813 alias = getAlias(null); 814 if ("".equals(alias)) { 815 throw new Exception(rb.getString("Must.specify.alias")); 816 } 817 } 818 819 // Create new keystore 820 // Probe for keystore type when filename is available 821 if (ksfile != null && ksStream != null && providerName == null && 822 hasStoretypeOption == false) { 823 keyStore = KeyStore.getInstance(ksfile, storePass); 824 } else { 825 if (providerName == null) { 826 keyStore = KeyStore.getInstance(storetype); 827 } else { 828 keyStore = KeyStore.getInstance(storetype, providerName); 829 } 830 831 /* 832 * Load the keystore data. 833 * 834 * At this point, it's OK if no keystore password has been provided. 835 * We want to make sure that we can load the keystore data, i.e., 836 * the keystore data has the right format. If we cannot load the 837 * keystore, why bother asking the user for his or her password? 838 * Only if we were able to load the keystore, and no keystore 839 * password has been provided, will we prompt the user for the 840 * keystore password to verify the keystore integrity. 841 * This means that the keystore is loaded twice: first load operation 842 * checks the keystore format, second load operation verifies the 843 * keystore integrity. 844 * 845 * If the keystore password has already been provided (at the 846 * command line), however, the keystore is loaded only once, and the 847 * keystore format and integrity are checked "at the same time". 848 * 849 * Null stream keystores are loaded later. 850 */ 851 if (!nullStream) { 852 keyStore.load(ksStream, storePass); 853 if (ksStream != null) { 854 ksStream.close(); 855 } 856 } 857 } 858 859 // All commands that create or modify the keystore require a keystore 860 // password. 861 862 if (nullStream && storePass != null) { 863 keyStore.load(null, storePass); 864 } else if (!nullStream && storePass != null) { 865 // If we are creating a new non nullStream-based keystore, 866 // insist that the password be at least 6 characters 867 if (ksStream == null && storePass.length < 6) { 868 throw new Exception(rb.getString 869 ("Keystore.password.must.be.at.least.6.characters")); 870 } 871 } else if (storePass == null) { 872 873 // only prompt if (protectedPath == false) 874 875 if (!protectedPath && !KeyStoreUtil.isWindowsKeyStore(storetype) && 876 (command == CERTREQ || 877 command == DELETE || 878 command == GENKEYPAIR || 879 command == GENSECKEY || 880 command == IMPORTCERT || 881 command == IMPORTPASS || 882 command == IMPORTKEYSTORE || 883 command == KEYCLONE || 884 command == CHANGEALIAS || 885 command == SELFCERT || 886 command == STOREPASSWD || 887 command == KEYPASSWD || 888 command == IDENTITYDB)) { 889 int count = 0; 890 do { 891 if (command == IMPORTKEYSTORE) { 892 System.err.print 893 (rb.getString("Enter.destination.keystore.password.")); 894 } else { 895 System.err.print 896 (rb.getString("Enter.keystore.password.")); 897 } 898 System.err.flush(); 899 storePass = Password.readPassword(System.in); 900 passwords.add(storePass); 901 902 // If we are creating a new non nullStream-based keystore, 903 // insist that the password be at least 6 characters 904 if (!nullStream && (storePass == null || storePass.length < 6)) { 905 System.err.println(rb.getString 906 ("Keystore.password.is.too.short.must.be.at.least.6.characters")); 907 storePass = null; 908 } 909 910 // If the keystore file does not exist and needs to be 911 // created, the storepass should be prompted twice. 912 if (storePass != null && !nullStream && ksStream == null) { 913 System.err.print(rb.getString("Re.enter.new.password.")); 914 char[] storePassAgain = Password.readPassword(System.in); 915 passwords.add(storePassAgain); 916 if (!Arrays.equals(storePass, storePassAgain)) { 917 System.err.println 918 (rb.getString("They.don.t.match.Try.again")); 919 storePass = null; 920 } 921 } 922 923 count++; 924 } while ((storePass == null) && count < 3); 925 926 927 if (storePass == null) { 928 System.err.println 929 (rb.getString("Too.many.failures.try.later")); 930 return; 931 } 932 } else if (!protectedPath 933 && !KeyStoreUtil.isWindowsKeyStore(storetype) 934 && isKeyStoreRelated(command)) { 935 // here we have EXPORTCERT and LIST (info valid until STOREPASSWD) 936 if (command != PRINTCRL) { 937 System.err.print(rb.getString("Enter.keystore.password.")); 938 System.err.flush(); 939 storePass = Password.readPassword(System.in); 940 passwords.add(storePass); 941 } 942 } 943 944 // Now load a nullStream-based keystore, 945 // or verify the integrity of an input stream-based keystore 946 if (nullStream) { 947 keyStore.load(null, storePass); 948 } else if (ksStream != null) { 949 ksStream = new FileInputStream(ksfile); 950 keyStore.load(ksStream, storePass); 951 ksStream.close(); 952 } 953 } 954 955 if (storePass != null && P12KEYSTORE.equalsIgnoreCase(storetype)) { 956 MessageFormat form = new MessageFormat(rb.getString( 957 "Warning.Different.store.and.key.passwords.not.supported.for.PKCS12.KeyStores.Ignoring.user.specified.command.value.")); 958 if (keyPass != null && !Arrays.equals(storePass, keyPass)) { 959 Object[] source = {"-keypass"}; 960 System.err.println(form.format(source)); 961 keyPass = storePass; 962 } 963 if (newPass != null && !Arrays.equals(storePass, newPass)) { 964 Object[] source = {"-new"}; 965 System.err.println(form.format(source)); 966 newPass = storePass; 967 } 968 if (destKeyPass != null && !Arrays.equals(storePass, destKeyPass)) { 969 Object[] source = {"-destkeypass"}; 970 System.err.println(form.format(source)); 971 destKeyPass = storePass; 972 } 973 } 974 975 // Create a certificate factory 976 if (command == PRINTCERT || command == IMPORTCERT 977 || command == IDENTITYDB || command == PRINTCRL) { 978 cf = CertificateFactory.getInstance("X509"); 979 } 980 981 if (trustcacerts) { 982 caks = KeyStoreUtil.getCacertsKeyStore(); 983 } 984 985 // Perform the specified command 986 if (command == CERTREQ) { 987 if (filename != null) { 988 try (PrintStream ps = new PrintStream(new FileOutputStream 989 (filename))) { 990 doCertReq(alias, sigAlgName, ps); 991 } 992 } else { 993 doCertReq(alias, sigAlgName, out); 994 } 995 if (verbose && filename != null) { 996 MessageFormat form = new MessageFormat(rb.getString 997 ("Certification.request.stored.in.file.filename.")); 998 Object[] source = {filename}; 999 System.err.println(form.format(source)); 1000 System.err.println(rb.getString("Submit.this.to.your.CA")); 1001 } 1002 } else if (command == DELETE) { 1003 doDeleteEntry(alias); 1004 kssave = true; 1005 } else if (command == EXPORTCERT) { 1006 if (filename != null) { 1007 try (PrintStream ps = new PrintStream(new FileOutputStream 1008 (filename))) { 1009 doExportCert(alias, ps); 1010 } 1011 } else { 1012 doExportCert(alias, out); 1013 } 1014 if (filename != null) { 1015 MessageFormat form = new MessageFormat(rb.getString 1016 ("Certificate.stored.in.file.filename.")); 1017 Object[] source = {filename}; 1018 System.err.println(form.format(source)); 1019 } 1020 } else if (command == GENKEYPAIR) { 1021 if (keyAlgName == null) { 1022 keyAlgName = "DSA"; 1023 } 1024 doGenKeyPair(alias, dname, keyAlgName, keysize, sigAlgName); 1025 kssave = true; 1026 } else if (command == GENSECKEY) { 1027 if (keyAlgName == null) { 1028 keyAlgName = "DES"; 1029 } 1030 doGenSecretKey(alias, keyAlgName, keysize); 1031 kssave = true; 1032 } else if (command == IMPORTPASS) { 1033 if (keyAlgName == null) { 1034 keyAlgName = "PBE"; 1035 } 1036 // password is stored as a secret key 1037 doGenSecretKey(alias, keyAlgName, keysize); 1038 kssave = true; 1039 } else if (command == IDENTITYDB) { 1040 if (filename != null) { 1041 try (InputStream inStream = new FileInputStream(filename)) { 1042 doImportIdentityDatabase(inStream); 1043 } 1044 } else { 1045 doImportIdentityDatabase(System.in); 1046 } 1047 } else if (command == IMPORTCERT) { 1048 InputStream inStream = System.in; 1049 if (filename != null) { 1050 inStream = new FileInputStream(filename); 1051 } 1052 String importAlias = (alias!=null)?alias:keyAlias; 1053 try { 1054 if (keyStore.entryInstanceOf( 1055 importAlias, KeyStore.PrivateKeyEntry.class)) { 1056 kssave = installReply(importAlias, inStream); 1057 if (kssave) { 1058 System.err.println(rb.getString 1059 ("Certificate.reply.was.installed.in.keystore")); 1060 } else { 1061 System.err.println(rb.getString 1062 ("Certificate.reply.was.not.installed.in.keystore")); 1063 } 1064 } else if (!keyStore.containsAlias(importAlias) || 1065 keyStore.entryInstanceOf(importAlias, 1066 KeyStore.TrustedCertificateEntry.class)) { 1067 kssave = addTrustedCert(importAlias, inStream); 1068 if (kssave) { 1069 System.err.println(rb.getString 1070 ("Certificate.was.added.to.keystore")); 1071 } else { 1072 System.err.println(rb.getString 1073 ("Certificate.was.not.added.to.keystore")); 1074 } 1075 } 1076 } finally { 1077 if (inStream != System.in) { 1078 inStream.close(); 1079 } 1080 } 1081 } else if (command == IMPORTKEYSTORE) { 1082 doImportKeyStore(); 1083 kssave = true; 1084 } else if (command == KEYCLONE) { 1085 keyPassNew = newPass; 1086 1087 // added to make sure only key can go thru 1088 if (alias == null) { 1089 alias = keyAlias; 1090 } 1091 if (keyStore.containsAlias(alias) == false) { 1092 MessageFormat form = new MessageFormat 1093 (rb.getString("Alias.alias.does.not.exist")); 1094 Object[] source = {alias}; 1095 throw new Exception(form.format(source)); 1096 } 1097 if (!keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) { 1098 MessageFormat form = new MessageFormat(rb.getString( 1099 "Alias.alias.references.an.entry.type.that.is.not.a.private.key.entry.The.keyclone.command.only.supports.cloning.of.private.key")); 1100 Object[] source = {alias}; 1101 throw new Exception(form.format(source)); 1102 } 1103 1104 doCloneEntry(alias, dest, true); // Now everything can be cloned 1105 kssave = true; 1106 } else if (command == CHANGEALIAS) { 1107 if (alias == null) { 1108 alias = keyAlias; 1109 } 1110 doCloneEntry(alias, dest, false); 1111 // in PKCS11, clone a PrivateKeyEntry will delete the old one 1112 if (keyStore.containsAlias(alias)) { 1113 doDeleteEntry(alias); 1114 } 1115 kssave = true; 1116 } else if (command == KEYPASSWD) { 1117 keyPassNew = newPass; 1118 doChangeKeyPasswd(alias); 1119 kssave = true; 1120 } else if (command == LIST) { 1121 if (storePass == null 1122 && !KeyStoreUtil.isWindowsKeyStore(storetype)) { 1123 printWarning(); 1124 } 1125 1126 if (alias != null) { 1127 doPrintEntry(alias, out); 1128 } else { 1129 doPrintEntries(out); 1130 } 1131 } else if (command == PRINTCERT) { 1132 doPrintCert(out); 1133 } else if (command == SELFCERT) { 1134 doSelfCert(alias, dname, sigAlgName); 1135 kssave = true; 1136 } else if (command == STOREPASSWD) { 1137 storePassNew = newPass; 1138 if (storePassNew == null) { 1139 storePassNew = getNewPasswd("keystore password", storePass); 1140 } 1141 kssave = true; 1142 } else if (command == GENCERT) { 1143 if (alias == null) { 1144 alias = keyAlias; 1145 } 1146 InputStream inStream = System.in; 1147 if (infilename != null) { 1148 inStream = new FileInputStream(infilename); 1149 } 1150 PrintStream ps = null; 1151 if (outfilename != null) { 1152 ps = new PrintStream(new FileOutputStream(outfilename)); 1153 out = ps; 1154 } 1155 try { 1156 doGenCert(alias, sigAlgName, inStream, out); 1157 } finally { 1158 if (inStream != System.in) { 1159 inStream.close(); 1160 } 1161 if (ps != null) { 1162 ps.close(); 1163 } 1164 } 1165 } else if (command == GENCRL) { 1166 if (alias == null) { 1167 alias = keyAlias; 1168 } 1169 if (filename != null) { 1170 try (PrintStream ps = 1171 new PrintStream(new FileOutputStream(filename))) { 1172 doGenCRL(ps); 1173 } 1174 } else { 1175 doGenCRL(out); 1176 } 1177 } else if (command == PRINTCERTREQ) { 1178 if (filename != null) { 1179 try (InputStream inStream = new FileInputStream(filename)) { 1180 doPrintCertReq(inStream, out); 1181 } 1182 } else { 1183 doPrintCertReq(System.in, out); 1184 } 1185 } else if (command == PRINTCRL) { 1186 doPrintCRL(filename, out); 1187 } 1188 1189 // If we need to save the keystore, do so. 1190 if (kssave) { 1191 if (verbose) { 1192 MessageFormat form = new MessageFormat 1193 (rb.getString(".Storing.ksfname.")); 1194 Object[] source = {nullStream ? "keystore" : ksfname}; 1195 System.err.println(form.format(source)); 1196 } 1197 1198 if (token) { 1199 keyStore.store(null, null); 1200 } else { 1201 char[] pass = (storePassNew!=null) ? storePassNew : storePass; 1202 if (nullStream) { 1203 keyStore.store(null, pass); 1204 } else { 1205 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 1206 keyStore.store(bout, pass); 1207 try (FileOutputStream fout = new FileOutputStream(ksfname)) { 1208 fout.write(bout.toByteArray()); 1209 } 1210 } 1211 } 1212 } 1213 } 1214 1215 /** 1216 * Generate a certificate: Read PKCS10 request from in, and print 1217 * certificate to out. Use alias as CA, sigAlgName as the signature 1218 * type. 1219 */ 1220 private void doGenCert(String alias, String sigAlgName, InputStream in, PrintStream out) 1221 throws Exception { 1222 1223 1224 Certificate signerCert = keyStore.getCertificate(alias); 1225 byte[] encoded = signerCert.getEncoded(); 1226 X509CertImpl signerCertImpl = new X509CertImpl(encoded); 1227 X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get( 1228 X509CertImpl.NAME + "." + X509CertImpl.INFO); 1229 X500Name issuer = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." + 1230 X509CertInfo.DN_NAME); 1231 1232 Date firstDate = getStartDate(startDate); 1233 Date lastDate = new Date(); 1234 lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L); 1235 CertificateValidity interval = new CertificateValidity(firstDate, 1236 lastDate); 1237 1238 PrivateKey privateKey = 1239 (PrivateKey)recoverKey(alias, storePass, keyPass).fst; 1240 if (sigAlgName == null) { 1241 sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm()); 1242 } 1243 Signature signature = Signature.getInstance(sigAlgName); 1244 signature.initSign(privateKey); 1245 1246 X509CertInfo info = new X509CertInfo(); 1247 info.set(X509CertInfo.VALIDITY, interval); 1248 info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( 1249 new java.util.Random().nextInt() & 0x7fffffff)); 1250 info.set(X509CertInfo.VERSION, 1251 new CertificateVersion(CertificateVersion.V3)); 1252 info.set(X509CertInfo.ALGORITHM_ID, 1253 new CertificateAlgorithmId( 1254 AlgorithmId.get(sigAlgName))); 1255 info.set(X509CertInfo.ISSUER, issuer); 1256 1257 BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 1258 boolean canRead = false; 1259 StringBuffer sb = new StringBuffer(); 1260 while (true) { 1261 String s = reader.readLine(); 1262 if (s == null) break; 1263 // OpenSSL does not use NEW 1264 //if (s.startsWith("-----BEGIN NEW CERTIFICATE REQUEST-----")) { 1265 if (s.startsWith("-----BEGIN") && s.indexOf("REQUEST") >= 0) { 1266 canRead = true; 1267 //} else if (s.startsWith("-----END NEW CERTIFICATE REQUEST-----")) { 1268 } else if (s.startsWith("-----END") && s.indexOf("REQUEST") >= 0) { 1269 break; 1270 } else if (canRead) { 1271 sb.append(s); 1272 } 1273 } 1274 byte[] rawReq = Pem.decode(new String(sb)); 1275 PKCS10 req = new PKCS10(rawReq); 1276 1277 info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo())); 1278 info.set(X509CertInfo.SUBJECT, 1279 dname==null?req.getSubjectName():new X500Name(dname)); 1280 CertificateExtensions reqex = null; 1281 Iterator<PKCS10Attribute> attrs = req.getAttributes().getAttributes().iterator(); 1282 while (attrs.hasNext()) { 1283 PKCS10Attribute attr = attrs.next(); 1284 if (attr.getAttributeId().equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) { 1285 reqex = (CertificateExtensions)attr.getAttributeValue(); 1286 } 1287 } 1288 CertificateExtensions ext = createV3Extensions( 1289 reqex, 1290 null, 1291 v3ext, 1292 req.getSubjectPublicKeyInfo(), 1293 signerCert.getPublicKey()); 1294 info.set(X509CertInfo.EXTENSIONS, ext); 1295 X509CertImpl cert = new X509CertImpl(info); 1296 cert.sign(privateKey, sigAlgName); 1297 dumpCert(cert, out); 1298 for (Certificate ca: keyStore.getCertificateChain(alias)) { 1299 if (ca instanceof X509Certificate) { 1300 X509Certificate xca = (X509Certificate)ca; 1301 if (!KeyStoreUtil.isSelfSigned(xca)) { 1302 dumpCert(xca, out); 1303 } 1304 } 1305 } 1306 } 1307 1308 private void doGenCRL(PrintStream out) 1309 throws Exception { 1310 if (ids == null) { 1311 throw new Exception("Must provide -id when -gencrl"); 1312 } 1313 Certificate signerCert = keyStore.getCertificate(alias); 1314 byte[] encoded = signerCert.getEncoded(); 1315 X509CertImpl signerCertImpl = new X509CertImpl(encoded); 1316 X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get( 1317 X509CertImpl.NAME + "." + X509CertImpl.INFO); 1318 X500Name owner = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." + 1319 X509CertInfo.DN_NAME); 1320 1321 Date firstDate = getStartDate(startDate); 1322 Date lastDate = (Date) firstDate.clone(); 1323 lastDate.setTime(lastDate.getTime() + validity*1000*24*60*60); 1324 CertificateValidity interval = new CertificateValidity(firstDate, 1325 lastDate); 1326 1327 1328 PrivateKey privateKey = 1329 (PrivateKey)recoverKey(alias, storePass, keyPass).fst; 1330 if (sigAlgName == null) { 1331 sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm()); 1332 } 1333 1334 X509CRLEntry[] badCerts = new X509CRLEntry[ids.size()]; 1335 for (int i=0; i<ids.size(); i++) { 1336 String id = ids.get(i); 1337 int d = id.indexOf(':'); 1338 if (d >= 0) { 1339 CRLExtensions ext = new CRLExtensions(); 1340 ext.set("Reason", new CRLReasonCodeExtension(Integer.parseInt(id.substring(d+1)))); 1341 badCerts[i] = new X509CRLEntryImpl(new BigInteger(id.substring(0, d)), 1342 firstDate, ext); 1343 } else { 1344 badCerts[i] = new X509CRLEntryImpl(new BigInteger(ids.get(i)), firstDate); 1345 } 1346 } 1347 X509CRLImpl crl = new X509CRLImpl(owner, firstDate, lastDate, badCerts); 1348 crl.sign(privateKey, sigAlgName); 1349 if (rfc) { 1350 out.println("-----BEGIN X509 CRL-----"); 1351 out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(crl.getEncodedInternal())); 1352 out.println("-----END X509 CRL-----"); 1353 } else { 1354 out.write(crl.getEncodedInternal()); 1355 } 1356 } 1357 1358 /** 1359 * Creates a PKCS#10 cert signing request, corresponding to the 1360 * keys (and name) associated with a given alias. 1361 */ 1362 private void doCertReq(String alias, String sigAlgName, PrintStream out) 1363 throws Exception 1364 { 1365 if (alias == null) { 1366 alias = keyAlias; 1367 } 1368 1369 Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass); 1370 PrivateKey privKey = (PrivateKey)objs.fst; 1371 if (keyPass == null) { 1372 keyPass = objs.snd; 1373 } 1374 1375 Certificate cert = keyStore.getCertificate(alias); 1376 if (cert == null) { 1377 MessageFormat form = new MessageFormat 1378 (rb.getString("alias.has.no.public.key.certificate.")); 1379 Object[] source = {alias}; 1380 throw new Exception(form.format(source)); 1381 } 1382 PKCS10 request = new PKCS10(cert.getPublicKey()); 1383 CertificateExtensions ext = createV3Extensions(null, null, v3ext, cert.getPublicKey(), null); 1384 // Attribute name is not significant 1385 request.getAttributes().setAttribute(X509CertInfo.EXTENSIONS, 1386 new PKCS10Attribute(PKCS9Attribute.EXTENSION_REQUEST_OID, ext)); 1387 1388 // Construct a Signature object, so that we can sign the request 1389 if (sigAlgName == null) { 1390 sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm()); 1391 } 1392 1393 Signature signature = Signature.getInstance(sigAlgName); 1394 signature.initSign(privKey); 1395 X500Name subject = dname == null? 1396 new X500Name(((X509Certificate)cert).getSubjectDN().toString()): 1397 new X500Name(dname); 1398 1399 // Sign the request and base-64 encode it 1400 request.encodeAndSign(subject, signature); 1401 request.print(out); 1402 } 1403 1404 /** 1405 * Deletes an entry from the keystore. 1406 */ 1407 private void doDeleteEntry(String alias) throws Exception { 1408 if (keyStore.containsAlias(alias) == false) { 1409 MessageFormat form = new MessageFormat 1410 (rb.getString("Alias.alias.does.not.exist")); 1411 Object[] source = {alias}; 1412 throw new Exception(form.format(source)); 1413 } 1414 keyStore.deleteEntry(alias); 1415 } 1416 1417 /** 1418 * Exports a certificate from the keystore. 1419 */ 1420 private void doExportCert(String alias, PrintStream out) 1421 throws Exception 1422 { 1423 if (storePass == null 1424 && !KeyStoreUtil.isWindowsKeyStore(storetype)) { 1425 printWarning(); 1426 } 1427 if (alias == null) { 1428 alias = keyAlias; 1429 } 1430 if (keyStore.containsAlias(alias) == false) { 1431 MessageFormat form = new MessageFormat 1432 (rb.getString("Alias.alias.does.not.exist")); 1433 Object[] source = {alias}; 1434 throw new Exception(form.format(source)); 1435 } 1436 1437 X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias); 1438 if (cert == null) { 1439 MessageFormat form = new MessageFormat 1440 (rb.getString("Alias.alias.has.no.certificate")); 1441 Object[] source = {alias}; 1442 throw new Exception(form.format(source)); 1443 } 1444 dumpCert(cert, out); 1445 } 1446 1447 /** 1448 * Prompt the user for a keypass when generating a key entry. 1449 * @param alias the entry we will set password for 1450 * @param orig the original entry of doing a dup, null if generate new 1451 * @param origPass the password to copy from if user press ENTER 1452 */ 1453 private char[] promptForKeyPass(String alias, String orig, char[] origPass) throws Exception{ 1454 if (P12KEYSTORE.equalsIgnoreCase(storetype)) { 1455 return origPass; 1456 } else if (!token && !protectedPath) { 1457 // Prompt for key password 1458 int count; 1459 for (count = 0; count < 3; count++) { 1460 MessageFormat form = new MessageFormat(rb.getString 1461 ("Enter.key.password.for.alias.")); 1462 Object[] source = {alias}; 1463 System.err.println(form.format(source)); 1464 if (orig == null) { 1465 System.err.print(rb.getString 1466 (".RETURN.if.same.as.keystore.password.")); 1467 } else { 1468 form = new MessageFormat(rb.getString 1469 (".RETURN.if.same.as.for.otherAlias.")); 1470 Object[] src = {orig}; 1471 System.err.print(form.format(src)); 1472 } 1473 System.err.flush(); 1474 char[] entered = Password.readPassword(System.in); 1475 passwords.add(entered); 1476 if (entered == null) { 1477 return origPass; 1478 } else if (entered.length >= 6) { 1479 System.err.print(rb.getString("Re.enter.new.password.")); 1480 char[] passAgain = Password.readPassword(System.in); 1481 passwords.add(passAgain); 1482 if (!Arrays.equals(entered, passAgain)) { 1483 System.err.println 1484 (rb.getString("They.don.t.match.Try.again")); 1485 continue; 1486 } 1487 return entered; 1488 } else { 1489 System.err.println(rb.getString 1490 ("Key.password.is.too.short.must.be.at.least.6.characters")); 1491 } 1492 } 1493 if (count == 3) { 1494 if (command == KEYCLONE) { 1495 throw new Exception(rb.getString 1496 ("Too.many.failures.Key.entry.not.cloned")); 1497 } else { 1498 throw new Exception(rb.getString 1499 ("Too.many.failures.key.not.added.to.keystore")); 1500 } 1501 } 1502 } 1503 return null; // PKCS11, MSCAPI, or -protected 1504 } 1505 1506 /* 1507 * Prompt the user for the password credential to be stored. 1508 */ 1509 private char[] promptForCredential() throws Exception { 1510 // Handle password supplied via stdin 1511 if (System.console() == null) { 1512 char[] importPass = Password.readPassword(System.in); 1513 passwords.add(importPass); 1514 return importPass; 1515 } 1516 1517 int count; 1518 for (count = 0; count < 3; count++) { 1519 System.err.print( 1520 rb.getString("Enter.the.password.to.be.stored.")); 1521 System.err.flush(); 1522 char[] entered = Password.readPassword(System.in); 1523 passwords.add(entered); 1524 System.err.print(rb.getString("Re.enter.password.")); 1525 char[] passAgain = Password.readPassword(System.in); 1526 passwords.add(passAgain); 1527 if (!Arrays.equals(entered, passAgain)) { 1528 System.err.println(rb.getString("They.don.t.match.Try.again")); 1529 continue; 1530 } 1531 return entered; 1532 } 1533 1534 if (count == 3) { 1535 throw new Exception(rb.getString 1536 ("Too.many.failures.key.not.added.to.keystore")); 1537 } 1538 1539 return null; 1540 } 1541 1542 /** 1543 * Creates a new secret key. 1544 */ 1545 private void doGenSecretKey(String alias, String keyAlgName, 1546 int keysize) 1547 throws Exception 1548 { 1549 if (alias == null) { 1550 alias = keyAlias; 1551 } 1552 if (keyStore.containsAlias(alias)) { 1553 MessageFormat form = new MessageFormat(rb.getString 1554 ("Secret.key.not.generated.alias.alias.already.exists")); 1555 Object[] source = {alias}; 1556 throw new Exception(form.format(source)); 1557 } 1558 1559 // Use the keystore's default PBE algorithm for entry protection 1560 boolean useDefaultPBEAlgorithm = true; 1561 SecretKey secKey = null; 1562 1563 if (keyAlgName.toUpperCase(Locale.ENGLISH).startsWith("PBE")) { 1564 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE"); 1565 1566 // User is prompted for PBE credential 1567 secKey = 1568 factory.generateSecret(new PBEKeySpec(promptForCredential())); 1569 1570 // Check whether a specific PBE algorithm was specified 1571 if (!"PBE".equalsIgnoreCase(keyAlgName)) { 1572 useDefaultPBEAlgorithm = false; 1573 } 1574 1575 if (verbose) { 1576 MessageFormat form = new MessageFormat(rb.getString( 1577 "Generated.keyAlgName.secret.key")); 1578 Object[] source = 1579 {useDefaultPBEAlgorithm ? "PBE" : secKey.getAlgorithm()}; 1580 System.err.println(form.format(source)); 1581 } 1582 } else { 1583 KeyGenerator keygen = KeyGenerator.getInstance(keyAlgName); 1584 if (keysize == -1) { 1585 if ("DES".equalsIgnoreCase(keyAlgName)) { 1586 keysize = 56; 1587 } else if ("DESede".equalsIgnoreCase(keyAlgName)) { 1588 keysize = 168; 1589 } else { 1590 throw new Exception(rb.getString 1591 ("Please.provide.keysize.for.secret.key.generation")); 1592 } 1593 } 1594 keygen.init(keysize); 1595 secKey = keygen.generateKey(); 1596 1597 if (verbose) { 1598 MessageFormat form = new MessageFormat(rb.getString 1599 ("Generated.keysize.bit.keyAlgName.secret.key")); 1600 Object[] source = {keysize, 1601 secKey.getAlgorithm()}; 1602 System.err.println(form.format(source)); 1603 } 1604 } 1605 1606 if (keyPass == null) { 1607 keyPass = promptForKeyPass(alias, null, storePass); 1608 } 1609 1610 if (useDefaultPBEAlgorithm) { 1611 keyStore.setKeyEntry(alias, secKey, keyPass, null); 1612 } else { 1613 keyStore.setEntry(alias, new KeyStore.SecretKeyEntry(secKey), 1614 new KeyStore.PasswordProtection(keyPass, keyAlgName, null)); 1615 } 1616 } 1617 1618 /** 1619 * If no signature algorithm was specified at the command line, 1620 * we choose one that is compatible with the selected private key 1621 */ 1622 private static String getCompatibleSigAlgName(String keyAlgName) 1623 throws Exception { 1624 if ("DSA".equalsIgnoreCase(keyAlgName)) { 1625 return "SHA256WithDSA"; 1626 } else if ("RSA".equalsIgnoreCase(keyAlgName)) { 1627 return "SHA256WithRSA"; 1628 } else if ("EC".equalsIgnoreCase(keyAlgName)) { 1629 return "SHA256withECDSA"; 1630 } else { 1631 throw new Exception(rb.getString 1632 ("Cannot.derive.signature.algorithm")); 1633 } 1634 } 1635 /** 1636 * Creates a new key pair and self-signed certificate. 1637 */ 1638 private void doGenKeyPair(String alias, String dname, String keyAlgName, 1639 int keysize, String sigAlgName) 1640 throws Exception 1641 { 1642 if (keysize == -1) { 1643 if ("EC".equalsIgnoreCase(keyAlgName)) { 1644 keysize = 256; 1645 } else { 1646 keysize = 2048; // RSA and DSA 1647 } 1648 } 1649 1650 if (alias == null) { 1651 alias = keyAlias; 1652 } 1653 1654 if (keyStore.containsAlias(alias)) { 1655 MessageFormat form = new MessageFormat(rb.getString 1656 ("Key.pair.not.generated.alias.alias.already.exists")); 1657 Object[] source = {alias}; 1658 throw new Exception(form.format(source)); 1659 } 1660 1661 if (sigAlgName == null) { 1662 sigAlgName = getCompatibleSigAlgName(keyAlgName); 1663 } 1664 CertAndKeyGen keypair = 1665 new CertAndKeyGen(keyAlgName, sigAlgName, providerName); 1666 1667 1668 // If DN is provided, parse it. Otherwise, prompt the user for it. 1669 X500Name x500Name; 1670 if (dname == null) { 1671 x500Name = getX500Name(); 1672 } else { 1673 x500Name = new X500Name(dname); 1674 } 1675 1676 keypair.generate(keysize); 1677 PrivateKey privKey = keypair.getPrivateKey(); 1678 1679 CertificateExtensions ext = createV3Extensions( 1680 null, 1681 null, 1682 v3ext, 1683 keypair.getPublicKeyAnyway(), 1684 null); 1685 1686 X509Certificate[] chain = new X509Certificate[1]; 1687 chain[0] = keypair.getSelfCertificate( 1688 x500Name, getStartDate(startDate), validity*24L*60L*60L, ext); 1689 1690 if (verbose) { 1691 MessageFormat form = new MessageFormat(rb.getString 1692 ("Generating.keysize.bit.keyAlgName.key.pair.and.self.signed.certificate.sigAlgName.with.a.validity.of.validality.days.for")); 1693 Object[] source = {keysize, 1694 privKey.getAlgorithm(), 1695 chain[0].getSigAlgName(), 1696 validity, 1697 x500Name}; 1698 System.err.println(form.format(source)); 1699 } 1700 1701 if (keyPass == null) { 1702 keyPass = promptForKeyPass(alias, null, storePass); 1703 } 1704 keyStore.setKeyEntry(alias, privKey, keyPass, chain); 1705 } 1706 1707 /** 1708 * Clones an entry 1709 * @param orig original alias 1710 * @param dest destination alias 1711 * @changePassword if the password can be changed 1712 */ 1713 private void doCloneEntry(String orig, String dest, boolean changePassword) 1714 throws Exception 1715 { 1716 if (orig == null) { 1717 orig = keyAlias; 1718 } 1719 1720 if (keyStore.containsAlias(dest)) { 1721 MessageFormat form = new MessageFormat 1722 (rb.getString("Destination.alias.dest.already.exists")); 1723 Object[] source = {dest}; 1724 throw new Exception(form.format(source)); 1725 } 1726 1727 Pair<Entry,char[]> objs = recoverEntry(keyStore, orig, storePass, keyPass); 1728 Entry entry = objs.fst; 1729 keyPass = objs.snd; 1730 1731 PasswordProtection pp = null; 1732 1733 if (keyPass != null) { // protected 1734 if (!changePassword || P12KEYSTORE.equalsIgnoreCase(storetype)) { 1735 keyPassNew = keyPass; 1736 } else { 1737 if (keyPassNew == null) { 1738 keyPassNew = promptForKeyPass(dest, orig, keyPass); 1739 } 1740 } 1741 pp = new PasswordProtection(keyPassNew); 1742 } 1743 keyStore.setEntry(dest, entry, pp); 1744 } 1745 1746 /** 1747 * Changes a key password. 1748 */ 1749 private void doChangeKeyPasswd(String alias) throws Exception 1750 { 1751 1752 if (alias == null) { 1753 alias = keyAlias; 1754 } 1755 Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass); 1756 Key privKey = objs.fst; 1757 if (keyPass == null) { 1758 keyPass = objs.snd; 1759 } 1760 1761 if (keyPassNew == null) { 1762 MessageFormat form = new MessageFormat 1763 (rb.getString("key.password.for.alias.")); 1764 Object[] source = {alias}; 1765 keyPassNew = getNewPasswd(form.format(source), keyPass); 1766 } 1767 keyStore.setKeyEntry(alias, privKey, keyPassNew, 1768 keyStore.getCertificateChain(alias)); 1769 } 1770 1771 /** 1772 * Imports a JDK 1.1-style identity database. We can only store one 1773 * certificate per identity, because we use the identity's name as the 1774 * alias (which references a keystore entry), and aliases must be unique. 1775 */ 1776 private void doImportIdentityDatabase(InputStream in) 1777 throws Exception 1778 { 1779 System.err.println(rb.getString 1780 ("No.entries.from.identity.database.added")); 1781 } 1782 1783 /** 1784 * Prints a single keystore entry. 1785 */ 1786 private void doPrintEntry(String alias, PrintStream out) 1787 throws Exception 1788 { 1789 if (keyStore.containsAlias(alias) == false) { 1790 MessageFormat form = new MessageFormat 1791 (rb.getString("Alias.alias.does.not.exist")); 1792 Object[] source = {alias}; 1793 throw new Exception(form.format(source)); 1794 } 1795 1796 if (verbose || rfc || debug) { 1797 MessageFormat form = new MessageFormat 1798 (rb.getString("Alias.name.alias")); 1799 Object[] source = {alias}; 1800 out.println(form.format(source)); 1801 1802 if (!token) { 1803 form = new MessageFormat(rb.getString 1804 ("Creation.date.keyStore.getCreationDate.alias.")); 1805 Object[] src = {keyStore.getCreationDate(alias)}; 1806 out.println(form.format(src)); 1807 } 1808 } else { 1809 if (!token) { 1810 MessageFormat form = new MessageFormat 1811 (rb.getString("alias.keyStore.getCreationDate.alias.")); 1812 Object[] source = {alias, keyStore.getCreationDate(alias)}; 1813 out.print(form.format(source)); 1814 } else { 1815 MessageFormat form = new MessageFormat 1816 (rb.getString("alias.")); 1817 Object[] source = {alias}; 1818 out.print(form.format(source)); 1819 } 1820 } 1821 1822 if (keyStore.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) { 1823 if (verbose || rfc || debug) { 1824 Object[] source = {"SecretKeyEntry"}; 1825 out.println(new MessageFormat( 1826 rb.getString("Entry.type.type.")).format(source)); 1827 } else { 1828 out.println("SecretKeyEntry, "); 1829 } 1830 } else if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) { 1831 if (verbose || rfc || debug) { 1832 Object[] source = {"PrivateKeyEntry"}; 1833 out.println(new MessageFormat( 1834 rb.getString("Entry.type.type.")).format(source)); 1835 } else { 1836 out.println("PrivateKeyEntry, "); 1837 } 1838 1839 // Get the chain 1840 Certificate[] chain = keyStore.getCertificateChain(alias); 1841 if (chain != null) { 1842 if (verbose || rfc || debug) { 1843 out.println(rb.getString 1844 ("Certificate.chain.length.") + chain.length); 1845 for (int i = 0; i < chain.length; i ++) { 1846 MessageFormat form = new MessageFormat 1847 (rb.getString("Certificate.i.1.")); 1848 Object[] source = {(i + 1)}; 1849 out.println(form.format(source)); 1850 if (verbose && (chain[i] instanceof X509Certificate)) { 1851 printX509Cert((X509Certificate)(chain[i]), out); 1852 } else if (debug) { 1853 out.println(chain[i].toString()); 1854 } else { 1855 dumpCert(chain[i], out); 1856 } 1857 } 1858 } else { 1859 // Print the digest of the user cert only 1860 out.println 1861 (rb.getString("Certificate.fingerprint.SHA.256.") + 1862 getCertFingerPrint("SHA-256", chain[0])); 1863 } 1864 } 1865 } else if (keyStore.entryInstanceOf(alias, 1866 KeyStore.TrustedCertificateEntry.class)) { 1867 // We have a trusted certificate entry 1868 Certificate cert = keyStore.getCertificate(alias); 1869 Object[] source = {"trustedCertEntry"}; 1870 String mf = new MessageFormat( 1871 rb.getString("Entry.type.type.")).format(source) + "\n"; 1872 if (verbose && (cert instanceof X509Certificate)) { 1873 out.println(mf); 1874 printX509Cert((X509Certificate)cert, out); 1875 } else if (rfc) { 1876 out.println(mf); 1877 dumpCert(cert, out); 1878 } else if (debug) { 1879 out.println(cert.toString()); 1880 } else { 1881 out.println("trustedCertEntry, "); 1882 out.println(rb.getString("Certificate.fingerprint.SHA.256.") 1883 + getCertFingerPrint("SHA-256", cert)); 1884 } 1885 } else { 1886 out.println(rb.getString("Unknown.Entry.Type")); 1887 } 1888 } 1889 1890 /** 1891 * Load the srckeystore from a stream, used in -importkeystore 1892 * @return the src KeyStore 1893 */ 1894 KeyStore loadSourceKeyStore() throws Exception { 1895 boolean isPkcs11 = false; 1896 1897 InputStream is = null; 1898 File srcksfile = null; 1899 1900 if (P11KEYSTORE.equalsIgnoreCase(srcstoretype) || 1901 KeyStoreUtil.isWindowsKeyStore(srcstoretype)) { 1902 if (!NONE.equals(srcksfname)) { 1903 System.err.println(MessageFormat.format(rb.getString 1904 (".keystore.must.be.NONE.if.storetype.is.{0}"), srcstoretype)); 1905 System.err.println(); 1906 tinyHelp(); 1907 } 1908 isPkcs11 = true; 1909 } else { 1910 if (srcksfname != null) { 1911 srcksfile = new File(srcksfname); 1912 if (srcksfile.exists() && srcksfile.length() == 0) { 1913 throw new Exception(rb.getString 1914 ("Source.keystore.file.exists.but.is.empty.") + 1915 srcksfname); 1916 } 1917 is = new FileInputStream(srcksfile); 1918 } else { 1919 throw new Exception(rb.getString 1920 ("Please.specify.srckeystore")); 1921 } 1922 } 1923 1924 KeyStore store; 1925 try { 1926 // Probe for keystore type when filename is available 1927 if (srcksfile != null && is != null && srcProviderName == null && 1928 hasStoretypeOption == false) { 1929 store = KeyStore.getInstance(srcksfile, srcstorePass); 1930 } else { 1931 if (srcProviderName == null) { 1932 store = KeyStore.getInstance(srcstoretype); 1933 } else { 1934 store = KeyStore.getInstance(srcstoretype, srcProviderName); 1935 } 1936 } 1937 1938 if (srcstorePass == null 1939 && !srcprotectedPath 1940 && !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) { 1941 System.err.print(rb.getString("Enter.source.keystore.password.")); 1942 System.err.flush(); 1943 srcstorePass = Password.readPassword(System.in); 1944 passwords.add(srcstorePass); 1945 } 1946 1947 // always let keypass be storepass when using pkcs12 1948 if (P12KEYSTORE.equalsIgnoreCase(srcstoretype)) { 1949 if (srckeyPass != null && srcstorePass != null && 1950 !Arrays.equals(srcstorePass, srckeyPass)) { 1951 MessageFormat form = new MessageFormat(rb.getString( 1952 "Warning.Different.store.and.key.passwords.not.supported.for.PKCS12.KeyStores.Ignoring.user.specified.command.value.")); 1953 Object[] source = {"-srckeypass"}; 1954 System.err.println(form.format(source)); 1955 srckeyPass = srcstorePass; 1956 } 1957 } 1958 1959 store.load(is, srcstorePass); // "is" already null in PKCS11 1960 } finally { 1961 if (is != null) { 1962 is.close(); 1963 } 1964 } 1965 1966 if (srcstorePass == null 1967 && !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) { 1968 // anti refactoring, copied from printWarning(), 1969 // but change 2 lines 1970 System.err.println(); 1971 System.err.println(rb.getString 1972 (".WARNING.WARNING.WARNING.")); 1973 System.err.println(rb.getString 1974 (".The.integrity.of.the.information.stored.in.the.srckeystore.")); 1975 System.err.println(rb.getString 1976 (".WARNING.WARNING.WARNING.")); 1977 System.err.println(); 1978 } 1979 1980 return store; 1981 } 1982 1983 /** 1984 * import all keys and certs from importkeystore. 1985 * keep alias unchanged if no name conflict, otherwise, prompt. 1986 * keep keypass unchanged for keys 1987 */ 1988 private void doImportKeyStore() throws Exception { 1989 1990 if (alias != null) { 1991 doImportKeyStoreSingle(loadSourceKeyStore(), alias); 1992 } else { 1993 if (dest != null || srckeyPass != null) { 1994 throw new Exception(rb.getString( 1995 "if.alias.not.specified.destalias.and.srckeypass.must.not.be.specified")); 1996 } 1997 doImportKeyStoreAll(loadSourceKeyStore()); 1998 } 1999 /* 2000 * Information display rule of -importkeystore 2001 * 1. inside single, shows failure 2002 * 2. inside all, shows sucess 2003 * 3. inside all where there is a failure, prompt for continue 2004 * 4. at the final of all, shows summary 2005 */ 2006 } 2007 2008 /** 2009 * Import a single entry named alias from srckeystore 2010 * @return 1 if the import action succeed 2011 * 0 if user choose to ignore an alias-dumplicated entry 2012 * 2 if setEntry throws Exception 2013 */ 2014 private int doImportKeyStoreSingle(KeyStore srckeystore, String alias) 2015 throws Exception { 2016 2017 String newAlias = (dest==null) ? alias : dest; 2018 2019 if (keyStore.containsAlias(newAlias)) { 2020 Object[] source = {alias}; 2021 if (noprompt) { 2022 System.err.println(new MessageFormat(rb.getString( 2023 "Warning.Overwriting.existing.alias.alias.in.destination.keystore")).format(source)); 2024 } else { 2025 String reply = getYesNoReply(new MessageFormat(rb.getString( 2026 "Existing.entry.alias.alias.exists.overwrite.no.")).format(source)); 2027 if ("NO".equals(reply)) { 2028 newAlias = inputStringFromStdin(rb.getString 2029 ("Enter.new.alias.name.RETURN.to.cancel.import.for.this.entry.")); 2030 if ("".equals(newAlias)) { 2031 System.err.println(new MessageFormat(rb.getString( 2032 "Entry.for.alias.alias.not.imported.")).format( 2033 source)); 2034 return 0; 2035 } 2036 } 2037 } 2038 } 2039 2040 Pair<Entry,char[]> objs = recoverEntry(srckeystore, alias, srcstorePass, srckeyPass); 2041 Entry entry = objs.fst; 2042 2043 PasswordProtection pp = null; 2044 2045 // According to keytool.html, "The destination entry will be protected 2046 // using destkeypass. If destkeypass is not provided, the destination 2047 // entry will be protected with the source entry password." 2048 // so always try to protect with destKeyPass. 2049 char[] newPass = null; 2050 if (destKeyPass != null) { 2051 newPass = destKeyPass; 2052 pp = new PasswordProtection(destKeyPass); 2053 } else if (objs.snd != null) { 2054 newPass = objs.snd; 2055 pp = new PasswordProtection(objs.snd); 2056 } 2057 2058 try { 2059 keyStore.setEntry(newAlias, entry, pp); 2060 // Place the check so that only successful imports are blocked. 2061 // For example, we don't block a failed SecretEntry import. 2062 if (P12KEYSTORE.equalsIgnoreCase(storetype)) { 2063 if (newPass != null && !Arrays.equals(newPass, storePass)) { 2064 throw new Exception(rb.getString( 2065 "The.destination.pkcs12.keystore.has.different.storepass.and.keypass.Please.retry.with.destkeypass.specified.")); 2066 } 2067 } 2068 return 1; 2069 } catch (KeyStoreException kse) { 2070 Object[] source2 = {alias, kse.toString()}; 2071 MessageFormat form = new MessageFormat(rb.getString( 2072 "Problem.importing.entry.for.alias.alias.exception.Entry.for.alias.alias.not.imported.")); 2073 System.err.println(form.format(source2)); 2074 return 2; 2075 } 2076 } 2077 2078 private void doImportKeyStoreAll(KeyStore srckeystore) throws Exception { 2079 2080 int ok = 0; 2081 int count = srckeystore.size(); 2082 for (Enumeration<String> e = srckeystore.aliases(); 2083 e.hasMoreElements(); ) { 2084 String alias = e.nextElement(); 2085 int result = doImportKeyStoreSingle(srckeystore, alias); 2086 if (result == 1) { 2087 ok++; 2088 Object[] source = {alias}; 2089 MessageFormat form = new MessageFormat(rb.getString("Entry.for.alias.alias.successfully.imported.")); 2090 System.err.println(form.format(source)); 2091 } else if (result == 2) { 2092 if (!noprompt) { 2093 String reply = getYesNoReply("Do you want to quit the import process? [no]: "); 2094 if ("YES".equals(reply)) { 2095 break; 2096 } 2097 } 2098 } 2099 } 2100 Object[] source = {ok, count-ok}; 2101 MessageFormat form = new MessageFormat(rb.getString( 2102 "Import.command.completed.ok.entries.successfully.imported.fail.entries.failed.or.cancelled")); 2103 System.err.println(form.format(source)); 2104 } 2105 2106 /** 2107 * Prints all keystore entries. 2108 */ 2109 private void doPrintEntries(PrintStream out) 2110 throws Exception 2111 { 2112 out.println(rb.getString("Keystore.type.") + keyStore.getType()); 2113 out.println(rb.getString("Keystore.provider.") + 2114 keyStore.getProvider().getName()); 2115 out.println(); 2116 2117 MessageFormat form; 2118 form = (keyStore.size() == 1) ? 2119 new MessageFormat(rb.getString 2120 ("Your.keystore.contains.keyStore.size.entry")) : 2121 new MessageFormat(rb.getString 2122 ("Your.keystore.contains.keyStore.size.entries")); 2123 Object[] source = {keyStore.size()}; 2124 out.println(form.format(source)); 2125 out.println(); 2126 2127 for (Enumeration<String> e = keyStore.aliases(); 2128 e.hasMoreElements(); ) { 2129 String alias = e.nextElement(); 2130 doPrintEntry(alias, out); 2131 if (verbose || rfc) { 2132 out.println(rb.getString("NEWLINE")); 2133 out.println(rb.getString 2134 ("STAR")); 2135 out.println(rb.getString 2136 ("STARNN")); 2137 } 2138 } 2139 } 2140 2141 private static <T> Iterable<T> e2i(final Enumeration<T> e) { 2142 return new Iterable<T>() { 2143 @Override 2144 public Iterator<T> iterator() { 2145 return new Iterator<T>() { 2146 @Override 2147 public boolean hasNext() { 2148 return e.hasMoreElements(); 2149 } 2150 @Override 2151 public T next() { 2152 return e.nextElement(); 2153 } 2154 public void remove() { 2155 throw new UnsupportedOperationException("Not supported yet."); 2156 } 2157 }; 2158 } 2159 }; 2160 } 2161 2162 /** 2163 * Loads CRLs from a source. This method is also called in JarSigner. 2164 * @param src the source, which means System.in if null, or a URI, 2165 * or a bare file path name 2166 */ 2167 public static Collection<? extends CRL> loadCRLs(String src) throws Exception { 2168 InputStream in = null; 2169 URI uri = null; 2170 if (src == null) { 2171 in = System.in; 2172 } else { 2173 try { 2174 uri = new URI(src); 2175 if (uri.getScheme().equals("ldap")) { 2176 // No input stream for LDAP 2177 } else { 2178 in = uri.toURL().openStream(); 2179 } 2180 } catch (Exception e) { 2181 try { 2182 in = new FileInputStream(src); 2183 } catch (Exception e2) { 2184 if (uri == null || uri.getScheme() == null) { 2185 throw e2; // More likely a bare file path 2186 } else { 2187 throw e; // More likely a protocol or network problem 2188 } 2189 } 2190 } 2191 } 2192 if (in != null) { 2193 try { 2194 // Read the full stream before feeding to X509Factory, 2195 // otherwise, keytool -gencrl | keytool -printcrl 2196 // might not work properly, since -gencrl is slow 2197 // and there's no data in the pipe at the beginning. 2198 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 2199 byte[] b = new byte[4096]; 2200 while (true) { 2201 int len = in.read(b); 2202 if (len < 0) break; 2203 bout.write(b, 0, len); 2204 } 2205 return CertificateFactory.getInstance("X509").generateCRLs( 2206 new ByteArrayInputStream(bout.toByteArray())); 2207 } finally { 2208 if (in != System.in) { 2209 in.close(); 2210 } 2211 } 2212 } else { // must be LDAP, and uri is not null 2213 URICertStoreParameters params = 2214 new URICertStoreParameters(uri); 2215 CertStore s = CertStore.getInstance("LDAP", params); 2216 return s.getCRLs(new X509CRLSelector()); 2217 } 2218 } 2219 2220 /** 2221 * Returns CRLs described in a X509Certificate's CRLDistributionPoints 2222 * Extension. Only those containing a general name of type URI are read. 2223 */ 2224 public static List<CRL> readCRLsFromCert(X509Certificate cert) 2225 throws Exception { 2226 List<CRL> crls = new ArrayList<>(); 2227 CRLDistributionPointsExtension ext = 2228 X509CertImpl.toImpl(cert).getCRLDistributionPointsExtension(); 2229 if (ext == null) return crls; 2230 List<DistributionPoint> distPoints = 2231 ext.get(CRLDistributionPointsExtension.POINTS); 2232 for (DistributionPoint o: distPoints) { 2233 GeneralNames names = o.getFullName(); 2234 if (names != null) { 2235 for (GeneralName name: names.names()) { 2236 if (name.getType() == GeneralNameInterface.NAME_URI) { 2237 URIName uriName = (URIName)name.getName(); 2238 for (CRL crl: loadCRLs(uriName.getName())) { 2239 if (crl instanceof X509CRL) { 2240 crls.add((X509CRL)crl); 2241 } 2242 } 2243 break; // Different name should point to same CRL 2244 } 2245 } 2246 } 2247 } 2248 return crls; 2249 } 2250 2251 private static String verifyCRL(KeyStore ks, CRL crl) 2252 throws Exception { 2253 X509CRLImpl xcrl = (X509CRLImpl)crl; 2254 X500Principal issuer = xcrl.getIssuerX500Principal(); 2255 for (String s: e2i(ks.aliases())) { 2256 Certificate cert = ks.getCertificate(s); 2257 if (cert instanceof X509Certificate) { 2258 X509Certificate xcert = (X509Certificate)cert; 2259 if (xcert.getSubjectX500Principal().equals(issuer)) { 2260 try { 2261 ((X509CRLImpl)crl).verify(cert.getPublicKey()); 2262 return s; 2263 } catch (Exception e) { 2264 } 2265 } 2266 } 2267 } 2268 return null; 2269 } 2270 2271 private void doPrintCRL(String src, PrintStream out) 2272 throws Exception { 2273 for (CRL crl: loadCRLs(src)) { 2274 printCRL(crl, out); 2275 String issuer = null; 2276 if (caks != null) { 2277 issuer = verifyCRL(caks, crl); 2278 if (issuer != null) { 2279 out.printf(rb.getString( 2280 "verified.by.s.in.s"), issuer, "cacerts"); 2281 out.println(); 2282 } 2283 } 2284 if (issuer == null && keyStore != null) { 2285 issuer = verifyCRL(keyStore, crl); 2286 if (issuer != null) { 2287 out.printf(rb.getString( 2288 "verified.by.s.in.s"), issuer, "keystore"); 2289 out.println(); 2290 } 2291 } 2292 if (issuer == null) { 2293 out.println(rb.getString 2294 ("STAR")); 2295 out.println(rb.getString 2296 ("warning.not.verified.make.sure.keystore.is.correct")); 2297 out.println(rb.getString 2298 ("STARNN")); 2299 } 2300 } 2301 } 2302 2303 private void printCRL(CRL crl, PrintStream out) 2304 throws Exception { 2305 if (rfc) { 2306 X509CRL xcrl = (X509CRL)crl; 2307 out.println("-----BEGIN X509 CRL-----"); 2308 out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(xcrl.getEncoded())); 2309 out.println("-----END X509 CRL-----"); 2310 } else { 2311 out.println(crl.toString()); 2312 } 2313 } 2314 2315 private void doPrintCertReq(InputStream in, PrintStream out) 2316 throws Exception { 2317 2318 BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 2319 StringBuffer sb = new StringBuffer(); 2320 boolean started = false; 2321 while (true) { 2322 String s = reader.readLine(); 2323 if (s == null) break; 2324 if (!started) { 2325 if (s.startsWith("-----")) { 2326 started = true; 2327 } 2328 } else { 2329 if (s.startsWith("-----")) { 2330 break; 2331 } 2332 sb.append(s); 2333 } 2334 } 2335 PKCS10 req = new PKCS10(Pem.decode(new String(sb))); 2336 2337 PublicKey pkey = req.getSubjectPublicKeyInfo(); 2338 out.printf(rb.getString("PKCS.10.Certificate.Request.Version.1.0.Subject.s.Public.Key.s.format.s.key."), 2339 req.getSubjectName(), pkey.getFormat(), pkey.getAlgorithm()); 2340 for (PKCS10Attribute attr: req.getAttributes().getAttributes()) { 2341 ObjectIdentifier oid = attr.getAttributeId(); 2342 if (oid.equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) { 2343 CertificateExtensions exts = (CertificateExtensions)attr.getAttributeValue(); 2344 if (exts != null) { 2345 printExtensions(rb.getString("Extension.Request."), exts, out); 2346 } 2347 } else { 2348 out.println("Attribute: " + attr.getAttributeId()); 2349 PKCS9Attribute pkcs9Attr = 2350 new PKCS9Attribute(attr.getAttributeId(), 2351 attr.getAttributeValue()); 2352 out.print(pkcs9Attr.getName() + ": "); 2353 Object attrVal = attr.getAttributeValue(); 2354 out.println(attrVal instanceof String[] ? 2355 Arrays.toString((String[]) attrVal) : 2356 attrVal); 2357 } 2358 } 2359 if (debug) { 2360 out.println(req); // Just to see more, say, public key length... 2361 } 2362 } 2363 2364 /** 2365 * Reads a certificate (or certificate chain) and prints its contents in 2366 * a human readable format. 2367 */ 2368 private void printCertFromStream(InputStream in, PrintStream out) 2369 throws Exception 2370 { 2371 Collection<? extends Certificate> c = null; 2372 try { 2373 c = cf.generateCertificates(in); 2374 } catch (CertificateException ce) { 2375 throw new Exception(rb.getString("Failed.to.parse.input"), ce); 2376 } 2377 if (c.isEmpty()) { 2378 throw new Exception(rb.getString("Empty.input")); 2379 } 2380 Certificate[] certs = c.toArray(new Certificate[c.size()]); 2381 for (int i=0; i<certs.length; i++) { 2382 X509Certificate x509Cert = null; 2383 try { 2384 x509Cert = (X509Certificate)certs[i]; 2385 } catch (ClassCastException cce) { 2386 throw new Exception(rb.getString("Not.X.509.certificate")); 2387 } 2388 if (certs.length > 1) { 2389 MessageFormat form = new MessageFormat 2390 (rb.getString("Certificate.i.1.")); 2391 Object[] source = {i + 1}; 2392 out.println(form.format(source)); 2393 } 2394 if (rfc) 2395 dumpCert(x509Cert, out); 2396 else 2397 printX509Cert(x509Cert, out); 2398 if (i < (certs.length-1)) { 2399 out.println(); 2400 } 2401 } 2402 } 2403 2404 private void doPrintCert(final PrintStream out) throws Exception { 2405 if (jarfile != null) { 2406 JarFile jf = new JarFile(jarfile, true); 2407 Enumeration<JarEntry> entries = jf.entries(); 2408 Set<CodeSigner> ss = new HashSet<>(); 2409 byte[] buffer = new byte[8192]; 2410 int pos = 0; 2411 while (entries.hasMoreElements()) { 2412 JarEntry je = entries.nextElement(); 2413 try (InputStream is = jf.getInputStream(je)) { 2414 while (is.read(buffer) != -1) { 2415 // we just read. this will throw a SecurityException 2416 // if a signature/digest check fails. This also 2417 // populate the signers 2418 } 2419 } 2420 CodeSigner[] signers = je.getCodeSigners(); 2421 if (signers != null) { 2422 for (CodeSigner signer: signers) { 2423 if (!ss.contains(signer)) { 2424 ss.add(signer); 2425 out.printf(rb.getString("Signer.d."), ++pos); 2426 out.println(); 2427 out.println(); 2428 out.println(rb.getString("Signature.")); 2429 out.println(); 2430 for (Certificate cert: signer.getSignerCertPath().getCertificates()) { 2431 X509Certificate x = (X509Certificate)cert; 2432 if (rfc) { 2433 out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n"); 2434 dumpCert(x, out); 2435 } else { 2436 printX509Cert(x, out); 2437 } 2438 out.println(); 2439 } 2440 Timestamp ts = signer.getTimestamp(); 2441 if (ts != null) { 2442 out.println(rb.getString("Timestamp.")); 2443 out.println(); 2444 for (Certificate cert: ts.getSignerCertPath().getCertificates()) { 2445 X509Certificate x = (X509Certificate)cert; 2446 if (rfc) { 2447 out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n"); 2448 dumpCert(x, out); 2449 } else { 2450 printX509Cert(x, out); 2451 } 2452 out.println(); 2453 } 2454 } 2455 } 2456 } 2457 } 2458 } 2459 jf.close(); 2460 if (ss.isEmpty()) { 2461 out.println(rb.getString("Not.a.signed.jar.file")); 2462 } 2463 } else if (sslserver != null) { 2464 CertStore cs = SSLServerCertStore.getInstance(new URI("https://" + sslserver)); 2465 Collection<? extends Certificate> chain; 2466 try { 2467 chain = cs.getCertificates(null); 2468 if (chain.isEmpty()) { 2469 // If the certs are not retrieved, we consider it an error 2470 // even if the URL connection is successful. 2471 throw new Exception(rb.getString( 2472 "No.certificate.from.the.SSL.server")); 2473 } 2474 } catch (CertStoreException cse) { 2475 if (cse.getCause() instanceof IOException) { 2476 throw new Exception(rb.getString( 2477 "No.certificate.from.the.SSL.server"), 2478 cse.getCause()); 2479 } else { 2480 throw cse; 2481 } 2482 } 2483 2484 int i = 0; 2485 for (Certificate cert : chain) { 2486 try { 2487 if (rfc) { 2488 dumpCert(cert, out); 2489 } else { 2490 out.println("Certificate #" + i++); 2491 out.println("===================================="); 2492 printX509Cert((X509Certificate)cert, out); 2493 out.println(); 2494 } 2495 } catch (Exception e) { 2496 if (debug) { 2497 e.printStackTrace(); 2498 } 2499 } 2500 } 2501 } else { 2502 if (filename != null) { 2503 try (FileInputStream inStream = new FileInputStream(filename)) { 2504 printCertFromStream(inStream, out); 2505 } 2506 } else { 2507 printCertFromStream(System.in, out); 2508 } 2509 } 2510 } 2511 /** 2512 * Creates a self-signed certificate, and stores it as a single-element 2513 * certificate chain. 2514 */ 2515 private void doSelfCert(String alias, String dname, String sigAlgName) 2516 throws Exception 2517 { 2518 if (alias == null) { 2519 alias = keyAlias; 2520 } 2521 2522 Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass); 2523 PrivateKey privKey = (PrivateKey)objs.fst; 2524 if (keyPass == null) 2525 keyPass = objs.snd; 2526 2527 // Determine the signature algorithm 2528 if (sigAlgName == null) { 2529 sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm()); 2530 } 2531 2532 // Get the old certificate 2533 Certificate oldCert = keyStore.getCertificate(alias); 2534 if (oldCert == null) { 2535 MessageFormat form = new MessageFormat 2536 (rb.getString("alias.has.no.public.key")); 2537 Object[] source = {alias}; 2538 throw new Exception(form.format(source)); 2539 } 2540 if (!(oldCert instanceof X509Certificate)) { 2541 MessageFormat form = new MessageFormat 2542 (rb.getString("alias.has.no.X.509.certificate")); 2543 Object[] source = {alias}; 2544 throw new Exception(form.format(source)); 2545 } 2546 2547 // convert to X509CertImpl, so that we can modify selected fields 2548 // (no public APIs available yet) 2549 byte[] encoded = oldCert.getEncoded(); 2550 X509CertImpl certImpl = new X509CertImpl(encoded); 2551 X509CertInfo certInfo = (X509CertInfo)certImpl.get(X509CertImpl.NAME 2552 + "." + 2553 X509CertImpl.INFO); 2554 2555 // Extend its validity 2556 Date firstDate = getStartDate(startDate); 2557 Date lastDate = new Date(); 2558 lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L); 2559 CertificateValidity interval = new CertificateValidity(firstDate, 2560 lastDate); 2561 certInfo.set(X509CertInfo.VALIDITY, interval); 2562 2563 // Make new serial number 2564 certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( 2565 new java.util.Random().nextInt() & 0x7fffffff)); 2566 2567 // Set owner and issuer fields 2568 X500Name owner; 2569 if (dname == null) { 2570 // Get the owner name from the certificate 2571 owner = (X500Name)certInfo.get(X509CertInfo.SUBJECT + "." + 2572 X509CertInfo.DN_NAME); 2573 } else { 2574 // Use the owner name specified at the command line 2575 owner = new X500Name(dname); 2576 certInfo.set(X509CertInfo.SUBJECT + "." + 2577 X509CertInfo.DN_NAME, owner); 2578 } 2579 // Make issuer same as owner (self-signed!) 2580 certInfo.set(X509CertInfo.ISSUER + "." + 2581 X509CertInfo.DN_NAME, owner); 2582 2583 // The inner and outer signature algorithms have to match. 2584 // The way we achieve that is really ugly, but there seems to be no 2585 // other solution: We first sign the cert, then retrieve the 2586 // outer sigalg and use it to set the inner sigalg 2587 X509CertImpl newCert = new X509CertImpl(certInfo); 2588 newCert.sign(privKey, sigAlgName); 2589 AlgorithmId sigAlgid = (AlgorithmId)newCert.get(X509CertImpl.SIG_ALG); 2590 certInfo.set(CertificateAlgorithmId.NAME + "." + 2591 CertificateAlgorithmId.ALGORITHM, sigAlgid); 2592 2593 certInfo.set(X509CertInfo.VERSION, 2594 new CertificateVersion(CertificateVersion.V3)); 2595 2596 CertificateExtensions ext = createV3Extensions( 2597 null, 2598 (CertificateExtensions)certInfo.get(X509CertInfo.EXTENSIONS), 2599 v3ext, 2600 oldCert.getPublicKey(), 2601 null); 2602 certInfo.set(X509CertInfo.EXTENSIONS, ext); 2603 // Sign the new certificate 2604 newCert = new X509CertImpl(certInfo); 2605 newCert.sign(privKey, sigAlgName); 2606 2607 // Store the new certificate as a single-element certificate chain 2608 keyStore.setKeyEntry(alias, privKey, 2609 (keyPass != null) ? keyPass : storePass, 2610 new Certificate[] { newCert } ); 2611 2612 if (verbose) { 2613 System.err.println(rb.getString("New.certificate.self.signed.")); 2614 System.err.print(newCert.toString()); 2615 System.err.println(); 2616 } 2617 } 2618 2619 /** 2620 * Processes a certificate reply from a certificate authority. 2621 * 2622 * <p>Builds a certificate chain on top of the certificate reply, 2623 * using trusted certificates from the keystore. The chain is complete 2624 * after a self-signed certificate has been encountered. The self-signed 2625 * certificate is considered a root certificate authority, and is stored 2626 * at the end of the chain. 2627 * 2628 * <p>The newly generated chain replaces the old chain associated with the 2629 * key entry. 2630 * 2631 * @return true if the certificate reply was installed, otherwise false. 2632 */ 2633 private boolean installReply(String alias, InputStream in) 2634 throws Exception 2635 { 2636 if (alias == null) { 2637 alias = keyAlias; 2638 } 2639 2640 Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass); 2641 PrivateKey privKey = (PrivateKey)objs.fst; 2642 if (keyPass == null) { 2643 keyPass = objs.snd; 2644 } 2645 2646 Certificate userCert = keyStore.getCertificate(alias); 2647 if (userCert == null) { 2648 MessageFormat form = new MessageFormat 2649 (rb.getString("alias.has.no.public.key.certificate.")); 2650 Object[] source = {alias}; 2651 throw new Exception(form.format(source)); 2652 } 2653 2654 // Read the certificates in the reply 2655 Collection<? extends Certificate> c = cf.generateCertificates(in); 2656 if (c.isEmpty()) { 2657 throw new Exception(rb.getString("Reply.has.no.certificates")); 2658 } 2659 Certificate[] replyCerts = c.toArray(new Certificate[c.size()]); 2660 Certificate[] newChain; 2661 if (replyCerts.length == 1) { 2662 // single-cert reply 2663 newChain = establishCertChain(userCert, replyCerts[0]); 2664 } else { 2665 // cert-chain reply (e.g., PKCS#7) 2666 newChain = validateReply(alias, userCert, replyCerts); 2667 } 2668 2669 // Now store the newly established chain in the keystore. The new 2670 // chain replaces the old one. 2671 if (newChain != null) { 2672 keyStore.setKeyEntry(alias, privKey, 2673 (keyPass != null) ? keyPass : storePass, 2674 newChain); 2675 return true; 2676 } else { 2677 return false; 2678 } 2679 } 2680 2681 /** 2682 * Imports a certificate and adds it to the list of trusted certificates. 2683 * 2684 * @return true if the certificate was added, otherwise false. 2685 */ 2686 private boolean addTrustedCert(String alias, InputStream in) 2687 throws Exception 2688 { 2689 if (alias == null) { 2690 throw new Exception(rb.getString("Must.specify.alias")); 2691 } 2692 if (keyStore.containsAlias(alias)) { 2693 MessageFormat form = new MessageFormat(rb.getString 2694 ("Certificate.not.imported.alias.alias.already.exists")); 2695 Object[] source = {alias}; 2696 throw new Exception(form.format(source)); 2697 } 2698 2699 // Read the certificate 2700 X509Certificate cert = null; 2701 try { 2702 cert = (X509Certificate)cf.generateCertificate(in); 2703 } catch (ClassCastException | CertificateException ce) { 2704 throw new Exception(rb.getString("Input.not.an.X.509.certificate")); 2705 } 2706 2707 // if certificate is self-signed, make sure it verifies 2708 boolean selfSigned = false; 2709 if (KeyStoreUtil.isSelfSigned(cert)) { 2710 cert.verify(cert.getPublicKey()); 2711 selfSigned = true; 2712 } 2713 2714 if (noprompt) { 2715 keyStore.setCertificateEntry(alias, cert); 2716 return true; 2717 } 2718 2719 // check if cert already exists in keystore 2720 String reply = null; 2721 String trustalias = keyStore.getCertificateAlias(cert); 2722 if (trustalias != null) { 2723 MessageFormat form = new MessageFormat(rb.getString 2724 ("Certificate.already.exists.in.keystore.under.alias.trustalias.")); 2725 Object[] source = {trustalias}; 2726 System.err.println(form.format(source)); 2727 reply = getYesNoReply 2728 (rb.getString("Do.you.still.want.to.add.it.no.")); 2729 } else if (selfSigned) { 2730 if (trustcacerts && (caks != null) && 2731 ((trustalias=caks.getCertificateAlias(cert)) != null)) { 2732 MessageFormat form = new MessageFormat(rb.getString 2733 ("Certificate.already.exists.in.system.wide.CA.keystore.under.alias.trustalias.")); 2734 Object[] source = {trustalias}; 2735 System.err.println(form.format(source)); 2736 reply = getYesNoReply 2737 (rb.getString("Do.you.still.want.to.add.it.to.your.own.keystore.no.")); 2738 } 2739 if (trustalias == null) { 2740 // Print the cert and ask user if they really want to add 2741 // it to their keystore 2742 printX509Cert(cert, System.out); 2743 reply = getYesNoReply 2744 (rb.getString("Trust.this.certificate.no.")); 2745 } 2746 } 2747 if (reply != null) { 2748 if ("YES".equals(reply)) { 2749 keyStore.setCertificateEntry(alias, cert); 2750 return true; 2751 } else { 2752 return false; 2753 } 2754 } 2755 2756 // Try to establish trust chain 2757 try { 2758 Certificate[] chain = establishCertChain(null, cert); 2759 if (chain != null) { 2760 keyStore.setCertificateEntry(alias, cert); 2761 return true; 2762 } 2763 } catch (Exception e) { 2764 // Print the cert and ask user if they really want to add it to 2765 // their keystore 2766 printX509Cert(cert, System.out); 2767 reply = getYesNoReply 2768 (rb.getString("Trust.this.certificate.no.")); 2769 if ("YES".equals(reply)) { 2770 keyStore.setCertificateEntry(alias, cert); 2771 return true; 2772 } else { 2773 return false; 2774 } 2775 } 2776 2777 return false; 2778 } 2779 2780 /** 2781 * Prompts user for new password. New password must be different from 2782 * old one. 2783 * 2784 * @param prompt the message that gets prompted on the screen 2785 * @param oldPasswd the current (i.e., old) password 2786 */ 2787 private char[] getNewPasswd(String prompt, char[] oldPasswd) 2788 throws Exception 2789 { 2790 char[] entered = null; 2791 char[] reentered = null; 2792 2793 for (int count = 0; count < 3; count++) { 2794 MessageFormat form = new MessageFormat 2795 (rb.getString("New.prompt.")); 2796 Object[] source = {prompt}; 2797 System.err.print(form.format(source)); 2798 entered = Password.readPassword(System.in); 2799 passwords.add(entered); 2800 if (entered == null || entered.length < 6) { 2801 System.err.println(rb.getString 2802 ("Password.is.too.short.must.be.at.least.6.characters")); 2803 } else if (Arrays.equals(entered, oldPasswd)) { 2804 System.err.println(rb.getString("Passwords.must.differ")); 2805 } else { 2806 form = new MessageFormat 2807 (rb.getString("Re.enter.new.prompt.")); 2808 Object[] src = {prompt}; 2809 System.err.print(form.format(src)); 2810 reentered = Password.readPassword(System.in); 2811 passwords.add(reentered); 2812 if (!Arrays.equals(entered, reentered)) { 2813 System.err.println 2814 (rb.getString("They.don.t.match.Try.again")); 2815 } else { 2816 Arrays.fill(reentered, ' '); 2817 return entered; 2818 } 2819 } 2820 if (entered != null) { 2821 Arrays.fill(entered, ' '); 2822 entered = null; 2823 } 2824 if (reentered != null) { 2825 Arrays.fill(reentered, ' '); 2826 reentered = null; 2827 } 2828 } 2829 throw new Exception(rb.getString("Too.many.failures.try.later")); 2830 } 2831 2832 /** 2833 * Prompts user for alias name. 2834 * @param prompt the {0} of "Enter {0} alias name: " in prompt line 2835 * @return the string entered by the user, without the \n at the end 2836 */ 2837 private String getAlias(String prompt) throws Exception { 2838 if (prompt != null) { 2839 MessageFormat form = new MessageFormat 2840 (rb.getString("Enter.prompt.alias.name.")); 2841 Object[] source = {prompt}; 2842 System.err.print(form.format(source)); 2843 } else { 2844 System.err.print(rb.getString("Enter.alias.name.")); 2845 } 2846 return (new BufferedReader(new InputStreamReader( 2847 System.in))).readLine(); 2848 } 2849 2850 /** 2851 * Prompts user for an input string from the command line (System.in) 2852 * @prompt the prompt string printed 2853 * @return the string entered by the user, without the \n at the end 2854 */ 2855 private String inputStringFromStdin(String prompt) throws Exception { 2856 System.err.print(prompt); 2857 return (new BufferedReader(new InputStreamReader( 2858 System.in))).readLine(); 2859 } 2860 2861 /** 2862 * Prompts user for key password. User may select to choose the same 2863 * password (<code>otherKeyPass</code>) as for <code>otherAlias</code>. 2864 */ 2865 private char[] getKeyPasswd(String alias, String otherAlias, 2866 char[] otherKeyPass) 2867 throws Exception 2868 { 2869 int count = 0; 2870 char[] keyPass = null; 2871 2872 do { 2873 if (otherKeyPass != null) { 2874 MessageFormat form = new MessageFormat(rb.getString 2875 ("Enter.key.password.for.alias.")); 2876 Object[] source = {alias}; 2877 System.err.println(form.format(source)); 2878 2879 form = new MessageFormat(rb.getString 2880 (".RETURN.if.same.as.for.otherAlias.")); 2881 Object[] src = {otherAlias}; 2882 System.err.print(form.format(src)); 2883 } else { 2884 MessageFormat form = new MessageFormat(rb.getString 2885 ("Enter.key.password.for.alias.")); 2886 Object[] source = {alias}; 2887 System.err.print(form.format(source)); 2888 } 2889 System.err.flush(); 2890 keyPass = Password.readPassword(System.in); 2891 passwords.add(keyPass); 2892 if (keyPass == null) { 2893 keyPass = otherKeyPass; 2894 } 2895 count++; 2896 } while ((keyPass == null) && count < 3); 2897 2898 if (keyPass == null) { 2899 throw new Exception(rb.getString("Too.many.failures.try.later")); 2900 } 2901 2902 return keyPass; 2903 } 2904 2905 /** 2906 * Prints a certificate in a human readable format. 2907 */ 2908 private void printX509Cert(X509Certificate cert, PrintStream out) 2909 throws Exception 2910 { 2911 2912 MessageFormat form = new MessageFormat 2913 (rb.getString(".PATTERN.printX509Cert")); 2914 PublicKey pkey = cert.getPublicKey(); 2915 Object[] source = {cert.getSubjectDN().toString(), 2916 cert.getIssuerDN().toString(), 2917 cert.getSerialNumber().toString(16), 2918 cert.getNotBefore().toString(), 2919 cert.getNotAfter().toString(), 2920 getCertFingerPrint("SHA-1", cert), 2921 getCertFingerPrint("SHA-256", cert), 2922 cert.getSigAlgName(), 2923 pkey.getAlgorithm(), 2924 KeyUtil.getKeySize(pkey), 2925 cert.getVersion(), 2926 }; 2927 out.println(form.format(source)); 2928 2929 if (cert instanceof X509CertImpl) { 2930 X509CertImpl impl = (X509CertImpl)cert; 2931 X509CertInfo certInfo = (X509CertInfo)impl.get(X509CertImpl.NAME 2932 + "." + 2933 X509CertImpl.INFO); 2934 CertificateExtensions exts = (CertificateExtensions) 2935 certInfo.get(X509CertInfo.EXTENSIONS); 2936 if (exts != null) { 2937 printExtensions(rb.getString("Extensions."), exts, out); 2938 } 2939 } 2940 } 2941 2942 private static void printExtensions(String title, CertificateExtensions exts, PrintStream out) 2943 throws Exception { 2944 int extnum = 0; 2945 Iterator<Extension> i1 = exts.getAllExtensions().iterator(); 2946 Iterator<Extension> i2 = exts.getUnparseableExtensions().values().iterator(); 2947 while (i1.hasNext() || i2.hasNext()) { 2948 Extension ext = i1.hasNext()?i1.next():i2.next(); 2949 if (extnum == 0) { 2950 out.println(); 2951 out.println(title); 2952 out.println(); 2953 } 2954 out.print("#"+(++extnum)+": "+ ext); 2955 if (ext.getClass() == Extension.class) { 2956 byte[] v = ext.getExtensionValue(); 2957 if (v.length == 0) { 2958 out.println(rb.getString(".Empty.value.")); 2959 } else { 2960 new sun.security.util.HexDumpEncoder().encodeBuffer(ext.getExtensionValue(), out); 2961 out.println(); 2962 } 2963 } 2964 out.println(); 2965 } 2966 } 2967 2968 /** 2969 * Locates a signer for a given certificate from a given keystore and 2970 * returns the signer's certificate. 2971 * @param cert the certificate whose signer is searched, not null 2972 * @param ks the keystore to search with, not null 2973 * @return <code>cert</code> itself if it's already inside <code>ks</code>, 2974 * or a certificate inside <code>ks</code> who signs <code>cert</code>, 2975 * or null otherwise. 2976 */ 2977 private static Certificate getTrustedSigner(Certificate cert, KeyStore ks) 2978 throws Exception { 2979 if (ks.getCertificateAlias(cert) != null) { 2980 return cert; 2981 } 2982 for (Enumeration<String> aliases = ks.aliases(); 2983 aliases.hasMoreElements(); ) { 2984 String name = aliases.nextElement(); 2985 Certificate trustedCert = ks.getCertificate(name); 2986 if (trustedCert != null) { 2987 try { 2988 cert.verify(trustedCert.getPublicKey()); 2989 return trustedCert; 2990 } catch (Exception e) { 2991 // Not verified, skip to the next one 2992 } 2993 } 2994 } 2995 return null; 2996 } 2997 2998 /** 2999 * Gets an X.500 name suitable for inclusion in a certification request. 3000 */ 3001 private X500Name getX500Name() throws IOException { 3002 BufferedReader in; 3003 in = new BufferedReader(new InputStreamReader(System.in)); 3004 String commonName = "Unknown"; 3005 String organizationalUnit = "Unknown"; 3006 String organization = "Unknown"; 3007 String city = "Unknown"; 3008 String state = "Unknown"; 3009 String country = "Unknown"; 3010 X500Name name; 3011 String userInput = null; 3012 3013 int maxRetry = 20; 3014 do { 3015 if (maxRetry-- < 0) { 3016 throw new RuntimeException(rb.getString( 3017 "Too.many.retries.program.terminated")); 3018 } 3019 commonName = inputString(in, 3020 rb.getString("What.is.your.first.and.last.name."), 3021 commonName); 3022 organizationalUnit = inputString(in, 3023 rb.getString 3024 ("What.is.the.name.of.your.organizational.unit."), 3025 organizationalUnit); 3026 organization = inputString(in, 3027 rb.getString("What.is.the.name.of.your.organization."), 3028 organization); 3029 city = inputString(in, 3030 rb.getString("What.is.the.name.of.your.City.or.Locality."), 3031 city); 3032 state = inputString(in, 3033 rb.getString("What.is.the.name.of.your.State.or.Province."), 3034 state); 3035 country = inputString(in, 3036 rb.getString 3037 ("What.is.the.two.letter.country.code.for.this.unit."), 3038 country); 3039 name = new X500Name(commonName, organizationalUnit, organization, 3040 city, state, country); 3041 MessageFormat form = new MessageFormat 3042 (rb.getString("Is.name.correct.")); 3043 Object[] source = {name}; 3044 userInput = inputString 3045 (in, form.format(source), rb.getString("no")); 3046 } while (collator.compare(userInput, rb.getString("yes")) != 0 && 3047 collator.compare(userInput, rb.getString("y")) != 0); 3048 3049 System.err.println(); 3050 return name; 3051 } 3052 3053 private String inputString(BufferedReader in, String prompt, 3054 String defaultValue) 3055 throws IOException 3056 { 3057 System.err.println(prompt); 3058 MessageFormat form = new MessageFormat 3059 (rb.getString(".defaultValue.")); 3060 Object[] source = {defaultValue}; 3061 System.err.print(form.format(source)); 3062 System.err.flush(); 3063 3064 String value = in.readLine(); 3065 if (value == null || collator.compare(value, "") == 0) { 3066 value = defaultValue; 3067 } 3068 return value; 3069 } 3070 3071 /** 3072 * Writes an X.509 certificate in base64 or binary encoding to an output 3073 * stream. 3074 */ 3075 private void dumpCert(Certificate cert, PrintStream out) 3076 throws IOException, CertificateException 3077 { 3078 if (rfc) { 3079 out.println(X509Factory.BEGIN_CERT); 3080 out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(cert.getEncoded())); 3081 out.println(X509Factory.END_CERT); 3082 } else { 3083 out.write(cert.getEncoded()); // binary 3084 } 3085 } 3086 3087 /** 3088 * Converts a byte to hex digit and writes to the supplied buffer 3089 */ 3090 private void byte2hex(byte b, StringBuffer buf) { 3091 char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', 3092 '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 3093 int high = ((b & 0xf0) >> 4); 3094 int low = (b & 0x0f); 3095 buf.append(hexChars[high]); 3096 buf.append(hexChars[low]); 3097 } 3098 3099 /** 3100 * Converts a byte array to hex string 3101 */ 3102 private String toHexString(byte[] block) { 3103 StringBuffer buf = new StringBuffer(); 3104 int len = block.length; 3105 for (int i = 0; i < len; i++) { 3106 byte2hex(block[i], buf); 3107 if (i < len-1) { 3108 buf.append(":"); 3109 } 3110 } 3111 return buf.toString(); 3112 } 3113 3114 /** 3115 * Recovers (private) key associated with given alias. 3116 * 3117 * @return an array of objects, where the 1st element in the array is the 3118 * recovered private key, and the 2nd element is the password used to 3119 * recover it. 3120 */ 3121 private Pair<Key,char[]> recoverKey(String alias, char[] storePass, 3122 char[] keyPass) 3123 throws Exception 3124 { 3125 Key key = null; 3126 3127 if (keyStore.containsAlias(alias) == false) { 3128 MessageFormat form = new MessageFormat 3129 (rb.getString("Alias.alias.does.not.exist")); 3130 Object[] source = {alias}; 3131 throw new Exception(form.format(source)); 3132 } 3133 if (!keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class) && 3134 !keyStore.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) { 3135 MessageFormat form = new MessageFormat 3136 (rb.getString("Alias.alias.has.no.key")); 3137 Object[] source = {alias}; 3138 throw new Exception(form.format(source)); 3139 } 3140 3141 if (keyPass == null) { 3142 // Try to recover the key using the keystore password 3143 try { 3144 key = keyStore.getKey(alias, storePass); 3145 3146 keyPass = storePass; 3147 passwords.add(keyPass); 3148 } catch (UnrecoverableKeyException e) { 3149 // Did not work out, so prompt user for key password 3150 if (!token) { 3151 keyPass = getKeyPasswd(alias, null, null); 3152 key = keyStore.getKey(alias, keyPass); 3153 } else { 3154 throw e; 3155 } 3156 } 3157 } else { 3158 key = keyStore.getKey(alias, keyPass); 3159 } 3160 3161 return Pair.of(key, keyPass); 3162 } 3163 3164 /** 3165 * Recovers entry associated with given alias. 3166 * 3167 * @return an array of objects, where the 1st element in the array is the 3168 * recovered entry, and the 2nd element is the password used to 3169 * recover it (null if no password). 3170 */ 3171 private Pair<Entry,char[]> recoverEntry(KeyStore ks, 3172 String alias, 3173 char[] pstore, 3174 char[] pkey) throws Exception { 3175 3176 if (ks.containsAlias(alias) == false) { 3177 MessageFormat form = new MessageFormat 3178 (rb.getString("Alias.alias.does.not.exist")); 3179 Object[] source = {alias}; 3180 throw new Exception(form.format(source)); 3181 } 3182 3183 PasswordProtection pp = null; 3184 Entry entry; 3185 3186 try { 3187 // First attempt to access entry without key password 3188 // (PKCS11 entry or trusted certificate entry, for example) 3189 3190 entry = ks.getEntry(alias, pp); 3191 pkey = null; 3192 } catch (UnrecoverableEntryException une) { 3193 3194 if(P11KEYSTORE.equalsIgnoreCase(ks.getType()) || 3195 KeyStoreUtil.isWindowsKeyStore(ks.getType())) { 3196 // should not happen, but a possibility 3197 throw une; 3198 } 3199 3200 // entry is protected 3201 3202 if (pkey != null) { 3203 3204 // try provided key password 3205 3206 pp = new PasswordProtection(pkey); 3207 entry = ks.getEntry(alias, pp); 3208 3209 } else { 3210 3211 // try store pass 3212 3213 try { 3214 pp = new PasswordProtection(pstore); 3215 entry = ks.getEntry(alias, pp); 3216 pkey = pstore; 3217 } catch (UnrecoverableEntryException une2) { 3218 if (P12KEYSTORE.equalsIgnoreCase(ks.getType())) { 3219 3220 // P12 keystore currently does not support separate 3221 // store and entry passwords 3222 3223 throw une2; 3224 } else { 3225 3226 // prompt for entry password 3227 3228 pkey = getKeyPasswd(alias, null, null); 3229 pp = new PasswordProtection(pkey); 3230 entry = ks.getEntry(alias, pp); 3231 } 3232 } 3233 } 3234 } 3235 3236 return Pair.of(entry, pkey); 3237 } 3238 /** 3239 * Gets the requested finger print of the certificate. 3240 */ 3241 private String getCertFingerPrint(String mdAlg, Certificate cert) 3242 throws Exception 3243 { 3244 byte[] encCertInfo = cert.getEncoded(); 3245 MessageDigest md = MessageDigest.getInstance(mdAlg); 3246 byte[] digest = md.digest(encCertInfo); 3247 return toHexString(digest); 3248 } 3249 3250 /** 3251 * Prints warning about missing integrity check. 3252 */ 3253 private void printWarning() { 3254 System.err.println(); 3255 System.err.println(rb.getString 3256 (".WARNING.WARNING.WARNING.")); 3257 System.err.println(rb.getString 3258 (".The.integrity.of.the.information.stored.in.your.keystore.")); 3259 System.err.println(rb.getString 3260 (".WARNING.WARNING.WARNING.")); 3261 System.err.println(); 3262 } 3263 3264 /** 3265 * Validates chain in certification reply, and returns the ordered 3266 * elements of the chain (with user certificate first, and root 3267 * certificate last in the array). 3268 * 3269 * @param alias the alias name 3270 * @param userCert the user certificate of the alias 3271 * @param replyCerts the chain provided in the reply 3272 */ 3273 private Certificate[] validateReply(String alias, 3274 Certificate userCert, 3275 Certificate[] replyCerts) 3276 throws Exception 3277 { 3278 // order the certs in the reply (bottom-up). 3279 // we know that all certs in the reply are of type X.509, because 3280 // we parsed them using an X.509 certificate factory 3281 int i; 3282 PublicKey userPubKey = userCert.getPublicKey(); 3283 for (i=0; i<replyCerts.length; i++) { 3284 if (userPubKey.equals(replyCerts[i].getPublicKey())) { 3285 break; 3286 } 3287 } 3288 if (i == replyCerts.length) { 3289 MessageFormat form = new MessageFormat(rb.getString 3290 ("Certificate.reply.does.not.contain.public.key.for.alias.")); 3291 Object[] source = {alias}; 3292 throw new Exception(form.format(source)); 3293 } 3294 3295 Certificate tmpCert = replyCerts[0]; 3296 replyCerts[0] = replyCerts[i]; 3297 replyCerts[i] = tmpCert; 3298 3299 X509Certificate thisCert = (X509Certificate)replyCerts[0]; 3300 3301 for (i=1; i < replyCerts.length-1; i++) { 3302 // find a cert in the reply who signs thisCert 3303 int j; 3304 for (j=i; j<replyCerts.length; j++) { 3305 if (KeyStoreUtil.signedBy(thisCert, (X509Certificate)replyCerts[j])) { 3306 tmpCert = replyCerts[i]; 3307 replyCerts[i] = replyCerts[j]; 3308 replyCerts[j] = tmpCert; 3309 thisCert = (X509Certificate)replyCerts[i]; 3310 break; 3311 } 3312 } 3313 if (j == replyCerts.length) { 3314 throw new Exception 3315 (rb.getString("Incomplete.certificate.chain.in.reply")); 3316 } 3317 } 3318 3319 if (noprompt) { 3320 return replyCerts; 3321 } 3322 3323 // do we trust the cert at the top? 3324 Certificate topCert = replyCerts[replyCerts.length-1]; 3325 Certificate root = getTrustedSigner(topCert, keyStore); 3326 if (root == null && trustcacerts && caks != null) { 3327 root = getTrustedSigner(topCert, caks); 3328 } 3329 if (root == null) { 3330 System.err.println(); 3331 System.err.println 3332 (rb.getString("Top.level.certificate.in.reply.")); 3333 printX509Cert((X509Certificate)topCert, System.out); 3334 System.err.println(); 3335 System.err.print(rb.getString(".is.not.trusted.")); 3336 String reply = getYesNoReply 3337 (rb.getString("Install.reply.anyway.no.")); 3338 if ("NO".equals(reply)) { 3339 return null; 3340 } 3341 } else { 3342 if (root != topCert) { 3343 // append the root CA cert to the chain 3344 Certificate[] tmpCerts = 3345 new Certificate[replyCerts.length+1]; 3346 System.arraycopy(replyCerts, 0, tmpCerts, 0, 3347 replyCerts.length); 3348 tmpCerts[tmpCerts.length-1] = root; 3349 replyCerts = tmpCerts; 3350 } 3351 } 3352 3353 return replyCerts; 3354 } 3355 3356 /** 3357 * Establishes a certificate chain (using trusted certificates in the 3358 * keystore), starting with the user certificate 3359 * and ending at a self-signed certificate found in the keystore. 3360 * 3361 * @param userCert the user certificate of the alias 3362 * @param certToVerify the single certificate provided in the reply 3363 */ 3364 private Certificate[] establishCertChain(Certificate userCert, 3365 Certificate certToVerify) 3366 throws Exception 3367 { 3368 if (userCert != null) { 3369 // Make sure that the public key of the certificate reply matches 3370 // the original public key in the keystore 3371 PublicKey origPubKey = userCert.getPublicKey(); 3372 PublicKey replyPubKey = certToVerify.getPublicKey(); 3373 if (!origPubKey.equals(replyPubKey)) { 3374 throw new Exception(rb.getString 3375 ("Public.keys.in.reply.and.keystore.don.t.match")); 3376 } 3377 3378 // If the two certs are identical, we're done: no need to import 3379 // anything 3380 if (certToVerify.equals(userCert)) { 3381 throw new Exception(rb.getString 3382 ("Certificate.reply.and.certificate.in.keystore.are.identical")); 3383 } 3384 } 3385 3386 // Build a hash table of all certificates in the keystore. 3387 // Use the subject distinguished name as the key into the hash table. 3388 // All certificates associated with the same subject distinguished 3389 // name are stored in the same hash table entry as a vector. 3390 Hashtable<Principal, Vector<Certificate>> certs = null; 3391 if (keyStore.size() > 0) { 3392 certs = new Hashtable<Principal, Vector<Certificate>>(11); 3393 keystorecerts2Hashtable(keyStore, certs); 3394 } 3395 if (trustcacerts) { 3396 if (caks!=null && caks.size()>0) { 3397 if (certs == null) { 3398 certs = new Hashtable<Principal, Vector<Certificate>>(11); 3399 } 3400 keystorecerts2Hashtable(caks, certs); 3401 } 3402 } 3403 3404 // start building chain 3405 Vector<Certificate> chain = new Vector<>(2); 3406 if (buildChain((X509Certificate)certToVerify, chain, certs)) { 3407 Certificate[] newChain = new Certificate[chain.size()]; 3408 // buildChain() returns chain with self-signed root-cert first and 3409 // user-cert last, so we need to invert the chain before we store 3410 // it 3411 int j=0; 3412 for (int i=chain.size()-1; i>=0; i--) { 3413 newChain[j] = chain.elementAt(i); 3414 j++; 3415 } 3416 return newChain; 3417 } else { 3418 throw new Exception 3419 (rb.getString("Failed.to.establish.chain.from.reply")); 3420 } 3421 } 3422 3423 /** 3424 * Recursively tries to establish chain from pool of trusted certs. 3425 * 3426 * @param certToVerify the cert that needs to be verified. 3427 * @param chain the chain that's being built. 3428 * @param certs the pool of trusted certs 3429 * 3430 * @return true if successful, false otherwise. 3431 */ 3432 private boolean buildChain(X509Certificate certToVerify, 3433 Vector<Certificate> chain, 3434 Hashtable<Principal, Vector<Certificate>> certs) { 3435 Principal issuer = certToVerify.getIssuerDN(); 3436 if (KeyStoreUtil.isSelfSigned(certToVerify)) { 3437 // reached self-signed root cert; 3438 // no verification needed because it's trusted. 3439 chain.addElement(certToVerify); 3440 return true; 3441 } 3442 3443 // Get the issuer's certificate(s) 3444 Vector<Certificate> vec = certs.get(issuer); 3445 if (vec == null) { 3446 return false; 3447 } 3448 3449 // Try out each certificate in the vector, until we find one 3450 // whose public key verifies the signature of the certificate 3451 // in question. 3452 for (Enumeration<Certificate> issuerCerts = vec.elements(); 3453 issuerCerts.hasMoreElements(); ) { 3454 X509Certificate issuerCert 3455 = (X509Certificate)issuerCerts.nextElement(); 3456 PublicKey issuerPubKey = issuerCert.getPublicKey(); 3457 try { 3458 certToVerify.verify(issuerPubKey); 3459 } catch (Exception e) { 3460 continue; 3461 } 3462 if (buildChain(issuerCert, chain, certs)) { 3463 chain.addElement(certToVerify); 3464 return true; 3465 } 3466 } 3467 return false; 3468 } 3469 3470 /** 3471 * Prompts user for yes/no decision. 3472 * 3473 * @return the user's decision, can only be "YES" or "NO" 3474 */ 3475 private String getYesNoReply(String prompt) 3476 throws IOException 3477 { 3478 String reply = null; 3479 int maxRetry = 20; 3480 do { 3481 if (maxRetry-- < 0) { 3482 throw new RuntimeException(rb.getString( 3483 "Too.many.retries.program.terminated")); 3484 } 3485 System.err.print(prompt); 3486 System.err.flush(); 3487 reply = (new BufferedReader(new InputStreamReader 3488 (System.in))).readLine(); 3489 if (collator.compare(reply, "") == 0 || 3490 collator.compare(reply, rb.getString("n")) == 0 || 3491 collator.compare(reply, rb.getString("no")) == 0) { 3492 reply = "NO"; 3493 } else if (collator.compare(reply, rb.getString("y")) == 0 || 3494 collator.compare(reply, rb.getString("yes")) == 0) { 3495 reply = "YES"; 3496 } else { 3497 System.err.println(rb.getString("Wrong.answer.try.again")); 3498 reply = null; 3499 } 3500 } while (reply == null); 3501 return reply; 3502 } 3503 3504 /** 3505 * Stores the (leaf) certificates of a keystore in a hashtable. 3506 * All certs belonging to the same CA are stored in a vector that 3507 * in turn is stored in the hashtable, keyed by the CA's subject DN 3508 */ 3509 private void keystorecerts2Hashtable(KeyStore ks, 3510 Hashtable<Principal, Vector<Certificate>> hash) 3511 throws Exception { 3512 3513 for (Enumeration<String> aliases = ks.aliases(); 3514 aliases.hasMoreElements(); ) { 3515 String alias = aliases.nextElement(); 3516 Certificate cert = ks.getCertificate(alias); 3517 if (cert != null) { 3518 Principal subjectDN = ((X509Certificate)cert).getSubjectDN(); 3519 Vector<Certificate> vec = hash.get(subjectDN); 3520 if (vec == null) { 3521 vec = new Vector<Certificate>(); 3522 vec.addElement(cert); 3523 } else { 3524 if (!vec.contains(cert)) { 3525 vec.addElement(cert); 3526 } 3527 } 3528 hash.put(subjectDN, vec); 3529 } 3530 } 3531 } 3532 3533 /** 3534 * Returns the issue time that's specified the -startdate option 3535 * @param s the value of -startdate option 3536 */ 3537 private static Date getStartDate(String s) throws IOException { 3538 Calendar c = new GregorianCalendar(); 3539 if (s != null) { 3540 IOException ioe = new IOException( 3541 rb.getString("Illegal.startdate.value")); 3542 int len = s.length(); 3543 if (len == 0) { 3544 throw ioe; 3545 } 3546 if (s.charAt(0) == '-' || s.charAt(0) == '+') { 3547 // Form 1: ([+-]nnn[ymdHMS])+ 3548 int start = 0; 3549 while (start < len) { 3550 int sign = 0; 3551 switch (s.charAt(start)) { 3552 case '+': sign = 1; break; 3553 case '-': sign = -1; break; 3554 default: throw ioe; 3555 } 3556 int i = start+1; 3557 for (; i<len; i++) { 3558 char ch = s.charAt(i); 3559 if (ch < '0' || ch > '9') break; 3560 } 3561 if (i == start+1) throw ioe; 3562 int number = Integer.parseInt(s.substring(start+1, i)); 3563 if (i >= len) throw ioe; 3564 int unit = 0; 3565 switch (s.charAt(i)) { 3566 case 'y': unit = Calendar.YEAR; break; 3567 case 'm': unit = Calendar.MONTH; break; 3568 case 'd': unit = Calendar.DATE; break; 3569 case 'H': unit = Calendar.HOUR; break; 3570 case 'M': unit = Calendar.MINUTE; break; 3571 case 'S': unit = Calendar.SECOND; break; 3572 default: throw ioe; 3573 } 3574 c.add(unit, sign * number); 3575 start = i + 1; 3576 } 3577 } else { 3578 // Form 2: [yyyy/mm/dd] [HH:MM:SS] 3579 String date = null, time = null; 3580 if (len == 19) { 3581 date = s.substring(0, 10); 3582 time = s.substring(11); 3583 if (s.charAt(10) != ' ') 3584 throw ioe; 3585 } else if (len == 10) { 3586 date = s; 3587 } else if (len == 8) { 3588 time = s; 3589 } else { 3590 throw ioe; 3591 } 3592 if (date != null) { 3593 if (date.matches("\\d\\d\\d\\d\\/\\d\\d\\/\\d\\d")) { 3594 c.set(Integer.valueOf(date.substring(0, 4)), 3595 Integer.valueOf(date.substring(5, 7))-1, 3596 Integer.valueOf(date.substring(8, 10))); 3597 } else { 3598 throw ioe; 3599 } 3600 } 3601 if (time != null) { 3602 if (time.matches("\\d\\d:\\d\\d:\\d\\d")) { 3603 c.set(Calendar.HOUR_OF_DAY, Integer.valueOf(time.substring(0, 2))); 3604 c.set(Calendar.MINUTE, Integer.valueOf(time.substring(0, 2))); 3605 c.set(Calendar.SECOND, Integer.valueOf(time.substring(0, 2))); 3606 c.set(Calendar.MILLISECOND, 0); 3607 } else { 3608 throw ioe; 3609 } 3610 } 3611 } 3612 } 3613 return c.getTime(); 3614 } 3615 3616 /** 3617 * Match a command (may be abbreviated) with a command set. 3618 * @param s the command provided 3619 * @param list the legal command set. If there is a null, commands after it 3620 * are regarded experimental, which means they are supported but their 3621 * existence should not be revealed to user. 3622 * @return the position of a single match, or -1 if none matched 3623 * @throws Exception if s is ambiguous 3624 */ 3625 private static int oneOf(String s, String... list) throws Exception { 3626 int[] match = new int[list.length]; 3627 int nmatch = 0; 3628 int experiment = Integer.MAX_VALUE; 3629 for (int i = 0; i<list.length; i++) { 3630 String one = list[i]; 3631 if (one == null) { 3632 experiment = i; 3633 continue; 3634 } 3635 if (one.toLowerCase(Locale.ENGLISH) 3636 .startsWith(s.toLowerCase(Locale.ENGLISH))) { 3637 match[nmatch++] = i; 3638 } else { 3639 StringBuilder sb = new StringBuilder(); 3640 boolean first = true; 3641 for (char c: one.toCharArray()) { 3642 if (first) { 3643 sb.append(c); 3644 first = false; 3645 } else { 3646 if (!Character.isLowerCase(c)) { 3647 sb.append(c); 3648 } 3649 } 3650 } 3651 if (sb.toString().equalsIgnoreCase(s)) { 3652 match[nmatch++] = i; 3653 } 3654 } 3655 } 3656 if (nmatch == 0) { 3657 return -1; 3658 } else if (nmatch == 1) { 3659 return match[0]; 3660 } else { 3661 // If multiple matches is in experimental commands, ignore them 3662 if (match[1] > experiment) { 3663 return match[0]; 3664 } 3665 StringBuilder sb = new StringBuilder(); 3666 MessageFormat form = new MessageFormat(rb.getString 3667 ("command.{0}.is.ambiguous.")); 3668 Object[] source = {s}; 3669 sb.append(form.format(source)); 3670 sb.append("\n "); 3671 for (int i=0; i<nmatch && match[i]<experiment; i++) { 3672 sb.append(' '); 3673 sb.append(list[match[i]]); 3674 } 3675 throw new Exception(sb.toString()); 3676 } 3677 } 3678 3679 /** 3680 * Create a GeneralName object from known types 3681 * @param t one of 5 known types 3682 * @param v value 3683 * @return which one 3684 */ 3685 private GeneralName createGeneralName(String t, String v) 3686 throws Exception { 3687 GeneralNameInterface gn; 3688 int p = oneOf(t, "EMAIL", "URI", "DNS", "IP", "OID"); 3689 if (p < 0) { 3690 throw new Exception(rb.getString( 3691 "Unrecognized.GeneralName.type.") + t); 3692 } 3693 switch (p) { 3694 case 0: gn = new RFC822Name(v); break; 3695 case 1: gn = new URIName(v); break; 3696 case 2: gn = new DNSName(v); break; 3697 case 3: gn = new IPAddressName(v); break; 3698 default: gn = new OIDName(v); break; //4 3699 } 3700 return new GeneralName(gn); 3701 } 3702 3703 private static final String[] extSupported = { 3704 "BasicConstraints", 3705 "KeyUsage", 3706 "ExtendedKeyUsage", 3707 "SubjectAlternativeName", 3708 "IssuerAlternativeName", 3709 "SubjectInfoAccess", 3710 "AuthorityInfoAccess", 3711 null, 3712 "CRLDistributionPoints", 3713 }; 3714 3715 private ObjectIdentifier findOidForExtName(String type) 3716 throws Exception { 3717 switch (oneOf(type, extSupported)) { 3718 case 0: return PKIXExtensions.BasicConstraints_Id; 3719 case 1: return PKIXExtensions.KeyUsage_Id; 3720 case 2: return PKIXExtensions.ExtendedKeyUsage_Id; 3721 case 3: return PKIXExtensions.SubjectAlternativeName_Id; 3722 case 4: return PKIXExtensions.IssuerAlternativeName_Id; 3723 case 5: return PKIXExtensions.SubjectInfoAccess_Id; 3724 case 6: return PKIXExtensions.AuthInfoAccess_Id; 3725 case 8: return PKIXExtensions.CRLDistributionPoints_Id; 3726 default: return new ObjectIdentifier(type); 3727 } 3728 } 3729 3730 // Add an extension into a CertificateExtensions, always using OID as key 3731 private static void setExt(CertificateExtensions result, Extension ex) 3732 throws IOException { 3733 result.set(ex.getId(), ex); 3734 } 3735 3736 /** 3737 * Create X509v3 extensions from a string representation. Note that the 3738 * SubjectKeyIdentifierExtension will always be created non-critical besides 3739 * the extension requested in the <code>extstr</code> argument. 3740 * 3741 * @param requestedEx the requested extensions, can be null, used for -gencert 3742 * @param existingEx the original extensions, can be null, used for -selfcert 3743 * @param extstrs -ext values, Read keytool doc 3744 * @param pkey the public key for the certificate 3745 * @param akey the public key for the authority (issuer) 3746 * @return the created CertificateExtensions 3747 */ 3748 private CertificateExtensions createV3Extensions( 3749 CertificateExtensions requestedEx, 3750 CertificateExtensions existingEx, 3751 List <String> extstrs, 3752 PublicKey pkey, 3753 PublicKey akey) throws Exception { 3754 3755 // By design, inside a CertificateExtensions object, all known 3756 // extensions uses name (say, "BasicConstraints") as key and 3757 // a child Extension type (say, "BasicConstraintsExtension") 3758 // as value, unknown extensions uses OID as key and bare 3759 // Extension object as value. This works fine inside JDK. 3760 // 3761 // However, in keytool, there is no way to prevent people 3762 // using OID in -ext, either as a new extension, or in a 3763 // honored value. Thus here we (ab)use CertificateExtensions 3764 // by always using OID as key and value can be of any type. 3765 3766 if (existingEx != null && requestedEx != null) { 3767 // This should not happen 3768 throw new Exception("One of request and original should be null."); 3769 } 3770 // A new extensions always using OID as key 3771 CertificateExtensions result = new CertificateExtensions(); 3772 if (existingEx != null) { 3773 for (Extension ex: existingEx.getAllExtensions()) { 3774 setExt(result, ex); 3775 } 3776 } 3777 try { 3778 // name{:critical}{=value} 3779 // Honoring requested extensions 3780 if (requestedEx != null) { 3781 // The existing requestedEx might use names as keys, 3782 // translate to all-OID first. 3783 CertificateExtensions request2 = new CertificateExtensions(); 3784 for (sun.security.x509.Extension ex: requestedEx.getAllExtensions()) { 3785 request2.set(ex.getId(), ex); 3786 } 3787 for(String extstr: extstrs) { 3788 if (extstr.toLowerCase(Locale.ENGLISH).startsWith("honored=")) { 3789 List<String> list = Arrays.asList( 3790 extstr.toLowerCase(Locale.ENGLISH).substring(8).split(",")); 3791 // First check existence of "all" 3792 if (list.contains("all")) { 3793 for (Extension ex: request2.getAllExtensions()) { 3794 setExt(result, ex); 3795 } 3796 } 3797 // one by one for others 3798 for (String item: list) { 3799 if (item.equals("all")) continue; 3800 3801 // add or remove 3802 boolean add; 3803 // -1, unchanged, 0 critical, 1 non-critical 3804 int action = -1; 3805 String type = null; 3806 if (item.startsWith("-")) { 3807 add = false; 3808 type = item.substring(1); 3809 } else { 3810 add = true; 3811 int colonpos = item.indexOf(':'); 3812 if (colonpos >= 0) { 3813 type = item.substring(0, colonpos); 3814 action = oneOf(item.substring(colonpos+1), 3815 "critical", "non-critical"); 3816 if (action == -1) { 3817 throw new Exception(rb.getString 3818 ("Illegal.value.") + item); 3819 } 3820 } else { 3821 type = item; 3822 } 3823 } 3824 String n = findOidForExtName(type).toString(); 3825 if (add) { 3826 Extension e = request2.get(n); 3827 if (!e.isCritical() && action == 0 3828 || e.isCritical() && action == 1) { 3829 e = Extension.newExtension( 3830 e.getExtensionId(), 3831 !e.isCritical(), 3832 e.getExtensionValue()); 3833 } 3834 setExt(result, e); 3835 } else { 3836 result.delete(n); 3837 } 3838 } 3839 break; 3840 } 3841 } 3842 } 3843 for(String extstr: extstrs) { 3844 String name, value; 3845 boolean isCritical = false; 3846 3847 int eqpos = extstr.indexOf('='); 3848 if (eqpos >= 0) { 3849 name = extstr.substring(0, eqpos); 3850 value = extstr.substring(eqpos+1); 3851 } else { 3852 name = extstr; 3853 value = null; 3854 } 3855 3856 int colonpos = name.indexOf(':'); 3857 if (colonpos >= 0) { 3858 if (oneOf(name.substring(colonpos+1), "critical") == 0) { 3859 isCritical = true; 3860 } 3861 name = name.substring(0, colonpos); 3862 } 3863 3864 if (name.equalsIgnoreCase("honored")) { 3865 continue; 3866 } 3867 int exttype = oneOf(name, extSupported); 3868 switch (exttype) { 3869 case 0: // BC 3870 int pathLen = -1; 3871 boolean isCA = false; 3872 if (value == null) { 3873 isCA = true; 3874 } else { 3875 try { // the abbr format 3876 pathLen = Integer.parseInt(value); 3877 isCA = true; 3878 } catch (NumberFormatException ufe) { 3879 // ca:true,pathlen:1 3880 for (String part: value.split(",")) { 3881 String[] nv = part.split(":"); 3882 if (nv.length != 2) { 3883 throw new Exception(rb.getString 3884 ("Illegal.value.") + extstr); 3885 } else { 3886 if (nv[0].equalsIgnoreCase("ca")) { 3887 isCA = Boolean.parseBoolean(nv[1]); 3888 } else if (nv[0].equalsIgnoreCase("pathlen")) { 3889 pathLen = Integer.parseInt(nv[1]); 3890 } else { 3891 throw new Exception(rb.getString 3892 ("Illegal.value.") + extstr); 3893 } 3894 } 3895 } 3896 } 3897 } 3898 setExt(result, new BasicConstraintsExtension(isCritical, isCA, 3899 pathLen)); 3900 break; 3901 case 1: // KU 3902 if(value != null) { 3903 boolean[] ok = new boolean[9]; 3904 for (String s: value.split(",")) { 3905 int p = oneOf(s, 3906 "digitalSignature", // (0), 3907 "nonRepudiation", // (1) 3908 "keyEncipherment", // (2), 3909 "dataEncipherment", // (3), 3910 "keyAgreement", // (4), 3911 "keyCertSign", // (5), 3912 "cRLSign", // (6), 3913 "encipherOnly", // (7), 3914 "decipherOnly", // (8) 3915 "contentCommitment" // also (1) 3916 ); 3917 if (p < 0) { 3918 throw new Exception(rb.getString("Unknown.keyUsage.type.") + s); 3919 } 3920 if (p == 9) p = 1; 3921 ok[p] = true; 3922 } 3923 KeyUsageExtension kue = new KeyUsageExtension(ok); 3924 // The above KeyUsageExtension constructor does not 3925 // allow isCritical value, so... 3926 setExt(result, Extension.newExtension( 3927 kue.getExtensionId(), 3928 isCritical, 3929 kue.getExtensionValue())); 3930 } else { 3931 throw new Exception(rb.getString 3932 ("Illegal.value.") + extstr); 3933 } 3934 break; 3935 case 2: // EKU 3936 if(value != null) { 3937 Vector<ObjectIdentifier> v = new Vector<>(); 3938 for (String s: value.split(",")) { 3939 int p = oneOf(s, 3940 "anyExtendedKeyUsage", 3941 "serverAuth", //1 3942 "clientAuth", //2 3943 "codeSigning", //3 3944 "emailProtection", //4 3945 "", //5 3946 "", //6 3947 "", //7 3948 "timeStamping", //8 3949 "OCSPSigning" //9 3950 ); 3951 if (p < 0) { 3952 try { 3953 v.add(new ObjectIdentifier(s)); 3954 } catch (Exception e) { 3955 throw new Exception(rb.getString( 3956 "Unknown.extendedkeyUsage.type.") + s); 3957 } 3958 } else if (p == 0) { 3959 v.add(new ObjectIdentifier("2.5.29.37.0")); 3960 } else { 3961 v.add(new ObjectIdentifier("1.3.6.1.5.5.7.3." + p)); 3962 } 3963 } 3964 setExt(result, new ExtendedKeyUsageExtension(isCritical, v)); 3965 } else { 3966 throw new Exception(rb.getString 3967 ("Illegal.value.") + extstr); 3968 } 3969 break; 3970 case 3: // SAN 3971 case 4: // IAN 3972 if(value != null) { 3973 String[] ps = value.split(","); 3974 GeneralNames gnames = new GeneralNames(); 3975 for(String item: ps) { 3976 colonpos = item.indexOf(':'); 3977 if (colonpos < 0) { 3978 throw new Exception("Illegal item " + item + " in " + extstr); 3979 } 3980 String t = item.substring(0, colonpos); 3981 String v = item.substring(colonpos+1); 3982 gnames.add(createGeneralName(t, v)); 3983 } 3984 if (exttype == 3) { 3985 setExt(result, new SubjectAlternativeNameExtension( 3986 isCritical, gnames)); 3987 } else { 3988 setExt(result, new IssuerAlternativeNameExtension( 3989 isCritical, gnames)); 3990 } 3991 } else { 3992 throw new Exception(rb.getString 3993 ("Illegal.value.") + extstr); 3994 } 3995 break; 3996 case 5: // SIA, always non-critical 3997 case 6: // AIA, always non-critical 3998 if (isCritical) { 3999 throw new Exception(rb.getString( 4000 "This.extension.cannot.be.marked.as.critical.") + extstr); 4001 } 4002 if(value != null) { 4003 List<AccessDescription> accessDescriptions = 4004 new ArrayList<>(); 4005 String[] ps = value.split(","); 4006 for(String item: ps) { 4007 colonpos = item.indexOf(':'); 4008 int colonpos2 = item.indexOf(':', colonpos+1); 4009 if (colonpos < 0 || colonpos2 < 0) { 4010 throw new Exception(rb.getString 4011 ("Illegal.value.") + extstr); 4012 } 4013 String m = item.substring(0, colonpos); 4014 String t = item.substring(colonpos+1, colonpos2); 4015 String v = item.substring(colonpos2+1); 4016 int p = oneOf(m, 4017 "", 4018 "ocsp", //1 4019 "caIssuers", //2 4020 "timeStamping", //3 4021 "", 4022 "caRepository" //5 4023 ); 4024 ObjectIdentifier oid; 4025 if (p < 0) { 4026 try { 4027 oid = new ObjectIdentifier(m); 4028 } catch (Exception e) { 4029 throw new Exception(rb.getString( 4030 "Unknown.AccessDescription.type.") + m); 4031 } 4032 } else { 4033 oid = new ObjectIdentifier("1.3.6.1.5.5.7.48." + p); 4034 } 4035 accessDescriptions.add(new AccessDescription( 4036 oid, createGeneralName(t, v))); 4037 } 4038 if (exttype == 5) { 4039 setExt(result, new SubjectInfoAccessExtension(accessDescriptions)); 4040 } else { 4041 setExt(result, new AuthorityInfoAccessExtension(accessDescriptions)); 4042 } 4043 } else { 4044 throw new Exception(rb.getString 4045 ("Illegal.value.") + extstr); 4046 } 4047 break; 4048 case 8: // CRL, experimental, only support 1 distributionpoint 4049 if(value != null) { 4050 String[] ps = value.split(","); 4051 GeneralNames gnames = new GeneralNames(); 4052 for(String item: ps) { 4053 colonpos = item.indexOf(':'); 4054 if (colonpos < 0) { 4055 throw new Exception("Illegal item " + item + " in " + extstr); 4056 } 4057 String t = item.substring(0, colonpos); 4058 String v = item.substring(colonpos+1); 4059 gnames.add(createGeneralName(t, v)); 4060 } 4061 setExt(result, new CRLDistributionPointsExtension( 4062 isCritical, Collections.singletonList( 4063 new DistributionPoint(gnames, null, null)))); 4064 } else { 4065 throw new Exception(rb.getString 4066 ("Illegal.value.") + extstr); 4067 } 4068 break; 4069 case -1: 4070 ObjectIdentifier oid = new ObjectIdentifier(name); 4071 byte[] data = null; 4072 if (value != null) { 4073 data = new byte[value.length() / 2 + 1]; 4074 int pos = 0; 4075 for (char c: value.toCharArray()) { 4076 int hex; 4077 if (c >= '0' && c <= '9') { 4078 hex = c - '0' ; 4079 } else if (c >= 'A' && c <= 'F') { 4080 hex = c - 'A' + 10; 4081 } else if (c >= 'a' && c <= 'f') { 4082 hex = c - 'a' + 10; 4083 } else { 4084 continue; 4085 } 4086 if (pos % 2 == 0) { 4087 data[pos/2] = (byte)(hex << 4); 4088 } else { 4089 data[pos/2] += hex; 4090 } 4091 pos++; 4092 } 4093 if (pos % 2 != 0) { 4094 throw new Exception(rb.getString( 4095 "Odd.number.of.hex.digits.found.") + extstr); 4096 } 4097 data = Arrays.copyOf(data, pos/2); 4098 } else { 4099 data = new byte[0]; 4100 } 4101 setExt(result, new Extension(oid, isCritical, 4102 new DerValue(DerValue.tag_OctetString, data) 4103 .toByteArray())); 4104 break; 4105 default: 4106 throw new Exception(rb.getString( 4107 "Unknown.extension.type.") + extstr); 4108 } 4109 } 4110 // always non-critical 4111 setExt(result, new SubjectKeyIdentifierExtension( 4112 new KeyIdentifier(pkey).getIdentifier())); 4113 if (akey != null && !pkey.equals(akey)) { 4114 setExt(result, new AuthorityKeyIdentifierExtension( 4115 new KeyIdentifier(akey), null, null)); 4116 } 4117 } catch(IOException e) { 4118 throw new RuntimeException(e); 4119 } 4120 return result; 4121 } 4122 4123 /** 4124 * Prints the usage of this tool. 4125 */ 4126 private void usage() { 4127 if (command != null) { 4128 System.err.println("keytool " + command + 4129 rb.getString(".OPTION.")); 4130 System.err.println(); 4131 System.err.println(rb.getString(command.description)); 4132 System.err.println(); 4133 System.err.println(rb.getString("Options.")); 4134 System.err.println(); 4135 4136 // Left and right sides of the options list 4137 String[] left = new String[command.options.length]; 4138 String[] right = new String[command.options.length]; 4139 4140 // Check if there's an unknown option 4141 boolean found = false; 4142 4143 // Length of left side of options list 4144 int lenLeft = 0; 4145 for (int j=0; j<left.length; j++) { 4146 Option opt = command.options[j]; 4147 left[j] = opt.toString(); 4148 if (opt.arg != null) left[j] += " " + opt.arg; 4149 if (left[j].length() > lenLeft) { 4150 lenLeft = left[j].length(); 4151 } 4152 right[j] = rb.getString(opt.description); 4153 } 4154 for (int j=0; j<left.length; j++) { 4155 System.err.printf(" %-" + lenLeft + "s %s\n", 4156 left[j], right[j]); 4157 } 4158 System.err.println(); 4159 System.err.println(rb.getString( 4160 "Use.keytool.help.for.all.available.commands")); 4161 } else { 4162 System.err.println(rb.getString( 4163 "Key.and.Certificate.Management.Tool")); 4164 System.err.println(); 4165 System.err.println(rb.getString("Commands.")); 4166 System.err.println(); 4167 for (Command c: Command.values()) { 4168 if (c == KEYCLONE) break; 4169 System.err.printf(" %-20s%s\n", c, rb.getString(c.description)); 4170 } 4171 System.err.println(); 4172 System.err.println(rb.getString( 4173 "Use.keytool.command.name.help.for.usage.of.command.name")); 4174 } 4175 } 4176 4177 private void tinyHelp() { 4178 usage(); 4179 if (debug) { 4180 throw new RuntimeException("NO BIG ERROR, SORRY"); 4181 } else { 4182 System.exit(1); 4183 } 4184 } 4185 4186 private void errorNeedArgument(String flag) { 4187 Object[] source = {flag}; 4188 System.err.println(new MessageFormat( 4189 rb.getString("Command.option.flag.needs.an.argument.")).format(source)); 4190 tinyHelp(); 4191 } 4192 4193 private char[] getPass(String modifier, String arg) { 4194 char[] output = KeyStoreUtil.getPassWithModifier(modifier, arg, rb); 4195 if (output != null) return output; 4196 tinyHelp(); 4197 return null; // Useless, tinyHelp() already exits. 4198 } 4199 } 4200 4201 // This class is exactly the same as com.sun.tools.javac.util.Pair, 4202 // it's copied here since the original one is not included in JRE. 4203 class Pair<A, B> { 4204 4205 public final A fst; 4206 public final B snd; 4207 4208 public Pair(A fst, B snd) { 4209 this.fst = fst; 4210 this.snd = snd; 4211 } 4212 4213 public String toString() { 4214 return "Pair[" + fst + "," + snd + "]"; 4215 } 4216 4217 public boolean equals(Object other) { 4218 return 4219 other instanceof Pair && 4220 Objects.equals(fst, ((Pair)other).fst) && 4221 Objects.equals(snd, ((Pair)other).snd); 4222 } 4223 4224 public int hashCode() { 4225 if (fst == null) return (snd == null) ? 0 : snd.hashCode() + 1; 4226 else if (snd == null) return fst.hashCode() + 2; 4227 else return fst.hashCode() * 17 + snd.hashCode(); 4228 } 4229 4230 public static <A,B> Pair<A,B> of(A a, B b) { 4231 return new Pair<>(a,b); 4232 } 4233 } 4234