< 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 >