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