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