--- old/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java 2021-05-06 23:50:31.000000000 +0300 +++ new/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java 2021-05-06 23:50:31.000000000 +0300 @@ -69,6 +69,7 @@ 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; @@ -78,9 +79,11 @@ * 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 : * @@ -123,24 +126,13 @@ * @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 @@ -161,10 +153,6 @@ 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 /* @@ -175,17 +163,15 @@ {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; @@ -200,6 +186,17 @@ // 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; @@ -211,16 +208,12 @@ 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); } } @@ -381,7 +374,7 @@ 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; @@ -417,7 +410,7 @@ if (debug != null) { debug.println("Retrieved a protected private key at alias" + " '" + alias + "' (" + - new AlgorithmId(algOid).getName() + + mapPBEParamsToAlgorithm(algOid, algParams) + " iterations: " + ic + ")"); } return tmp; @@ -442,7 +435,7 @@ if (debug != null) { debug.println("Retrieved a protected secret key at alias " + "'" + alias + "' (" + - new AlgorithmId(algOid).getName() + + mapPBEParamsToAlgorithm(algOid, algParams) + " iterations: " + ic + ")"); } return tmp; @@ -691,7 +684,7 @@ 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); } } @@ -788,14 +781,13 @@ /* * 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); @@ -858,13 +850,14 @@ } /* - * 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) @@ -886,27 +879,14 @@ 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() { - 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); @@ -964,7 +944,7 @@ if (algorithm.equals((Object)pbes2_OID) && algParams != null) { return algParams.toString(); } - return algorithm.toString(); + return new AlgorithmId(algorithm).getName(); } /** @@ -1189,10 +1169,6 @@ 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(); @@ -1225,16 +1201,28 @@ // -- 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 @@ -1249,9 +1237,16 @@ 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); @@ -1462,24 +1457,6 @@ } /* - * 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 @@ -1489,16 +1466,16 @@ 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); @@ -1506,7 +1483,7 @@ // 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(); @@ -1764,15 +1741,19 @@ 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; + } } /* @@ -1881,47 +1862,52 @@ 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(); } /** @@ -1944,10 +1930,12 @@ 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; @@ -1987,6 +1975,8 @@ secretKeyCount = 0; certificateCount = 0; + boolean seeEncBag = false; + /* * Spin over the ContentInfos. */ @@ -2012,6 +2002,21 @@ 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; } @@ -2055,13 +2060,18 @@ 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 + ")"); } @@ -2086,48 +2096,62 @@ } } + // 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); + 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(); + // Change SHA-1 to SHA1 + algName = algName.replace("-", ""); - if (debug != null) { - debug.println("Checking keystore integrity " + - "(" + m.getAlgorithm() + " iterations: " + ic + ")"); - } + macAlgorithm = "HmacPBE" + algName; + macIterationCount = 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); + // 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); + } } + } else { + macAlgorithm = "NONE"; } /* @@ -2167,8 +2191,14 @@ 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); + } } } @@ -2184,6 +2214,46 @@ } /** + * 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 @@ -2339,8 +2409,8 @@ 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 @@ -2350,6 +2420,9 @@ } else { continue; } + } else { + // keyId in a SecretKeyEntry is not significant + keyId = "00".getBytes("UTF8"); } } entry.keyId = keyId; @@ -2420,4 +2493,83 @@ 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() { + 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; + } }