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