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