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