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