Home | History | Annotate | Download | only in openssl
      1 package org.bouncycastle.openssl;
      2 
      3 import java.io.ByteArrayInputStream;
      4 import java.io.IOException;
      5 import java.io.Reader;
      6 import java.security.AlgorithmParameters;
      7 import java.security.KeyFactory;
      8 import java.security.KeyPair;
      9 import java.security.NoSuchAlgorithmException;
     10 import java.security.NoSuchProviderException;
     11 import java.security.PublicKey;
     12 import java.security.cert.CertificateFactory;
     13 import java.security.spec.DSAPrivateKeySpec;
     14 import java.security.spec.DSAPublicKeySpec;
     15 import java.security.spec.InvalidKeySpecException;
     16 import java.security.spec.KeySpec;
     17 import java.security.spec.PKCS8EncodedKeySpec;
     18 import java.security.spec.RSAPrivateCrtKeySpec;
     19 import java.security.spec.RSAPublicKeySpec;
     20 import java.security.spec.X509EncodedKeySpec;
     21 import java.util.HashMap;
     22 import java.util.Iterator;
     23 import java.util.List;
     24 import java.util.Map;
     25 import java.util.StringTokenizer;
     26 
     27 import javax.crypto.Cipher;
     28 import javax.crypto.SecretKey;
     29 import javax.crypto.SecretKeyFactory;
     30 import javax.crypto.spec.PBEKeySpec;
     31 import javax.crypto.spec.PBEParameterSpec;
     32 
     33 import org.bouncycastle.asn1.ASN1InputStream;
     34 import org.bouncycastle.asn1.ASN1Object;
     35 import org.bouncycastle.asn1.ASN1Sequence;
     36 import org.bouncycastle.asn1.DERInteger;
     37 import org.bouncycastle.asn1.DERObjectIdentifier;
     38 import org.bouncycastle.asn1.cms.ContentInfo;
     39 import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
     40 import org.bouncycastle.asn1.pkcs.EncryptionScheme;
     41 import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
     42 import org.bouncycastle.asn1.pkcs.PBEParameter;
     43 import org.bouncycastle.asn1.pkcs.PBES2Parameters;
     44 import org.bouncycastle.asn1.pkcs.PBKDF2Params;
     45 import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
     46 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
     47 import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
     48 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
     49 import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
     50 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
     51 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
     52 import org.bouncycastle.jce.ECNamedCurveTable;
     53 import org.bouncycastle.jce.PKCS10CertificationRequest;
     54 import org.bouncycastle.util.encoders.Hex;
     55 import org.bouncycastle.util.io.pem.PemHeader;
     56 import org.bouncycastle.util.io.pem.PemObject;
     57 import org.bouncycastle.util.io.pem.PemObjectParser;
     58 import org.bouncycastle.util.io.pem.PemReader;
     59 import org.bouncycastle.x509.X509V2AttributeCertificate;
     60 
     61 /**
     62  * Class for reading OpenSSL PEM encoded streams containing
     63  * X509 certificates, PKCS8 encoded keys and PKCS7 objects.
     64  * <p>
     65  * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Keys and
     66  * Certificates will be returned using the appropriate java.security type (KeyPair, PublicKey, X509Certificate,
     67  * or X509CRL). In the case of a Certificate Request a PKCS10CertificationRequest will be returned.
     68  * </p>
     69  */
     70 public class PEMReader
     71     extends PemReader
     72 {
     73     private final Map parsers = new HashMap();
     74 
     75     private PasswordFinder pFinder;
     76 
     77 
     78     /**
     79      * Create a new PEMReader
     80      *
     81      * @param reader the Reader
     82      */
     83     public PEMReader(
     84         Reader reader)
     85     {
     86         this(reader, null, "BC");
     87     }
     88 
     89     /**
     90      * Create a new PEMReader with a password finder
     91      *
     92      * @param reader  the Reader
     93      * @param pFinder the password finder
     94      */
     95     public PEMReader(
     96         Reader reader,
     97         PasswordFinder pFinder)
     98     {
     99         this(reader, pFinder, "BC");
    100     }
    101 
    102     /**
    103      * Create a new PEMReader with a password finder
    104      *
    105      * @param reader   the Reader
    106      * @param pFinder  the password finder
    107      * @param provider the cryptography provider to use
    108      */
    109     public PEMReader(
    110         Reader reader,
    111         PasswordFinder pFinder,
    112         String provider)
    113     {
    114         this(reader, pFinder, provider, provider);
    115     }
    116 
    117     /**
    118      * Create a new PEMReader with a password finder and differing providers for secret and public key
    119      * operations.
    120      *
    121      * @param reader   the Reader
    122      * @param pFinder  the password finder
    123      * @param symProvider  provider to use for symmetric operations
    124      * @param asymProvider provider to use for asymmetric (public/private key) operations
    125      */
    126     public PEMReader(
    127         Reader reader,
    128         PasswordFinder pFinder,
    129         String symProvider,
    130         String asymProvider)
    131     {
    132         super(reader);
    133 
    134         this.pFinder = pFinder;
    135 
    136         parsers.put("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
    137         parsers.put("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
    138         parsers.put("CERTIFICATE", new X509CertificateParser(asymProvider));
    139         parsers.put("X509 CERTIFICATE", new X509CertificateParser(asymProvider));
    140         parsers.put("X509 CRL", new X509CRLParser(asymProvider));
    141         parsers.put("PKCS7", new PKCS7Parser());
    142         parsers.put("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser());
    143         parsers.put("EC PARAMETERS", new ECNamedCurveSpecParser());
    144         parsers.put("PUBLIC KEY", new PublicKeyParser(asymProvider));
    145         parsers.put("RSA PUBLIC KEY", new RSAPublicKeyParser(asymProvider));
    146         parsers.put("RSA PRIVATE KEY", new RSAKeyPairParser(asymProvider));
    147         parsers.put("DSA PRIVATE KEY", new DSAKeyPairParser(asymProvider));
    148         parsers.put("EC PRIVATE KEY", new ECDSAKeyPairParser(asymProvider));
    149         parsers.put("ENCRYPTED PRIVATE KEY", new EncryptedPrivateKeyParser(symProvider, asymProvider));
    150         parsers.put("PRIVATE KEY", new PrivateKeyParser(asymProvider));
    151     }
    152 
    153     public Object readObject()
    154         throws IOException
    155     {
    156         PemObject obj = readPemObject();
    157 
    158         if (obj != null)
    159         {
    160             String type = obj.getType();
    161             if (parsers.containsKey(type))
    162             {
    163                 return ((PemObjectParser)parsers.get(type)).parseObject(obj);
    164             }
    165             else
    166             {
    167                 throw new IOException("unrecognised object: " + type);
    168             }
    169         }
    170 
    171         return null;
    172     }
    173 
    174     private abstract class KeyPairParser
    175         implements PemObjectParser
    176     {
    177         protected String provider;
    178 
    179         public KeyPairParser(String provider)
    180         {
    181             this.provider = provider;
    182         }
    183 
    184         /**
    185          * Read a Key Pair
    186          */
    187         protected ASN1Sequence readKeyPair(
    188             PemObject obj)
    189             throws IOException
    190         {
    191             boolean isEncrypted = false;
    192             String dekInfo = null;
    193             List headers = obj.getHeaders();
    194 
    195             for (Iterator it = headers.iterator(); it.hasNext();)
    196             {
    197                 PemHeader hdr = (PemHeader)it.next();
    198 
    199                 if (hdr.getName().equals("Proc-Type") && hdr.getValue().equals("4,ENCRYPTED"))
    200                 {
    201                     isEncrypted = true;
    202                 }
    203                 else if (hdr.getName().equals("DEK-Info"))
    204                 {
    205                     dekInfo = hdr.getValue();
    206                 }
    207             }
    208 
    209             //
    210             // extract the key
    211             //
    212             byte[] keyBytes = obj.getContent();
    213 
    214             if (isEncrypted)
    215             {
    216                 if (pFinder == null)
    217                 {
    218                     throw new PasswordException("No password finder specified, but a password is required");
    219                 }
    220 
    221                 char[] password = pFinder.getPassword();
    222 
    223                 if (password == null)
    224                 {
    225                     throw new PasswordException("Password is null, but a password is required");
    226                 }
    227 
    228                 StringTokenizer tknz = new StringTokenizer(dekInfo, ",");
    229                 String dekAlgName = tknz.nextToken();
    230                 byte[] iv = Hex.decode(tknz.nextToken());
    231 
    232                 keyBytes = PEMUtilities.crypt(false, provider, keyBytes, password, dekAlgName, iv);
    233             }
    234 
    235             try
    236             {
    237                 return (ASN1Sequence)ASN1Object.fromByteArray(keyBytes);
    238             }
    239             catch (IOException e)
    240             {
    241                 if (isEncrypted)
    242                 {
    243                     throw new PEMException("exception decoding - please check password and data.", e);
    244                 }
    245                 else
    246                 {
    247                     throw new PEMException(e.getMessage(), e);
    248                 }
    249             }
    250             catch (ClassCastException e)
    251             {
    252                 if (isEncrypted)
    253                 {
    254                     throw new PEMException("exception decoding - please check password and data.", e);
    255                 }
    256                 else
    257                 {
    258                     throw new PEMException(e.getMessage(), e);
    259                 }
    260             }
    261         }
    262     }
    263 
    264     private class DSAKeyPairParser
    265         extends KeyPairParser
    266     {
    267         public DSAKeyPairParser(String provider)
    268         {
    269             super(provider);
    270         }
    271 
    272         public Object parseObject(PemObject obj)
    273             throws IOException
    274         {
    275             try
    276             {
    277                 ASN1Sequence seq = readKeyPair(obj);
    278 
    279                 if (seq.size() != 6)
    280                 {
    281                     throw new PEMException("malformed sequence in DSA private key");
    282                 }
    283 
    284                 //            DERInteger              v = (DERInteger)seq.getObjectAt(0);
    285                 DERInteger p = (DERInteger)seq.getObjectAt(1);
    286                 DERInteger q = (DERInteger)seq.getObjectAt(2);
    287                 DERInteger g = (DERInteger)seq.getObjectAt(3);
    288                 DERInteger y = (DERInteger)seq.getObjectAt(4);
    289                 DERInteger x = (DERInteger)seq.getObjectAt(5);
    290 
    291                 DSAPrivateKeySpec privSpec = new DSAPrivateKeySpec(
    292                     x.getValue(), p.getValue(),
    293                     q.getValue(), g.getValue());
    294                 DSAPublicKeySpec pubSpec = new DSAPublicKeySpec(
    295                     y.getValue(), p.getValue(),
    296                     q.getValue(), g.getValue());
    297 
    298                 KeyFactory fact = KeyFactory.getInstance("DSA", provider);
    299 
    300                 return new KeyPair(
    301                     fact.generatePublic(pubSpec),
    302                     fact.generatePrivate(privSpec));
    303             }
    304             catch (IOException e)
    305             {
    306                 throw e;
    307             }
    308             catch (Exception e)
    309             {
    310                 throw new PEMException(
    311                     "problem creating DSA private key: " + e.toString(), e);
    312             }
    313         }
    314     }
    315 
    316     private class ECDSAKeyPairParser
    317         extends KeyPairParser
    318     {
    319         public ECDSAKeyPairParser(String provider)
    320         {
    321             super(provider);
    322         }
    323 
    324         public Object parseObject(PemObject obj)
    325             throws IOException
    326         {
    327             try
    328             {
    329                 ASN1Sequence seq = readKeyPair(obj);
    330 
    331                 ECPrivateKeyStructure pKey = new ECPrivateKeyStructure(seq);
    332                 AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters());
    333                 PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.getDERObject());
    334                 SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes());
    335 
    336                 PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privInfo.getEncoded());
    337                 X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded());
    338 
    339 
    340                 KeyFactory fact = KeyFactory.getInstance("ECDSA", provider);
    341 
    342 
    343                 return new KeyPair(
    344                     fact.generatePublic(pubSpec),
    345                     fact.generatePrivate(privSpec));
    346             }
    347             catch (IOException e)
    348             {
    349                 throw e;
    350             }
    351             catch (Exception e)
    352             {
    353                 throw new PEMException(
    354                     "problem creating EC private key: " + e.toString(), e);
    355             }
    356         }
    357     }
    358 
    359     private class RSAKeyPairParser
    360         extends KeyPairParser
    361     {
    362         public RSAKeyPairParser(String provider)
    363         {
    364             super(provider);
    365         }
    366 
    367         public Object parseObject(PemObject obj)
    368             throws IOException
    369         {
    370             try
    371             {
    372                 ASN1Sequence seq = readKeyPair(obj);
    373 
    374                 if (seq.size() != 9)
    375                 {
    376                     throw new PEMException("malformed sequence in RSA private key");
    377                 }
    378 
    379                 //            DERInteger              v = (DERInteger)seq.getObjectAt(0);
    380                 DERInteger mod = (DERInteger)seq.getObjectAt(1);
    381                 DERInteger pubExp = (DERInteger)seq.getObjectAt(2);
    382                 DERInteger privExp = (DERInteger)seq.getObjectAt(3);
    383                 DERInteger p1 = (DERInteger)seq.getObjectAt(4);
    384                 DERInteger p2 = (DERInteger)seq.getObjectAt(5);
    385                 DERInteger exp1 = (DERInteger)seq.getObjectAt(6);
    386                 DERInteger exp2 = (DERInteger)seq.getObjectAt(7);
    387                 DERInteger crtCoef = (DERInteger)seq.getObjectAt(8);
    388 
    389                 RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(
    390                     mod.getValue(), pubExp.getValue());
    391                 RSAPrivateCrtKeySpec privSpec = new RSAPrivateCrtKeySpec(
    392                     mod.getValue(), pubExp.getValue(), privExp.getValue(),
    393                     p1.getValue(), p2.getValue(),
    394                     exp1.getValue(), exp2.getValue(),
    395                     crtCoef.getValue());
    396 
    397 
    398                 KeyFactory fact = KeyFactory.getInstance("RSA", provider);
    399 
    400 
    401                 return new KeyPair(
    402                     fact.generatePublic(pubSpec),
    403                     fact.generatePrivate(privSpec));
    404             }
    405             catch (IOException e)
    406             {
    407                 throw e;
    408             }
    409             catch (Exception e)
    410             {
    411                 throw new PEMException(
    412                     "problem creating RSA private key: " + e.toString(), e);
    413             }
    414         }
    415     }
    416 
    417     private class PublicKeyParser
    418         implements PemObjectParser
    419     {
    420         private String provider;
    421 
    422         public PublicKeyParser(String provider)
    423         {
    424             this.provider = provider;
    425         }
    426 
    427         public Object parseObject(PemObject obj)
    428             throws IOException
    429         {
    430             KeySpec keySpec = new X509EncodedKeySpec(obj.getContent());
    431             String[] algorithms = {"DSA", "RSA"};
    432             for (int i = 0; i < algorithms.length; i++)
    433             {
    434                 try
    435                 {
    436                     KeyFactory keyFact = KeyFactory.getInstance(algorithms[i], provider);
    437                     PublicKey pubKey = keyFact.generatePublic(keySpec);
    438 
    439                     return pubKey;
    440                 }
    441                 catch (NoSuchAlgorithmException e)
    442                 {
    443                     // ignore
    444                 }
    445                 catch (InvalidKeySpecException e)
    446                 {
    447                     // ignore
    448                 }
    449                 catch (NoSuchProviderException e)
    450                 {
    451                     throw new RuntimeException("can't find provider " + provider);
    452                 }
    453             }
    454 
    455             return null;
    456         }
    457     }
    458 
    459     private class RSAPublicKeyParser
    460         implements PemObjectParser
    461     {
    462         private String provider;
    463 
    464         public RSAPublicKeyParser(String provider)
    465         {
    466             this.provider = provider;
    467         }
    468 
    469         public Object parseObject(PemObject obj)
    470             throws IOException
    471         {
    472             try
    473             {
    474                 ASN1InputStream ais = new ASN1InputStream(obj.getContent());
    475                 Object asnObject = ais.readObject();
    476                 ASN1Sequence sequence = (ASN1Sequence)asnObject;
    477                 RSAPublicKeyStructure rsaPubStructure = new RSAPublicKeyStructure(sequence);
    478                 RSAPublicKeySpec keySpec = new RSAPublicKeySpec(
    479                     rsaPubStructure.getModulus(),
    480                     rsaPubStructure.getPublicExponent());
    481 
    482 
    483                     KeyFactory keyFact = KeyFactory.getInstance("RSA", provider);
    484 
    485                     return keyFact.generatePublic(keySpec);
    486             }
    487             catch (IOException e)
    488             {
    489                 throw e;
    490             }
    491             catch (NoSuchProviderException e)
    492             {
    493                 throw new IOException("can't find provider " + provider);
    494             }
    495             catch (Exception e)
    496             {
    497                 throw new PEMException("problem extracting key: " + e.toString(), e);
    498             }
    499         }
    500     }
    501 
    502     private class X509CertificateParser
    503         implements PemObjectParser
    504     {
    505         private String provider;
    506 
    507         public X509CertificateParser(String provider)
    508         {
    509             this.provider = provider;
    510         }
    511 
    512         /**
    513          * Reads in a X509Certificate.
    514          *
    515          * @return the X509Certificate
    516          * @throws IOException if an I/O error occured
    517          */
    518         public Object parseObject(PemObject obj)
    519             throws IOException
    520         {
    521             ByteArrayInputStream bIn = new ByteArrayInputStream(obj.getContent());
    522 
    523             try
    524             {
    525                 CertificateFactory certFact
    526                     = CertificateFactory.getInstance("X.509", provider);
    527 
    528                 return certFact.generateCertificate(bIn);
    529             }
    530             catch (Exception e)
    531             {
    532                 throw new PEMException("problem parsing cert: " + e.toString(), e);
    533             }
    534         }
    535     }
    536 
    537     private class X509CRLParser
    538         implements PemObjectParser
    539     {
    540         private String provider;
    541 
    542         public X509CRLParser(String provider)
    543         {
    544             this.provider = provider;
    545         }
    546 
    547         /**
    548          * Reads in a X509CRL.
    549          *
    550          * @return the X509Certificate
    551          * @throws IOException if an I/O error occured
    552          */
    553         public Object parseObject(PemObject obj)
    554             throws IOException
    555         {
    556             ByteArrayInputStream bIn = new ByteArrayInputStream(obj.getContent());
    557 
    558             try
    559             {
    560                 CertificateFactory certFact
    561                     = CertificateFactory.getInstance("X.509", provider);
    562 
    563                 return certFact.generateCRL(bIn);
    564             }
    565             catch (Exception e)
    566             {
    567                 throw new PEMException("problem parsing cert: " + e.toString(), e);
    568             }
    569         }
    570     }
    571 
    572     private class PKCS10CertificationRequestParser
    573         implements PemObjectParser
    574     {
    575         /**
    576          * Reads in a PKCS10 certification request.
    577          *
    578          * @return the certificate request.
    579          * @throws IOException if an I/O error occured
    580          */
    581         public Object parseObject(PemObject obj)
    582             throws IOException
    583         {
    584             try
    585             {
    586                 return new PKCS10CertificationRequest(obj.getContent());
    587             }
    588             catch (Exception e)
    589             {
    590                 throw new PEMException("problem parsing certrequest: " + e.toString(), e);
    591             }
    592         }
    593     }
    594 
    595     private class PKCS7Parser
    596         implements PemObjectParser
    597     {
    598         /**
    599          * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS
    600          * API.
    601          *
    602          * @return the X509Certificate
    603          * @throws IOException if an I/O error occured
    604          */
    605         public Object parseObject(PemObject obj)
    606             throws IOException
    607         {
    608             try
    609             {
    610                 ASN1InputStream aIn = new ASN1InputStream(obj.getContent());
    611 
    612                 return ContentInfo.getInstance(aIn.readObject());
    613             }
    614             catch (Exception e)
    615             {
    616                 throw new PEMException("problem parsing PKCS7 object: " + e.toString(), e);
    617             }
    618         }
    619     }
    620 
    621     private class X509AttributeCertificateParser
    622         implements PemObjectParser
    623     {
    624         public Object parseObject(PemObject obj)
    625             throws IOException
    626         {
    627             return new X509V2AttributeCertificate(obj.getContent());
    628         }
    629     }
    630 
    631     private class ECNamedCurveSpecParser
    632         implements PemObjectParser
    633     {
    634         public Object parseObject(PemObject obj)
    635             throws IOException
    636         {
    637             try
    638             {
    639                 DERObjectIdentifier oid = (DERObjectIdentifier)ASN1Object.fromByteArray(obj.getContent());
    640 
    641                 Object params = ECNamedCurveTable.getParameterSpec(oid.getId());
    642 
    643                 if (params == null)
    644                 {
    645                     throw new IOException("object ID not found in EC curve table");
    646                 }
    647 
    648                 return params;
    649             }
    650             catch (IOException e)
    651             {
    652                 throw e;
    653             }
    654             catch (Exception e)
    655             {
    656                 throw new PEMException("exception extracting EC named curve: " + e.toString());
    657             }
    658         }
    659     }
    660 
    661     private class EncryptedPrivateKeyParser
    662         implements PemObjectParser
    663     {
    664         private String symProvider;
    665         private String asymProvider;
    666 
    667         public EncryptedPrivateKeyParser(String symProvider, String asymProvider)
    668         {
    669             this.symProvider = symProvider;
    670             this.asymProvider = asymProvider;
    671         }
    672 
    673         /**
    674          * Reads in a X509CRL.
    675          *
    676          * @return the X509Certificate
    677          * @throws IOException if an I/O error occured
    678          */
    679         public Object parseObject(PemObject obj)
    680             throws IOException
    681         {
    682             try
    683             {
    684                 EncryptedPrivateKeyInfo info = EncryptedPrivateKeyInfo.getInstance(ASN1Object.fromByteArray(obj.getContent()));
    685                 AlgorithmIdentifier algId = info.getEncryptionAlgorithm();
    686 
    687                 if (pFinder == null)
    688                 {
    689                     throw new PEMException("no PasswordFinder specified");
    690                 }
    691 
    692                 if (PEMUtilities.isPKCS5Scheme2(algId.getAlgorithm()))
    693                 {
    694                     PBES2Parameters params = PBES2Parameters.getInstance(algId.getParameters());
    695                     KeyDerivationFunc func = params.getKeyDerivationFunc();
    696                     EncryptionScheme scheme = params.getEncryptionScheme();
    697                     PBKDF2Params defParams = (PBKDF2Params)func.getParameters();
    698 
    699                     int iterationCount = defParams.getIterationCount().intValue();
    700                     byte[] salt = defParams.getSalt();
    701 
    702                     String algorithm = scheme.getAlgorithm().getId();
    703 
    704                     SecretKey key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(algorithm, pFinder.getPassword(), salt, iterationCount);
    705 
    706                     Cipher cipher = Cipher.getInstance(algorithm, symProvider);
    707                     AlgorithmParameters algParams = AlgorithmParameters.getInstance(algorithm, symProvider);
    708 
    709                     algParams.init(scheme.getParameters().getDERObject().getEncoded());
    710 
    711                     cipher.init(Cipher.DECRYPT_MODE, key, algParams);
    712 
    713                     PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData())));
    714                     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded());
    715 
    716                     KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider);
    717 
    718                     return keyFact.generatePrivate(keySpec);
    719                 }
    720                 else if (PEMUtilities.isPKCS12(algId.getAlgorithm()))
    721                 {
    722                     PKCS12PBEParams params = PKCS12PBEParams.getInstance(algId.getParameters());
    723                     String algorithm = algId.getAlgorithm().getId();
    724                     PBEKeySpec pbeSpec = new PBEKeySpec(pFinder.getPassword());
    725 
    726                     SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm, symProvider);
    727                     PBEParameterSpec defParams = new PBEParameterSpec(params.getIV(), params.getIterations().intValue());
    728 
    729                     Cipher cipher = Cipher.getInstance(algorithm, symProvider);
    730 
    731                     cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams);
    732 
    733                     PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData())));
    734                     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded());
    735 
    736                     KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider);
    737 
    738                     return keyFact.generatePrivate(keySpec);
    739                 }
    740                 else if (PEMUtilities.isPKCS5Scheme1(algId.getAlgorithm()))
    741                 {
    742                     PBEParameter params = PBEParameter.getInstance(algId.getParameters());
    743                     String algorithm = algId.getAlgorithm().getId();
    744                     PBEKeySpec pbeSpec = new PBEKeySpec(pFinder.getPassword());
    745 
    746                     SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm, symProvider);
    747                     PBEParameterSpec defParams = new PBEParameterSpec(params.getSalt(), params.getIterationCount().intValue());
    748 
    749                     Cipher cipher = Cipher.getInstance(algorithm, symProvider);
    750 
    751                     cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams);
    752 
    753                     PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData())));
    754                     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded());
    755 
    756                     KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider);
    757 
    758                     return keyFact.generatePrivate(keySpec);
    759                 }
    760                 else
    761                 {
    762                     throw new PEMException("Unknown algorithm: " + algId.getAlgorithm());
    763                 }
    764             }
    765             catch (IOException e)
    766             {
    767                 throw e;
    768             }
    769             catch (Exception e)
    770             {
    771                 throw new PEMException("problem parsing ENCRYPTED PRIVATE KEY: " + e.toString(), e);
    772             }
    773         }
    774     }
    775 
    776     private class PrivateKeyParser
    777         implements PemObjectParser
    778     {
    779         private String provider;
    780 
    781         public PrivateKeyParser(String provider)
    782         {
    783             this.provider = provider;
    784         }
    785 
    786         public Object parseObject(PemObject obj)
    787             throws IOException
    788         {
    789             try
    790             {
    791                 PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(obj.getContent()));
    792                 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(obj.getContent());
    793 
    794                 KeyFactory keyFact = KeyFactory.getInstance(info.getAlgorithmId().getAlgorithm().getId(), provider);
    795 
    796                 return keyFact.generatePrivate(keySpec);
    797             }
    798             catch (Exception e)
    799             {
    800                 throw new PEMException("problem parsing PRIVATE KEY: " + e.toString(), e);
    801             }
    802         }
    803     }
    804 }
    805