1 package org.bouncycastle.jcajce.provider.keystore.pkcs12;
2 
3 import java.io.BufferedInputStream;
4 import java.io.ByteArrayInputStream;
5 import java.io.ByteArrayOutputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.OutputStream;
9 import java.security.InvalidAlgorithmParameterException;
10 import java.security.InvalidKeyException;
11 import java.security.Key;
12 import java.security.KeyStore;
13 import java.security.KeyStore.LoadStoreParameter;
14 import java.security.KeyStore.ProtectionParameter;
15 import java.security.KeyStoreException;
16 import java.security.KeyStoreSpi;
17 import java.security.NoSuchAlgorithmException;
18 import java.security.NoSuchProviderException;
19 import java.security.Principal;
20 import java.security.PrivateKey;
21 import java.security.Provider;
22 import java.security.PublicKey;
23 import java.security.SecureRandom;
24 import java.security.UnrecoverableKeyException;
25 import java.security.cert.Certificate;
26 import java.security.cert.CertificateEncodingException;
27 import java.security.cert.CertificateException;
28 import java.security.cert.CertificateFactory;
29 import java.security.cert.X509Certificate;
30 import java.security.spec.InvalidKeySpecException;
31 import java.util.Collections;
32 import java.util.Date;
33 import java.util.Enumeration;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.Hashtable;
37 import java.util.Map;
38 import java.util.Set;
39 import java.util.Vector;
40 
41 import javax.crypto.Cipher;
42 import javax.crypto.Mac;
43 import javax.crypto.NoSuchPaddingException;
44 import javax.crypto.SecretKey;
45 import javax.crypto.SecretKeyFactory;
46 import javax.crypto.spec.IvParameterSpec;
47 import javax.crypto.spec.PBEKeySpec;
48 import javax.crypto.spec.PBEParameterSpec;
49 
50 import org.bouncycastle.asn1.ASN1Encodable;
51 import org.bouncycastle.asn1.ASN1EncodableVector;
52 import org.bouncycastle.asn1.ASN1Encoding;
53 import org.bouncycastle.asn1.ASN1InputStream;
54 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
55 import org.bouncycastle.asn1.ASN1OctetString;
56 import org.bouncycastle.asn1.ASN1Primitive;
57 import org.bouncycastle.asn1.ASN1Sequence;
58 import org.bouncycastle.asn1.ASN1Set;
59 import org.bouncycastle.asn1.BEROctetString;
60 import org.bouncycastle.asn1.BEROutputStream;
61 import org.bouncycastle.asn1.DERBMPString;
62 import org.bouncycastle.asn1.DERNull;
63 import org.bouncycastle.asn1.DEROctetString;
64 import org.bouncycastle.asn1.DEROutputStream;
65 import org.bouncycastle.asn1.DERSequence;
66 import org.bouncycastle.asn1.DERSet;
67 // BEGIN android-removed
68 // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
69 // import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
70 // END android-removed
71 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
72 import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
73 import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
74 import org.bouncycastle.asn1.pkcs.CertBag;
75 import org.bouncycastle.asn1.pkcs.ContentInfo;
76 import org.bouncycastle.asn1.pkcs.EncryptedData;
77 import org.bouncycastle.asn1.pkcs.MacData;
78 import org.bouncycastle.asn1.pkcs.PBES2Parameters;
79 import org.bouncycastle.asn1.pkcs.PBKDF2Params;
80 import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
81 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
82 import org.bouncycastle.asn1.pkcs.Pfx;
83 import org.bouncycastle.asn1.pkcs.SafeBag;
84 import org.bouncycastle.asn1.util.ASN1Dump;
85 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
86 import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
87 import org.bouncycastle.asn1.x509.DigestInfo;
88 import org.bouncycastle.asn1.x509.Extension;
89 import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
90 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
91 import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
92 import org.bouncycastle.crypto.Digest;
93 import org.bouncycastle.crypto.digests.SHA1Digest;
94 import org.bouncycastle.jcajce.PKCS12Key;
95 import org.bouncycastle.jcajce.PKCS12StoreParameter;
96 // BEGIN android-removed
97 // import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
98 // END android-removed
99 import org.bouncycastle.jcajce.spec.PBKDF2KeySpec;
100 import org.bouncycastle.jcajce.util.BCJcaJceHelper;
101 import org.bouncycastle.jcajce.util.JcaJceHelper;
102 import org.bouncycastle.jce.interfaces.BCKeyStore;
103 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
104 import org.bouncycastle.jce.provider.BouncyCastleProvider;
105 import org.bouncycastle.jce.provider.JDKPKCS12StoreParameter;
106 import org.bouncycastle.util.Arrays;
107 import org.bouncycastle.util.Integers;
108 import org.bouncycastle.util.Strings;
109 import org.bouncycastle.util.encoders.Hex;
110 
111 public class PKCS12KeyStoreSpi
112     extends KeyStoreSpi
113     implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
114 {
115     private final JcaJceHelper helper = new BCJcaJceHelper();
116 
117     private static final int SALT_SIZE = 20;
118     private static final int MIN_ITERATIONS = 1024;
119 
120     private static final DefaultSecretKeyProvider keySizeProvider = new DefaultSecretKeyProvider();
121 
122     private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
123     private Hashtable localIds = new Hashtable();
124     private IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
125     private Hashtable chainCerts = new Hashtable();
126     private Hashtable keyCerts = new Hashtable();
127 
128     //
129     // generic object types
130     //
131     static final int NULL = 0;
132     static final int CERTIFICATE = 1;
133     static final int KEY = 2;
134     static final int SECRET = 3;
135     static final int SEALED = 4;
136 
137     //
138     // key types
139     //
140     static final int KEY_PRIVATE = 0;
141     static final int KEY_PUBLIC = 1;
142     static final int KEY_SECRET = 2;
143 
144     protected SecureRandom random = new SecureRandom();
145 
146     // use of final causes problems with JDK 1.2 compiler
147     private CertificateFactory certFact;
148     private ASN1ObjectIdentifier keyAlgorithm;
149     private ASN1ObjectIdentifier certAlgorithm;
150 
151     private class CertId
152     {
153         byte[] id;
154 
CertId( PublicKey key)155         CertId(
156             PublicKey key)
157         {
158             this.id = createSubjectKeyId(key).getKeyIdentifier();
159         }
160 
CertId( byte[] id)161         CertId(
162             byte[] id)
163         {
164             this.id = id;
165         }
166 
hashCode()167         public int hashCode()
168         {
169             return Arrays.hashCode(id);
170         }
171 
equals( Object o)172         public boolean equals(
173             Object o)
174         {
175             if (o == this)
176             {
177                 return true;
178             }
179 
180             if (!(o instanceof CertId))
181             {
182                 return false;
183             }
184 
185             CertId cId = (CertId)o;
186 
187             return Arrays.areEqual(id, cId.id);
188         }
189     }
190 
PKCS12KeyStoreSpi( Provider provider, ASN1ObjectIdentifier keyAlgorithm, ASN1ObjectIdentifier certAlgorithm)191     public PKCS12KeyStoreSpi(
192         Provider provider,
193         ASN1ObjectIdentifier keyAlgorithm,
194         ASN1ObjectIdentifier certAlgorithm)
195     {
196         this.keyAlgorithm = keyAlgorithm;
197         this.certAlgorithm = certAlgorithm;
198 
199         try
200         {
201             if (provider != null)
202             {
203                 certFact = CertificateFactory.getInstance("X.509", provider);
204             }
205             else
206             {
207                 certFact = CertificateFactory.getInstance("X.509");
208             }
209         }
210         catch (Exception e)
211         {
212             throw new IllegalArgumentException("can't create cert factory - " + e.toString());
213         }
214     }
215 
createSubjectKeyId( PublicKey pubKey)216     private SubjectKeyIdentifier createSubjectKeyId(
217         PublicKey pubKey)
218     {
219         try
220         {
221             SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
222 
223             return new SubjectKeyIdentifier(getDigest(info));
224         }
225         catch (Exception e)
226         {
227             throw new RuntimeException("error creating key");
228         }
229     }
230 
getDigest(SubjectPublicKeyInfo spki)231     private static byte[] getDigest(SubjectPublicKeyInfo spki)
232     {
233         Digest digest = new SHA1Digest();
234         byte[]  resBuf = new byte[digest.getDigestSize()];
235 
236         byte[] bytes = spki.getPublicKeyData().getBytes();
237         digest.update(bytes, 0, bytes.length);
238         digest.doFinal(resBuf, 0);
239         return resBuf;
240     }
241 
setRandom( SecureRandom rand)242     public void setRandom(
243         SecureRandom rand)
244     {
245         this.random = rand;
246     }
247 
engineAliases()248     public Enumeration engineAliases()
249     {
250         Hashtable tab = new Hashtable();
251 
252         Enumeration e = certs.keys();
253         while (e.hasMoreElements())
254         {
255             tab.put(e.nextElement(), "cert");
256         }
257 
258         e = keys.keys();
259         while (e.hasMoreElements())
260         {
261             String a = (String)e.nextElement();
262             if (tab.get(a) == null)
263             {
264                 tab.put(a, "key");
265             }
266         }
267 
268         return tab.keys();
269     }
270 
engineContainsAlias( String alias)271     public boolean engineContainsAlias(
272         String alias)
273     {
274         return (certs.get(alias) != null || keys.get(alias) != null);
275     }
276 
277     /**
278      * this is not quite complete - we should follow up on the chain, a bit
279      * tricky if a certificate appears in more than one chain... the store method
280      * now prunes out unused certificates from the chain map if they are present.
281      */
engineDeleteEntry( String alias)282     public void engineDeleteEntry(
283         String alias)
284         throws KeyStoreException
285     {
286         Key k = (Key)keys.remove(alias);
287 
288         Certificate c = (Certificate)certs.remove(alias);
289 
290         if (c != null)
291         {
292             chainCerts.remove(new CertId(c.getPublicKey()));
293         }
294 
295         if (k != null)
296         {
297             String id = (String)localIds.remove(alias);
298             if (id != null)
299             {
300                 c = (Certificate)keyCerts.remove(id);
301             }
302             if (c != null)
303             {
304                 chainCerts.remove(new CertId(c.getPublicKey()));
305             }
306         }
307     }
308 
309     /**
310      * simply return the cert for the private key
311      */
engineGetCertificate( String alias)312     public Certificate engineGetCertificate(
313         String alias)
314     {
315         if (alias == null)
316         {
317             throw new IllegalArgumentException("null alias passed to getCertificate.");
318         }
319 
320         Certificate c = (Certificate)certs.get(alias);
321 
322         //
323         // look up the key table - and try the local key id
324         //
325         if (c == null)
326         {
327             String id = (String)localIds.get(alias);
328             if (id != null)
329             {
330                 c = (Certificate)keyCerts.get(id);
331             }
332             else
333             {
334                 c = (Certificate)keyCerts.get(alias);
335             }
336         }
337 
338         return c;
339     }
340 
engineGetCertificateAlias( Certificate cert)341     public String engineGetCertificateAlias(
342         Certificate cert)
343     {
344         Enumeration c = certs.elements();
345         Enumeration k = certs.keys();
346 
347         while (c.hasMoreElements())
348         {
349             Certificate tc = (Certificate)c.nextElement();
350             String ta = (String)k.nextElement();
351 
352             if (tc.equals(cert))
353             {
354                 return ta;
355             }
356         }
357 
358         c = keyCerts.elements();
359         k = keyCerts.keys();
360 
361         while (c.hasMoreElements())
362         {
363             Certificate tc = (Certificate)c.nextElement();
364             String ta = (String)k.nextElement();
365 
366             if (tc.equals(cert))
367             {
368                 return ta;
369             }
370         }
371 
372         return null;
373     }
374 
engineGetCertificateChain( String alias)375     public Certificate[] engineGetCertificateChain(
376         String alias)
377     {
378         if (alias == null)
379         {
380             throw new IllegalArgumentException("null alias passed to getCertificateChain.");
381         }
382 
383         if (!engineIsKeyEntry(alias))
384         {
385             return null;
386         }
387 
388         Certificate c = engineGetCertificate(alias);
389 
390         if (c != null)
391         {
392             Vector cs = new Vector();
393 
394             while (c != null)
395             {
396                 X509Certificate x509c = (X509Certificate)c;
397                 Certificate nextC = null;
398 
399                 byte[] bytes = x509c.getExtensionValue(Extension.authorityKeyIdentifier.getId());
400                 if (bytes != null)
401                 {
402                     try
403                     {
404                         ASN1InputStream aIn = new ASN1InputStream(bytes);
405 
406                         byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
407                         aIn = new ASN1InputStream(authBytes);
408 
409                         AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance(aIn.readObject());
410                         if (id.getKeyIdentifier() != null)
411                         {
412                             nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
413                         }
414 
415                     }
416                     catch (IOException e)
417                     {
418                         throw new RuntimeException(e.toString());
419                     }
420                 }
421 
422                 if (nextC == null)
423                 {
424                     //
425                     // no authority key id, try the Issuer DN
426                     //
427                     Principal i = x509c.getIssuerDN();
428                     Principal s = x509c.getSubjectDN();
429 
430                     if (!i.equals(s))
431                     {
432                         Enumeration e = chainCerts.keys();
433 
434                         while (e.hasMoreElements())
435                         {
436                             X509Certificate crt = (X509Certificate)chainCerts.get(e.nextElement());
437                             Principal sub = crt.getSubjectDN();
438                             if (sub.equals(i))
439                             {
440                                 try
441                                 {
442                                     x509c.verify(crt.getPublicKey());
443                                     nextC = crt;
444                                     break;
445                                 }
446                                 catch (Exception ex)
447                                 {
448                                     // continue
449                                 }
450                             }
451                         }
452                     }
453                 }
454 
455                 if (cs.contains(c))
456                 {
457                     c = null;          // we've got a certificate chain loop time to stop
458                 }
459                 else
460                 {
461                     cs.addElement(c);
462                     if (nextC != c)     // self signed - end of the chain
463                     {
464                         c = nextC;
465                     }
466                     else
467                     {
468                         c = null;
469                     }
470                 }
471             }
472 
473             Certificate[] certChain = new Certificate[cs.size()];
474 
475             for (int i = 0; i != certChain.length; i++)
476             {
477                 certChain[i] = (Certificate)cs.elementAt(i);
478             }
479 
480             return certChain;
481         }
482 
483         return null;
484     }
485 
engineGetCreationDate(String alias)486     public Date engineGetCreationDate(String alias)
487     {
488         if (alias == null)
489         {
490             throw new NullPointerException("alias == null");
491         }
492         if (keys.get(alias) == null && certs.get(alias) == null)
493         {
494             return null;
495         }
496         return new Date();
497     }
498 
engineGetKey( String alias, char[] password)499     public Key engineGetKey(
500         String alias,
501         char[] password)
502         throws NoSuchAlgorithmException, UnrecoverableKeyException
503     {
504         if (alias == null)
505         {
506             throw new IllegalArgumentException("null alias passed to getKey.");
507         }
508 
509         return (Key)keys.get(alias);
510     }
511 
engineIsCertificateEntry( String alias)512     public boolean engineIsCertificateEntry(
513         String alias)
514     {
515         return (certs.get(alias) != null && keys.get(alias) == null);
516     }
517 
engineIsKeyEntry( String alias)518     public boolean engineIsKeyEntry(
519         String alias)
520     {
521         return (keys.get(alias) != null);
522     }
523 
engineSetCertificateEntry( String alias, Certificate cert)524     public void engineSetCertificateEntry(
525         String alias,
526         Certificate cert)
527         throws KeyStoreException
528     {
529         if (keys.get(alias) != null)
530         {
531             throw new KeyStoreException("There is a key entry with the name " + alias + ".");
532         }
533 
534         certs.put(alias, cert);
535         chainCerts.put(new CertId(cert.getPublicKey()), cert);
536     }
537 
engineSetKeyEntry( String alias, byte[] key, Certificate[] chain)538     public void engineSetKeyEntry(
539         String alias,
540         byte[] key,
541         Certificate[] chain)
542         throws KeyStoreException
543     {
544         throw new RuntimeException("operation not supported");
545     }
546 
engineSetKeyEntry( String alias, Key key, char[] password, Certificate[] chain)547     public void engineSetKeyEntry(
548         String alias,
549         Key key,
550         char[] password,
551         Certificate[] chain)
552         throws KeyStoreException
553     {
554         if (!(key instanceof PrivateKey))
555         {
556             throw new KeyStoreException("PKCS12 does not support non-PrivateKeys");
557         }
558 
559         if ((key instanceof PrivateKey) && (chain == null))
560         {
561             throw new KeyStoreException("no certificate chain for private key");
562         }
563 
564         if (keys.get(alias) != null)
565         {
566             engineDeleteEntry(alias);
567         }
568 
569         keys.put(alias, key);
570         if (chain != null)
571         {
572             certs.put(alias, chain[0]);
573 
574             for (int i = 0; i != chain.length; i++)
575             {
576                 chainCerts.put(new CertId(chain[i].getPublicKey()), chain[i]);
577             }
578         }
579     }
580 
engineSize()581     public int engineSize()
582     {
583         Hashtable tab = new Hashtable();
584 
585         Enumeration e = certs.keys();
586         while (e.hasMoreElements())
587         {
588             tab.put(e.nextElement(), "cert");
589         }
590 
591         e = keys.keys();
592         while (e.hasMoreElements())
593         {
594             String a = (String)e.nextElement();
595             if (tab.get(a) == null)
596             {
597                 tab.put(a, "key");
598             }
599         }
600 
601         return tab.size();
602     }
603 
unwrapKey( AlgorithmIdentifier algId, byte[] data, char[] password, boolean wrongPKCS12Zero)604     protected PrivateKey unwrapKey(
605         AlgorithmIdentifier algId,
606         byte[] data,
607         char[] password,
608         boolean wrongPKCS12Zero)
609         throws IOException
610     {
611         ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
612         try
613         {
614             if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
615             {
616                 PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
617                 PBEParameterSpec defParams = new PBEParameterSpec(
618                     pbeParams.getIV(),
619                     pbeParams.getIterations().intValue());
620 
621                 Cipher cipher = helper.createCipher(algorithm.getId());
622 
623                 PKCS12Key key = new PKCS12Key(password, wrongPKCS12Zero);
624 
625                 cipher.init(Cipher.UNWRAP_MODE, key, defParams);
626 
627                 // we pass "" as the key algorithm type as it is unknown at this point
628                 return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
629             }
630             else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
631             {
632 
633                 Cipher cipher = createCipher(Cipher.UNWRAP_MODE, password, algId);
634 
635                 // we pass "" as the key algorithm type as it is unknown at this point
636                 return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
637             }
638         }
639         catch (Exception e)
640         {
641             throw new IOException("exception unwrapping private key - " + e.toString());
642         }
643 
644         throw new IOException("exception unwrapping private key - cannot recognise: " + algorithm);
645     }
646 
wrapKey( String algorithm, Key key, PKCS12PBEParams pbeParams, char[] password)647     protected byte[] wrapKey(
648         String algorithm,
649         Key key,
650         PKCS12PBEParams pbeParams,
651         char[] password)
652         throws IOException
653     {
654         PBEKeySpec pbeSpec = new PBEKeySpec(password);
655         byte[] out;
656 
657         try
658         {
659             SecretKeyFactory keyFact =  helper.createSecretKeyFactory(algorithm);
660             PBEParameterSpec defParams = new PBEParameterSpec(
661                 pbeParams.getIV(),
662                 pbeParams.getIterations().intValue());
663 
664             Cipher cipher = helper.createCipher(algorithm);
665 
666             cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
667 
668             out = cipher.wrap(key);
669         }
670         catch (Exception e)
671         {
672             throw new IOException("exception encrypting data - " + e.toString());
673         }
674 
675         return out;
676     }
677 
cryptData( boolean forEncryption, AlgorithmIdentifier algId, char[] password, boolean wrongPKCS12Zero, byte[] data)678     protected byte[] cryptData(
679         boolean forEncryption,
680         AlgorithmIdentifier algId,
681         char[] password,
682         boolean wrongPKCS12Zero,
683         byte[] data)
684         throws IOException
685     {
686         ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
687         int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
688 
689         if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
690         {
691             PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
692             PBEKeySpec pbeSpec = new PBEKeySpec(password);
693 
694             try
695             {
696                 PBEParameterSpec defParams = new PBEParameterSpec(
697                     pbeParams.getIV(),
698                     pbeParams.getIterations().intValue());
699                 PKCS12Key key = new PKCS12Key(password, wrongPKCS12Zero);
700 
701                 Cipher cipher = helper.createCipher(algorithm.getId());
702 
703                 cipher.init(mode, key, defParams);
704                 return cipher.doFinal(data);
705             }
706             catch (Exception e)
707             {
708                 throw new IOException("exception decrypting data - " + e.toString());
709             }
710         }
711         else  if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
712         {
713             try
714             {
715                 Cipher cipher = createCipher(mode, password, algId);
716 
717                 return cipher.doFinal(data);
718             }
719             catch (Exception e)
720             {
721                 throw new IOException("exception decrypting data - " + e.toString());
722             }
723         }
724         else
725         {
726             throw new IOException("unknown PBE algorithm: " + algorithm);
727         }
728     }
729 
createCipher(int mode, char[] password, AlgorithmIdentifier algId)730     private Cipher createCipher(int mode, char[] password, AlgorithmIdentifier algId)
731         throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchProviderException
732     {
733         PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters());
734         PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
735         AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
736 
737         SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
738         SecretKey key;
739 
740         if (func.isDefaultPrf())
741         {
742             key = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme)));
743         }
744         else
745         {
746             key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme), func.getPrf()));
747         }
748 
749         Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId());
750 
751         AlgorithmIdentifier encryptionAlg = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
752 
753         ASN1Encodable encParams = alg.getEncryptionScheme().getParameters();
754         if (encParams instanceof ASN1OctetString)
755         {
756             cipher.init(mode, key, new IvParameterSpec(ASN1OctetString.getInstance(encParams).getOctets()));
757         }
758         // BEGIN android-removed
759         // else
760         // {
761         //     // TODO: at the moment it's just GOST, but...
762         //     GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams);
763         //
764         //     cipher.init(mode, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV()));
765         // }
766         // END android-removed
767         return cipher;
768     }
769 
engineLoad( InputStream stream, char[] password)770     public void engineLoad(
771         InputStream stream,
772         char[] password)
773         throws IOException
774     {
775         if (stream == null)     // just initialising
776         {
777             return;
778         }
779 
780         if (password == null)
781         {
782             throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
783         }
784 
785         BufferedInputStream bufIn = new BufferedInputStream(stream);
786 
787         bufIn.mark(10);
788 
789         int head = bufIn.read();
790 
791         if (head != 0x30)
792         {
793             throw new IOException("stream does not represent a PKCS12 key store");
794         }
795 
796         bufIn.reset();
797 
798         ASN1InputStream bIn = new ASN1InputStream(bufIn);
799         ASN1Sequence obj = (ASN1Sequence)bIn.readObject();
800         Pfx bag = Pfx.getInstance(obj);
801         ContentInfo info = bag.getAuthSafe();
802         Vector chain = new Vector();
803         boolean unmarkedKey = false;
804         boolean wrongPKCS12Zero = false;
805 
806         if (bag.getMacData() != null)           // check the mac code
807         {
808             MacData mData = bag.getMacData();
809             DigestInfo dInfo = mData.getMac();
810             AlgorithmIdentifier algId = dInfo.getAlgorithmId();
811             byte[] salt = mData.getSalt();
812             int itCount = mData.getIterationCount().intValue();
813 
814             byte[] data = ((ASN1OctetString)info.getContent()).getOctets();
815 
816             try
817             {
818                 byte[] res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, false, data);
819                 byte[] dig = dInfo.getDigest();
820 
821                 if (!Arrays.constantTimeAreEqual(res, dig))
822                 {
823                     if (password.length > 0)
824                     {
825                         throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
826                     }
827 
828                     // Try with incorrect zero length password
829                     res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, true, data);
830 
831                     if (!Arrays.constantTimeAreEqual(res, dig))
832                     {
833                         throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
834                     }
835 
836                     wrongPKCS12Zero = true;
837                 }
838             }
839             catch (IOException e)
840             {
841                 throw e;
842             }
843             catch (Exception e)
844             {
845                 throw new IOException("error constructing MAC: " + e.toString());
846             }
847         }
848 
849         keys = new IgnoresCaseHashtable();
850         localIds = new Hashtable();
851 
852         if (info.getContentType().equals(data))
853         {
854             bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
855 
856             AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(bIn.readObject());
857             ContentInfo[] c = authSafe.getContentInfo();
858 
859             for (int i = 0; i != c.length; i++)
860             {
861                 if (c[i].getContentType().equals(data))
862                 {
863                     ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets());
864                     ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
865 
866                     for (int j = 0; j != seq.size(); j++)
867                     {
868                         SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
869                         if (b.getBagId().equals(pkcs8ShroudedKeyBag))
870                         {
871                             org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
872                             PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
873 
874                             //
875                             // set the attributes on the key
876                             //
877                             PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
878                             String alias = null;
879                             ASN1OctetString localId = null;
880 
881                             if (b.getBagAttributes() != null)
882                             {
883                                 Enumeration e = b.getBagAttributes().getObjects();
884                                 while (e.hasMoreElements())
885                                 {
886                                     ASN1Sequence sq = (ASN1Sequence)e.nextElement();
887                                     ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
888                                     ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
889                                     ASN1Primitive attr = null;
890 
891                                     if (attrSet.size() > 0)
892                                     {
893                                         attr = (ASN1Primitive)attrSet.getObjectAt(0);
894 
895                                         ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
896                                         if (existing != null)
897                                         {
898                                             // OK, but the value has to be the same
899                                             if (!existing.toASN1Primitive().equals(attr))
900                                             {
901                                                 throw new IOException(
902                                                     "attempt to add existing attribute with different value");
903                                             }
904                                         }
905                                         else
906                                         {
907                                             bagAttr.setBagAttribute(aOid, attr);
908                                         }
909                                     }
910 
911                                     if (aOid.equals(pkcs_9_at_friendlyName))
912                                     {
913                                         alias = ((DERBMPString)attr).getString();
914                                         keys.put(alias, privKey);
915                                     }
916                                     else if (aOid.equals(pkcs_9_at_localKeyId))
917                                     {
918                                         localId = (ASN1OctetString)attr;
919                                     }
920                                 }
921                             }
922 
923                             if (localId != null)
924                             {
925                                 String name = new String(Hex.encode(localId.getOctets()));
926 
927                                 if (alias == null)
928                                 {
929                                     keys.put(name, privKey);
930                                 }
931                                 else
932                                 {
933                                     localIds.put(alias, name);
934                                 }
935                             }
936                             else
937                             {
938                                 unmarkedKey = true;
939                                 keys.put("unmarked", privKey);
940                             }
941                         }
942                         else if (b.getBagId().equals(certBag))
943                         {
944                             chain.addElement(b);
945                         }
946                         else
947                         {
948                             System.out.println("extra in data " + b.getBagId());
949                             System.out.println(ASN1Dump.dumpAsString(b));
950                         }
951                     }
952                 }
953                 else if (c[i].getContentType().equals(encryptedData))
954                 {
955                     EncryptedData d = EncryptedData.getInstance(c[i].getContent());
956                     byte[] octets = cryptData(false, d.getEncryptionAlgorithm(),
957                         password, wrongPKCS12Zero, d.getContent().getOctets());
958                     ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(octets);
959 
960                     for (int j = 0; j != seq.size(); j++)
961                     {
962                         SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
963 
964                         if (b.getBagId().equals(certBag))
965                         {
966                             chain.addElement(b);
967                         }
968                         else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
969                         {
970                             org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
971                             PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
972 
973                             //
974                             // set the attributes on the key
975                             //
976                             PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
977                             String alias = null;
978                             ASN1OctetString localId = null;
979 
980                             Enumeration e = b.getBagAttributes().getObjects();
981                             while (e.hasMoreElements())
982                             {
983                                 ASN1Sequence sq = (ASN1Sequence)e.nextElement();
984                                 ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
985                                 ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
986                                 ASN1Primitive attr = null;
987 
988                                 if (attrSet.size() > 0)
989                                 {
990                                     attr = (ASN1Primitive)attrSet.getObjectAt(0);
991 
992                                     ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
993                                     if (existing != null)
994                                     {
995                                         // OK, but the value has to be the same
996                                         if (!existing.toASN1Primitive().equals(attr))
997                                         {
998                                             throw new IOException(
999                                                 "attempt to add existing attribute with different value");
1000                                         }
1001                                     }
1002                                     else
1003                                     {
1004                                         bagAttr.setBagAttribute(aOid, attr);
1005                                     }
1006                                 }
1007 
1008                                 if (aOid.equals(pkcs_9_at_friendlyName))
1009                                 {
1010                                     alias = ((DERBMPString)attr).getString();
1011                                     keys.put(alias, privKey);
1012                                 }
1013                                 else if (aOid.equals(pkcs_9_at_localKeyId))
1014                                 {
1015                                     localId = (ASN1OctetString)attr;
1016                                 }
1017                             }
1018 
1019                             String name = new String(Hex.encode(localId.getOctets()));
1020 
1021                             if (alias == null)
1022                             {
1023                                 keys.put(name, privKey);
1024                             }
1025                             else
1026                             {
1027                                 localIds.put(alias, name);
1028                             }
1029                         }
1030                         else if (b.getBagId().equals(keyBag))
1031                         {
1032                             org.bouncycastle.asn1.pkcs.PrivateKeyInfo kInfo = org.bouncycastle.asn1.pkcs.PrivateKeyInfo.getInstance(b.getBagValue());
1033                             PrivateKey privKey = BouncyCastleProvider.getPrivateKey(kInfo);
1034 
1035                             //
1036                             // set the attributes on the key
1037                             //
1038                             PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
1039                             String alias = null;
1040                             ASN1OctetString localId = null;
1041 
1042                             Enumeration e = b.getBagAttributes().getObjects();
1043                             while (e.hasMoreElements())
1044                             {
1045                                 ASN1Sequence sq = ASN1Sequence.getInstance(e.nextElement());
1046                                 ASN1ObjectIdentifier aOid = ASN1ObjectIdentifier.getInstance(sq.getObjectAt(0));
1047                                 ASN1Set attrSet = ASN1Set.getInstance(sq.getObjectAt(1));
1048                                 ASN1Primitive attr = null;
1049 
1050                                 if (attrSet.size() > 0)
1051                                 {
1052                                     attr = (ASN1Primitive)attrSet.getObjectAt(0);
1053 
1054                                     ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
1055                                     if (existing != null)
1056                                     {
1057                                         // OK, but the value has to be the same
1058                                         if (!existing.toASN1Primitive().equals(attr))
1059                                         {
1060                                             throw new IOException(
1061                                                 "attempt to add existing attribute with different value");
1062                                         }
1063                                     }
1064                                     else
1065                                     {
1066                                         bagAttr.setBagAttribute(aOid, attr);
1067                                     }
1068 
1069                                     if (aOid.equals(pkcs_9_at_friendlyName))
1070                                     {
1071                                         alias = ((DERBMPString)attr).getString();
1072                                         keys.put(alias, privKey);
1073                                     }
1074                                     else if (aOid.equals(pkcs_9_at_localKeyId))
1075                                     {
1076                                         localId = (ASN1OctetString)attr;
1077                                     }
1078                                 }
1079                             }
1080 
1081                             String name = new String(Hex.encode(localId.getOctets()));
1082 
1083                             if (alias == null)
1084                             {
1085                                 keys.put(name, privKey);
1086                             }
1087                             else
1088                             {
1089                                 localIds.put(alias, name);
1090                             }
1091                         }
1092                         else
1093                         {
1094                             System.out.println("extra in encryptedData " + b.getBagId());
1095                             System.out.println(ASN1Dump.dumpAsString(b));
1096                         }
1097                     }
1098                 }
1099                 else
1100                 {
1101                     System.out.println("extra " + c[i].getContentType().getId());
1102                     System.out.println("extra " + ASN1Dump.dumpAsString(c[i].getContent()));
1103                 }
1104             }
1105         }
1106 
1107         certs = new IgnoresCaseHashtable();
1108         chainCerts = new Hashtable();
1109         keyCerts = new Hashtable();
1110 
1111         for (int i = 0; i != chain.size(); i++)
1112         {
1113             SafeBag b = (SafeBag)chain.elementAt(i);
1114             CertBag cb = CertBag.getInstance(b.getBagValue());
1115 
1116             if (!cb.getCertId().equals(x509Certificate))
1117             {
1118                 throw new RuntimeException("Unsupported certificate type: " + cb.getCertId());
1119             }
1120 
1121             Certificate cert;
1122 
1123             try
1124             {
1125                 ByteArrayInputStream cIn = new ByteArrayInputStream(
1126                     ((ASN1OctetString)cb.getCertValue()).getOctets());
1127                 cert = certFact.generateCertificate(cIn);
1128             }
1129             catch (Exception e)
1130             {
1131                 throw new RuntimeException(e.toString());
1132             }
1133 
1134             //
1135             // set the attributes
1136             //
1137             ASN1OctetString localId = null;
1138             String alias = null;
1139 
1140             if (b.getBagAttributes() != null)
1141             {
1142                 Enumeration e = b.getBagAttributes().getObjects();
1143                 while (e.hasMoreElements())
1144                 {
1145                     ASN1Sequence sq = ASN1Sequence.getInstance(e.nextElement());
1146                     ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(sq.getObjectAt(0));
1147                     ASN1Set attrSet = ASN1Set.getInstance(sq.getObjectAt(1));
1148 
1149                     if (attrSet.size() > 0)   // sometimes this is empty!
1150                     {
1151                         ASN1Primitive attr = (ASN1Primitive)attrSet.getObjectAt(0);
1152                         PKCS12BagAttributeCarrier bagAttr = null;
1153 
1154                         if (cert instanceof PKCS12BagAttributeCarrier)
1155                         {
1156                             bagAttr = (PKCS12BagAttributeCarrier)cert;
1157 
1158                             ASN1Encodable existing = bagAttr.getBagAttribute(oid);
1159                             if (existing != null)
1160                             {
1161                                 // OK, but the value has to be the same
1162                                 if (!existing.toASN1Primitive().equals(attr))
1163                                 {
1164                                     throw new IOException(
1165                                         "attempt to add existing attribute with different value");
1166                                 }
1167                             }
1168                             else
1169                             {
1170                                 bagAttr.setBagAttribute(oid, attr);
1171                             }
1172                         }
1173 
1174                         if (oid.equals(pkcs_9_at_friendlyName))
1175                         {
1176                             alias = ((DERBMPString)attr).getString();
1177                         }
1178                         else if (oid.equals(pkcs_9_at_localKeyId))
1179                         {
1180                             localId = (ASN1OctetString)attr;
1181                         }
1182                     }
1183                 }
1184             }
1185 
1186             chainCerts.put(new CertId(cert.getPublicKey()), cert);
1187 
1188             if (unmarkedKey)
1189             {
1190                 if (keyCerts.isEmpty())
1191                 {
1192                     String name = new String(Hex.encode(createSubjectKeyId(cert.getPublicKey()).getKeyIdentifier()));
1193 
1194                     keyCerts.put(name, cert);
1195                     keys.put(name, keys.remove("unmarked"));
1196                 }
1197             }
1198             else
1199             {
1200                 //
1201                 // the local key id needs to override the friendly name
1202                 //
1203                 if (localId != null)
1204                 {
1205                     String name = new String(Hex.encode(localId.getOctets()));
1206 
1207                     keyCerts.put(name, cert);
1208                 }
1209                 if (alias != null)
1210                 {
1211                     certs.put(alias, cert);
1212                 }
1213             }
1214         }
1215     }
1216 
engineStore(LoadStoreParameter param)1217     public void engineStore(LoadStoreParameter param)
1218         throws IOException,
1219         NoSuchAlgorithmException, CertificateException
1220     {
1221         if (param == null)
1222         {
1223             throw new IllegalArgumentException("'param' arg cannot be null");
1224         }
1225 
1226         if (!(param instanceof PKCS12StoreParameter || param instanceof JDKPKCS12StoreParameter))
1227         {
1228             throw new IllegalArgumentException(
1229                 "No support for 'param' of type " + param.getClass().getName());
1230         }
1231 
1232         PKCS12StoreParameter bcParam;
1233 
1234         if (param instanceof PKCS12StoreParameter)
1235         {
1236             bcParam = (PKCS12StoreParameter)param;
1237         }
1238         else
1239         {
1240             bcParam = new PKCS12StoreParameter(((JDKPKCS12StoreParameter)param).getOutputStream(),
1241                 param.getProtectionParameter(), ((JDKPKCS12StoreParameter)param).isUseDEREncoding());
1242         }
1243 
1244         char[] password;
1245         ProtectionParameter protParam = param.getProtectionParameter();
1246         if (protParam == null)
1247         {
1248             password = null;
1249         }
1250         else if (protParam instanceof KeyStore.PasswordProtection)
1251         {
1252             password = ((KeyStore.PasswordProtection)protParam).getPassword();
1253         }
1254         else
1255         {
1256             throw new IllegalArgumentException(
1257                 "No support for protection parameter of type " + protParam.getClass().getName());
1258         }
1259 
1260         doStore(bcParam.getOutputStream(), password, bcParam.isForDEREncoding());
1261     }
1262 
engineStore(OutputStream stream, char[] password)1263     public void engineStore(OutputStream stream, char[] password)
1264         throws IOException
1265     {
1266         doStore(stream, password, false);
1267     }
1268 
doStore(OutputStream stream, char[] password, boolean useDEREncoding)1269     private void doStore(OutputStream stream, char[] password, boolean useDEREncoding)
1270         throws IOException
1271     {
1272         if (password == null)
1273         {
1274             throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
1275         }
1276 
1277         //
1278         // handle the key
1279         //
1280         ASN1EncodableVector keyS = new ASN1EncodableVector();
1281 
1282         Enumeration ks = keys.keys();
1283 
1284         while (ks.hasMoreElements())
1285         {
1286             byte[] kSalt = new byte[SALT_SIZE];
1287 
1288             random.nextBytes(kSalt);
1289 
1290             String name = (String)ks.nextElement();
1291             PrivateKey privKey = (PrivateKey)keys.get(name);
1292             PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
1293             byte[] kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
1294             AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
1295             org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
1296             boolean attrSet = false;
1297             ASN1EncodableVector kName = new ASN1EncodableVector();
1298 
1299             if (privKey instanceof PKCS12BagAttributeCarrier)
1300             {
1301                 PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)privKey;
1302                 //
1303                 // make sure we are using the local alias on store
1304                 //
1305                 DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
1306                 if (nm == null || !nm.getString().equals(name))
1307                 {
1308                     bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
1309                 }
1310 
1311                 //
1312                 // make sure we have a local key-id
1313                 //
1314                 if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
1315                 {
1316                     Certificate ct = engineGetCertificate(name);
1317 
1318                     bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(ct.getPublicKey()));
1319                 }
1320 
1321                 Enumeration e = bagAttrs.getBagAttributeKeys();
1322 
1323                 while (e.hasMoreElements())
1324                 {
1325                     ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
1326                     ASN1EncodableVector kSeq = new ASN1EncodableVector();
1327 
1328                     kSeq.add(oid);
1329                     kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
1330 
1331                     attrSet = true;
1332 
1333                     kName.add(new DERSequence(kSeq));
1334                 }
1335             }
1336 
1337             if (!attrSet)
1338             {
1339                 //
1340                 // set a default friendly name (from the key id) and local id
1341                 //
1342                 ASN1EncodableVector kSeq = new ASN1EncodableVector();
1343                 Certificate ct = engineGetCertificate(name);
1344 
1345                 kSeq.add(pkcs_9_at_localKeyId);
1346                 kSeq.add(new DERSet(createSubjectKeyId(ct.getPublicKey())));
1347 
1348                 kName.add(new DERSequence(kSeq));
1349 
1350                 kSeq = new ASN1EncodableVector();
1351 
1352                 kSeq.add(pkcs_9_at_friendlyName);
1353                 kSeq.add(new DERSet(new DERBMPString(name)));
1354 
1355                 kName.add(new DERSequence(kSeq));
1356             }
1357 
1358             SafeBag kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.toASN1Primitive(), new DERSet(kName));
1359             keyS.add(kBag);
1360         }
1361 
1362         byte[] keySEncoded = new DERSequence(keyS).getEncoded(ASN1Encoding.DER);
1363         BEROctetString keyString = new BEROctetString(keySEncoded);
1364 
1365         //
1366         // certificate processing
1367         //
1368         byte[] cSalt = new byte[SALT_SIZE];
1369 
1370         random.nextBytes(cSalt);
1371 
1372         ASN1EncodableVector certSeq = new ASN1EncodableVector();
1373         PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
1374         AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
1375         Hashtable doneCerts = new Hashtable();
1376 
1377         Enumeration cs = keys.keys();
1378         while (cs.hasMoreElements())
1379         {
1380             try
1381             {
1382                 String name = (String)cs.nextElement();
1383                 Certificate cert = engineGetCertificate(name);
1384                 boolean cAttrSet = false;
1385                 CertBag cBag = new CertBag(
1386                     x509Certificate,
1387                     new DEROctetString(cert.getEncoded()));
1388                 ASN1EncodableVector fName = new ASN1EncodableVector();
1389 
1390                 if (cert instanceof PKCS12BagAttributeCarrier)
1391                 {
1392                     PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
1393                     //
1394                     // make sure we are using the local alias on store
1395                     //
1396                     DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
1397                     if (nm == null || !nm.getString().equals(name))
1398                     {
1399                         bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
1400                     }
1401 
1402                     //
1403                     // make sure we have a local key-id
1404                     //
1405                     if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
1406                     {
1407                         bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(cert.getPublicKey()));
1408                     }
1409 
1410                     Enumeration e = bagAttrs.getBagAttributeKeys();
1411 
1412                     while (e.hasMoreElements())
1413                     {
1414                         ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
1415                         ASN1EncodableVector fSeq = new ASN1EncodableVector();
1416 
1417                         fSeq.add(oid);
1418                         fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
1419                         fName.add(new DERSequence(fSeq));
1420 
1421                         cAttrSet = true;
1422                     }
1423                 }
1424 
1425                 if (!cAttrSet)
1426                 {
1427                     ASN1EncodableVector fSeq = new ASN1EncodableVector();
1428 
1429                     fSeq.add(pkcs_9_at_localKeyId);
1430                     fSeq.add(new DERSet(createSubjectKeyId(cert.getPublicKey())));
1431                     fName.add(new DERSequence(fSeq));
1432 
1433                     fSeq = new ASN1EncodableVector();
1434 
1435                     fSeq.add(pkcs_9_at_friendlyName);
1436                     fSeq.add(new DERSet(new DERBMPString(name)));
1437 
1438                     fName.add(new DERSequence(fSeq));
1439                 }
1440 
1441                 SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
1442 
1443                 certSeq.add(sBag);
1444 
1445                 doneCerts.put(cert, cert);
1446             }
1447             catch (CertificateEncodingException e)
1448             {
1449                 throw new IOException("Error encoding certificate: " + e.toString());
1450             }
1451         }
1452 
1453         cs = certs.keys();
1454         while (cs.hasMoreElements())
1455         {
1456             try
1457             {
1458                 String certId = (String)cs.nextElement();
1459                 Certificate cert = (Certificate)certs.get(certId);
1460                 boolean cAttrSet = false;
1461 
1462                 if (keys.get(certId) != null)
1463                 {
1464                     continue;
1465                 }
1466 
1467                 CertBag cBag = new CertBag(
1468                     x509Certificate,
1469                     new DEROctetString(cert.getEncoded()));
1470                 ASN1EncodableVector fName = new ASN1EncodableVector();
1471 
1472                 if (cert instanceof PKCS12BagAttributeCarrier)
1473                 {
1474                     PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
1475                     //
1476                     // make sure we are using the local alias on store
1477                     //
1478                     DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
1479                     if (nm == null || !nm.getString().equals(certId))
1480                     {
1481                         bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId));
1482                     }
1483 
1484                     Enumeration e = bagAttrs.getBagAttributeKeys();
1485 
1486                     while (e.hasMoreElements())
1487                     {
1488                         ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
1489 
1490                         // a certificate not immediately linked to a key doesn't require
1491                         // a localKeyID and will confuse some PKCS12 implementations.
1492                         //
1493                         // If we find one, we'll prune it out.
1494                         if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
1495                         {
1496                             continue;
1497                         }
1498 
1499                         ASN1EncodableVector fSeq = new ASN1EncodableVector();
1500 
1501                         fSeq.add(oid);
1502                         fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
1503                         fName.add(new DERSequence(fSeq));
1504 
1505                         cAttrSet = true;
1506                     }
1507                 }
1508 
1509                 if (!cAttrSet)
1510                 {
1511                     ASN1EncodableVector fSeq = new ASN1EncodableVector();
1512 
1513                     fSeq.add(pkcs_9_at_friendlyName);
1514                     fSeq.add(new DERSet(new DERBMPString(certId)));
1515 
1516                     fName.add(new DERSequence(fSeq));
1517                 }
1518 
1519                 SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
1520 
1521                 certSeq.add(sBag);
1522 
1523                 doneCerts.put(cert, cert);
1524             }
1525             catch (CertificateEncodingException e)
1526             {
1527                 throw new IOException("Error encoding certificate: " + e.toString());
1528             }
1529         }
1530 
1531         Set usedSet = getUsedCertificateSet();
1532 
1533         cs = chainCerts.keys();
1534         while (cs.hasMoreElements())
1535         {
1536             try
1537             {
1538                 CertId certId = (CertId)cs.nextElement();
1539                 Certificate cert = (Certificate)chainCerts.get(certId);
1540 
1541                 if (!usedSet.contains(cert))
1542                 {
1543                     continue;
1544                 }
1545 
1546                 if (doneCerts.get(cert) != null)
1547                 {
1548                     continue;
1549                 }
1550 
1551                 CertBag cBag = new CertBag(
1552                     x509Certificate,
1553                     new DEROctetString(cert.getEncoded()));
1554                 ASN1EncodableVector fName = new ASN1EncodableVector();
1555 
1556                 if (cert instanceof PKCS12BagAttributeCarrier)
1557                 {
1558                     PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
1559                     Enumeration e = bagAttrs.getBagAttributeKeys();
1560 
1561                     while (e.hasMoreElements())
1562                     {
1563                         ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
1564 
1565                         // a certificate not immediately linked to a key doesn't require
1566                         // a localKeyID and will confuse some PKCS12 implementations.
1567                         //
1568                         // If we find one, we'll prune it out.
1569                         if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
1570                         {
1571                             continue;
1572                         }
1573 
1574                         ASN1EncodableVector fSeq = new ASN1EncodableVector();
1575 
1576                         fSeq.add(oid);
1577                         fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
1578                         fName.add(new DERSequence(fSeq));
1579                     }
1580                 }
1581 
1582                 SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
1583 
1584                 certSeq.add(sBag);
1585             }
1586             catch (CertificateEncodingException e)
1587             {
1588                 throw new IOException("Error encoding certificate: " + e.toString());
1589             }
1590         }
1591 
1592         byte[] certSeqEncoded = new DERSequence(certSeq).getEncoded(ASN1Encoding.DER);
1593         byte[] certBytes = cryptData(true, cAlgId, password, false, certSeqEncoded);
1594         EncryptedData cInfo = new EncryptedData(data, cAlgId, new BEROctetString(certBytes));
1595 
1596         ContentInfo[] info = new ContentInfo[]
1597             {
1598                 new ContentInfo(data, keyString),
1599                 new ContentInfo(encryptedData, cInfo.toASN1Primitive())
1600             };
1601 
1602         AuthenticatedSafe auth = new AuthenticatedSafe(info);
1603 
1604         ByteArrayOutputStream bOut = new ByteArrayOutputStream();
1605         DEROutputStream asn1Out;
1606         if (useDEREncoding)
1607         {
1608             asn1Out = new DEROutputStream(bOut);
1609         }
1610         else
1611         {
1612             asn1Out = new BEROutputStream(bOut);
1613         }
1614 
1615         asn1Out.writeObject(auth);
1616 
1617         byte[] pkg = bOut.toByteArray();
1618 
1619         ContentInfo mainInfo = new ContentInfo(data, new BEROctetString(pkg));
1620 
1621         //
1622         // create the mac
1623         //
1624         byte[] mSalt = new byte[20];
1625         int itCount = MIN_ITERATIONS;
1626 
1627         random.nextBytes(mSalt);
1628 
1629         byte[] data = ((ASN1OctetString)mainInfo.getContent()).getOctets();
1630 
1631         MacData mData;
1632 
1633         try
1634         {
1635             byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data);
1636 
1637             AlgorithmIdentifier algId = new AlgorithmIdentifier(id_SHA1, DERNull.INSTANCE);
1638             DigestInfo dInfo = new DigestInfo(algId, res);
1639 
1640             mData = new MacData(dInfo, mSalt, itCount);
1641         }
1642         catch (Exception e)
1643         {
1644             throw new IOException("error constructing MAC: " + e.toString());
1645         }
1646 
1647         //
1648         // output the Pfx
1649         //
1650         Pfx pfx = new Pfx(mainInfo, mData);
1651 
1652         if (useDEREncoding)
1653         {
1654             asn1Out = new DEROutputStream(stream);
1655         }
1656         else
1657         {
1658             asn1Out = new BEROutputStream(stream);
1659         }
1660 
1661         asn1Out.writeObject(pfx);
1662     }
1663 
getUsedCertificateSet()1664     private Set getUsedCertificateSet()
1665     {
1666         Set usedSet = new HashSet();
1667 
1668         for (Enumeration en = keys.keys(); en.hasMoreElements();)
1669         {
1670             String alias = (String)en.nextElement();
1671 
1672                 Certificate[] certs = engineGetCertificateChain(alias);
1673 
1674                 for (int i = 0; i != certs.length; i++)
1675                 {
1676                     usedSet.add(certs[i]);
1677                 }
1678         }
1679 
1680         for (Enumeration en = certs.keys(); en.hasMoreElements();)
1681         {
1682             String alias = (String)en.nextElement();
1683 
1684             Certificate cert = engineGetCertificate(alias);
1685 
1686             usedSet.add(cert);
1687         }
1688 
1689         return usedSet;
1690     }
1691 
calculatePbeMac( ASN1ObjectIdentifier oid, byte[] salt, int itCount, char[] password, boolean wrongPkcs12Zero, byte[] data)1692     private byte[] calculatePbeMac(
1693         ASN1ObjectIdentifier oid,
1694         byte[] salt,
1695         int itCount,
1696         char[] password,
1697         boolean wrongPkcs12Zero,
1698         byte[] data)
1699         throws Exception
1700     {
1701         PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
1702 
1703         Mac mac = helper.createMac(oid.getId());
1704         mac.init(new PKCS12Key(password, wrongPkcs12Zero), defParams);
1705         mac.update(data);
1706 
1707         return mac.doFinal();
1708     }
1709 
1710     public static class BCPKCS12KeyStore
1711         extends PKCS12KeyStoreSpi
1712     {
BCPKCS12KeyStore()1713         public BCPKCS12KeyStore()
1714         {
1715             super(new BouncyCastleProvider(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
1716         }
1717     }
1718     // BEGIN android-removed
1719     // public static class BCPKCS12KeyStore3DES
1720     //     extends PKCS12KeyStoreSpi
1721     // {
1722     //     public BCPKCS12KeyStore3DES()
1723     //     {
1724     //         super(new BouncyCastleProvider(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
1725     //     }
1726     // }
1727     //
1728     // public static class DefPKCS12KeyStore
1729     //     extends PKCS12KeyStoreSpi
1730     // {
1731     //     public DefPKCS12KeyStore()
1732     //     {
1733     //         super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
1734     //     }
1735     // }
1736     //
1737     // public static class DefPKCS12KeyStore3DES
1738     //     extends PKCS12KeyStoreSpi
1739     // {
1740     //     public DefPKCS12KeyStore3DES()
1741     //     {
1742     //         super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
1743     //     }
1744     // }
1745     // END android-removed
1746 
1747     private static class IgnoresCaseHashtable
1748     {
1749         private Hashtable orig = new Hashtable();
1750         private Hashtable keys = new Hashtable();
1751 
put(String key, Object value)1752         public void put(String key, Object value)
1753         {
1754             String lower = (key == null) ? null : Strings.toLowerCase(key);
1755             String k = (String)keys.get(lower);
1756             if (k != null)
1757             {
1758                 orig.remove(k);
1759             }
1760 
1761             keys.put(lower, key);
1762             orig.put(key, value);
1763         }
1764 
keys()1765         public Enumeration keys()
1766         {
1767             return orig.keys();
1768         }
1769 
remove(String alias)1770         public Object remove(String alias)
1771         {
1772             String k = (String)keys.remove(alias == null ? null : Strings.toLowerCase(alias));
1773             if (k == null)
1774             {
1775                 return null;
1776             }
1777 
1778             return orig.remove(k);
1779         }
1780 
get(String alias)1781         public Object get(String alias)
1782         {
1783             String k = (String)keys.get(alias == null ? null : Strings.toLowerCase(alias));
1784             if (k == null)
1785             {
1786                 return null;
1787             }
1788 
1789             return orig.get(k);
1790         }
1791 
elements()1792         public Enumeration elements()
1793         {
1794             return orig.elements();
1795         }
1796     }
1797 
1798     private static class DefaultSecretKeyProvider
1799     {
1800         private final Map KEY_SIZES;
1801 
DefaultSecretKeyProvider()1802         DefaultSecretKeyProvider()
1803         {
1804             Map keySizes = new HashMap();
1805 
1806             keySizes.put(new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"), Integers.valueOf(128));
1807 
1808             keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, Integers.valueOf(192));
1809 
1810             keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128));
1811             keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192));
1812             keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256));
1813 
1814             keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128));
1815             keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192));
1816             keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256));
1817 
1818             // BEGIN android-removed
1819             // keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256));
1820             // END android-removed
1821 
1822             KEY_SIZES = Collections.unmodifiableMap(keySizes);
1823         }
1824 
getKeySize(AlgorithmIdentifier algorithmIdentifier)1825         public int getKeySize(AlgorithmIdentifier algorithmIdentifier)
1826         {
1827             // TODO: not all ciphers/oid relationships are this simple.
1828             Integer keySize = (Integer)KEY_SIZES.get(algorithmIdentifier.getAlgorithm());
1829 
1830             if (keySize != null)
1831             {
1832                 return keySize.intValue();
1833             }
1834 
1835             return -1;
1836         }
1837     }
1838 }
1839