52 import java.util.*;
53
54 import java.security.AlgorithmParameters;
55 import java.security.InvalidAlgorithmParameterException;
56 import javax.crypto.spec.PBEParameterSpec;
57 import javax.crypto.spec.PBEKeySpec;
58 import javax.crypto.spec.SecretKeySpec;
59 import javax.crypto.SecretKeyFactory;
60 import javax.crypto.SecretKey;
61 import javax.crypto.Cipher;
62 import javax.crypto.Mac;
63 import javax.security.auth.DestroyFailedException;
64 import javax.security.auth.x500.X500Principal;
65
66 import sun.security.util.Debug;
67 import sun.security.util.DerInputStream;
68 import sun.security.util.DerOutputStream;
69 import sun.security.util.DerValue;
70 import sun.security.util.ObjectIdentifier;
71 import sun.security.pkcs.ContentInfo;
72 import sun.security.x509.AlgorithmId;
73 import sun.security.pkcs.EncryptedPrivateKeyInfo;
74
75
76 /**
77 * This class provides the keystore implementation referred to as "PKCS12".
78 * Implements the PKCS#12 PFX protected using the Password privacy mode.
79 * The contents are protected using Password integrity mode.
80 *
81 * Currently we support following PBE algorithms:
82 * - pbeWithSHAAnd3KeyTripleDESCBC to encrypt private keys
83 * - pbeWithSHAAnd40BitRC2CBC to encrypt certificates
84 *
85 * Supported encryption of various implementations :
86 *
87 * Software and mode. Certificate encryption Private key encryption
88 * ---------------------------------------------------------------------
89 * MSIE4 (domestic 40 bit RC2. 40 bit RC2
90 * and xport versions)
91 * PKCS#12 export.
92 *
93 * MSIE4, 5 (domestic 40 bit RC2, 40 bit RC2,
94 * and export versions) 3 key triple DES 3 key triple DES
95 * PKCS#12 import.
96 *
97 * MSIE5 40 bit RC2 3 key triple DES,
98 * PKCS#12 export. with SHA1 (168 bits)
99 *
100 * Netscape Communicator 40 bit RC2 3 key triple DES,
101 * (domestic and export with SHA1 (168 bits)
102 * versions) PKCS#12 export
103 *
106 * PKCS#12 import.
107 *
108 * Netscape Communicator All. All.
109 * (domestic or fortified
110 * version) PKCS#12 import.
111 *
112 * OpenSSL PKCS#12 code. All. All.
113 * ---------------------------------------------------------------------
114 *
115 * NOTE: PKCS12 KeyStore supports PrivateKeyEntry and TrustedCertficateEntry.
116 * PKCS#12 is mainly used to deliver private keys with their associated
117 * certificate chain and aliases. In a PKCS12 keystore, entries are
118 * identified by the alias, and a localKeyId is required to match the
119 * private key with the certificate. Trusted certificate entries are identified
120 * by the presence of an trustedKeyUsage attribute.
121 *
122 * @author Seema Malkani
123 * @author Jeff Nisewanger
124 * @author Jan Luehe
125 *
126 * @see KeyProtector
127 * @see java.security.KeyStoreSpi
128 * @see KeyTool
129 *
130 *
131 */
132 public final class PKCS12KeyStore extends KeyStoreSpi {
133
134 public static final int VERSION_3 = 3;
135
136 private static final String[] KEY_PROTECTION_ALGORITHM = {
137 "keystore.pkcs12.keyProtectionAlgorithm",
138 "keystore.PKCS12.keyProtectionAlgorithm"
139 };
140
141 private static final int MAX_ITERATION_COUNT = 5000000;
142 private static final int PBE_ITERATION_COUNT = 50000; // default
143 private static final int MAC_ITERATION_COUNT = 100000; // default
144 private static final int SALT_LEN = 20;
145
146 // friendlyName, localKeyId, trustedKeyUsage
147 private static final String[] CORE_ATTRIBUTES = {
148 "1.2.840.113549.1.9.20",
149 "1.2.840.113549.1.9.21",
150 "2.16.840.1.113894.746875.1.1"
151 };
152
153 private static final Debug debug = Debug.getInstance("pkcs12");
154
155 private static final int keyBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 2};
156 private static final int certBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 3};
157 private static final int secretBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 5};
158
159 private static final int pkcs9Name[] = {1, 2, 840, 113549, 1, 9, 20};
160 private static final int pkcs9KeyId[] = {1, 2, 840, 113549, 1, 9, 21};
161
162 private static final int pkcs9certType[] = {1, 2, 840, 113549, 1, 9, 22, 1};
163
164 private static final int pbeWithSHAAnd40BitRC2CBC[] =
165 {1, 2, 840, 113549, 1, 12, 1, 6};
166 private static final int pbeWithSHAAnd3KeyTripleDESCBC[] =
167 {1, 2, 840, 113549, 1, 12, 1, 3};
168 private static final int pbes2[] = {1, 2, 840, 113549, 1, 5, 13};
169 // TODO: temporary Oracle OID
170 /*
171 * { joint-iso-itu-t(2) country(16) us(840) organization(1) oracle(113894)
172 * jdk(746875) crypto(1) id-at-trustedKeyUsage(1) }
173 */
174 private static final int TrustedKeyUsage[] =
175 {2, 16, 840, 1, 113894, 746875, 1, 1};
176 private static final int AnyExtendedKeyUsage[] = {2, 5, 29, 37, 0};
177
178 private static ObjectIdentifier PKCS8ShroudedKeyBag_OID;
179 private static ObjectIdentifier CertBag_OID;
180 private static ObjectIdentifier SecretBag_OID;
181 private static ObjectIdentifier PKCS9FriendlyName_OID;
182 private static ObjectIdentifier PKCS9LocalKeyId_OID;
183 private static ObjectIdentifier PKCS9CertType_OID;
184 private static ObjectIdentifier pbeWithSHAAnd40BitRC2CBC_OID;
185 private static ObjectIdentifier pbeWithSHAAnd3KeyTripleDESCBC_OID;
186 private static ObjectIdentifier pbes2_OID;
187 private static ObjectIdentifier TrustedKeyUsage_OID;
188 private static ObjectIdentifier[] AnyUsage;
189
190 private int counter = 0;
191
192 // private key count
193 // Note: This is a workaround to allow null localKeyID attribute
194 // in pkcs12 with one private key entry and associated cert-chain
195 private int privateKeyCount = 0;
196
197 // secret key count
198 private int secretKeyCount = 0;
199
200 // certificate count
201 private int certificateCount = 0;
202
203 // the source of randomness
204 private SecureRandom random;
205
206 static {
207 try {
208 PKCS8ShroudedKeyBag_OID = new ObjectIdentifier(keyBag);
209 CertBag_OID = new ObjectIdentifier(certBag);
210 SecretBag_OID = new ObjectIdentifier(secretBag);
211 PKCS9FriendlyName_OID = new ObjectIdentifier(pkcs9Name);
212 PKCS9LocalKeyId_OID = new ObjectIdentifier(pkcs9KeyId);
213 PKCS9CertType_OID = new ObjectIdentifier(pkcs9certType);
214 pbeWithSHAAnd40BitRC2CBC_OID =
215 new ObjectIdentifier(pbeWithSHAAnd40BitRC2CBC);
216 pbeWithSHAAnd3KeyTripleDESCBC_OID =
217 new ObjectIdentifier(pbeWithSHAAnd3KeyTripleDESCBC);
218 pbes2_OID = new ObjectIdentifier(pbes2);
219 TrustedKeyUsage_OID = new ObjectIdentifier(TrustedKeyUsage);
220 AnyUsage = new ObjectIdentifier[]{
221 new ObjectIdentifier(AnyExtendedKeyUsage)};
222 } catch (IOException ioe) {
223 // should not happen
224 }
225 }
226
227 // A keystore entry and associated attributes
228 private static class Entry {
229 Date date; // the creation date of this entry
230 String alias;
231 byte[] keyId;
232 Set<KeyStore.Entry.Attribute> attributes;
233 }
234
235 // A key entry
236 private static class KeyEntry extends Entry {
237 }
238
239 // A private key entry and its supporting certificate chain
240 private static class PrivateKeyEntry extends KeyEntry {
241 byte[] protectedPrivKey;
242 Certificate chain[];
243 };
364 new UnrecoverableKeyException("Private key not stored as "
365 + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe);
366 uke.initCause(ioe);
367 throw uke;
368 }
369
370 try {
371 PBEParameterSpec pbeSpec;
372 int ic;
373
374 if (algParams != null) {
375 try {
376 pbeSpec =
377 algParams.getParameterSpec(PBEParameterSpec.class);
378 } catch (InvalidParameterSpecException ipse) {
379 throw new IOException("Invalid PBE algorithm parameters");
380 }
381 ic = pbeSpec.getIterationCount();
382
383 if (ic > MAX_ITERATION_COUNT) {
384 throw new IOException("PBE iteration count too large");
385 }
386 } else {
387 ic = 0;
388 }
389
390 key = RetryWithZero.run(pass -> {
391 // Use JCE
392 SecretKey skey = getPBEKey(pass);
393 Cipher cipher = Cipher.getInstance(
394 mapPBEParamsToAlgorithm(algOid, algParams));
395 cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
396 byte[] keyInfo = cipher.doFinal(encryptedKey);
397 /*
398 * Parse the key algorithm and then use a JCA key factory
399 * to re-create the key.
400 */
401 DerValue val = new DerValue(keyInfo);
402 DerInputStream in = val.toDerInputStream();
403 int i = in.getInteger();
404 DerValue[] value = in.getSequence(2);
405 if (value.length < 1 || value.length > 2) {
406 throw new IOException("Invalid length for AlgorithmIdentifier");
407 }
408 AlgorithmId algId = new AlgorithmId(value[0].getOID());
409 String keyAlgo = algId.getName();
410
411 // decode private key
412 if (entry instanceof PrivateKeyEntry) {
413 KeyFactory kfac = KeyFactory.getInstance(keyAlgo);
414 PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(keyInfo);
415 Key tmp = kfac.generatePrivate(kspec);
416
417 if (debug != null) {
418 debug.println("Retrieved a protected private key at alias" +
419 " '" + alias + "' (" +
420 new AlgorithmId(algOid).getName() +
421 " iterations: " + ic + ")");
422 }
423 return tmp;
424 // decode secret key
425 } else {
426 byte[] keyBytes = in.getOctetString();
427 SecretKeySpec secretKeySpec =
428 new SecretKeySpec(keyBytes, keyAlgo);
429
430 // Special handling required for PBE: needs a PBEKeySpec
431 Key tmp;
432 if (keyAlgo.startsWith("PBE")) {
433 SecretKeyFactory sKeyFactory =
434 SecretKeyFactory.getInstance(keyAlgo);
435 KeySpec pbeKeySpec =
436 sKeyFactory.getKeySpec(secretKeySpec, PBEKeySpec.class);
437 tmp = sKeyFactory.generateSecret(pbeKeySpec);
438 } else {
439 tmp = secretKeySpec;
440 }
441
442 if (debug != null) {
443 debug.println("Retrieved a protected secret key at alias " +
444 "'" + alias + "' (" +
445 new AlgorithmId(algOid).getName() +
446 " iterations: " + ic + ")");
447 }
448 return tmp;
449 }
450 }, password);
451
452 } catch (Exception e) {
453 UnrecoverableKeyException uke =
454 new UnrecoverableKeyException("Get Key failed: " +
455 e.getMessage());
456 uke.initCause(e);
457 throw uke;
458 }
459 return key;
460 }
461
462 /**
463 * Returns the certificate chain associated with the given alias.
464 *
465 * @param alias the alias name
674 }
675 secretKeyCount++;
676 entry = keyEntry;
677
678 } else {
679 throw new KeyStoreException("Unsupported Key type");
680 }
681
682 entry.attributes = new HashSet<>();
683 if (attributes != null) {
684 entry.attributes.addAll(attributes);
685 }
686 // set the keyId to current date
687 entry.keyId = ("Time " + (entry.date).getTime()).getBytes("UTF8");
688 // set the alias
689 entry.alias = alias.toLowerCase(Locale.ENGLISH);
690 // add the entry
691 entries.put(alias.toLowerCase(Locale.ENGLISH), entry);
692
693 } catch (Exception nsae) {
694 throw new KeyStoreException("Key protection " +
695 " algorithm not found: " + nsae, nsae);
696 }
697 }
698
699 /**
700 * Assigns the given key (that has already been protected) to the given
701 * alias.
702 *
703 * <p>If the protected key is of type
704 * <code>java.security.PrivateKey</code>, it must be accompanied by a
705 * certificate chain certifying the corresponding public key. If the
706 * underlying keystore implementation is of type <code>jks</code>,
707 * <code>key</code> must be encoded as an
708 * <code>EncryptedPrivateKeyInfo</code> as defined in the PKCS #8 standard.
709 *
710 * <p>If the given alias already exists, the keystore information
711 * associated with it is overridden by the given key (and possibly
712 * certificate chain).
713 *
714 * @param alias the alias name
771 }
772
773
774 /*
775 * Generate random salt
776 */
777 private byte[] getSalt()
778 {
779 // Generate a random salt.
780 byte[] salt = new byte[SALT_LEN];
781 if (random == null) {
782 random = new SecureRandom();
783 }
784 random.nextBytes(salt);
785 return salt;
786 }
787
788 /*
789 * Generate PBE Algorithm Parameters
790 */
791 private AlgorithmParameters getPBEAlgorithmParameters(String algorithm)
792 throws IOException
793 {
794 AlgorithmParameters algParams = null;
795
796 // create PBE parameters from salt and iteration count
797 PBEParameterSpec paramSpec =
798 new PBEParameterSpec(getSalt(), PBE_ITERATION_COUNT);
799 try {
800 algParams = AlgorithmParameters.getInstance(algorithm);
801 algParams.init(paramSpec);
802 } catch (Exception e) {
803 throw new IOException("getPBEAlgorithmParameters failed: " +
804 e.getMessage(), e);
805 }
806 return algParams;
807 }
808
809 /*
810 * parse Algorithm Parameters
811 */
812 private AlgorithmParameters parseAlgParameters(ObjectIdentifier algorithm,
813 DerInputStream in) throws IOException
814 {
815 AlgorithmParameters algParams = null;
816 try {
817 DerValue params;
818 if (in.available() == 0) {
841 /*
842 * Generate PBE key
843 */
844 private SecretKey getPBEKey(char[] password) throws IOException
845 {
846 SecretKey skey = null;
847
848 try {
849 PBEKeySpec keySpec = new PBEKeySpec(password);
850 SecretKeyFactory skFac = SecretKeyFactory.getInstance("PBE");
851 skey = skFac.generateSecret(keySpec);
852 keySpec.clearPassword();
853 } catch (Exception e) {
854 throw new IOException("getSecretKey failed: " +
855 e.getMessage(), e);
856 }
857 return skey;
858 }
859
860 /*
861 * Encrypt private key using Password-based encryption (PBE)
862 * as defined in PKCS#5.
863 *
864 * NOTE: By default, pbeWithSHAAnd3-KeyTripleDES-CBC algorithmID is
865 * used to derive the key and IV.
866 *
867 * @return encrypted private key encoded as EncryptedPrivateKeyInfo
868 */
869 private byte[] encryptPrivateKey(byte[] data,
870 KeyStore.PasswordProtection passwordProtection)
871 throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException
872 {
873 byte[] key = null;
874
875 try {
876 String algorithm;
877 AlgorithmParameters algParams;
878 AlgorithmId algid;
879
880 // Initialize PBE algorithm and parameters
881 algorithm = passwordProtection.getProtectionAlgorithm();
882 if (algorithm != null) {
883 AlgorithmParameterSpec algParamSpec =
884 passwordProtection.getProtectionParameters();
885 if (algParamSpec != null) {
886 algParams = AlgorithmParameters.getInstance(algorithm);
887 algParams.init(algParamSpec);
888 } else {
889 algParams = getPBEAlgorithmParameters(algorithm);
890 }
891 } else {
892 // Check default key protection algorithm for PKCS12 keystores
893 algorithm = AccessController.doPrivileged(
894 new PrivilegedAction<String>() {
895 public String run() {
896 String prop =
897 Security.getProperty(
898 KEY_PROTECTION_ALGORITHM[0]);
899 if (prop == null) {
900 prop = Security.getProperty(
901 KEY_PROTECTION_ALGORITHM[1]);
902 }
903 return prop;
904 }
905 });
906 if (algorithm == null || algorithm.isEmpty()) {
907 algorithm = "PBEWithSHA1AndDESede";
908 }
909 algParams = getPBEAlgorithmParameters(algorithm);
910 }
911
912 ObjectIdentifier pbeOID = mapPBEAlgorithmToOID(algorithm);
913 if (pbeOID == null) {
914 throw new IOException("PBE algorithm '" + algorithm +
915 " 'is not supported for key entry protection");
916 }
917
918 // Use JCE
919 SecretKey skey = getPBEKey(passwordProtection.getPassword());
920 Cipher cipher = Cipher.getInstance(algorithm);
921 cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
922 byte[] encryptedKey = cipher.doFinal(data);
923 algid = new AlgorithmId(pbeOID, cipher.getParameters());
924
925 if (debug != null) {
926 debug.println(" (Cipher algorithm: " + cipher.getAlgorithm() +
927 ")");
928 }
929
947 * Map a PBE algorithm name onto its object identifier
948 */
949 private static ObjectIdentifier mapPBEAlgorithmToOID(String algorithm)
950 throws NoSuchAlgorithmException {
951 // Check for PBES2 algorithms
952 if (algorithm.toLowerCase(Locale.ENGLISH).startsWith("pbewithhmacsha")) {
953 return pbes2_OID;
954 }
955 return AlgorithmId.get(algorithm).getOID();
956 }
957
958 /*
959 * Map a PBE algorithm parameters onto its algorithm name
960 */
961 private static String mapPBEParamsToAlgorithm(ObjectIdentifier algorithm,
962 AlgorithmParameters algParams) throws NoSuchAlgorithmException {
963 // Check for PBES2 algorithms
964 if (algorithm.equals((Object)pbes2_OID) && algParams != null) {
965 return algParams.toString();
966 }
967 return algorithm.toString();
968 }
969
970 /**
971 * Assigns the given certificate to the given alias.
972 *
973 * <p>If the given alias already exists in this keystore and identifies a
974 * <i>trusted certificate entry</i>, the certificate associated with it is
975 * overridden by the given certificate.
976 *
977 * @param alias the alias name
978 * @param cert the certificate
979 *
980 * @exception KeyStoreException if the given alias already exists and does
981 * not identify a <i>trusted certificate entry</i>, or this operation fails
982 * for some other reason.
983 */
984 public synchronized void engineSetCertificateEntry(String alias,
985 Certificate cert) throws KeyStoreException
986 {
987 setCertEntry(alias, cert, null);
1172 }
1173 return null;
1174 }
1175
1176 /**
1177 * Stores this keystore to the given output stream, and protects its
1178 * integrity with the given password.
1179 *
1180 * @param stream the output stream to which this keystore is written.
1181 * @param password the password to generate the keystore integrity check
1182 *
1183 * @exception IOException if there was an I/O problem with data
1184 * @exception NoSuchAlgorithmException if the appropriate data integrity
1185 * algorithm could not be found
1186 * @exception CertificateException if any of the certificates included in
1187 * the keystore data could not be stored
1188 */
1189 public synchronized void engineStore(OutputStream stream, char[] password)
1190 throws IOException, NoSuchAlgorithmException, CertificateException
1191 {
1192 // password is mandatory when storing
1193 if (password == null) {
1194 throw new IllegalArgumentException("password can't be null");
1195 }
1196
1197 // -- Create PFX
1198 DerOutputStream pfx = new DerOutputStream();
1199
1200 // PFX version (always write the latest version)
1201 DerOutputStream version = new DerOutputStream();
1202 version.putInteger(VERSION_3);
1203 byte[] pfxVersion = version.toByteArray();
1204 pfx.write(pfxVersion);
1205
1206 // -- Create AuthSafe
1207 DerOutputStream authSafe = new DerOutputStream();
1208
1209 // -- Create ContentInfos
1210 DerOutputStream authSafeContentInfo = new DerOutputStream();
1211
1212 // -- create safeContent Data ContentInfo
1213 if (privateKeyCount > 0 || secretKeyCount > 0) {
1214
1215 if (debug != null) {
1216 debug.println("Storing " + (privateKeyCount + secretKeyCount) +
1217 " protected key(s) in a PKCS#7 data");
1218 }
1219
1220 byte[] safeContentData = createSafeContent();
1221 ContentInfo dataContentInfo = new ContentInfo(safeContentData);
1222 dataContentInfo.encode(authSafeContentInfo);
1223 }
1224
1225 // -- create EncryptedContentInfo
1226 if (certificateCount > 0) {
1227
1228 if (debug != null) {
1229 debug.println("Storing " + certificateCount +
1230 " certificate(s) in a PKCS#7 encryptedData");
1231 }
1232
1233 byte[] encrData = createEncryptedData(password);
1234 ContentInfo encrContentInfo =
1235 new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID,
1236 new DerValue(encrData));
1237 encrContentInfo.encode(authSafeContentInfo);
1238 }
1239
1240 // wrap as SequenceOf ContentInfos
1241 DerOutputStream cInfo = new DerOutputStream();
1242 cInfo.write(DerValue.tag_SequenceOf, authSafeContentInfo);
1243 byte[] authenticatedSafe = cInfo.toByteArray();
1244
1245 // Create Encapsulated ContentInfo
1246 ContentInfo contentInfo = new ContentInfo(authenticatedSafe);
1247 contentInfo.encode(authSafe);
1248 byte[] authSafeData = authSafe.toByteArray();
1249 pfx.write(authSafeData);
1250
1251 // -- MAC
1252 byte[] macData = calculateMac(password, authenticatedSafe);
1253 pfx.write(macData);
1254
1255 // write PFX to output stream
1256 DerOutputStream pfxout = new DerOutputStream();
1257 pfxout.write(DerValue.tag_Sequence, pfx);
1258 byte[] pfxData = pfxout.toByteArray();
1259 stream.write(pfxData);
1260 stream.flush();
1261 }
1262
1263 /**
1264 * Gets a <code>KeyStore.Entry</code> for the specified alias
1265 * with the specified protection parameter.
1266 *
1267 * @param alias get the <code>KeyStore.Entry</code> for this alias
1268 * @param protParam the <code>ProtectionParameter</code>
1269 * used to protect the <code>Entry</code>,
1270 * which may be <code>null</code>
1271 *
1272 * @return the <code>KeyStore.Entry</code> for the specified alias,
1273 * or <code>null</code> if there is no such entry
1274 *
1445 if (entry instanceof CertEntry) {
1446 ObjectIdentifier[] trustedKeyUsageValue =
1447 ((CertEntry) entry).trustedKeyUsage;
1448 if (trustedKeyUsageValue != null) {
1449 if (trustedKeyUsageValue.length == 1) { // omit brackets
1450 entry.attributes.add(new PKCS12Attribute(
1451 TrustedKeyUsage_OID.toString(),
1452 trustedKeyUsageValue[0].toString()));
1453 } else { // multi-valued
1454 entry.attributes.add(new PKCS12Attribute(
1455 TrustedKeyUsage_OID.toString(),
1456 Arrays.toString(trustedKeyUsageValue)));
1457 }
1458 }
1459 }
1460
1461 return entry.attributes;
1462 }
1463
1464 /*
1465 * Generate Hash.
1466 */
1467 private byte[] generateHash(byte[] data) throws IOException
1468 {
1469 byte[] digest = null;
1470
1471 try {
1472 MessageDigest md = MessageDigest.getInstance("SHA1");
1473 md.update(data);
1474 digest = md.digest();
1475 } catch (Exception e) {
1476 throw new IOException("generateHash failed: " + e, e);
1477 }
1478 return digest;
1479 }
1480
1481
1482 /*
1483 * Calculate MAC using HMAC algorithm (required for password integrity)
1484 *
1485 * Hash-based MAC algorithm combines secret key with message digest to
1486 * create a message authentication code (MAC)
1487 */
1488 private byte[] calculateMac(char[] passwd, byte[] data)
1489 throws IOException
1490 {
1491 byte[] mData = null;
1492 String algName = "SHA1";
1493
1494 try {
1495 // Generate a random salt.
1496 byte[] salt = getSalt();
1497
1498 // generate MAC (MAC key is generated within JCE)
1499 Mac m = Mac.getInstance("HmacPBESHA1");
1500 PBEParameterSpec params =
1501 new PBEParameterSpec(salt, MAC_ITERATION_COUNT);
1502 SecretKey key = getPBEKey(passwd);
1503 m.init(key, params);
1504 m.update(data);
1505 byte[] macResult = m.doFinal();
1506
1507 // encode as MacData
1508 MacData macData = new MacData(algName, macResult, salt,
1509 MAC_ITERATION_COUNT);
1510 DerOutputStream bytes = new DerOutputStream();
1511 bytes.write(macData.getEncoded());
1512 mData = bytes.toByteArray();
1513 } catch (Exception e) {
1514 throw new IOException("calculateMac failed: " + e, e);
1515 }
1516 return mData;
1517 }
1518
1519
1520 /*
1521 * Validate Certificate Chain
1522 */
1523 private boolean validateChain(Certificate[] certChain)
1524 {
1525 for (int i = 0; i < certChain.length-1; i++) {
1526 X500Principal issuerDN =
1527 ((X509Certificate)certChain[i]).getIssuerX500Principal();
1528 X500Principal subjectDN =
1529 ((X509Certificate)certChain[i+1]).getSubjectX500Principal();
1747 // However, IE/OpenSSL do not impose this restriction.
1748 bagAttrs = getBagAttributes(
1749 cert.getSubjectX500Principal().getName(), null,
1750 entry.attributes);
1751 }
1752 if (bagAttrs != null) {
1753 safeBag.write(bagAttrs);
1754 }
1755
1756 // wrap as Sequence
1757 out.write(DerValue.tag_Sequence, safeBag);
1758 } // for cert-chain
1759 }
1760
1761 // wrap as SequenceOf SafeBag
1762 DerOutputStream safeBagValue = new DerOutputStream();
1763 safeBagValue.write(DerValue.tag_SequenceOf, out);
1764 byte[] safeBagData = safeBagValue.toByteArray();
1765
1766 // encrypt the content (EncryptedContentInfo)
1767 byte[] encrContentInfo = encryptContent(safeBagData, password);
1768
1769 // -- SEQUENCE of EncryptedData
1770 DerOutputStream encrData = new DerOutputStream();
1771 DerOutputStream encrDataContent = new DerOutputStream();
1772 encrData.putInteger(0);
1773 encrData.write(encrContentInfo);
1774 encrDataContent.write(DerValue.tag_Sequence, encrData);
1775 return encrDataContent.toByteArray();
1776 }
1777
1778 /*
1779 * Create SafeContent Data content type.
1780 * Includes encrypted secret key in a SafeBag of type SecretBag.
1781 * Includes encrypted private key in a SafeBag of type PKCS8ShroudedKeyBag.
1782 * Each PKCS8ShroudedKeyBag includes pkcs12 attributes
1783 * (see comments in getBagAttributes)
1784 */
1785 private byte[] createSafeContent()
1786 throws CertificateException, IOException {
1787
1788 DerOutputStream out = new DerOutputStream();
1789 for (Enumeration<String> e = engineAliases(); e.hasMoreElements(); ) {
1790
1791 String alias = e.nextElement();
1792 Entry entry = entries.get(alias);
1793 if (entry == null || (!(entry instanceof KeyEntry))) {
1794 continue;
1795 }
1864 DerOutputStream safeBagValue = new DerOutputStream();
1865 safeBagValue.write(DerValue.tag_Sequence, out);
1866 return safeBagValue.toByteArray();
1867 }
1868
1869
1870 /*
1871 * Encrypt the contents using Password-based (PBE) encryption
1872 * as defined in PKCS #5.
1873 *
1874 * NOTE: Currently pbeWithSHAAnd40BiteRC2-CBC algorithmID is used
1875 * to derive the key and IV.
1876 *
1877 * @return encrypted contents encoded as EncryptedContentInfo
1878 */
1879 private byte[] encryptContent(byte[] data, char[] password)
1880 throws IOException {
1881
1882 byte[] encryptedData = null;
1883
1884 // create AlgorithmParameters
1885 AlgorithmParameters algParams =
1886 getPBEAlgorithmParameters("PBEWithSHA1AndRC2_40");
1887 DerOutputStream bytes = new DerOutputStream();
1888 AlgorithmId algId =
1889 new AlgorithmId(pbeWithSHAAnd40BitRC2CBC_OID, algParams);
1890 algId.encode(bytes);
1891 byte[] encodedAlgId = bytes.toByteArray();
1892
1893 try {
1894 // Use JCE
1895 SecretKey skey = getPBEKey(password);
1896 Cipher cipher = Cipher.getInstance("PBEWithSHA1AndRC2_40");
1897 cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
1898 encryptedData = cipher.doFinal(data);
1899
1900 if (debug != null) {
1901 debug.println(" (Cipher algorithm: " + cipher.getAlgorithm() +
1902 ")");
1903 }
1904
1905 } catch (Exception e) {
1906 throw new IOException("Failed to encrypt" +
1907 " safe contents entry: " + e, e);
1908 }
1909
1910 // create EncryptedContentInfo
1911 DerOutputStream bytes2 = new DerOutputStream();
1912 bytes2.putOID(ContentInfo.DATA_OID);
1913 bytes2.write(encodedAlgId);
1914
1915 // Wrap encrypted data in a context-specific tag.
1916 DerOutputStream tmpout2 = new DerOutputStream();
1917 tmpout2.putOctetString(encryptedData);
1918 bytes2.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
1919 false, (byte)0), tmpout2);
1920
1921 // wrap EncryptedContentInfo in a Sequence
1922 DerOutputStream out = new DerOutputStream();
1923 out.write(DerValue.tag_Sequence, bytes2);
1924 return out.toByteArray();
1925 }
1926
1927 /**
1928 * Loads the keystore from the given input stream.
1929 *
1930 * <p>If a password is given, it is used to check the integrity of the
1931 * keystore data. Otherwise, the integrity of the keystore is not checked.
1932 *
1933 * @param stream the input stream from which the keystore is loaded
1934 * @param password the (optional) password used to check the integrity of
1935 * the keystore.
1936 *
1937 * @exception IOException if there is an I/O or format problem with the
1938 * keystore data
1939 * @exception NoSuchAlgorithmException if the algorithm used to check
1940 * the integrity of the keystore cannot be found
1941 * @exception CertificateException if any of the certificates in the
1942 * keystore could not be loaded
1943 */
1944 public synchronized void engineLoad(InputStream stream, char[] password)
1945 throws IOException, NoSuchAlgorithmException, CertificateException
1946 {
1947 DataInputStream dis;
1948 CertificateFactory cf = null;
1949 ByteArrayInputStream bais = null;
1950 byte[] encoded = null;
1951
1952 if (stream == null)
1953 return;
1954
1955 // reset the counter
1956 counter = 0;
1957
1958 DerValue val = new DerValue(stream);
1959 DerInputStream s = val.toDerInputStream();
1960 int version = s.getInteger();
1961
1962 if (version != VERSION_3) {
1963 throw new IOException("PKCS12 keystore not in version 3 format");
1964 }
1965
1966 entries.clear();
1967
1968 /*
1969 * Read the authSafe.
1970 */
1971 byte[] authSafeData;
1972 ContentInfo authSafe = new ContentInfo(s);
1973 ObjectIdentifier contentType = authSafe.getContentType();
1974
1975 if (contentType.equals((Object)ContentInfo.DATA_OID)) {
1976 authSafeData = authSafe.getData();
1977 } else /* signed data */ {
1978 throw new IOException("public key protected PKCS12 not supported");
1979 }
1980
1981 DerInputStream as = new DerInputStream(authSafeData);
1982 DerValue[] safeContentsArray = as.getSequence(2);
1983 int count = safeContentsArray.length;
1984
1985 // reset the counters at the start
1986 privateKeyCount = 0;
1987 secretKeyCount = 0;
1988 certificateCount = 0;
1989
1990 /*
1991 * Spin over the ContentInfos.
1992 */
1993 for (int i = 0; i < count; i++) {
1994 ContentInfo safeContents;
1995 DerInputStream sci;
1996 byte[] eAlgId = null;
1997
1998 sci = new DerInputStream(safeContentsArray[i].toByteArray());
1999 safeContents = new ContentInfo(sci);
2000 contentType = safeContents.getContentType();
2001 if (contentType.equals((Object)ContentInfo.DATA_OID)) {
2002
2003 if (debug != null) {
2004 debug.println("Loading PKCS#7 data");
2005 }
2006
2007 loadSafeContents(new DerInputStream(safeContents.getData()));
2008 } else if (contentType.equals((Object)ContentInfo.ENCRYPTED_DATA_OID)) {
2009 if (password == null) {
2010
2011 if (debug != null) {
2012 debug.println("Warning: skipping PKCS#7 encryptedData" +
2013 " - no password was supplied");
2014 }
2015 continue;
2016 }
2017
2018 DerInputStream edi =
2019 safeContents.getContent().toDerInputStream();
2020 int edVersion = edi.getInteger();
2021 DerValue[] seq = edi.getSequence(3);
2022 if (seq.length != 3) {
2023 // We require the encryptedContent field, even though
2024 // it is optional
2025 throw new IOException("Invalid length for EncryptedContentInfo");
2026 }
2027 ObjectIdentifier edContentType = seq[0].getOID();
2028 eAlgId = seq[1].toByteArray();
2029 if (!seq[2].isContextSpecific((byte)0)) {
2030 throw new IOException("unsupported encrypted content type "
2031 + seq[2].tag);
2032 }
2033 byte newTag = DerValue.tag_OctetString;
2034 if (seq[2].isConstructed())
2038
2039 // parse Algorithm parameters
2040 DerInputStream in = seq[1].toDerInputStream();
2041 ObjectIdentifier algOid = in.getOID();
2042 AlgorithmParameters algParams = parseAlgParameters(algOid, in);
2043
2044 PBEParameterSpec pbeSpec;
2045 int ic = 0;
2046
2047 if (algParams != null) {
2048 try {
2049 pbeSpec =
2050 algParams.getParameterSpec(PBEParameterSpec.class);
2051 } catch (InvalidParameterSpecException ipse) {
2052 throw new IOException(
2053 "Invalid PBE algorithm parameters");
2054 }
2055 ic = pbeSpec.getIterationCount();
2056
2057 if (ic > MAX_ITERATION_COUNT) {
2058 throw new IOException("PBE iteration count too large");
2059 }
2060 }
2061
2062 if (debug != null) {
2063 debug.println("Loading PKCS#7 encryptedData " +
2064 "(" + new AlgorithmId(algOid).getName() +
2065 " iterations: " + ic + ")");
2066 }
2067
2068 try {
2069 RetryWithZero.run(pass -> {
2070 // Use JCE
2071 SecretKey skey = getPBEKey(pass);
2072 Cipher cipher = Cipher.getInstance(
2073 mapPBEParamsToAlgorithm(algOid, algParams));
2074 cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
2075 loadSafeContents(new DerInputStream(cipher.doFinal(rawData)));
2076 return null;
2077 }, password);
2078 } catch (Exception e) {
2079 throw new IOException("keystore password was incorrect",
2080 new UnrecoverableKeyException(
2081 "failed to decrypt safe contents entry: " + e));
2082 }
2083 } else {
2084 throw new IOException("public key protected PKCS12" +
2085 " not supported");
2086 }
2087 }
2088
2089 // The MacData is optional.
2090 if (password != null && s.available() > 0) {
2091 MacData macData = new MacData(s);
2092 int ic = macData.getIterations();
2093
2094 try {
2095 if (ic > MAX_ITERATION_COUNT) {
2096 throw new InvalidAlgorithmParameterException(
2097 "MAC iteration count too large: " + ic);
2098 }
2099
2100 String algName =
2101 macData.getDigestAlgName().toUpperCase(Locale.ENGLISH);
2102
2103 // Change SHA-1 to SHA1
2104 algName = algName.replace("-", "");
2105
2106 // generate MAC (MAC key is created within JCE)
2107 Mac m = Mac.getInstance("HmacPBE" + algName);
2108 PBEParameterSpec params =
2109 new PBEParameterSpec(macData.getSalt(), ic);
2110
2111 RetryWithZero.run(pass -> {
2112 SecretKey key = getPBEKey(pass);
2113 m.init(key, params);
2114 m.update(authSafeData);
2115 byte[] macResult = m.doFinal();
2116
2117 if (debug != null) {
2118 debug.println("Checking keystore integrity " +
2119 "(" + m.getAlgorithm() + " iterations: " + ic + ")");
2120 }
2121
2122 if (!MessageDigest.isEqual(macData.getDigest(), macResult)) {
2123 throw new UnrecoverableKeyException("Failed PKCS12" +
2124 " integrity checking");
2125 }
2126 return (Void)null;
2127 }, password);
2128 } catch (Exception e) {
2129 throw new IOException("Integrity check failed: " + e, e);
2130 }
2131 }
2132
2133 /*
2134 * Match up private keys with certificate chains.
2135 */
2136 PrivateKeyEntry[] list =
2137 keyList.toArray(new PrivateKeyEntry[keyList.size()]);
2138 for (int m = 0; m < list.length; m++) {
2139 PrivateKeyEntry entry = list[m];
2140 if (entry.keyId != null) {
2141 ArrayList<X509Certificate> chain =
2142 new ArrayList<X509Certificate>();
2143 X509Certificate cert = findMatchedCertificate(entry);
2144
2145 mainloop:
2146 while (cert != null) {
2147 // Check for loops in the certificate chain
2148 if (!chain.isEmpty()) {
2149 for (X509Certificate chainCert : chain) {
2150 if (cert.equals(chainCert)) {
2151 if (debug != null) {
2152 debug.println("Loop detected in " +
2153 "certificate chain. Skip adding " +
2154 "repeated cert to chain. Subject: " +
2155 cert.getSubjectX500Principal()
2156 .toString());
2157 }
2158 break mainloop;
2159 }
2160 }
2161 }
2162 chain.add(cert);
2163 X500Principal issuerDN = cert.getIssuerX500Principal();
2164 if (issuerDN.equals(cert.getSubjectX500Principal())) {
2165 break;
2166 }
2167 cert = certsMap.get(issuerDN);
2168 }
2169 /* Update existing KeyEntry in entries table */
2170 if (chain.size() > 0)
2171 entry.chain = chain.toArray(new Certificate[chain.size()]);
2172 }
2173 }
2174
2175 if (debug != null) {
2176 debug.println("PKCS12KeyStore load: private key count: " +
2177 privateKeyCount + ". secret key count: " + secretKeyCount +
2178 ". certificate count: " + certificateCount);
2179 }
2180
2181 certEntries.clear();
2182 certsMap.clear();
2183 keyList.clear();
2184 }
2185
2186 /**
2187 * Locates a matched CertEntry from certEntries, and returns its cert.
2188 * @param entry the KeyEntry to match
2189 * @return a certificate, null if not found
2190 */
2191 private X509Certificate findMatchedCertificate(PrivateKeyEntry entry) {
2192 CertEntry keyIdMatch = null;
2193 CertEntry aliasMatch = null;
2194 for (CertEntry ce: certEntries) {
2195 if (Arrays.equals(entry.keyId, ce.keyId)) {
2196 keyIdMatch = ce;
2197 if (entry.alias.equalsIgnoreCase(ce.alias)) {
2198 // Full match!
2199 return ce.cert;
2200 }
2201 } else if (entry.alias.equalsIgnoreCase(ce.alias)) {
2202 aliasMatch = ce;
2203 }
2204 }
2205 // keyId match first, for compatibility
2206 if (keyIdMatch != null) return keyIdMatch.cert;
2322 trustedKeyUsage[k] = valSet[k].getOID();
2323 }
2324 } else {
2325 attributes.add(new PKCS12Attribute(encoded));
2326 }
2327 }
2328 }
2329
2330 /*
2331 * As per PKCS12 v1.0 friendlyname (alias) and localKeyId (keyId)
2332 * are optional PKCS12 bagAttributes. But entries in the keyStore
2333 * are identified by their alias. Hence we need to have an
2334 * Unfriendlyname in the alias, if alias is null. The keyId
2335 * attribute is required to match the private key with the
2336 * certificate. If we get a bagItem of type KeyEntry with a
2337 * null keyId, we should skip it entirely.
2338 */
2339 if (bagItem instanceof KeyEntry) {
2340 KeyEntry entry = (KeyEntry)bagItem;
2341
2342 if (bagItem instanceof PrivateKeyEntry) {
2343 if (keyId == null) {
2344 // Insert a localKeyID for the privateKey
2345 // Note: This is a workaround to allow null localKeyID
2346 // attribute in pkcs12 with one private key entry and
2347 // associated cert-chain
2348 if (privateKeyCount == 1) {
2349 keyId = "01".getBytes("UTF8");
2350 } else {
2351 continue;
2352 }
2353 }
2354 }
2355 entry.keyId = keyId;
2356 // restore date if it exists
2357 String keyIdStr = new String(keyId, "UTF8");
2358 Date date = null;
2359 if (keyIdStr.startsWith("Time ")) {
2360 try {
2361 date = new Date(
2362 Long.parseLong(keyIdStr.substring(5)));
2363 } catch (Exception e) {
2364 date = null;
2365 }
2366 }
2367 if (date == null) {
2368 date = new Date();
2369 }
2370 entry.date = date;
2371
2372 if (bagItem instanceof PrivateKeyEntry) {
2403 new CertEntry(cert, keyId, alias, trustedKeyUsage,
2404 attributes);
2405 entries.put(alias.toLowerCase(Locale.ENGLISH), certEntry);
2406 } else {
2407 certEntries.add(new CertEntry(cert, keyId, alias));
2408 }
2409 X500Principal subjectDN = cert.getSubjectX500Principal();
2410 if (subjectDN != null) {
2411 if (!certsMap.containsKey(subjectDN)) {
2412 certsMap.put(subjectDN, cert);
2413 }
2414 }
2415 }
2416 }
2417 }
2418
2419 private String getUnfriendlyName() {
2420 counter++;
2421 return (String.valueOf(counter));
2422 }
2423 }
|
52 import java.util.*;
53
54 import java.security.AlgorithmParameters;
55 import java.security.InvalidAlgorithmParameterException;
56 import javax.crypto.spec.PBEParameterSpec;
57 import javax.crypto.spec.PBEKeySpec;
58 import javax.crypto.spec.SecretKeySpec;
59 import javax.crypto.SecretKeyFactory;
60 import javax.crypto.SecretKey;
61 import javax.crypto.Cipher;
62 import javax.crypto.Mac;
63 import javax.security.auth.DestroyFailedException;
64 import javax.security.auth.x500.X500Principal;
65
66 import sun.security.util.Debug;
67 import sun.security.util.DerInputStream;
68 import sun.security.util.DerOutputStream;
69 import sun.security.util.DerValue;
70 import sun.security.util.ObjectIdentifier;
71 import sun.security.pkcs.ContentInfo;
72 import sun.security.util.SecurityProperties;
73 import sun.security.x509.AlgorithmId;
74 import sun.security.pkcs.EncryptedPrivateKeyInfo;
75
76
77 /**
78 * This class provides the keystore implementation referred to as "PKCS12".
79 * Implements the PKCS#12 PFX protected using the Password privacy mode.
80 * The contents are protected using Password integrity mode.
81 *
82 * Currently these PBE algorithms are used by default:
83 * - PBEWithSHA1AndDESede to encrypt private keys, iteration count 50000.
84 * - PBEWithSHA1AndRC2_40 to encrypt certificates, iteration count 50000.
85 *
86 * The default Mac algorithm is HmacPBESHA1, iteration count 100000.
87 *
88 * Supported encryption of various implementations :
89 *
90 * Software and mode. Certificate encryption Private key encryption
91 * ---------------------------------------------------------------------
92 * MSIE4 (domestic 40 bit RC2. 40 bit RC2
93 * and xport versions)
94 * PKCS#12 export.
95 *
96 * MSIE4, 5 (domestic 40 bit RC2, 40 bit RC2,
97 * and export versions) 3 key triple DES 3 key triple DES
98 * PKCS#12 import.
99 *
100 * MSIE5 40 bit RC2 3 key triple DES,
101 * PKCS#12 export. with SHA1 (168 bits)
102 *
103 * Netscape Communicator 40 bit RC2 3 key triple DES,
104 * (domestic and export with SHA1 (168 bits)
105 * versions) PKCS#12 export
106 *
109 * PKCS#12 import.
110 *
111 * Netscape Communicator All. All.
112 * (domestic or fortified
113 * version) PKCS#12 import.
114 *
115 * OpenSSL PKCS#12 code. All. All.
116 * ---------------------------------------------------------------------
117 *
118 * NOTE: PKCS12 KeyStore supports PrivateKeyEntry and TrustedCertficateEntry.
119 * PKCS#12 is mainly used to deliver private keys with their associated
120 * certificate chain and aliases. In a PKCS12 keystore, entries are
121 * identified by the alias, and a localKeyId is required to match the
122 * private key with the certificate. Trusted certificate entries are identified
123 * by the presence of an trustedKeyUsage attribute.
124 *
125 * @author Seema Malkani
126 * @author Jeff Nisewanger
127 * @author Jan Luehe
128 *
129 * @see java.security.KeyStoreSpi
130 */
131 public final class PKCS12KeyStore extends KeyStoreSpi {
132
133 public static final int VERSION_3 = 3;
134
135 private static final int MAX_ITERATION_COUNT = 5000000;
136 private static final int SALT_LEN = 20;
137
138 // friendlyName, localKeyId, trustedKeyUsage
139 private static final String[] CORE_ATTRIBUTES = {
140 "1.2.840.113549.1.9.20",
141 "1.2.840.113549.1.9.21",
142 "2.16.840.1.113894.746875.1.1"
143 };
144
145 private static final Debug debug = Debug.getInstance("pkcs12");
146
147 private static final int keyBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 2};
148 private static final int certBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 3};
149 private static final int secretBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 5};
150
151 private static final int pkcs9Name[] = {1, 2, 840, 113549, 1, 9, 20};
152 private static final int pkcs9KeyId[] = {1, 2, 840, 113549, 1, 9, 21};
153
154 private static final int pkcs9certType[] = {1, 2, 840, 113549, 1, 9, 22, 1};
155
156 private static final int pbes2[] = {1, 2, 840, 113549, 1, 5, 13};
157 // TODO: temporary Oracle OID
158 /*
159 * { joint-iso-itu-t(2) country(16) us(840) organization(1) oracle(113894)
160 * jdk(746875) crypto(1) id-at-trustedKeyUsage(1) }
161 */
162 private static final int TrustedKeyUsage[] =
163 {2, 16, 840, 1, 113894, 746875, 1, 1};
164 private static final int AnyExtendedKeyUsage[] = {2, 5, 29, 37, 0};
165
166 private static final ObjectIdentifier PKCS8ShroudedKeyBag_OID;
167 private static final ObjectIdentifier CertBag_OID;
168 private static final ObjectIdentifier SecretBag_OID;
169 private static final ObjectIdentifier PKCS9FriendlyName_OID;
170 private static final ObjectIdentifier PKCS9LocalKeyId_OID;
171 private static final ObjectIdentifier PKCS9CertType_OID;
172 private static final ObjectIdentifier pbes2_OID;
173 private static final ObjectIdentifier TrustedKeyUsage_OID;
174 private static final ObjectIdentifier[] AnyUsage;
175
176 private int counter = 0;
177
178 // private key count
179 // Note: This is a workaround to allow null localKeyID attribute
180 // in pkcs12 with one private key entry and associated cert-chain
181 private int privateKeyCount = 0;
182
183 // secret key count
184 private int secretKeyCount = 0;
185
186 // certificate count
187 private int certificateCount = 0;
188
189 // Alg/params used for *this* keystore. Initialized as -1 for ic and
190 // null for algorithm names. When an existing file is read, they will be
191 // assigned inside engineLoad() so storing an existing keystore uses the
192 // old alg/params. This makes sure if a keystore is created password-less
193 // it will be password-less forever. Otherwise, engineStore() will read
194 // the default values. These fields are always reset when load() is called.
195 private String certProtectionAlgorithm = null;
196 private int certPbeIterationCount = -1;
197 private String macAlgorithm = null;
198 private int macIterationCount = -1;
199
200 // the source of randomness
201 private SecureRandom random;
202
203 static {
204 try {
205 PKCS8ShroudedKeyBag_OID = new ObjectIdentifier(keyBag);
206 CertBag_OID = new ObjectIdentifier(certBag);
207 SecretBag_OID = new ObjectIdentifier(secretBag);
208 PKCS9FriendlyName_OID = new ObjectIdentifier(pkcs9Name);
209 PKCS9LocalKeyId_OID = new ObjectIdentifier(pkcs9KeyId);
210 PKCS9CertType_OID = new ObjectIdentifier(pkcs9certType);
211 pbes2_OID = new ObjectIdentifier(pbes2);
212 TrustedKeyUsage_OID = new ObjectIdentifier(TrustedKeyUsage);
213 AnyUsage = new ObjectIdentifier[]{
214 new ObjectIdentifier(AnyExtendedKeyUsage)};
215 } catch (IOException ioe) {
216 throw new AssertionError("OID not initialized", ioe);
217 }
218 }
219
220 // A keystore entry and associated attributes
221 private static class Entry {
222 Date date; // the creation date of this entry
223 String alias;
224 byte[] keyId;
225 Set<KeyStore.Entry.Attribute> attributes;
226 }
227
228 // A key entry
229 private static class KeyEntry extends Entry {
230 }
231
232 // A private key entry and its supporting certificate chain
233 private static class PrivateKeyEntry extends KeyEntry {
234 byte[] protectedPrivKey;
235 Certificate chain[];
236 };
357 new UnrecoverableKeyException("Private key not stored as "
358 + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe);
359 uke.initCause(ioe);
360 throw uke;
361 }
362
363 try {
364 PBEParameterSpec pbeSpec;
365 int ic;
366
367 if (algParams != null) {
368 try {
369 pbeSpec =
370 algParams.getParameterSpec(PBEParameterSpec.class);
371 } catch (InvalidParameterSpecException ipse) {
372 throw new IOException("Invalid PBE algorithm parameters");
373 }
374 ic = pbeSpec.getIterationCount();
375
376 if (ic > MAX_ITERATION_COUNT) {
377 throw new IOException("key PBE iteration count too large");
378 }
379 } else {
380 ic = 0;
381 }
382
383 key = RetryWithZero.run(pass -> {
384 // Use JCE
385 SecretKey skey = getPBEKey(pass);
386 Cipher cipher = Cipher.getInstance(
387 mapPBEParamsToAlgorithm(algOid, algParams));
388 cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
389 byte[] keyInfo = cipher.doFinal(encryptedKey);
390 /*
391 * Parse the key algorithm and then use a JCA key factory
392 * to re-create the key.
393 */
394 DerValue val = new DerValue(keyInfo);
395 DerInputStream in = val.toDerInputStream();
396 int i = in.getInteger();
397 DerValue[] value = in.getSequence(2);
398 if (value.length < 1 || value.length > 2) {
399 throw new IOException("Invalid length for AlgorithmIdentifier");
400 }
401 AlgorithmId algId = new AlgorithmId(value[0].getOID());
402 String keyAlgo = algId.getName();
403
404 // decode private key
405 if (entry instanceof PrivateKeyEntry) {
406 KeyFactory kfac = KeyFactory.getInstance(keyAlgo);
407 PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(keyInfo);
408 Key tmp = kfac.generatePrivate(kspec);
409
410 if (debug != null) {
411 debug.println("Retrieved a protected private key at alias" +
412 " '" + alias + "' (" +
413 mapPBEParamsToAlgorithm(algOid, algParams) +
414 " iterations: " + ic + ")");
415 }
416 return tmp;
417 // decode secret key
418 } else {
419 byte[] keyBytes = in.getOctetString();
420 SecretKeySpec secretKeySpec =
421 new SecretKeySpec(keyBytes, keyAlgo);
422
423 // Special handling required for PBE: needs a PBEKeySpec
424 Key tmp;
425 if (keyAlgo.startsWith("PBE")) {
426 SecretKeyFactory sKeyFactory =
427 SecretKeyFactory.getInstance(keyAlgo);
428 KeySpec pbeKeySpec =
429 sKeyFactory.getKeySpec(secretKeySpec, PBEKeySpec.class);
430 tmp = sKeyFactory.generateSecret(pbeKeySpec);
431 } else {
432 tmp = secretKeySpec;
433 }
434
435 if (debug != null) {
436 debug.println("Retrieved a protected secret key at alias " +
437 "'" + alias + "' (" +
438 mapPBEParamsToAlgorithm(algOid, algParams) +
439 " iterations: " + ic + ")");
440 }
441 return tmp;
442 }
443 }, password);
444
445 } catch (Exception e) {
446 UnrecoverableKeyException uke =
447 new UnrecoverableKeyException("Get Key failed: " +
448 e.getMessage());
449 uke.initCause(e);
450 throw uke;
451 }
452 return key;
453 }
454
455 /**
456 * Returns the certificate chain associated with the given alias.
457 *
458 * @param alias the alias name
667 }
668 secretKeyCount++;
669 entry = keyEntry;
670
671 } else {
672 throw new KeyStoreException("Unsupported Key type");
673 }
674
675 entry.attributes = new HashSet<>();
676 if (attributes != null) {
677 entry.attributes.addAll(attributes);
678 }
679 // set the keyId to current date
680 entry.keyId = ("Time " + (entry.date).getTime()).getBytes("UTF8");
681 // set the alias
682 entry.alias = alias.toLowerCase(Locale.ENGLISH);
683 // add the entry
684 entries.put(alias.toLowerCase(Locale.ENGLISH), entry);
685
686 } catch (Exception nsae) {
687 throw new KeyStoreException("Key protection" +
688 " algorithm not found: " + nsae, nsae);
689 }
690 }
691
692 /**
693 * Assigns the given key (that has already been protected) to the given
694 * alias.
695 *
696 * <p>If the protected key is of type
697 * <code>java.security.PrivateKey</code>, it must be accompanied by a
698 * certificate chain certifying the corresponding public key. If the
699 * underlying keystore implementation is of type <code>jks</code>,
700 * <code>key</code> must be encoded as an
701 * <code>EncryptedPrivateKeyInfo</code> as defined in the PKCS #8 standard.
702 *
703 * <p>If the given alias already exists, the keystore information
704 * associated with it is overridden by the given key (and possibly
705 * certificate chain).
706 *
707 * @param alias the alias name
764 }
765
766
767 /*
768 * Generate random salt
769 */
770 private byte[] getSalt()
771 {
772 // Generate a random salt.
773 byte[] salt = new byte[SALT_LEN];
774 if (random == null) {
775 random = new SecureRandom();
776 }
777 random.nextBytes(salt);
778 return salt;
779 }
780
781 /*
782 * Generate PBE Algorithm Parameters
783 */
784 private AlgorithmParameters getPBEAlgorithmParameters(
785 String algorithm, int iterationCount) throws IOException {
786 AlgorithmParameters algParams = null;
787
788 // create PBE parameters from salt and iteration count
789 PBEParameterSpec paramSpec =
790 new PBEParameterSpec(getSalt(), iterationCount);
791 try {
792 algParams = AlgorithmParameters.getInstance(algorithm);
793 algParams.init(paramSpec);
794 } catch (Exception e) {
795 throw new IOException("getPBEAlgorithmParameters failed: " +
796 e.getMessage(), e);
797 }
798 return algParams;
799 }
800
801 /*
802 * parse Algorithm Parameters
803 */
804 private AlgorithmParameters parseAlgParameters(ObjectIdentifier algorithm,
805 DerInputStream in) throws IOException
806 {
807 AlgorithmParameters algParams = null;
808 try {
809 DerValue params;
810 if (in.available() == 0) {
833 /*
834 * Generate PBE key
835 */
836 private SecretKey getPBEKey(char[] password) throws IOException
837 {
838 SecretKey skey = null;
839
840 try {
841 PBEKeySpec keySpec = new PBEKeySpec(password);
842 SecretKeyFactory skFac = SecretKeyFactory.getInstance("PBE");
843 skey = skFac.generateSecret(keySpec);
844 keySpec.clearPassword();
845 } catch (Exception e) {
846 throw new IOException("getSecretKey failed: " +
847 e.getMessage(), e);
848 }
849 return skey;
850 }
851
852 /*
853 * Encrypt private key or secret key using Password-based encryption (PBE)
854 * as defined in PKCS#5.
855 *
856 * NOTE: By default, pbeWithSHAAnd3-KeyTripleDES-CBC algorithmID is
857 * used to derive the key and IV.
858 *
859 * @return encrypted private key or secret key encoded as
860 * EncryptedPrivateKeyInfo
861 */
862 private byte[] encryptPrivateKey(byte[] data,
863 KeyStore.PasswordProtection passwordProtection)
864 throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException
865 {
866 byte[] key = null;
867
868 try {
869 String algorithm;
870 AlgorithmParameters algParams;
871 AlgorithmId algid;
872
873 // Initialize PBE algorithm and parameters
874 algorithm = passwordProtection.getProtectionAlgorithm();
875 if (algorithm != null) {
876 AlgorithmParameterSpec algParamSpec =
877 passwordProtection.getProtectionParameters();
878 if (algParamSpec != null) {
879 algParams = AlgorithmParameters.getInstance(algorithm);
880 algParams.init(algParamSpec);
881 } else {
882 algParams = getPBEAlgorithmParameters(algorithm,
883 defaultKeyPbeIterationCount());
884 }
885 } else {
886 // Check default key protection algorithm for PKCS12 keystores
887 algorithm = defaultKeyProtectionAlgorithm();
888 algParams = getPBEAlgorithmParameters(algorithm,
889 defaultKeyPbeIterationCount());
890 }
891
892 ObjectIdentifier pbeOID = mapPBEAlgorithmToOID(algorithm);
893 if (pbeOID == null) {
894 throw new IOException("PBE algorithm '" + algorithm +
895 " 'is not supported for key entry protection");
896 }
897
898 // Use JCE
899 SecretKey skey = getPBEKey(passwordProtection.getPassword());
900 Cipher cipher = Cipher.getInstance(algorithm);
901 cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
902 byte[] encryptedKey = cipher.doFinal(data);
903 algid = new AlgorithmId(pbeOID, cipher.getParameters());
904
905 if (debug != null) {
906 debug.println(" (Cipher algorithm: " + cipher.getAlgorithm() +
907 ")");
908 }
909
927 * Map a PBE algorithm name onto its object identifier
928 */
929 private static ObjectIdentifier mapPBEAlgorithmToOID(String algorithm)
930 throws NoSuchAlgorithmException {
931 // Check for PBES2 algorithms
932 if (algorithm.toLowerCase(Locale.ENGLISH).startsWith("pbewithhmacsha")) {
933 return pbes2_OID;
934 }
935 return AlgorithmId.get(algorithm).getOID();
936 }
937
938 /*
939 * Map a PBE algorithm parameters onto its algorithm name
940 */
941 private static String mapPBEParamsToAlgorithm(ObjectIdentifier algorithm,
942 AlgorithmParameters algParams) throws NoSuchAlgorithmException {
943 // Check for PBES2 algorithms
944 if (algorithm.equals((Object)pbes2_OID) && algParams != null) {
945 return algParams.toString();
946 }
947 return new AlgorithmId(algorithm).getName();
948 }
949
950 /**
951 * Assigns the given certificate to the given alias.
952 *
953 * <p>If the given alias already exists in this keystore and identifies a
954 * <i>trusted certificate entry</i>, the certificate associated with it is
955 * overridden by the given certificate.
956 *
957 * @param alias the alias name
958 * @param cert the certificate
959 *
960 * @exception KeyStoreException if the given alias already exists and does
961 * not identify a <i>trusted certificate entry</i>, or this operation fails
962 * for some other reason.
963 */
964 public synchronized void engineSetCertificateEntry(String alias,
965 Certificate cert) throws KeyStoreException
966 {
967 setCertEntry(alias, cert, null);
1152 }
1153 return null;
1154 }
1155
1156 /**
1157 * Stores this keystore to the given output stream, and protects its
1158 * integrity with the given password.
1159 *
1160 * @param stream the output stream to which this keystore is written.
1161 * @param password the password to generate the keystore integrity check
1162 *
1163 * @exception IOException if there was an I/O problem with data
1164 * @exception NoSuchAlgorithmException if the appropriate data integrity
1165 * algorithm could not be found
1166 * @exception CertificateException if any of the certificates included in
1167 * the keystore data could not be stored
1168 */
1169 public synchronized void engineStore(OutputStream stream, char[] password)
1170 throws IOException, NoSuchAlgorithmException, CertificateException
1171 {
1172
1173 // -- Create PFX
1174 DerOutputStream pfx = new DerOutputStream();
1175
1176 // PFX version (always write the latest version)
1177 DerOutputStream version = new DerOutputStream();
1178 version.putInteger(VERSION_3);
1179 byte[] pfxVersion = version.toByteArray();
1180 pfx.write(pfxVersion);
1181
1182 // -- Create AuthSafe
1183 DerOutputStream authSafe = new DerOutputStream();
1184
1185 // -- Create ContentInfos
1186 DerOutputStream authSafeContentInfo = new DerOutputStream();
1187
1188 // -- create safeContent Data ContentInfo
1189 if (privateKeyCount > 0 || secretKeyCount > 0) {
1190
1191 if (debug != null) {
1192 debug.println("Storing " + (privateKeyCount + secretKeyCount) +
1193 " protected key(s) in a PKCS#7 data");
1194 }
1195
1196 byte[] safeContentData = createSafeContent();
1197 ContentInfo dataContentInfo = new ContentInfo(safeContentData);
1198 dataContentInfo.encode(authSafeContentInfo);
1199 }
1200
1201 // -- create EncryptedContentInfo
1202 if (certificateCount > 0) {
1203
1204 if (certProtectionAlgorithm == null) {
1205 certProtectionAlgorithm = defaultCertProtectionAlgorithm();
1206 }
1207 if (certPbeIterationCount < 0) {
1208 certPbeIterationCount = defaultCertPbeIterationCount();
1209 }
1210
1211 if (debug != null) {
1212 debug.println("Storing " + certificateCount +
1213 " certificate(s) in a PKCS#7 encryptedData");
1214 }
1215
1216 byte[] encrData = createEncryptedData(password);
1217 if (!certProtectionAlgorithm.equalsIgnoreCase("NONE")) {
1218 ContentInfo encrContentInfo =
1219 new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID,
1220 new DerValue(encrData));
1221 encrContentInfo.encode(authSafeContentInfo);
1222 } else {
1223 ContentInfo dataContentInfo = new ContentInfo(encrData);
1224 dataContentInfo.encode(authSafeContentInfo);
1225 }
1226 }
1227
1228 // wrap as SequenceOf ContentInfos
1229 DerOutputStream cInfo = new DerOutputStream();
1230 cInfo.write(DerValue.tag_SequenceOf, authSafeContentInfo);
1231 byte[] authenticatedSafe = cInfo.toByteArray();
1232
1233 // Create Encapsulated ContentInfo
1234 ContentInfo contentInfo = new ContentInfo(authenticatedSafe);
1235 contentInfo.encode(authSafe);
1236 byte[] authSafeData = authSafe.toByteArray();
1237 pfx.write(authSafeData);
1238
1239 // -- MAC
1240 if (macAlgorithm == null) {
1241 macAlgorithm = defaultMacAlgorithm();
1242 }
1243 if (macIterationCount < 0) {
1244 macIterationCount = defaultMacIterationCount();
1245 }
1246 if (!macAlgorithm.equalsIgnoreCase("NONE")) {
1247 byte[] macData = calculateMac(password, authenticatedSafe);
1248 pfx.write(macData);
1249 }
1250 // write PFX to output stream
1251 DerOutputStream pfxout = new DerOutputStream();
1252 pfxout.write(DerValue.tag_Sequence, pfx);
1253 byte[] pfxData = pfxout.toByteArray();
1254 stream.write(pfxData);
1255 stream.flush();
1256 }
1257
1258 /**
1259 * Gets a <code>KeyStore.Entry</code> for the specified alias
1260 * with the specified protection parameter.
1261 *
1262 * @param alias get the <code>KeyStore.Entry</code> for this alias
1263 * @param protParam the <code>ProtectionParameter</code>
1264 * used to protect the <code>Entry</code>,
1265 * which may be <code>null</code>
1266 *
1267 * @return the <code>KeyStore.Entry</code> for the specified alias,
1268 * or <code>null</code> if there is no such entry
1269 *
1440 if (entry instanceof CertEntry) {
1441 ObjectIdentifier[] trustedKeyUsageValue =
1442 ((CertEntry) entry).trustedKeyUsage;
1443 if (trustedKeyUsageValue != null) {
1444 if (trustedKeyUsageValue.length == 1) { // omit brackets
1445 entry.attributes.add(new PKCS12Attribute(
1446 TrustedKeyUsage_OID.toString(),
1447 trustedKeyUsageValue[0].toString()));
1448 } else { // multi-valued
1449 entry.attributes.add(new PKCS12Attribute(
1450 TrustedKeyUsage_OID.toString(),
1451 Arrays.toString(trustedKeyUsageValue)));
1452 }
1453 }
1454 }
1455
1456 return entry.attributes;
1457 }
1458
1459 /*
1460 * Calculate MAC using HMAC algorithm (required for password integrity)
1461 *
1462 * Hash-based MAC algorithm combines secret key with message digest to
1463 * create a message authentication code (MAC)
1464 */
1465 private byte[] calculateMac(char[] passwd, byte[] data)
1466 throws IOException
1467 {
1468 byte[] mData = null;
1469 String algName = macAlgorithm.substring(7);
1470
1471 try {
1472 // Generate a random salt.
1473 byte[] salt = getSalt();
1474
1475 // generate MAC (MAC key is generated within JCE)
1476 Mac m = Mac.getInstance(macAlgorithm);
1477 PBEParameterSpec params =
1478 new PBEParameterSpec(salt, macIterationCount);
1479 SecretKey key = getPBEKey(passwd);
1480 m.init(key, params);
1481 m.update(data);
1482 byte[] macResult = m.doFinal();
1483
1484 // encode as MacData
1485 MacData macData = new MacData(algName, macResult, salt,
1486 macIterationCount);
1487 DerOutputStream bytes = new DerOutputStream();
1488 bytes.write(macData.getEncoded());
1489 mData = bytes.toByteArray();
1490 } catch (Exception e) {
1491 throw new IOException("calculateMac failed: " + e, e);
1492 }
1493 return mData;
1494 }
1495
1496
1497 /*
1498 * Validate Certificate Chain
1499 */
1500 private boolean validateChain(Certificate[] certChain)
1501 {
1502 for (int i = 0; i < certChain.length-1; i++) {
1503 X500Principal issuerDN =
1504 ((X509Certificate)certChain[i]).getIssuerX500Principal();
1505 X500Principal subjectDN =
1506 ((X509Certificate)certChain[i+1]).getSubjectX500Principal();
1724 // However, IE/OpenSSL do not impose this restriction.
1725 bagAttrs = getBagAttributes(
1726 cert.getSubjectX500Principal().getName(), null,
1727 entry.attributes);
1728 }
1729 if (bagAttrs != null) {
1730 safeBag.write(bagAttrs);
1731 }
1732
1733 // wrap as Sequence
1734 out.write(DerValue.tag_Sequence, safeBag);
1735 } // for cert-chain
1736 }
1737
1738 // wrap as SequenceOf SafeBag
1739 DerOutputStream safeBagValue = new DerOutputStream();
1740 safeBagValue.write(DerValue.tag_SequenceOf, out);
1741 byte[] safeBagData = safeBagValue.toByteArray();
1742
1743 // encrypt the content (EncryptedContentInfo)
1744 if (!certProtectionAlgorithm.equalsIgnoreCase("NONE")) {
1745 byte[] encrContentInfo = encryptContent(safeBagData, password);
1746
1747 // -- SEQUENCE of EncryptedData
1748 DerOutputStream encrData = new DerOutputStream();
1749 DerOutputStream encrDataContent = new DerOutputStream();
1750 encrData.putInteger(0);
1751 encrData.write(encrContentInfo);
1752 encrDataContent.write(DerValue.tag_Sequence, encrData);
1753 return encrDataContent.toByteArray();
1754 } else {
1755 return safeBagData;
1756 }
1757 }
1758
1759 /*
1760 * Create SafeContent Data content type.
1761 * Includes encrypted secret key in a SafeBag of type SecretBag.
1762 * Includes encrypted private key in a SafeBag of type PKCS8ShroudedKeyBag.
1763 * Each PKCS8ShroudedKeyBag includes pkcs12 attributes
1764 * (see comments in getBagAttributes)
1765 */
1766 private byte[] createSafeContent()
1767 throws CertificateException, IOException {
1768
1769 DerOutputStream out = new DerOutputStream();
1770 for (Enumeration<String> e = engineAliases(); e.hasMoreElements(); ) {
1771
1772 String alias = e.nextElement();
1773 Entry entry = entries.get(alias);
1774 if (entry == null || (!(entry instanceof KeyEntry))) {
1775 continue;
1776 }
1845 DerOutputStream safeBagValue = new DerOutputStream();
1846 safeBagValue.write(DerValue.tag_Sequence, out);
1847 return safeBagValue.toByteArray();
1848 }
1849
1850
1851 /*
1852 * Encrypt the contents using Password-based (PBE) encryption
1853 * as defined in PKCS #5.
1854 *
1855 * NOTE: Currently pbeWithSHAAnd40BiteRC2-CBC algorithmID is used
1856 * to derive the key and IV.
1857 *
1858 * @return encrypted contents encoded as EncryptedContentInfo
1859 */
1860 private byte[] encryptContent(byte[] data, char[] password)
1861 throws IOException {
1862
1863 byte[] encryptedData = null;
1864
1865
1866 try {
1867 // create AlgorithmParameters
1868 AlgorithmParameters algParams = getPBEAlgorithmParameters(
1869 certProtectionAlgorithm, certPbeIterationCount);
1870 DerOutputStream bytes = new DerOutputStream();
1871
1872 // Use JCE
1873 SecretKey skey = getPBEKey(password);
1874 Cipher cipher = Cipher.getInstance(certProtectionAlgorithm);
1875 cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
1876 encryptedData = cipher.doFinal(data);
1877
1878 AlgorithmId algId = new AlgorithmId(
1879 mapPBEAlgorithmToOID(certProtectionAlgorithm),
1880 cipher.getParameters());
1881 // cipher.getParameters() now has IV
1882 algId.encode(bytes);
1883 byte[] encodedAlgId = bytes.toByteArray();
1884
1885 if (debug != null) {
1886 debug.println(" (Cipher algorithm: " + cipher.getAlgorithm() +
1887 ")");
1888 }
1889
1890 // create EncryptedContentInfo
1891 DerOutputStream bytes2 = new DerOutputStream();
1892 bytes2.putOID(ContentInfo.DATA_OID);
1893 bytes2.write(encodedAlgId);
1894
1895 // Wrap encrypted data in a context-specific tag.
1896 DerOutputStream tmpout2 = new DerOutputStream();
1897 tmpout2.putOctetString(encryptedData);
1898 bytes2.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
1899 false, (byte) 0), tmpout2);
1900
1901 // wrap EncryptedContentInfo in a Sequence
1902 DerOutputStream out = new DerOutputStream();
1903 out.write(DerValue.tag_Sequence, bytes2);
1904 return out.toByteArray();
1905 } catch (IOException ioe) {
1906 throw ioe;
1907 } catch (Exception e) {
1908 throw new IOException("Failed to encrypt" +
1909 " safe contents entry: " + e, e);
1910 }
1911 }
1912
1913 /**
1914 * Loads the keystore from the given input stream.
1915 *
1916 * <p>If a password is given, it is used to check the integrity of the
1917 * keystore data. Otherwise, the integrity of the keystore is not checked.
1918 *
1919 * @param stream the input stream from which the keystore is loaded
1920 * @param password the (optional) password used to check the integrity of
1921 * the keystore.
1922 *
1923 * @exception IOException if there is an I/O or format problem with the
1924 * keystore data
1925 * @exception NoSuchAlgorithmException if the algorithm used to check
1926 * the integrity of the keystore cannot be found
1927 * @exception CertificateException if any of the certificates in the
1928 * keystore could not be loaded
1929 */
1930 public synchronized void engineLoad(InputStream stream, char[] password)
1931 throws IOException, NoSuchAlgorithmException, CertificateException
1932 {
1933
1934 // Reset config when loading a different keystore.
1935 certProtectionAlgorithm = null;
1936 certPbeIterationCount = -1;
1937 macAlgorithm = null;
1938 macIterationCount = -1;
1939
1940 if (stream == null)
1941 return;
1942
1943 // reset the counter
1944 counter = 0;
1945
1946 DerValue val = new DerValue(stream);
1947 DerInputStream s = val.toDerInputStream();
1948 int version = s.getInteger();
1949
1950 if (version != VERSION_3) {
1951 throw new IOException("PKCS12 keystore not in version 3 format");
1952 }
1953
1954 entries.clear();
1955
1956 /*
1957 * Read the authSafe.
1958 */
1959 byte[] authSafeData;
1960 ContentInfo authSafe = new ContentInfo(s);
1961 ObjectIdentifier contentType = authSafe.getContentType();
1962
1963 if (contentType.equals((Object)ContentInfo.DATA_OID)) {
1964 authSafeData = authSafe.getData();
1965 } else /* signed data */ {
1966 throw new IOException("public key protected PKCS12 not supported");
1967 }
1968
1969 DerInputStream as = new DerInputStream(authSafeData);
1970 DerValue[] safeContentsArray = as.getSequence(2);
1971 int count = safeContentsArray.length;
1972
1973 // reset the counters at the start
1974 privateKeyCount = 0;
1975 secretKeyCount = 0;
1976 certificateCount = 0;
1977
1978 boolean seeEncBag = false;
1979
1980 /*
1981 * Spin over the ContentInfos.
1982 */
1983 for (int i = 0; i < count; i++) {
1984 ContentInfo safeContents;
1985 DerInputStream sci;
1986 byte[] eAlgId = null;
1987
1988 sci = new DerInputStream(safeContentsArray[i].toByteArray());
1989 safeContents = new ContentInfo(sci);
1990 contentType = safeContents.getContentType();
1991 if (contentType.equals((Object)ContentInfo.DATA_OID)) {
1992
1993 if (debug != null) {
1994 debug.println("Loading PKCS#7 data");
1995 }
1996
1997 loadSafeContents(new DerInputStream(safeContents.getData()));
1998 } else if (contentType.equals((Object)ContentInfo.ENCRYPTED_DATA_OID)) {
1999 if (password == null) {
2000
2001 if (debug != null) {
2002 debug.println("Warning: skipping PKCS#7 encryptedData" +
2003 " - no password was supplied");
2004 }
2005 // No password to decrypt ENCRYPTED_DATA_OID. *Skip it*.
2006 // This means user will see a PrivateKeyEntry without
2007 // certificates and a whole TrustedCertificateEntry will
2008 // be lost. This is not a perfect solution but alternative
2009 // solutions are more disruptive:
2010 //
2011 // We cannot just fail, since KeyStore.load(is, null)
2012 // has been known to never fail because of a null password.
2013 //
2014 // We cannot just throw away the whole PrivateKeyEntry,
2015 // this is too silent and no one will notice anything.
2016 //
2017 // We also cannot fail when getCertificate() on such a
2018 // PrivateKeyEntry is called, since the method has not
2019 // specified this behavior.
2020 continue;
2021 }
2022
2023 DerInputStream edi =
2024 safeContents.getContent().toDerInputStream();
2025 int edVersion = edi.getInteger();
2026 DerValue[] seq = edi.getSequence(3);
2027 if (seq.length != 3) {
2028 // We require the encryptedContent field, even though
2029 // it is optional
2030 throw new IOException("Invalid length for EncryptedContentInfo");
2031 }
2032 ObjectIdentifier edContentType = seq[0].getOID();
2033 eAlgId = seq[1].toByteArray();
2034 if (!seq[2].isContextSpecific((byte)0)) {
2035 throw new IOException("unsupported encrypted content type "
2036 + seq[2].tag);
2037 }
2038 byte newTag = DerValue.tag_OctetString;
2039 if (seq[2].isConstructed())
2043
2044 // parse Algorithm parameters
2045 DerInputStream in = seq[1].toDerInputStream();
2046 ObjectIdentifier algOid = in.getOID();
2047 AlgorithmParameters algParams = parseAlgParameters(algOid, in);
2048
2049 PBEParameterSpec pbeSpec;
2050 int ic = 0;
2051
2052 if (algParams != null) {
2053 try {
2054 pbeSpec =
2055 algParams.getParameterSpec(PBEParameterSpec.class);
2056 } catch (InvalidParameterSpecException ipse) {
2057 throw new IOException(
2058 "Invalid PBE algorithm parameters");
2059 }
2060 ic = pbeSpec.getIterationCount();
2061
2062 if (ic > MAX_ITERATION_COUNT) {
2063 throw new IOException("cert PBE iteration count too large");
2064 }
2065
2066 certProtectionAlgorithm
2067 = mapPBEParamsToAlgorithm(algOid, algParams);
2068 certPbeIterationCount = ic;
2069 seeEncBag = true;
2070 }
2071
2072 if (debug != null) {
2073 debug.println("Loading PKCS#7 encryptedData " +
2074 "(" + mapPBEParamsToAlgorithm(algOid, algParams) +
2075 " iterations: " + ic + ")");
2076 }
2077
2078 try {
2079 RetryWithZero.run(pass -> {
2080 // Use JCE
2081 SecretKey skey = getPBEKey(pass);
2082 Cipher cipher = Cipher.getInstance(
2083 mapPBEParamsToAlgorithm(algOid, algParams));
2084 cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
2085 loadSafeContents(new DerInputStream(cipher.doFinal(rawData)));
2086 return null;
2087 }, password);
2088 } catch (Exception e) {
2089 throw new IOException("keystore password was incorrect",
2090 new UnrecoverableKeyException(
2091 "failed to decrypt safe contents entry: " + e));
2092 }
2093 } else {
2094 throw new IOException("public key protected PKCS12" +
2095 " not supported");
2096 }
2097 }
2098
2099 // No ENCRYPTED_DATA_OID but see certificate. Must be passwordless.
2100 if (!seeEncBag && certificateCount > 0) {
2101 certProtectionAlgorithm = "NONE";
2102 }
2103
2104 // The MacData is optional.
2105 if (s.available() > 0) {
2106 // If there is no password, we cannot fail. KeyStore.load(is, null)
2107 // has been known to never fail because of a null password.
2108 if (password != null) {
2109 MacData macData = new MacData(s);
2110 int ic = macData.getIterations();
2111
2112 try {
2113 if (ic > MAX_ITERATION_COUNT) {
2114 throw new InvalidAlgorithmParameterException(
2115 "MAC iteration count too large: " + ic);
2116 }
2117
2118 String algName =
2119 macData.getDigestAlgName().toUpperCase(Locale.ENGLISH);
2120
2121 // Change SHA-1 to SHA1
2122 algName = algName.replace("-", "");
2123
2124 macAlgorithm = "HmacPBE" + algName;
2125 macIterationCount = ic;
2126
2127 // generate MAC (MAC key is created within JCE)
2128 Mac m = Mac.getInstance(macAlgorithm);
2129 PBEParameterSpec params =
2130 new PBEParameterSpec(macData.getSalt(), ic);
2131
2132 RetryWithZero.run(pass -> {
2133 SecretKey key = getPBEKey(pass);
2134 m.init(key, params);
2135 m.update(authSafeData);
2136 byte[] macResult = m.doFinal();
2137
2138 if (debug != null) {
2139 debug.println("Checking keystore integrity " +
2140 "(" + m.getAlgorithm() + " iterations: " + ic + ")");
2141 }
2142
2143 if (!MessageDigest.isEqual(macData.getDigest(), macResult)) {
2144 throw new UnrecoverableKeyException("Failed PKCS12" +
2145 " integrity checking");
2146 }
2147 return (Void) null;
2148 }, password);
2149 } catch (Exception e) {
2150 throw new IOException("Integrity check failed: " + e, e);
2151 }
2152 }
2153 } else {
2154 macAlgorithm = "NONE";
2155 }
2156
2157 /*
2158 * Match up private keys with certificate chains.
2159 */
2160 PrivateKeyEntry[] list =
2161 keyList.toArray(new PrivateKeyEntry[keyList.size()]);
2162 for (int m = 0; m < list.length; m++) {
2163 PrivateKeyEntry entry = list[m];
2164 if (entry.keyId != null) {
2165 ArrayList<X509Certificate> chain =
2166 new ArrayList<X509Certificate>();
2167 X509Certificate cert = findMatchedCertificate(entry);
2168
2169 mainloop:
2170 while (cert != null) {
2171 // Check for loops in the certificate chain
2172 if (!chain.isEmpty()) {
2173 for (X509Certificate chainCert : chain) {
2174 if (cert.equals(chainCert)) {
2175 if (debug != null) {
2176 debug.println("Loop detected in " +
2177 "certificate chain. Skip adding " +
2178 "repeated cert to chain. Subject: " +
2179 cert.getSubjectX500Principal()
2180 .toString());
2181 }
2182 break mainloop;
2183 }
2184 }
2185 }
2186 chain.add(cert);
2187 X500Principal issuerDN = cert.getIssuerX500Principal();
2188 if (issuerDN.equals(cert.getSubjectX500Principal())) {
2189 break;
2190 }
2191 cert = certsMap.get(issuerDN);
2192 }
2193 /* Update existing KeyEntry in entries table */
2194 if (chain.size() > 0) {
2195 entry.chain = chain.toArray(new Certificate[chain.size()]);
2196 } else {
2197 // Remove private key entries where there is no associated
2198 // certs. Most likely the keystore is loaded with a null
2199 // password.
2200 entries.remove(entry);
2201 }
2202 }
2203 }
2204
2205 if (debug != null) {
2206 debug.println("PKCS12KeyStore load: private key count: " +
2207 privateKeyCount + ". secret key count: " + secretKeyCount +
2208 ". certificate count: " + certificateCount);
2209 }
2210
2211 certEntries.clear();
2212 certsMap.clear();
2213 keyList.clear();
2214 }
2215
2216 /**
2217 * Returns if a pkcs12 file is password-less. This means no cert is
2218 * encrypted and there is no Mac. Please note that the private key
2219 * can be encrypted.
2220 *
2221 * This is a simplified version of {@link #engineLoad} that only looks
2222 * at the ContentInfo types.
2223 *
2224 * @param f the pkcs12 file
2225 * @return if it's password-less
2226 * @throws IOException
2227 */
2228 public static boolean isPasswordless(File f) throws IOException {
2229
2230 try (FileInputStream stream = new FileInputStream(f)) {
2231 DerValue val = new DerValue(stream);
2232 DerInputStream s = val.toDerInputStream();
2233
2234 s.getInteger(); // skip version
2235
2236 ContentInfo authSafe = new ContentInfo(s);
2237 DerInputStream as = new DerInputStream(authSafe.getData());
2238 for (DerValue seq : as.getSequence(2)) {
2239 DerInputStream sci = new DerInputStream(seq.toByteArray());
2240 ContentInfo safeContents = new ContentInfo(sci);
2241 if (safeContents.getContentType()
2242 .equals(ContentInfo.ENCRYPTED_DATA_OID)) {
2243 // Certificate encrypted
2244 return false;
2245 }
2246 }
2247
2248 if (s.available() > 0) {
2249 // The MacData exists.
2250 return false;
2251 }
2252 }
2253 return true;
2254 }
2255
2256 /**
2257 * Locates a matched CertEntry from certEntries, and returns its cert.
2258 * @param entry the KeyEntry to match
2259 * @return a certificate, null if not found
2260 */
2261 private X509Certificate findMatchedCertificate(PrivateKeyEntry entry) {
2262 CertEntry keyIdMatch = null;
2263 CertEntry aliasMatch = null;
2264 for (CertEntry ce: certEntries) {
2265 if (Arrays.equals(entry.keyId, ce.keyId)) {
2266 keyIdMatch = ce;
2267 if (entry.alias.equalsIgnoreCase(ce.alias)) {
2268 // Full match!
2269 return ce.cert;
2270 }
2271 } else if (entry.alias.equalsIgnoreCase(ce.alias)) {
2272 aliasMatch = ce;
2273 }
2274 }
2275 // keyId match first, for compatibility
2276 if (keyIdMatch != null) return keyIdMatch.cert;
2392 trustedKeyUsage[k] = valSet[k].getOID();
2393 }
2394 } else {
2395 attributes.add(new PKCS12Attribute(encoded));
2396 }
2397 }
2398 }
2399
2400 /*
2401 * As per PKCS12 v1.0 friendlyname (alias) and localKeyId (keyId)
2402 * are optional PKCS12 bagAttributes. But entries in the keyStore
2403 * are identified by their alias. Hence we need to have an
2404 * Unfriendlyname in the alias, if alias is null. The keyId
2405 * attribute is required to match the private key with the
2406 * certificate. If we get a bagItem of type KeyEntry with a
2407 * null keyId, we should skip it entirely.
2408 */
2409 if (bagItem instanceof KeyEntry) {
2410 KeyEntry entry = (KeyEntry)bagItem;
2411
2412 if (keyId == null) {
2413 if (bagItem instanceof PrivateKeyEntry) {
2414 // Insert a localKeyID for the privateKey
2415 // Note: This is a workaround to allow null localKeyID
2416 // attribute in pkcs12 with one private key entry and
2417 // associated cert-chain
2418 if (privateKeyCount == 1) {
2419 keyId = "01".getBytes("UTF8");
2420 } else {
2421 continue;
2422 }
2423 } else {
2424 // keyId in a SecretKeyEntry is not significant
2425 keyId = "00".getBytes("UTF8");
2426 }
2427 }
2428 entry.keyId = keyId;
2429 // restore date if it exists
2430 String keyIdStr = new String(keyId, "UTF8");
2431 Date date = null;
2432 if (keyIdStr.startsWith("Time ")) {
2433 try {
2434 date = new Date(
2435 Long.parseLong(keyIdStr.substring(5)));
2436 } catch (Exception e) {
2437 date = null;
2438 }
2439 }
2440 if (date == null) {
2441 date = new Date();
2442 }
2443 entry.date = date;
2444
2445 if (bagItem instanceof PrivateKeyEntry) {
2476 new CertEntry(cert, keyId, alias, trustedKeyUsage,
2477 attributes);
2478 entries.put(alias.toLowerCase(Locale.ENGLISH), certEntry);
2479 } else {
2480 certEntries.add(new CertEntry(cert, keyId, alias));
2481 }
2482 X500Principal subjectDN = cert.getSubjectX500Principal();
2483 if (subjectDN != null) {
2484 if (!certsMap.containsKey(subjectDN)) {
2485 certsMap.put(subjectDN, cert);
2486 }
2487 }
2488 }
2489 }
2490 }
2491
2492 private String getUnfriendlyName() {
2493 counter++;
2494 return (String.valueOf(counter));
2495 }
2496
2497 // 8076190: Customizing the generation of a PKCS12 keystore
2498
2499 private static String defaultCertProtectionAlgorithm() {
2500 String result = SecurityProperties.privilegedGetOverridable(
2501 "keystore.pkcs12.certProtectionAlgorithm");
2502 return (result != null && !result.isEmpty())
2503 ? result : "PBEWithSHA1AndRC2_40";
2504 }
2505
2506 private static int defaultCertPbeIterationCount() {
2507 String result = SecurityProperties.privilegedGetOverridable(
2508 "keystore.pkcs12.certPbeIterationCount");
2509 return (result != null && !result.isEmpty())
2510 ? string2IC("certPbeIterationCount", result) : 50000;
2511 }
2512
2513 // Read both "keystore.pkcs12.keyProtectionAlgorithm" and
2514 // "keystore.PKCS12.keyProtectionAlgorithm" for compatibility.
2515 private static String defaultKeyProtectionAlgorithm() {
2516 String result = AccessController.doPrivileged(new PrivilegedAction<String>() {
2517 public String run() {
2518 String result;
2519 String name1 = "keystore.pkcs12.keyProtectionAlgorithm";
2520 String name2 = "keystore.PKCS12.keyProtectionAlgorithm";
2521 result = System.getProperty(name1);
2522 if (result != null) {
2523 return result;
2524 }
2525 result = System.getProperty(name2);
2526 if (result != null) {
2527 return result;
2528 }
2529 result = Security.getProperty(name1);
2530 if (result != null) {
2531 return result;
2532 }
2533 return Security.getProperty(name2);
2534 }
2535 });
2536 return (result != null && !result.isEmpty())
2537 ? result : "PBEWithSHA1AndDESede";
2538 }
2539
2540 private static int defaultKeyPbeIterationCount() {
2541 String result = SecurityProperties.privilegedGetOverridable(
2542 "keystore.pkcs12.keyPbeIterationCount");
2543 return (result != null && !result.isEmpty())
2544 ? string2IC("keyPbeIterationCount", result) : 50000;
2545 }
2546
2547 private static String defaultMacAlgorithm() {
2548 String result = SecurityProperties.privilegedGetOverridable(
2549 "keystore.pkcs12.macAlgorithm");
2550 return (result != null && !result.isEmpty())
2551 ? result : "HmacPBESHA1";
2552 }
2553
2554 private static int defaultMacIterationCount() {
2555 String result = SecurityProperties.privilegedGetOverridable(
2556 "keystore.pkcs12.macIterationCount");
2557 return (result != null && !result.isEmpty())
2558 ? string2IC("macIterationCount", result) : 100000;
2559 }
2560
2561 private static int string2IC(String type, String value) {
2562 int number;
2563 try {
2564 number = Integer.parseInt(value);
2565 } catch (NumberFormatException e) {
2566 throw new IllegalArgumentException("keystore.pkcs12." + type
2567 + " is not a number: " + value);
2568 }
2569 if (number <= 0 || number > MAX_ITERATION_COUNT) {
2570 throw new IllegalArgumentException("Invalid keystore.pkcs12."
2571 + type + ": " + value);
2572 }
2573 return number;
2574 }
2575 }
|