44 import java.security.cert.Certificate; |
44 import java.security.cert.Certificate; |
45 import java.security.cert.CertificateFactory; |
45 import java.security.cert.CertificateFactory; |
46 import java.security.cert.X509Certificate; |
46 import java.security.cert.X509Certificate; |
47 import java.security.cert.CertificateException; |
47 import java.security.cert.CertificateException; |
48 import java.security.spec.AlgorithmParameterSpec; |
48 import java.security.spec.AlgorithmParameterSpec; |
|
49 import java.security.spec.InvalidParameterSpecException; |
49 import java.security.spec.KeySpec; |
50 import java.security.spec.KeySpec; |
50 import java.security.spec.PKCS8EncodedKeySpec; |
51 import java.security.spec.PKCS8EncodedKeySpec; |
51 import java.util.*; |
52 import java.util.*; |
52 |
53 |
53 import java.security.AlgorithmParameters; |
54 import java.security.AlgorithmParameters; |
145 private static final String[] KEY_PROTECTION_ALGORITHM = { |
146 private static final String[] KEY_PROTECTION_ALGORITHM = { |
146 "keystore.pkcs12.keyProtectionAlgorithm", |
147 "keystore.pkcs12.keyProtectionAlgorithm", |
147 "keystore.PKCS12.keyProtectionAlgorithm" |
148 "keystore.PKCS12.keyProtectionAlgorithm" |
148 }; |
149 }; |
149 |
150 |
|
151 private static final int MAX_ITERATION_COUNT = 5000000; |
|
152 private static final int PBE_ITERATION_COUNT = 50000; // default |
|
153 private static final int MAC_ITERATION_COUNT = 100000; // default |
|
154 private static final int SALT_LEN = 20; |
|
155 |
150 // friendlyName, localKeyId, trustedKeyUsage |
156 // friendlyName, localKeyId, trustedKeyUsage |
151 private static final String[] CORE_ATTRIBUTES = { |
157 private static final String[] CORE_ATTRIBUTES = { |
152 "1.2.840.113549.1.9.20", |
158 "1.2.840.113549.1.9.20", |
153 "1.2.840.113549.1.9.21", |
159 "1.2.840.113549.1.9.21", |
154 "2.16.840.1.113894.746875.1.1" |
160 "2.16.840.1.113894.746875.1.1" |
190 private static ObjectIdentifier pbes2_OID; |
196 private static ObjectIdentifier pbes2_OID; |
191 private static ObjectIdentifier TrustedKeyUsage_OID; |
197 private static ObjectIdentifier TrustedKeyUsage_OID; |
192 private static ObjectIdentifier[] AnyUsage; |
198 private static ObjectIdentifier[] AnyUsage; |
193 |
199 |
194 private int counter = 0; |
200 private int counter = 0; |
195 private static final int iterationCount = 1024; |
|
196 private static final int SALT_LEN = 20; |
|
197 |
201 |
198 // private key count |
202 // private key count |
199 // Note: This is a workaround to allow null localKeyID attribute |
203 // Note: This is a workaround to allow null localKeyID attribute |
200 // in pkcs12 with one private key entry and associated cert-chain |
204 // in pkcs12 with one private key entry and associated cert-chain |
201 private int privateKeyCount = 0; |
205 private int privateKeyCount = 0; |
325 } |
329 } |
326 |
330 |
327 byte[] encryptedKey; |
331 byte[] encryptedKey; |
328 AlgorithmParameters algParams; |
332 AlgorithmParameters algParams; |
329 ObjectIdentifier algOid; |
333 ObjectIdentifier algOid; |
|
334 |
330 try { |
335 try { |
331 // get the encrypted private key |
336 // get the encrypted private key |
332 EncryptedPrivateKeyInfo encrInfo = |
337 EncryptedPrivateKeyInfo encrInfo = |
333 new EncryptedPrivateKeyInfo(encrBytes); |
338 new EncryptedPrivateKeyInfo(encrBytes); |
334 encryptedKey = encrInfo.getEncryptedData(); |
339 encryptedKey = encrInfo.getEncryptedData(); |
345 + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe); |
350 + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe); |
346 uke.initCause(ioe); |
351 uke.initCause(ioe); |
347 throw uke; |
352 throw uke; |
348 } |
353 } |
349 |
354 |
350 try { |
355 try { |
|
356 PBEParameterSpec pbeSpec; |
|
357 int ic = 0; |
|
358 |
|
359 if (algParams != null) { |
|
360 try { |
|
361 pbeSpec = |
|
362 algParams.getParameterSpec(PBEParameterSpec.class); |
|
363 } catch (InvalidParameterSpecException ipse) { |
|
364 throw new IOException("Invalid PBE algorithm parameters"); |
|
365 } |
|
366 ic = pbeSpec.getIterationCount(); |
|
367 |
|
368 if (ic > MAX_ITERATION_COUNT) { |
|
369 throw new IOException("PBE iteration count too large"); |
|
370 } |
|
371 } |
|
372 |
351 byte[] keyInfo; |
373 byte[] keyInfo; |
352 while (true) { |
374 while (true) { |
353 try { |
375 try { |
354 // Use JCE |
376 // Use JCE |
355 SecretKey skey = getPBEKey(password); |
377 SecretKey skey = getPBEKey(password); |
385 KeyFactory kfac = KeyFactory.getInstance(keyAlgo); |
407 KeyFactory kfac = KeyFactory.getInstance(keyAlgo); |
386 PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(keyInfo); |
408 PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(keyInfo); |
387 key = kfac.generatePrivate(kspec); |
409 key = kfac.generatePrivate(kspec); |
388 |
410 |
389 if (debug != null) { |
411 if (debug != null) { |
390 debug.println("Retrieved a protected private key (" + |
412 debug.println("Retrieved a protected private key at alias" + |
391 key.getClass().getName() + ") at alias '" + alias + |
413 " '" + alias + "' (" + |
392 "'"); |
414 new AlgorithmId(algOid).getName() + |
|
415 " iterations: " + ic + ")"); |
393 } |
416 } |
394 |
417 |
395 // decode secret key |
418 // decode secret key |
396 } else { |
419 } else { |
397 byte[] keyBytes = in.getOctetString(); |
420 byte[] keyBytes = in.getOctetString(); |
408 } else { |
431 } else { |
409 key = secretKeySpec; |
432 key = secretKeySpec; |
410 } |
433 } |
411 |
434 |
412 if (debug != null) { |
435 if (debug != null) { |
413 debug.println("Retrieved a protected secret key (" + |
436 debug.println("Retrieved a protected secret key at alias " + |
414 key.getClass().getName() + ") at alias '" + alias + |
437 "'" + alias + "' (" + |
415 "'"); |
438 new AlgorithmId(algOid).getName() + |
|
439 " iterations: " + ic + ")"); |
416 } |
440 } |
417 } |
441 } |
418 } catch (Exception e) { |
442 } catch (Exception e) { |
419 UnrecoverableKeyException uke = |
443 UnrecoverableKeyException uke = |
420 new UnrecoverableKeyException("Get Key failed: " + |
444 new UnrecoverableKeyException("Get Key failed: " + |
588 |
612 |
589 if ((key.getFormat().equals("PKCS#8")) || |
613 if ((key.getFormat().equals("PKCS#8")) || |
590 (key.getFormat().equals("PKCS8"))) { |
614 (key.getFormat().equals("PKCS8"))) { |
591 |
615 |
592 if (debug != null) { |
616 if (debug != null) { |
593 debug.println("Setting a protected private key (" + |
617 debug.println( |
594 key.getClass().getName() + ") at alias '" + alias + |
618 "Setting a protected private key at alias '" + |
595 "'"); |
619 alias + "'"); |
596 } |
620 } |
597 |
621 |
598 // Encrypt the private key |
622 // Encrypt the private key |
599 keyEntry.protectedPrivKey = |
623 keyEntry.protectedPrivKey = |
600 encryptPrivateKey(key.getEncoded(), passwordProtection); |
624 encryptPrivateKey(key.getEncoded(), passwordProtection); |
759 } |
782 } |
760 |
783 |
761 /* |
784 /* |
762 * Generate PBE Algorithm Parameters |
785 * Generate PBE Algorithm Parameters |
763 */ |
786 */ |
764 private AlgorithmParameters getAlgorithmParameters(String algorithm) |
787 private AlgorithmParameters getPBEAlgorithmParameters(String algorithm) |
765 throws IOException |
788 throws IOException |
766 { |
789 { |
767 AlgorithmParameters algParams = null; |
790 AlgorithmParameters algParams = null; |
768 |
791 |
769 // create PBE parameters from salt and iteration count |
792 // create PBE parameters from salt and iteration count |
770 PBEParameterSpec paramSpec = |
793 PBEParameterSpec paramSpec = |
771 new PBEParameterSpec(getSalt(), iterationCount); |
794 new PBEParameterSpec(getSalt(), PBE_ITERATION_COUNT); |
772 try { |
795 try { |
773 algParams = AlgorithmParameters.getInstance(algorithm); |
796 algParams = AlgorithmParameters.getInstance(algorithm); |
774 algParams.init(paramSpec); |
797 algParams.init(paramSpec); |
775 } catch (Exception e) { |
798 } catch (Exception e) { |
776 throw new IOException("getAlgorithmParameters failed: " + |
799 throw new IOException("getPBEAlgorithmParameters failed: " + |
777 e.getMessage(), e); |
800 e.getMessage(), e); |
778 } |
801 } |
779 return algParams; |
802 return algParams; |
780 } |
803 } |
781 |
804 |
857 passwordProtection.getProtectionParameters(); |
880 passwordProtection.getProtectionParameters(); |
858 if (algParamSpec != null) { |
881 if (algParamSpec != null) { |
859 algParams = AlgorithmParameters.getInstance(algorithm); |
882 algParams = AlgorithmParameters.getInstance(algorithm); |
860 algParams.init(algParamSpec); |
883 algParams.init(algParamSpec); |
861 } else { |
884 } else { |
862 algParams = getAlgorithmParameters(algorithm); |
885 algParams = getPBEAlgorithmParameters(algorithm); |
863 } |
886 } |
864 } else { |
887 } else { |
865 // Check default key protection algorithm for PKCS12 keystores |
888 // Check default key protection algorithm for PKCS12 keystores |
866 algorithm = AccessController.doPrivileged( |
889 algorithm = AccessController.doPrivileged( |
867 new PrivilegedAction<String>() { |
890 new PrivilegedAction<String>() { |
877 } |
900 } |
878 }); |
901 }); |
879 if (algorithm == null || algorithm.isEmpty()) { |
902 if (algorithm == null || algorithm.isEmpty()) { |
880 algorithm = "PBEWithSHA1AndDESede"; |
903 algorithm = "PBEWithSHA1AndDESede"; |
881 } |
904 } |
882 algParams = getAlgorithmParameters(algorithm); |
905 algParams = getPBEAlgorithmParameters(algorithm); |
883 } |
906 } |
884 |
907 |
885 ObjectIdentifier pbeOID = mapPBEAlgorithmToOID(algorithm); |
908 ObjectIdentifier pbeOID = mapPBEAlgorithmToOID(algorithm); |
886 if (pbeOID == null) { |
909 if (pbeOID == null) { |
887 throw new IOException("PBE algorithm '" + algorithm + |
910 throw new IOException("PBE algorithm '" + algorithm + |
1192 // -- create safeContent Data ContentInfo |
1215 // -- create safeContent Data ContentInfo |
1193 if (privateKeyCount > 0 || secretKeyCount > 0) { |
1216 if (privateKeyCount > 0 || secretKeyCount > 0) { |
1194 |
1217 |
1195 if (debug != null) { |
1218 if (debug != null) { |
1196 debug.println("Storing " + (privateKeyCount + secretKeyCount) + |
1219 debug.println("Storing " + (privateKeyCount + secretKeyCount) + |
1197 " protected key(s) in a PKCS#7 data content-type"); |
1220 " protected key(s) in a PKCS#7 data"); |
1198 } |
1221 } |
1199 |
1222 |
1200 byte[] safeContentData = createSafeContent(); |
1223 byte[] safeContentData = createSafeContent(); |
1201 ContentInfo dataContentInfo = new ContentInfo(safeContentData); |
1224 ContentInfo dataContentInfo = new ContentInfo(safeContentData); |
1202 dataContentInfo.encode(authSafeContentInfo); |
1225 dataContentInfo.encode(authSafeContentInfo); |
1205 // -- create EncryptedContentInfo |
1228 // -- create EncryptedContentInfo |
1206 if (certificateCount > 0) { |
1229 if (certificateCount > 0) { |
1207 |
1230 |
1208 if (debug != null) { |
1231 if (debug != null) { |
1209 debug.println("Storing " + certificateCount + |
1232 debug.println("Storing " + certificateCount + |
1210 " certificate(s) in a PKCS#7 encryptedData content-type"); |
1233 " certificate(s) in a PKCS#7 encryptedData"); |
1211 } |
1234 } |
1212 |
1235 |
1213 byte[] encrData = createEncryptedData(password); |
1236 byte[] encrData = createEncryptedData(password); |
1214 ContentInfo encrContentInfo = |
1237 ContentInfo encrContentInfo = |
1215 new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID, |
1238 new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID, |
1476 byte[] salt = getSalt(); |
1499 byte[] salt = getSalt(); |
1477 |
1500 |
1478 // generate MAC (MAC key is generated within JCE) |
1501 // generate MAC (MAC key is generated within JCE) |
1479 Mac m = Mac.getInstance("HmacPBESHA1"); |
1502 Mac m = Mac.getInstance("HmacPBESHA1"); |
1480 PBEParameterSpec params = |
1503 PBEParameterSpec params = |
1481 new PBEParameterSpec(salt, iterationCount); |
1504 new PBEParameterSpec(salt, MAC_ITERATION_COUNT); |
1482 SecretKey key = getPBEKey(passwd); |
1505 SecretKey key = getPBEKey(passwd); |
1483 m.init(key, params); |
1506 m.init(key, params); |
1484 m.update(data); |
1507 m.update(data); |
1485 byte[] macResult = m.doFinal(); |
1508 byte[] macResult = m.doFinal(); |
1486 |
1509 |
1487 // encode as MacData |
1510 // encode as MacData |
1488 MacData macData = new MacData(algName, macResult, salt, |
1511 MacData macData = new MacData(algName, macResult, salt, |
1489 iterationCount); |
1512 MAC_ITERATION_COUNT); |
1490 DerOutputStream bytes = new DerOutputStream(); |
1513 DerOutputStream bytes = new DerOutputStream(); |
1491 bytes.write(macData.getEncoded()); |
1514 bytes.write(macData.getEncoded()); |
1492 mData = bytes.toByteArray(); |
1515 mData = bytes.toByteArray(); |
1493 } catch (Exception e) { |
1516 } catch (Exception e) { |
1494 throw new IOException("calculateMac failed: " + e, e); |
1517 throw new IOException("calculateMac failed: " + e, e); |
1876 |
1899 |
1877 byte[] encryptedData = null; |
1900 byte[] encryptedData = null; |
1878 |
1901 |
1879 // create AlgorithmParameters |
1902 // create AlgorithmParameters |
1880 AlgorithmParameters algParams = |
1903 AlgorithmParameters algParams = |
1881 getAlgorithmParameters("PBEWithSHA1AndRC2_40"); |
1904 getPBEAlgorithmParameters("PBEWithSHA1AndRC2_40"); |
1882 DerOutputStream bytes = new DerOutputStream(); |
1905 DerOutputStream bytes = new DerOutputStream(); |
1883 AlgorithmId algId = |
1906 AlgorithmId algId = |
1884 new AlgorithmId(pbeWithSHAAnd40BitRC2CBC_OID, algParams); |
1907 new AlgorithmId(pbeWithSHAAnd40BitRC2CBC_OID, algParams); |
1885 algId.encode(bytes); |
1908 algId.encode(bytes); |
1886 byte[] encodedAlgId = bytes.toByteArray(); |
1909 byte[] encodedAlgId = bytes.toByteArray(); |
1996 contentType = safeContents.getContentType(); |
2019 contentType = safeContents.getContentType(); |
1997 safeContentsData = null; |
2020 safeContentsData = null; |
1998 if (contentType.equals(ContentInfo.DATA_OID)) { |
2021 if (contentType.equals(ContentInfo.DATA_OID)) { |
1999 |
2022 |
2000 if (debug != null) { |
2023 if (debug != null) { |
2001 debug.println("Loading PKCS#7 data content-type"); |
2024 debug.println("Loading PKCS#7 data"); |
2002 } |
2025 } |
2003 |
2026 |
2004 safeContentsData = safeContents.getData(); |
2027 safeContentsData = safeContents.getData(); |
2005 } else if (contentType.equals(ContentInfo.ENCRYPTED_DATA_OID)) { |
2028 } else if (contentType.equals(ContentInfo.ENCRYPTED_DATA_OID)) { |
2006 if (password == null) { |
2029 if (password == null) { |
2007 |
2030 |
2008 if (debug != null) { |
2031 if (debug != null) { |
2009 debug.println("Warning: skipping PKCS#7 encryptedData" + |
2032 debug.println("Warning: skipping PKCS#7 encryptedData" + |
2010 " content-type - no password was supplied"); |
2033 " - no password was supplied"); |
2011 } |
2034 } |
2012 continue; |
2035 continue; |
2013 } |
|
2014 |
|
2015 if (debug != null) { |
|
2016 debug.println("Loading PKCS#7 encryptedData content-type"); |
|
2017 } |
2036 } |
2018 |
2037 |
2019 DerInputStream edi = |
2038 DerInputStream edi = |
2020 safeContents.getContent().toDerInputStream(); |
2039 safeContents.getContent().toDerInputStream(); |
2021 int edVersion = edi.getInteger(); |
2040 int edVersion = edi.getInteger(); |
2033 |
2052 |
2034 // parse Algorithm parameters |
2053 // parse Algorithm parameters |
2035 DerInputStream in = seq[1].toDerInputStream(); |
2054 DerInputStream in = seq[1].toDerInputStream(); |
2036 ObjectIdentifier algOid = in.getOID(); |
2055 ObjectIdentifier algOid = in.getOID(); |
2037 AlgorithmParameters algParams = parseAlgParameters(algOid, in); |
2056 AlgorithmParameters algParams = parseAlgParameters(algOid, in); |
|
2057 |
|
2058 PBEParameterSpec pbeSpec; |
|
2059 int ic = 0; |
|
2060 |
|
2061 if (algParams != null) { |
|
2062 try { |
|
2063 pbeSpec = |
|
2064 algParams.getParameterSpec(PBEParameterSpec.class); |
|
2065 } catch (InvalidParameterSpecException ipse) { |
|
2066 throw new IOException( |
|
2067 "Invalid PBE algorithm parameters"); |
|
2068 } |
|
2069 ic = pbeSpec.getIterationCount(); |
|
2070 |
|
2071 if (ic > MAX_ITERATION_COUNT) { |
|
2072 throw new IOException("PBE iteration count too large"); |
|
2073 } |
|
2074 } |
|
2075 |
|
2076 if (debug != null) { |
|
2077 debug.println("Loading PKCS#7 encryptedData " + |
|
2078 "(" + new AlgorithmId(algOid).getName() + |
|
2079 " iterations: " + ic + ")"); |
|
2080 } |
2038 |
2081 |
2039 while (true) { |
2082 while (true) { |
2040 try { |
2083 try { |
2041 // Use JCE |
2084 // Use JCE |
2042 SecretKey skey = getPBEKey(password); |
2085 SecretKey skey = getPBEKey(password); |
2064 loadSafeContents(sc, password); |
2107 loadSafeContents(sc, password); |
2065 } |
2108 } |
2066 |
2109 |
2067 // The MacData is optional. |
2110 // The MacData is optional. |
2068 if (password != null && s.available() > 0) { |
2111 if (password != null && s.available() > 0) { |
2069 MacData macData = new MacData(s); |
2112 MacData macData = new MacData(s); |
2070 try { |
2113 int ic = macData.getIterations(); |
|
2114 |
|
2115 try { |
|
2116 if (ic > MAX_ITERATION_COUNT) { |
|
2117 throw new InvalidAlgorithmParameterException( |
|
2118 "MAC iteration count too large: " + ic); |
|
2119 } |
|
2120 |
2071 String algName = |
2121 String algName = |
2072 macData.getDigestAlgName().toUpperCase(Locale.ENGLISH); |
2122 macData.getDigestAlgName().toUpperCase(Locale.ENGLISH); |
2073 |
2123 |
2074 // Change SHA-1 to SHA1 |
2124 // Change SHA-1 to SHA1 |
2075 algName = algName.replace("-", ""); |
2125 algName = algName.replace("-", ""); |
2076 |
2126 |
2077 // generate MAC (MAC key is created within JCE) |
2127 // generate MAC (MAC key is created within JCE) |
2078 Mac m = Mac.getInstance("HmacPBE" + algName); |
2128 Mac m = Mac.getInstance("HmacPBE" + algName); |
2079 PBEParameterSpec params = |
2129 PBEParameterSpec params = |
2080 new PBEParameterSpec(macData.getSalt(), |
2130 new PBEParameterSpec(macData.getSalt(), ic); |
2081 macData.getIterations()); |
|
2082 SecretKey key = getPBEKey(password); |
2131 SecretKey key = getPBEKey(password); |
2083 m.init(key, params); |
2132 m.init(key, params); |
2084 m.update(authSafeData); |
2133 m.update(authSafeData); |
2085 byte[] macResult = m.doFinal(); |
2134 byte[] macResult = m.doFinal(); |
2086 |
2135 |
2087 if (debug != null) { |
2136 if (debug != null) { |
2088 debug.println("Checking keystore integrity " + |
2137 debug.println("Checking keystore integrity " + |
2089 "(MAC algorithm: " + m.getAlgorithm() + ")"); |
2138 "(" + m.getAlgorithm() + " iterations: " + ic + ")"); |
2090 } |
2139 } |
2091 |
2140 |
2092 if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { |
2141 if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { |
2093 throw new UnrecoverableKeyException("Failed PKCS12" + |
2142 throw new UnrecoverableKeyException("Failed PKCS12" + |
2094 " integrity checking"); |
2143 " integrity checking"); |
2095 } |
2144 } |
2096 } catch (Exception e) { |
2145 } catch (Exception e) { |
2097 throw new IOException("Integrity check failed: " + e, e); |
2146 throw new IOException("Integrity check failed: " + e, e); |
2098 } |
2147 } |
2099 } |
2148 } |
2100 |
2149 |
2101 /* |
2150 /* |
2102 * Match up private keys with certificate chains. |
2151 * Match up private keys with certificate chains. |
2103 */ |
2152 */ |