1 /*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.security.tools.keytool;
27
28 import java.io.*;
29 import java.security.CodeSigner;
30 import java.security.KeyStore;
31 import java.security.KeyStoreException;
32 import java.security.MessageDigest;
33 import java.security.Key;
34 import java.security.PublicKey;
35 import java.security.PrivateKey;
36 import java.security.Security;
37 import java.security.Signature;
38 import java.security.Timestamp;
39 import java.security.UnrecoverableEntryException;
40 import java.security.UnrecoverableKeyException;
41 import java.security.NoSuchAlgorithmException;
42 import java.security.Principal;
43 import java.security.Provider;
44 import java.security.cert.Certificate;
45 import java.security.cert.CertificateFactory;
46 import java.security.cert.CertStoreException;
47 import java.security.cert.CRL;
48 import java.security.cert.X509Certificate;
49 import java.security.cert.CertificateException;
50 import java.text.Collator;
51 import java.text.MessageFormat;
52 import java.util.*;
53 import java.util.jar.JarEntry;
54 import java.util.jar.JarFile;
55 import java.lang.reflect.Constructor;
56 import java.math.BigInteger;
57 import java.net.URI;
58 import java.net.URL;
59 import java.net.URLClassLoader;
60 import java.security.cert.CertStore;
61
62 import java.security.cert.X509CRL;
63 import java.security.cert.X509CRLEntry;
64 import java.security.cert.X509CRLSelector;
65 import javax.security.auth.x500.X500Principal;
66 import java.util.Base64;
67 import sun.security.util.ObjectIdentifier;
68 import sun.security.pkcs10.PKCS10;
69 import sun.security.pkcs10.PKCS10Attribute;
70 import sun.security.provider.X509Factory;
71 import sun.security.provider.certpath.CertStoreHelper;
72 import sun.security.util.Password;
73 import javax.crypto.KeyGenerator;
74 import javax.crypto.SecretKey;
75 import javax.crypto.SecretKeyFactory;
76 import javax.crypto.spec.PBEKeySpec;
77
78 import sun.security.pkcs.PKCS9Attribute;
79 import sun.security.tools.KeyStoreUtil;
80 import sun.security.tools.PathList;
81 import sun.security.util.DerValue;
82 import sun.security.util.Pem;
83 import sun.security.x509.*;
84
85 import static java.security.KeyStore.*;
86 import static sun.security.tools.keytool.Main.Command.*;
87 import static sun.security.tools.keytool.Main.Option.*;
88
89 /**
90 * This tool manages keystores.
91 *
92 * @author Jan Luehe
130 private String providerName = null;
131 private String pathlist = null;
132 private char[] storePass = null;
133 private char[] storePassNew = null;
134 private char[] keyPass = null;
135 private char[] keyPassNew = null;
136 private char[] newPass = null;
137 private char[] destKeyPass = null;
138 private char[] srckeyPass = null;
139 private String ksfname = null;
140 private File ksfile = null;
141 private InputStream ksStream = null; // keystore stream
142 private String sslserver = null;
143 private String jarfile = null;
144 private KeyStore keyStore = null;
145 private boolean token = false;
146 private boolean nullStream = false;
147 private boolean kssave = false;
148 private boolean noprompt = false;
149 private boolean trustcacerts = false;
150 private boolean protectedPath = false;
151 private boolean srcprotectedPath = false;
152 private CertificateFactory cf = null;
153 private KeyStore caks = null; // "cacerts" keystore
154 private char[] srcstorePass = null;
155 private String srcstoretype = null;
156 private Set<char[]> passwords = new HashSet<>();
157 private String startDate = null;
158
159 private List<String> ids = new ArrayList<>(); // used in GENCRL
160 private List<String> v3ext = new ArrayList<>();
161
162 enum Command {
163 CERTREQ("Generates.a.certificate.request",
164 ALIAS, SIGALG, FILEOUT, KEYPASS, KEYSTORE, DNAME,
165 STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS,
166 PROVIDERARG, PROVIDERPATH, V, PROTECTED),
167 CHANGEALIAS("Changes.an.entry.s.alias",
168 ALIAS, DESTALIAS, KEYPASS, KEYSTORE, STOREPASS,
169 STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG,
170 PROVIDERPATH, V, PROTECTED),
171 DELETE("Deletes.an.entry",
172 ALIAS, KEYSTORE, STOREPASS, STORETYPE,
173 PROVIDERNAME, PROVIDERCLASS, PROVIDERARG,
174 PROVIDERPATH, V, PROTECTED),
175 EXPORTCERT("Exports.certificate",
176 RFC, ALIAS, FILEOUT, KEYSTORE, STOREPASS,
177 STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG,
178 PROVIDERPATH, V, PROTECTED),
179 GENKEYPAIR("Generates.a.key.pair",
180 ALIAS, KEYALG, KEYSIZE, SIGALG, DESTALIAS, DNAME,
181 STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE,
300 V("v", null, "verbose.output"),
301 VALIDITY("validity", "<valDays>", "validity.number.of.days");
302
303 final String name, arg, description;
304 Option(String name, String arg, String description) {
305 this.name = name;
306 this.arg = arg;
307 this.description = description;
308 }
309 @Override
310 public String toString() {
311 return "-" + name;
312 }
313 };
314
315 private static final Class<?>[] PARAM_STRING = { String.class };
316
317 private static final String NONE = "NONE";
318 private static final String P11KEYSTORE = "PKCS11";
319 private static final String P12KEYSTORE = "PKCS12";
320 private final String keyAlias = "mykey";
321
322 // for i18n
323 private static final java.util.ResourceBundle rb =
324 java.util.ResourceBundle.getBundle(
325 "sun.security.tools.keytool.Resources");
326 private static final Collator collator = Collator.getInstance();
327 static {
328 // this is for case insensitive string comparisons
329 collator.setStrength(Collator.PRIMARY);
330 };
331
332 private Main() { }
333
334 public static void main(String[] args) throws Exception {
335 Main kt = new Main();
336 kt.run(args, System.out);
337 }
338
339 private void run(String[] args, PrintStream out) throws Exception {
340 try {
341 parseArgs(args);
342 if (command != null) {
343 doCommands(out);
344 }
345 } catch (Exception e) {
346 System.out.println(rb.getString("keytool.error.") + e);
347 if (verbose) {
348 e.printStackTrace(System.out);
349 }
350 if (!debug) {
351 System.exit(1);
352 } else {
353 throw e;
354 }
355 } finally {
356 for (char[] pass : passwords) {
357 if (pass != null) {
358 Arrays.fill(pass, ' ');
359 pass = null;
360 }
361 }
362
363 if (ksStream != null) {
364 ksStream.close();
365 }
366 }
367 }
368
369 /**
370 * Parse command line arguments.
371 */
372 void parseArgs(String[] args) {
373
374 int i=0;
375 boolean help = args.length == 0;
403 */
404 boolean isCommand = false;
405 for (Command c: Command.values()) {
406 if (collator.compare(flags, c.toString()) == 0) {
407 command = c;
408 isCommand = true;
409 break;
410 }
411 }
412
413 if (isCommand) {
414 // already recognized as a command
415 } else if (collator.compare(flags, "-export") == 0) {
416 command = EXPORTCERT;
417 } else if (collator.compare(flags, "-genkey") == 0) {
418 command = GENKEYPAIR;
419 } else if (collator.compare(flags, "-import") == 0) {
420 command = IMPORTCERT;
421 } else if (collator.compare(flags, "-importpassword") == 0) {
422 command = IMPORTPASS;
423 }
424 /*
425 * Help
426 */
427 else if (collator.compare(flags, "-help") == 0) {
428 help = true;
429 }
430
431 /*
432 * specifiers
433 */
434 else if (collator.compare(flags, "-keystore") == 0 ||
435 collator.compare(flags, "-destkeystore") == 0) {
436 ksfname = args[++i];
437 } else if (collator.compare(flags, "-storepass") == 0 ||
438 collator.compare(flags, "-deststorepass") == 0) {
439 storePass = getPass(modifier, args[++i]);
440 passwords.add(storePass);
441 } else if (collator.compare(flags, "-storetype") == 0 ||
442 collator.compare(flags, "-deststoretype") == 0) {
443 storetype = args[++i];
444 } else if (collator.compare(flags, "-srcstorepass") == 0) {
445 srcstorePass = getPass(modifier, args[++i]);
446 passwords.add(srcstorePass);
447 } else if (collator.compare(flags, "-srcstoretype") == 0) {
448 srcstoretype = args[++i];
696 if (command == LIST && verbose && rfc) {
697 System.err.println(rb.getString
698 ("Must.not.specify.both.v.and.rfc.with.list.command"));
699 tinyHelp();
700 }
701
702 // Make sure provided passwords are at least 6 characters long
703 if (command == GENKEYPAIR && keyPass!=null && keyPass.length < 6) {
704 throw new Exception(rb.getString
705 ("Key.password.must.be.at.least.6.characters"));
706 }
707 if (newPass != null && newPass.length < 6) {
708 throw new Exception(rb.getString
709 ("New.password.must.be.at.least.6.characters"));
710 }
711 if (destKeyPass != null && destKeyPass.length < 6) {
712 throw new Exception(rb.getString
713 ("New.password.must.be.at.least.6.characters"));
714 }
715
716 // Check if keystore exists.
717 // If no keystore has been specified at the command line, try to use
718 // the default, which is located in $HOME/.keystore.
719 // If the command is "genkey", "identitydb", "import", or "printcert",
720 // it is OK not to have a keystore.
721 if (isKeyStoreRelated(command)) {
722 if (ksfname == null) {
723 ksfname = System.getProperty("user.home") + File.separator
724 + ".keystore";
725 }
726
727 if (!nullStream) {
728 try {
729 ksfile = new File(ksfname);
730 // Check if keystore file is empty
731 if (ksfile.exists() && ksfile.length() == 0) {
732 throw new Exception(rb.getString
733 ("Keystore.file.exists.but.is.empty.") + ksfname);
734 }
735 ksStream = new FileInputStream(ksfile);
736 } catch (FileNotFoundException e) {
737 if (command != GENKEYPAIR &&
738 command != GENSECKEY &&
739 command != IDENTITYDB &&
740 command != IMPORTCERT &&
741 command != IMPORTPASS &&
742 command != IMPORTKEYSTORE &&
743 command != PRINTCRL) {
744 throw new Exception(rb.getString
745 ("Keystore.file.does.not.exist.") + ksfname);
746 }
747 }
748 }
749 }
750
751 if ((command == KEYCLONE || command == CHANGEALIAS)
752 && dest == null) {
753 dest = getAlias("destination");
754 if ("".equals(dest)) {
755 throw new Exception(rb.getString
756 ("Must.specify.destination.alias"));
757 }
758 }
759
760 if (command == DELETE && alias == null) {
761 alias = getAlias(null);
762 if ("".equals(alias)) {
763 throw new Exception(rb.getString("Must.specify.alias"));
764 }
765 }
766
767 // Create new keystore
768 if (providerName == null) {
769 keyStore = KeyStore.getInstance(storetype);
775 * Load the keystore data.
776 *
777 * At this point, it's OK if no keystore password has been provided.
778 * We want to make sure that we can load the keystore data, i.e.,
779 * the keystore data has the right format. If we cannot load the
780 * keystore, why bother asking the user for his or her password?
781 * Only if we were able to load the keystore, and no keystore
782 * password has been provided, will we prompt the user for the
783 * keystore password to verify the keystore integrity.
784 * This means that the keystore is loaded twice: first load operation
785 * checks the keystore format, second load operation verifies the
786 * keystore integrity.
787 *
788 * If the keystore password has already been provided (at the
789 * command line), however, the keystore is loaded only once, and the
790 * keystore format and integrity are checked "at the same time".
791 *
792 * Null stream keystores are loaded later.
793 */
794 if (!nullStream) {
795 keyStore.load(ksStream, storePass);
796 if (ksStream != null) {
797 ksStream.close();
798 }
799 }
800
801 // All commands that create or modify the keystore require a keystore
802 // password.
803
804 if (nullStream && storePass != null) {
805 keyStore.load(null, storePass);
806 } else if (!nullStream && storePass != null) {
807 // If we are creating a new non nullStream-based keystore,
808 // insist that the password be at least 6 characters
809 if (ksStream == null && storePass.length < 6) {
810 throw new Exception(rb.getString
811 ("Keystore.password.must.be.at.least.6.characters"));
812 }
813 } else if (storePass == null) {
814
815 // only prompt if (protectedPath == false)
903 keyPass = storePass;
904 }
905 if (newPass != null && !Arrays.equals(storePass, newPass)) {
906 Object[] source = {"-new"};
907 System.err.println(form.format(source));
908 newPass = storePass;
909 }
910 if (destKeyPass != null && !Arrays.equals(storePass, destKeyPass)) {
911 Object[] source = {"-destkeypass"};
912 System.err.println(form.format(source));
913 destKeyPass = storePass;
914 }
915 }
916
917 // Create a certificate factory
918 if (command == PRINTCERT || command == IMPORTCERT
919 || command == IDENTITYDB || command == PRINTCRL) {
920 cf = CertificateFactory.getInstance("X509");
921 }
922
923 if (trustcacerts) {
924 caks = KeyStoreUtil.getCacertsKeyStore();
925 }
926
927 // Perform the specified command
928 if (command == CERTREQ) {
929 if (filename != null) {
930 try (PrintStream ps = new PrintStream(new FileOutputStream
931 (filename))) {
932 doCertReq(alias, sigAlgName, ps);
933 }
934 } else {
935 doCertReq(alias, sigAlgName, out);
936 }
937 if (verbose && filename != null) {
938 MessageFormat form = new MessageFormat(rb.getString
939 ("Certification.request.stored.in.file.filename."));
940 Object[] source = {filename};
941 System.err.println(form.format(source));
942 System.err.println(rb.getString("Submit.this.to.your.CA"));
1004 ("Certificate.reply.was.not.installed.in.keystore"));
1005 }
1006 } else if (!keyStore.containsAlias(importAlias) ||
1007 keyStore.entryInstanceOf(importAlias,
1008 KeyStore.TrustedCertificateEntry.class)) {
1009 kssave = addTrustedCert(importAlias, inStream);
1010 if (kssave) {
1011 System.err.println(rb.getString
1012 ("Certificate.was.added.to.keystore"));
1013 } else {
1014 System.err.println(rb.getString
1015 ("Certificate.was.not.added.to.keystore"));
1016 }
1017 }
1018 } finally {
1019 if (inStream != System.in) {
1020 inStream.close();
1021 }
1022 }
1023 } else if (command == IMPORTKEYSTORE) {
1024 doImportKeyStore();
1025 kssave = true;
1026 } else if (command == KEYCLONE) {
1027 keyPassNew = newPass;
1028
1029 // added to make sure only key can go thru
1030 if (alias == null) {
1031 alias = keyAlias;
1032 }
1033 if (keyStore.containsAlias(alias) == false) {
1034 MessageFormat form = new MessageFormat
1035 (rb.getString("Alias.alias.does.not.exist"));
1036 Object[] source = {alias};
1037 throw new Exception(form.format(source));
1038 }
1039 if (!keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
1040 MessageFormat form = new MessageFormat(rb.getString(
1041 "Alias.alias.references.an.entry.type.that.is.not.a.private.key.entry.The.keyclone.command.only.supports.cloning.of.private.key"));
1042 Object[] source = {alias};
1043 throw new Exception(form.format(source));
1044 }
1045
1046 doCloneEntry(alias, dest, true); // Now everything can be cloned
1047 kssave = true;
1048 } else if (command == CHANGEALIAS) {
1049 if (alias == null) {
1050 alias = keyAlias;
1051 }
1052 doCloneEntry(alias, dest, false);
1053 // in PKCS11, clone a PrivateKeyEntry will delete the old one
1054 if (keyStore.containsAlias(alias)) {
1055 doDeleteEntry(alias);
1056 }
1057 kssave = true;
1058 } else if (command == KEYPASSWD) {
1059 keyPassNew = newPass;
1060 doChangeKeyPasswd(alias);
1061 kssave = true;
1062 } else if (command == LIST) {
1063 if (alias != null) {
1064 doPrintEntry(alias, out, true);
1065 } else {
1066 doPrintEntries(out);
1067 }
1068 } else if (command == PRINTCERT) {
1069 doPrintCert(out);
1070 } else if (command == SELFCERT) {
1071 doSelfCert(alias, dname, sigAlgName);
1072 kssave = true;
1073 } else if (command == STOREPASSWD) {
1074 storePassNew = newPass;
1075 if (storePassNew == null) {
1076 storePassNew = getNewPasswd("keystore password", storePass);
1077 }
1078 kssave = true;
1079 } else if (command == GENCERT) {
1080 if (alias == null) {
1081 alias = keyAlias;
1082 }
1083 InputStream inStream = System.in;
1084 if (infilename != null) {
1130 (rb.getString(".Storing.ksfname."));
1131 Object[] source = {nullStream ? "keystore" : ksfname};
1132 System.err.println(form.format(source));
1133 }
1134
1135 if (token) {
1136 keyStore.store(null, null);
1137 } else {
1138 char[] pass = (storePassNew!=null) ? storePassNew : storePass;
1139 if (nullStream) {
1140 keyStore.store(null, pass);
1141 } else {
1142 ByteArrayOutputStream bout = new ByteArrayOutputStream();
1143 keyStore.store(bout, pass);
1144 try (FileOutputStream fout = new FileOutputStream(ksfname)) {
1145 fout.write(bout.toByteArray());
1146 }
1147 }
1148 }
1149 }
1150 }
1151
1152 /**
1153 * Generate a certificate: Read PKCS10 request from in, and print
1154 * certificate to out. Use alias as CA, sigAlgName as the signature
1155 * type.
1156 */
1157 private void doGenCert(String alias, String sigAlgName, InputStream in, PrintStream out)
1158 throws Exception {
1159
1160
1161 Certificate signerCert = keyStore.getCertificate(alias);
1162 byte[] encoded = signerCert.getEncoded();
1163 X509CertImpl signerCertImpl = new X509CertImpl(encoded);
1164 X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get(
1165 X509CertImpl.NAME + "." + X509CertImpl.INFO);
1166 X500Name issuer = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." +
1167 X509CertInfo.DN_NAME);
1168
1169 Date firstDate = getStartDate(startDate);
1170 Date lastDate = new Date();
1171 lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L);
1172 CertificateValidity interval = new CertificateValidity(firstDate,
1173 lastDate);
1174
1175 PrivateKey privateKey =
1176 (PrivateKey)recoverKey(alias, storePass, keyPass).fst;
1177 if (sigAlgName == null) {
1178 sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm());
1179 }
1180 Signature signature = Signature.getInstance(sigAlgName);
1194 BufferedReader reader = new BufferedReader(new InputStreamReader(in));
1195 boolean canRead = false;
1196 StringBuffer sb = new StringBuffer();
1197 while (true) {
1198 String s = reader.readLine();
1199 if (s == null) break;
1200 // OpenSSL does not use NEW
1201 //if (s.startsWith("-----BEGIN NEW CERTIFICATE REQUEST-----")) {
1202 if (s.startsWith("-----BEGIN") && s.indexOf("REQUEST") >= 0) {
1203 canRead = true;
1204 //} else if (s.startsWith("-----END NEW CERTIFICATE REQUEST-----")) {
1205 } else if (s.startsWith("-----END") && s.indexOf("REQUEST") >= 0) {
1206 break;
1207 } else if (canRead) {
1208 sb.append(s);
1209 }
1210 }
1211 byte[] rawReq = Pem.decode(new String(sb));
1212 PKCS10 req = new PKCS10(rawReq);
1213
1214 info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo()));
1215 info.set(X509CertInfo.SUBJECT,
1216 dname==null?req.getSubjectName():new X500Name(dname));
1217 CertificateExtensions reqex = null;
1218 Iterator<PKCS10Attribute> attrs = req.getAttributes().getAttributes().iterator();
1219 while (attrs.hasNext()) {
1220 PKCS10Attribute attr = attrs.next();
1221 if (attr.getAttributeId().equals((Object)PKCS9Attribute.EXTENSION_REQUEST_OID)) {
1222 reqex = (CertificateExtensions)attr.getAttributeValue();
1223 }
1224 }
1225 CertificateExtensions ext = createV3Extensions(
1226 reqex,
1227 null,
1228 v3ext,
1229 req.getSubjectPublicKeyInfo(),
1230 signerCert.getPublicKey());
1231 info.set(X509CertInfo.EXTENSIONS, ext);
1232 X509CertImpl cert = new X509CertImpl(info);
1233 cert.sign(privateKey, sigAlgName);
1234 dumpCert(cert, out);
1235 for (Certificate ca: keyStore.getCertificateChain(alias)) {
1236 if (ca instanceof X509Certificate) {
1237 X509Certificate xca = (X509Certificate)ca;
1238 if (!isSelfSigned(xca)) {
1239 dumpCert(xca, out);
1240 }
1241 }
1242 }
1243 }
1244
1245 private void doGenCRL(PrintStream out)
1246 throws Exception {
1247 if (ids == null) {
1248 throw new Exception("Must provide -id when -gencrl");
1249 }
1250 Certificate signerCert = keyStore.getCertificate(alias);
1251 byte[] encoded = signerCert.getEncoded();
1252 X509CertImpl signerCertImpl = new X509CertImpl(encoded);
1253 X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get(
1254 X509CertImpl.NAME + "." + X509CertImpl.INFO);
1255 X500Name owner = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." +
1256 X509CertInfo.DN_NAME);
1257
1258 Date firstDate = getStartDate(startDate);
1259 Date lastDate = (Date) firstDate.clone();
1260 lastDate.setTime(lastDate.getTime() + validity*1000*24*60*60);
1261 CertificateValidity interval = new CertificateValidity(firstDate,
1262 lastDate);
1273 String id = ids.get(i);
1274 int d = id.indexOf(':');
1275 if (d >= 0) {
1276 CRLExtensions ext = new CRLExtensions();
1277 ext.set("Reason", new CRLReasonCodeExtension(Integer.parseInt(id.substring(d+1))));
1278 badCerts[i] = new X509CRLEntryImpl(new BigInteger(id.substring(0, d)),
1279 firstDate, ext);
1280 } else {
1281 badCerts[i] = new X509CRLEntryImpl(new BigInteger(ids.get(i)), firstDate);
1282 }
1283 }
1284 X509CRLImpl crl = new X509CRLImpl(owner, firstDate, lastDate, badCerts);
1285 crl.sign(privateKey, sigAlgName);
1286 if (rfc) {
1287 out.println("-----BEGIN X509 CRL-----");
1288 out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(crl.getEncodedInternal()));
1289 out.println("-----END X509 CRL-----");
1290 } else {
1291 out.write(crl.getEncodedInternal());
1292 }
1293 }
1294
1295 /**
1296 * Creates a PKCS#10 cert signing request, corresponding to the
1297 * keys (and name) associated with a given alias.
1298 */
1299 private void doCertReq(String alias, String sigAlgName, PrintStream out)
1300 throws Exception
1301 {
1302 if (alias == null) {
1303 alias = keyAlias;
1304 }
1305
1306 Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass);
1307 PrivateKey privKey = (PrivateKey)objs.fst;
1308 if (keyPass == null) {
1309 keyPass = objs.snd;
1310 }
1311
1312 Certificate cert = keyStore.getCertificate(alias);
1319 PKCS10 request = new PKCS10(cert.getPublicKey());
1320 CertificateExtensions ext = createV3Extensions(null, null, v3ext, cert.getPublicKey(), null);
1321 // Attribute name is not significant
1322 request.getAttributes().setAttribute(X509CertInfo.EXTENSIONS,
1323 new PKCS10Attribute(PKCS9Attribute.EXTENSION_REQUEST_OID, ext));
1324
1325 // Construct a Signature object, so that we can sign the request
1326 if (sigAlgName == null) {
1327 sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm());
1328 }
1329
1330 Signature signature = Signature.getInstance(sigAlgName);
1331 signature.initSign(privKey);
1332 X500Name subject = dname == null?
1333 new X500Name(((X509Certificate)cert).getSubjectDN().toString()):
1334 new X500Name(dname);
1335
1336 // Sign the request and base-64 encode it
1337 request.encodeAndSign(subject, signature);
1338 request.print(out);
1339 }
1340
1341 /**
1342 * Deletes an entry from the keystore.
1343 */
1344 private void doDeleteEntry(String alias) throws Exception {
1345 if (keyStore.containsAlias(alias) == false) {
1346 MessageFormat form = new MessageFormat
1347 (rb.getString("Alias.alias.does.not.exist"));
1348 Object[] source = {alias};
1349 throw new Exception(form.format(source));
1350 }
1351 keyStore.deleteEntry(alias);
1352 }
1353
1354 /**
1355 * Exports a certificate from the keystore.
1356 */
1357 private void doExportCert(String alias, PrintStream out)
1358 throws Exception
1359 {
1360 if (storePass == null
1361 && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
1362 printWarning();
1363 }
1364 if (alias == null) {
1365 alias = keyAlias;
1366 }
1367 if (keyStore.containsAlias(alias) == false) {
1368 MessageFormat form = new MessageFormat
1369 (rb.getString("Alias.alias.does.not.exist"));
1370 Object[] source = {alias};
1371 throw new Exception(form.format(source));
1372 }
1373
1374 X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias);
1375 if (cert == null) {
1376 MessageFormat form = new MessageFormat
1377 (rb.getString("Alias.alias.has.no.certificate"));
1378 Object[] source = {alias};
1379 throw new Exception(form.format(source));
1380 }
1381 dumpCert(cert, out);
1382 }
1383
1384 /**
1385 * Prompt the user for a keypass when generating a key entry.
1386 * @param alias the entry we will set password for
1387 * @param orig the original entry of doing a dup, null if generate new
1388 * @param origPass the password to copy from if user press ENTER
1389 */
1390 private char[] promptForKeyPass(String alias, String orig, char[] origPass) throws Exception{
1391 if (P12KEYSTORE.equalsIgnoreCase(storetype)) {
1392 return origPass;
1393 } else if (!token && !protectedPath) {
1394 // Prompt for key password
1395 int count;
1396 for (count = 0; count < 3; count++) {
1397 MessageFormat form = new MessageFormat(rb.getString
1398 ("Enter.key.password.for.alias."));
1399 Object[] source = {alias};
1400 System.err.println(form.format(source));
1401 if (orig == null) {
1542
1543 if (keyPass == null) {
1544 keyPass = promptForKeyPass(alias, null, storePass);
1545 }
1546
1547 if (useDefaultPBEAlgorithm) {
1548 keyStore.setKeyEntry(alias, secKey, keyPass, null);
1549 } else {
1550 keyStore.setEntry(alias, new KeyStore.SecretKeyEntry(secKey),
1551 new KeyStore.PasswordProtection(keyPass, keyAlgName, null));
1552 }
1553 }
1554
1555 /**
1556 * If no signature algorithm was specified at the command line,
1557 * we choose one that is compatible with the selected private key
1558 */
1559 private static String getCompatibleSigAlgName(String keyAlgName)
1560 throws Exception {
1561 if ("DSA".equalsIgnoreCase(keyAlgName)) {
1562 return "SHA1WithDSA";
1563 } else if ("RSA".equalsIgnoreCase(keyAlgName)) {
1564 return "SHA256WithRSA";
1565 } else if ("EC".equalsIgnoreCase(keyAlgName)) {
1566 return "SHA256withECDSA";
1567 } else {
1568 throw new Exception(rb.getString
1569 ("Cannot.derive.signature.algorithm"));
1570 }
1571 }
1572 /**
1573 * Creates a new key pair and self-signed certificate.
1574 */
1575 private void doGenKeyPair(String alias, String dname, String keyAlgName,
1576 int keysize, String sigAlgName)
1577 throws Exception
1578 {
1579 if (keysize == -1) {
1580 if ("EC".equalsIgnoreCase(keyAlgName)) {
1581 keysize = 256;
1582 } else if ("RSA".equalsIgnoreCase(keyAlgName)) {
1583 keysize = 2048;
1584 } else {
1585 keysize = 1024;
1586 }
1587 }
1588
1589 if (alias == null) {
1590 alias = keyAlias;
1591 }
1592
1593 if (keyStore.containsAlias(alias)) {
1594 MessageFormat form = new MessageFormat(rb.getString
1595 ("Key.pair.not.generated.alias.alias.already.exists"));
1596 Object[] source = {alias};
1597 throw new Exception(form.format(source));
1598 }
1599
1600 if (sigAlgName == null) {
1601 sigAlgName = getCompatibleSigAlgName(keyAlgName);
1602 }
1603 CertAndKeyGen keypair =
1604 new CertAndKeyGen(keyAlgName, sigAlgName, providerName);
1605
1623 null);
1624
1625 X509Certificate[] chain = new X509Certificate[1];
1626 chain[0] = keypair.getSelfCertificate(
1627 x500Name, getStartDate(startDate), validity*24L*60L*60L, ext);
1628
1629 if (verbose) {
1630 MessageFormat form = new MessageFormat(rb.getString
1631 ("Generating.keysize.bit.keyAlgName.key.pair.and.self.signed.certificate.sigAlgName.with.a.validity.of.validality.days.for"));
1632 Object[] source = {new Integer(keysize),
1633 privKey.getAlgorithm(),
1634 chain[0].getSigAlgName(),
1635 new Long(validity),
1636 x500Name};
1637 System.err.println(form.format(source));
1638 }
1639
1640 if (keyPass == null) {
1641 keyPass = promptForKeyPass(alias, null, storePass);
1642 }
1643 keyStore.setKeyEntry(alias, privKey, keyPass, chain);
1644 }
1645
1646 /**
1647 * Clones an entry
1648 * @param orig original alias
1649 * @param dest destination alias
1650 * @changePassword if the password can be changed
1651 */
1652 private void doCloneEntry(String orig, String dest, boolean changePassword)
1653 throws Exception
1654 {
1655 if (orig == null) {
1656 orig = keyAlias;
1657 }
1658
1659 if (keyStore.containsAlias(dest)) {
1660 MessageFormat form = new MessageFormat
1661 (rb.getString("Destination.alias.dest.already.exists"));
1662 Object[] source = {dest};
1705 }
1706 keyStore.setKeyEntry(alias, privKey, keyPassNew,
1707 keyStore.getCertificateChain(alias));
1708 }
1709
1710 /**
1711 * Imports a JDK 1.1-style identity database. We can only store one
1712 * certificate per identity, because we use the identity's name as the
1713 * alias (which references a keystore entry), and aliases must be unique.
1714 */
1715 private void doImportIdentityDatabase(InputStream in)
1716 throws Exception
1717 {
1718 System.err.println(rb.getString
1719 ("No.entries.from.identity.database.added"));
1720 }
1721
1722 /**
1723 * Prints a single keystore entry.
1724 */
1725 private void doPrintEntry(String alias, PrintStream out,
1726 boolean printWarning)
1727 throws Exception
1728 {
1729 if (storePass == null && printWarning
1730 && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
1731 printWarning();
1732 }
1733
1734 if (keyStore.containsAlias(alias) == false) {
1735 MessageFormat form = new MessageFormat
1736 (rb.getString("Alias.alias.does.not.exist"));
1737 Object[] source = {alias};
1738 throw new Exception(form.format(source));
1739 }
1740
1741 if (verbose || rfc || debug) {
1742 MessageFormat form = new MessageFormat
1743 (rb.getString("Alias.name.alias"));
1744 Object[] source = {alias};
1745 out.println(form.format(source));
1746
1747 if (!token) {
1748 form = new MessageFormat(rb.getString
1749 ("Creation.date.keyStore.getCreationDate.alias."));
1750 Object[] src = {keyStore.getCreationDate(alias)};
1751 out.println(form.format(src));
1752 }
1753 } else {
1782 }
1783
1784 // Get the chain
1785 Certificate[] chain = keyStore.getCertificateChain(alias);
1786 if (chain != null) {
1787 if (verbose || rfc || debug) {
1788 out.println(rb.getString
1789 ("Certificate.chain.length.") + chain.length);
1790 for (int i = 0; i < chain.length; i ++) {
1791 MessageFormat form = new MessageFormat
1792 (rb.getString("Certificate.i.1."));
1793 Object[] source = {new Integer((i + 1))};
1794 out.println(form.format(source));
1795 if (verbose && (chain[i] instanceof X509Certificate)) {
1796 printX509Cert((X509Certificate)(chain[i]), out);
1797 } else if (debug) {
1798 out.println(chain[i].toString());
1799 } else {
1800 dumpCert(chain[i], out);
1801 }
1802 }
1803 } else {
1804 // Print the digest of the user cert only
1805 out.println
1806 (rb.getString("Certificate.fingerprint.SHA1.") +
1807 getCertFingerPrint("SHA1", chain[0]));
1808 }
1809 }
1810 } else if (keyStore.entryInstanceOf(alias,
1811 KeyStore.TrustedCertificateEntry.class)) {
1812 // We have a trusted certificate entry
1813 Certificate cert = keyStore.getCertificate(alias);
1814 Object[] source = {"trustedCertEntry"};
1815 String mf = new MessageFormat(
1816 rb.getString("Entry.type.type.")).format(source) + "\n";
1817 if (verbose && (cert instanceof X509Certificate)) {
1818 out.println(mf);
1819 printX509Cert((X509Certificate)cert, out);
1820 } else if (rfc) {
1821 out.println(mf);
1822 dumpCert(cert, out);
1823 } else if (debug) {
1824 out.println(cert.toString());
1825 } else {
1826 out.println("trustedCertEntry, ");
1827 out.println(rb.getString("Certificate.fingerprint.SHA1.")
1828 + getCertFingerPrint("SHA1", cert));
1829 }
1830 } else {
1831 out.println(rb.getString("Unknown.Entry.Type"));
1832 }
1833 }
1834
1835 /**
1836 * Load the srckeystore from a stream, used in -importkeystore
1837 * @returns the src KeyStore
1838 */
1839 KeyStore loadSourceKeyStore() throws Exception {
1840 boolean isPkcs11 = false;
1841
1842 InputStream is = null;
1843
1844 if (P11KEYSTORE.equalsIgnoreCase(srcstoretype) ||
1845 KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
1846 if (!NONE.equals(srcksfname)) {
1847 System.err.println(MessageFormat.format(rb.getString
1848 (".keystore.must.be.NONE.if.storetype.is.{0}"), srcstoretype));
1849 System.err.println();
1850 tinyHelp();
1851 }
1852 isPkcs11 = true;
1853 } else {
1854 if (srcksfname != null) {
1855 File srcksfile = new File(srcksfname);
1856 if (srcksfile.exists() && srcksfile.length() == 0) {
1857 throw new Exception(rb.getString
1858 ("Source.keystore.file.exists.but.is.empty.") +
1859 srcksfname);
1860 }
1861 is = new FileInputStream(srcksfile);
1862 } else {
1863 throw new Exception(rb.getString
1864 ("Please.specify.srckeystore"));
1865 }
1866 }
1867
1868 KeyStore store;
1869 try {
1870 if (srcProviderName == null) {
1871 store = KeyStore.getInstance(srcstoretype);
1872 } else {
1873 store = KeyStore.getInstance(srcstoretype, srcProviderName);
1874 }
1875
1876 if (srcstorePass == null
1877 && !srcprotectedPath
1878 && !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
1879 System.err.print(rb.getString("Enter.source.keystore.password."));
1880 System.err.flush();
1881 srcstorePass = Password.readPassword(System.in);
1882 passwords.add(srcstorePass);
1883 }
1884
1885 // always let keypass be storepass when using pkcs12
1886 if (P12KEYSTORE.equalsIgnoreCase(srcstoretype)) {
1887 if (srckeyPass != null && srcstorePass != null &&
1888 !Arrays.equals(srcstorePass, srckeyPass)) {
1889 MessageFormat form = new MessageFormat(rb.getString(
1890 "Warning.Different.store.and.key.passwords.not.supported.for.PKCS12.KeyStores.Ignoring.user.specified.command.value."));
1891 Object[] source = {"-srckeypass"};
1892 System.err.println(form.format(source));
1893 srckeyPass = srcstorePass;
1894 }
1895 }
1896
1897 store.load(is, srcstorePass); // "is" already null in PKCS11
1898 } finally {
1899 if (is != null) {
1900 is.close();
1901 }
1902 }
1903
1904 if (srcstorePass == null
1905 && !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
1906 // anti refactoring, copied from printWarning(),
1907 // but change 2 lines
1908 System.err.println();
1909 System.err.println(rb.getString
1910 (".WARNING.WARNING.WARNING."));
1911 System.err.println(rb.getString
1912 (".The.integrity.of.the.information.stored.in.the.srckeystore."));
1913 System.err.println(rb.getString
1914 (".WARNING.WARNING.WARNING."));
1915 System.err.println();
1916 }
1917
1918 return store;
1919 }
1920
1921 /**
1922 * import all keys and certs from importkeystore.
1923 * keep alias unchanged if no name conflict, otherwise, prompt.
1924 * keep keypass unchanged for keys
1925 */
1926 private void doImportKeyStore() throws Exception {
1927
1928 if (alias != null) {
1929 doImportKeyStoreSingle(loadSourceKeyStore(), alias);
1930 } else {
1931 if (dest != null || srckeyPass != null) {
1932 throw new Exception(rb.getString(
1933 "if.alias.not.specified.destalias.and.srckeypass.must.not.be.specified"));
1934 }
1935 doImportKeyStoreAll(loadSourceKeyStore());
1936 }
1937 /*
1938 * Information display rule of -importkeystore
1939 * 1. inside single, shows failure
1940 * 2. inside all, shows sucess
1941 * 3. inside all where there is a failure, prompt for continue
1942 * 4. at the final of all, shows summary
1943 */
1944 }
1945
1946 /**
1947 * Import a single entry named alias from srckeystore
1948 * @returns 1 if the import action succeed
1949 * 0 if user choose to ignore an alias-dumplicated entry
1950 * 2 if setEntry throws Exception
1951 */
1952 private int doImportKeyStoreSingle(KeyStore srckeystore, String alias)
1953 throws Exception {
1954
1955 String newAlias = (dest==null) ? alias : dest;
1956
1977
1978 Pair<Entry,char[]> objs = recoverEntry(srckeystore, alias, srcstorePass, srckeyPass);
1979 Entry entry = objs.fst;
1980
1981 PasswordProtection pp = null;
1982
1983 // According to keytool.html, "The destination entry will be protected
1984 // using destkeypass. If destkeypass is not provided, the destination
1985 // entry will be protected with the source entry password."
1986 // so always try to protect with destKeyPass.
1987 char[] newPass = null;
1988 if (destKeyPass != null) {
1989 newPass = destKeyPass;
1990 pp = new PasswordProtection(destKeyPass);
1991 } else if (objs.snd != null) {
1992 newPass = objs.snd;
1993 pp = new PasswordProtection(objs.snd);
1994 }
1995
1996 try {
1997 keyStore.setEntry(newAlias, entry, pp);
1998 // Place the check so that only successful imports are blocked.
1999 // For example, we don't block a failed SecretEntry import.
2000 if (P12KEYSTORE.equalsIgnoreCase(storetype)) {
2001 if (newPass != null && !Arrays.equals(newPass, storePass)) {
2002 throw new Exception(rb.getString(
2003 "The.destination.pkcs12.keystore.has.different.storepass.and.keypass.Please.retry.with.destkeypass.specified."));
2004 }
2005 }
2006 return 1;
2007 } catch (KeyStoreException kse) {
2008 Object[] source2 = {alias, kse.toString()};
2009 MessageFormat form = new MessageFormat(rb.getString(
2010 "Problem.importing.entry.for.alias.alias.exception.Entry.for.alias.alias.not.imported."));
2011 System.err.println(form.format(source2));
2012 return 2;
2013 }
2014 }
2015
2016 private void doImportKeyStoreAll(KeyStore srckeystore) throws Exception {
2030 if (!noprompt) {
2031 String reply = getYesNoReply("Do you want to quit the import process? [no]: ");
2032 if ("YES".equals(reply)) {
2033 break;
2034 }
2035 }
2036 }
2037 }
2038 Object[] source = {ok, count-ok};
2039 MessageFormat form = new MessageFormat(rb.getString(
2040 "Import.command.completed.ok.entries.successfully.imported.fail.entries.failed.or.cancelled"));
2041 System.err.println(form.format(source));
2042 }
2043
2044 /**
2045 * Prints all keystore entries.
2046 */
2047 private void doPrintEntries(PrintStream out)
2048 throws Exception
2049 {
2050 if (storePass == null
2051 && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
2052 printWarning();
2053 } else {
2054 out.println();
2055 }
2056
2057 out.println(rb.getString("Keystore.type.") + keyStore.getType());
2058 out.println(rb.getString("Keystore.provider.") +
2059 keyStore.getProvider().getName());
2060 out.println();
2061
2062 MessageFormat form;
2063 form = (keyStore.size() == 1) ?
2064 new MessageFormat(rb.getString
2065 ("Your.keystore.contains.keyStore.size.entry")) :
2066 new MessageFormat(rb.getString
2067 ("Your.keystore.contains.keyStore.size.entries"));
2068 Object[] source = {new Integer(keyStore.size())};
2069 out.println(form.format(source));
2070 out.println();
2071
2072 for (Enumeration<String> e = keyStore.aliases();
2073 e.hasMoreElements(); ) {
2074 String alias = e.nextElement();
2075 doPrintEntry(alias, out, false);
2076 if (verbose || rfc) {
2077 out.println(rb.getString("NEWLINE"));
2078 out.println(rb.getString
2079 ("STAR"));
2080 out.println(rb.getString
2081 ("STARNN"));
2082 }
2083 }
2084 }
2085
2086 private static <T> Iterable<T> e2i(final Enumeration<T> e) {
2087 return new Iterable<T>() {
2088 @Override
2089 public Iterator<T> iterator() {
2090 return new Iterator<T>() {
2091 @Override
2092 public boolean hasNext() {
2093 return e.hasMoreElements();
2094 }
2095 @Override
2205 Certificate cert = ks.getCertificate(s);
2206 if (cert instanceof X509Certificate) {
2207 X509Certificate xcert = (X509Certificate)cert;
2208 if (xcert.getSubjectX500Principal().equals(issuer)) {
2209 try {
2210 ((X509CRLImpl)crl).verify(cert.getPublicKey());
2211 return s;
2212 } catch (Exception e) {
2213 }
2214 }
2215 }
2216 }
2217 return null;
2218 }
2219
2220 private void doPrintCRL(String src, PrintStream out)
2221 throws Exception {
2222 for (CRL crl: loadCRLs(src)) {
2223 printCRL(crl, out);
2224 String issuer = null;
2225 if (caks != null) {
2226 issuer = verifyCRL(caks, crl);
2227 if (issuer != null) {
2228 out.printf(rb.getString(
2229 "verified.by.s.in.s"), issuer, "cacerts");
2230 out.println();
2231 }
2232 }
2233 if (issuer == null && keyStore != null) {
2234 issuer = verifyCRL(keyStore, crl);
2235 if (issuer != null) {
2236 out.printf(rb.getString(
2237 "verified.by.s.in.s"), issuer, "keystore");
2238 out.println();
2239 }
2240 }
2241 if (issuer == null) {
2242 out.println(rb.getString
2243 ("STAR"));
2244 out.println(rb.getString
2245 ("warning.not.verified.make.sure.keystore.is.correct"));
2246 out.println(rb.getString
2247 ("STARNN"));
2248 }
2249 }
2250 }
2251
2252 private void printCRL(CRL crl, PrintStream out)
2253 throws Exception {
2254 if (rfc) {
2255 X509CRL xcrl = (X509CRL)crl;
2256 out.println("-----BEGIN X509 CRL-----");
2257 out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(xcrl.getEncoded()));
2258 out.println("-----END X509 CRL-----");
2259 } else {
2260 out.println(crl.toString());
2261 }
2262 }
2263
2264 private void doPrintCertReq(InputStream in, PrintStream out)
2265 throws Exception {
2266
2267 BufferedReader reader = new BufferedReader(new InputStreamReader(in));
2268 StringBuffer sb = new StringBuffer();
2269 boolean started = false;
2270 while (true) {
2271 String s = reader.readLine();
2272 if (s == null) break;
2273 if (!started) {
2274 if (s.startsWith("-----")) {
2275 started = true;
2276 }
2277 } else {
2278 if (s.startsWith("-----")) {
2279 break;
2280 }
2281 sb.append(s);
2282 }
2283 }
2284 PKCS10 req = new PKCS10(Pem.decode(new String(sb)));
2285
2286 PublicKey pkey = req.getSubjectPublicKeyInfo();
2287 out.printf(rb.getString("PKCS.10.Certificate.Request.Version.1.0.Subject.s.Public.Key.s.format.s.key."),
2288 req.getSubjectName(), pkey.getFormat(), pkey.getAlgorithm());
2289 for (PKCS10Attribute attr: req.getAttributes().getAttributes()) {
2290 ObjectIdentifier oid = attr.getAttributeId();
2291 if (oid.equals((Object)PKCS9Attribute.EXTENSION_REQUEST_OID)) {
2292 CertificateExtensions exts = (CertificateExtensions)attr.getAttributeValue();
2293 if (exts != null) {
2294 printExtensions(rb.getString("Extension.Request."), exts, out);
2295 }
2296 } else {
2297 out.println("Attribute: " + attr.getAttributeId());
2298 PKCS9Attribute pkcs9Attr =
2299 new PKCS9Attribute(attr.getAttributeId(),
2300 attr.getAttributeValue());
2301 out.print(pkcs9Attr.getName() + ": ");
2302 Object attrVal = attr.getAttributeValue();
2303 out.println(attrVal instanceof String[] ?
2304 Arrays.toString((String[]) attrVal) :
2305 attrVal);
2306 }
2307 }
2308 if (debug) {
2309 out.println(req); // Just to see more, say, public key length...
2310 }
2311 }
2312
2313 /**
2314 * Reads a certificate (or certificate chain) and prints its contents in
2315 * a human readable format.
2316 */
2317 private void printCertFromStream(InputStream in, PrintStream out)
2318 throws Exception
2319 {
2320 Collection<? extends Certificate> c = null;
2321 try {
2322 c = cf.generateCertificates(in);
2323 } catch (CertificateException ce) {
2324 throw new Exception(rb.getString("Failed.to.parse.input"), ce);
2325 }
2326 if (c.isEmpty()) {
2327 throw new Exception(rb.getString("Empty.input"));
2328 }
2329 Certificate[] certs = c.toArray(new Certificate[c.size()]);
2330 for (int i=0; i<certs.length; i++) {
2331 X509Certificate x509Cert = null;
2332 try {
2333 x509Cert = (X509Certificate)certs[i];
2334 } catch (ClassCastException cce) {
2335 throw new Exception(rb.getString("Not.X.509.certificate"));
2336 }
2337 if (certs.length > 1) {
2338 MessageFormat form = new MessageFormat
2339 (rb.getString("Certificate.i.1."));
2340 Object[] source = {new Integer(i + 1)};
2341 out.println(form.format(source));
2342 }
2343 if (rfc)
2344 dumpCert(x509Cert, out);
2345 else
2346 printX509Cert(x509Cert, out);
2347 if (i < (certs.length-1)) {
2348 out.println();
2349 }
2350 }
2351 }
2352
2353 private void doPrintCert(final PrintStream out) throws Exception {
2354 if (jarfile != null) {
2355 JarFile jf = new JarFile(jarfile, true);
2356 Enumeration<JarEntry> entries = jf.entries();
2357 Set<CodeSigner> ss = new HashSet<>();
2358 byte[] buffer = new byte[8192];
2359 int pos = 0;
2360 while (entries.hasMoreElements()) {
2361 JarEntry je = entries.nextElement();
2362 try (InputStream is = jf.getInputStream(je)) {
2363 while (is.read(buffer) != -1) {
2364 // we just read. this will throw a SecurityException
2365 // if a signature/digest check fails. This also
2366 // populate the signers
2367 }
2368 }
2369 CodeSigner[] signers = je.getCodeSigners();
2370 if (signers != null) {
2371 for (CodeSigner signer: signers) {
2372 if (!ss.contains(signer)) {
2373 ss.add(signer);
2374 out.printf(rb.getString("Signer.d."), ++pos);
2375 out.println();
2376 out.println();
2377 out.println(rb.getString("Signature."));
2378 out.println();
2379 for (Certificate cert: signer.getSignerCertPath().getCertificates()) {
2380 X509Certificate x = (X509Certificate)cert;
2381 if (rfc) {
2382 out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n");
2383 dumpCert(x, out);
2384 } else {
2385 printX509Cert(x, out);
2386 }
2387 out.println();
2388 }
2389 Timestamp ts = signer.getTimestamp();
2390 if (ts != null) {
2391 out.println(rb.getString("Timestamp."));
2392 out.println();
2393 for (Certificate cert: ts.getSignerCertPath().getCertificates()) {
2394 X509Certificate x = (X509Certificate)cert;
2395 if (rfc) {
2396 out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n");
2397 dumpCert(x, out);
2398 } else {
2399 printX509Cert(x, out);
2400 }
2401 out.println();
2402 }
2403 }
2404 }
2405 }
2406 }
2407 }
2408 jf.close();
2409 if (ss.isEmpty()) {
2410 out.println(rb.getString("Not.a.signed.jar.file"));
2411 }
2412 } else if (sslserver != null) {
2413 // Lazily load SSLCertStoreHelper if present
2414 CertStoreHelper helper = CertStoreHelper.getInstance("SSLServer");
2415 CertStore cs = helper.getCertStore(new URI("https://" + sslserver));
2416 Collection<? extends Certificate> chain;
2417 try {
2418 chain = cs.getCertificates(null);
2419 if (chain.isEmpty()) {
2420 // If the certs are not retrieved, we consider it an error
2421 // even if the URL connection is successful.
2426 if (cse.getCause() instanceof IOException) {
2427 throw new Exception(rb.getString(
2428 "No.certificate.from.the.SSL.server"),
2429 cse.getCause());
2430 } else {
2431 throw cse;
2432 }
2433 }
2434
2435 int i = 0;
2436 for (Certificate cert : chain) {
2437 try {
2438 if (rfc) {
2439 dumpCert(cert, out);
2440 } else {
2441 out.println("Certificate #" + i++);
2442 out.println("====================================");
2443 printX509Cert((X509Certificate)cert, out);
2444 out.println();
2445 }
2446 } catch (Exception e) {
2447 if (debug) {
2448 e.printStackTrace();
2449 }
2450 }
2451 }
2452 } else {
2453 if (filename != null) {
2454 try (FileInputStream inStream = new FileInputStream(filename)) {
2455 printCertFromStream(inStream, out);
2456 }
2457 } else {
2458 printCertFromStream(System.in, out);
2459 }
2460 }
2461 }
2462 /**
2463 * Creates a self-signed certificate, and stores it as a single-element
2464 * certificate chain.
2465 */
2601 Object[] source = {alias};
2602 throw new Exception(form.format(source));
2603 }
2604
2605 // Read the certificates in the reply
2606 Collection<? extends Certificate> c = cf.generateCertificates(in);
2607 if (c.isEmpty()) {
2608 throw new Exception(rb.getString("Reply.has.no.certificates"));
2609 }
2610 Certificate[] replyCerts = c.toArray(new Certificate[c.size()]);
2611 Certificate[] newChain;
2612 if (replyCerts.length == 1) {
2613 // single-cert reply
2614 newChain = establishCertChain(userCert, replyCerts[0]);
2615 } else {
2616 // cert-chain reply (e.g., PKCS#7)
2617 newChain = validateReply(alias, userCert, replyCerts);
2618 }
2619
2620 // Now store the newly established chain in the keystore. The new
2621 // chain replaces the old one.
2622 if (newChain != null) {
2623 keyStore.setKeyEntry(alias, privKey,
2624 (keyPass != null) ? keyPass : storePass,
2625 newChain);
2626 return true;
2627 } else {
2628 return false;
2629 }
2630 }
2631
2632 /**
2633 * Imports a certificate and adds it to the list of trusted certificates.
2634 *
2635 * @return true if the certificate was added, otherwise false.
2636 */
2637 private boolean addTrustedCert(String alias, InputStream in)
2638 throws Exception
2639 {
2640 if (alias == null) {
2641 throw new Exception(rb.getString("Must.specify.alias"));
2642 }
2643 if (keyStore.containsAlias(alias)) {
2644 MessageFormat form = new MessageFormat(rb.getString
2645 ("Certificate.not.imported.alias.alias.already.exists"));
2646 Object[] source = {alias};
2647 throw new Exception(form.format(source));
2648 }
2649
2650 // Read the certificate
2651 X509Certificate cert = null;
2652 try {
2653 cert = (X509Certificate)cf.generateCertificate(in);
2654 } catch (ClassCastException | CertificateException ce) {
2655 throw new Exception(rb.getString("Input.not.an.X.509.certificate"));
2656 }
2657
2658 // if certificate is self-signed, make sure it verifies
2659 boolean selfSigned = false;
2660 if (isSelfSigned(cert)) {
2661 cert.verify(cert.getPublicKey());
2662 selfSigned = true;
2663 }
2664
2665 if (noprompt) {
2666 keyStore.setCertificateEntry(alias, cert);
2667 return true;
2668 }
2669
2670 // check if cert already exists in keystore
2671 String reply = null;
2672 String trustalias = keyStore.getCertificateAlias(cert);
2673 if (trustalias != null) {
2674 MessageFormat form = new MessageFormat(rb.getString
2675 ("Certificate.already.exists.in.keystore.under.alias.trustalias."));
2676 Object[] source = {trustalias};
2677 System.err.println(form.format(source));
2678 reply = getYesNoReply
2679 (rb.getString("Do.you.still.want.to.add.it.no."));
2680 } else if (selfSigned) {
2681 if (trustcacerts && (caks != null) &&
2682 ((trustalias=caks.getCertificateAlias(cert)) != null)) {
2683 MessageFormat form = new MessageFormat(rb.getString
2684 ("Certificate.already.exists.in.system.wide.CA.keystore.under.alias.trustalias."));
2685 Object[] source = {trustalias};
2686 System.err.println(form.format(source));
2687 reply = getYesNoReply
2688 (rb.getString("Do.you.still.want.to.add.it.to.your.own.keystore.no."));
2689 }
2690 if (trustalias == null) {
2691 // Print the cert and ask user if they really want to add
2692 // it to their keystore
2693 printX509Cert(cert, System.out);
2694 reply = getYesNoReply
2695 (rb.getString("Trust.this.certificate.no."));
2696 }
2697 }
2698 if (reply != null) {
2699 if ("YES".equals(reply)) {
2700 keyStore.setCertificateEntry(alias, cert);
2701 return true;
2702 } else {
2703 return false;
2704 }
2705 }
2706
2707 // Try to establish trust chain
2708 try {
2709 Certificate[] chain = establishCertChain(null, cert);
2710 if (chain != null) {
2711 keyStore.setCertificateEntry(alias, cert);
2712 return true;
2713 }
2714 } catch (Exception e) {
2715 // Print the cert and ask user if they really want to add it to
2716 // their keystore
2717 printX509Cert(cert, System.out);
2718 reply = getYesNoReply
2719 (rb.getString("Trust.this.certificate.no."));
2720 if ("YES".equals(reply)) {
2721 keyStore.setCertificateEntry(alias, cert);
2722 return true;
2723 } else {
2724 return false;
2725 }
2726 }
2727
2728 return false;
2729 }
2730
2731 /**
2732 * Prompts user for new password. New password must be different from
2733 * old one.
2734 *
2735 * @param prompt the message that gets prompted on the screen
2736 * @param oldPasswd the current (i.e., old) password
2737 */
2836 ("Enter.key.password.for.alias."));
2837 Object[] source = {alias};
2838 System.err.print(form.format(source));
2839 }
2840 System.err.flush();
2841 keyPass = Password.readPassword(System.in);
2842 passwords.add(keyPass);
2843 if (keyPass == null) {
2844 keyPass = otherKeyPass;
2845 }
2846 count++;
2847 } while ((keyPass == null) && count < 3);
2848
2849 if (keyPass == null) {
2850 throw new Exception(rb.getString("Too.many.failures.try.later"));
2851 }
2852
2853 return keyPass;
2854 }
2855
2856 /**
2857 * Prints a certificate in a human readable format.
2858 */
2859 private void printX509Cert(X509Certificate cert, PrintStream out)
2860 throws Exception
2861 {
2862 /*
2863 out.println("Owner: "
2864 + cert.getSubjectDN().toString()
2865 + "\n"
2866 + "Issuer: "
2867 + cert.getIssuerDN().toString()
2868 + "\n"
2869 + "Serial number: " + cert.getSerialNumber().toString(16)
2870 + "\n"
2871 + "Valid from: " + cert.getNotBefore().toString()
2872 + " until: " + cert.getNotAfter().toString()
2873 + "\n"
2874 + "Certificate fingerprints:\n"
2875 + "\t MD5: " + getCertFingerPrint("MD5", cert)
2876 + "\n"
2877 + "\t SHA1: " + getCertFingerPrint("SHA1", cert));
2878 */
2879
2880 MessageFormat form = new MessageFormat
2881 (rb.getString(".PATTERN.printX509Cert"));
2882 Object[] source = {cert.getSubjectDN().toString(),
2883 cert.getIssuerDN().toString(),
2884 cert.getSerialNumber().toString(16),
2885 cert.getNotBefore().toString(),
2886 cert.getNotAfter().toString(),
2887 getCertFingerPrint("MD5", cert),
2888 getCertFingerPrint("SHA1", cert),
2889 getCertFingerPrint("SHA-256", cert),
2890 cert.getSigAlgName(),
2891 cert.getVersion()
2892 };
2893 out.println(form.format(source));
2894
2895 if (cert instanceof X509CertImpl) {
2896 X509CertImpl impl = (X509CertImpl)cert;
2897 X509CertInfo certInfo = (X509CertInfo)impl.get(X509CertImpl.NAME
2898 + "." +
2899 X509CertImpl.INFO);
2900 CertificateExtensions exts = (CertificateExtensions)
2901 certInfo.get(X509CertInfo.EXTENSIONS);
2902 if (exts != null) {
2903 printExtensions(rb.getString("Extensions."), exts, out);
2904 }
2905 }
2906 }
2907
2908 private static void printExtensions(String title, CertificateExtensions exts, PrintStream out)
2909 throws Exception {
2910 int extnum = 0;
2940
2941 private boolean signedBy(X509Certificate end, X509Certificate ca) {
2942 if (!ca.getSubjectDN().equals(end.getIssuerDN())) {
2943 return false;
2944 }
2945 try {
2946 end.verify(ca.getPublicKey());
2947 return true;
2948 } catch (Exception e) {
2949 return false;
2950 }
2951 }
2952
2953 /**
2954 * Locates a signer for a given certificate from a given keystore and
2955 * returns the signer's certificate.
2956 * @param cert the certificate whose signer is searched, not null
2957 * @param ks the keystore to search with, not null
2958 * @return <code>cert</code> itself if it's already inside <code>ks</code>,
2959 * or a certificate inside <code>ks</code> who signs <code>cert</code>,
2960 * or null otherwise.
2961 */
2962 private static Certificate getTrustedSigner(Certificate cert, KeyStore ks)
2963 throws Exception {
2964 if (ks.getCertificateAlias(cert) != null) {
2965 return cert;
2966 }
2967 for (Enumeration<String> aliases = ks.aliases();
2968 aliases.hasMoreElements(); ) {
2969 String name = aliases.nextElement();
2970 Certificate trustedCert = ks.getCertificate(name);
2971 if (trustedCert != null) {
2972 try {
2973 cert.verify(trustedCert.getPublicKey());
2974 return trustedCert;
2975 } catch (Exception e) {
2976 // Not verified, skip to the next one
2977 }
2978 }
2979 }
2980 return null;
2981 }
2982
2983 /**
2984 * Gets an X.500 name suitable for inclusion in a certification request.
2985 */
2986 private X500Name getX500Name() throws IOException {
2987 BufferedReader in;
2988 in = new BufferedReader(new InputStreamReader(System.in));
2989 String commonName = "Unknown";
2990 String organizationalUnit = "Unknown";
2991 String organization = "Unknown";
2992 String city = "Unknown";
2993 String state = "Unknown";
2994 String country = "Unknown";
3218 }
3219 }
3220
3221 return Pair.of(entry, pkey);
3222 }
3223 /**
3224 * Gets the requested finger print of the certificate.
3225 */
3226 private String getCertFingerPrint(String mdAlg, Certificate cert)
3227 throws Exception
3228 {
3229 byte[] encCertInfo = cert.getEncoded();
3230 MessageDigest md = MessageDigest.getInstance(mdAlg);
3231 byte[] digest = md.digest(encCertInfo);
3232 return toHexString(digest);
3233 }
3234
3235 /**
3236 * Prints warning about missing integrity check.
3237 */
3238 private void printWarning() {
3239 System.err.println();
3240 System.err.println(rb.getString
3241 (".WARNING.WARNING.WARNING."));
3242 System.err.println(rb.getString
3243 (".The.integrity.of.the.information.stored.in.your.keystore."));
3244 System.err.println(rb.getString
3245 (".WARNING.WARNING.WARNING."));
3246 System.err.println();
3247 }
3248
3249 /**
3250 * Validates chain in certification reply, and returns the ordered
3251 * elements of the chain (with user certificate first, and root
3252 * certificate last in the array).
3253 *
3254 * @param alias the alias name
3255 * @param userCert the user certificate of the alias
3256 * @param replyCerts the chain provided in the reply
3257 */
3258 private Certificate[] validateReply(String alias,
3259 Certificate userCert,
3260 Certificate[] replyCerts)
3261 throws Exception
3262 {
3263 // order the certs in the reply (bottom-up).
3264 // we know that all certs in the reply are of type X.509, because
3265 // we parsed them using an X.509 certificate factory
3266 int i;
3267 PublicKey userPubKey = userCert.getPublicKey();
3268 for (i=0; i<replyCerts.length; i++) {
3269 if (userPubKey.equals(replyCerts[i].getPublicKey())) {
3270 break;
3271 }
3272 }
3273 if (i == replyCerts.length) {
3274 MessageFormat form = new MessageFormat(rb.getString
3275 ("Certificate.reply.does.not.contain.public.key.for.alias."));
3276 Object[] source = {alias};
3277 throw new Exception(form.format(source));
3278 }
3279
3280 Certificate tmpCert = replyCerts[0];
3281 replyCerts[0] = replyCerts[i];
3282 replyCerts[i] = tmpCert;
3290 if (signedBy(thisCert, (X509Certificate)replyCerts[j])) {
3291 tmpCert = replyCerts[i];
3292 replyCerts[i] = replyCerts[j];
3293 replyCerts[j] = tmpCert;
3294 thisCert = (X509Certificate)replyCerts[i];
3295 break;
3296 }
3297 }
3298 if (j == replyCerts.length) {
3299 throw new Exception
3300 (rb.getString("Incomplete.certificate.chain.in.reply"));
3301 }
3302 }
3303
3304 if (noprompt) {
3305 return replyCerts;
3306 }
3307
3308 // do we trust the cert at the top?
3309 Certificate topCert = replyCerts[replyCerts.length-1];
3310 Certificate root = getTrustedSigner(topCert, keyStore);
3311 if (root == null && trustcacerts && caks != null) {
3312 root = getTrustedSigner(topCert, caks);
3313 }
3314 if (root == null) {
3315 System.err.println();
3316 System.err.println
3317 (rb.getString("Top.level.certificate.in.reply."));
3318 printX509Cert((X509Certificate)topCert, System.out);
3319 System.err.println();
3320 System.err.print(rb.getString(".is.not.trusted."));
3321 String reply = getYesNoReply
3322 (rb.getString("Install.reply.anyway.no."));
3323 if ("NO".equals(reply)) {
3324 return null;
3325 }
3326 } else {
3327 if (root != topCert) {
3328 // append the root CA cert to the chain
3329 Certificate[] tmpCerts =
3330 new Certificate[replyCerts.length+1];
3331 System.arraycopy(replyCerts, 0, tmpCerts, 0,
3332 replyCerts.length);
3333 tmpCerts[tmpCerts.length-1] = root;
3334 replyCerts = tmpCerts;
3335 }
3336 }
3337
3338 return replyCerts;
3339 }
3340
3341 /**
3342 * Establishes a certificate chain (using trusted certificates in the
3343 * keystore), starting with the user certificate
3344 * and ending at a self-signed certificate found in the keystore.
3345 *
3346 * @param userCert the user certificate of the alias
3347 * @param certToVerify the single certificate provided in the reply
3348 */
3349 private Certificate[] establishCertChain(Certificate userCert,
3350 Certificate certToVerify)
3351 throws Exception
3352 {
3353 if (userCert != null) {
3354 // Make sure that the public key of the certificate reply matches
3355 // the original public key in the keystore
3356 PublicKey origPubKey = userCert.getPublicKey();
3357 PublicKey replyPubKey = certToVerify.getPublicKey();
3358 if (!origPubKey.equals(replyPubKey)) {
3359 throw new Exception(rb.getString
3360 ("Public.keys.in.reply.and.keystore.don.t.match"));
3361 }
3362
3363 // If the two certs are identical, we're done: no need to import
3364 // anything
3365 if (certToVerify.equals(userCert)) {
3366 throw new Exception(rb.getString
3367 ("Certificate.reply.and.certificate.in.keystore.are.identical"));
3368 }
3369 }
3370
3371 // Build a hash table of all certificates in the keystore.
3372 // Use the subject distinguished name as the key into the hash table.
3373 // All certificates associated with the same subject distinguished
3374 // name are stored in the same hash table entry as a vector.
3375 Hashtable<Principal, Vector<Certificate>> certs = null;
3376 if (keyStore.size() > 0) {
3377 certs = new Hashtable<Principal, Vector<Certificate>>(11);
3378 keystorecerts2Hashtable(keyStore, certs);
3379 }
3380 if (trustcacerts) {
3381 if (caks!=null && caks.size()>0) {
3382 if (certs == null) {
3383 certs = new Hashtable<Principal, Vector<Certificate>>(11);
3384 }
3385 keystorecerts2Hashtable(caks, certs);
3386 }
3387 }
3388
3389 // start building chain
3390 Vector<Certificate> chain = new Vector<>(2);
3391 if (buildChain((X509Certificate)certToVerify, chain, certs)) {
3392 Certificate[] newChain = new Certificate[chain.size()];
3393 // buildChain() returns chain with self-signed root-cert first and
3394 // user-cert last, so we need to invert the chain before we store
3395 // it
3396 int j=0;
3397 for (int i=chain.size()-1; i>=0; i--) {
3398 newChain[j] = chain.elementAt(i);
3399 j++;
3400 }
3401 return newChain;
3402 } else {
3403 throw new Exception
3404 (rb.getString("Failed.to.establish.chain.from.reply"));
3405 }
3406 }
3407
3408 /**
3409 * Recursively tries to establish chain from pool of trusted certs.
3410 *
3411 * @param certToVerify the cert that needs to be verified.
3412 * @param chain the chain that's being built.
3413 * @param certs the pool of trusted certs
3414 *
3415 * @return true if successful, false otherwise.
3416 */
3417 private boolean buildChain(X509Certificate certToVerify,
3418 Vector<Certificate> chain,
3419 Hashtable<Principal, Vector<Certificate>> certs) {
3420 Principal issuer = certToVerify.getIssuerDN();
3421 if (isSelfSigned(certToVerify)) {
3422 // reached self-signed root cert;
3423 // no verification needed because it's trusted.
3424 chain.addElement(certToVerify);
3425 return true;
3426 }
3427
3428 // Get the issuer's certificate(s)
3429 Vector<Certificate> vec = certs.get(issuer);
3430 if (vec == null) {
3431 return false;
3432 }
3433
3434 // Try out each certificate in the vector, until we find one
3435 // whose public key verifies the signature of the certificate
3436 // in question.
3437 for (Enumeration<Certificate> issuerCerts = vec.elements();
3438 issuerCerts.hasMoreElements(); ) {
3439 X509Certificate issuerCert
3440 = (X509Certificate)issuerCerts.nextElement();
3441 PublicKey issuerPubKey = issuerCert.getPublicKey();
3442 try {
3443 certToVerify.verify(issuerPubKey);
3444 } catch (Exception e) {
3445 continue;
3446 }
3447 if (buildChain(issuerCert, chain, certs)) {
3448 chain.addElement(certToVerify);
3449 return true;
3450 }
3451 }
3452 return false;
3453 }
3454
3455 /**
3456 * Prompts user for yes/no decision.
3457 *
3458 * @return the user's decision, can only be "YES" or "NO"
3459 */
3460 private String getYesNoReply(String prompt)
3461 throws IOException
3462 {
3463 String reply = null;
3472 reply = (new BufferedReader(new InputStreamReader
3473 (System.in))).readLine();
3474 if (collator.compare(reply, "") == 0 ||
3475 collator.compare(reply, rb.getString("n")) == 0 ||
3476 collator.compare(reply, rb.getString("no")) == 0) {
3477 reply = "NO";
3478 } else if (collator.compare(reply, rb.getString("y")) == 0 ||
3479 collator.compare(reply, rb.getString("yes")) == 0) {
3480 reply = "YES";
3481 } else {
3482 System.err.println(rb.getString("Wrong.answer.try.again"));
3483 reply = null;
3484 }
3485 } while (reply == null);
3486 return reply;
3487 }
3488
3489 /**
3490 * Stores the (leaf) certificates of a keystore in a hashtable.
3491 * All certs belonging to the same CA are stored in a vector that
3492 * in turn is stored in the hashtable, keyed by the CA's subject DN
3493 */
3494 private void keystorecerts2Hashtable(KeyStore ks,
3495 Hashtable<Principal, Vector<Certificate>> hash)
3496 throws Exception {
3497
3498 for (Enumeration<String> aliases = ks.aliases();
3499 aliases.hasMoreElements(); ) {
3500 String alias = aliases.nextElement();
3501 Certificate cert = ks.getCertificate(alias);
3502 if (cert != null) {
3503 Principal subjectDN = ((X509Certificate)cert).getSubjectDN();
3504 Vector<Certificate> vec = hash.get(subjectDN);
3505 if (vec == null) {
3506 vec = new Vector<Certificate>();
3507 vec.addElement(cert);
3508 } else {
3509 if (!vec.contains(cert)) {
3510 vec.addElement(cert);
3511 }
3512 }
3513 hash.put(subjectDN, vec);
3514 }
3515 }
3516 }
3517
3518 /**
3519 * Returns the issue time that's specified the -startdate option
3520 * @param s the value of -startdate option
3521 */
3522 private static Date getStartDate(String s) throws IOException {
3523 Calendar c = new GregorianCalendar();
3524 if (s != null) {
3525 IOException ioe = new IOException(
3526 rb.getString("Illegal.startdate.value"));
3527 int len = s.length();
3528 if (len == 0) {
3529 throw ioe;
3530 }
4061 .toByteArray()));
4062 break;
4063 default:
4064 throw new Exception(rb.getString(
4065 "Unknown.extension.type.") + extstr);
4066 }
4067 }
4068 // always non-critical
4069 ext.set(SubjectKeyIdentifierExtension.NAME,
4070 new SubjectKeyIdentifierExtension(
4071 new KeyIdentifier(pkey).getIdentifier()));
4072 if (akey != null && !pkey.equals(akey)) {
4073 ext.set(AuthorityKeyIdentifierExtension.NAME,
4074 new AuthorityKeyIdentifierExtension(
4075 new KeyIdentifier(akey), null, null));
4076 }
4077 } catch(IOException e) {
4078 throw new RuntimeException(e);
4079 }
4080 return ext;
4081 }
4082
4083 /**
4084 * Prints the usage of this tool.
4085 */
4086 private void usage() {
4087 if (command != null) {
4088 System.err.println("keytool " + command +
4089 rb.getString(".OPTION."));
4090 System.err.println();
4091 System.err.println(rb.getString(command.description));
4092 System.err.println();
4093 System.err.println(rb.getString("Options."));
4094 System.err.println();
4095
4096 // Left and right sides of the options list
4097 String[] left = new String[command.options.length];
4098 String[] right = new String[command.options.length];
4099
4100 // Check if there's an unknown option
|
1 /*
2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.security.tools.keytool;
27
28 import java.io.*;
29 import java.nio.file.Files;
30 import java.nio.file.Paths;
31 import java.security.CodeSigner;
32 import java.security.CryptoPrimitive;
33 import java.security.KeyStore;
34 import java.security.KeyStoreException;
35 import java.security.MessageDigest;
36 import java.security.Key;
37 import java.security.PublicKey;
38 import java.security.PrivateKey;
39 import java.security.Security;
40 import java.security.Signature;
41 import java.security.Timestamp;
42 import java.security.UnrecoverableEntryException;
43 import java.security.UnrecoverableKeyException;
44 import java.security.NoSuchAlgorithmException;
45 import java.security.Principal;
46 import java.security.Provider;
47 import java.security.cert.Certificate;
48 import java.security.cert.CertificateFactory;
49 import java.security.cert.CertStoreException;
50 import java.security.cert.CRL;
51 import java.security.cert.X509Certificate;
52 import java.security.cert.CertificateException;
53 import java.text.Collator;
54 import java.text.MessageFormat;
55 import java.util.*;
56 import java.util.jar.JarEntry;
57 import java.util.jar.JarFile;
58 import java.lang.reflect.Constructor;
59 import java.math.BigInteger;
60 import java.net.URI;
61 import java.net.URL;
62 import java.net.URLClassLoader;
63 import java.security.cert.CertStore;
64
65 import java.security.cert.X509CRL;
66 import java.security.cert.X509CRLEntry;
67 import java.security.cert.X509CRLSelector;
68 import javax.security.auth.x500.X500Principal;
69 import java.util.Base64;
70
71 import sun.security.util.DisabledAlgorithmConstraints;
72 import sun.security.util.KeyUtil;
73 import sun.security.util.ObjectIdentifier;
74 import sun.security.pkcs10.PKCS10;
75 import sun.security.pkcs10.PKCS10Attribute;
76 import sun.security.provider.X509Factory;
77 import sun.security.provider.certpath.CertStoreHelper;
78 import sun.security.util.Password;
79 import sun.security.util.SecurityProviderConstants;
80 import javax.crypto.KeyGenerator;
81 import javax.crypto.SecretKey;
82 import javax.crypto.SecretKeyFactory;
83 import javax.crypto.spec.PBEKeySpec;
84
85 import sun.security.pkcs.PKCS9Attribute;
86 import sun.security.tools.KeyStoreUtil;
87 import sun.security.tools.PathList;
88 import sun.security.util.DerValue;
89 import sun.security.util.Pem;
90 import sun.security.x509.*;
91
92 import static java.security.KeyStore.*;
93 import static sun.security.tools.keytool.Main.Command.*;
94 import static sun.security.tools.keytool.Main.Option.*;
95
96 /**
97 * This tool manages keystores.
98 *
99 * @author Jan Luehe
137 private String providerName = null;
138 private String pathlist = null;
139 private char[] storePass = null;
140 private char[] storePassNew = null;
141 private char[] keyPass = null;
142 private char[] keyPassNew = null;
143 private char[] newPass = null;
144 private char[] destKeyPass = null;
145 private char[] srckeyPass = null;
146 private String ksfname = null;
147 private File ksfile = null;
148 private InputStream ksStream = null; // keystore stream
149 private String sslserver = null;
150 private String jarfile = null;
151 private KeyStore keyStore = null;
152 private boolean token = false;
153 private boolean nullStream = false;
154 private boolean kssave = false;
155 private boolean noprompt = false;
156 private boolean trustcacerts = false;
157 private boolean nowarn = false;
158 private boolean protectedPath = false;
159 private boolean srcprotectedPath = false;
160 private CertificateFactory cf = null;
161 private KeyStore caks = null; // "cacerts" keystore
162 private char[] srcstorePass = null;
163 private String srcstoretype = null;
164 private Set<char[]> passwords = new HashSet<>();
165 private String startDate = null;
166
167 private List<String> ids = new ArrayList<>(); // used in GENCRL
168 private List<String> v3ext = new ArrayList<>();
169
170 // In-place importkeystore is special.
171 // A backup is needed, and no need to prompt for deststorepass.
172 private boolean inplaceImport = false;
173 private String inplaceBackupName = null;
174
175 // Warnings on weak algorithms etc
176 private List<String> weakWarnings = new ArrayList<>();
177
178 private static final DisabledAlgorithmConstraints DISABLED_CHECK =
179 new DisabledAlgorithmConstraints(
180 DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
181
182 private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections
183 .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
184
185 enum Command {
186 CERTREQ("Generates.a.certificate.request",
187 ALIAS, SIGALG, FILEOUT, KEYPASS, KEYSTORE, DNAME,
188 STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS,
189 PROVIDERARG, PROVIDERPATH, V, PROTECTED),
190 CHANGEALIAS("Changes.an.entry.s.alias",
191 ALIAS, DESTALIAS, KEYPASS, KEYSTORE, STOREPASS,
192 STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG,
193 PROVIDERPATH, V, PROTECTED),
194 DELETE("Deletes.an.entry",
195 ALIAS, KEYSTORE, STOREPASS, STORETYPE,
196 PROVIDERNAME, PROVIDERCLASS, PROVIDERARG,
197 PROVIDERPATH, V, PROTECTED),
198 EXPORTCERT("Exports.certificate",
199 RFC, ALIAS, FILEOUT, KEYSTORE, STOREPASS,
200 STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG,
201 PROVIDERPATH, V, PROTECTED),
202 GENKEYPAIR("Generates.a.key.pair",
203 ALIAS, KEYALG, KEYSIZE, SIGALG, DESTALIAS, DNAME,
204 STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE,
323 V("v", null, "verbose.output"),
324 VALIDITY("validity", "<valDays>", "validity.number.of.days");
325
326 final String name, arg, description;
327 Option(String name, String arg, String description) {
328 this.name = name;
329 this.arg = arg;
330 this.description = description;
331 }
332 @Override
333 public String toString() {
334 return "-" + name;
335 }
336 };
337
338 private static final Class<?>[] PARAM_STRING = { String.class };
339
340 private static final String NONE = "NONE";
341 private static final String P11KEYSTORE = "PKCS11";
342 private static final String P12KEYSTORE = "PKCS12";
343 private static final String keyAlias = "mykey";
344
345 // for i18n
346 private static final java.util.ResourceBundle rb =
347 java.util.ResourceBundle.getBundle(
348 "sun.security.tools.keytool.Resources");
349 private static final Collator collator = Collator.getInstance();
350 static {
351 // this is for case insensitive string comparisons
352 collator.setStrength(Collator.PRIMARY);
353 };
354
355 private Main() { }
356
357 public static void main(String[] args) throws Exception {
358 Main kt = new Main();
359 kt.run(args, System.out);
360 }
361
362 private void run(String[] args, PrintStream out) throws Exception {
363 try {
364 parseArgs(args);
365 if (command != null) {
366 doCommands(out);
367 }
368 } catch (Exception e) {
369 System.out.println(rb.getString("keytool.error.") + e);
370 if (verbose) {
371 e.printStackTrace(System.out);
372 }
373 if (!debug) {
374 System.exit(1);
375 } else {
376 throw e;
377 }
378 } finally {
379 printWeakWarnings(false);
380 for (char[] pass : passwords) {
381 if (pass != null) {
382 Arrays.fill(pass, ' ');
383 pass = null;
384 }
385 }
386
387 if (ksStream != null) {
388 ksStream.close();
389 }
390 }
391 }
392
393 /**
394 * Parse command line arguments.
395 */
396 void parseArgs(String[] args) {
397
398 int i=0;
399 boolean help = args.length == 0;
427 */
428 boolean isCommand = false;
429 for (Command c: Command.values()) {
430 if (collator.compare(flags, c.toString()) == 0) {
431 command = c;
432 isCommand = true;
433 break;
434 }
435 }
436
437 if (isCommand) {
438 // already recognized as a command
439 } else if (collator.compare(flags, "-export") == 0) {
440 command = EXPORTCERT;
441 } else if (collator.compare(flags, "-genkey") == 0) {
442 command = GENKEYPAIR;
443 } else if (collator.compare(flags, "-import") == 0) {
444 command = IMPORTCERT;
445 } else if (collator.compare(flags, "-importpassword") == 0) {
446 command = IMPORTPASS;
447 } else if (collator.compare(flags, "-help") == 0) {
448 help = true;
449 } else if (collator.compare(flags, "-nowarn") == 0) {
450 nowarn = true;
451 }
452
453 /*
454 * specifiers
455 */
456 else if (collator.compare(flags, "-keystore") == 0 ||
457 collator.compare(flags, "-destkeystore") == 0) {
458 ksfname = args[++i];
459 } else if (collator.compare(flags, "-storepass") == 0 ||
460 collator.compare(flags, "-deststorepass") == 0) {
461 storePass = getPass(modifier, args[++i]);
462 passwords.add(storePass);
463 } else if (collator.compare(flags, "-storetype") == 0 ||
464 collator.compare(flags, "-deststoretype") == 0) {
465 storetype = args[++i];
466 } else if (collator.compare(flags, "-srcstorepass") == 0) {
467 srcstorePass = getPass(modifier, args[++i]);
468 passwords.add(srcstorePass);
469 } else if (collator.compare(flags, "-srcstoretype") == 0) {
470 srcstoretype = args[++i];
718 if (command == LIST && verbose && rfc) {
719 System.err.println(rb.getString
720 ("Must.not.specify.both.v.and.rfc.with.list.command"));
721 tinyHelp();
722 }
723
724 // Make sure provided passwords are at least 6 characters long
725 if (command == GENKEYPAIR && keyPass!=null && keyPass.length < 6) {
726 throw new Exception(rb.getString
727 ("Key.password.must.be.at.least.6.characters"));
728 }
729 if (newPass != null && newPass.length < 6) {
730 throw new Exception(rb.getString
731 ("New.password.must.be.at.least.6.characters"));
732 }
733 if (destKeyPass != null && destKeyPass.length < 6) {
734 throw new Exception(rb.getString
735 ("New.password.must.be.at.least.6.characters"));
736 }
737
738 // Set this before inplaceImport check so we can compare name.
739 if (ksfname == null) {
740 ksfname = System.getProperty("user.home") + File.separator
741 + ".keystore";
742 }
743
744 KeyStore srcKeyStore = null;
745 if (command == IMPORTKEYSTORE) {
746 inplaceImport = inplaceImportCheck();
747 if (inplaceImport) {
748 // We load srckeystore first so we have srcstorePass that
749 // can be assigned to storePass
750 srcKeyStore = loadSourceKeyStore();
751 if (storePass == null) {
752 storePass = srcstorePass;
753 }
754 }
755 }
756
757 // Check if keystore exists.
758 // If no keystore has been specified at the command line, try to use
759 // the default, which is located in $HOME/.keystore.
760 // If the command is "genkey", "identitydb", "import", or "printcert",
761 // it is OK not to have a keystore.
762
763 // DO NOT open the existing keystore if this is an in-place import.
764 // The keystore should be created as brand new.
765 if (isKeyStoreRelated(command) && !nullStream && !inplaceImport) {
766 try {
767 ksfile = new File(ksfname);
768 // Check if keystore file is empty
769 if (ksfile.exists() && ksfile.length() == 0) {
770 throw new Exception(rb.getString
771 ("Keystore.file.exists.but.is.empty.") + ksfname);
772 }
773 ksStream = new FileInputStream(ksfile);
774 } catch (FileNotFoundException e) {
775 if (command != GENKEYPAIR &&
776 command != GENSECKEY &&
777 command != IDENTITYDB &&
778 command != IMPORTCERT &&
779 command != IMPORTPASS &&
780 command != IMPORTKEYSTORE &&
781 command != PRINTCRL) {
782 throw new Exception(rb.getString
783 ("Keystore.file.does.not.exist.") + ksfname);
784 }
785 }
786 }
787
788 if ((command == KEYCLONE || command == CHANGEALIAS)
789 && dest == null) {
790 dest = getAlias("destination");
791 if ("".equals(dest)) {
792 throw new Exception(rb.getString
793 ("Must.specify.destination.alias"));
794 }
795 }
796
797 if (command == DELETE && alias == null) {
798 alias = getAlias(null);
799 if ("".equals(alias)) {
800 throw new Exception(rb.getString("Must.specify.alias"));
801 }
802 }
803
804 // Create new keystore
805 if (providerName == null) {
806 keyStore = KeyStore.getInstance(storetype);
812 * Load the keystore data.
813 *
814 * At this point, it's OK if no keystore password has been provided.
815 * We want to make sure that we can load the keystore data, i.e.,
816 * the keystore data has the right format. If we cannot load the
817 * keystore, why bother asking the user for his or her password?
818 * Only if we were able to load the keystore, and no keystore
819 * password has been provided, will we prompt the user for the
820 * keystore password to verify the keystore integrity.
821 * This means that the keystore is loaded twice: first load operation
822 * checks the keystore format, second load operation verifies the
823 * keystore integrity.
824 *
825 * If the keystore password has already been provided (at the
826 * command line), however, the keystore is loaded only once, and the
827 * keystore format and integrity are checked "at the same time".
828 *
829 * Null stream keystores are loaded later.
830 */
831 if (!nullStream) {
832 if (inplaceImport) {
833 keyStore.load(null, storePass);
834 } else {
835 keyStore.load(ksStream, storePass);
836 }
837 if (ksStream != null) {
838 ksStream.close();
839 }
840 }
841
842 // All commands that create or modify the keystore require a keystore
843 // password.
844
845 if (nullStream && storePass != null) {
846 keyStore.load(null, storePass);
847 } else if (!nullStream && storePass != null) {
848 // If we are creating a new non nullStream-based keystore,
849 // insist that the password be at least 6 characters
850 if (ksStream == null && storePass.length < 6) {
851 throw new Exception(rb.getString
852 ("Keystore.password.must.be.at.least.6.characters"));
853 }
854 } else if (storePass == null) {
855
856 // only prompt if (protectedPath == false)
944 keyPass = storePass;
945 }
946 if (newPass != null && !Arrays.equals(storePass, newPass)) {
947 Object[] source = {"-new"};
948 System.err.println(form.format(source));
949 newPass = storePass;
950 }
951 if (destKeyPass != null && !Arrays.equals(storePass, destKeyPass)) {
952 Object[] source = {"-destkeypass"};
953 System.err.println(form.format(source));
954 destKeyPass = storePass;
955 }
956 }
957
958 // Create a certificate factory
959 if (command == PRINTCERT || command == IMPORTCERT
960 || command == IDENTITYDB || command == PRINTCRL) {
961 cf = CertificateFactory.getInstance("X509");
962 }
963
964 // -trustcacerts can only be specified on -importcert.
965 // Reset it so that warnings on CA cert will remain for
966 // -printcert, etc.
967 if (command != IMPORTCERT) {
968 trustcacerts = false;
969 }
970
971 if (trustcacerts) {
972 caks = KeyStoreUtil.getCacertsKeyStore();
973 }
974
975 // Perform the specified command
976 if (command == CERTREQ) {
977 if (filename != null) {
978 try (PrintStream ps = new PrintStream(new FileOutputStream
979 (filename))) {
980 doCertReq(alias, sigAlgName, ps);
981 }
982 } else {
983 doCertReq(alias, sigAlgName, out);
984 }
985 if (verbose && filename != null) {
986 MessageFormat form = new MessageFormat(rb.getString
987 ("Certification.request.stored.in.file.filename."));
988 Object[] source = {filename};
989 System.err.println(form.format(source));
990 System.err.println(rb.getString("Submit.this.to.your.CA"));
1052 ("Certificate.reply.was.not.installed.in.keystore"));
1053 }
1054 } else if (!keyStore.containsAlias(importAlias) ||
1055 keyStore.entryInstanceOf(importAlias,
1056 KeyStore.TrustedCertificateEntry.class)) {
1057 kssave = addTrustedCert(importAlias, inStream);
1058 if (kssave) {
1059 System.err.println(rb.getString
1060 ("Certificate.was.added.to.keystore"));
1061 } else {
1062 System.err.println(rb.getString
1063 ("Certificate.was.not.added.to.keystore"));
1064 }
1065 }
1066 } finally {
1067 if (inStream != System.in) {
1068 inStream.close();
1069 }
1070 }
1071 } else if (command == IMPORTKEYSTORE) {
1072 // When not in-place import, srcKeyStore is not loaded yet.
1073 if (srcKeyStore == null) {
1074 srcKeyStore = loadSourceKeyStore();
1075 }
1076 doImportKeyStore(srcKeyStore);
1077 kssave = true;
1078 } else if (command == KEYCLONE) {
1079 keyPassNew = newPass;
1080
1081 // added to make sure only key can go thru
1082 if (alias == null) {
1083 alias = keyAlias;
1084 }
1085 if (keyStore.containsAlias(alias) == false) {
1086 MessageFormat form = new MessageFormat
1087 (rb.getString("Alias.alias.does.not.exist"));
1088 Object[] source = {alias};
1089 throw new Exception(form.format(source));
1090 }
1091 if (!keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
1092 MessageFormat form = new MessageFormat(rb.getString(
1093 "Alias.alias.references.an.entry.type.that.is.not.a.private.key.entry.The.keyclone.command.only.supports.cloning.of.private.key"));
1094 Object[] source = {alias};
1095 throw new Exception(form.format(source));
1096 }
1097
1098 doCloneEntry(alias, dest, true); // Now everything can be cloned
1099 kssave = true;
1100 } else if (command == CHANGEALIAS) {
1101 if (alias == null) {
1102 alias = keyAlias;
1103 }
1104 doCloneEntry(alias, dest, false);
1105 // in PKCS11, clone a PrivateKeyEntry will delete the old one
1106 if (keyStore.containsAlias(alias)) {
1107 doDeleteEntry(alias);
1108 }
1109 kssave = true;
1110 } else if (command == KEYPASSWD) {
1111 keyPassNew = newPass;
1112 doChangeKeyPasswd(alias);
1113 kssave = true;
1114 } else if (command == LIST) {
1115 if (storePass == null
1116 && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
1117 printNoIntegrityWarning();
1118 }
1119
1120 if (alias != null) {
1121 doPrintEntry(rb.getString("the.certificate"), alias, out);
1122 } else {
1123 doPrintEntries(out);
1124 }
1125 } else if (command == PRINTCERT) {
1126 doPrintCert(out);
1127 } else if (command == SELFCERT) {
1128 doSelfCert(alias, dname, sigAlgName);
1129 kssave = true;
1130 } else if (command == STOREPASSWD) {
1131 storePassNew = newPass;
1132 if (storePassNew == null) {
1133 storePassNew = getNewPasswd("keystore password", storePass);
1134 }
1135 kssave = true;
1136 } else if (command == GENCERT) {
1137 if (alias == null) {
1138 alias = keyAlias;
1139 }
1140 InputStream inStream = System.in;
1141 if (infilename != null) {
1187 (rb.getString(".Storing.ksfname."));
1188 Object[] source = {nullStream ? "keystore" : ksfname};
1189 System.err.println(form.format(source));
1190 }
1191
1192 if (token) {
1193 keyStore.store(null, null);
1194 } else {
1195 char[] pass = (storePassNew!=null) ? storePassNew : storePass;
1196 if (nullStream) {
1197 keyStore.store(null, pass);
1198 } else {
1199 ByteArrayOutputStream bout = new ByteArrayOutputStream();
1200 keyStore.store(bout, pass);
1201 try (FileOutputStream fout = new FileOutputStream(ksfname)) {
1202 fout.write(bout.toByteArray());
1203 }
1204 }
1205 }
1206 }
1207
1208 if (isKeyStoreRelated(command)
1209 && !token && !nullStream && ksfname != null) {
1210
1211 // JKS storetype warning on the final result keystore
1212 File f = new File(ksfname);
1213 if (f.exists()) {
1214 // Read the first 4 bytes to determine
1215 // if we're dealing with JKS/JCEKS type store
1216 String realType = keyStoreType(f);
1217 if (realType.equalsIgnoreCase("JKS")
1218 || realType.equalsIgnoreCase("JCEKS")) {
1219 boolean allCerts = true;
1220 for (String a : Collections.list(keyStore.aliases())) {
1221 if (!keyStore.entryInstanceOf(
1222 a, TrustedCertificateEntry.class)) {
1223 allCerts = false;
1224 break;
1225 }
1226 }
1227 // Don't warn for "cacerts" style keystore.
1228 if (!allCerts) {
1229 weakWarnings.add(String.format(
1230 rb.getString("jks.storetype.warning"),
1231 realType, ksfname));
1232 }
1233 }
1234 if (inplaceImport) {
1235 String realSourceStoreType =
1236 keyStoreType(new File(inplaceBackupName));
1237 String format =
1238 realType.equalsIgnoreCase(realSourceStoreType) ?
1239 rb.getString("backup.keystore.warning") :
1240 rb.getString("migrate.keystore.warning");
1241 weakWarnings.add(
1242 String.format(format,
1243 srcksfname,
1244 realSourceStoreType,
1245 inplaceBackupName,
1246 realType));
1247 }
1248 }
1249 }
1250 }
1251
1252 private String keyStoreType(File f) throws IOException {
1253 int MAGIC = 0xfeedfeed;
1254 int JCEKS_MAGIC = 0xcececece;
1255 try (DataInputStream dis = new DataInputStream(
1256 new FileInputStream(f))) {
1257 int xMagic = dis.readInt();
1258 if (xMagic == MAGIC) {
1259 return "JKS";
1260 } else if (xMagic == JCEKS_MAGIC) {
1261 return "JCEKS";
1262 } else {
1263 return "Non JKS/JCEKS";
1264 }
1265 }
1266 }
1267
1268 /**
1269 * Generate a certificate: Read PKCS10 request from in, and print
1270 * certificate to out. Use alias as CA, sigAlgName as the signature
1271 * type.
1272 */
1273 private void doGenCert(String alias, String sigAlgName, InputStream in, PrintStream out)
1274 throws Exception {
1275
1276
1277 if (keyStore.containsAlias(alias) == false) {
1278 MessageFormat form = new MessageFormat
1279 (rb.getString("Alias.alias.does.not.exist"));
1280 Object[] source = {alias};
1281 throw new Exception(form.format(source));
1282 }
1283 Certificate signerCert = keyStore.getCertificate(alias);
1284 byte[] encoded = signerCert.getEncoded();
1285 X509CertImpl signerCertImpl = new X509CertImpl(encoded);
1286 X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get(
1287 X509CertImpl.NAME + "." + X509CertImpl.INFO);
1288 X500Name issuer = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." +
1289 X509CertInfo.DN_NAME);
1290
1291 Date firstDate = getStartDate(startDate);
1292 Date lastDate = new Date();
1293 lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L);
1294 CertificateValidity interval = new CertificateValidity(firstDate,
1295 lastDate);
1296
1297 PrivateKey privateKey =
1298 (PrivateKey)recoverKey(alias, storePass, keyPass).fst;
1299 if (sigAlgName == null) {
1300 sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm());
1301 }
1302 Signature signature = Signature.getInstance(sigAlgName);
1316 BufferedReader reader = new BufferedReader(new InputStreamReader(in));
1317 boolean canRead = false;
1318 StringBuffer sb = new StringBuffer();
1319 while (true) {
1320 String s = reader.readLine();
1321 if (s == null) break;
1322 // OpenSSL does not use NEW
1323 //if (s.startsWith("-----BEGIN NEW CERTIFICATE REQUEST-----")) {
1324 if (s.startsWith("-----BEGIN") && s.indexOf("REQUEST") >= 0) {
1325 canRead = true;
1326 //} else if (s.startsWith("-----END NEW CERTIFICATE REQUEST-----")) {
1327 } else if (s.startsWith("-----END") && s.indexOf("REQUEST") >= 0) {
1328 break;
1329 } else if (canRead) {
1330 sb.append(s);
1331 }
1332 }
1333 byte[] rawReq = Pem.decode(new String(sb));
1334 PKCS10 req = new PKCS10(rawReq);
1335
1336 checkWeak(rb.getString("the.certificate.request"), req);
1337
1338 info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo()));
1339 info.set(X509CertInfo.SUBJECT,
1340 dname==null?req.getSubjectName():new X500Name(dname));
1341 CertificateExtensions reqex = null;
1342 Iterator<PKCS10Attribute> attrs = req.getAttributes().getAttributes().iterator();
1343 while (attrs.hasNext()) {
1344 PKCS10Attribute attr = attrs.next();
1345 if (attr.getAttributeId().equals((Object)PKCS9Attribute.EXTENSION_REQUEST_OID)) {
1346 reqex = (CertificateExtensions)attr.getAttributeValue();
1347 }
1348 }
1349 CertificateExtensions ext = createV3Extensions(
1350 reqex,
1351 null,
1352 v3ext,
1353 req.getSubjectPublicKeyInfo(),
1354 signerCert.getPublicKey());
1355 info.set(X509CertInfo.EXTENSIONS, ext);
1356 X509CertImpl cert = new X509CertImpl(info);
1357 cert.sign(privateKey, sigAlgName);
1358 dumpCert(cert, out);
1359 for (Certificate ca: keyStore.getCertificateChain(alias)) {
1360 if (ca instanceof X509Certificate) {
1361 X509Certificate xca = (X509Certificate)ca;
1362 if (!isSelfSigned(xca)) {
1363 dumpCert(xca, out);
1364 }
1365 }
1366 }
1367
1368 checkWeak(rb.getString("the.issuer"), keyStore.getCertificateChain(alias));
1369 checkWeak(rb.getString("the.generated.certificate"), cert);
1370 }
1371
1372 private void doGenCRL(PrintStream out)
1373 throws Exception {
1374 if (ids == null) {
1375 throw new Exception("Must provide -id when -gencrl");
1376 }
1377 Certificate signerCert = keyStore.getCertificate(alias);
1378 byte[] encoded = signerCert.getEncoded();
1379 X509CertImpl signerCertImpl = new X509CertImpl(encoded);
1380 X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get(
1381 X509CertImpl.NAME + "." + X509CertImpl.INFO);
1382 X500Name owner = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." +
1383 X509CertInfo.DN_NAME);
1384
1385 Date firstDate = getStartDate(startDate);
1386 Date lastDate = (Date) firstDate.clone();
1387 lastDate.setTime(lastDate.getTime() + validity*1000*24*60*60);
1388 CertificateValidity interval = new CertificateValidity(firstDate,
1389 lastDate);
1400 String id = ids.get(i);
1401 int d = id.indexOf(':');
1402 if (d >= 0) {
1403 CRLExtensions ext = new CRLExtensions();
1404 ext.set("Reason", new CRLReasonCodeExtension(Integer.parseInt(id.substring(d+1))));
1405 badCerts[i] = new X509CRLEntryImpl(new BigInteger(id.substring(0, d)),
1406 firstDate, ext);
1407 } else {
1408 badCerts[i] = new X509CRLEntryImpl(new BigInteger(ids.get(i)), firstDate);
1409 }
1410 }
1411 X509CRLImpl crl = new X509CRLImpl(owner, firstDate, lastDate, badCerts);
1412 crl.sign(privateKey, sigAlgName);
1413 if (rfc) {
1414 out.println("-----BEGIN X509 CRL-----");
1415 out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(crl.getEncodedInternal()));
1416 out.println("-----END X509 CRL-----");
1417 } else {
1418 out.write(crl.getEncodedInternal());
1419 }
1420 checkWeak(rb.getString("the.generated.crl"), crl, privateKey);
1421 }
1422
1423 /**
1424 * Creates a PKCS#10 cert signing request, corresponding to the
1425 * keys (and name) associated with a given alias.
1426 */
1427 private void doCertReq(String alias, String sigAlgName, PrintStream out)
1428 throws Exception
1429 {
1430 if (alias == null) {
1431 alias = keyAlias;
1432 }
1433
1434 Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass);
1435 PrivateKey privKey = (PrivateKey)objs.fst;
1436 if (keyPass == null) {
1437 keyPass = objs.snd;
1438 }
1439
1440 Certificate cert = keyStore.getCertificate(alias);
1447 PKCS10 request = new PKCS10(cert.getPublicKey());
1448 CertificateExtensions ext = createV3Extensions(null, null, v3ext, cert.getPublicKey(), null);
1449 // Attribute name is not significant
1450 request.getAttributes().setAttribute(X509CertInfo.EXTENSIONS,
1451 new PKCS10Attribute(PKCS9Attribute.EXTENSION_REQUEST_OID, ext));
1452
1453 // Construct a Signature object, so that we can sign the request
1454 if (sigAlgName == null) {
1455 sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm());
1456 }
1457
1458 Signature signature = Signature.getInstance(sigAlgName);
1459 signature.initSign(privKey);
1460 X500Name subject = dname == null?
1461 new X500Name(((X509Certificate)cert).getSubjectDN().toString()):
1462 new X500Name(dname);
1463
1464 // Sign the request and base-64 encode it
1465 request.encodeAndSign(subject, signature);
1466 request.print(out);
1467
1468 checkWeak(rb.getString("the.generated.certificate.request"), request);
1469 }
1470
1471 /**
1472 * Deletes an entry from the keystore.
1473 */
1474 private void doDeleteEntry(String alias) throws Exception {
1475 if (keyStore.containsAlias(alias) == false) {
1476 MessageFormat form = new MessageFormat
1477 (rb.getString("Alias.alias.does.not.exist"));
1478 Object[] source = {alias};
1479 throw new Exception(form.format(source));
1480 }
1481 keyStore.deleteEntry(alias);
1482 }
1483
1484 /**
1485 * Exports a certificate from the keystore.
1486 */
1487 private void doExportCert(String alias, PrintStream out)
1488 throws Exception
1489 {
1490 if (storePass == null
1491 && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
1492 printNoIntegrityWarning();
1493 }
1494 if (alias == null) {
1495 alias = keyAlias;
1496 }
1497 if (keyStore.containsAlias(alias) == false) {
1498 MessageFormat form = new MessageFormat
1499 (rb.getString("Alias.alias.does.not.exist"));
1500 Object[] source = {alias};
1501 throw new Exception(form.format(source));
1502 }
1503
1504 X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias);
1505 if (cert == null) {
1506 MessageFormat form = new MessageFormat
1507 (rb.getString("Alias.alias.has.no.certificate"));
1508 Object[] source = {alias};
1509 throw new Exception(form.format(source));
1510 }
1511 dumpCert(cert, out);
1512 checkWeak(rb.getString("the.certificate"), cert);
1513 }
1514
1515 /**
1516 * Prompt the user for a keypass when generating a key entry.
1517 * @param alias the entry we will set password for
1518 * @param orig the original entry of doing a dup, null if generate new
1519 * @param origPass the password to copy from if user press ENTER
1520 */
1521 private char[] promptForKeyPass(String alias, String orig, char[] origPass) throws Exception{
1522 if (P12KEYSTORE.equalsIgnoreCase(storetype)) {
1523 return origPass;
1524 } else if (!token && !protectedPath) {
1525 // Prompt for key password
1526 int count;
1527 for (count = 0; count < 3; count++) {
1528 MessageFormat form = new MessageFormat(rb.getString
1529 ("Enter.key.password.for.alias."));
1530 Object[] source = {alias};
1531 System.err.println(form.format(source));
1532 if (orig == null) {
1673
1674 if (keyPass == null) {
1675 keyPass = promptForKeyPass(alias, null, storePass);
1676 }
1677
1678 if (useDefaultPBEAlgorithm) {
1679 keyStore.setKeyEntry(alias, secKey, keyPass, null);
1680 } else {
1681 keyStore.setEntry(alias, new KeyStore.SecretKeyEntry(secKey),
1682 new KeyStore.PasswordProtection(keyPass, keyAlgName, null));
1683 }
1684 }
1685
1686 /**
1687 * If no signature algorithm was specified at the command line,
1688 * we choose one that is compatible with the selected private key
1689 */
1690 private static String getCompatibleSigAlgName(String keyAlgName)
1691 throws Exception {
1692 if ("DSA".equalsIgnoreCase(keyAlgName)) {
1693 return "SHA256WithDSA";
1694 } else if ("RSA".equalsIgnoreCase(keyAlgName)) {
1695 return "SHA256WithRSA";
1696 } else if ("EC".equalsIgnoreCase(keyAlgName)) {
1697 return "SHA256withECDSA";
1698 } else {
1699 throw new Exception(rb.getString
1700 ("Cannot.derive.signature.algorithm"));
1701 }
1702 }
1703 /**
1704 * Creates a new key pair and self-signed certificate.
1705 */
1706 private void doGenKeyPair(String alias, String dname, String keyAlgName,
1707 int keysize, String sigAlgName)
1708 throws Exception
1709 {
1710 if (keysize == -1) {
1711 if ("EC".equalsIgnoreCase(keyAlgName)) {
1712 keysize = SecurityProviderConstants.DEF_EC_KEY_SIZE;
1713 } else if ("RSA".equalsIgnoreCase(keyAlgName)) {
1714 // hardcode for now as DEF_RSA_KEY_SIZE is still 1024
1715 keysize = 2048; // SecurityProviderConstants.DEF_RSA_KEY_SIZE;
1716 } else if ("DSA".equalsIgnoreCase(keyAlgName)) {
1717 // hardcode for now as DEF_DSA_KEY_SIZE is still 1024
1718 keysize = 2048;
1719 }
1720 }
1721
1722 if (alias == null) {
1723 alias = keyAlias;
1724 }
1725
1726 if (keyStore.containsAlias(alias)) {
1727 MessageFormat form = new MessageFormat(rb.getString
1728 ("Key.pair.not.generated.alias.alias.already.exists"));
1729 Object[] source = {alias};
1730 throw new Exception(form.format(source));
1731 }
1732
1733 if (sigAlgName == null) {
1734 sigAlgName = getCompatibleSigAlgName(keyAlgName);
1735 }
1736 CertAndKeyGen keypair =
1737 new CertAndKeyGen(keyAlgName, sigAlgName, providerName);
1738
1756 null);
1757
1758 X509Certificate[] chain = new X509Certificate[1];
1759 chain[0] = keypair.getSelfCertificate(
1760 x500Name, getStartDate(startDate), validity*24L*60L*60L, ext);
1761
1762 if (verbose) {
1763 MessageFormat form = new MessageFormat(rb.getString
1764 ("Generating.keysize.bit.keyAlgName.key.pair.and.self.signed.certificate.sigAlgName.with.a.validity.of.validality.days.for"));
1765 Object[] source = {new Integer(keysize),
1766 privKey.getAlgorithm(),
1767 chain[0].getSigAlgName(),
1768 new Long(validity),
1769 x500Name};
1770 System.err.println(form.format(source));
1771 }
1772
1773 if (keyPass == null) {
1774 keyPass = promptForKeyPass(alias, null, storePass);
1775 }
1776 checkWeak(rb.getString("the.generated.certificate"), chain[0]);
1777 keyStore.setKeyEntry(alias, privKey, keyPass, chain);
1778 }
1779
1780 /**
1781 * Clones an entry
1782 * @param orig original alias
1783 * @param dest destination alias
1784 * @changePassword if the password can be changed
1785 */
1786 private void doCloneEntry(String orig, String dest, boolean changePassword)
1787 throws Exception
1788 {
1789 if (orig == null) {
1790 orig = keyAlias;
1791 }
1792
1793 if (keyStore.containsAlias(dest)) {
1794 MessageFormat form = new MessageFormat
1795 (rb.getString("Destination.alias.dest.already.exists"));
1796 Object[] source = {dest};
1839 }
1840 keyStore.setKeyEntry(alias, privKey, keyPassNew,
1841 keyStore.getCertificateChain(alias));
1842 }
1843
1844 /**
1845 * Imports a JDK 1.1-style identity database. We can only store one
1846 * certificate per identity, because we use the identity's name as the
1847 * alias (which references a keystore entry), and aliases must be unique.
1848 */
1849 private void doImportIdentityDatabase(InputStream in)
1850 throws Exception
1851 {
1852 System.err.println(rb.getString
1853 ("No.entries.from.identity.database.added"));
1854 }
1855
1856 /**
1857 * Prints a single keystore entry.
1858 */
1859 private void doPrintEntry(String label, String alias, PrintStream out)
1860 throws Exception
1861 {
1862 if (keyStore.containsAlias(alias) == false) {
1863 MessageFormat form = new MessageFormat
1864 (rb.getString("Alias.alias.does.not.exist"));
1865 Object[] source = {alias};
1866 throw new Exception(form.format(source));
1867 }
1868
1869 if (verbose || rfc || debug) {
1870 MessageFormat form = new MessageFormat
1871 (rb.getString("Alias.name.alias"));
1872 Object[] source = {alias};
1873 out.println(form.format(source));
1874
1875 if (!token) {
1876 form = new MessageFormat(rb.getString
1877 ("Creation.date.keyStore.getCreationDate.alias."));
1878 Object[] src = {keyStore.getCreationDate(alias)};
1879 out.println(form.format(src));
1880 }
1881 } else {
1910 }
1911
1912 // Get the chain
1913 Certificate[] chain = keyStore.getCertificateChain(alias);
1914 if (chain != null) {
1915 if (verbose || rfc || debug) {
1916 out.println(rb.getString
1917 ("Certificate.chain.length.") + chain.length);
1918 for (int i = 0; i < chain.length; i ++) {
1919 MessageFormat form = new MessageFormat
1920 (rb.getString("Certificate.i.1."));
1921 Object[] source = {new Integer((i + 1))};
1922 out.println(form.format(source));
1923 if (verbose && (chain[i] instanceof X509Certificate)) {
1924 printX509Cert((X509Certificate)(chain[i]), out);
1925 } else if (debug) {
1926 out.println(chain[i].toString());
1927 } else {
1928 dumpCert(chain[i], out);
1929 }
1930 checkWeak(label, chain[i]);
1931 }
1932 } else {
1933 // Print the digest of the user cert only
1934 out.println
1935 (rb.getString("Certificate.fingerprint.SHA1.") +
1936 getCertFingerPrint("SHA1", chain[0]));
1937 checkWeak(label, chain[0]);
1938 }
1939 }
1940 } else if (keyStore.entryInstanceOf(alias,
1941 KeyStore.TrustedCertificateEntry.class)) {
1942 // We have a trusted certificate entry
1943 Certificate cert = keyStore.getCertificate(alias);
1944 Object[] source = {"trustedCertEntry"};
1945 String mf = new MessageFormat(
1946 rb.getString("Entry.type.type.")).format(source) + "\n";
1947 if (verbose && (cert instanceof X509Certificate)) {
1948 out.println(mf);
1949 printX509Cert((X509Certificate)cert, out);
1950 } else if (rfc) {
1951 out.println(mf);
1952 dumpCert(cert, out);
1953 } else if (debug) {
1954 out.println(cert.toString());
1955 } else {
1956 out.println("trustedCertEntry, ");
1957 out.println(rb.getString("Certificate.fingerprint.SHA1.")
1958 + getCertFingerPrint("SHA1", cert));
1959 }
1960 checkWeak(label, cert);
1961 } else {
1962 out.println(rb.getString("Unknown.Entry.Type"));
1963 }
1964 }
1965
1966 boolean inplaceImportCheck() throws Exception {
1967 if (P11KEYSTORE.equalsIgnoreCase(srcstoretype) ||
1968 KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
1969 return false;
1970 }
1971
1972 if (srcksfname != null) {
1973 File srcksfile = new File(srcksfname);
1974 if (srcksfile.exists() && srcksfile.length() == 0) {
1975 throw new Exception(rb.getString
1976 ("Source.keystore.file.exists.but.is.empty.") +
1977 srcksfname);
1978 }
1979 if (srcksfile.getCanonicalFile()
1980 .equals(new File(ksfname).getCanonicalFile())) {
1981 return true;
1982 } else {
1983 // Informational, especially if destkeystore is not
1984 // provided, which default to ~/.keystore.
1985 System.err.println(String.format(rb.getString(
1986 "importing.keystore.status"), srcksfname, ksfname));
1987 return false;
1988 }
1989 } else {
1990 throw new Exception(rb.getString
1991 ("Please.specify.srckeystore"));
1992 }
1993 }
1994
1995 /**
1996 * Load the srckeystore from a stream, used in -importkeystore
1997 * @returns the src KeyStore
1998 */
1999 KeyStore loadSourceKeyStore() throws Exception {
2000
2001 InputStream is = null;
2002 File srcksfile = null;
2003
2004 if (P11KEYSTORE.equalsIgnoreCase(srcstoretype) ||
2005 KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
2006 if (!NONE.equals(srcksfname)) {
2007 System.err.println(MessageFormat.format(rb.getString
2008 (".keystore.must.be.NONE.if.storetype.is.{0}"), srcstoretype));
2009 System.err.println();
2010 tinyHelp();
2011 }
2012 } else {
2013 srcksfile = new File(srcksfname);
2014 is = new FileInputStream(srcksfile);
2015 }
2016
2017 KeyStore store;
2018 try {
2019 if (srcProviderName == null) {
2020 store = KeyStore.getInstance(srcstoretype);
2021 } else {
2022 store = KeyStore.getInstance(srcstoretype, srcProviderName);
2023 }
2024
2025 if (srcstorePass == null
2026 && !srcprotectedPath
2027 && !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
2028 System.err.print(rb.getString("Enter.source.keystore.password."));
2029 System.err.flush();
2030 srcstorePass = Password.readPassword(System.in);
2031 passwords.add(srcstorePass);
2032 }
2033
2034 // always let keypass be storepass when using pkcs12
2035 if (P12KEYSTORE.equalsIgnoreCase(srcstoretype)) {
2036 if (srckeyPass != null && srcstorePass != null &&
2037 !Arrays.equals(srcstorePass, srckeyPass)) {
2038 MessageFormat form = new MessageFormat(rb.getString(
2039 "Warning.Different.store.and.key.passwords.not.supported.for.PKCS12.KeyStores.Ignoring.user.specified.command.value."));
2040 Object[] source = {"-srckeypass"};
2041 System.err.println(form.format(source));
2042 srckeyPass = srcstorePass;
2043 }
2044 }
2045
2046 store.load(is, srcstorePass); // "is" already null in PKCS11
2047 } finally {
2048 if (is != null) {
2049 is.close();
2050 }
2051 }
2052
2053 if (srcstorePass == null
2054 && !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
2055 // anti refactoring, copied from printNoIntegrityWarning(),
2056 // but change 2 lines
2057 System.err.println();
2058 System.err.println(rb.getString
2059 (".WARNING.WARNING.WARNING."));
2060 System.err.println(rb.getString
2061 (".The.integrity.of.the.information.stored.in.the.srckeystore."));
2062 System.err.println(rb.getString
2063 (".WARNING.WARNING.WARNING."));
2064 System.err.println();
2065 }
2066
2067 return store;
2068 }
2069
2070 /**
2071 * import all keys and certs from importkeystore.
2072 * keep alias unchanged if no name conflict, otherwise, prompt.
2073 * keep keypass unchanged for keys
2074 */
2075 private void doImportKeyStore(KeyStore srcKS) throws Exception {
2076
2077 if (alias != null) {
2078 doImportKeyStoreSingle(srcKS, alias);
2079 } else {
2080 if (dest != null || srckeyPass != null) {
2081 throw new Exception(rb.getString(
2082 "if.alias.not.specified.destalias.and.srckeypass.must.not.be.specified"));
2083 }
2084 doImportKeyStoreAll(srcKS);
2085 }
2086
2087 if (inplaceImport) {
2088 // Backup to file.old or file.old2...
2089 // The keystore is not rewritten yet now.
2090 for (int n = 1; /* forever */; n++) {
2091 inplaceBackupName = srcksfname + ".old" + (n == 1 ? "" : n);
2092 File bkFile = new File(inplaceBackupName);
2093 if (!bkFile.exists()) {
2094 Files.copy(Paths.get(srcksfname), bkFile.toPath());
2095 break;
2096 }
2097 }
2098
2099 }
2100
2101 /*
2102 * Information display rule of -importkeystore
2103 * 1. inside single, shows failure
2104 * 2. inside all, shows sucess
2105 * 3. inside all where there is a failure, prompt for continue
2106 * 4. at the final of all, shows summary
2107 */
2108 }
2109
2110 /**
2111 * Import a single entry named alias from srckeystore
2112 * @returns 1 if the import action succeed
2113 * 0 if user choose to ignore an alias-dumplicated entry
2114 * 2 if setEntry throws Exception
2115 */
2116 private int doImportKeyStoreSingle(KeyStore srckeystore, String alias)
2117 throws Exception {
2118
2119 String newAlias = (dest==null) ? alias : dest;
2120
2141
2142 Pair<Entry,char[]> objs = recoverEntry(srckeystore, alias, srcstorePass, srckeyPass);
2143 Entry entry = objs.fst;
2144
2145 PasswordProtection pp = null;
2146
2147 // According to keytool.html, "The destination entry will be protected
2148 // using destkeypass. If destkeypass is not provided, the destination
2149 // entry will be protected with the source entry password."
2150 // so always try to protect with destKeyPass.
2151 char[] newPass = null;
2152 if (destKeyPass != null) {
2153 newPass = destKeyPass;
2154 pp = new PasswordProtection(destKeyPass);
2155 } else if (objs.snd != null) {
2156 newPass = objs.snd;
2157 pp = new PasswordProtection(objs.snd);
2158 }
2159
2160 try {
2161 Certificate c = srckeystore.getCertificate(alias);
2162 if (c != null) {
2163 checkWeak("<" + newAlias + ">", c);
2164 }
2165 keyStore.setEntry(newAlias, entry, pp);
2166 // Place the check so that only successful imports are blocked.
2167 // For example, we don't block a failed SecretEntry import.
2168 if (P12KEYSTORE.equalsIgnoreCase(storetype)) {
2169 if (newPass != null && !Arrays.equals(newPass, storePass)) {
2170 throw new Exception(rb.getString(
2171 "The.destination.pkcs12.keystore.has.different.storepass.and.keypass.Please.retry.with.destkeypass.specified."));
2172 }
2173 }
2174 return 1;
2175 } catch (KeyStoreException kse) {
2176 Object[] source2 = {alias, kse.toString()};
2177 MessageFormat form = new MessageFormat(rb.getString(
2178 "Problem.importing.entry.for.alias.alias.exception.Entry.for.alias.alias.not.imported."));
2179 System.err.println(form.format(source2));
2180 return 2;
2181 }
2182 }
2183
2184 private void doImportKeyStoreAll(KeyStore srckeystore) throws Exception {
2198 if (!noprompt) {
2199 String reply = getYesNoReply("Do you want to quit the import process? [no]: ");
2200 if ("YES".equals(reply)) {
2201 break;
2202 }
2203 }
2204 }
2205 }
2206 Object[] source = {ok, count-ok};
2207 MessageFormat form = new MessageFormat(rb.getString(
2208 "Import.command.completed.ok.entries.successfully.imported.fail.entries.failed.or.cancelled"));
2209 System.err.println(form.format(source));
2210 }
2211
2212 /**
2213 * Prints all keystore entries.
2214 */
2215 private void doPrintEntries(PrintStream out)
2216 throws Exception
2217 {
2218 out.println(rb.getString("Keystore.type.") + keyStore.getType());
2219 out.println(rb.getString("Keystore.provider.") +
2220 keyStore.getProvider().getName());
2221 out.println();
2222
2223 MessageFormat form;
2224 form = (keyStore.size() == 1) ?
2225 new MessageFormat(rb.getString
2226 ("Your.keystore.contains.keyStore.size.entry")) :
2227 new MessageFormat(rb.getString
2228 ("Your.keystore.contains.keyStore.size.entries"));
2229 Object[] source = {new Integer(keyStore.size())};
2230 out.println(form.format(source));
2231 out.println();
2232
2233 for (Enumeration<String> e = keyStore.aliases();
2234 e.hasMoreElements(); ) {
2235 String alias = e.nextElement();
2236 doPrintEntry("<" + alias + ">", alias, out);
2237 if (verbose || rfc) {
2238 out.println(rb.getString("NEWLINE"));
2239 out.println(rb.getString
2240 ("STAR"));
2241 out.println(rb.getString
2242 ("STARNN"));
2243 }
2244 }
2245 }
2246
2247 private static <T> Iterable<T> e2i(final Enumeration<T> e) {
2248 return new Iterable<T>() {
2249 @Override
2250 public Iterator<T> iterator() {
2251 return new Iterator<T>() {
2252 @Override
2253 public boolean hasNext() {
2254 return e.hasMoreElements();
2255 }
2256 @Override
2366 Certificate cert = ks.getCertificate(s);
2367 if (cert instanceof X509Certificate) {
2368 X509Certificate xcert = (X509Certificate)cert;
2369 if (xcert.getSubjectX500Principal().equals(issuer)) {
2370 try {
2371 ((X509CRLImpl)crl).verify(cert.getPublicKey());
2372 return s;
2373 } catch (Exception e) {
2374 }
2375 }
2376 }
2377 }
2378 return null;
2379 }
2380
2381 private void doPrintCRL(String src, PrintStream out)
2382 throws Exception {
2383 for (CRL crl: loadCRLs(src)) {
2384 printCRL(crl, out);
2385 String issuer = null;
2386 Certificate signer = null;
2387 if (caks != null) {
2388 issuer = verifyCRL(caks, crl);
2389 if (issuer != null) {
2390 signer = caks.getCertificate(issuer);
2391 out.printf(rb.getString(
2392 "verified.by.s.in.s.weak"),
2393 issuer,
2394 "cacerts",
2395 withWeak(signer.getPublicKey()));
2396 out.println();
2397 }
2398 }
2399 if (issuer == null && keyStore != null) {
2400 issuer = verifyCRL(keyStore, crl);
2401 if (issuer != null) {
2402 signer = keyStore.getCertificate(issuer);
2403 out.printf(rb.getString(
2404 "verified.by.s.in.s.weak"),
2405 issuer,
2406 "keystore",
2407 withWeak(signer.getPublicKey()));
2408 out.println();
2409 }
2410 }
2411 if (issuer == null) {
2412 out.println(rb.getString
2413 ("STAR"));
2414 out.println(rb.getString
2415 ("warning.not.verified.make.sure.keystore.is.correct"));
2416 out.println(rb.getString
2417 ("STARNN"));
2418 }
2419 checkWeak(rb.getString("the.crl"), crl, signer == null ? null : signer.getPublicKey());
2420 }
2421 }
2422
2423 private void printCRL(CRL crl, PrintStream out)
2424 throws Exception {
2425 X509CRL xcrl = (X509CRL)crl;
2426 if (rfc) {
2427 out.println("-----BEGIN X509 CRL-----");
2428 out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(xcrl.getEncoded()));
2429 out.println("-----END X509 CRL-----");
2430 } else {
2431 String s;
2432 if (crl instanceof X509CRLImpl) {
2433 X509CRLImpl x509crl = (X509CRLImpl) crl;
2434 s = x509crl.toStringWithAlgName(withWeak("" + x509crl.getSigAlgId()));
2435 } else {
2436 s = crl.toString();
2437 }
2438 out.println(s);
2439 }
2440 }
2441
2442 private void doPrintCertReq(InputStream in, PrintStream out)
2443 throws Exception {
2444
2445 BufferedReader reader = new BufferedReader(new InputStreamReader(in));
2446 StringBuffer sb = new StringBuffer();
2447 boolean started = false;
2448 while (true) {
2449 String s = reader.readLine();
2450 if (s == null) break;
2451 if (!started) {
2452 if (s.startsWith("-----")) {
2453 started = true;
2454 }
2455 } else {
2456 if (s.startsWith("-----")) {
2457 break;
2458 }
2459 sb.append(s);
2460 }
2461 }
2462 PKCS10 req = new PKCS10(Pem.decode(new String(sb)));
2463
2464 PublicKey pkey = req.getSubjectPublicKeyInfo();
2465 out.printf(rb.getString("PKCS.10.with.weak"),
2466 req.getSubjectName(),
2467 pkey.getFormat(),
2468 withWeak(pkey),
2469 withWeak(req.getSigAlg()));
2470 for (PKCS10Attribute attr: req.getAttributes().getAttributes()) {
2471 ObjectIdentifier oid = attr.getAttributeId();
2472 if (oid.equals((Object)PKCS9Attribute.EXTENSION_REQUEST_OID)) {
2473 CertificateExtensions exts = (CertificateExtensions)attr.getAttributeValue();
2474 if (exts != null) {
2475 printExtensions(rb.getString("Extension.Request."), exts, out);
2476 }
2477 } else {
2478 out.println("Attribute: " + attr.getAttributeId());
2479 PKCS9Attribute pkcs9Attr =
2480 new PKCS9Attribute(attr.getAttributeId(),
2481 attr.getAttributeValue());
2482 out.print(pkcs9Attr.getName() + ": ");
2483 Object attrVal = attr.getAttributeValue();
2484 out.println(attrVal instanceof String[] ?
2485 Arrays.toString((String[]) attrVal) :
2486 attrVal);
2487 }
2488 }
2489 if (debug) {
2490 out.println(req); // Just to see more, say, public key length...
2491 }
2492 checkWeak(rb.getString("the.certificate.request"), req);
2493 }
2494
2495 /**
2496 * Reads a certificate (or certificate chain) and prints its contents in
2497 * a human readable format.
2498 */
2499 private void printCertFromStream(InputStream in, PrintStream out)
2500 throws Exception
2501 {
2502 Collection<? extends Certificate> c = null;
2503 try {
2504 c = cf.generateCertificates(in);
2505 } catch (CertificateException ce) {
2506 throw new Exception(rb.getString("Failed.to.parse.input"), ce);
2507 }
2508 if (c.isEmpty()) {
2509 throw new Exception(rb.getString("Empty.input"));
2510 }
2511 Certificate[] certs = c.toArray(new Certificate[c.size()]);
2512 for (int i=0; i<certs.length; i++) {
2513 X509Certificate x509Cert = null;
2514 try {
2515 x509Cert = (X509Certificate)certs[i];
2516 } catch (ClassCastException cce) {
2517 throw new Exception(rb.getString("Not.X.509.certificate"));
2518 }
2519 if (certs.length > 1) {
2520 MessageFormat form = new MessageFormat
2521 (rb.getString("Certificate.i.1."));
2522 Object[] source = {new Integer(i + 1)};
2523 out.println(form.format(source));
2524 }
2525 if (rfc)
2526 dumpCert(x509Cert, out);
2527 else
2528 printX509Cert(x509Cert, out);
2529 if (i < (certs.length-1)) {
2530 out.println();
2531 }
2532 checkWeak(oneInMany(rb.getString("the.certificate"), i, certs.length), x509Cert);
2533 }
2534 }
2535
2536 private static String oneInMany(String label, int i, int num) {
2537 if (num == 1) {
2538 return label;
2539 } else {
2540 return String.format(rb.getString("one.in.many"), label, i+1, num);
2541 }
2542 }
2543
2544 private void doPrintCert(final PrintStream out) throws Exception {
2545 if (jarfile != null) {
2546 JarFile jf = new JarFile(jarfile, true);
2547 Enumeration<JarEntry> entries = jf.entries();
2548 Set<CodeSigner> ss = new HashSet<>();
2549 byte[] buffer = new byte[8192];
2550 int pos = 0;
2551 while (entries.hasMoreElements()) {
2552 JarEntry je = entries.nextElement();
2553 try (InputStream is = jf.getInputStream(je)) {
2554 while (is.read(buffer) != -1) {
2555 // we just read. this will throw a SecurityException
2556 // if a signature/digest check fails. This also
2557 // populate the signers
2558 }
2559 }
2560 CodeSigner[] signers = je.getCodeSigners();
2561 if (signers != null) {
2562 for (CodeSigner signer: signers) {
2563 if (!ss.contains(signer)) {
2564 ss.add(signer);
2565 out.printf(rb.getString("Signer.d."), ++pos);
2566 out.println();
2567 out.println();
2568 out.println(rb.getString("Signature."));
2569 out.println();
2570
2571 List<? extends Certificate> certs
2572 = signer.getSignerCertPath().getCertificates();
2573 int cc = 0;
2574 for (Certificate cert: certs) {
2575 X509Certificate x = (X509Certificate)cert;
2576 if (rfc) {
2577 out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n");
2578 dumpCert(x, out);
2579 } else {
2580 printX509Cert(x, out);
2581 }
2582 out.println();
2583 checkWeak(oneInMany(rb.getString("the.certificate"), cc++, certs.size()), x);
2584 }
2585 Timestamp ts = signer.getTimestamp();
2586 if (ts != null) {
2587 out.println(rb.getString("Timestamp."));
2588 out.println();
2589 certs = ts.getSignerCertPath().getCertificates();
2590 cc = 0;
2591 for (Certificate cert: certs) {
2592 X509Certificate x = (X509Certificate)cert;
2593 if (rfc) {
2594 out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n");
2595 dumpCert(x, out);
2596 } else {
2597 printX509Cert(x, out);
2598 }
2599 out.println();
2600 checkWeak(oneInMany(rb.getString("the.tsa.certificate"), cc++, certs.size()), x);
2601 }
2602 }
2603 }
2604 }
2605 }
2606 }
2607 jf.close();
2608 if (ss.isEmpty()) {
2609 out.println(rb.getString("Not.a.signed.jar.file"));
2610 }
2611 } else if (sslserver != null) {
2612 // Lazily load SSLCertStoreHelper if present
2613 CertStoreHelper helper = CertStoreHelper.getInstance("SSLServer");
2614 CertStore cs = helper.getCertStore(new URI("https://" + sslserver));
2615 Collection<? extends Certificate> chain;
2616 try {
2617 chain = cs.getCertificates(null);
2618 if (chain.isEmpty()) {
2619 // If the certs are not retrieved, we consider it an error
2620 // even if the URL connection is successful.
2625 if (cse.getCause() instanceof IOException) {
2626 throw new Exception(rb.getString(
2627 "No.certificate.from.the.SSL.server"),
2628 cse.getCause());
2629 } else {
2630 throw cse;
2631 }
2632 }
2633
2634 int i = 0;
2635 for (Certificate cert : chain) {
2636 try {
2637 if (rfc) {
2638 dumpCert(cert, out);
2639 } else {
2640 out.println("Certificate #" + i++);
2641 out.println("====================================");
2642 printX509Cert((X509Certificate)cert, out);
2643 out.println();
2644 }
2645 checkWeak(oneInMany(rb.getString("the.certificate"), i, chain.size()), cert);
2646 } catch (Exception e) {
2647 if (debug) {
2648 e.printStackTrace();
2649 }
2650 }
2651 }
2652 } else {
2653 if (filename != null) {
2654 try (FileInputStream inStream = new FileInputStream(filename)) {
2655 printCertFromStream(inStream, out);
2656 }
2657 } else {
2658 printCertFromStream(System.in, out);
2659 }
2660 }
2661 }
2662 /**
2663 * Creates a self-signed certificate, and stores it as a single-element
2664 * certificate chain.
2665 */
2801 Object[] source = {alias};
2802 throw new Exception(form.format(source));
2803 }
2804
2805 // Read the certificates in the reply
2806 Collection<? extends Certificate> c = cf.generateCertificates(in);
2807 if (c.isEmpty()) {
2808 throw new Exception(rb.getString("Reply.has.no.certificates"));
2809 }
2810 Certificate[] replyCerts = c.toArray(new Certificate[c.size()]);
2811 Certificate[] newChain;
2812 if (replyCerts.length == 1) {
2813 // single-cert reply
2814 newChain = establishCertChain(userCert, replyCerts[0]);
2815 } else {
2816 // cert-chain reply (e.g., PKCS#7)
2817 newChain = validateReply(alias, userCert, replyCerts);
2818 }
2819
2820 // Now store the newly established chain in the keystore. The new
2821 // chain replaces the old one. The chain can be null if user chooses no.
2822 if (newChain != null) {
2823 keyStore.setKeyEntry(alias, privKey,
2824 (keyPass != null) ? keyPass : storePass,
2825 newChain);
2826 return true;
2827 } else {
2828 return false;
2829 }
2830 }
2831
2832 /**
2833 * Imports a certificate and adds it to the list of trusted certificates.
2834 *
2835 * @return true if the certificate was added, otherwise false.
2836 */
2837 private boolean addTrustedCert(String alias, InputStream in)
2838 throws Exception
2839 {
2840 if (alias == null) {
2841 throw new Exception(rb.getString("Must.specify.alias"));
2842 }
2843 if (keyStore.containsAlias(alias)) {
2844 MessageFormat form = new MessageFormat(rb.getString
2845 ("Certificate.not.imported.alias.alias.already.exists"));
2846 Object[] source = {alias};
2847 throw new Exception(form.format(source));
2848 }
2849
2850 // Read the certificate
2851 X509Certificate cert = null;
2852 try {
2853 cert = (X509Certificate)cf.generateCertificate(in);
2854 } catch (ClassCastException | CertificateException ce) {
2855 throw new Exception(rb.getString("Input.not.an.X.509.certificate"));
2856 }
2857
2858 if (noprompt) {
2859 checkWeak(rb.getString("the.input"), cert);
2860 keyStore.setCertificateEntry(alias, cert);
2861 return true;
2862 }
2863
2864 // if certificate is self-signed, make sure it verifies
2865 boolean selfSigned = false;
2866 if (isSelfSigned(cert)) {
2867 cert.verify(cert.getPublicKey());
2868 selfSigned = true;
2869 }
2870
2871 // check if cert already exists in keystore
2872 String reply = null;
2873 String trustalias = keyStore.getCertificateAlias(cert);
2874 if (trustalias != null) {
2875 MessageFormat form = new MessageFormat(rb.getString
2876 ("Certificate.already.exists.in.keystore.under.alias.trustalias."));
2877 Object[] source = {trustalias};
2878 System.err.println(form.format(source));
2879 checkWeak(rb.getString("the.input"), cert);
2880 printWeakWarnings(true);
2881 reply = getYesNoReply
2882 (rb.getString("Do.you.still.want.to.add.it.no."));
2883 } else if (selfSigned) {
2884 if (trustcacerts && (caks != null) &&
2885 ((trustalias=caks.getCertificateAlias(cert)) != null)) {
2886 MessageFormat form = new MessageFormat(rb.getString
2887 ("Certificate.already.exists.in.system.wide.CA.keystore.under.alias.trustalias."));
2888 Object[] source = {trustalias};
2889 System.err.println(form.format(source));
2890 checkWeak(rb.getString("the.input"), cert);
2891 printWeakWarnings(true);
2892 reply = getYesNoReply
2893 (rb.getString("Do.you.still.want.to.add.it.to.your.own.keystore.no."));
2894 }
2895 if (trustalias == null) {
2896 // Print the cert and ask user if they really want to add
2897 // it to their keystore
2898 printX509Cert(cert, System.out);
2899 checkWeak(rb.getString("the.input"), cert);
2900 printWeakWarnings(true);
2901 reply = getYesNoReply
2902 (rb.getString("Trust.this.certificate.no."));
2903 }
2904 }
2905 if (reply != null) {
2906 if ("YES".equals(reply)) {
2907 keyStore.setCertificateEntry(alias, cert);
2908 return true;
2909 } else {
2910 return false;
2911 }
2912 }
2913
2914 // Not found in this keystore and not self-signed
2915 // Try to establish trust chain
2916 try {
2917 Certificate[] chain = establishCertChain(null, cert);
2918 if (chain != null) {
2919 keyStore.setCertificateEntry(alias, cert);
2920 return true;
2921 }
2922 } catch (Exception e) {
2923 // Print the cert and ask user if they really want to add it to
2924 // their keystore
2925 printX509Cert(cert, System.out);
2926 checkWeak(rb.getString("the.input"), cert);
2927 printWeakWarnings(true);
2928 reply = getYesNoReply
2929 (rb.getString("Trust.this.certificate.no."));
2930 if ("YES".equals(reply)) {
2931 keyStore.setCertificateEntry(alias, cert);
2932 return true;
2933 } else {
2934 return false;
2935 }
2936 }
2937
2938 return false;
2939 }
2940
2941 /**
2942 * Prompts user for new password. New password must be different from
2943 * old one.
2944 *
2945 * @param prompt the message that gets prompted on the screen
2946 * @param oldPasswd the current (i.e., old) password
2947 */
3046 ("Enter.key.password.for.alias."));
3047 Object[] source = {alias};
3048 System.err.print(form.format(source));
3049 }
3050 System.err.flush();
3051 keyPass = Password.readPassword(System.in);
3052 passwords.add(keyPass);
3053 if (keyPass == null) {
3054 keyPass = otherKeyPass;
3055 }
3056 count++;
3057 } while ((keyPass == null) && count < 3);
3058
3059 if (keyPass == null) {
3060 throw new Exception(rb.getString("Too.many.failures.try.later"));
3061 }
3062
3063 return keyPass;
3064 }
3065
3066 private String withWeak(String alg) {
3067 if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) {
3068 return alg;
3069 } else {
3070 return String.format(rb.getString("with.weak"), alg);
3071 }
3072 }
3073
3074 private String withWeak(PublicKey key) {
3075 if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
3076 return String.format(rb.getString("key.bit"),
3077 KeyUtil.getKeySize(key), key.getAlgorithm());
3078 } else {
3079 return String.format(rb.getString("key.bit.weak"),
3080 KeyUtil.getKeySize(key), key.getAlgorithm());
3081 }
3082 }
3083
3084 /**
3085 * Prints a certificate in a human readable format.
3086 */
3087 private void printX509Cert(X509Certificate cert, PrintStream out)
3088 throws Exception
3089 {
3090 /*
3091 out.println("Owner: "
3092 + cert.getSubjectDN().toString()
3093 + "\n"
3094 + "Issuer: "
3095 + cert.getIssuerDN().toString()
3096 + "\n"
3097 + "Serial number: " + cert.getSerialNumber().toString(16)
3098 + "\n"
3099 + "Valid from: " + cert.getNotBefore().toString()
3100 + " until: " + cert.getNotAfter().toString()
3101 + "\n"
3102 + "Certificate fingerprints:\n"
3103 + "\t MD5: " + getCertFingerPrint("MD5", cert)
3104 + "\n"
3105 + "\t SHA1: " + getCertFingerPrint("SHA1", cert));
3106 */
3107
3108 MessageFormat form = new MessageFormat
3109 (rb.getString(".PATTERN.printX509Cert.with.weak"));
3110 PublicKey pkey = cert.getPublicKey();
3111 String sigName = cert.getSigAlgName();
3112 // No need to warn about sigalg of a trust anchor
3113 if (!isTrustedCert(cert)) {
3114 sigName = withWeak(sigName);
3115 }
3116 Object[] source = {cert.getSubjectDN().toString(),
3117 cert.getIssuerDN().toString(),
3118 cert.getSerialNumber().toString(16),
3119 cert.getNotBefore().toString(),
3120 cert.getNotAfter().toString(),
3121 getCertFingerPrint("MD5", cert),
3122 getCertFingerPrint("SHA1", cert),
3123 getCertFingerPrint("SHA-256", cert),
3124 sigName,
3125 withWeak(pkey),
3126 cert.getVersion()
3127 };
3128 out.println(form.format(source));
3129
3130 if (cert instanceof X509CertImpl) {
3131 X509CertImpl impl = (X509CertImpl)cert;
3132 X509CertInfo certInfo = (X509CertInfo)impl.get(X509CertImpl.NAME
3133 + "." +
3134 X509CertImpl.INFO);
3135 CertificateExtensions exts = (CertificateExtensions)
3136 certInfo.get(X509CertInfo.EXTENSIONS);
3137 if (exts != null) {
3138 printExtensions(rb.getString("Extensions."), exts, out);
3139 }
3140 }
3141 }
3142
3143 private static void printExtensions(String title, CertificateExtensions exts, PrintStream out)
3144 throws Exception {
3145 int extnum = 0;
3175
3176 private boolean signedBy(X509Certificate end, X509Certificate ca) {
3177 if (!ca.getSubjectDN().equals(end.getIssuerDN())) {
3178 return false;
3179 }
3180 try {
3181 end.verify(ca.getPublicKey());
3182 return true;
3183 } catch (Exception e) {
3184 return false;
3185 }
3186 }
3187
3188 /**
3189 * Locates a signer for a given certificate from a given keystore and
3190 * returns the signer's certificate.
3191 * @param cert the certificate whose signer is searched, not null
3192 * @param ks the keystore to search with, not null
3193 * @return <code>cert</code> itself if it's already inside <code>ks</code>,
3194 * or a certificate inside <code>ks</code> who signs <code>cert</code>,
3195 * or null otherwise. A label is added.
3196 */
3197 private static Pair<String,Certificate>
3198 getSigner(Certificate cert, KeyStore ks) throws Exception {
3199 if (ks.getCertificateAlias(cert) != null) {
3200 return new Pair<>("", cert);
3201 }
3202 for (Enumeration<String> aliases = ks.aliases();
3203 aliases.hasMoreElements(); ) {
3204 String name = aliases.nextElement();
3205 Certificate trustedCert = ks.getCertificate(name);
3206 if (trustedCert != null) {
3207 try {
3208 cert.verify(trustedCert.getPublicKey());
3209 return new Pair<>(name, trustedCert);
3210 } catch (Exception e) {
3211 // Not verified, skip to the next one
3212 }
3213 }
3214 }
3215 return null;
3216 }
3217
3218 /**
3219 * Gets an X.500 name suitable for inclusion in a certification request.
3220 */
3221 private X500Name getX500Name() throws IOException {
3222 BufferedReader in;
3223 in = new BufferedReader(new InputStreamReader(System.in));
3224 String commonName = "Unknown";
3225 String organizationalUnit = "Unknown";
3226 String organization = "Unknown";
3227 String city = "Unknown";
3228 String state = "Unknown";
3229 String country = "Unknown";
3453 }
3454 }
3455
3456 return Pair.of(entry, pkey);
3457 }
3458 /**
3459 * Gets the requested finger print of the certificate.
3460 */
3461 private String getCertFingerPrint(String mdAlg, Certificate cert)
3462 throws Exception
3463 {
3464 byte[] encCertInfo = cert.getEncoded();
3465 MessageDigest md = MessageDigest.getInstance(mdAlg);
3466 byte[] digest = md.digest(encCertInfo);
3467 return toHexString(digest);
3468 }
3469
3470 /**
3471 * Prints warning about missing integrity check.
3472 */
3473 private void printNoIntegrityWarning() {
3474 System.err.println();
3475 System.err.println(rb.getString
3476 (".WARNING.WARNING.WARNING."));
3477 System.err.println(rb.getString
3478 (".The.integrity.of.the.information.stored.in.your.keystore."));
3479 System.err.println(rb.getString
3480 (".WARNING.WARNING.WARNING."));
3481 System.err.println();
3482 }
3483
3484 /**
3485 * Validates chain in certification reply, and returns the ordered
3486 * elements of the chain (with user certificate first, and root
3487 * certificate last in the array).
3488 *
3489 * @param alias the alias name
3490 * @param userCert the user certificate of the alias
3491 * @param replyCerts the chain provided in the reply
3492 */
3493 private Certificate[] validateReply(String alias,
3494 Certificate userCert,
3495 Certificate[] replyCerts)
3496 throws Exception
3497 {
3498
3499 checkWeak(rb.getString("reply"), replyCerts);
3500
3501 // order the certs in the reply (bottom-up).
3502 // we know that all certs in the reply are of type X.509, because
3503 // we parsed them using an X.509 certificate factory
3504 int i;
3505 PublicKey userPubKey = userCert.getPublicKey();
3506 for (i=0; i<replyCerts.length; i++) {
3507 if (userPubKey.equals(replyCerts[i].getPublicKey())) {
3508 break;
3509 }
3510 }
3511 if (i == replyCerts.length) {
3512 MessageFormat form = new MessageFormat(rb.getString
3513 ("Certificate.reply.does.not.contain.public.key.for.alias."));
3514 Object[] source = {alias};
3515 throw new Exception(form.format(source));
3516 }
3517
3518 Certificate tmpCert = replyCerts[0];
3519 replyCerts[0] = replyCerts[i];
3520 replyCerts[i] = tmpCert;
3528 if (signedBy(thisCert, (X509Certificate)replyCerts[j])) {
3529 tmpCert = replyCerts[i];
3530 replyCerts[i] = replyCerts[j];
3531 replyCerts[j] = tmpCert;
3532 thisCert = (X509Certificate)replyCerts[i];
3533 break;
3534 }
3535 }
3536 if (j == replyCerts.length) {
3537 throw new Exception
3538 (rb.getString("Incomplete.certificate.chain.in.reply"));
3539 }
3540 }
3541
3542 if (noprompt) {
3543 return replyCerts;
3544 }
3545
3546 // do we trust the cert at the top?
3547 Certificate topCert = replyCerts[replyCerts.length-1];
3548 boolean fromKeyStore = true;
3549 Pair<String,Certificate> root = getSigner(topCert, keyStore);
3550 if (root == null && trustcacerts && caks != null) {
3551 root = getSigner(topCert, caks);
3552 fromKeyStore = false;
3553 }
3554 if (root == null) {
3555 System.err.println();
3556 System.err.println
3557 (rb.getString("Top.level.certificate.in.reply."));
3558 printX509Cert((X509Certificate)topCert, System.out);
3559 System.err.println();
3560 System.err.print(rb.getString(".is.not.trusted."));
3561 printWeakWarnings(true);
3562 String reply = getYesNoReply
3563 (rb.getString("Install.reply.anyway.no."));
3564 if ("NO".equals(reply)) {
3565 return null;
3566 }
3567 } else {
3568 if (root.snd != topCert) {
3569 // append the root CA cert to the chain
3570 Certificate[] tmpCerts =
3571 new Certificate[replyCerts.length+1];
3572 System.arraycopy(replyCerts, 0, tmpCerts, 0,
3573 replyCerts.length);
3574 tmpCerts[tmpCerts.length-1] = root.snd;
3575 replyCerts = tmpCerts;
3576 checkWeak(String.format(rb.getString(fromKeyStore ?
3577 "alias.in.keystore" :
3578 "alias.in.cacerts"),
3579 root.fst),
3580 root.snd);
3581 }
3582 }
3583 return replyCerts;
3584 }
3585
3586 /**
3587 * Establishes a certificate chain (using trusted certificates in the
3588 * keystore and cacerts), starting with the reply (certToVerify)
3589 * and ending at a self-signed certificate found in the keystore.
3590 *
3591 * @param userCert optional existing certificate, mostly likely be the
3592 * original self-signed cert created by -genkeypair.
3593 * It must have the same public key as certToVerify
3594 * but cannot be the same cert.
3595 * @param certToVerify the starting certificate to build the chain
3596 * @returns the established chain, might be null if user decides not
3597 */
3598 private Certificate[] establishCertChain(Certificate userCert,
3599 Certificate certToVerify)
3600 throws Exception
3601 {
3602 if (userCert != null) {
3603 // Make sure that the public key of the certificate reply matches
3604 // the original public key in the keystore
3605 PublicKey origPubKey = userCert.getPublicKey();
3606 PublicKey replyPubKey = certToVerify.getPublicKey();
3607 if (!origPubKey.equals(replyPubKey)) {
3608 throw new Exception(rb.getString
3609 ("Public.keys.in.reply.and.keystore.don.t.match"));
3610 }
3611
3612 // If the two certs are identical, we're done: no need to import
3613 // anything
3614 if (certToVerify.equals(userCert)) {
3615 throw new Exception(rb.getString
3616 ("Certificate.reply.and.certificate.in.keystore.are.identical"));
3617 }
3618 }
3619
3620 // Build a hash table of all certificates in the keystore.
3621 // Use the subject distinguished name as the key into the hash table.
3622 // All certificates associated with the same subject distinguished
3623 // name are stored in the same hash table entry as a vector.
3624 Hashtable<Principal, Vector<Pair<String,X509Certificate>>> certs = null;
3625 if (keyStore.size() > 0) {
3626 certs = new Hashtable<>(11);
3627 keystorecerts2Hashtable(keyStore, certs);
3628 }
3629 if (trustcacerts) {
3630 if (caks!=null && caks.size()>0) {
3631 if (certs == null) {
3632 certs = new Hashtable<>(11);
3633 }
3634 keystorecerts2Hashtable(caks, certs);
3635 }
3636 }
3637
3638 // start building chain
3639 Vector<Pair<String,X509Certificate>> chain = new Vector<>(2);
3640 if (buildChain(
3641 new Pair<>(rb.getString("the.input"),
3642 (X509Certificate) certToVerify),
3643 chain, certs)) {
3644 for (Pair<String,X509Certificate> p : chain) {
3645 checkWeak(p.fst, p.snd);
3646 }
3647 Certificate[] newChain =
3648 new Certificate[chain.size()];
3649 // buildChain() returns chain with self-signed root-cert first and
3650 // user-cert last, so we need to invert the chain before we store
3651 // it
3652 int j=0;
3653 for (int i=chain.size()-1; i>=0; i--) {
3654 newChain[j] = chain.elementAt(i).snd;
3655 j++;
3656 }
3657 return newChain;
3658 } else {
3659 throw new Exception
3660 (rb.getString("Failed.to.establish.chain.from.reply"));
3661 }
3662 }
3663
3664 /**
3665 * Recursively tries to establish chain from pool of certs starting from
3666 * certToVerify until a self-signed cert is found, and fill the certs found
3667 * into chain. Each cert in the chain signs the next one.
3668 *
3669 * This method is able to recover from an error, say, if certToVerify
3670 * is signed by certA but certA has no issuer in certs and itself is not
3671 * self-signed, the method can try another certB that also signs
3672 * certToVerify and look for signer of certB, etc, etc.
3673 *
3674 * Each cert in chain comes with a label showing its origin. The label is
3675 * used in the warning message when the cert is considered a risk.
3676 *
3677 * @param certToVerify the cert that needs to be verified.
3678 * @param chain the chain that's being built.
3679 * @param certs the pool of trusted certs
3680 *
3681 * @return true if successful, false otherwise.
3682 */
3683 private boolean buildChain(Pair<String,X509Certificate> certToVerify,
3684 Vector<Pair<String,X509Certificate>> chain,
3685 Hashtable<Principal, Vector<Pair<String,X509Certificate>>> certs) {
3686 if (isSelfSigned(certToVerify.snd)) {
3687 // reached self-signed root cert;
3688 // no verification needed because it's trusted.
3689 chain.addElement(certToVerify);
3690 return true;
3691 }
3692
3693 Principal issuer = certToVerify.snd.getIssuerDN();
3694
3695 // Get the issuer's certificate(s)
3696 Vector<Pair<String,X509Certificate>> vec = certs.get(issuer);
3697 if (vec == null) {
3698 return false;
3699 }
3700
3701 // Try out each certificate in the vector, until we find one
3702 // whose public key verifies the signature of the certificate
3703 // in question.
3704 for (Enumeration<Pair<String,X509Certificate>> issuerCerts = vec.elements();
3705 issuerCerts.hasMoreElements(); ) {
3706 Pair<String,X509Certificate> issuerCert = issuerCerts.nextElement();
3707 PublicKey issuerPubKey = issuerCert.snd.getPublicKey();
3708 try {
3709 certToVerify.snd.verify(issuerPubKey);
3710 } catch (Exception e) {
3711 continue;
3712 }
3713 if (buildChain(issuerCert, chain, certs)) {
3714 chain.addElement(certToVerify);
3715 return true;
3716 }
3717 }
3718 return false;
3719 }
3720
3721 /**
3722 * Prompts user for yes/no decision.
3723 *
3724 * @return the user's decision, can only be "YES" or "NO"
3725 */
3726 private String getYesNoReply(String prompt)
3727 throws IOException
3728 {
3729 String reply = null;
3738 reply = (new BufferedReader(new InputStreamReader
3739 (System.in))).readLine();
3740 if (collator.compare(reply, "") == 0 ||
3741 collator.compare(reply, rb.getString("n")) == 0 ||
3742 collator.compare(reply, rb.getString("no")) == 0) {
3743 reply = "NO";
3744 } else if (collator.compare(reply, rb.getString("y")) == 0 ||
3745 collator.compare(reply, rb.getString("yes")) == 0) {
3746 reply = "YES";
3747 } else {
3748 System.err.println(rb.getString("Wrong.answer.try.again"));
3749 reply = null;
3750 }
3751 } while (reply == null);
3752 return reply;
3753 }
3754
3755 /**
3756 * Stores the (leaf) certificates of a keystore in a hashtable.
3757 * All certs belonging to the same CA are stored in a vector that
3758 * in turn is stored in the hashtable, keyed by the CA's subject DN.
3759 * Each cert comes with a string label that shows its origin and alias.
3760 */
3761 private void keystorecerts2Hashtable(KeyStore ks,
3762 Hashtable<Principal, Vector<Pair<String,X509Certificate>>> hash)
3763 throws Exception {
3764
3765 for (Enumeration<String> aliases = ks.aliases();
3766 aliases.hasMoreElements(); ) {
3767 String alias = aliases.nextElement();
3768 Certificate cert = ks.getCertificate(alias);
3769 if (cert != null) {
3770 Principal subjectDN = ((X509Certificate)cert).getSubjectDN();
3771 Pair<String,X509Certificate> pair = new Pair<>(
3772 String.format(
3773 rb.getString(ks == caks ?
3774 "alias.in.cacerts" :
3775 "alias.in.keystore"),
3776 alias),
3777 (X509Certificate)cert);
3778 Vector<Pair<String,X509Certificate>> vec = hash.get(subjectDN);
3779 if (vec == null) {
3780 vec = new Vector<>();
3781 vec.addElement(pair);
3782 } else {
3783 if (!vec.contains(pair)) {
3784 vec.addElement(pair);
3785 }
3786 }
3787 hash.put(subjectDN, vec);
3788 }
3789 }
3790 }
3791
3792 /**
3793 * Returns the issue time that's specified the -startdate option
3794 * @param s the value of -startdate option
3795 */
3796 private static Date getStartDate(String s) throws IOException {
3797 Calendar c = new GregorianCalendar();
3798 if (s != null) {
3799 IOException ioe = new IOException(
3800 rb.getString("Illegal.startdate.value"));
3801 int len = s.length();
3802 if (len == 0) {
3803 throw ioe;
3804 }
4335 .toByteArray()));
4336 break;
4337 default:
4338 throw new Exception(rb.getString(
4339 "Unknown.extension.type.") + extstr);
4340 }
4341 }
4342 // always non-critical
4343 ext.set(SubjectKeyIdentifierExtension.NAME,
4344 new SubjectKeyIdentifierExtension(
4345 new KeyIdentifier(pkey).getIdentifier()));
4346 if (akey != null && !pkey.equals(akey)) {
4347 ext.set(AuthorityKeyIdentifierExtension.NAME,
4348 new AuthorityKeyIdentifierExtension(
4349 new KeyIdentifier(akey), null, null));
4350 }
4351 } catch(IOException e) {
4352 throw new RuntimeException(e);
4353 }
4354 return ext;
4355 }
4356
4357 private boolean isTrustedCert(Certificate cert) throws KeyStoreException {
4358 if (caks != null && caks.getCertificateAlias(cert) != null) {
4359 return true;
4360 } else {
4361 String inKS = keyStore.getCertificateAlias(cert);
4362 return inKS != null && keyStore.isCertificateEntry(inKS);
4363 }
4364 }
4365
4366 private void checkWeak(String label, String sigAlg, Key key) {
4367
4368 if (sigAlg != null && !DISABLED_CHECK.permits(
4369 SIG_PRIMITIVE_SET, sigAlg, null)) {
4370 weakWarnings.add(String.format(
4371 rb.getString("whose.sigalg.risk"), label, sigAlg));
4372 }
4373 if (key != null && !DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
4374 weakWarnings.add(String.format(
4375 rb.getString("whose.key.risk"),
4376 label,
4377 String.format(rb.getString("key.bit"),
4378 KeyUtil.getKeySize(key), key.getAlgorithm())));
4379 }
4380 }
4381
4382 private void checkWeak(String label, Certificate[] certs)
4383 throws KeyStoreException {
4384 for (int i = 0; i < certs.length; i++) {
4385 Certificate cert = certs[i];
4386 if (cert instanceof X509Certificate) {
4387 X509Certificate xc = (X509Certificate)cert;
4388 String fullLabel = label;
4389 if (certs.length > 1) {
4390 fullLabel = oneInMany(label, i, certs.length);
4391 }
4392 checkWeak(fullLabel, xc);
4393 }
4394 }
4395 }
4396
4397 private void checkWeak(String label, Certificate cert)
4398 throws KeyStoreException {
4399 if (cert instanceof X509Certificate) {
4400 X509Certificate xc = (X509Certificate)cert;
4401 // No need to check the sigalg of a trust anchor
4402 String sigAlg = isTrustedCert(cert) ? null : xc.getSigAlgName();
4403 checkWeak(label, sigAlg, xc.getPublicKey());
4404 }
4405 }
4406
4407 private void checkWeak(String label, PKCS10 p10) {
4408 checkWeak(label, p10.getSigAlg(), p10.getSubjectPublicKeyInfo());
4409 }
4410
4411 private void checkWeak(String label, CRL crl, Key key) {
4412 if (crl instanceof X509CRLImpl) {
4413 X509CRLImpl impl = (X509CRLImpl)crl;
4414 checkWeak(label, impl.getSigAlgName(), key);
4415 }
4416 }
4417
4418 private void printWeakWarnings(boolean newLine) {
4419 if (!weakWarnings.isEmpty() && !nowarn) {
4420 System.err.println("\nWarning:");
4421 for (String warning : weakWarnings) {
4422 System.err.println(warning);
4423 }
4424 if (newLine) {
4425 // When calling before a yes/no prompt, add a new line
4426 System.err.println();
4427 }
4428 }
4429 weakWarnings.clear();
4430 }
4431
4432 /**
4433 * Prints the usage of this tool.
4434 */
4435 private void usage() {
4436 if (command != null) {
4437 System.err.println("keytool " + command +
4438 rb.getString(".OPTION."));
4439 System.err.println();
4440 System.err.println(rb.getString(command.description));
4441 System.err.println();
4442 System.err.println(rb.getString("Options."));
4443 System.err.println();
4444
4445 // Left and right sides of the options list
4446 String[] left = new String[command.options.length];
4447 String[] right = new String[command.options.length];
4448
4449 // Check if there's an unknown option
|