Home | History | Annotate | Download | only in openssl
      1 package org.bouncycastle.openssl;
      2 
      3 import java.io.IOException;
      4 import java.math.BigInteger;
      5 import java.security.Key;
      6 import java.security.KeyPair;
      7 import java.security.NoSuchProviderException;
      8 import java.security.PrivateKey;
      9 import java.security.Provider;
     10 import java.security.PublicKey;
     11 import java.security.SecureRandom;
     12 import java.security.Security;
     13 import java.security.cert.CRLException;
     14 import java.security.cert.CertificateEncodingException;
     15 import java.security.cert.X509CRL;
     16 import java.security.cert.X509Certificate;
     17 import java.security.interfaces.DSAParams;
     18 import java.security.interfaces.DSAPrivateKey;
     19 import java.security.interfaces.RSAPrivateCrtKey;
     20 import java.security.interfaces.RSAPrivateKey;
     21 import java.util.ArrayList;
     22 import java.util.List;
     23 
     24 import org.bouncycastle.asn1.ASN1EncodableVector;
     25 import org.bouncycastle.asn1.ASN1Object;
     26 import org.bouncycastle.asn1.ASN1Sequence;
     27 import org.bouncycastle.asn1.DERInteger;
     28 import org.bouncycastle.asn1.DERSequence;
     29 import org.bouncycastle.asn1.cms.ContentInfo;
     30 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
     31 import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
     32 import org.bouncycastle.asn1.x509.DSAParameter;
     33 import org.bouncycastle.jce.PKCS10CertificationRequest;
     34 import org.bouncycastle.util.Strings;
     35 import org.bouncycastle.util.encoders.Hex;
     36 import org.bouncycastle.util.io.pem.PemGenerationException;
     37 import org.bouncycastle.util.io.pem.PemHeader;
     38 import org.bouncycastle.util.io.pem.PemObject;
     39 import org.bouncycastle.util.io.pem.PemObjectGenerator;
     40 import org.bouncycastle.x509.X509AttributeCertificate;
     41 import org.bouncycastle.x509.X509V2AttributeCertificate;
     42 
     43 /**
     44  * PEM generator for the original set of PEM objects used in Open SSL.
     45  */
     46 public class MiscPEMGenerator
     47     implements PemObjectGenerator
     48 {
     49     private Object obj;
     50     private String algorithm;
     51     private char[] password;
     52     private SecureRandom random;
     53     private Provider provider;
     54 
     55     public MiscPEMGenerator(Object o)
     56     {
     57         this.obj = o;
     58     }
     59 
     60     public MiscPEMGenerator(
     61         Object       obj,
     62         String       algorithm,
     63         char[]       password,
     64         SecureRandom random,
     65         Provider     provider)
     66     {
     67         this.obj = obj;
     68         this.algorithm = algorithm;
     69         this.password = password;
     70         this.random = random;
     71         this.provider = provider;
     72     }
     73 
     74     public MiscPEMGenerator(
     75         Object       obj,
     76         String       algorithm,
     77         char[]       password,
     78         SecureRandom random,
     79         String       provider)
     80         throws NoSuchProviderException
     81     {
     82         this.obj = obj;
     83         this.algorithm = algorithm;
     84         this.password = password;
     85         this.random = random;
     86 
     87         if (provider != null)
     88         {
     89             this.provider = Security.getProvider(provider);
     90             if (this.provider == null)
     91             {
     92                 throw new NoSuchProviderException("cannot find provider: " + provider);
     93             }
     94         }
     95     }
     96 
     97     private PemObject createPemObject(Object o)
     98         throws IOException
     99     {
    100         String  type;
    101         byte[]  encoding;
    102 
    103         if (o instanceof PemObject)
    104         {
    105             return (PemObject)o;
    106         }
    107         if (o instanceof PemObjectGenerator)
    108         {
    109             return ((PemObjectGenerator)o).generate();
    110         }
    111         if (o instanceof X509Certificate)
    112         {
    113             type = "CERTIFICATE";
    114             try
    115             {
    116                 encoding = ((X509Certificate)o).getEncoded();
    117             }
    118             catch (CertificateEncodingException e)
    119             {
    120                 throw new PemGenerationException("Cannot encode object: " + e.toString());
    121             }
    122         }
    123         else if (o instanceof X509CRL)
    124         {
    125             type = "X509 CRL";
    126             try
    127             {
    128                 encoding = ((X509CRL)o).getEncoded();
    129             }
    130             catch (CRLException e)
    131             {
    132                 throw new PemGenerationException("Cannot encode object: " + e.toString());
    133             }
    134         }
    135         else if (o instanceof KeyPair)
    136         {
    137             return createPemObject(((KeyPair)o).getPrivate());
    138         }
    139         else if (o instanceof PrivateKey)
    140         {
    141             PrivateKeyInfo info = new PrivateKeyInfo(
    142                 (ASN1Sequence) ASN1Object.fromByteArray(((Key)o).getEncoded()));
    143 
    144             if (o instanceof RSAPrivateKey)
    145             {
    146                 type = "RSA PRIVATE KEY";
    147 
    148                 encoding = info.getPrivateKey().getEncoded();
    149             }
    150             else if (o instanceof DSAPrivateKey)
    151             {
    152                 type = "DSA PRIVATE KEY";
    153 
    154                 DSAParameter p = DSAParameter.getInstance(info.getAlgorithmId().getParameters());
    155                 ASN1EncodableVector v = new ASN1EncodableVector();
    156 
    157                 v.add(new DERInteger(0));
    158                 v.add(new DERInteger(p.getP()));
    159                 v.add(new DERInteger(p.getQ()));
    160                 v.add(new DERInteger(p.getG()));
    161 
    162                 BigInteger x = ((DSAPrivateKey)o).getX();
    163                 BigInteger y = p.getG().modPow(x, p.getP());
    164 
    165                 v.add(new DERInteger(y));
    166                 v.add(new DERInteger(x));
    167 
    168                 encoding = new DERSequence(v).getEncoded();
    169             }
    170             else if (((PrivateKey)o).getAlgorithm().equals("ECDSA"))
    171             {
    172                 type = "EC PRIVATE KEY";
    173 
    174                 encoding = info.getPrivateKey().getEncoded();
    175             }
    176             else
    177             {
    178                 throw new IOException("Cannot identify private key");
    179             }
    180         }
    181         else if (o instanceof PublicKey)
    182         {
    183             type = "PUBLIC KEY";
    184 
    185             encoding = ((PublicKey)o).getEncoded();
    186         }
    187         else if (o instanceof X509AttributeCertificate)
    188         {
    189             type = "ATTRIBUTE CERTIFICATE";
    190             encoding = ((X509V2AttributeCertificate)o).getEncoded();
    191         }
    192         else if (o instanceof PKCS10CertificationRequest)
    193         {
    194             type = "CERTIFICATE REQUEST";
    195             encoding = ((PKCS10CertificationRequest)o).getEncoded();
    196         }
    197         else if (o instanceof ContentInfo)
    198         {
    199             type = "PKCS7";
    200             encoding = ((ContentInfo)o).getEncoded();
    201         }
    202         else
    203         {
    204             throw new PemGenerationException("unknown object passed - can't encode.");
    205         }
    206 
    207         return new PemObject(type, encoding);
    208     }
    209 
    210     private String getHexEncoded(byte[] bytes)
    211         throws IOException
    212     {
    213         bytes = Hex.encode(bytes);
    214 
    215         char[] chars = new char[bytes.length];
    216 
    217         for (int i = 0; i != bytes.length; i++)
    218         {
    219             chars[i] = (char)bytes[i];
    220         }
    221 
    222         return new String(chars);
    223     }
    224 
    225     private PemObject createPemObject(
    226         Object       obj,
    227         String       algorithm,
    228         char[]       password,
    229         SecureRandom random)
    230         throws IOException
    231     {
    232         if (obj instanceof KeyPair)
    233         {
    234             return createPemObject(((KeyPair)obj).getPrivate(), algorithm, password, random);
    235         }
    236 
    237         String type = null;
    238         byte[] keyData = null;
    239 
    240         if (obj instanceof RSAPrivateCrtKey)
    241         {
    242             type = "RSA PRIVATE KEY";
    243 
    244             RSAPrivateCrtKey k = (RSAPrivateCrtKey)obj;
    245 
    246             RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(
    247                 k.getModulus(),
    248                 k.getPublicExponent(),
    249                 k.getPrivateExponent(),
    250                 k.getPrimeP(),
    251                 k.getPrimeQ(),
    252                 k.getPrimeExponentP(),
    253                 k.getPrimeExponentQ(),
    254                 k.getCrtCoefficient());
    255 
    256             // convert to bytearray
    257             keyData = keyStruct.getEncoded();
    258         }
    259         else if (obj instanceof DSAPrivateKey)
    260         {
    261             type = "DSA PRIVATE KEY";
    262 
    263             DSAPrivateKey       k = (DSAPrivateKey)obj;
    264             DSAParams p = k.getParams();
    265             ASN1EncodableVector v = new ASN1EncodableVector();
    266 
    267             v.add(new DERInteger(0));
    268             v.add(new DERInteger(p.getP()));
    269             v.add(new DERInteger(p.getQ()));
    270             v.add(new DERInteger(p.getG()));
    271 
    272             BigInteger x = k.getX();
    273             BigInteger y = p.getG().modPow(x, p.getP());
    274 
    275             v.add(new DERInteger(y));
    276             v.add(new DERInteger(x));
    277 
    278             keyData = new DERSequence(v).getEncoded();
    279         }
    280         else if (obj instanceof PrivateKey && "ECDSA".equals(((PrivateKey)obj).getAlgorithm()))
    281         {
    282             type = "EC PRIVATE KEY";
    283 
    284             PrivateKeyInfo      privInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(((PrivateKey)obj).getEncoded()));
    285 
    286             keyData = privInfo.getPrivateKey().getEncoded();
    287         }
    288 
    289         if (type == null || keyData == null)
    290         {
    291             // TODO Support other types?
    292             throw new IllegalArgumentException("Object type not supported: " + obj.getClass().getName());
    293         }
    294 
    295         String dekAlgName = Strings.toUpperCase(algorithm);
    296 
    297         // Note: For backward compatibility
    298         if (dekAlgName.equals("DESEDE"))
    299         {
    300             dekAlgName = "DES-EDE3-CBC";
    301         }
    302 
    303         int ivLength = dekAlgName.startsWith("AES-") ? 16 : 8;
    304 
    305         byte[] iv = new byte[ivLength];
    306         random.nextBytes(iv);
    307 
    308         byte[] encData = PEMUtilities.crypt(true, provider, keyData, password, dekAlgName, iv);
    309 
    310         List headers = new ArrayList(2);
    311 
    312         headers.add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
    313         headers.add(new PemHeader("DEK-Info", dekAlgName + "," + getHexEncoded(iv)));
    314 
    315         return new PemObject(type, headers, encData);
    316     }
    317 
    318     public PemObject generate()
    319         throws PemGenerationException
    320     {
    321         try
    322         {
    323             if (algorithm != null)
    324             {
    325                 return createPemObject(obj, algorithm, password, random);
    326             }
    327 
    328             return createPemObject(obj);
    329         }
    330         catch (IOException e)
    331         {
    332             throw new PemGenerationException("encoding exception: " + e.getMessage(), e);
    333         }
    334     }
    335 }
    336