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