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