mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8182879: Add warnings to keytool when using JKS and JCEKS
Reviewed-by: vinnie, ahgross, mullan
This commit is contained in:
parent
bbfbe9af71
commit
7cf3c0ff14
3 changed files with 319 additions and 55 deletions
|
@ -26,6 +26,8 @@
|
|||
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;
|
||||
|
@ -168,7 +170,12 @@ public final class Main {
|
|||
private List<String> ids = new ArrayList<>(); // used in GENCRL
|
||||
private List<String> v3ext = new ArrayList<>();
|
||||
|
||||
// Warnings on weak algorithms
|
||||
// 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 =
|
||||
|
@ -846,37 +853,52 @@ public final class Main {
|
|||
("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.
|
||||
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
|
||||
("Keystore.file.exists.but.is.empty.") + ksfname);
|
||||
}
|
||||
ksStream = new FileInputStream(ksfile);
|
||||
} catch (FileNotFoundException e) {
|
||||
if (command != GENKEYPAIR &&
|
||||
// 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
|
||||
("Keystore.file.exists.but.is.empty.") + ksfname);
|
||||
}
|
||||
ksStream = new FileInputStream(ksfile);
|
||||
} catch (FileNotFoundException e) {
|
||||
if (command != GENKEYPAIR &&
|
||||
command != GENSECKEY &&
|
||||
command != IDENTITYDB &&
|
||||
command != IMPORTCERT &&
|
||||
command != IMPORTPASS &&
|
||||
command != IMPORTKEYSTORE &&
|
||||
command != PRINTCRL) {
|
||||
throw new Exception(rb.getString
|
||||
("Keystore.file.does.not.exist.") + ksfname);
|
||||
}
|
||||
throw new Exception(rb.getString
|
||||
("Keystore.file.does.not.exist.") + ksfname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -900,7 +922,7 @@ public final class Main {
|
|||
// Create new keystore
|
||||
// Probe for keystore type when filename is available
|
||||
if (ksfile != null && ksStream != null && providerName == null &&
|
||||
hasStoretypeOption == false) {
|
||||
hasStoretypeOption == false && !inplaceImport) {
|
||||
keyStore = KeyStore.getInstance(ksfile, storePass);
|
||||
} else {
|
||||
if (providerName == null) {
|
||||
|
@ -930,7 +952,11 @@ public final class Main {
|
|||
* Null stream keystores are loaded later.
|
||||
*/
|
||||
if (!nullStream) {
|
||||
keyStore.load(ksStream, storePass);
|
||||
if (inplaceImport) {
|
||||
keyStore.load(null, storePass);
|
||||
} else {
|
||||
keyStore.load(ksStream, storePass);
|
||||
}
|
||||
if (ksStream != null) {
|
||||
ksStream.close();
|
||||
}
|
||||
|
@ -1167,7 +1193,11 @@ public final class Main {
|
|||
}
|
||||
}
|
||||
} else if (command == IMPORTKEYSTORE) {
|
||||
doImportKeyStore();
|
||||
// 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;
|
||||
|
@ -1298,6 +1328,51 @@ public final class Main {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isKeyStoreRelated(command)
|
||||
&& !token && !nullStream && ksfname != null) {
|
||||
|
||||
// JKS storetype warning on the final result keystore
|
||||
File f = new File(ksfname);
|
||||
char[] pass = (storePassNew!=null) ? storePassNew : storePass;
|
||||
if (f.exists()) {
|
||||
// Probe for real type. A JKS can be loaded as PKCS12 because
|
||||
// DualFormat support, vice versa.
|
||||
keyStore = KeyStore.getInstance(f, pass);
|
||||
String realType = keyStore.getType();
|
||||
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 = KeyStore.getInstance(
|
||||
new File(inplaceBackupName), srcstorePass).getType();
|
||||
String format =
|
||||
realType.equalsIgnoreCase(realSourceStoreType) ?
|
||||
rb.getString("backup.keystore.warning") :
|
||||
rb.getString("migrate.keystore.warning");
|
||||
weakWarnings.add(
|
||||
String.format(format,
|
||||
srcksfname,
|
||||
realSourceStoreType,
|
||||
inplaceBackupName,
|
||||
realType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1989,12 +2064,40 @@ public final class Main {
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
* @return the src KeyStore
|
||||
*/
|
||||
KeyStore loadSourceKeyStore() throws Exception {
|
||||
boolean isPkcs11 = false;
|
||||
|
||||
InputStream is = null;
|
||||
File srcksfile = null;
|
||||
|
@ -2007,20 +2110,9 @@ public final class Main {
|
|||
System.err.println();
|
||||
tinyHelp();
|
||||
}
|
||||
isPkcs11 = true;
|
||||
} else {
|
||||
if (srcksfname != null) {
|
||||
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"));
|
||||
}
|
||||
srcksfile = new File(srcksfname);
|
||||
is = new FileInputStream(srcksfile);
|
||||
}
|
||||
|
||||
KeyStore store;
|
||||
|
@ -2087,17 +2179,32 @@ public final class Main {
|
|||
* keep alias unchanged if no name conflict, otherwise, prompt.
|
||||
* keep keypass unchanged for keys
|
||||
*/
|
||||
private void doImportKeyStore() throws Exception {
|
||||
private void doImportKeyStore(KeyStore srcKS) throws Exception {
|
||||
|
||||
if (alias != null) {
|
||||
doImportKeyStoreSingle(loadSourceKeyStore(), alias);
|
||||
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(loadSourceKeyStore());
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue