< prev index next >
src/share/classes/sun/security/tools/keytool/Main.java
Print this page
rev 12520 : 8029659: Keytool, print key algorithm of certificate or key entry
Reviewed-by: xuelei
rev 12521 : 8057810: New defaults for DSA keys in jarsigner and keytool
Reviewed-by: coffeys, valeriep
Contributed-by: prasadarao.koppula@oracle.com
rev 12532 : 8171319: keytool should print out warnings when reading or generating cert/cert req using weak algorithms
Reviewed-by: coffeys
rev 12537 : 8177569: keytool should not warn if signature algorithm used in cacerts is weak
Reviewed-by: mullan
rev 12543 : 8181048: Refactor existing providers to refer to the same constants for default values for key length
Reviewed-by: mullan, ahgross
rev 12549 : 8182879: Add warnings to keytool when using JKS and JCEKS
Reviewed-by: mullan, weijun
rev 12558 : 8186503: sun/security/tools/jarsigner/DefaultSigalg.java failed after backport to JDK 6/7/8
Reviewed-by: bgopularam
*** 1,7 ****
/*
! * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 24,34 ****
--- 24,37 ----
*/
package sun.security.tools.keytool;
import java.io.*;
+ import java.nio.file.Files;
+ import java.nio.file.Paths;
import java.security.CodeSigner;
+ import java.security.CryptoPrimitive;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.Key;
import java.security.PublicKey;
*** 62,77 ****
--- 65,84 ----
import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
import java.security.cert.X509CRLSelector;
import javax.security.auth.x500.X500Principal;
import java.util.Base64;
+
+ import sun.security.util.DisabledAlgorithmConstraints;
+ import sun.security.util.KeyUtil;
import sun.security.util.ObjectIdentifier;
import sun.security.pkcs10.PKCS10;
import sun.security.pkcs10.PKCS10Attribute;
import sun.security.provider.X509Factory;
import sun.security.provider.certpath.CertStoreHelper;
import sun.security.util.Password;
+ import sun.security.util.SecurityProviderConstants;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
*** 145,154 ****
--- 152,162 ----
private boolean token = false;
private boolean nullStream = false;
private boolean kssave = false;
private boolean noprompt = false;
private boolean trustcacerts = false;
+ private boolean nowarn = false;
private boolean protectedPath = false;
private boolean srcprotectedPath = false;
private CertificateFactory cf = null;
private KeyStore caks = null; // "cacerts" keystore
private char[] srcstorePass = null;
*** 157,166 ****
--- 165,189 ----
private String startDate = null;
private List<String> ids = new ArrayList<>(); // used in GENCRL
private List<String> v3ext = new ArrayList<>();
+ // In-place importkeystore is special.
+ // A backup is needed, and no need to prompt for deststorepass.
+ private boolean inplaceImport = false;
+ private String inplaceBackupName = null;
+
+ // Warnings on weak algorithms etc
+ private List<String> weakWarnings = new ArrayList<>();
+
+ private static final DisabledAlgorithmConstraints DISABLED_CHECK =
+ new DisabledAlgorithmConstraints(
+ DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
+
+ private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections
+ .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
+
enum Command {
CERTREQ("Generates.a.certificate.request",
ALIAS, SIGALG, FILEOUT, KEYPASS, KEYSTORE, DNAME,
STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS,
PROVIDERARG, PROVIDERPATH, V, PROTECTED),
*** 315,325 ****
private static final Class<?>[] PARAM_STRING = { String.class };
private static final String NONE = "NONE";
private static final String P11KEYSTORE = "PKCS11";
private static final String P12KEYSTORE = "PKCS12";
! private final String keyAlias = "mykey";
// for i18n
private static final java.util.ResourceBundle rb =
java.util.ResourceBundle.getBundle(
"sun.security.tools.keytool.Resources");
--- 338,348 ----
private static final Class<?>[] PARAM_STRING = { String.class };
private static final String NONE = "NONE";
private static final String P11KEYSTORE = "PKCS11";
private static final String P12KEYSTORE = "PKCS12";
! private static final String keyAlias = "mykey";
// for i18n
private static final java.util.ResourceBundle rb =
java.util.ResourceBundle.getBundle(
"sun.security.tools.keytool.Resources");
*** 351,360 ****
--- 374,384 ----
System.exit(1);
} else {
throw e;
}
} finally {
+ printWeakWarnings(false);
for (char[] pass : passwords) {
if (pass != null) {
Arrays.fill(pass, ' ');
pass = null;
}
*** 418,433 ****
command = GENKEYPAIR;
} else if (collator.compare(flags, "-import") == 0) {
command = IMPORTCERT;
} else if (collator.compare(flags, "-importpassword") == 0) {
command = IMPORTPASS;
! }
! /*
! * Help
! */
! else if (collator.compare(flags, "-help") == 0) {
help = true;
}
/*
* specifiers
*/
--- 442,455 ----
command = GENKEYPAIR;
} else if (collator.compare(flags, "-import") == 0) {
command = IMPORTCERT;
} else if (collator.compare(flags, "-importpassword") == 0) {
command = IMPORTPASS;
! } else if (collator.compare(flags, "-help") == 0) {
help = true;
+ } else if (collator.compare(flags, "-nowarn") == 0) {
+ nowarn = true;
}
/*
* specifiers
*/
*** 711,732 ****
if (destKeyPass != null && destKeyPass.length < 6) {
throw new Exception(rb.getString
("New.password.must.be.at.least.6.characters"));
}
// Check if keystore exists.
// If no keystore has been specified at the command line, try to use
// the default, which is located in $HOME/.keystore.
// If the command is "genkey", "identitydb", "import", or "printcert",
// it is OK not to have a keystore.
- if (isKeyStoreRelated(command)) {
- if (ksfname == null) {
- ksfname = System.getProperty("user.home") + File.separator
- + ".keystore";
- }
! if (!nullStream) {
try {
ksfile = new File(ksfname);
// Check if keystore file is empty
if (ksfile.exists() && ksfile.length() == 0) {
throw new Exception(rb.getString
--- 733,770 ----
if (destKeyPass != null && destKeyPass.length < 6) {
throw new Exception(rb.getString
("New.password.must.be.at.least.6.characters"));
}
+ // Set this before inplaceImport check so we can compare name.
+ if (ksfname == null) {
+ ksfname = System.getProperty("user.home") + File.separator
+ + ".keystore";
+ }
+
+ KeyStore srcKeyStore = null;
+ if (command == IMPORTKEYSTORE) {
+ inplaceImport = inplaceImportCheck();
+ if (inplaceImport) {
+ // We load srckeystore first so we have srcstorePass that
+ // can be assigned to storePass
+ srcKeyStore = loadSourceKeyStore();
+ if (storePass == null) {
+ storePass = srcstorePass;
+ }
+ }
+ }
+
// Check if keystore exists.
// If no keystore has been specified at the command line, try to use
// the default, which is located in $HOME/.keystore.
// If the command is "genkey", "identitydb", "import", or "printcert",
// it is OK not to have a keystore.
! // DO NOT open the existing keystore if this is an in-place import.
! // The keystore should be created as brand new.
! if (isKeyStoreRelated(command) && !nullStream && !inplaceImport) {
try {
ksfile = new File(ksfname);
// Check if keystore file is empty
if (ksfile.exists() && ksfile.length() == 0) {
throw new Exception(rb.getString
*** 744,754 ****
throw new Exception(rb.getString
("Keystore.file.does.not.exist.") + ksfname);
}
}
}
- }
if ((command == KEYCLONE || command == CHANGEALIAS)
&& dest == null) {
dest = getAlias("destination");
if ("".equals(dest)) {
--- 782,791 ----
*** 790,800 ****
--- 827,841 ----
* keystore format and integrity are checked "at the same time".
*
* Null stream keystores are loaded later.
*/
if (!nullStream) {
+ if (inplaceImport) {
+ keyStore.load(null, storePass);
+ } else {
keyStore.load(ksStream, storePass);
+ }
if (ksStream != null) {
ksStream.close();
}
}
*** 918,927 ****
--- 959,975 ----
if (command == PRINTCERT || command == IMPORTCERT
|| command == IDENTITYDB || command == PRINTCRL) {
cf = CertificateFactory.getInstance("X509");
}
+ // -trustcacerts can only be specified on -importcert.
+ // Reset it so that warnings on CA cert will remain for
+ // -printcert, etc.
+ if (command != IMPORTCERT) {
+ trustcacerts = false;
+ }
+
if (trustcacerts) {
caks = KeyStoreUtil.getCacertsKeyStore();
}
// Perform the specified command
*** 1019,1029 ****
if (inStream != System.in) {
inStream.close();
}
}
} else if (command == IMPORTKEYSTORE) {
! doImportKeyStore();
kssave = true;
} else if (command == KEYCLONE) {
keyPassNew = newPass;
// added to make sure only key can go thru
--- 1067,1081 ----
if (inStream != System.in) {
inStream.close();
}
}
} else if (command == IMPORTKEYSTORE) {
! // When not in-place import, srcKeyStore is not loaded yet.
! if (srcKeyStore == null) {
! srcKeyStore = loadSourceKeyStore();
! }
! doImportKeyStore(srcKeyStore);
kssave = true;
} else if (command == KEYCLONE) {
keyPassNew = newPass;
// added to make sure only key can go thru
*** 1058,1069 ****
} else if (command == KEYPASSWD) {
keyPassNew = newPass;
doChangeKeyPasswd(alias);
kssave = true;
} else if (command == LIST) {
if (alias != null) {
! doPrintEntry(alias, out, true);
} else {
doPrintEntries(out);
}
} else if (command == PRINTCERT) {
doPrintCert(out);
--- 1110,1126 ----
} else if (command == KEYPASSWD) {
keyPassNew = newPass;
doChangeKeyPasswd(alias);
kssave = true;
} else if (command == LIST) {
+ if (storePass == null
+ && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
+ printNoIntegrityWarning();
+ }
+
if (alias != null) {
! doPrintEntry(rb.getString("the.certificate"), alias, out);
} else {
doPrintEntries(out);
}
} else if (command == PRINTCERT) {
doPrintCert(out);
*** 1145,1154 ****
--- 1202,1270 ----
fout.write(bout.toByteArray());
}
}
}
}
+
+ if (isKeyStoreRelated(command)
+ && !token && !nullStream && ksfname != null) {
+
+ // JKS storetype warning on the final result keystore
+ File f = new File(ksfname);
+ if (f.exists()) {
+ // Read the first 4 bytes to determine
+ // if we're dealing with JKS/JCEKS type store
+ String realType = keyStoreType(f);
+ if (realType.equalsIgnoreCase("JKS")
+ || realType.equalsIgnoreCase("JCEKS")) {
+ boolean allCerts = true;
+ for (String a : Collections.list(keyStore.aliases())) {
+ if (!keyStore.entryInstanceOf(
+ a, TrustedCertificateEntry.class)) {
+ allCerts = false;
+ break;
+ }
+ }
+ // Don't warn for "cacerts" style keystore.
+ if (!allCerts) {
+ weakWarnings.add(String.format(
+ rb.getString("jks.storetype.warning"),
+ realType, ksfname));
+ }
+ }
+ if (inplaceImport) {
+ String realSourceStoreType =
+ keyStoreType(new File(inplaceBackupName));
+ String format =
+ realType.equalsIgnoreCase(realSourceStoreType) ?
+ rb.getString("backup.keystore.warning") :
+ rb.getString("migrate.keystore.warning");
+ weakWarnings.add(
+ String.format(format,
+ srcksfname,
+ realSourceStoreType,
+ inplaceBackupName,
+ realType));
+ }
+ }
+ }
+ }
+
+ private String keyStoreType(File f) throws IOException {
+ int MAGIC = 0xfeedfeed;
+ int JCEKS_MAGIC = 0xcececece;
+ try (DataInputStream dis = new DataInputStream(
+ new FileInputStream(f))) {
+ int xMagic = dis.readInt();
+ if (xMagic == MAGIC) {
+ return "JKS";
+ } else if (xMagic == JCEKS_MAGIC) {
+ return "JCEKS";
+ } else {
+ return "Non JKS/JCEKS";
+ }
+ }
}
/**
* Generate a certificate: Read PKCS10 request from in, and print
* certificate to out. Use alias as CA, sigAlgName as the signature
*** 1156,1165 ****
--- 1272,1287 ----
*/
private void doGenCert(String alias, String sigAlgName, InputStream in, PrintStream out)
throws Exception {
+ if (keyStore.containsAlias(alias) == false) {
+ MessageFormat form = new MessageFormat
+ (rb.getString("Alias.alias.does.not.exist"));
+ Object[] source = {alias};
+ throw new Exception(form.format(source));
+ }
Certificate signerCert = keyStore.getCertificate(alias);
byte[] encoded = signerCert.getEncoded();
X509CertImpl signerCertImpl = new X509CertImpl(encoded);
X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get(
X509CertImpl.NAME + "." + X509CertImpl.INFO);
*** 1209,1218 ****
--- 1331,1342 ----
}
}
byte[] rawReq = Pem.decode(new String(sb));
PKCS10 req = new PKCS10(rawReq);
+ checkWeak(rb.getString("the.certificate.request"), req);
+
info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo()));
info.set(X509CertInfo.SUBJECT,
dname==null?req.getSubjectName():new X500Name(dname));
CertificateExtensions reqex = null;
Iterator<PKCS10Attribute> attrs = req.getAttributes().getAttributes().iterator();
*** 1238,1247 ****
--- 1362,1374 ----
if (!isSelfSigned(xca)) {
dumpCert(xca, out);
}
}
}
+
+ checkWeak(rb.getString("the.issuer"), keyStore.getCertificateChain(alias));
+ checkWeak(rb.getString("the.generated.certificate"), cert);
}
private void doGenCRL(PrintStream out)
throws Exception {
if (ids == null) {
*** 1288,1297 ****
--- 1415,1425 ----
out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(crl.getEncodedInternal()));
out.println("-----END X509 CRL-----");
} else {
out.write(crl.getEncodedInternal());
}
+ checkWeak(rb.getString("the.generated.crl"), crl, privateKey);
}
/**
* Creates a PKCS#10 cert signing request, corresponding to the
* keys (and name) associated with a given alias.
*** 1334,1343 ****
--- 1462,1473 ----
new X500Name(dname);
// Sign the request and base-64 encode it
request.encodeAndSign(subject, signature);
request.print(out);
+
+ checkWeak(rb.getString("the.generated.certificate.request"), request);
}
/**
* Deletes an entry from the keystore.
*/
*** 1357,1367 ****
private void doExportCert(String alias, PrintStream out)
throws Exception
{
if (storePass == null
&& !KeyStoreUtil.isWindowsKeyStore(storetype)) {
! printWarning();
}
if (alias == null) {
alias = keyAlias;
}
if (keyStore.containsAlias(alias) == false) {
--- 1487,1497 ----
private void doExportCert(String alias, PrintStream out)
throws Exception
{
if (storePass == null
&& !KeyStoreUtil.isWindowsKeyStore(storetype)) {
! printNoIntegrityWarning();
}
if (alias == null) {
alias = keyAlias;
}
if (keyStore.containsAlias(alias) == false) {
*** 1377,1386 ****
--- 1507,1517 ----
(rb.getString("Alias.alias.has.no.certificate"));
Object[] source = {alias};
throw new Exception(form.format(source));
}
dumpCert(cert, out);
+ checkWeak(rb.getString("the.certificate"), cert);
}
/**
* Prompt the user for a keypass when generating a key entry.
* @param alias the entry we will set password for
*** 1557,1567 ****
* we choose one that is compatible with the selected private key
*/
private static String getCompatibleSigAlgName(String keyAlgName)
throws Exception {
if ("DSA".equalsIgnoreCase(keyAlgName)) {
! return "SHA1WithDSA";
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
return "SHA256WithRSA";
} else if ("EC".equalsIgnoreCase(keyAlgName)) {
return "SHA256withECDSA";
} else {
--- 1688,1698 ----
* we choose one that is compatible with the selected private key
*/
private static String getCompatibleSigAlgName(String keyAlgName)
throws Exception {
if ("DSA".equalsIgnoreCase(keyAlgName)) {
! return "SHA256WithDSA";
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
return "SHA256WithRSA";
} else if ("EC".equalsIgnoreCase(keyAlgName)) {
return "SHA256withECDSA";
} else {
*** 1576,1590 ****
int keysize, String sigAlgName)
throws Exception
{
if (keysize == -1) {
if ("EC".equalsIgnoreCase(keyAlgName)) {
! keysize = 256;
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
keysize = 2048;
- } else {
- keysize = 1024;
}
}
if (alias == null) {
alias = keyAlias;
--- 1707,1723 ----
int keysize, String sigAlgName)
throws Exception
{
if (keysize == -1) {
if ("EC".equalsIgnoreCase(keyAlgName)) {
! keysize = SecurityProviderConstants.DEF_EC_KEY_SIZE;
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
+ // hardcode for now as DEF_RSA_KEY_SIZE is still 1024
+ keysize = 2048; // SecurityProviderConstants.DEF_RSA_KEY_SIZE;
+ } else if ("DSA".equalsIgnoreCase(keyAlgName)) {
+ // hardcode for now as DEF_DSA_KEY_SIZE is still 1024
keysize = 2048;
}
}
if (alias == null) {
alias = keyAlias;
*** 1638,1647 ****
--- 1771,1781 ----
}
if (keyPass == null) {
keyPass = promptForKeyPass(alias, null, storePass);
}
+ checkWeak(rb.getString("the.generated.certificate"), chain[0]);
keyStore.setKeyEntry(alias, privKey, keyPass, chain);
}
/**
* Clones an entry
*** 1720,1738 ****
}
/**
* Prints a single keystore entry.
*/
! private void doPrintEntry(String alias, PrintStream out,
! boolean printWarning)
throws Exception
{
- if (storePass == null && printWarning
- && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
- printWarning();
- }
-
if (keyStore.containsAlias(alias) == false) {
MessageFormat form = new MessageFormat
(rb.getString("Alias.alias.does.not.exist"));
Object[] source = {alias};
throw new Exception(form.format(source));
--- 1854,1866 ----
}
/**
* Prints a single keystore entry.
*/
! private void doPrintEntry(String label, String alias, PrintStream out)
throws Exception
{
if (keyStore.containsAlias(alias) == false) {
MessageFormat form = new MessageFormat
(rb.getString("Alias.alias.does.not.exist"));
Object[] source = {alias};
throw new Exception(form.format(source));
*** 1797,1812 ****
--- 1925,1942 ----
} else if (debug) {
out.println(chain[i].toString());
} else {
dumpCert(chain[i], out);
}
+ checkWeak(label, chain[i]);
}
} else {
// Print the digest of the user cert only
out.println
(rb.getString("Certificate.fingerprint.SHA1.") +
getCertFingerPrint("SHA1", chain[0]));
+ checkWeak(label, chain[0]);
}
}
} else if (keyStore.entryInstanceOf(alias,
KeyStore.TrustedCertificateEntry.class)) {
// We have a trusted certificate entry
*** 1825,1870 ****
} else {
out.println("trustedCertEntry, ");
out.println(rb.getString("Certificate.fingerprint.SHA1.")
+ getCertFingerPrint("SHA1", cert));
}
} else {
out.println(rb.getString("Unknown.Entry.Type"));
}
}
/**
* Load the srckeystore from a stream, used in -importkeystore
* @returns the src KeyStore
*/
KeyStore loadSourceKeyStore() throws Exception {
- boolean isPkcs11 = false;
InputStream is = null;
if (P11KEYSTORE.equalsIgnoreCase(srcstoretype) ||
KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
if (!NONE.equals(srcksfname)) {
System.err.println(MessageFormat.format(rb.getString
(".keystore.must.be.NONE.if.storetype.is.{0}"), srcstoretype));
System.err.println();
tinyHelp();
}
- isPkcs11 = true;
} else {
! if (srcksfname != null) {
! File srcksfile = new File(srcksfname);
! if (srcksfile.exists() && srcksfile.length() == 0) {
! throw new Exception(rb.getString
! ("Source.keystore.file.exists.but.is.empty.") +
! srcksfname);
! }
is = new FileInputStream(srcksfile);
- } else {
- throw new Exception(rb.getString
- ("Please.specify.srckeystore"));
- }
}
KeyStore store;
try {
if (srcProviderName == null) {
--- 1955,2019 ----
} else {
out.println("trustedCertEntry, ");
out.println(rb.getString("Certificate.fingerprint.SHA1.")
+ getCertFingerPrint("SHA1", cert));
}
+ checkWeak(label, cert);
} else {
out.println(rb.getString("Unknown.Entry.Type"));
}
}
+ boolean inplaceImportCheck() throws Exception {
+ if (P11KEYSTORE.equalsIgnoreCase(srcstoretype) ||
+ KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
+ return false;
+ }
+
+ if (srcksfname != null) {
+ File srcksfile = new File(srcksfname);
+ if (srcksfile.exists() && srcksfile.length() == 0) {
+ throw new Exception(rb.getString
+ ("Source.keystore.file.exists.but.is.empty.") +
+ srcksfname);
+ }
+ if (srcksfile.getCanonicalFile()
+ .equals(new File(ksfname).getCanonicalFile())) {
+ return true;
+ } else {
+ // Informational, especially if destkeystore is not
+ // provided, which default to ~/.keystore.
+ System.err.println(String.format(rb.getString(
+ "importing.keystore.status"), srcksfname, ksfname));
+ return false;
+ }
+ } else {
+ throw new Exception(rb.getString
+ ("Please.specify.srckeystore"));
+ }
+ }
+
/**
* Load the srckeystore from a stream, used in -importkeystore
* @returns the src KeyStore
*/
KeyStore loadSourceKeyStore() throws Exception {
InputStream is = null;
+ File srcksfile = null;
if (P11KEYSTORE.equalsIgnoreCase(srcstoretype) ||
KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
if (!NONE.equals(srcksfname)) {
System.err.println(MessageFormat.format(rb.getString
(".keystore.must.be.NONE.if.storetype.is.{0}"), srcstoretype));
System.err.println();
tinyHelp();
}
} else {
! srcksfile = new File(srcksfname);
is = new FileInputStream(srcksfile);
}
KeyStore store;
try {
if (srcProviderName == null) {
*** 1901,1911 ****
}
}
if (srcstorePass == null
&& !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
! // anti refactoring, copied from printWarning(),
// but change 2 lines
System.err.println();
System.err.println(rb.getString
(".WARNING.WARNING.WARNING."));
System.err.println(rb.getString
--- 2050,2060 ----
}
}
if (srcstorePass == null
&& !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
! // anti refactoring, copied from printNoIntegrityWarning(),
// but change 2 lines
System.err.println();
System.err.println(rb.getString
(".WARNING.WARNING.WARNING."));
System.err.println(rb.getString
*** 1921,1941 ****
/**
* import all keys and certs from importkeystore.
* keep alias unchanged if no name conflict, otherwise, prompt.
* keep keypass unchanged for keys
*/
! private void doImportKeyStore() throws Exception {
if (alias != null) {
! doImportKeyStoreSingle(loadSourceKeyStore(), alias);
} else {
if (dest != null || srckeyPass != null) {
throw new Exception(rb.getString(
"if.alias.not.specified.destalias.and.srckeypass.must.not.be.specified"));
}
! doImportKeyStoreAll(loadSourceKeyStore());
}
/*
* Information display rule of -importkeystore
* 1. inside single, shows failure
* 2. inside all, shows sucess
* 3. inside all where there is a failure, prompt for continue
--- 2070,2105 ----
/**
* import all keys and certs from importkeystore.
* keep alias unchanged if no name conflict, otherwise, prompt.
* keep keypass unchanged for keys
*/
! private void doImportKeyStore(KeyStore srcKS) throws Exception {
if (alias != null) {
! doImportKeyStoreSingle(srcKS, alias);
} else {
if (dest != null || srckeyPass != null) {
throw new Exception(rb.getString(
"if.alias.not.specified.destalias.and.srckeypass.must.not.be.specified"));
}
! doImportKeyStoreAll(srcKS);
}
+
+ if (inplaceImport) {
+ // Backup to file.old or file.old2...
+ // The keystore is not rewritten yet now.
+ for (int n = 1; /* forever */; n++) {
+ inplaceBackupName = srcksfname + ".old" + (n == 1 ? "" : n);
+ File bkFile = new File(inplaceBackupName);
+ if (!bkFile.exists()) {
+ Files.copy(Paths.get(srcksfname), bkFile.toPath());
+ break;
+ }
+ }
+
+ }
+
/*
* Information display rule of -importkeystore
* 1. inside single, shows failure
* 2. inside all, shows sucess
* 3. inside all where there is a failure, prompt for continue
*** 1992,2001 ****
--- 2156,2169 ----
newPass = objs.snd;
pp = new PasswordProtection(objs.snd);
}
try {
+ Certificate c = srckeystore.getCertificate(alias);
+ if (c != null) {
+ checkWeak("<" + newAlias + ">", c);
+ }
keyStore.setEntry(newAlias, entry, pp);
// Place the check so that only successful imports are blocked.
// For example, we don't block a failed SecretEntry import.
if (P12KEYSTORE.equalsIgnoreCase(storetype)) {
if (newPass != null && !Arrays.equals(newPass, storePass)) {
*** 2045,2061 ****
* Prints all keystore entries.
*/
private void doPrintEntries(PrintStream out)
throws Exception
{
- if (storePass == null
- && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
- printWarning();
- } else {
- out.println();
- }
-
out.println(rb.getString("Keystore.type.") + keyStore.getType());
out.println(rb.getString("Keystore.provider.") +
keyStore.getProvider().getName());
out.println();
--- 2213,2222 ----
*** 2070,2080 ****
out.println();
for (Enumeration<String> e = keyStore.aliases();
e.hasMoreElements(); ) {
String alias = e.nextElement();
! doPrintEntry(alias, out, false);
if (verbose || rfc) {
out.println(rb.getString("NEWLINE"));
out.println(rb.getString
("STAR"));
out.println(rb.getString
--- 2231,2241 ----
out.println();
for (Enumeration<String> e = keyStore.aliases();
e.hasMoreElements(); ) {
String alias = e.nextElement();
! doPrintEntry("<" + alias + ">", alias, out);
if (verbose || rfc) {
out.println(rb.getString("NEWLINE"));
out.println(rb.getString
("STAR"));
out.println(rb.getString
*** 2220,2242 ****
private void doPrintCRL(String src, PrintStream out)
throws Exception {
for (CRL crl: loadCRLs(src)) {
printCRL(crl, out);
String issuer = null;
if (caks != null) {
issuer = verifyCRL(caks, crl);
if (issuer != null) {
out.printf(rb.getString(
! "verified.by.s.in.s"), issuer, "cacerts");
out.println();
}
}
if (issuer == null && keyStore != null) {
issuer = verifyCRL(keyStore, crl);
if (issuer != null) {
out.printf(rb.getString(
! "verified.by.s.in.s"), issuer, "keystore");
out.println();
}
}
if (issuer == null) {
out.println(rb.getString
--- 2381,2412 ----
private void doPrintCRL(String src, PrintStream out)
throws Exception {
for (CRL crl: loadCRLs(src)) {
printCRL(crl, out);
String issuer = null;
+ Certificate signer = null;
if (caks != null) {
issuer = verifyCRL(caks, crl);
if (issuer != null) {
+ signer = caks.getCertificate(issuer);
out.printf(rb.getString(
! "verified.by.s.in.s.weak"),
! issuer,
! "cacerts",
! withWeak(signer.getPublicKey()));
out.println();
}
}
if (issuer == null && keyStore != null) {
issuer = verifyCRL(keyStore, crl);
if (issuer != null) {
+ signer = keyStore.getCertificate(issuer);
out.printf(rb.getString(
! "verified.by.s.in.s.weak"),
! issuer,
! "keystore",
! withWeak(signer.getPublicKey()));
out.println();
}
}
if (issuer == null) {
out.println(rb.getString
*** 2244,2265 ****
out.println(rb.getString
("warning.not.verified.make.sure.keystore.is.correct"));
out.println(rb.getString
("STARNN"));
}
}
}
private void printCRL(CRL crl, PrintStream out)
throws Exception {
- if (rfc) {
X509CRL xcrl = (X509CRL)crl;
out.println("-----BEGIN X509 CRL-----");
out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(xcrl.getEncoded()));
out.println("-----END X509 CRL-----");
} else {
! out.println(crl.toString());
}
}
private void doPrintCertReq(InputStream in, PrintStream out)
throws Exception {
--- 2414,2443 ----
out.println(rb.getString
("warning.not.verified.make.sure.keystore.is.correct"));
out.println(rb.getString
("STARNN"));
}
+ checkWeak(rb.getString("the.crl"), crl, signer == null ? null : signer.getPublicKey());
}
}
private void printCRL(CRL crl, PrintStream out)
throws Exception {
X509CRL xcrl = (X509CRL)crl;
+ if (rfc) {
out.println("-----BEGIN X509 CRL-----");
out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(xcrl.getEncoded()));
out.println("-----END X509 CRL-----");
} else {
! String s;
! if (crl instanceof X509CRLImpl) {
! X509CRLImpl x509crl = (X509CRLImpl) crl;
! s = x509crl.toStringWithAlgName(withWeak("" + x509crl.getSigAlgId()));
! } else {
! s = crl.toString();
! }
! out.println(s);
}
}
private void doPrintCertReq(InputStream in, PrintStream out)
throws Exception {
*** 2282,2293 ****
}
}
PKCS10 req = new PKCS10(Pem.decode(new String(sb)));
PublicKey pkey = req.getSubjectPublicKeyInfo();
! out.printf(rb.getString("PKCS.10.Certificate.Request.Version.1.0.Subject.s.Public.Key.s.format.s.key."),
! req.getSubjectName(), pkey.getFormat(), pkey.getAlgorithm());
for (PKCS10Attribute attr: req.getAttributes().getAttributes()) {
ObjectIdentifier oid = attr.getAttributeId();
if (oid.equals((Object)PKCS9Attribute.EXTENSION_REQUEST_OID)) {
CertificateExtensions exts = (CertificateExtensions)attr.getAttributeValue();
if (exts != null) {
--- 2460,2474 ----
}
}
PKCS10 req = new PKCS10(Pem.decode(new String(sb)));
PublicKey pkey = req.getSubjectPublicKeyInfo();
! out.printf(rb.getString("PKCS.10.with.weak"),
! req.getSubjectName(),
! pkey.getFormat(),
! withWeak(pkey),
! withWeak(req.getSigAlg()));
for (PKCS10Attribute attr: req.getAttributes().getAttributes()) {
ObjectIdentifier oid = attr.getAttributeId();
if (oid.equals((Object)PKCS9Attribute.EXTENSION_REQUEST_OID)) {
CertificateExtensions exts = (CertificateExtensions)attr.getAttributeValue();
if (exts != null) {
*** 2306,2315 ****
--- 2487,2497 ----
}
}
if (debug) {
out.println(req); // Just to see more, say, public key length...
}
+ checkWeak(rb.getString("the.certificate.request"), req);
}
/**
* Reads a certificate (or certificate chain) and prints its contents in
* a human readable format.
*** 2345,2354 ****
--- 2527,2545 ----
else
printX509Cert(x509Cert, out);
if (i < (certs.length-1)) {
out.println();
}
+ checkWeak(oneInMany(rb.getString("the.certificate"), i, certs.length), x509Cert);
+ }
+ }
+
+ private static String oneInMany(String label, int i, int num) {
+ if (num == 1) {
+ return label;
+ } else {
+ return String.format(rb.getString("one.in.many"), label, i+1, num);
}
}
private void doPrintCert(final PrintStream out) throws Exception {
if (jarfile != null) {
*** 2374,2406 ****
out.printf(rb.getString("Signer.d."), ++pos);
out.println();
out.println();
out.println(rb.getString("Signature."));
out.println();
! for (Certificate cert: signer.getSignerCertPath().getCertificates()) {
X509Certificate x = (X509Certificate)cert;
if (rfc) {
out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n");
dumpCert(x, out);
} else {
printX509Cert(x, out);
}
out.println();
}
Timestamp ts = signer.getTimestamp();
if (ts != null) {
out.println(rb.getString("Timestamp."));
out.println();
! for (Certificate cert: ts.getSignerCertPath().getCertificates()) {
X509Certificate x = (X509Certificate)cert;
if (rfc) {
out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n");
dumpCert(x, out);
} else {
printX509Cert(x, out);
}
out.println();
}
}
}
}
}
--- 2565,2605 ----
out.printf(rb.getString("Signer.d."), ++pos);
out.println();
out.println();
out.println(rb.getString("Signature."));
out.println();
!
! List<? extends Certificate> certs
! = signer.getSignerCertPath().getCertificates();
! int cc = 0;
! for (Certificate cert: certs) {
X509Certificate x = (X509Certificate)cert;
if (rfc) {
out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n");
dumpCert(x, out);
} else {
printX509Cert(x, out);
}
out.println();
+ checkWeak(oneInMany(rb.getString("the.certificate"), cc++, certs.size()), x);
}
Timestamp ts = signer.getTimestamp();
if (ts != null) {
out.println(rb.getString("Timestamp."));
out.println();
! certs = ts.getSignerCertPath().getCertificates();
! cc = 0;
! for (Certificate cert: certs) {
X509Certificate x = (X509Certificate)cert;
if (rfc) {
out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n");
dumpCert(x, out);
} else {
printX509Cert(x, out);
}
out.println();
+ checkWeak(oneInMany(rb.getString("the.tsa.certificate"), cc++, certs.size()), x);
}
}
}
}
}
*** 2441,2450 ****
--- 2640,2650 ----
out.println("Certificate #" + i++);
out.println("====================================");
printX509Cert((X509Certificate)cert, out);
out.println();
}
+ checkWeak(oneInMany(rb.getString("the.certificate"), i, chain.size()), cert);
} catch (Exception e) {
if (debug) {
e.printStackTrace();
}
}
*** 2616,2626 ****
// cert-chain reply (e.g., PKCS#7)
newChain = validateReply(alias, userCert, replyCerts);
}
// Now store the newly established chain in the keystore. The new
! // chain replaces the old one.
if (newChain != null) {
keyStore.setKeyEntry(alias, privKey,
(keyPass != null) ? keyPass : storePass,
newChain);
return true;
--- 2816,2826 ----
// cert-chain reply (e.g., PKCS#7)
newChain = validateReply(alias, userCert, replyCerts);
}
// Now store the newly established chain in the keystore. The new
! // chain replaces the old one. The chain can be null if user chooses no.
if (newChain != null) {
keyStore.setKeyEntry(alias, privKey,
(keyPass != null) ? keyPass : storePass,
newChain);
return true;
*** 2653,2698 ****
cert = (X509Certificate)cf.generateCertificate(in);
} catch (ClassCastException | CertificateException ce) {
throw new Exception(rb.getString("Input.not.an.X.509.certificate"));
}
// if certificate is self-signed, make sure it verifies
boolean selfSigned = false;
if (isSelfSigned(cert)) {
cert.verify(cert.getPublicKey());
selfSigned = true;
}
- if (noprompt) {
- keyStore.setCertificateEntry(alias, cert);
- return true;
- }
-
// check if cert already exists in keystore
String reply = null;
String trustalias = keyStore.getCertificateAlias(cert);
if (trustalias != null) {
MessageFormat form = new MessageFormat(rb.getString
("Certificate.already.exists.in.keystore.under.alias.trustalias."));
Object[] source = {trustalias};
System.err.println(form.format(source));
reply = getYesNoReply
(rb.getString("Do.you.still.want.to.add.it.no."));
} else if (selfSigned) {
if (trustcacerts && (caks != null) &&
((trustalias=caks.getCertificateAlias(cert)) != null)) {
MessageFormat form = new MessageFormat(rb.getString
("Certificate.already.exists.in.system.wide.CA.keystore.under.alias.trustalias."));
Object[] source = {trustalias};
System.err.println(form.format(source));
reply = getYesNoReply
(rb.getString("Do.you.still.want.to.add.it.to.your.own.keystore.no."));
}
if (trustalias == null) {
// Print the cert and ask user if they really want to add
// it to their keystore
printX509Cert(cert, System.out);
reply = getYesNoReply
(rb.getString("Trust.this.certificate.no."));
}
}
if (reply != null) {
--- 2853,2905 ----
cert = (X509Certificate)cf.generateCertificate(in);
} catch (ClassCastException | CertificateException ce) {
throw new Exception(rb.getString("Input.not.an.X.509.certificate"));
}
+ if (noprompt) {
+ checkWeak(rb.getString("the.input"), cert);
+ keyStore.setCertificateEntry(alias, cert);
+ return true;
+ }
+
// if certificate is self-signed, make sure it verifies
boolean selfSigned = false;
if (isSelfSigned(cert)) {
cert.verify(cert.getPublicKey());
selfSigned = true;
}
// check if cert already exists in keystore
String reply = null;
String trustalias = keyStore.getCertificateAlias(cert);
if (trustalias != null) {
MessageFormat form = new MessageFormat(rb.getString
("Certificate.already.exists.in.keystore.under.alias.trustalias."));
Object[] source = {trustalias};
System.err.println(form.format(source));
+ checkWeak(rb.getString("the.input"), cert);
+ printWeakWarnings(true);
reply = getYesNoReply
(rb.getString("Do.you.still.want.to.add.it.no."));
} else if (selfSigned) {
if (trustcacerts && (caks != null) &&
((trustalias=caks.getCertificateAlias(cert)) != null)) {
MessageFormat form = new MessageFormat(rb.getString
("Certificate.already.exists.in.system.wide.CA.keystore.under.alias.trustalias."));
Object[] source = {trustalias};
System.err.println(form.format(source));
+ checkWeak(rb.getString("the.input"), cert);
+ printWeakWarnings(true);
reply = getYesNoReply
(rb.getString("Do.you.still.want.to.add.it.to.your.own.keystore.no."));
}
if (trustalias == null) {
// Print the cert and ask user if they really want to add
// it to their keystore
printX509Cert(cert, System.out);
+ checkWeak(rb.getString("the.input"), cert);
+ printWeakWarnings(true);
reply = getYesNoReply
(rb.getString("Trust.this.certificate.no."));
}
}
if (reply != null) {
*** 2702,2711 ****
--- 2909,2919 ----
} else {
return false;
}
}
+ // Not found in this keystore and not self-signed
// Try to establish trust chain
try {
Certificate[] chain = establishCertChain(null, cert);
if (chain != null) {
keyStore.setCertificateEntry(alias, cert);
*** 2713,2722 ****
--- 2921,2932 ----
}
} catch (Exception e) {
// Print the cert and ask user if they really want to add it to
// their keystore
printX509Cert(cert, System.out);
+ checkWeak(rb.getString("the.input"), cert);
+ printWeakWarnings(true);
reply = getYesNoReply
(rb.getString("Trust.this.certificate.no."));
if ("YES".equals(reply)) {
keyStore.setCertificateEntry(alias, cert);
return true;
*** 2851,2860 ****
--- 3061,3088 ----
}
return keyPass;
}
+ private String withWeak(String alg) {
+ if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) {
+ return alg;
+ } else {
+ return String.format(rb.getString("with.weak"), alg);
+ }
+ }
+
+ private String withWeak(PublicKey key) {
+ if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
+ return String.format(rb.getString("key.bit"),
+ KeyUtil.getKeySize(key), key.getAlgorithm());
+ } else {
+ return String.format(rb.getString("key.bit.weak"),
+ KeyUtil.getKeySize(key), key.getAlgorithm());
+ }
+ }
+
/**
* Prints a certificate in a human readable format.
*/
private void printX509Cert(X509Certificate cert, PrintStream out)
throws Exception
*** 2876,2895 ****
+ "\n"
+ "\t SHA1: " + getCertFingerPrint("SHA1", cert));
*/
MessageFormat form = new MessageFormat
! (rb.getString(".PATTERN.printX509Cert"));
Object[] source = {cert.getSubjectDN().toString(),
cert.getIssuerDN().toString(),
cert.getSerialNumber().toString(16),
cert.getNotBefore().toString(),
cert.getNotAfter().toString(),
getCertFingerPrint("MD5", cert),
getCertFingerPrint("SHA1", cert),
getCertFingerPrint("SHA-256", cert),
! cert.getSigAlgName(),
cert.getVersion()
};
out.println(form.format(source));
if (cert instanceof X509CertImpl) {
--- 3104,3130 ----
+ "\n"
+ "\t SHA1: " + getCertFingerPrint("SHA1", cert));
*/
MessageFormat form = new MessageFormat
! (rb.getString(".PATTERN.printX509Cert.with.weak"));
! PublicKey pkey = cert.getPublicKey();
! String sigName = cert.getSigAlgName();
! // No need to warn about sigalg of a trust anchor
! if (!isTrustedCert(cert)) {
! sigName = withWeak(sigName);
! }
Object[] source = {cert.getSubjectDN().toString(),
cert.getIssuerDN().toString(),
cert.getSerialNumber().toString(16),
cert.getNotBefore().toString(),
cert.getNotAfter().toString(),
getCertFingerPrint("MD5", cert),
getCertFingerPrint("SHA1", cert),
getCertFingerPrint("SHA-256", cert),
! sigName,
! withWeak(pkey),
cert.getVersion()
};
out.println(form.format(source));
if (cert instanceof X509CertImpl) {
*** 2955,2979 ****
* returns the signer's certificate.
* @param cert the certificate whose signer is searched, not null
* @param ks the keystore to search with, not null
* @return <code>cert</code> itself if it's already inside <code>ks</code>,
* or a certificate inside <code>ks</code> who signs <code>cert</code>,
! * or null otherwise.
*/
! private static Certificate getTrustedSigner(Certificate cert, KeyStore ks)
! throws Exception {
if (ks.getCertificateAlias(cert) != null) {
! return cert;
}
for (Enumeration<String> aliases = ks.aliases();
aliases.hasMoreElements(); ) {
String name = aliases.nextElement();
Certificate trustedCert = ks.getCertificate(name);
if (trustedCert != null) {
try {
cert.verify(trustedCert.getPublicKey());
! return trustedCert;
} catch (Exception e) {
// Not verified, skip to the next one
}
}
}
--- 3190,3214 ----
* returns the signer's certificate.
* @param cert the certificate whose signer is searched, not null
* @param ks the keystore to search with, not null
* @return <code>cert</code> itself if it's already inside <code>ks</code>,
* or a certificate inside <code>ks</code> who signs <code>cert</code>,
! * or null otherwise. A label is added.
*/
! private static Pair<String,Certificate>
! getSigner(Certificate cert, KeyStore ks) throws Exception {
if (ks.getCertificateAlias(cert) != null) {
! return new Pair<>("", cert);
}
for (Enumeration<String> aliases = ks.aliases();
aliases.hasMoreElements(); ) {
String name = aliases.nextElement();
Certificate trustedCert = ks.getCertificate(name);
if (trustedCert != null) {
try {
cert.verify(trustedCert.getPublicKey());
! return new Pair<>(name, trustedCert);
} catch (Exception e) {
// Not verified, skip to the next one
}
}
}
*** 3233,3243 ****
}
/**
* Prints warning about missing integrity check.
*/
! private void printWarning() {
System.err.println();
System.err.println(rb.getString
(".WARNING.WARNING.WARNING."));
System.err.println(rb.getString
(".The.integrity.of.the.information.stored.in.your.keystore."));
--- 3468,3478 ----
}
/**
* Prints warning about missing integrity check.
*/
! private void printNoIntegrityWarning() {
System.err.println();
System.err.println(rb.getString
(".WARNING.WARNING.WARNING."));
System.err.println(rb.getString
(".The.integrity.of.the.information.stored.in.your.keystore."));
*** 3258,3267 ****
--- 3493,3505 ----
private Certificate[] validateReply(String alias,
Certificate userCert,
Certificate[] replyCerts)
throws Exception
{
+
+ checkWeak(rb.getString("reply"), replyCerts);
+
// order the certs in the reply (bottom-up).
// we know that all certs in the reply are of type X.509, because
// we parsed them using an X.509 certificate factory
int i;
PublicKey userPubKey = userCert.getPublicKey();
*** 3305,3352 ****
return replyCerts;
}
// do we trust the cert at the top?
Certificate topCert = replyCerts[replyCerts.length-1];
! Certificate root = getTrustedSigner(topCert, keyStore);
if (root == null && trustcacerts && caks != null) {
! root = getTrustedSigner(topCert, caks);
}
if (root == null) {
System.err.println();
System.err.println
(rb.getString("Top.level.certificate.in.reply."));
printX509Cert((X509Certificate)topCert, System.out);
System.err.println();
System.err.print(rb.getString(".is.not.trusted."));
String reply = getYesNoReply
(rb.getString("Install.reply.anyway.no."));
if ("NO".equals(reply)) {
return null;
}
} else {
! if (root != topCert) {
// append the root CA cert to the chain
Certificate[] tmpCerts =
new Certificate[replyCerts.length+1];
System.arraycopy(replyCerts, 0, tmpCerts, 0,
replyCerts.length);
! tmpCerts[tmpCerts.length-1] = root;
replyCerts = tmpCerts;
}
}
-
return replyCerts;
}
/**
* Establishes a certificate chain (using trusted certificates in the
! * keystore), starting with the user certificate
* and ending at a self-signed certificate found in the keystore.
*
! * @param userCert the user certificate of the alias
! * @param certToVerify the single certificate provided in the reply
*/
private Certificate[] establishCertChain(Certificate userCert,
Certificate certToVerify)
throws Exception
{
--- 3543,3601 ----
return replyCerts;
}
// do we trust the cert at the top?
Certificate topCert = replyCerts[replyCerts.length-1];
! boolean fromKeyStore = true;
! Pair<String,Certificate> root = getSigner(topCert, keyStore);
if (root == null && trustcacerts && caks != null) {
! root = getSigner(topCert, caks);
! fromKeyStore = false;
}
if (root == null) {
System.err.println();
System.err.println
(rb.getString("Top.level.certificate.in.reply."));
printX509Cert((X509Certificate)topCert, System.out);
System.err.println();
System.err.print(rb.getString(".is.not.trusted."));
+ printWeakWarnings(true);
String reply = getYesNoReply
(rb.getString("Install.reply.anyway.no."));
if ("NO".equals(reply)) {
return null;
}
} else {
! if (root.snd != topCert) {
// append the root CA cert to the chain
Certificate[] tmpCerts =
new Certificate[replyCerts.length+1];
System.arraycopy(replyCerts, 0, tmpCerts, 0,
replyCerts.length);
! tmpCerts[tmpCerts.length-1] = root.snd;
replyCerts = tmpCerts;
+ checkWeak(String.format(rb.getString(fromKeyStore ?
+ "alias.in.keystore" :
+ "alias.in.cacerts"),
+ root.fst),
+ root.snd);
}
}
return replyCerts;
}
/**
* Establishes a certificate chain (using trusted certificates in the
! * keystore and cacerts), starting with the reply (certToVerify)
* and ending at a self-signed certificate found in the keystore.
*
! * @param userCert optional existing certificate, mostly likely be the
! * original self-signed cert created by -genkeypair.
! * It must have the same public key as certToVerify
! * but cannot be the same cert.
! * @param certToVerify the starting certificate to build the chain
! * @returns the established chain, might be null if user decides not
*/
private Certificate[] establishCertChain(Certificate userCert,
Certificate certToVerify)
throws Exception
{
*** 3370,3448 ****
// Build a hash table of all certificates in the keystore.
// Use the subject distinguished name as the key into the hash table.
// All certificates associated with the same subject distinguished
// name are stored in the same hash table entry as a vector.
! Hashtable<Principal, Vector<Certificate>> certs = null;
if (keyStore.size() > 0) {
! certs = new Hashtable<Principal, Vector<Certificate>>(11);
keystorecerts2Hashtable(keyStore, certs);
}
if (trustcacerts) {
if (caks!=null && caks.size()>0) {
if (certs == null) {
! certs = new Hashtable<Principal, Vector<Certificate>>(11);
}
keystorecerts2Hashtable(caks, certs);
}
}
// start building chain
! Vector<Certificate> chain = new Vector<>(2);
! if (buildChain((X509Certificate)certToVerify, chain, certs)) {
! Certificate[] newChain = new Certificate[chain.size()];
// buildChain() returns chain with self-signed root-cert first and
// user-cert last, so we need to invert the chain before we store
// it
int j=0;
for (int i=chain.size()-1; i>=0; i--) {
! newChain[j] = chain.elementAt(i);
j++;
}
return newChain;
} else {
throw new Exception
(rb.getString("Failed.to.establish.chain.from.reply"));
}
}
/**
! * Recursively tries to establish chain from pool of trusted certs.
*
* @param certToVerify the cert that needs to be verified.
* @param chain the chain that's being built.
* @param certs the pool of trusted certs
*
* @return true if successful, false otherwise.
*/
! private boolean buildChain(X509Certificate certToVerify,
! Vector<Certificate> chain,
! Hashtable<Principal, Vector<Certificate>> certs) {
! Principal issuer = certToVerify.getIssuerDN();
! if (isSelfSigned(certToVerify)) {
// reached self-signed root cert;
// no verification needed because it's trusted.
chain.addElement(certToVerify);
return true;
}
// Get the issuer's certificate(s)
! Vector<Certificate> vec = certs.get(issuer);
if (vec == null) {
return false;
}
// Try out each certificate in the vector, until we find one
// whose public key verifies the signature of the certificate
// in question.
! for (Enumeration<Certificate> issuerCerts = vec.elements();
issuerCerts.hasMoreElements(); ) {
! X509Certificate issuerCert
! = (X509Certificate)issuerCerts.nextElement();
! PublicKey issuerPubKey = issuerCert.getPublicKey();
try {
! certToVerify.verify(issuerPubKey);
} catch (Exception e) {
continue;
}
if (buildChain(issuerCert, chain, certs)) {
chain.addElement(certToVerify);
--- 3619,3714 ----
// Build a hash table of all certificates in the keystore.
// Use the subject distinguished name as the key into the hash table.
// All certificates associated with the same subject distinguished
// name are stored in the same hash table entry as a vector.
! Hashtable<Principal, Vector<Pair<String,X509Certificate>>> certs = null;
if (keyStore.size() > 0) {
! certs = new Hashtable<>(11);
keystorecerts2Hashtable(keyStore, certs);
}
if (trustcacerts) {
if (caks!=null && caks.size()>0) {
if (certs == null) {
! certs = new Hashtable<>(11);
}
keystorecerts2Hashtable(caks, certs);
}
}
// start building chain
! Vector<Pair<String,X509Certificate>> chain = new Vector<>(2);
! if (buildChain(
! new Pair<>(rb.getString("the.input"),
! (X509Certificate) certToVerify),
! chain, certs)) {
! for (Pair<String,X509Certificate> p : chain) {
! checkWeak(p.fst, p.snd);
! }
! Certificate[] newChain =
! new Certificate[chain.size()];
// buildChain() returns chain with self-signed root-cert first and
// user-cert last, so we need to invert the chain before we store
// it
int j=0;
for (int i=chain.size()-1; i>=0; i--) {
! newChain[j] = chain.elementAt(i).snd;
j++;
}
return newChain;
} else {
throw new Exception
(rb.getString("Failed.to.establish.chain.from.reply"));
}
}
/**
! * Recursively tries to establish chain from pool of certs starting from
! * certToVerify until a self-signed cert is found, and fill the certs found
! * into chain. Each cert in the chain signs the next one.
! *
! * This method is able to recover from an error, say, if certToVerify
! * is signed by certA but certA has no issuer in certs and itself is not
! * self-signed, the method can try another certB that also signs
! * certToVerify and look for signer of certB, etc, etc.
! *
! * Each cert in chain comes with a label showing its origin. The label is
! * used in the warning message when the cert is considered a risk.
*
* @param certToVerify the cert that needs to be verified.
* @param chain the chain that's being built.
* @param certs the pool of trusted certs
*
* @return true if successful, false otherwise.
*/
! private boolean buildChain(Pair<String,X509Certificate> certToVerify,
! Vector<Pair<String,X509Certificate>> chain,
! Hashtable<Principal, Vector<Pair<String,X509Certificate>>> certs) {
! if (isSelfSigned(certToVerify.snd)) {
// reached self-signed root cert;
// no verification needed because it's trusted.
chain.addElement(certToVerify);
return true;
}
+ Principal issuer = certToVerify.snd.getIssuerDN();
+
// Get the issuer's certificate(s)
! Vector<Pair<String,X509Certificate>> vec = certs.get(issuer);
if (vec == null) {
return false;
}
// Try out each certificate in the vector, until we find one
// whose public key verifies the signature of the certificate
// in question.
! for (Enumeration<Pair<String,X509Certificate>> issuerCerts = vec.elements();
issuerCerts.hasMoreElements(); ) {
! Pair<String,X509Certificate> issuerCert = issuerCerts.nextElement();
! PublicKey issuerPubKey = issuerCert.snd.getPublicKey();
try {
! certToVerify.snd.verify(issuerPubKey);
} catch (Exception e) {
continue;
}
if (buildChain(issuerCert, chain, certs)) {
chain.addElement(certToVerify);
*** 3487,3515 ****
}
/**
* Stores the (leaf) certificates of a keystore in a hashtable.
* All certs belonging to the same CA are stored in a vector that
! * in turn is stored in the hashtable, keyed by the CA's subject DN
*/
private void keystorecerts2Hashtable(KeyStore ks,
! Hashtable<Principal, Vector<Certificate>> hash)
throws Exception {
for (Enumeration<String> aliases = ks.aliases();
aliases.hasMoreElements(); ) {
String alias = aliases.nextElement();
Certificate cert = ks.getCertificate(alias);
if (cert != null) {
Principal subjectDN = ((X509Certificate)cert).getSubjectDN();
! Vector<Certificate> vec = hash.get(subjectDN);
if (vec == null) {
! vec = new Vector<Certificate>();
! vec.addElement(cert);
} else {
! if (!vec.contains(cert)) {
! vec.addElement(cert);
}
}
hash.put(subjectDN, vec);
}
}
--- 3753,3789 ----
}
/**
* Stores the (leaf) certificates of a keystore in a hashtable.
* All certs belonging to the same CA are stored in a vector that
! * in turn is stored in the hashtable, keyed by the CA's subject DN.
! * Each cert comes with a string label that shows its origin and alias.
*/
private void keystorecerts2Hashtable(KeyStore ks,
! Hashtable<Principal, Vector<Pair<String,X509Certificate>>> hash)
throws Exception {
for (Enumeration<String> aliases = ks.aliases();
aliases.hasMoreElements(); ) {
String alias = aliases.nextElement();
Certificate cert = ks.getCertificate(alias);
if (cert != null) {
Principal subjectDN = ((X509Certificate)cert).getSubjectDN();
! Pair<String,X509Certificate> pair = new Pair<>(
! String.format(
! rb.getString(ks == caks ?
! "alias.in.cacerts" :
! "alias.in.keystore"),
! alias),
! (X509Certificate)cert);
! Vector<Pair<String,X509Certificate>> vec = hash.get(subjectDN);
if (vec == null) {
! vec = new Vector<>();
! vec.addElement(pair);
} else {
! if (!vec.contains(pair)) {
! vec.addElement(pair);
}
}
hash.put(subjectDN, vec);
}
}
*** 4078,4087 ****
--- 4352,4436 ----
throw new RuntimeException(e);
}
return ext;
}
+ private boolean isTrustedCert(Certificate cert) throws KeyStoreException {
+ if (caks != null && caks.getCertificateAlias(cert) != null) {
+ return true;
+ } else {
+ String inKS = keyStore.getCertificateAlias(cert);
+ return inKS != null && keyStore.isCertificateEntry(inKS);
+ }
+ }
+
+ private void checkWeak(String label, String sigAlg, Key key) {
+
+ if (sigAlg != null && !DISABLED_CHECK.permits(
+ SIG_PRIMITIVE_SET, sigAlg, null)) {
+ weakWarnings.add(String.format(
+ rb.getString("whose.sigalg.risk"), label, sigAlg));
+ }
+ if (key != null && !DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
+ weakWarnings.add(String.format(
+ rb.getString("whose.key.risk"),
+ label,
+ String.format(rb.getString("key.bit"),
+ KeyUtil.getKeySize(key), key.getAlgorithm())));
+ }
+ }
+
+ private void checkWeak(String label, Certificate[] certs)
+ throws KeyStoreException {
+ for (int i = 0; i < certs.length; i++) {
+ Certificate cert = certs[i];
+ if (cert instanceof X509Certificate) {
+ X509Certificate xc = (X509Certificate)cert;
+ String fullLabel = label;
+ if (certs.length > 1) {
+ fullLabel = oneInMany(label, i, certs.length);
+ }
+ checkWeak(fullLabel, xc);
+ }
+ }
+ }
+
+ private void checkWeak(String label, Certificate cert)
+ throws KeyStoreException {
+ if (cert instanceof X509Certificate) {
+ X509Certificate xc = (X509Certificate)cert;
+ // No need to check the sigalg of a trust anchor
+ String sigAlg = isTrustedCert(cert) ? null : xc.getSigAlgName();
+ checkWeak(label, sigAlg, xc.getPublicKey());
+ }
+ }
+
+ private void checkWeak(String label, PKCS10 p10) {
+ checkWeak(label, p10.getSigAlg(), p10.getSubjectPublicKeyInfo());
+ }
+
+ private void checkWeak(String label, CRL crl, Key key) {
+ if (crl instanceof X509CRLImpl) {
+ X509CRLImpl impl = (X509CRLImpl)crl;
+ checkWeak(label, impl.getSigAlgName(), key);
+ }
+ }
+
+ private void printWeakWarnings(boolean newLine) {
+ if (!weakWarnings.isEmpty() && !nowarn) {
+ System.err.println("\nWarning:");
+ for (String warning : weakWarnings) {
+ System.err.println(warning);
+ }
+ if (newLine) {
+ // When calling before a yes/no prompt, add a new line
+ System.err.println();
+ }
+ }
+ weakWarnings.clear();
+ }
+
/**
* Prints the usage of this tool.
*/
private void usage() {
if (command != null) {
< prev index next >