< prev index next >
src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
Print this page
@@ -67,22 +67,25 @@
import sun.security.util.DerInputStream;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier;
import sun.security.pkcs.ContentInfo;
+import sun.security.util.SecurityProperties;
import sun.security.x509.AlgorithmId;
import sun.security.pkcs.EncryptedPrivateKeyInfo;
/**
* This class provides the keystore implementation referred to as "PKCS12".
* Implements the PKCS#12 PFX protected using the Password privacy mode.
* The contents are protected using Password integrity mode.
*
- * Currently we support following PBE algorithms:
- * - pbeWithSHAAnd3KeyTripleDESCBC to encrypt private keys
- * - pbeWithSHAAnd40BitRC2CBC to encrypt certificates
+ * Currently these PBE algorithms are used by default:
+ * - PBEWithSHA1AndDESede to encrypt private keys, iteration count 50000.
+ * - PBEWithSHA1AndRC2_40 to encrypt certificates, iteration count 50000.
+ *
+ * The default Mac algorithm is HmacPBESHA1, iteration count 100000.
*
* Supported encryption of various implementations :
*
* Software and mode. Certificate encryption Private key encryption
* ---------------------------------------------------------------------
@@ -121,28 +124,17 @@
*
* @author Seema Malkani
* @author Jeff Nisewanger
* @author Jan Luehe
*
- * @see KeyProtector
* @see java.security.KeyStoreSpi
- * @see KeyTool
- *
- *
*/
public final class PKCS12KeyStore extends KeyStoreSpi {
public static final int VERSION_3 = 3;
- private static final String[] KEY_PROTECTION_ALGORITHM = {
- "keystore.pkcs12.keyProtectionAlgorithm",
- "keystore.PKCS12.keyProtectionAlgorithm"
- };
-
private static final int MAX_ITERATION_COUNT = 5000000;
- private static final int PBE_ITERATION_COUNT = 50000; // default
- private static final int MAC_ITERATION_COUNT = 100000; // default
private static final int SALT_LEN = 20;
// friendlyName, localKeyId, trustedKeyUsage
private static final String[] CORE_ATTRIBUTES = {
"1.2.840.113549.1.9.20",
@@ -159,35 +151,29 @@
private static final int pkcs9Name[] = {1, 2, 840, 113549, 1, 9, 20};
private static final int pkcs9KeyId[] = {1, 2, 840, 113549, 1, 9, 21};
private static final int pkcs9certType[] = {1, 2, 840, 113549, 1, 9, 22, 1};
- private static final int pbeWithSHAAnd40BitRC2CBC[] =
- {1, 2, 840, 113549, 1, 12, 1, 6};
- private static final int pbeWithSHAAnd3KeyTripleDESCBC[] =
- {1, 2, 840, 113549, 1, 12, 1, 3};
private static final int pbes2[] = {1, 2, 840, 113549, 1, 5, 13};
// TODO: temporary Oracle OID
/*
* { joint-iso-itu-t(2) country(16) us(840) organization(1) oracle(113894)
* jdk(746875) crypto(1) id-at-trustedKeyUsage(1) }
*/
private static final int TrustedKeyUsage[] =
{2, 16, 840, 1, 113894, 746875, 1, 1};
private static final int AnyExtendedKeyUsage[] = {2, 5, 29, 37, 0};
- private static ObjectIdentifier PKCS8ShroudedKeyBag_OID;
- private static ObjectIdentifier CertBag_OID;
- private static ObjectIdentifier SecretBag_OID;
- private static ObjectIdentifier PKCS9FriendlyName_OID;
- private static ObjectIdentifier PKCS9LocalKeyId_OID;
- private static ObjectIdentifier PKCS9CertType_OID;
- private static ObjectIdentifier pbeWithSHAAnd40BitRC2CBC_OID;
- private static ObjectIdentifier pbeWithSHAAnd3KeyTripleDESCBC_OID;
- private static ObjectIdentifier pbes2_OID;
- private static ObjectIdentifier TrustedKeyUsage_OID;
- private static ObjectIdentifier[] AnyUsage;
+ private static final ObjectIdentifier PKCS8ShroudedKeyBag_OID;
+ private static final ObjectIdentifier CertBag_OID;
+ private static final ObjectIdentifier SecretBag_OID;
+ private static final ObjectIdentifier PKCS9FriendlyName_OID;
+ private static final ObjectIdentifier PKCS9LocalKeyId_OID;
+ private static final ObjectIdentifier PKCS9CertType_OID;
+ private static final ObjectIdentifier pbes2_OID;
+ private static final ObjectIdentifier TrustedKeyUsage_OID;
+ private static final ObjectIdentifier[] AnyUsage;
private int counter = 0;
// private key count
// Note: This is a workaround to allow null localKeyID attribute
@@ -198,10 +184,21 @@
private int secretKeyCount = 0;
// certificate count
private int certificateCount = 0;
+ // Alg/params used for *this* keystore. Initialized as -1 for ic and
+ // null for algorithm names. When an existing file is read, they will be
+ // assigned inside engineLoad() so storing an existing keystore uses the
+ // old alg/params. This makes sure if a keystore is created password-less
+ // it will be password-less forever. Otherwise, engineStore() will read
+ // the default values. These fields are always reset when load() is called.
+ private String certProtectionAlgorithm = null;
+ private int certPbeIterationCount = -1;
+ private String macAlgorithm = null;
+ private int macIterationCount = -1;
+
// the source of randomness
private SecureRandom random;
static {
try {
@@ -209,20 +206,16 @@
CertBag_OID = new ObjectIdentifier(certBag);
SecretBag_OID = new ObjectIdentifier(secretBag);
PKCS9FriendlyName_OID = new ObjectIdentifier(pkcs9Name);
PKCS9LocalKeyId_OID = new ObjectIdentifier(pkcs9KeyId);
PKCS9CertType_OID = new ObjectIdentifier(pkcs9certType);
- pbeWithSHAAnd40BitRC2CBC_OID =
- new ObjectIdentifier(pbeWithSHAAnd40BitRC2CBC);
- pbeWithSHAAnd3KeyTripleDESCBC_OID =
- new ObjectIdentifier(pbeWithSHAAnd3KeyTripleDESCBC);
pbes2_OID = new ObjectIdentifier(pbes2);
TrustedKeyUsage_OID = new ObjectIdentifier(TrustedKeyUsage);
AnyUsage = new ObjectIdentifier[]{
new ObjectIdentifier(AnyExtendedKeyUsage)};
} catch (IOException ioe) {
- // should not happen
+ throw new AssertionError("OID not initialized", ioe);
}
}
// A keystore entry and associated attributes
private static class Entry {
@@ -379,11 +372,11 @@
throw new IOException("Invalid PBE algorithm parameters");
}
ic = pbeSpec.getIterationCount();
if (ic > MAX_ITERATION_COUNT) {
- throw new IOException("PBE iteration count too large");
+ throw new IOException("key PBE iteration count too large");
}
} else {
ic = 0;
}
@@ -415,11 +408,11 @@
Key tmp = kfac.generatePrivate(kspec);
if (debug != null) {
debug.println("Retrieved a protected private key at alias" +
" '" + alias + "' (" +
- new AlgorithmId(algOid).getName() +
+ mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
}
return tmp;
// decode secret key
} else {
@@ -440,11 +433,11 @@
}
if (debug != null) {
debug.println("Retrieved a protected secret key at alias " +
"'" + alias + "' (" +
- new AlgorithmId(algOid).getName() +
+ mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
}
return tmp;
}
}, password);
@@ -689,11 +682,11 @@
entry.alias = alias.toLowerCase(Locale.ENGLISH);
// add the entry
entries.put(alias.toLowerCase(Locale.ENGLISH), entry);
} catch (Exception nsae) {
- throw new KeyStoreException("Key protection " +
+ throw new KeyStoreException("Key protection" +
" algorithm not found: " + nsae, nsae);
}
}
/**
@@ -786,18 +779,17 @@
}
/*
* Generate PBE Algorithm Parameters
*/
- private AlgorithmParameters getPBEAlgorithmParameters(String algorithm)
- throws IOException
- {
+ private AlgorithmParameters getPBEAlgorithmParameters(
+ String algorithm, int iterationCount) throws IOException {
AlgorithmParameters algParams = null;
// create PBE parameters from salt and iteration count
PBEParameterSpec paramSpec =
- new PBEParameterSpec(getSalt(), PBE_ITERATION_COUNT);
+ new PBEParameterSpec(getSalt(), iterationCount);
try {
algParams = AlgorithmParameters.getInstance(algorithm);
algParams.init(paramSpec);
} catch (Exception e) {
throw new IOException("getPBEAlgorithmParameters failed: " +
@@ -856,17 +848,18 @@
}
return skey;
}
/*
- * Encrypt private key using Password-based encryption (PBE)
+ * Encrypt private key or secret key using Password-based encryption (PBE)
* as defined in PKCS#5.
*
* NOTE: By default, pbeWithSHAAnd3-KeyTripleDES-CBC algorithmID is
* used to derive the key and IV.
*
- * @return encrypted private key encoded as EncryptedPrivateKeyInfo
+ * @return encrypted private key or secret key encoded as
+ * EncryptedPrivateKeyInfo
*/
private byte[] encryptPrivateKey(byte[] data,
KeyStore.PasswordProtection passwordProtection)
throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException
{
@@ -884,31 +877,18 @@
passwordProtection.getProtectionParameters();
if (algParamSpec != null) {
algParams = AlgorithmParameters.getInstance(algorithm);
algParams.init(algParamSpec);
} else {
- algParams = getPBEAlgorithmParameters(algorithm);
+ algParams = getPBEAlgorithmParameters(algorithm,
+ defaultKeyPbeIterationCount());
}
} else {
// Check default key protection algorithm for PKCS12 keystores
- algorithm = AccessController.doPrivileged(
- new PrivilegedAction<String>() {
- public String run() {
- String prop =
- Security.getProperty(
- KEY_PROTECTION_ALGORITHM[0]);
- if (prop == null) {
- prop = Security.getProperty(
- KEY_PROTECTION_ALGORITHM[1]);
- }
- return prop;
- }
- });
- if (algorithm == null || algorithm.isEmpty()) {
- algorithm = "PBEWithSHA1AndDESede";
- }
- algParams = getPBEAlgorithmParameters(algorithm);
+ algorithm = defaultKeyProtectionAlgorithm();
+ algParams = getPBEAlgorithmParameters(algorithm,
+ defaultKeyPbeIterationCount());
}
ObjectIdentifier pbeOID = mapPBEAlgorithmToOID(algorithm);
if (pbeOID == null) {
throw new IOException("PBE algorithm '" + algorithm +
@@ -962,11 +942,11 @@
AlgorithmParameters algParams) throws NoSuchAlgorithmException {
// Check for PBES2 algorithms
if (algorithm.equals((Object)pbes2_OID) && algParams != null) {
return algParams.toString();
}
- return algorithm.toString();
+ return new AlgorithmId(algorithm).getName();
}
/**
* Assigns the given certificate to the given alias.
*
@@ -1187,14 +1167,10 @@
* the keystore data could not be stored
*/
public synchronized void engineStore(OutputStream stream, char[] password)
throws IOException, NoSuchAlgorithmException, CertificateException
{
- // password is mandatory when storing
- if (password == null) {
- throw new IllegalArgumentException("password can't be null");
- }
// -- Create PFX
DerOutputStream pfx = new DerOutputStream();
// PFX version (always write the latest version)
@@ -1223,20 +1199,32 @@
}
// -- create EncryptedContentInfo
if (certificateCount > 0) {
+ if (certProtectionAlgorithm == null) {
+ certProtectionAlgorithm = defaultCertProtectionAlgorithm();
+ }
+ if (certPbeIterationCount < 0) {
+ certPbeIterationCount = defaultCertPbeIterationCount();
+ }
+
if (debug != null) {
debug.println("Storing " + certificateCount +
" certificate(s) in a PKCS#7 encryptedData");
}
byte[] encrData = createEncryptedData(password);
+ if (!certProtectionAlgorithm.equalsIgnoreCase("NONE")) {
ContentInfo encrContentInfo =
new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID,
new DerValue(encrData));
encrContentInfo.encode(authSafeContentInfo);
+ } else {
+ ContentInfo dataContentInfo = new ContentInfo(encrData);
+ dataContentInfo.encode(authSafeContentInfo);
+ }
}
// wrap as SequenceOf ContentInfos
DerOutputStream cInfo = new DerOutputStream();
cInfo.write(DerValue.tag_SequenceOf, authSafeContentInfo);
@@ -1247,13 +1235,20 @@
contentInfo.encode(authSafe);
byte[] authSafeData = authSafe.toByteArray();
pfx.write(authSafeData);
// -- MAC
+ if (macAlgorithm == null) {
+ macAlgorithm = defaultMacAlgorithm();
+ }
+ if (macIterationCount < 0) {
+ macIterationCount = defaultMacIterationCount();
+ }
+ if (!macAlgorithm.equalsIgnoreCase("NONE")) {
byte[] macData = calculateMac(password, authenticatedSafe);
pfx.write(macData);
-
+ }
// write PFX to output stream
DerOutputStream pfxout = new DerOutputStream();
pfxout.write(DerValue.tag_Sequence, pfx);
byte[] pfxData = pfxout.toByteArray();
stream.write(pfxData);
@@ -1460,55 +1455,37 @@
return entry.attributes;
}
/*
- * Generate Hash.
- */
- private byte[] generateHash(byte[] data) throws IOException
- {
- byte[] digest = null;
-
- try {
- MessageDigest md = MessageDigest.getInstance("SHA1");
- md.update(data);
- digest = md.digest();
- } catch (Exception e) {
- throw new IOException("generateHash failed: " + e, e);
- }
- return digest;
- }
-
-
- /*
* Calculate MAC using HMAC algorithm (required for password integrity)
*
* Hash-based MAC algorithm combines secret key with message digest to
* create a message authentication code (MAC)
*/
private byte[] calculateMac(char[] passwd, byte[] data)
throws IOException
{
byte[] mData = null;
- String algName = "SHA1";
+ String algName = macAlgorithm.substring(7);
try {
// Generate a random salt.
byte[] salt = getSalt();
// generate MAC (MAC key is generated within JCE)
- Mac m = Mac.getInstance("HmacPBESHA1");
+ Mac m = Mac.getInstance(macAlgorithm);
PBEParameterSpec params =
- new PBEParameterSpec(salt, MAC_ITERATION_COUNT);
+ new PBEParameterSpec(salt, macIterationCount);
SecretKey key = getPBEKey(passwd);
m.init(key, params);
m.update(data);
byte[] macResult = m.doFinal();
// encode as MacData
MacData macData = new MacData(algName, macResult, salt,
- MAC_ITERATION_COUNT);
+ macIterationCount);
DerOutputStream bytes = new DerOutputStream();
bytes.write(macData.getEncoded());
mData = bytes.toByteArray();
} catch (Exception e) {
throw new IOException("calculateMac failed: " + e, e);
@@ -1762,19 +1739,23 @@
DerOutputStream safeBagValue = new DerOutputStream();
safeBagValue.write(DerValue.tag_SequenceOf, out);
byte[] safeBagData = safeBagValue.toByteArray();
// encrypt the content (EncryptedContentInfo)
+ if (!certProtectionAlgorithm.equalsIgnoreCase("NONE")) {
byte[] encrContentInfo = encryptContent(safeBagData, password);
// -- SEQUENCE of EncryptedData
DerOutputStream encrData = new DerOutputStream();
DerOutputStream encrDataContent = new DerOutputStream();
encrData.putInteger(0);
encrData.write(encrContentInfo);
encrDataContent.write(DerValue.tag_Sequence, encrData);
return encrDataContent.toByteArray();
+ } else {
+ return safeBagData;
+ }
}
/*
* Create SafeContent Data content type.
* Includes encrypted secret key in a SafeBag of type SecretBag.
@@ -1879,51 +1860,56 @@
private byte[] encryptContent(byte[] data, char[] password)
throws IOException {
byte[] encryptedData = null;
+
+ try {
// create AlgorithmParameters
- AlgorithmParameters algParams =
- getPBEAlgorithmParameters("PBEWithSHA1AndRC2_40");
+ AlgorithmParameters algParams = getPBEAlgorithmParameters(
+ certProtectionAlgorithm, certPbeIterationCount);
DerOutputStream bytes = new DerOutputStream();
- AlgorithmId algId =
- new AlgorithmId(pbeWithSHAAnd40BitRC2CBC_OID, algParams);
- algId.encode(bytes);
- byte[] encodedAlgId = bytes.toByteArray();
- try {
// Use JCE
SecretKey skey = getPBEKey(password);
- Cipher cipher = Cipher.getInstance("PBEWithSHA1AndRC2_40");
+ Cipher cipher = Cipher.getInstance(certProtectionAlgorithm);
cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
encryptedData = cipher.doFinal(data);
+ AlgorithmId algId = new AlgorithmId(
+ mapPBEAlgorithmToOID(certProtectionAlgorithm),
+ cipher.getParameters());
+ // cipher.getParameters() now has IV
+ algId.encode(bytes);
+ byte[] encodedAlgId = bytes.toByteArray();
+
if (debug != null) {
debug.println(" (Cipher algorithm: " + cipher.getAlgorithm() +
")");
}
- } catch (Exception e) {
- throw new IOException("Failed to encrypt" +
- " safe contents entry: " + e, e);
- }
-
// create EncryptedContentInfo
DerOutputStream bytes2 = new DerOutputStream();
bytes2.putOID(ContentInfo.DATA_OID);
bytes2.write(encodedAlgId);
// Wrap encrypted data in a context-specific tag.
DerOutputStream tmpout2 = new DerOutputStream();
tmpout2.putOctetString(encryptedData);
bytes2.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
- false, (byte)0), tmpout2);
+ false, (byte) 0), tmpout2);
// wrap EncryptedContentInfo in a Sequence
DerOutputStream out = new DerOutputStream();
out.write(DerValue.tag_Sequence, bytes2);
return out.toByteArray();
+ } catch (IOException ioe) {
+ throw ioe;
+ } catch (Exception e) {
+ throw new IOException("Failed to encrypt" +
+ " safe contents entry: " + e, e);
+ }
}
/**
* Loads the keystore from the given input stream.
*
@@ -1942,14 +1928,16 @@
* keystore could not be loaded
*/
public synchronized void engineLoad(InputStream stream, char[] password)
throws IOException, NoSuchAlgorithmException, CertificateException
{
- DataInputStream dis;
- CertificateFactory cf = null;
- ByteArrayInputStream bais = null;
- byte[] encoded = null;
+
+ // Reset config when loading a different keystore.
+ certProtectionAlgorithm = null;
+ certPbeIterationCount = -1;
+ macAlgorithm = null;
+ macIterationCount = -1;
if (stream == null)
return;
// reset the counter
@@ -1985,10 +1973,12 @@
// reset the counters at the start
privateKeyCount = 0;
secretKeyCount = 0;
certificateCount = 0;
+ boolean seeEncBag = false;
+
/*
* Spin over the ContentInfos.
*/
for (int i = 0; i < count; i++) {
ContentInfo safeContents;
@@ -2010,10 +2000,25 @@
if (debug != null) {
debug.println("Warning: skipping PKCS#7 encryptedData" +
" - no password was supplied");
}
+ // No password to decrypt ENCRYPTED_DATA_OID. *Skip it*.
+ // This means user will see a PrivateKeyEntry without
+ // certificates and a whole TrustedCertificateEntry will
+ // be lost. This is not a perfect solution but alternative
+ // solutions are more disruptive:
+ //
+ // We cannot just fail, since KeyStore.load(is, null)
+ // has been known to never fail because of a null password.
+ //
+ // We cannot just throw away the whole PrivateKeyEntry,
+ // this is too silent and no one will notice anything.
+ //
+ // We also cannot fail when getCertificate() on such a
+ // PrivateKeyEntry is called, since the method has not
+ // specified this behavior.
continue;
}
DerInputStream edi =
safeContents.getContent().toDerInputStream();
@@ -2053,17 +2058,22 @@
"Invalid PBE algorithm parameters");
}
ic = pbeSpec.getIterationCount();
if (ic > MAX_ITERATION_COUNT) {
- throw new IOException("PBE iteration count too large");
+ throw new IOException("cert PBE iteration count too large");
}
+
+ certProtectionAlgorithm
+ = mapPBEParamsToAlgorithm(algOid, algParams);
+ certPbeIterationCount = ic;
+ seeEncBag = true;
}
if (debug != null) {
debug.println("Loading PKCS#7 encryptedData " +
- "(" + new AlgorithmId(algOid).getName() +
+ "(" + mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
}
try {
RetryWithZero.run(pass -> {
@@ -2084,12 +2094,20 @@
throw new IOException("public key protected PKCS12" +
" not supported");
}
}
+ // No ENCRYPTED_DATA_OID but see certificate. Must be passwordless.
+ if (!seeEncBag && certificateCount > 0) {
+ certProtectionAlgorithm = "NONE";
+ }
+
// The MacData is optional.
- if (password != null && s.available() > 0) {
+ if (s.available() > 0) {
+ // If there is no password, we cannot fail. KeyStore.load(is, null)
+ // has been known to never fail because of a null password.
+ if (password != null) {
MacData macData = new MacData(s);
int ic = macData.getIterations();
try {
if (ic > MAX_ITERATION_COUNT) {
@@ -2101,12 +2119,15 @@
macData.getDigestAlgName().toUpperCase(Locale.ENGLISH);
// Change SHA-1 to SHA1
algName = algName.replace("-", "");
+ macAlgorithm = "HmacPBE" + algName;
+ macIterationCount = ic;
+
// generate MAC (MAC key is created within JCE)
- Mac m = Mac.getInstance("HmacPBE" + algName);
+ Mac m = Mac.getInstance(macAlgorithm);
PBEParameterSpec params =
new PBEParameterSpec(macData.getSalt(), ic);
RetryWithZero.run(pass -> {
SecretKey key = getPBEKey(pass);
@@ -2121,16 +2142,19 @@
if (!MessageDigest.isEqual(macData.getDigest(), macResult)) {
throw new UnrecoverableKeyException("Failed PKCS12" +
" integrity checking");
}
- return (Void)null;
+ return (Void) null;
}, password);
} catch (Exception e) {
throw new IOException("Integrity check failed: " + e, e);
}
}
+ } else {
+ macAlgorithm = "NONE";
+ }
/*
* Match up private keys with certificate chains.
*/
PrivateKeyEntry[] list =
@@ -2165,12 +2189,18 @@
break;
}
cert = certsMap.get(issuerDN);
}
/* Update existing KeyEntry in entries table */
- if (chain.size() > 0)
+ if (chain.size() > 0) {
entry.chain = chain.toArray(new Certificate[chain.size()]);
+ } else {
+ // Remove private key entries where there is no associated
+ // certs. Most likely the keystore is loaded with a null
+ // password.
+ entries.remove(entry);
+ }
}
}
if (debug != null) {
debug.println("PKCS12KeyStore load: private key count: " +
@@ -2182,10 +2212,50 @@
certsMap.clear();
keyList.clear();
}
/**
+ * Returns if a pkcs12 file is password-less. This means no cert is
+ * encrypted and there is no Mac. Please note that the private key
+ * can be encrypted.
+ *
+ * This is a simplified version of {@link #engineLoad} that only looks
+ * at the ContentInfo types.
+ *
+ * @param f the pkcs12 file
+ * @return if it's password-less
+ * @throws IOException
+ */
+ public static boolean isPasswordless(File f) throws IOException {
+
+ try (FileInputStream stream = new FileInputStream(f)) {
+ DerValue val = new DerValue(stream);
+ DerInputStream s = val.toDerInputStream();
+
+ s.getInteger(); // skip version
+
+ ContentInfo authSafe = new ContentInfo(s);
+ DerInputStream as = new DerInputStream(authSafe.getData());
+ for (DerValue seq : as.getSequence(2)) {
+ DerInputStream sci = new DerInputStream(seq.toByteArray());
+ ContentInfo safeContents = new ContentInfo(sci);
+ if (safeContents.getContentType()
+ .equals(ContentInfo.ENCRYPTED_DATA_OID)) {
+ // Certificate encrypted
+ return false;
+ }
+ }
+
+ if (s.available() > 0) {
+ // The MacData exists.
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* Locates a matched CertEntry from certEntries, and returns its cert.
* @param entry the KeyEntry to match
* @return a certificate, null if not found
*/
private X509Certificate findMatchedCertificate(PrivateKeyEntry entry) {
@@ -2337,21 +2407,24 @@
* null keyId, we should skip it entirely.
*/
if (bagItem instanceof KeyEntry) {
KeyEntry entry = (KeyEntry)bagItem;
- if (bagItem instanceof PrivateKeyEntry) {
if (keyId == null) {
+ if (bagItem instanceof PrivateKeyEntry) {
// Insert a localKeyID for the privateKey
// Note: This is a workaround to allow null localKeyID
// attribute in pkcs12 with one private key entry and
// associated cert-chain
if (privateKeyCount == 1) {
keyId = "01".getBytes("UTF8");
} else {
continue;
}
+ } else {
+ // keyId in a SecretKeyEntry is not significant
+ keyId = "00".getBytes("UTF8");
}
}
entry.keyId = keyId;
// restore date if it exists
String keyIdStr = new String(keyId, "UTF8");
@@ -2418,6 +2491,85 @@
private String getUnfriendlyName() {
counter++;
return (String.valueOf(counter));
}
+
+ // 8076190: Customizing the generation of a PKCS12 keystore
+
+ private static String defaultCertProtectionAlgorithm() {
+ String result = SecurityProperties.privilegedGetOverridable(
+ "keystore.pkcs12.certProtectionAlgorithm");
+ return (result != null && !result.isEmpty())
+ ? result : "PBEWithSHA1AndRC2_40";
+ }
+
+ private static int defaultCertPbeIterationCount() {
+ String result = SecurityProperties.privilegedGetOverridable(
+ "keystore.pkcs12.certPbeIterationCount");
+ return (result != null && !result.isEmpty())
+ ? string2IC("certPbeIterationCount", result) : 50000;
+ }
+
+ // Read both "keystore.pkcs12.keyProtectionAlgorithm" and
+ // "keystore.PKCS12.keyProtectionAlgorithm" for compatibility.
+ private static String defaultKeyProtectionAlgorithm() {
+ String result = AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ String result;
+ String name1 = "keystore.pkcs12.keyProtectionAlgorithm";
+ String name2 = "keystore.PKCS12.keyProtectionAlgorithm";
+ result = System.getProperty(name1);
+ if (result != null) {
+ return result;
+ }
+ result = System.getProperty(name2);
+ if (result != null) {
+ return result;
+ }
+ result = Security.getProperty(name1);
+ if (result != null) {
+ return result;
+ }
+ return Security.getProperty(name2);
+ }
+ });
+ return (result != null && !result.isEmpty())
+ ? result : "PBEWithSHA1AndDESede";
+ }
+
+ private static int defaultKeyPbeIterationCount() {
+ String result = SecurityProperties.privilegedGetOverridable(
+ "keystore.pkcs12.keyPbeIterationCount");
+ return (result != null && !result.isEmpty())
+ ? string2IC("keyPbeIterationCount", result) : 50000;
+ }
+
+ private static String defaultMacAlgorithm() {
+ String result = SecurityProperties.privilegedGetOverridable(
+ "keystore.pkcs12.macAlgorithm");
+ return (result != null && !result.isEmpty())
+ ? result : "HmacPBESHA1";
+ }
+
+ private static int defaultMacIterationCount() {
+ String result = SecurityProperties.privilegedGetOverridable(
+ "keystore.pkcs12.macIterationCount");
+ return (result != null && !result.isEmpty())
+ ? string2IC("macIterationCount", result) : 100000;
+ }
+
+ private static int string2IC(String type, String value) {
+ int number;
+ try {
+ number = Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("keystore.pkcs12." + type
+ + " is not a number: " + value);
+ }
+ if (number <= 0 || number > MAX_ITERATION_COUNT) {
+ throw new IllegalArgumentException("Invalid keystore.pkcs12."
+ + type + ": " + value);
+ }
+ return number;
+ }
}
< prev index next >