History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/tools/KeyTool.java (1 of 18352 files). Show all

Unified · Split

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