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