8076190: Customizing the generation of a PKCS12 keystore

Reviewed-by: mullan
This commit is contained in:
Weijun Wang 2018-12-13 11:16:33 +08:00
parent 0b05ebed2e
commit 9136c7d1d0
19 changed files with 1782 additions and 350 deletions

View file

@ -53,7 +53,6 @@ import java.util.*;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
@ -70,6 +69,7 @@ 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;
import sun.security.provider.JavaKeyStore.JKS;
@ -81,9 +81,11 @@ import sun.security.util.KeyStoreDelegator;
* 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 :
*
@ -126,11 +128,7 @@ import sun.security.util.KeyStoreDelegator;
* @author Jeff Nisewanger
* @author Jan Luehe
*
* @see KeyProtector
* @see java.security.KeyStoreSpi
* @see KeyTool
*
*
*/
public final class PKCS12KeyStore extends KeyStoreSpi {
@ -143,14 +141,7 @@ 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
@ -171,10 +162,6 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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
/*
@ -185,17 +172,15 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
{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;
@ -210,6 +195,17 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
// 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;
@ -221,16 +217,12 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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);
}
}
@ -391,7 +383,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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;
@ -424,7 +416,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
if (debug != null) {
debug.println("Retrieved a protected private key at alias" +
" '" + alias + "' (" +
new AlgorithmId(algOid).getName() +
mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
}
return tmp;
@ -449,7 +441,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
if (debug != null) {
debug.println("Retrieved a protected secret key at alias " +
"'" + alias + "' (" +
new AlgorithmId(algOid).getName() +
mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
}
return tmp;
@ -701,7 +693,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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);
}
}
@ -801,14 +793,13 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
/*
* 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);
@ -871,13 +862,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
/*
* 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)
@ -899,27 +891,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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);
@ -977,7 +956,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
if (algorithm.equals(pbes2_OID) && algParams != null) {
return algParams.toString();
}
return algorithm.toString();
return new AlgorithmId(algorithm).getName();
}
/**
@ -1209,10 +1188,6 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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();
@ -1245,16 +1220,28 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
// -- 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);
ContentInfo encrContentInfo =
new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID,
if (!certProtectionAlgorithm.equalsIgnoreCase("NONE")) {
ContentInfo encrContentInfo =
new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID,
new DerValue(encrData));
encrContentInfo.encode(authSafeContentInfo);
encrContentInfo.encode(authSafeContentInfo);
} else {
ContentInfo dataContentInfo = new ContentInfo(encrData);
dataContentInfo.encode(authSafeContentInfo);
}
}
// wrap as SequenceOf ContentInfos
@ -1269,9 +1256,16 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
pfx.write(authSafeData);
// -- MAC
byte[] macData = calculateMac(password, authenticatedSafe);
pfx.write(macData);
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);
@ -1481,24 +1475,6 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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)
*
@ -1509,16 +1485,16 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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);
@ -1526,7 +1502,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
// 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();
@ -1799,15 +1775,19 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
byte[] safeBagData = safeBagValue.toByteArray();
// encrypt the content (EncryptedContentInfo)
byte[] encrContentInfo = encryptContent(safeBagData, password);
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();
// -- 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;
}
}
/*
@ -1916,47 +1896,52 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
byte[] encryptedData = null;
// create AlgorithmParameters
AlgorithmParameters algParams =
getPBEAlgorithmParameters("PBEWithSHA1AndRC2_40");
DerOutputStream bytes = new DerOutputStream();
AlgorithmId algId =
new AlgorithmId(pbeWithSHAAnd40BitRC2CBC_OID, algParams);
algId.encode(bytes);
byte[] encodedAlgId = bytes.toByteArray();
try {
// create AlgorithmParameters
AlgorithmParameters algParams = getPBEAlgorithmParameters(
certProtectionAlgorithm, certPbeIterationCount);
DerOutputStream bytes = new DerOutputStream();
// 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() +
")");
")");
}
// 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);
// 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);
}
// 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);
// wrap EncryptedContentInfo in a Sequence
DerOutputStream out = new DerOutputStream();
out.write(DerValue.tag_Sequence, bytes2);
return out.toByteArray();
}
/**
@ -1979,10 +1964,12 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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;
@ -2022,6 +2009,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
secretKeyCount = 0;
certificateCount = 0;
boolean seeEncBag = false;
/*
* Spin over the ContentInfos.
*/
@ -2047,6 +2036,21 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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;
}
@ -2084,13 +2088,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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 + ")");
}
@ -2115,48 +2124,62 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
}
// 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) {
MacData macData = new MacData(s);
int ic = macData.getIterations();
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) {
throw new InvalidAlgorithmParameterException(
"MAC iteration count too large: " + ic);
try {
if (ic > MAX_ITERATION_COUNT) {
throw new InvalidAlgorithmParameterException(
"MAC iteration count too large: " + ic);
}
String algName =
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(macAlgorithm);
PBEParameterSpec params =
new PBEParameterSpec(macData.getSalt(), ic);
RetryWithZero.run(pass -> {
SecretKey key = getPBEKey(pass);
m.init(key, params);
m.update(authSafeData);
byte[] macResult = m.doFinal();
if (debug != null) {
debug.println("Checking keystore integrity " +
"(" + m.getAlgorithm() + " iterations: " + ic + ")");
}
if (!MessageDigest.isEqual(macData.getDigest(), macResult)) {
throw new UnrecoverableKeyException("Failed PKCS12" +
" integrity checking");
}
return (Void) null;
}, password);
} catch (Exception e) {
throw new IOException("Integrity check failed: " + e, e);
}
String algName =
macData.getDigestAlgName().toUpperCase(Locale.ENGLISH);
// Change SHA-1 to SHA1
algName = algName.replace("-", "");
// generate MAC (MAC key is created within JCE)
Mac m = Mac.getInstance("HmacPBE" + algName);
PBEParameterSpec params =
new PBEParameterSpec(macData.getSalt(), ic);
RetryWithZero.run(pass -> {
SecretKey key = getPBEKey(pass);
m.init(key, params);
m.update(authSafeData);
byte[] macResult = m.doFinal();
if (debug != null) {
debug.println("Checking keystore integrity " +
"(" + m.getAlgorithm() + " iterations: " + ic + ")");
}
if (!MessageDigest.isEqual(macData.getDigest(), macResult)) {
throw new UnrecoverableKeyException("Failed PKCS12" +
" integrity checking");
}
return (Void)null;
}, password);
} catch (Exception e) {
throw new IOException("Integrity check failed: " + e, e);
}
} else {
macAlgorithm = "NONE";
}
/*
@ -2196,8 +2219,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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);
}
}
}
@ -2221,6 +2250,46 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
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
@ -2368,8 +2437,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
if (bagItem instanceof KeyEntry) {
KeyEntry entry = (KeyEntry)bagItem;
if (bagItem instanceof PrivateKeyEntry) {
if (keyId == null) {
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
@ -2379,6 +2448,9 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
} else {
continue;
}
} else {
// keyId in a SecretKeyEntry is not significant
keyId = "00".getBytes("UTF8");
}
}
entry.keyId = keyId;
@ -2518,4 +2590,83 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
return result;
}
// 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;
}
}