Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/tools/keytool/Main.java
41161 views
1
/*
2
* Copyright (c) 1997, 2021, 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 = new Date();
1449
lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L);
1450
CertificateValidity interval = new CertificateValidity(firstDate,
1451
lastDate);
1452
1453
PrivateKey privateKey =
1454
(PrivateKey)recoverKey(alias, storePass, keyPass).fst;
1455
if (sigAlgName == null) {
1456
sigAlgName = getCompatibleSigAlgName(privateKey);
1457
}
1458
X509CertInfo info = new X509CertInfo();
1459
info.set(X509CertInfo.VALIDITY, interval);
1460
info.set(X509CertInfo.SERIAL_NUMBER,
1461
CertificateSerialNumber.newRandom64bit(new SecureRandom()));
1462
info.set(X509CertInfo.VERSION,
1463
new CertificateVersion(CertificateVersion.V3));
1464
info.set(X509CertInfo.ISSUER, issuer);
1465
1466
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
1467
boolean canRead = false;
1468
StringBuilder sb = new StringBuilder();
1469
while (true) {
1470
String s = reader.readLine();
1471
if (s == null) break;
1472
// OpenSSL does not use NEW
1473
//if (s.startsWith("-----BEGIN NEW CERTIFICATE REQUEST-----")) {
1474
if (s.startsWith("-----BEGIN") && s.indexOf("REQUEST") >= 0) {
1475
canRead = true;
1476
//} else if (s.startsWith("-----END NEW CERTIFICATE REQUEST-----")) {
1477
} else if (s.startsWith("-----END") && s.indexOf("REQUEST") >= 0) {
1478
break;
1479
} else if (canRead) {
1480
sb.append(s);
1481
}
1482
}
1483
byte[] rawReq = Pem.decode(new String(sb));
1484
PKCS10 req = new PKCS10(rawReq);
1485
1486
checkWeak(rb.getString("the.certificate.request"), req);
1487
1488
info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo()));
1489
info.set(X509CertInfo.SUBJECT,
1490
dname==null?req.getSubjectName():new X500Name(dname));
1491
CertificateExtensions reqex = null;
1492
Iterator<PKCS10Attribute> attrs = req.getAttributes().getAttributes().iterator();
1493
while (attrs.hasNext()) {
1494
PKCS10Attribute attr = attrs.next();
1495
if (attr.getAttributeId().equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) {
1496
reqex = (CertificateExtensions)attr.getAttributeValue();
1497
}
1498
}
1499
1500
PublicKey subjectPubKey = req.getSubjectPublicKeyInfo();
1501
PublicKey issuerPubKey = signerCert.getPublicKey();
1502
1503
KeyIdentifier signerSubjectKeyId;
1504
if (Arrays.equals(subjectPubKey.getEncoded(), issuerPubKey.getEncoded())) {
1505
// No AKID for self-signed cert
1506
signerSubjectKeyId = null;
1507
} else {
1508
X509CertImpl certImpl;
1509
if (signerCert instanceof X509CertImpl) {
1510
certImpl = (X509CertImpl) signerCert;
1511
} else {
1512
certImpl = new X509CertImpl(signerCert.getEncoded());
1513
}
1514
1515
// To enforce compliance with RFC 5280 section 4.2.1.1: "Where a key
1516
// identifier has been previously established, the CA SHOULD use the
1517
// previously established identifier."
1518
// Use issuer's SKID to establish the AKID in createV3Extensions() method.
1519
signerSubjectKeyId = certImpl.getSubjectKeyId();
1520
1521
if (signerSubjectKeyId == null) {
1522
signerSubjectKeyId = new KeyIdentifier(issuerPubKey);
1523
}
1524
}
1525
1526
CertificateExtensions ext = createV3Extensions(
1527
reqex,
1528
null,
1529
v3ext,
1530
subjectPubKey,
1531
signerSubjectKeyId);
1532
info.set(X509CertInfo.EXTENSIONS, ext);
1533
X509CertImpl cert = new X509CertImpl(info);
1534
cert.sign(privateKey, sigAlgName);
1535
dumpCert(cert, out);
1536
for (Certificate ca: keyStore.getCertificateChain(alias)) {
1537
if (ca instanceof X509Certificate) {
1538
X509Certificate xca = (X509Certificate)ca;
1539
if (!KeyStoreUtil.isSelfSigned(xca)) {
1540
dumpCert(xca, out);
1541
}
1542
}
1543
}
1544
1545
checkWeak(rb.getString("the.issuer"), keyStore.getCertificateChain(alias));
1546
checkWeak(rb.getString("the.generated.certificate"), cert);
1547
}
1548
1549
private void doGenCRL(PrintStream out)
1550
throws Exception {
1551
if (ids == null) {
1552
throw new Exception("Must provide -id when -gencrl");
1553
}
1554
Certificate signerCert = keyStore.getCertificate(alias);
1555
byte[] encoded = signerCert.getEncoded();
1556
X509CertImpl signerCertImpl = new X509CertImpl(encoded);
1557
X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get(
1558
X509CertImpl.NAME + "." + X509CertImpl.INFO);
1559
X500Name owner = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." +
1560
X509CertInfo.DN_NAME);
1561
1562
Date firstDate = getStartDate(startDate);
1563
Date lastDate = (Date) firstDate.clone();
1564
lastDate.setTime(lastDate.getTime() + validity*1000*24*60*60);
1565
CertificateValidity interval = new CertificateValidity(firstDate,
1566
lastDate);
1567
1568
1569
PrivateKey privateKey =
1570
(PrivateKey)recoverKey(alias, storePass, keyPass).fst;
1571
if (sigAlgName == null) {
1572
sigAlgName = getCompatibleSigAlgName(privateKey);
1573
}
1574
1575
X509CRLEntry[] badCerts = new X509CRLEntry[ids.size()];
1576
for (int i=0; i<ids.size(); i++) {
1577
String id = ids.get(i);
1578
int d = id.indexOf(':');
1579
if (d >= 0) {
1580
CRLExtensions ext = new CRLExtensions();
1581
ext.set("Reason", new CRLReasonCodeExtension(Integer.parseInt(id.substring(d+1))));
1582
badCerts[i] = new X509CRLEntryImpl(new BigInteger(id.substring(0, d)),
1583
firstDate, ext);
1584
} else {
1585
badCerts[i] = new X509CRLEntryImpl(new BigInteger(ids.get(i)), firstDate);
1586
}
1587
}
1588
X509CRLImpl crl = new X509CRLImpl(owner, firstDate, lastDate, badCerts);
1589
crl.sign(privateKey, sigAlgName);
1590
if (rfc) {
1591
out.println("-----BEGIN X509 CRL-----");
1592
out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(crl.getEncodedInternal()));
1593
out.println("-----END X509 CRL-----");
1594
} else {
1595
out.write(crl.getEncodedInternal());
1596
}
1597
checkWeak(rb.getString("the.generated.crl"), crl, privateKey);
1598
}
1599
1600
/**
1601
* Creates a PKCS#10 cert signing request, corresponding to the
1602
* keys (and name) associated with a given alias.
1603
*/
1604
private void doCertReq(String alias, String sigAlgName, PrintStream out)
1605
throws Exception
1606
{
1607
if (alias == null) {
1608
alias = keyAlias;
1609
}
1610
1611
Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass);
1612
PrivateKey privKey = (PrivateKey)objs.fst;
1613
if (keyPass == null) {
1614
keyPass = objs.snd;
1615
}
1616
1617
Certificate cert = keyStore.getCertificate(alias);
1618
if (cert == null) {
1619
MessageFormat form = new MessageFormat
1620
(rb.getString("alias.has.no.public.key.certificate."));
1621
Object[] source = {alias};
1622
throw new Exception(form.format(source));
1623
}
1624
PKCS10 request = new PKCS10(cert.getPublicKey());
1625
CertificateExtensions ext = createV3Extensions(null, null, v3ext, cert.getPublicKey(), null);
1626
// Attribute name is not significant
1627
request.getAttributes().setAttribute(X509CertInfo.EXTENSIONS,
1628
new PKCS10Attribute(PKCS9Attribute.EXTENSION_REQUEST_OID, ext));
1629
1630
// Construct a Signature object, so that we can sign the request
1631
if (sigAlgName == null) {
1632
sigAlgName = getCompatibleSigAlgName(privKey);
1633
}
1634
1635
X500Name subject = dname == null?
1636
new X500Name(((X509Certificate)cert).getSubjectX500Principal().getEncoded()):
1637
new X500Name(dname);
1638
1639
// Sign the request and base-64 encode it
1640
request.encodeAndSign(subject, privKey, sigAlgName);
1641
request.print(out);
1642
1643
checkWeak(rb.getString("the.generated.certificate.request"), request);
1644
}
1645
1646
/**
1647
* Deletes an entry from the keystore.
1648
*/
1649
private void doDeleteEntry(String alias) throws Exception {
1650
if (keyStore.containsAlias(alias) == false) {
1651
MessageFormat form = new MessageFormat
1652
(rb.getString("Alias.alias.does.not.exist"));
1653
Object[] source = {alias};
1654
throw new Exception(form.format(source));
1655
}
1656
keyStore.deleteEntry(alias);
1657
}
1658
1659
/**
1660
* Exports a certificate from the keystore.
1661
*/
1662
private void doExportCert(String alias, PrintStream out)
1663
throws Exception
1664
{
1665
if (storePass == null
1666
&& !KeyStoreUtil.isWindowsKeyStore(storetype)
1667
&& !isPasswordlessKeyStore) {
1668
printNoIntegrityWarning();
1669
}
1670
if (alias == null) {
1671
alias = keyAlias;
1672
}
1673
if (keyStore.containsAlias(alias) == false) {
1674
MessageFormat form = new MessageFormat
1675
(rb.getString("Alias.alias.does.not.exist"));
1676
Object[] source = {alias};
1677
throw new Exception(form.format(source));
1678
}
1679
1680
X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias);
1681
if (cert == null) {
1682
MessageFormat form = new MessageFormat
1683
(rb.getString("Alias.alias.has.no.certificate"));
1684
Object[] source = {alias};
1685
throw new Exception(form.format(source));
1686
}
1687
dumpCert(cert, out);
1688
checkWeak(rb.getString("the.certificate"), cert);
1689
}
1690
1691
/**
1692
* Prompt the user for a keypass when generating a key entry.
1693
* @param alias the entry we will set password for
1694
* @param orig the original entry of doing a dup, null if generate new
1695
* @param origPass the password to copy from if user press ENTER
1696
*/
1697
private char[] promptForKeyPass(String alias, String orig, char[] origPass) throws Exception{
1698
if (origPass != null && P12KEYSTORE.equalsIgnoreCase(storetype)) {
1699
return origPass;
1700
} else if (!token && !protectedPath) {
1701
// Prompt for key password
1702
int count;
1703
for (count = 0; count < 3; count++) {
1704
MessageFormat form = new MessageFormat(rb.getString
1705
("Enter.key.password.for.alias."));
1706
Object[] source = {alias};
1707
System.err.print(form.format(source));
1708
if (origPass != null) {
1709
System.err.println();
1710
if (orig == null) {
1711
System.err.print(rb.getString
1712
(".RETURN.if.same.as.keystore.password."));
1713
} else {
1714
form = new MessageFormat(rb.getString
1715
(".RETURN.if.same.as.for.otherAlias."));
1716
Object[] src = {orig};
1717
System.err.print(form.format(src));
1718
}
1719
}
1720
System.err.flush();
1721
char[] entered = Password.readPassword(System.in);
1722
passwords.add(entered);
1723
if (entered == null && origPass != null) {
1724
return origPass;
1725
} else if (entered != null && entered.length >= 6) {
1726
System.err.print(rb.getString("Re.enter.new.password."));
1727
char[] passAgain = Password.readPassword(System.in);
1728
passwords.add(passAgain);
1729
if (!Arrays.equals(entered, passAgain)) {
1730
System.err.println
1731
(rb.getString("They.don.t.match.Try.again"));
1732
continue;
1733
}
1734
return entered;
1735
} else {
1736
System.err.println(rb.getString
1737
("Key.password.is.too.short.must.be.at.least.6.characters"));
1738
}
1739
}
1740
if (count == 3) {
1741
if (command == KEYCLONE) {
1742
throw new Exception(rb.getString
1743
("Too.many.failures.Key.entry.not.cloned"));
1744
} else {
1745
throw new Exception(rb.getString
1746
("Too.many.failures.key.not.added.to.keystore"));
1747
}
1748
}
1749
}
1750
return null; // PKCS11, MSCAPI, or -protected
1751
}
1752
1753
/*
1754
* Prompt the user for the password credential to be stored.
1755
*/
1756
private char[] promptForCredential() throws Exception {
1757
// Handle password supplied via stdin
1758
if (System.console() == null) {
1759
char[] importPass = Password.readPassword(System.in);
1760
passwords.add(importPass);
1761
return importPass;
1762
}
1763
1764
int count;
1765
for (count = 0; count < 3; count++) {
1766
System.err.print(
1767
rb.getString("Enter.the.password.to.be.stored."));
1768
System.err.flush();
1769
char[] entered = Password.readPassword(System.in);
1770
passwords.add(entered);
1771
System.err.print(rb.getString("Re.enter.password."));
1772
char[] passAgain = Password.readPassword(System.in);
1773
passwords.add(passAgain);
1774
if (!Arrays.equals(entered, passAgain)) {
1775
System.err.println(rb.getString("They.don.t.match.Try.again"));
1776
continue;
1777
}
1778
return entered;
1779
}
1780
1781
if (count == 3) {
1782
throw new Exception(rb.getString
1783
("Too.many.failures.key.not.added.to.keystore"));
1784
}
1785
1786
return null;
1787
}
1788
1789
/**
1790
* Creates a new secret key.
1791
*/
1792
private void doGenSecretKey(String alias, String keyAlgName,
1793
int keysize)
1794
throws Exception
1795
{
1796
if (alias == null) {
1797
alias = keyAlias;
1798
}
1799
if (keyStore.containsAlias(alias)) {
1800
MessageFormat form = new MessageFormat(rb.getString
1801
("Secret.key.not.generated.alias.alias.already.exists"));
1802
Object[] source = {alias};
1803
throw new Exception(form.format(source));
1804
}
1805
1806
// Use the keystore's default PBE algorithm for entry protection
1807
boolean useDefaultPBEAlgorithm = true;
1808
SecretKey secKey = null;
1809
1810
if (keyAlgName.toUpperCase(Locale.ENGLISH).startsWith("PBE")) {
1811
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE");
1812
1813
// User is prompted for PBE credential
1814
secKey =
1815
factory.generateSecret(new PBEKeySpec(promptForCredential()));
1816
1817
// Check whether a specific PBE algorithm was specified
1818
if (!"PBE".equalsIgnoreCase(keyAlgName)) {
1819
useDefaultPBEAlgorithm = false;
1820
}
1821
1822
if (verbose) {
1823
MessageFormat form = new MessageFormat(rb.getString(
1824
"Generated.keyAlgName.secret.key"));
1825
Object[] source =
1826
{useDefaultPBEAlgorithm ? "PBE" : secKey.getAlgorithm()};
1827
System.err.println(form.format(source));
1828
}
1829
} else {
1830
KeyGenerator keygen = KeyGenerator.getInstance(keyAlgName);
1831
if (keysize == -1) {
1832
if ("DES".equalsIgnoreCase(keyAlgName)) {
1833
keysize = 56;
1834
} else if ("DESede".equalsIgnoreCase(keyAlgName)) {
1835
keysize = 168;
1836
} else {
1837
throw new Exception(rb.getString
1838
("Please.provide.keysize.for.secret.key.generation"));
1839
}
1840
}
1841
keygen.init(keysize);
1842
secKey = keygen.generateKey();
1843
1844
MessageFormat form = new MessageFormat(rb.getString
1845
("Generated.keysize.bit.keyAlgName.secret.key"));
1846
Object[] source = {keysize,
1847
secKey.getAlgorithm()};
1848
System.err.println(form.format(source));
1849
}
1850
1851
if (keyPass == null) {
1852
keyPass = promptForKeyPass(alias, null, storePass);
1853
}
1854
1855
if (useDefaultPBEAlgorithm) {
1856
keyStore.setKeyEntry(alias, secKey, keyPass, null);
1857
} else {
1858
keyStore.setEntry(alias, new KeyStore.SecretKeyEntry(secKey),
1859
new KeyStore.PasswordProtection(keyPass, keyAlgName, null));
1860
}
1861
}
1862
1863
/**
1864
* If no signature algorithm was specified at the command line,
1865
* we choose one that is compatible with the selected private key
1866
*/
1867
private static String getCompatibleSigAlgName(PrivateKey key)
1868
throws Exception {
1869
String result = SignatureUtil.getDefaultSigAlgForKey(key);
1870
if (result != null) {
1871
return result;
1872
} else {
1873
throw new Exception(rb.getString
1874
("Cannot.derive.signature.algorithm"));
1875
}
1876
}
1877
1878
/**
1879
* Creates a new key pair and self-signed certificate.
1880
*/
1881
private void doGenKeyPair(String alias, String dname, String keyAlgName,
1882
int keysize, String groupName, String sigAlgName,
1883
String signerAlias)
1884
throws Exception
1885
{
1886
if (groupName != null) {
1887
if (keysize != -1) {
1888
throw new Exception(rb.getString("groupname.keysize.coexist"));
1889
}
1890
} else {
1891
if (keysize == -1) {
1892
if ("EC".equalsIgnoreCase(keyAlgName)) {
1893
keysize = SecurityProviderConstants.DEF_EC_KEY_SIZE;
1894
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
1895
keysize = SecurityProviderConstants.DEF_RSA_KEY_SIZE;
1896
} else if ("DSA".equalsIgnoreCase(keyAlgName)) {
1897
keysize = SecurityProviderConstants.DEF_DSA_KEY_SIZE;
1898
} else if ("EdDSA".equalsIgnoreCase(keyAlgName)) {
1899
keysize = SecurityProviderConstants.DEF_ED_KEY_SIZE;
1900
} else if ("Ed25519".equalsIgnoreCase(keyAlgName)) {
1901
keysize = 255;
1902
} else if ("Ed448".equalsIgnoreCase(keyAlgName)) {
1903
keysize = 448;
1904
} else if ("XDH".equalsIgnoreCase(keyAlgName)) {
1905
keysize = SecurityProviderConstants.DEF_XEC_KEY_SIZE;
1906
} else if ("X25519".equalsIgnoreCase(keyAlgName)) {
1907
keysize = 255;
1908
} else if ("X448".equalsIgnoreCase(keyAlgName)) {
1909
keysize = 448;
1910
} else if ("DH".equalsIgnoreCase(keyAlgName)) {
1911
keysize = SecurityProviderConstants.DEF_DH_KEY_SIZE;
1912
}
1913
} else {
1914
if ("EC".equalsIgnoreCase(keyAlgName)) {
1915
weakWarnings.add(String.format(
1916
rb.getString("deprecate.keysize.for.ec"),
1917
ecGroupNameForSize(keysize)));
1918
}
1919
}
1920
}
1921
1922
if (alias == null) {
1923
alias = keyAlias;
1924
}
1925
1926
if (keyStore.containsAlias(alias)) {
1927
MessageFormat form = new MessageFormat(rb.getString
1928
("Key.pair.not.generated.alias.alias.already.exists"));
1929
Object[] source = {alias};
1930
throw new Exception(form.format(source));
1931
}
1932
1933
CertAndKeyGen keypair;
1934
KeyIdentifier signerSubjectKeyId = null;
1935
if (signerAlias != null) {
1936
PrivateKey signerPrivateKey =
1937
(PrivateKey)recoverKey(signerAlias, storePass, signerKeyPass).fst;
1938
Certificate signerCert = keyStore.getCertificate(signerAlias);
1939
1940
X509CertImpl signerCertImpl;
1941
if (signerCert instanceof X509CertImpl) {
1942
signerCertImpl = (X509CertImpl) signerCert;
1943
} else {
1944
signerCertImpl = new X509CertImpl(signerCert.getEncoded());
1945
}
1946
1947
X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get(
1948
X509CertImpl.NAME + "." + X509CertImpl.INFO);
1949
X500Name signerSubjectName = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." +
1950
X509CertInfo.DN_NAME);
1951
1952
keypair = new CertAndKeyGen(keyAlgName, sigAlgName, providerName,
1953
signerPrivateKey, signerSubjectName);
1954
1955
signerSubjectKeyId = signerCertImpl.getSubjectKeyId();
1956
if (signerSubjectKeyId == null) {
1957
signerSubjectKeyId = new KeyIdentifier(signerCert.getPublicKey());
1958
}
1959
} else {
1960
keypair = new CertAndKeyGen(keyAlgName, sigAlgName, providerName);
1961
}
1962
1963
// If DN is provided, parse it. Otherwise, prompt the user for it.
1964
X500Name x500Name;
1965
if (dname == null) {
1966
printWeakWarnings(true);
1967
x500Name = getX500Name();
1968
} else {
1969
x500Name = new X500Name(dname);
1970
}
1971
1972
if (groupName != null) {
1973
keypair.generate(groupName);
1974
} else {
1975
// This covers keysize both specified and unspecified
1976
keypair.generate(keysize);
1977
}
1978
1979
CertificateExtensions ext = createV3Extensions(
1980
null,
1981
null,
1982
v3ext,
1983
keypair.getPublicKeyAnyway(),
1984
signerSubjectKeyId);
1985
1986
PrivateKey privKey = keypair.getPrivateKey();
1987
X509Certificate newCert = keypair.getSelfCertificate(
1988
x500Name, getStartDate(startDate), validity*24L*60L*60L, ext);
1989
1990
if (signerAlias != null) {
1991
MessageFormat form = new MessageFormat(rb.getString
1992
("Generating.keysize.bit.keyAlgName.key.pair.and.a.certificate.sigAlgName.issued.by.signerAlias.with.a.validity.of.validality.days.for"));
1993
Object[] source = {
1994
groupName == null ? keysize : KeyUtil.getKeySize(privKey),
1995
fullDisplayAlgName(privKey),
1996
newCert.getSigAlgName(),
1997
signerAlias,
1998
validity,
1999
x500Name};
2000
System.err.println(form.format(source));
2001
} else {
2002
MessageFormat form = new MessageFormat(rb.getString
2003
("Generating.keysize.bit.keyAlgName.key.pair.and.self.signed.certificate.sigAlgName.with.a.validity.of.validality.days.for"));
2004
Object[] source = {
2005
groupName == null ? keysize : KeyUtil.getKeySize(privKey),
2006
fullDisplayAlgName(privKey),
2007
newCert.getSigAlgName(),
2008
validity,
2009
x500Name};
2010
System.err.println(form.format(source));
2011
}
2012
2013
if (keyPass == null) {
2014
keyPass = promptForKeyPass(alias, null, storePass);
2015
}
2016
2017
Certificate[] finalChain;
2018
if (signerAlias != null) {
2019
Certificate[] signerChain = keyStore.getCertificateChain(signerAlias);
2020
finalChain = new X509Certificate[signerChain.length + 1];
2021
finalChain[0] = newCert;
2022
System.arraycopy(signerChain, 0, finalChain, 1, signerChain.length);
2023
} else {
2024
finalChain = new Certificate[] { newCert };
2025
}
2026
checkWeak(rb.getString("the.generated.certificate"), finalChain);
2027
keyStore.setKeyEntry(alias, privKey, keyPass, finalChain);
2028
}
2029
2030
private String ecGroupNameForSize(int size) throws Exception {
2031
AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
2032
ap.init(new ECKeySizeParameterSpec(size));
2033
// The following line assumes the toString value is "name (oid)"
2034
return ap.toString().split(" ")[0];
2035
}
2036
2037
/**
2038
* Clones an entry
2039
* @param orig original alias
2040
* @param dest destination alias
2041
* @changePassword if the password can be changed
2042
*/
2043
private void doCloneEntry(String orig, String dest, boolean changePassword)
2044
throws Exception
2045
{
2046
if (orig == null) {
2047
orig = keyAlias;
2048
}
2049
2050
if (keyStore.containsAlias(dest)) {
2051
MessageFormat form = new MessageFormat
2052
(rb.getString("Destination.alias.dest.already.exists"));
2053
Object[] source = {dest};
2054
throw new Exception(form.format(source));
2055
}
2056
2057
Pair<Entry,char[]> objs = recoverEntry(keyStore, orig, storePass, keyPass);
2058
Entry entry = objs.fst;
2059
keyPass = objs.snd;
2060
2061
PasswordProtection pp = null;
2062
2063
if (keyPass != null) { // protected
2064
if (!changePassword || P12KEYSTORE.equalsIgnoreCase(storetype)) {
2065
keyPassNew = keyPass;
2066
} else {
2067
if (keyPassNew == null) {
2068
keyPassNew = promptForKeyPass(dest, orig, keyPass);
2069
}
2070
}
2071
pp = new PasswordProtection(keyPassNew);
2072
}
2073
keyStore.setEntry(dest, entry, pp);
2074
}
2075
2076
/**
2077
* Changes a key password.
2078
*/
2079
private void doChangeKeyPasswd(String alias) throws Exception
2080
{
2081
2082
if (alias == null) {
2083
alias = keyAlias;
2084
}
2085
Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass);
2086
Key privKey = objs.fst;
2087
if (keyPass == null) {
2088
keyPass = objs.snd;
2089
}
2090
2091
if (keyPassNew == null) {
2092
MessageFormat form = new MessageFormat
2093
(rb.getString("key.password.for.alias."));
2094
Object[] source = {alias};
2095
keyPassNew = getNewPasswd(form.format(source), keyPass);
2096
}
2097
keyStore.setKeyEntry(alias, privKey, keyPassNew,
2098
keyStore.getCertificateChain(alias));
2099
}
2100
2101
/**
2102
* Imports a JDK 1.1-style identity database. We can only store one
2103
* certificate per identity, because we use the identity's name as the
2104
* alias (which references a keystore entry), and aliases must be unique.
2105
*/
2106
private void doImportIdentityDatabase(InputStream in)
2107
throws Exception
2108
{
2109
System.err.println(rb.getString
2110
("No.entries.from.identity.database.added"));
2111
}
2112
2113
/**
2114
* Prints a single keystore entry.
2115
*/
2116
private void doPrintEntry(String label, String alias, PrintStream out)
2117
throws Exception
2118
{
2119
if (keyStore.containsAlias(alias) == false) {
2120
MessageFormat form = new MessageFormat
2121
(rb.getString("Alias.alias.does.not.exist"));
2122
Object[] source = {alias};
2123
throw new Exception(form.format(source));
2124
}
2125
2126
if (verbose || rfc || debug) {
2127
MessageFormat form = new MessageFormat
2128
(rb.getString("Alias.name.alias"));
2129
Object[] source = {alias};
2130
out.println(form.format(source));
2131
2132
if (!token) {
2133
form = new MessageFormat(rb.getString
2134
("Creation.date.keyStore.getCreationDate.alias."));
2135
Object[] src = {keyStore.getCreationDate(alias)};
2136
out.println(form.format(src));
2137
}
2138
} else {
2139
if (!token) {
2140
MessageFormat form = new MessageFormat
2141
(rb.getString("alias.keyStore.getCreationDate.alias."));
2142
Object[] source = {alias, keyStore.getCreationDate(alias)};
2143
out.print(form.format(source));
2144
} else {
2145
MessageFormat form = new MessageFormat
2146
(rb.getString("alias."));
2147
Object[] source = {alias};
2148
out.print(form.format(source));
2149
}
2150
}
2151
2152
if (keyStore.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) {
2153
if (verbose || rfc || debug) {
2154
Object[] source = {"SecretKeyEntry"};
2155
out.println(new MessageFormat(
2156
rb.getString("Entry.type.type.")).format(source));
2157
} else {
2158
out.println("SecretKeyEntry, ");
2159
}
2160
} else if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
2161
if (verbose || rfc || debug) {
2162
Object[] source = {"PrivateKeyEntry"};
2163
out.println(new MessageFormat(
2164
rb.getString("Entry.type.type.")).format(source));
2165
} else {
2166
out.println("PrivateKeyEntry, ");
2167
}
2168
2169
// Get the chain
2170
Certificate[] chain = keyStore.getCertificateChain(alias);
2171
if (chain != null) {
2172
if (verbose || rfc || debug) {
2173
out.println(rb.getString
2174
("Certificate.chain.length.") + chain.length);
2175
for (int i = 0; i < chain.length; i ++) {
2176
MessageFormat form = new MessageFormat
2177
(rb.getString("Certificate.i.1."));
2178
Object[] source = {(i + 1)};
2179
out.println(form.format(source));
2180
if (verbose && (chain[i] instanceof X509Certificate)) {
2181
printX509Cert((X509Certificate)(chain[i]), out);
2182
} else if (debug) {
2183
out.println(chain[i].toString());
2184
} else {
2185
dumpCert(chain[i], out);
2186
}
2187
checkWeak(label, chain[i]);
2188
}
2189
} else {
2190
// Print the digest of the user cert only
2191
out.println
2192
(rb.getString("Certificate.fingerprint.SHA.256.") +
2193
getCertFingerPrint("SHA-256", chain[0]));
2194
checkWeak(label, chain);
2195
}
2196
} else {
2197
out.println(rb.getString
2198
("Certificate.chain.length.") + 0);
2199
}
2200
} else if (keyStore.entryInstanceOf(alias,
2201
KeyStore.TrustedCertificateEntry.class)) {
2202
// We have a trusted certificate entry
2203
Certificate cert = keyStore.getCertificate(alias);
2204
Object[] source = {"trustedCertEntry"};
2205
String mf = new MessageFormat(
2206
rb.getString("Entry.type.type.")).format(source) + "\n";
2207
if (verbose && (cert instanceof X509Certificate)) {
2208
out.println(mf);
2209
printX509Cert((X509Certificate)cert, out);
2210
} else if (rfc) {
2211
out.println(mf);
2212
dumpCert(cert, out);
2213
} else if (debug) {
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 = new Date();
3037
lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L);
3038
CertificateValidity interval = new CertificateValidity(firstDate,
3039
lastDate);
3040
certInfo.set(X509CertInfo.VALIDITY, interval);
3041
3042
// Make new serial number
3043
certInfo.set(X509CertInfo.SERIAL_NUMBER,
3044
CertificateSerialNumber.newRandom64bit(new SecureRandom()));
3045
3046
// Set owner and issuer fields
3047
X500Name owner;
3048
if (dname == null) {
3049
// Get the owner name from the certificate
3050
owner = (X500Name)certInfo.get(X509CertInfo.SUBJECT + "." +
3051
X509CertInfo.DN_NAME);
3052
} else {
3053
// Use the owner name specified at the command line
3054
owner = new X500Name(dname);
3055
certInfo.set(X509CertInfo.SUBJECT + "." +
3056
X509CertInfo.DN_NAME, owner);
3057
}
3058
// Make issuer same as owner (self-signed!)
3059
certInfo.set(X509CertInfo.ISSUER + "." +
3060
X509CertInfo.DN_NAME, owner);
3061
3062
certInfo.set(X509CertInfo.VERSION,
3063
new CertificateVersion(CertificateVersion.V3));
3064
3065
CertificateExtensions ext = createV3Extensions(
3066
null,
3067
(CertificateExtensions)certInfo.get(X509CertInfo.EXTENSIONS),
3068
v3ext,
3069
oldCert.getPublicKey(),
3070
null);
3071
certInfo.set(X509CertInfo.EXTENSIONS, ext);
3072
// Sign the new certificate
3073
X509CertImpl newCert = new X509CertImpl(certInfo);
3074
newCert.sign(privKey, sigAlgName);
3075
3076
// Store the new certificate as a single-element certificate chain
3077
keyStore.setKeyEntry(alias, privKey,
3078
(keyPass != null) ? keyPass : storePass,
3079
new Certificate[] { newCert } );
3080
3081
if (verbose) {
3082
System.err.println(rb.getString("New.certificate.self.signed."));
3083
System.err.print(newCert.toString());
3084
System.err.println();
3085
}
3086
}
3087
3088
/**
3089
* Processes a certificate reply from a certificate authority.
3090
*
3091
* <p>Builds a certificate chain on top of the certificate reply,
3092
* using trusted certificates from the keystore. The chain is complete
3093
* after a self-signed certificate has been encountered. The self-signed
3094
* certificate is considered a root certificate authority, and is stored
3095
* at the end of the chain.
3096
*
3097
* <p>The newly generated chain replaces the old chain associated with the
3098
* key entry.
3099
*
3100
* @return true if the certificate reply was installed, otherwise false.
3101
*/
3102
private boolean installReply(String alias, InputStream in)
3103
throws Exception
3104
{
3105
if (alias == null) {
3106
alias = keyAlias;
3107
}
3108
3109
Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass);
3110
PrivateKey privKey = (PrivateKey)objs.fst;
3111
if (keyPass == null) {
3112
keyPass = objs.snd;
3113
}
3114
3115
Certificate userCert = keyStore.getCertificate(alias);
3116
if (userCert == null) {
3117
MessageFormat form = new MessageFormat
3118
(rb.getString("alias.has.no.public.key.certificate."));
3119
Object[] source = {alias};
3120
throw new Exception(form.format(source));
3121
}
3122
3123
// Read the certificates in the reply
3124
Collection<? extends Certificate> c = generateCertificates(in);
3125
if (c.isEmpty()) {
3126
throw new Exception(rb.getString("Reply.has.no.certificates"));
3127
}
3128
Certificate[] replyCerts = c.toArray(new Certificate[c.size()]);
3129
Certificate[] newChain;
3130
if (replyCerts.length == 1) {
3131
// single-cert reply
3132
newChain = establishCertChain(userCert, replyCerts[0]);
3133
} else {
3134
// cert-chain reply (e.g., PKCS#7)
3135
newChain = validateReply(alias, userCert, replyCerts);
3136
}
3137
3138
// Now store the newly established chain in the keystore. The new
3139
// chain replaces the old one. The chain can be null if user chooses no.
3140
if (newChain != null) {
3141
keyStore.setKeyEntry(alias, privKey,
3142
(keyPass != null) ? keyPass : storePass,
3143
newChain);
3144
return true;
3145
} else {
3146
return false;
3147
}
3148
}
3149
3150
/**
3151
* Imports a certificate and adds it to the list of trusted certificates.
3152
*
3153
* @return true if the certificate was added, otherwise false.
3154
*/
3155
private boolean addTrustedCert(String alias, InputStream in)
3156
throws Exception
3157
{
3158
if (alias == null) {
3159
throw new Exception(rb.getString("Must.specify.alias"));
3160
}
3161
if (keyStore.containsAlias(alias)) {
3162
MessageFormat form = new MessageFormat(rb.getString
3163
("Certificate.not.imported.alias.alias.already.exists"));
3164
Object[] source = {alias};
3165
throw new Exception(form.format(source));
3166
}
3167
3168
// Read the certificate
3169
X509Certificate cert = null;
3170
try {
3171
cert = (X509Certificate)generateCertificate(in);
3172
} catch (ClassCastException | CertificateException ce) {
3173
throw new Exception(rb.getString("Input.not.an.X.509.certificate"));
3174
}
3175
3176
if (noprompt) {
3177
checkWeak(rb.getString("the.input"), cert);
3178
keyStore.setCertificateEntry(alias, cert);
3179
return true;
3180
}
3181
3182
// if certificate is self-signed, make sure it verifies
3183
boolean selfSigned = false;
3184
if (KeyStoreUtil.isSelfSigned(cert)) {
3185
cert.verify(cert.getPublicKey());
3186
selfSigned = true;
3187
}
3188
3189
// check if cert already exists in keystore
3190
String reply = null;
3191
String trustalias = keyStore.getCertificateAlias(cert);
3192
if (trustalias != null) {
3193
MessageFormat form = new MessageFormat(rb.getString
3194
("Certificate.already.exists.in.keystore.under.alias.trustalias."));
3195
Object[] source = {trustalias};
3196
System.err.println(form.format(source));
3197
checkWeak(rb.getString("the.input"), cert);
3198
printWeakWarnings(true);
3199
reply = getYesNoReply
3200
(rb.getString("Do.you.still.want.to.add.it.no."));
3201
} else if (selfSigned) {
3202
if (trustcacerts && (caks != null) &&
3203
((trustalias=caks.getCertificateAlias(cert)) != null)) {
3204
MessageFormat form = new MessageFormat(rb.getString
3205
("Certificate.already.exists.in.system.wide.CA.keystore.under.alias.trustalias."));
3206
Object[] source = {trustalias};
3207
System.err.println(form.format(source));
3208
checkWeak(rb.getString("the.input"), cert);
3209
printWeakWarnings(true);
3210
reply = getYesNoReply
3211
(rb.getString("Do.you.still.want.to.add.it.to.your.own.keystore.no."));
3212
}
3213
if (trustalias == null) {
3214
// Print the cert and ask user if they really want to add
3215
// it to their keystore
3216
printX509Cert(cert, System.out);
3217
checkWeak(rb.getString("the.input"), cert);
3218
printWeakWarnings(true);
3219
reply = getYesNoReply
3220
(rb.getString("Trust.this.certificate.no."));
3221
}
3222
}
3223
if (reply != null) {
3224
if ("YES".equals(reply)) {
3225
keyStore.setCertificateEntry(alias, cert);
3226
return true;
3227
} else {
3228
return false;
3229
}
3230
}
3231
3232
// Not found in this keystore and not self-signed
3233
// Try to establish trust chain
3234
try {
3235
Certificate[] chain = establishCertChain(null, cert);
3236
if (chain != null) {
3237
keyStore.setCertificateEntry(alias, cert);
3238
return true;
3239
}
3240
} catch (Exception e) {
3241
// Print the cert and ask user if they really want to add it to
3242
// their keystore
3243
printX509Cert(cert, System.out);
3244
checkWeak(rb.getString("the.input"), cert);
3245
printWeakWarnings(true);
3246
reply = getYesNoReply
3247
(rb.getString("Trust.this.certificate.no."));
3248
if ("YES".equals(reply)) {
3249
keyStore.setCertificateEntry(alias, cert);
3250
return true;
3251
} else {
3252
return false;
3253
}
3254
}
3255
3256
return false;
3257
}
3258
3259
/**
3260
* Prompts user for new password. New password must be different from
3261
* old one.
3262
*
3263
* @param prompt the message that gets prompted on the screen
3264
* @param oldPasswd the current (i.e., old) password
3265
*/
3266
private char[] getNewPasswd(String prompt, char[] oldPasswd)
3267
throws Exception
3268
{
3269
char[] entered = null;
3270
char[] reentered = null;
3271
3272
for (int count = 0; count < 3; count++) {
3273
MessageFormat form = new MessageFormat
3274
(rb.getString("New.prompt."));
3275
Object[] source = {prompt};
3276
System.err.print(form.format(source));
3277
entered = Password.readPassword(System.in);
3278
passwords.add(entered);
3279
if (entered == null || entered.length < 6) {
3280
System.err.println(rb.getString
3281
("Password.is.too.short.must.be.at.least.6.characters"));
3282
} else if (Arrays.equals(entered, oldPasswd)) {
3283
System.err.println(rb.getString("Passwords.must.differ"));
3284
} else {
3285
form = new MessageFormat
3286
(rb.getString("Re.enter.new.prompt."));
3287
Object[] src = {prompt};
3288
System.err.print(form.format(src));
3289
reentered = Password.readPassword(System.in);
3290
passwords.add(reentered);
3291
if (!Arrays.equals(entered, reentered)) {
3292
System.err.println
3293
(rb.getString("They.don.t.match.Try.again"));
3294
} else {
3295
Arrays.fill(reentered, ' ');
3296
return entered;
3297
}
3298
}
3299
if (entered != null) {
3300
Arrays.fill(entered, ' ');
3301
entered = null;
3302
}
3303
if (reentered != null) {
3304
Arrays.fill(reentered, ' ');
3305
reentered = null;
3306
}
3307
}
3308
throw new Exception(rb.getString("Too.many.failures.try.later"));
3309
}
3310
3311
/**
3312
* Prompts user for alias name.
3313
* @param prompt the {0} of "Enter {0} alias name: " in prompt line
3314
* @return the string entered by the user, without the \n at the end
3315
*/
3316
private String getAlias(String prompt) throws Exception {
3317
if (prompt != null) {
3318
MessageFormat form = new MessageFormat
3319
(rb.getString("Enter.prompt.alias.name."));
3320
Object[] source = {prompt};
3321
System.err.print(form.format(source));
3322
} else {
3323
System.err.print(rb.getString("Enter.alias.name."));
3324
}
3325
return (new BufferedReader(new InputStreamReader(
3326
System.in))).readLine();
3327
}
3328
3329
/**
3330
* Prompts user for an input string from the command line (System.in)
3331
* @prompt the prompt string printed
3332
* @return the string entered by the user, without the \n at the end
3333
*/
3334
private String inputStringFromStdin(String prompt) throws Exception {
3335
System.err.print(prompt);
3336
return (new BufferedReader(new InputStreamReader(
3337
System.in))).readLine();
3338
}
3339
3340
/**
3341
* Prompts user for key password. User may select to choose the same
3342
* password (<code>otherKeyPass</code>) as for <code>otherAlias</code>.
3343
*/
3344
private char[] getKeyPasswd(String alias, String otherAlias,
3345
char[] otherKeyPass)
3346
throws Exception
3347
{
3348
int count = 0;
3349
char[] keyPass = null;
3350
3351
do {
3352
if (otherKeyPass != null) {
3353
MessageFormat form = new MessageFormat(rb.getString
3354
("Enter.key.password.for.alias."));
3355
Object[] source = {alias};
3356
System.err.println(form.format(source));
3357
3358
form = new MessageFormat(rb.getString
3359
(".RETURN.if.same.as.for.otherAlias."));
3360
Object[] src = {otherAlias};
3361
System.err.print(form.format(src));
3362
} else {
3363
MessageFormat form = new MessageFormat(rb.getString
3364
("Enter.key.password.for.alias."));
3365
Object[] source = {alias};
3366
System.err.print(form.format(source));
3367
}
3368
System.err.flush();
3369
keyPass = Password.readPassword(System.in);
3370
passwords.add(keyPass);
3371
if (keyPass == null) {
3372
keyPass = otherKeyPass;
3373
}
3374
count++;
3375
} while ((keyPass == null) && count < 3);
3376
3377
if (keyPass == null) {
3378
throw new Exception(rb.getString("Too.many.failures.try.later"));
3379
}
3380
3381
return keyPass;
3382
}
3383
3384
private String withWeak(String alg) {
3385
if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) {
3386
if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) {
3387
return alg;
3388
} else {
3389
return String.format(rb.getString("with.weak"), alg);
3390
}
3391
} else {
3392
return String.format(rb.getString("with.disabled"), alg);
3393
}
3394
}
3395
3396
private String fullDisplayAlgName(Key key) {
3397
String result = key.getAlgorithm();
3398
if (key instanceof ECKey) {
3399
ECParameterSpec paramSpec = ((ECKey) key).getParams();
3400
if (paramSpec instanceof NamedCurve) {
3401
NamedCurve nc = (NamedCurve)paramSpec;
3402
result += " (" + nc.getNameAndAliases()[0] + ")";
3403
}
3404
} else if (key instanceof EdECKey) {
3405
result = ((EdECKey) key).getParams().getName();
3406
}
3407
return result;
3408
}
3409
3410
private String withWeak(Key key) {
3411
int kLen = KeyUtil.getKeySize(key);
3412
String displayAlg = fullDisplayAlgName(key);
3413
if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
3414
if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
3415
if (kLen >= 0) {
3416
return String.format(rb.getString("key.bit"), kLen, displayAlg);
3417
} else {
3418
return String.format(rb.getString("unknown.size.1"), displayAlg);
3419
}
3420
} else {
3421
return String.format(rb.getString("key.bit.weak"), kLen, displayAlg);
3422
}
3423
} else {
3424
return String.format(rb.getString("key.bit.disabled"), kLen, displayAlg);
3425
}
3426
}
3427
3428
/**
3429
* Prints a certificate in a human readable format.
3430
*/
3431
private void printX509Cert(X509Certificate cert, PrintStream out)
3432
throws Exception
3433
{
3434
3435
MessageFormat form = new MessageFormat
3436
(rb.getString(".PATTERN.printX509Cert.with.weak"));
3437
PublicKey pkey = cert.getPublicKey();
3438
String sigName = cert.getSigAlgName();
3439
// No need to warn about sigalg of a trust anchor
3440
if (!isTrustedCert(cert)) {
3441
sigName = withWeak(sigName);
3442
}
3443
Object[] source = {cert.getSubjectX500Principal().toString(),
3444
cert.getIssuerX500Principal().toString(),
3445
cert.getSerialNumber().toString(16),
3446
cert.getNotBefore().toString(),
3447
cert.getNotAfter().toString(),
3448
getCertFingerPrint("SHA-1", cert),
3449
getCertFingerPrint("SHA-256", cert),
3450
sigName,
3451
withWeak(pkey),
3452
cert.getVersion()
3453
};
3454
out.println(form.format(source));
3455
3456
if (cert instanceof X509CertImpl) {
3457
X509CertImpl impl = (X509CertImpl)cert;
3458
X509CertInfo certInfo = (X509CertInfo)impl.get(X509CertImpl.NAME
3459
+ "." +
3460
X509CertImpl.INFO);
3461
CertificateExtensions exts = (CertificateExtensions)
3462
certInfo.get(X509CertInfo.EXTENSIONS);
3463
if (exts != null) {
3464
printExtensions(rb.getString("Extensions."), exts, out);
3465
}
3466
}
3467
}
3468
3469
private static void printExtensions(String title, CertificateExtensions exts, PrintStream out)
3470
throws Exception {
3471
int extnum = 0;
3472
Iterator<Extension> i1 = exts.getAllExtensions().iterator();
3473
Iterator<Extension> i2 = exts.getUnparseableExtensions().values().iterator();
3474
while (i1.hasNext() || i2.hasNext()) {
3475
Extension ext = i1.hasNext()?i1.next():i2.next();
3476
if (extnum == 0) {
3477
out.println();
3478
out.println(title);
3479
out.println();
3480
}
3481
out.print("#"+(++extnum)+": "+ ext);
3482
if (ext.getClass() == Extension.class) {
3483
byte[] v = ext.getExtensionValue();
3484
if (v.length == 0) {
3485
out.println(rb.getString(".Empty.value."));
3486
} else {
3487
new sun.security.util.HexDumpEncoder().encodeBuffer(ext.getExtensionValue(), out);
3488
out.println();
3489
}
3490
}
3491
out.println();
3492
}
3493
}
3494
3495
/**
3496
* Locates a signer for a given certificate from a given keystore and
3497
* returns the signer's certificate.
3498
* @param cert the certificate whose signer is searched, not null
3499
* @param ks the keystore to search with, not null
3500
* @return <code>cert</code> itself if it's already inside <code>ks</code>,
3501
* or a certificate inside <code>ks</code> who signs <code>cert</code>,
3502
* or null otherwise. A label is added.
3503
*/
3504
private static Pair<String,Certificate>
3505
getSigner(Certificate cert, KeyStore ks) throws Exception {
3506
if (ks.getCertificateAlias(cert) != null) {
3507
return new Pair<>("", cert);
3508
}
3509
for (Enumeration<String> aliases = ks.aliases();
3510
aliases.hasMoreElements(); ) {
3511
String name = aliases.nextElement();
3512
Certificate trustedCert = ks.getCertificate(name);
3513
if (trustedCert != null) {
3514
try {
3515
cert.verify(trustedCert.getPublicKey());
3516
return new Pair<>(name, trustedCert);
3517
} catch (Exception e) {
3518
// Not verified, skip to the next one
3519
}
3520
}
3521
}
3522
return null;
3523
}
3524
3525
/**
3526
* Gets an X.500 name suitable for inclusion in a certification request.
3527
*/
3528
private X500Name getX500Name() throws IOException {
3529
BufferedReader in;
3530
in = new BufferedReader(new InputStreamReader(System.in));
3531
String commonName = "Unknown";
3532
String organizationalUnit = "Unknown";
3533
String organization = "Unknown";
3534
String city = "Unknown";
3535
String state = "Unknown";
3536
String country = "Unknown";
3537
X500Name name;
3538
String userInput = null;
3539
3540
int maxRetry = 20;
3541
do {
3542
if (maxRetry-- < 0) {
3543
throw new RuntimeException(rb.getString(
3544
"Too.many.retries.program.terminated"));
3545
}
3546
commonName = inputString(in,
3547
rb.getString("What.is.your.first.and.last.name."),
3548
commonName);
3549
organizationalUnit = inputString(in,
3550
rb.getString
3551
("What.is.the.name.of.your.organizational.unit."),
3552
organizationalUnit);
3553
organization = inputString(in,
3554
rb.getString("What.is.the.name.of.your.organization."),
3555
organization);
3556
city = inputString(in,
3557
rb.getString("What.is.the.name.of.your.City.or.Locality."),
3558
city);
3559
state = inputString(in,
3560
rb.getString("What.is.the.name.of.your.State.or.Province."),
3561
state);
3562
country = inputString(in,
3563
rb.getString
3564
("What.is.the.two.letter.country.code.for.this.unit."),
3565
country);
3566
name = new X500Name(commonName, organizationalUnit, organization,
3567
city, state, country);
3568
MessageFormat form = new MessageFormat
3569
(rb.getString("Is.name.correct."));
3570
Object[] source = {name};
3571
userInput = inputString
3572
(in, form.format(source), rb.getString("no"));
3573
} while (collator.compare(userInput, rb.getString("yes")) != 0 &&
3574
collator.compare(userInput, rb.getString("y")) != 0);
3575
3576
System.err.println();
3577
return name;
3578
}
3579
3580
private String inputString(BufferedReader in, String prompt,
3581
String defaultValue)
3582
throws IOException
3583
{
3584
System.err.println(prompt);
3585
MessageFormat form = new MessageFormat
3586
(rb.getString(".defaultValue."));
3587
Object[] source = {defaultValue};
3588
System.err.print(form.format(source));
3589
System.err.flush();
3590
3591
String value = in.readLine();
3592
if (value == null || collator.compare(value, "") == 0) {
3593
value = defaultValue;
3594
}
3595
return value;
3596
}
3597
3598
/**
3599
* Writes an X.509 certificate in base64 or binary encoding to an output
3600
* stream.
3601
*/
3602
private void dumpCert(Certificate cert, PrintStream out)
3603
throws IOException, CertificateException
3604
{
3605
if (rfc) {
3606
out.println(X509Factory.BEGIN_CERT);
3607
out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(cert.getEncoded()));
3608
out.println(X509Factory.END_CERT);
3609
} else {
3610
out.write(cert.getEncoded()); // binary
3611
}
3612
}
3613
3614
/**
3615
* Recovers (private) key associated with given alias.
3616
*
3617
* @return an array of objects, where the 1st element in the array is the
3618
* recovered private key, and the 2nd element is the password used to
3619
* recover it.
3620
*/
3621
private Pair<Key,char[]> recoverKey(String alias, char[] storePass,
3622
char[] keyPass)
3623
throws Exception
3624
{
3625
Key key = null;
3626
3627
if (KeyStoreUtil.isWindowsKeyStore(storetype)) {
3628
key = keyStore.getKey(alias, null);
3629
return Pair.of(key, null);
3630
}
3631
3632
if (keyStore.containsAlias(alias) == false) {
3633
MessageFormat form = new MessageFormat
3634
(rb.getString("Alias.alias.does.not.exist"));
3635
Object[] source = {alias};
3636
throw new Exception(form.format(source));
3637
}
3638
if (!keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class) &&
3639
!keyStore.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) {
3640
MessageFormat form = new MessageFormat
3641
(rb.getString("Alias.alias.has.no.key"));
3642
Object[] source = {alias};
3643
throw new Exception(form.format(source));
3644
}
3645
3646
if (keyPass == null) {
3647
// Try to recover the key using the keystore password
3648
if (storePass != null) {
3649
try {
3650
key = keyStore.getKey(alias, storePass);
3651
passwords.add(storePass);
3652
return Pair.of(key, storePass);
3653
} catch (UnrecoverableKeyException e) {
3654
if (token) {
3655
throw e;
3656
}
3657
}
3658
}
3659
// prompt user for key password
3660
keyPass = getKeyPasswd(alias, null, null);
3661
key = keyStore.getKey(alias, keyPass);
3662
return Pair.of(key, keyPass);
3663
} else {
3664
key = keyStore.getKey(alias, keyPass);
3665
return Pair.of(key, keyPass);
3666
}
3667
}
3668
3669
/**
3670
* Recovers entry associated with given alias.
3671
*
3672
* @return an array of objects, where the 1st element in the array is the
3673
* recovered entry, and the 2nd element is the password used to
3674
* recover it (null if no password).
3675
*/
3676
private Pair<Entry,char[]> recoverEntry(KeyStore ks,
3677
String alias,
3678
char[] pstore,
3679
char[] pkey) throws Exception {
3680
3681
if (!ks.containsAlias(alias)) {
3682
MessageFormat form = new MessageFormat(
3683
rb.getString("Alias.alias.does.not.exist"));
3684
Object[] source = {alias};
3685
throw new Exception(form.format(source));
3686
}
3687
3688
// Step 1: First attempt to access entry without key password
3689
// (PKCS11 entry or trusted certificate entry, for example).
3690
// If fail, go next.
3691
try {
3692
Entry entry = ks.getEntry(alias, null);
3693
return Pair.of(entry, null);
3694
} catch (UnrecoverableEntryException une) {
3695
if(P11KEYSTORE.equalsIgnoreCase(ks.getType()) ||
3696
KeyStoreUtil.isWindowsKeyStore(ks.getType())) {
3697
// should not happen, but a possibility
3698
throw une;
3699
}
3700
}
3701
3702
// entry is protected
3703
3704
// Step 2: try pkey if not null. If fail, fail.
3705
if (pkey != null) {
3706
PasswordProtection pp = new PasswordProtection(pkey);
3707
Entry entry = ks.getEntry(alias, pp);
3708
return Pair.of(entry, pkey);
3709
}
3710
3711
// Step 3: try pstore if not null. If fail, go next.
3712
if (pstore != null) {
3713
try {
3714
PasswordProtection pp = new PasswordProtection(pstore);
3715
Entry entry = ks.getEntry(alias, pp);
3716
return Pair.of(entry, pstore);
3717
} catch (UnrecoverableEntryException une) {
3718
if (P12KEYSTORE.equalsIgnoreCase(ks.getType())) {
3719
// P12 keystore currently does not support separate
3720
// store and entry passwords. We will not prompt for
3721
// entry password.
3722
throw une;
3723
}
3724
}
3725
}
3726
3727
// Step 4: prompt for entry password
3728
pkey = getKeyPasswd(alias, null, null);
3729
PasswordProtection pp = new PasswordProtection(pkey);
3730
Entry entry = ks.getEntry(alias, pp);
3731
return Pair.of(entry, pkey);
3732
}
3733
3734
/**
3735
* Gets the requested finger print of the certificate.
3736
*/
3737
private String getCertFingerPrint(String mdAlg, Certificate cert)
3738
throws Exception
3739
{
3740
byte[] encCertInfo = cert.getEncoded();
3741
MessageDigest md = MessageDigest.getInstance(mdAlg);
3742
byte[] digest = md.digest(encCertInfo);
3743
return HexFormat.ofDelimiter(":").withUpperCase().formatHex(digest);
3744
}
3745
3746
/**
3747
* Prints warning about missing integrity check.
3748
*/
3749
private void printNoIntegrityWarning() {
3750
System.err.println();
3751
System.err.println(rb.getString
3752
(".WARNING.WARNING.WARNING."));
3753
System.err.println(rb.getString
3754
(".The.integrity.of.the.information.stored.in.your.keystore."));
3755
System.err.println(rb.getString
3756
(".WARNING.WARNING.WARNING."));
3757
System.err.println();
3758
}
3759
3760
/**
3761
* Validates chain in certification reply, and returns the ordered
3762
* elements of the chain (with user certificate first, and root
3763
* certificate last in the array).
3764
*
3765
* @param alias the alias name
3766
* @param userCert the user certificate of the alias
3767
* @param replyCerts the chain provided in the reply
3768
*/
3769
private Certificate[] validateReply(String alias,
3770
Certificate userCert,
3771
Certificate[] replyCerts)
3772
throws Exception
3773
{
3774
3775
checkWeak(rb.getString("reply"), replyCerts);
3776
3777
// order the certs in the reply (bottom-up).
3778
// we know that all certs in the reply are of type X.509, because
3779
// we parsed them using an X.509 certificate factory
3780
int i;
3781
PublicKey userPubKey = userCert.getPublicKey();
3782
3783
// Remove duplicated certificates.
3784
HashSet<Certificate> nodup = new HashSet<>(Arrays.asList(replyCerts));
3785
replyCerts = nodup.toArray(new Certificate[nodup.size()]);
3786
3787
for (i=0; i<replyCerts.length; i++) {
3788
if (userPubKey.equals(replyCerts[i].getPublicKey())) {
3789
break;
3790
}
3791
}
3792
if (i == replyCerts.length) {
3793
MessageFormat form = new MessageFormat(rb.getString
3794
("Certificate.reply.does.not.contain.public.key.for.alias."));
3795
Object[] source = {alias};
3796
throw new Exception(form.format(source));
3797
}
3798
3799
Certificate tmpCert = replyCerts[0];
3800
replyCerts[0] = replyCerts[i];
3801
replyCerts[i] = tmpCert;
3802
3803
X509Certificate thisCert = (X509Certificate)replyCerts[0];
3804
3805
for (i=1; i < replyCerts.length-1; i++) {
3806
// find a cert in the reply who signs thisCert
3807
int j;
3808
for (j=i; j<replyCerts.length; j++) {
3809
if (KeyStoreUtil.signedBy(thisCert, (X509Certificate)replyCerts[j])) {
3810
tmpCert = replyCerts[i];
3811
replyCerts[i] = replyCerts[j];
3812
replyCerts[j] = tmpCert;
3813
thisCert = (X509Certificate)replyCerts[i];
3814
break;
3815
}
3816
}
3817
if (j == replyCerts.length) {
3818
throw new Exception
3819
(rb.getString("Incomplete.certificate.chain.in.reply"));
3820
}
3821
}
3822
3823
if (noprompt) {
3824
return replyCerts;
3825
}
3826
3827
// do we trust the cert at the top?
3828
Certificate topCert = replyCerts[replyCerts.length-1];
3829
boolean fromKeyStore = true;
3830
Pair<String,Certificate> root = getSigner(topCert, keyStore);
3831
if (root == null && trustcacerts && caks != null) {
3832
root = getSigner(topCert, caks);
3833
fromKeyStore = false;
3834
}
3835
if (root == null) {
3836
System.err.println();
3837
System.err.println
3838
(rb.getString("Top.level.certificate.in.reply."));
3839
printX509Cert((X509Certificate)topCert, System.out);
3840
System.err.println();
3841
System.err.print(rb.getString(".is.not.trusted."));
3842
printWeakWarnings(true);
3843
String reply = getYesNoReply
3844
(rb.getString("Install.reply.anyway.no."));
3845
if ("NO".equals(reply)) {
3846
return null;
3847
}
3848
} else {
3849
if (root.snd != topCert) {
3850
// append the root CA cert to the chain
3851
Certificate[] tmpCerts =
3852
new Certificate[replyCerts.length+1];
3853
System.arraycopy(replyCerts, 0, tmpCerts, 0,
3854
replyCerts.length);
3855
tmpCerts[tmpCerts.length-1] = root.snd;
3856
replyCerts = tmpCerts;
3857
checkWeak(String.format(fromKeyStore
3858
? rb.getString("alias.in.keystore")
3859
: rb.getString("alias.in.cacerts"),
3860
root.fst),
3861
root.snd);
3862
}
3863
}
3864
return replyCerts;
3865
}
3866
3867
/**
3868
* Establishes a certificate chain (using trusted certificates in the
3869
* keystore and cacerts), starting with the reply (certToVerify)
3870
* and ending at a self-signed certificate found in the keystore.
3871
*
3872
* @param userCert optional existing certificate, mostly likely be the
3873
* original self-signed cert created by -genkeypair.
3874
* It must have the same public key as certToVerify
3875
* but cannot be the same cert.
3876
* @param certToVerify the starting certificate to build the chain
3877
* @returns the established chain, might be null if user decides not
3878
*/
3879
private Certificate[] establishCertChain(Certificate userCert,
3880
Certificate certToVerify)
3881
throws Exception
3882
{
3883
if (userCert != null) {
3884
// Make sure that the public key of the certificate reply matches
3885
// the original public key in the keystore
3886
PublicKey origPubKey = userCert.getPublicKey();
3887
PublicKey replyPubKey = certToVerify.getPublicKey();
3888
if (!origPubKey.equals(replyPubKey)) {
3889
throw new Exception(rb.getString
3890
("Public.keys.in.reply.and.keystore.don.t.match"));
3891
}
3892
3893
// If the two certs are identical, we're done: no need to import
3894
// anything
3895
if (certToVerify.equals(userCert)) {
3896
throw new Exception(rb.getString
3897
("Certificate.reply.and.certificate.in.keystore.are.identical"));
3898
}
3899
}
3900
3901
// Build a hash table of all certificates in the keystore.
3902
// Use the subject distinguished name as the key into the hash table.
3903
// All certificates associated with the same subject distinguished
3904
// name are stored in the same hash table entry as a vector.
3905
Hashtable<Principal, Vector<Pair<String,X509Certificate>>> certs = null;
3906
if (keyStore.size() > 0) {
3907
certs = new Hashtable<>(11);
3908
keystorecerts2Hashtable(keyStore, certs);
3909
}
3910
if (trustcacerts) {
3911
if (caks!=null && caks.size()>0) {
3912
if (certs == null) {
3913
certs = new Hashtable<>(11);
3914
}
3915
keystorecerts2Hashtable(caks, certs);
3916
}
3917
}
3918
3919
// start building chain
3920
Vector<Pair<String,X509Certificate>> chain = new Vector<>(2);
3921
if (buildChain(
3922
new Pair<>(rb.getString("the.input"),
3923
(X509Certificate) certToVerify),
3924
chain, certs)) {
3925
for (Pair<String,X509Certificate> p : chain) {
3926
checkWeak(p.fst, p.snd);
3927
}
3928
Certificate[] newChain =
3929
new Certificate[chain.size()];
3930
// buildChain() returns chain with self-signed root-cert first and
3931
// user-cert last, so we need to invert the chain before we store
3932
// it
3933
int j=0;
3934
for (int i=chain.size()-1; i>=0; i--) {
3935
newChain[j] = chain.elementAt(i).snd;
3936
j++;
3937
}
3938
return newChain;
3939
} else {
3940
throw new Exception
3941
(rb.getString("Failed.to.establish.chain.from.reply"));
3942
}
3943
}
3944
3945
/**
3946
* Recursively tries to establish chain from pool of certs starting from
3947
* certToVerify until a self-signed cert is found, and fill the certs found
3948
* into chain. Each cert in the chain signs the next one.
3949
*
3950
* This method is able to recover from an error, say, if certToVerify
3951
* is signed by certA but certA has no issuer in certs and itself is not
3952
* self-signed, the method can try another certB that also signs
3953
* certToVerify and look for signer of certB, etc, etc.
3954
*
3955
* Each cert in chain comes with a label showing its origin. The label is
3956
* used in the warning message when the cert is considered a risk.
3957
*
3958
* @param certToVerify the cert that needs to be verified.
3959
* @param chain the chain that's being built.
3960
* @param certs the pool of trusted certs
3961
*
3962
* @return true if successful, false otherwise.
3963
*/
3964
private boolean buildChain(Pair<String,X509Certificate> certToVerify,
3965
Vector<Pair<String,X509Certificate>> chain,
3966
Hashtable<Principal, Vector<Pair<String,X509Certificate>>> certs) {
3967
if (KeyStoreUtil.isSelfSigned(certToVerify.snd)) {
3968
// reached self-signed root cert;
3969
// no verification needed because it's trusted.
3970
chain.addElement(certToVerify);
3971
return true;
3972
}
3973
3974
Principal issuer = certToVerify.snd.getIssuerX500Principal();
3975
3976
// Get the issuer's certificate(s)
3977
Vector<Pair<String,X509Certificate>> vec = certs.get(issuer);
3978
if (vec == null) {
3979
return false;
3980
}
3981
3982
// Try out each certificate in the vector, until we find one
3983
// whose public key verifies the signature of the certificate
3984
// in question.
3985
for (Enumeration<Pair<String,X509Certificate>> issuerCerts = vec.elements();
3986
issuerCerts.hasMoreElements(); ) {
3987
Pair<String,X509Certificate> issuerCert = issuerCerts.nextElement();
3988
PublicKey issuerPubKey = issuerCert.snd.getPublicKey();
3989
try {
3990
certToVerify.snd.verify(issuerPubKey);
3991
} catch (Exception e) {
3992
continue;
3993
}
3994
if (buildChain(issuerCert, chain, certs)) {
3995
chain.addElement(certToVerify);
3996
return true;
3997
}
3998
}
3999
return false;
4000
}
4001
4002
/**
4003
* Prompts user for yes/no decision.
4004
*
4005
* @return the user's decision, can only be "YES" or "NO"
4006
*/
4007
private String getYesNoReply(String prompt)
4008
throws IOException
4009
{
4010
String reply = null;
4011
int maxRetry = 20;
4012
do {
4013
if (maxRetry-- < 0) {
4014
throw new RuntimeException(rb.getString(
4015
"Too.many.retries.program.terminated"));
4016
}
4017
System.err.print(prompt);
4018
System.err.flush();
4019
reply = (new BufferedReader(new InputStreamReader
4020
(System.in))).readLine();
4021
if (reply == null ||
4022
collator.compare(reply, "") == 0 ||
4023
collator.compare(reply, rb.getString("n")) == 0 ||
4024
collator.compare(reply, rb.getString("no")) == 0) {
4025
reply = "NO";
4026
} else if (collator.compare(reply, rb.getString("y")) == 0 ||
4027
collator.compare(reply, rb.getString("yes")) == 0) {
4028
reply = "YES";
4029
} else {
4030
System.err.println(rb.getString("Wrong.answer.try.again"));
4031
reply = null;
4032
}
4033
} while (reply == null);
4034
return reply;
4035
}
4036
4037
/**
4038
* Stores the (leaf) certificates of a keystore in a hashtable.
4039
* All certs belonging to the same CA are stored in a vector that
4040
* in turn is stored in the hashtable, keyed by the CA's subject DN.
4041
* Each cert comes with a string label that shows its origin and alias.
4042
*/
4043
private void keystorecerts2Hashtable(KeyStore ks,
4044
Hashtable<Principal, Vector<Pair<String,X509Certificate>>> hash)
4045
throws Exception {
4046
4047
for (Enumeration<String> aliases = ks.aliases();
4048
aliases.hasMoreElements(); ) {
4049
String alias = aliases.nextElement();
4050
Certificate cert = ks.getCertificate(alias);
4051
if (cert != null) {
4052
Principal subjectDN = ((X509Certificate)cert).getSubjectX500Principal();
4053
Pair<String,X509Certificate> pair = new Pair<>(
4054
String.format(
4055
rb.getString(ks == caks ?
4056
"alias.in.cacerts" :
4057
"alias.in.keystore"),
4058
alias),
4059
(X509Certificate)cert);
4060
Vector<Pair<String,X509Certificate>> vec = hash.get(subjectDN);
4061
if (vec == null) {
4062
vec = new Vector<>();
4063
vec.addElement(pair);
4064
} else {
4065
if (!vec.contains(pair)) {
4066
vec.addElement(pair);
4067
}
4068
}
4069
hash.put(subjectDN, vec);
4070
}
4071
}
4072
}
4073
4074
/**
4075
* Returns the issue time that's specified the -startdate option
4076
* @param s the value of -startdate option
4077
*/
4078
private static Date getStartDate(String s) throws IOException {
4079
Calendar c = new GregorianCalendar();
4080
if (s != null) {
4081
IOException ioe = new IOException(
4082
rb.getString("Illegal.startdate.value"));
4083
int len = s.length();
4084
if (len == 0) {
4085
throw ioe;
4086
}
4087
if (s.charAt(0) == '-' || s.charAt(0) == '+') {
4088
// Form 1: ([+-]nnn[ymdHMS])+
4089
int start = 0;
4090
while (start < len) {
4091
int sign = 0;
4092
switch (s.charAt(start)) {
4093
case '+': sign = 1; break;
4094
case '-': sign = -1; break;
4095
default: throw ioe;
4096
}
4097
int i = start+1;
4098
for (; i<len; i++) {
4099
char ch = s.charAt(i);
4100
if (ch < '0' || ch > '9') break;
4101
}
4102
if (i == start+1) throw ioe;
4103
int number = Integer.parseInt(s.substring(start+1, i));
4104
if (i >= len) throw ioe;
4105
int unit = 0;
4106
switch (s.charAt(i)) {
4107
case 'y': unit = Calendar.YEAR; break;
4108
case 'm': unit = Calendar.MONTH; break;
4109
case 'd': unit = Calendar.DATE; break;
4110
case 'H': unit = Calendar.HOUR; break;
4111
case 'M': unit = Calendar.MINUTE; break;
4112
case 'S': unit = Calendar.SECOND; break;
4113
default: throw ioe;
4114
}
4115
c.add(unit, sign * number);
4116
start = i + 1;
4117
}
4118
} else {
4119
// Form 2: [yyyy/mm/dd] [HH:MM:SS]
4120
String date = null, time = null;
4121
if (len == 19) {
4122
date = s.substring(0, 10);
4123
time = s.substring(11);
4124
if (s.charAt(10) != ' ')
4125
throw ioe;
4126
} else if (len == 10) {
4127
date = s;
4128
} else if (len == 8) {
4129
time = s;
4130
} else {
4131
throw ioe;
4132
}
4133
if (date != null) {
4134
if (date.matches("\\d\\d\\d\\d\\/\\d\\d\\/\\d\\d")) {
4135
c.set(Integer.valueOf(date.substring(0, 4)),
4136
Integer.valueOf(date.substring(5, 7))-1,
4137
Integer.valueOf(date.substring(8, 10)));
4138
} else {
4139
throw ioe;
4140
}
4141
}
4142
if (time != null) {
4143
if (time.matches("\\d\\d:\\d\\d:\\d\\d")) {
4144
c.set(Calendar.HOUR_OF_DAY, Integer.valueOf(time.substring(0, 2)));
4145
c.set(Calendar.MINUTE, Integer.valueOf(time.substring(3, 5)));
4146
c.set(Calendar.SECOND, Integer.valueOf(time.substring(6, 8)));
4147
c.set(Calendar.MILLISECOND, 0);
4148
} else {
4149
throw ioe;
4150
}
4151
}
4152
}
4153
}
4154
return c.getTime();
4155
}
4156
4157
/**
4158
* Match a command with a command set. The match can be exact, or
4159
* partial, or case-insensitive.
4160
*
4161
* @param s the command provided by user
4162
* @param list the legal command set represented by KnownOIDs enums.
4163
* @return the position of a single match, or -1 if none matched
4164
* @throws Exception if s is ambiguous
4165
*/
4166
private static int oneOf(String s, KnownOIDs... list) throws Exception {
4167
String[] convertedList = new String[list.length];
4168
for (int i = 0; i < list.length; i++) {
4169
convertedList[i] = list[i].stdName();
4170
}
4171
return oneOf(s, convertedList);
4172
}
4173
4174
/**
4175
* Match a command with a command set. The match can be exact, or
4176
* partial, or case-insensitive.
4177
*
4178
* @param s the command provided by user
4179
* @param list the legal command set. If there is a null, commands after it
4180
* are regarded experimental, which means they are supported but their
4181
* existence should not be revealed to user.
4182
* @return the position of a single match, or -1 if none matched
4183
* @throws Exception if s is ambiguous
4184
*/
4185
private static int oneOf(String s, String... list) throws Exception {
4186
4187
// First, if there is an exact match, returns it.
4188
int res = oneOfMatch((a,b) -> a.equals(b), s, list);
4189
if (res >= 0) {
4190
return res;
4191
}
4192
4193
// Second, if there is one single camelCase or prefix match, returns it.
4194
// This regex substitution removes all lowercase letters not at the
4195
// beginning, so "keyCertSign" becomes "kCS".
4196
res = oneOfMatch((a,b) -> a.equals(b.replaceAll("(?<!^)[a-z]", ""))
4197
|| b.startsWith(a), s, list);
4198
if (res >= 0) {
4199
return res;
4200
}
4201
4202
// Finally, retry the 2nd step ignoring case
4203
return oneOfMatch((a,b) -> a.equalsIgnoreCase(b.replaceAll("(?<!^)[a-z]", ""))
4204
|| b.toUpperCase(Locale.ROOT).startsWith(a.toUpperCase(Locale.ROOT)),
4205
s, list);
4206
}
4207
4208
/**
4209
* Match a command with a command set.
4210
*
4211
* @param matcher a BiFunction which returns {@code true} if the 1st
4212
* argument (user input) matches the 2nd one (full command)
4213
* @param s the command provided by user
4214
* @param list the legal command set
4215
* @return the position of a single match, or -1 if none matched
4216
* @throws Exception if s is ambiguous
4217
*/
4218
private static int oneOfMatch(BiFunction<String,String,Boolean> matcher,
4219
String s, String... list) throws Exception {
4220
int[] match = new int[list.length];
4221
int nmatch = 0;
4222
int experiment = Integer.MAX_VALUE;
4223
for (int i = 0; i<list.length; i++) {
4224
String one = list[i];
4225
if (one == null) {
4226
experiment = i;
4227
continue;
4228
}
4229
if (matcher.apply(s, one)) {
4230
match[nmatch++] = i;
4231
}
4232
}
4233
if (nmatch == 0) {
4234
return -1;
4235
} else if (nmatch == 1) {
4236
return match[0];
4237
} else {
4238
// If multiple matches is in experimental commands, ignore them
4239
if (match[1] > experiment) {
4240
return match[0];
4241
}
4242
StringBuilder sb = new StringBuilder();
4243
MessageFormat form = new MessageFormat(rb.getString
4244
("command.{0}.is.ambiguous."));
4245
Object[] source = {s};
4246
sb.append(form.format(source));
4247
sb.append("\n ");
4248
for (int i=0; i<nmatch && match[i]<experiment; i++) {
4249
sb.append(' ');
4250
sb.append(list[match[i]]);
4251
}
4252
throw new Exception(sb.toString());
4253
}
4254
}
4255
4256
/**
4257
* Create a GeneralName object from known types
4258
* @param t one of 5 known types
4259
* @param v value
4260
* @param exttype X.509 extension type
4261
* @return which one
4262
*/
4263
private GeneralName createGeneralName(String t, String v, int exttype)
4264
throws Exception {
4265
GeneralNameInterface gn;
4266
int p = oneOf(t, "EMAIL", "URI", "DNS", "IP", "OID");
4267
if (p < 0) {
4268
throw new Exception(rb.getString(
4269
"Unrecognized.GeneralName.type.") + t);
4270
}
4271
switch (p) {
4272
case 0: gn = new RFC822Name(v); break;
4273
case 1: gn = new URIName(v); break;
4274
case 2:
4275
if (exttype == 3) {
4276
// Allow wildcard only for SAN extension
4277
gn = new DNSName(v, true);
4278
} else {
4279
gn = new DNSName(v);
4280
}
4281
break;
4282
case 3: gn = new IPAddressName(v); break;
4283
default: gn = new OIDName(v); break; //4
4284
}
4285
return new GeneralName(gn);
4286
}
4287
4288
private static final String[] extSupported = {
4289
"BasicConstraints",
4290
"KeyUsage",
4291
"ExtendedKeyUsage",
4292
"SubjectAlternativeName",
4293
"IssuerAlternativeName",
4294
"SubjectInfoAccess",
4295
"AuthorityInfoAccess",
4296
null,
4297
"CRLDistributionPoints",
4298
};
4299
4300
private ObjectIdentifier findOidForExtName(String type)
4301
throws Exception {
4302
switch (oneOf(type, extSupported)) {
4303
case 0: return PKIXExtensions.BasicConstraints_Id;
4304
case 1: return PKIXExtensions.KeyUsage_Id;
4305
case 2: return PKIXExtensions.ExtendedKeyUsage_Id;
4306
case 3: return PKIXExtensions.SubjectAlternativeName_Id;
4307
case 4: return PKIXExtensions.IssuerAlternativeName_Id;
4308
case 5: return PKIXExtensions.SubjectInfoAccess_Id;
4309
case 6: return PKIXExtensions.AuthInfoAccess_Id;
4310
case 8: return PKIXExtensions.CRLDistributionPoints_Id;
4311
default: return ObjectIdentifier.of(type);
4312
}
4313
}
4314
4315
// Add an extension into a CertificateExtensions, always using OID as key
4316
private static void setExt(CertificateExtensions result, Extension ex)
4317
throws IOException {
4318
result.set(ex.getId(), ex);
4319
}
4320
4321
/**
4322
* Create X509v3 extensions from a string representation. Note that the
4323
* SubjectKeyIdentifierExtension will always be created non-critical besides
4324
* the extension requested in the <code>extstr</code> argument.
4325
*
4326
* @param requestedEx the requested extensions, can be null, used for -gencert
4327
* @param existingEx the original extensions, can be null, used for -selfcert
4328
* @param extstrs -ext values, Read keytool doc
4329
* @param pkey the public key for the certificate
4330
* @param aSubjectKeyId the subject key identifier for the authority (issuer)
4331
* @return the created CertificateExtensions
4332
*/
4333
private CertificateExtensions createV3Extensions(
4334
CertificateExtensions requestedEx,
4335
CertificateExtensions existingEx,
4336
List <String> extstrs,
4337
PublicKey pkey,
4338
KeyIdentifier aSubjectKeyId) throws Exception {
4339
4340
// By design, inside a CertificateExtensions object, all known
4341
// extensions uses name (say, "BasicConstraints") as key and
4342
// a child Extension type (say, "BasicConstraintsExtension")
4343
// as value, unknown extensions uses OID as key and bare
4344
// Extension object as value. This works fine inside JDK.
4345
//
4346
// However, in keytool, there is no way to prevent people
4347
// using OID in -ext, either as a new extension, or in a
4348
// honored value. Thus here we (ab)use CertificateExtensions
4349
// by always using OID as key and value can be of any type.
4350
4351
if (existingEx != null && requestedEx != null) {
4352
// This should not happen
4353
throw new Exception("One of request and original should be null.");
4354
}
4355
// A new extensions always using OID as key
4356
CertificateExtensions result = new CertificateExtensions();
4357
if (existingEx != null) {
4358
for (Extension ex: existingEx.getAllExtensions()) {
4359
setExt(result, ex);
4360
}
4361
}
4362
try {
4363
// always non-critical
4364
setExt(result, new SubjectKeyIdentifierExtension(
4365
new KeyIdentifier(pkey).getIdentifier()));
4366
if (aSubjectKeyId != null) {
4367
setExt(result, new AuthorityKeyIdentifierExtension(aSubjectKeyId,
4368
null, null));
4369
}
4370
4371
// name{:critical}{=value}
4372
// Honoring requested extensions
4373
if (requestedEx != null) {
4374
// The existing requestedEx might use names as keys,
4375
// translate to all-OID first.
4376
CertificateExtensions request2 = new CertificateExtensions();
4377
for (sun.security.x509.Extension ex: requestedEx.getAllExtensions()) {
4378
request2.set(ex.getId(), ex);
4379
}
4380
for(String extstr: extstrs) {
4381
if (extstr.toLowerCase(Locale.ENGLISH).startsWith("honored=")) {
4382
List<String> list = Arrays.asList(
4383
extstr.toLowerCase(Locale.ENGLISH).substring(8).split(","));
4384
// First check existence of "all"
4385
if (list.contains("all")) {
4386
for (Extension ex: request2.getAllExtensions()) {
4387
setExt(result, ex);
4388
}
4389
}
4390
// one by one for others
4391
for (String item: list) {
4392
if (item.equals("all")) continue;
4393
4394
// add or remove
4395
boolean add;
4396
// -1, unchanged, 0 critical, 1 non-critical
4397
int action = -1;
4398
String type = null;
4399
if (item.startsWith("-")) {
4400
add = false;
4401
type = item.substring(1);
4402
} else {
4403
add = true;
4404
int colonpos = item.indexOf(':');
4405
if (colonpos >= 0) {
4406
type = item.substring(0, colonpos);
4407
action = oneOf(item.substring(colonpos+1),
4408
"critical", "non-critical");
4409
if (action == -1) {
4410
throw new Exception(rb.getString
4411
("Illegal.value.") + item);
4412
}
4413
} else {
4414
type = item;
4415
}
4416
}
4417
String n = findOidForExtName(type).toString();
4418
if (add) {
4419
Extension e = request2.get(n);
4420
if (!e.isCritical() && action == 0
4421
|| e.isCritical() && action == 1) {
4422
e = Extension.newExtension(
4423
e.getExtensionId(),
4424
!e.isCritical(),
4425
e.getExtensionValue());
4426
}
4427
setExt(result, e);
4428
} else {
4429
result.delete(n);
4430
}
4431
}
4432
break;
4433
}
4434
}
4435
}
4436
for(String extstr: extstrs) {
4437
String name, value;
4438
boolean isCritical = false;
4439
4440
int eqpos = extstr.indexOf('=');
4441
if (eqpos >= 0) {
4442
name = extstr.substring(0, eqpos);
4443
value = extstr.substring(eqpos+1);
4444
} else {
4445
name = extstr;
4446
value = null;
4447
}
4448
4449
int colonpos = name.indexOf(':');
4450
if (colonpos >= 0) {
4451
if (oneOf(name.substring(colonpos+1), "critical") == 0) {
4452
isCritical = true;
4453
}
4454
name = name.substring(0, colonpos);
4455
}
4456
4457
if (name.equalsIgnoreCase("honored")) {
4458
continue;
4459
}
4460
int exttype = oneOf(name, extSupported);
4461
switch (exttype) {
4462
case 0: // BC
4463
int pathLen = -1;
4464
boolean isCA = false;
4465
if (value == null) {
4466
isCA = true;
4467
} else {
4468
try { // the abbr format
4469
pathLen = Integer.parseInt(value);
4470
isCA = true;
4471
} catch (NumberFormatException ufe) {
4472
// ca:true,pathlen:1
4473
for (String part: value.split(",")) {
4474
String[] nv = part.split(":");
4475
if (nv.length != 2) {
4476
throw new Exception(rb.getString
4477
("Illegal.value.") + extstr);
4478
} else {
4479
if (nv[0].equalsIgnoreCase("ca")) {
4480
isCA = Boolean.parseBoolean(nv[1]);
4481
} else if (nv[0].equalsIgnoreCase("pathlen")) {
4482
pathLen = Integer.parseInt(nv[1]);
4483
} else {
4484
throw new Exception(rb.getString
4485
("Illegal.value.") + extstr);
4486
}
4487
}
4488
}
4489
}
4490
}
4491
setExt(result, new BasicConstraintsExtension(isCritical, isCA,
4492
pathLen));
4493
break;
4494
case 1: // KU
4495
if(value != null) {
4496
boolean[] ok = new boolean[9];
4497
for (String s: value.split(",")) {
4498
int p = oneOf(s,
4499
"digitalSignature", // (0),
4500
"nonRepudiation", // (1)
4501
"keyEncipherment", // (2),
4502
"dataEncipherment", // (3),
4503
"keyAgreement", // (4),
4504
"keyCertSign", // (5),
4505
"cRLSign", // (6),
4506
"encipherOnly", // (7),
4507
"decipherOnly", // (8)
4508
"contentCommitment" // also (1)
4509
);
4510
if (p < 0) {
4511
throw new Exception(rb.getString("Unknown.keyUsage.type.") + s);
4512
}
4513
if (p == 9) p = 1;
4514
ok[p] = true;
4515
}
4516
KeyUsageExtension kue = new KeyUsageExtension(ok);
4517
// The above KeyUsageExtension constructor does not
4518
// allow isCritical value, so...
4519
setExt(result, Extension.newExtension(
4520
kue.getExtensionId(),
4521
isCritical,
4522
kue.getExtensionValue()));
4523
} else {
4524
throw new Exception(rb.getString
4525
("Illegal.value.") + extstr);
4526
}
4527
break;
4528
case 2: // EKU
4529
if(value != null) {
4530
Vector<ObjectIdentifier> v = new Vector<>();
4531
KnownOIDs[] choices = {
4532
KnownOIDs.anyExtendedKeyUsage,
4533
KnownOIDs.serverAuth,
4534
KnownOIDs.clientAuth,
4535
KnownOIDs.codeSigning,
4536
KnownOIDs.emailProtection,
4537
KnownOIDs.KP_TimeStamping,
4538
KnownOIDs.OCSPSigning
4539
};
4540
for (String s: value.split(",")) {
4541
int p = oneOf(s, choices);
4542
String o = s;
4543
if (p >= 0) {
4544
o = choices[p].value();
4545
}
4546
try {
4547
v.add(ObjectIdentifier.of(o));
4548
} catch (Exception e) {
4549
throw new Exception(rb.getString(
4550
"Unknown.extendedkeyUsage.type.") + s);
4551
}
4552
}
4553
setExt(result, new ExtendedKeyUsageExtension(isCritical, v));
4554
} else {
4555
throw new Exception(rb.getString
4556
("Illegal.value.") + extstr);
4557
}
4558
break;
4559
case 3: // SAN
4560
case 4: // IAN
4561
if(value != null) {
4562
String[] ps = value.split(",");
4563
GeneralNames gnames = new GeneralNames();
4564
for(String item: ps) {
4565
colonpos = item.indexOf(':');
4566
if (colonpos < 0) {
4567
throw new Exception("Illegal item " + item + " in " + extstr);
4568
}
4569
String t = item.substring(0, colonpos);
4570
String v = item.substring(colonpos+1);
4571
gnames.add(createGeneralName(t, v, exttype));
4572
}
4573
if (exttype == 3) {
4574
setExt(result, new SubjectAlternativeNameExtension(
4575
isCritical, gnames));
4576
} else {
4577
setExt(result, new IssuerAlternativeNameExtension(
4578
isCritical, gnames));
4579
}
4580
} else {
4581
throw new Exception(rb.getString
4582
("Illegal.value.") + extstr);
4583
}
4584
break;
4585
case 5: // SIA, always non-critical
4586
case 6: // AIA, always non-critical
4587
if (isCritical) {
4588
throw new Exception(rb.getString(
4589
"This.extension.cannot.be.marked.as.critical.") + extstr);
4590
}
4591
if(value != null) {
4592
List<AccessDescription> accessDescriptions =
4593
new ArrayList<>();
4594
String[] ps = value.split(",");
4595
for(String item: ps) {
4596
colonpos = item.indexOf(':');
4597
int colonpos2 = item.indexOf(':', colonpos+1);
4598
if (colonpos < 0 || colonpos2 < 0) {
4599
throw new Exception(rb.getString
4600
("Illegal.value.") + extstr);
4601
}
4602
String m = item.substring(0, colonpos);
4603
String t = item.substring(colonpos+1, colonpos2);
4604
String v = item.substring(colonpos2+1);
4605
KnownOIDs[] choices = {
4606
KnownOIDs.OCSP,
4607
KnownOIDs.caIssuers,
4608
KnownOIDs.AD_TimeStamping,
4609
KnownOIDs.caRepository
4610
};
4611
int p = oneOf(m, choices);
4612
ObjectIdentifier oid;
4613
if (p >= 0) {
4614
oid = ObjectIdentifier.of(choices[p]);
4615
} else {
4616
try {
4617
oid = ObjectIdentifier.of(m);
4618
} catch (Exception e) {
4619
throw new Exception(rb.getString(
4620
"Unknown.AccessDescription.type.") + m);
4621
}
4622
}
4623
accessDescriptions.add(new AccessDescription(
4624
oid, createGeneralName(t, v, exttype)));
4625
}
4626
if (exttype == 5) {
4627
setExt(result, new SubjectInfoAccessExtension(accessDescriptions));
4628
} else {
4629
setExt(result, new AuthorityInfoAccessExtension(accessDescriptions));
4630
}
4631
} else {
4632
throw new Exception(rb.getString
4633
("Illegal.value.") + extstr);
4634
}
4635
break;
4636
case 8: // CRL, experimental, only support 1 distributionpoint
4637
if(value != null) {
4638
String[] ps = value.split(",");
4639
GeneralNames gnames = new GeneralNames();
4640
for(String item: ps) {
4641
colonpos = item.indexOf(':');
4642
if (colonpos < 0) {
4643
throw new Exception("Illegal item " + item + " in " + extstr);
4644
}
4645
String t = item.substring(0, colonpos);
4646
String v = item.substring(colonpos+1);
4647
gnames.add(createGeneralName(t, v, exttype));
4648
}
4649
setExt(result, new CRLDistributionPointsExtension(
4650
isCritical, Collections.singletonList(
4651
new DistributionPoint(gnames, null, null))));
4652
} else {
4653
throw new Exception(rb.getString
4654
("Illegal.value.") + extstr);
4655
}
4656
break;
4657
case -1:
4658
ObjectIdentifier oid = ObjectIdentifier.of(name);
4659
byte[] data = null;
4660
if (value != null) {
4661
data = new byte[value.length() / 2 + 1];
4662
int pos = 0;
4663
for (char c: value.toCharArray()) {
4664
if (!HexFormat.isHexDigit(c)) {
4665
continue;
4666
}
4667
int hex = HexFormat.fromHexDigit(c);
4668
if (pos % 2 == 0) {
4669
data[pos/2] = (byte)(hex << 4);
4670
} else {
4671
data[pos/2] += hex;
4672
}
4673
pos++;
4674
}
4675
if (pos % 2 != 0) {
4676
throw new Exception(rb.getString(
4677
"Odd.number.of.hex.digits.found.") + extstr);
4678
}
4679
data = Arrays.copyOf(data, pos/2);
4680
} else {
4681
data = new byte[0];
4682
}
4683
setExt(result, new Extension(oid, isCritical,
4684
new DerValue(DerValue.tag_OctetString, data)
4685
.toByteArray()));
4686
break;
4687
default:
4688
throw new Exception(rb.getString(
4689
"Unknown.extension.type.") + extstr);
4690
}
4691
}
4692
} catch(IOException e) {
4693
throw new RuntimeException(e);
4694
}
4695
return result;
4696
}
4697
4698
private boolean isTrustedCert(Certificate cert) throws KeyStoreException {
4699
if (caks != null && caks.getCertificateAlias(cert) != null) {
4700
return true;
4701
} else {
4702
String inKS = keyStore.getCertificateAlias(cert);
4703
return inKS != null && keyStore.isCertificateEntry(inKS);
4704
}
4705
}
4706
4707
private void checkWeak(String label, String sigAlg, Key key) {
4708
if (sigAlg != null) {
4709
if (!DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, sigAlg, null)) {
4710
weakWarnings.add(String.format(
4711
rb.getString("whose.sigalg.disabled"), label, sigAlg));
4712
} else if (!LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, sigAlg, null)) {
4713
weakWarnings.add(String.format(
4714
rb.getString("whose.sigalg.weak"), label, sigAlg));
4715
}
4716
}
4717
4718
if (key != null) {
4719
if (!DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
4720
weakWarnings.add(String.format(
4721
rb.getString("whose.key.disabled"), label,
4722
String.format(rb.getString("key.bit"),
4723
KeyUtil.getKeySize(key), fullDisplayAlgName(key))));
4724
} else if (!LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
4725
weakWarnings.add(String.format(
4726
rb.getString("whose.key.weak"), label,
4727
String.format(rb.getString("key.bit"),
4728
KeyUtil.getKeySize(key), fullDisplayAlgName(key))));
4729
}
4730
}
4731
}
4732
4733
private void checkWeak(String label, Certificate[] certs)
4734
throws KeyStoreException {
4735
for (int i = 0; i < certs.length; i++) {
4736
Certificate cert = certs[i];
4737
if (cert instanceof X509Certificate) {
4738
X509Certificate xc = (X509Certificate)cert;
4739
String fullLabel = label;
4740
if (certs.length > 1) {
4741
fullLabel = oneInMany(label, i, certs.length);
4742
}
4743
checkWeak(fullLabel, xc);
4744
}
4745
}
4746
}
4747
4748
private void checkWeak(String label, Certificate cert)
4749
throws KeyStoreException {
4750
if (cert instanceof X509Certificate) {
4751
X509Certificate xc = (X509Certificate)cert;
4752
// No need to check the sigalg of a trust anchor
4753
String sigAlg = isTrustedCert(cert) ? null : xc.getSigAlgName();
4754
checkWeak(label, sigAlg, xc.getPublicKey());
4755
}
4756
}
4757
4758
private void checkWeak(String label, PKCS10 p10) {
4759
checkWeak(label, p10.getSigAlg(), p10.getSubjectPublicKeyInfo());
4760
}
4761
4762
private void checkWeak(String label, CRL crl, Key key) {
4763
if (crl instanceof X509CRLImpl) {
4764
X509CRLImpl impl = (X509CRLImpl)crl;
4765
checkWeak(label, impl.getSigAlgName(), key);
4766
}
4767
}
4768
4769
private void printWeakWarnings(boolean newLine) {
4770
if (!weakWarnings.isEmpty() && !nowarn) {
4771
System.err.println("\nWarning:");
4772
for (String warning : weakWarnings) {
4773
System.err.println(warning);
4774
}
4775
if (newLine) {
4776
// When calling before a yes/no prompt, add a new line
4777
System.err.println();
4778
}
4779
}
4780
weakWarnings.clear();
4781
}
4782
4783
/**
4784
* Prints the usage of this tool.
4785
*/
4786
private void usage() {
4787
if (command != null) {
4788
System.err.println("keytool " + command +
4789
rb.getString(".OPTION."));
4790
System.err.println();
4791
System.err.println(rb.getString(command.description));
4792
System.err.println();
4793
System.err.println(rb.getString("Options."));
4794
System.err.println();
4795
4796
// Left and right sides of the options list. Both might
4797
// contain "\n" and span multiple lines
4798
String[] left = new String[command.options.length];
4799
String[] right = new String[command.options.length];
4800
4801
// Length of left side of options list
4802
int lenLeft = 0;
4803
4804
for (int j = 0; j < command.options.length; j++) {
4805
Option opt = command.options[j];
4806
left[j] = opt.toString();
4807
if (opt.arg != null) {
4808
left[j] += " " + opt.arg;
4809
}
4810
String[] lefts = left[j].split("\n");
4811
for (String s : lefts) {
4812
if (s.length() > lenLeft) {
4813
lenLeft = s.length();
4814
}
4815
}
4816
right[j] = rb.getString(opt.description);
4817
}
4818
for (int j = 0; j < left.length; j++) {
4819
String[] lefts = left[j].split("\n");
4820
String[] rights = right[j].split("\n");
4821
for (int i = 0; i < lefts.length && i < rights.length; i++) {
4822
String s1 = i < lefts.length ? lefts[i] : "";
4823
String s2 = i < rights.length ? rights[i] : "";
4824
if (i == 0) {
4825
System.err.printf(" %-" + lenLeft + "s %s\n", s1, s2);
4826
} else {
4827
System.err.printf(" %-" + lenLeft + "s %s\n", s1, s2);
4828
}
4829
}
4830
}
4831
System.err.println();
4832
System.err.println(rb.getString(
4833
"Use.keytool.help.for.all.available.commands"));
4834
} else {
4835
System.err.println(rb.getString(
4836
"Key.and.Certificate.Management.Tool"));
4837
System.err.println();
4838
System.err.println(rb.getString("Commands."));
4839
System.err.println();
4840
for (Command c: Command.values()) {
4841
if (c == KEYCLONE) break;
4842
System.err.printf(" %-20s%s\n", c, rb.getString(c.description));
4843
}
4844
System.err.println();
4845
System.err.println(rb.getString(
4846
"Use.keytool.help.for.all.available.commands"));
4847
System.err.println(rb.getString(
4848
"Use.keytool.command.name.help.for.usage.of.command.name"));
4849
}
4850
}
4851
4852
private void tinyHelp() {
4853
usage();
4854
if (debug) {
4855
throw new RuntimeException("NO BIG ERROR, SORRY");
4856
} else {
4857
System.exit(1);
4858
}
4859
}
4860
4861
private void errorNeedArgument(String flag) {
4862
Object[] source = {flag};
4863
System.err.println(new MessageFormat(
4864
rb.getString("Command.option.flag.needs.an.argument.")).format(source));
4865
tinyHelp();
4866
}
4867
4868
private char[] getPass(String modifier, String arg) {
4869
char[] output =
4870
KeyStoreUtil.getPassWithModifier(modifier, arg, rb, collator);
4871
if (output != null) return output;
4872
tinyHelp();
4873
return null; // Useless, tinyHelp() already exits.
4874
}
4875
}
4876
4877
// This class is exactly the same as com.sun.tools.javac.util.Pair,
4878
// it's copied here since the original one is not included in JRE.
4879
class Pair<A, B> {
4880
4881
public final A fst;
4882
public final B snd;
4883
4884
public Pair(A fst, B snd) {
4885
this.fst = fst;
4886
this.snd = snd;
4887
}
4888
4889
public String toString() {
4890
return "Pair[" + fst + "," + snd + "]";
4891
}
4892
4893
public boolean equals(Object other) {
4894
return
4895
other instanceof Pair &&
4896
Objects.equals(fst, ((Pair)other).fst) &&
4897
Objects.equals(snd, ((Pair)other).snd);
4898
}
4899
4900
public int hashCode() {
4901
if (fst == null) return (snd == null) ? 0 : snd.hashCode() + 1;
4902
else if (snd == null) return fst.hashCode() + 2;
4903
else return fst.hashCode() * 17 + snd.hashCode();
4904
}
4905
4906
public static <A,B> Pair<A,B> of(A a, B b) {
4907
return new Pair<>(a,b);
4908
}
4909
}
4910
4911
4912