Home | History | Annotate | Download | only in jce
      1 package org.bouncycastle.jce;
      2 
      3 import java.io.ByteArrayInputStream;
      4 import java.io.ByteArrayOutputStream;
      5 import java.io.IOException;
      6 import java.security.InvalidKeyException;
      7 import java.security.KeyFactory;
      8 import java.security.NoSuchAlgorithmException;
      9 import java.security.NoSuchProviderException;
     10 import java.security.PrivateKey;
     11 import java.security.PublicKey;
     12 import java.security.Signature;
     13 import java.security.SignatureException;
     14 import java.security.spec.InvalidKeySpecException;
     15 import java.security.spec.X509EncodedKeySpec;
     16 import java.util.Set;
     17 import java.util.HashSet;
     18 import java.util.Hashtable;
     19 
     20 import javax.security.auth.x500.X500Principal;
     21 
     22 import org.bouncycastle.asn1.ASN1InputStream;
     23 import org.bouncycastle.asn1.ASN1Sequence;
     24 import org.bouncycastle.asn1.ASN1Set;
     25 import org.bouncycastle.asn1.DERBitString;
     26 import org.bouncycastle.asn1.DERObjectIdentifier;
     27 import org.bouncycastle.asn1.DEROutputStream;
     28 import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
     29 import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
     30 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
     31 import org.bouncycastle.asn1.pkcs.CertificationRequest;
     32 import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
     33 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
     34 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
     35 import org.bouncycastle.asn1.x509.X509Name;
     36 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
     37 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
     38 import org.bouncycastle.util.Strings;
     39 
     40 /**
     41  * A class for verifying and creating PKCS10 Certification requests.
     42  * <pre>
     43  * CertificationRequest ::= SEQUENCE {
     44  *   certificationRequestInfo  CertificationRequestInfo,
     45  *   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
     46  *   signature                 BIT STRING
     47  * }
     48  *
     49  * CertificationRequestInfo ::= SEQUENCE {
     50  *   version             INTEGER { v1(0) } (v1,...),
     51  *   subject             Name,
     52  *   subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
     53  *   attributes          [0] Attributes{{ CRIAttributes }}
     54  *  }
     55  *
     56  *  Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
     57  *
     58  *  Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
     59  *    type    ATTRIBUTE.&id({IOSet}),
     60  *    values  SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
     61  *  }
     62  * </pre>
     63  */
     64 public class PKCS10CertificationRequest
     65     extends CertificationRequest
     66 {
     67     private static Hashtable            algorithms = new Hashtable();
     68     private static Hashtable            keyAlgorithms = new Hashtable();
     69     private static Hashtable            oids = new Hashtable();
     70     private static Set                  noParams = new HashSet();
     71 
     72     static
     73     {
     74         // BEGIN android-removed
     75         // Dropping MD2
     76         // algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
     77         // algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
     78         // END android-removed
     79         algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
     80         algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
     81         algorithms.put("RSAWITHMD5", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
     82         algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
     83         algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
     84         algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
     85         algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
     86         algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
     87         algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
     88         algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
     89         algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
     90         algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
     91         algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
     92         algorithms.put("RSAWITHSHA1", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
     93         algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
     94         algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
     95         algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
     96         algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
     97         algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
     98         algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
     99         algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
    100         algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
    101         algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
    102         algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
    103         algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
    104         algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
    105         algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
    106         algorithms.put("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
    107         algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
    108         //algorithms.put("ECGOST3410WITHGOST3411", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
    109 
    110         //
    111         // reverse mappings
    112         //
    113         oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
    114         oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
    115         oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
    116         oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
    117         oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
    118         oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
    119         //oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
    120 
    121         oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
    122         // BEGIN android-removed
    123         // Dropping MD2
    124         // oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
    125         // END android-removed
    126         oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
    127         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
    128         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
    129         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
    130         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
    131         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
    132         oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
    133         oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
    134         oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
    135         oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
    136 
    137         //
    138         // key types
    139         //
    140         keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
    141         keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA");
    142 
    143         //
    144         // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
    145         // The parameters field SHALL be NULL for RSA based signature algorithms.
    146         //
    147         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
    148         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
    149         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
    150         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
    151         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
    152         noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
    153         noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
    154         noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
    155     }
    156 
    157     private static ASN1Sequence toDERSequence(
    158         byte[]  bytes)
    159     {
    160         try
    161         {
    162             ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
    163             ASN1InputStream         dIn = new ASN1InputStream(bIn);
    164 
    165             return (ASN1Sequence)dIn.readObject();
    166         }
    167         catch (Exception e)
    168         {
    169             throw new IllegalArgumentException("badly encoded request");
    170         }
    171     }
    172 
    173     /**
    174      * construct a PKCS10 certification request from a DER encoded
    175      * byte stream.
    176      */
    177     public PKCS10CertificationRequest(
    178         byte[]  bytes)
    179     {
    180         super(toDERSequence(bytes));
    181     }
    182 
    183     public PKCS10CertificationRequest(
    184         ASN1Sequence  sequence)
    185     {
    186         super(sequence);
    187     }
    188 
    189     /**
    190      * create a PKCS10 certfication request using the BC provider.
    191      */
    192     public PKCS10CertificationRequest(
    193         String              signatureAlgorithm,
    194         X509Name            subject,
    195         PublicKey           key,
    196         ASN1Set             attributes,
    197         PrivateKey          signingKey)
    198         throws NoSuchAlgorithmException, NoSuchProviderException,
    199                 InvalidKeyException, SignatureException
    200     {
    201         this(signatureAlgorithm, subject, key, attributes, signingKey, "BC");
    202     }
    203 
    204     private static X509Name convertName(
    205         X500Principal    name)
    206     {
    207         try
    208         {
    209             return new X509Principal(name.getEncoded());
    210         }
    211         catch (IOException e)
    212         {
    213             throw new IllegalArgumentException("can't convert name");
    214         }
    215     }
    216 
    217     /**
    218      * create a PKCS10 certfication request using the BC provider.
    219      */
    220     public PKCS10CertificationRequest(
    221         String              signatureAlgorithm,
    222         X500Principal       subject,
    223         PublicKey           key,
    224         ASN1Set             attributes,
    225         PrivateKey          signingKey)
    226         throws NoSuchAlgorithmException, NoSuchProviderException,
    227                 InvalidKeyException, SignatureException
    228     {
    229         this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, "BC");
    230     }
    231 
    232     /**
    233      * create a PKCS10 certfication request using the named provider.
    234      */
    235     public PKCS10CertificationRequest(
    236         String              signatureAlgorithm,
    237         X500Principal       subject,
    238         PublicKey           key,
    239         ASN1Set             attributes,
    240         PrivateKey          signingKey,
    241         String              provider)
    242         throws NoSuchAlgorithmException, NoSuchProviderException,
    243                 InvalidKeyException, SignatureException
    244     {
    245         this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, provider);
    246     }
    247 
    248     /**
    249      * create a PKCS10 certfication request using the named provider.
    250      */
    251     public PKCS10CertificationRequest(
    252         String              signatureAlgorithm,
    253         X509Name            subject,
    254         PublicKey           key,
    255         ASN1Set             attributes,
    256         PrivateKey          signingKey,
    257         String              provider)
    258         throws NoSuchAlgorithmException, NoSuchProviderException,
    259                 InvalidKeyException, SignatureException
    260     {
    261         DERObjectIdentifier sigOID = (DERObjectIdentifier)algorithms.get(Strings.toUpperCase(signatureAlgorithm));
    262 
    263         if (sigOID == null)
    264         {
    265             throw new IllegalArgumentException("Unknown signature type requested");
    266         }
    267 
    268         if (subject == null)
    269         {
    270             throw new IllegalArgumentException("subject must not be null");
    271         }
    272 
    273         if (key == null)
    274         {
    275             throw new IllegalArgumentException("public key must not be null");
    276         }
    277 
    278         if (noParams.contains(sigOID))
    279         {
    280             this.sigAlgId = new AlgorithmIdentifier(sigOID);
    281         }
    282         else
    283         {
    284             this.sigAlgId = new AlgorithmIdentifier(sigOID, null);
    285         }
    286 
    287         byte[]                  bytes = key.getEncoded();
    288         ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
    289         ASN1InputStream         dIn = new ASN1InputStream(bIn);
    290 
    291         try
    292         {
    293             this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo((ASN1Sequence)dIn.readObject()), attributes);
    294         }
    295         catch (IOException e)
    296         {
    297             throw new IllegalArgumentException("can't encode public key");
    298         }
    299 
    300         Signature sig = null;
    301 
    302         try
    303         {
    304             sig = Signature.getInstance(sigAlgId.getObjectId().getId(), provider);
    305         }
    306         catch (NoSuchAlgorithmException e)
    307         {
    308             sig = Signature.getInstance(signatureAlgorithm, provider);
    309         }
    310 
    311         sig.initSign(signingKey);
    312 
    313         try
    314         {
    315             ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
    316             DEROutputStream         dOut = new DEROutputStream(bOut);
    317 
    318             dOut.writeObject(reqInfo);
    319 
    320             sig.update(bOut.toByteArray());
    321         }
    322         catch (Exception e)
    323         {
    324             throw new SecurityException("exception encoding TBS cert request - " + e);
    325         }
    326 
    327         this.sigBits = new DERBitString(sig.sign());
    328     }
    329 
    330     /**
    331      * return the public key associated with the certification request -
    332      * the public key is created using the BC provider.
    333      */
    334     public PublicKey getPublicKey()
    335         throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException
    336     {
    337         return getPublicKey("BC");
    338     }
    339 
    340     public PublicKey getPublicKey(
    341         String  provider)
    342         throws NoSuchAlgorithmException, NoSuchProviderException,
    343                 InvalidKeyException
    344     {
    345         SubjectPublicKeyInfo    subjectPKInfo = reqInfo.getSubjectPublicKeyInfo();
    346         X509EncodedKeySpec      xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getBytes());
    347         AlgorithmIdentifier     keyAlg = subjectPKInfo.getAlgorithmId();
    348 
    349         try
    350         {
    351             try
    352             {
    353                 return KeyFactory.getInstance(keyAlg.getObjectId().getId(), provider).generatePublic(xspec);
    354             }
    355             catch (NoSuchAlgorithmException e)
    356             {
    357                 //
    358                 // try an alternate
    359                 //
    360                 if (keyAlgorithms.get(keyAlg.getObjectId()) != null)
    361                 {
    362                     String  keyAlgorithm = (String)keyAlgorithms.get(keyAlg.getObjectId());
    363 
    364                     return KeyFactory.getInstance(keyAlgorithm, provider).generatePublic(xspec);
    365                 }
    366 
    367                 throw e;
    368             }
    369         }
    370         catch (InvalidKeySpecException e)
    371         {
    372             throw new InvalidKeyException("error decoding public key");
    373         }
    374     }
    375 
    376     /**
    377      * verify the request using the BC provider.
    378      */
    379     public boolean verify()
    380         throws NoSuchAlgorithmException, NoSuchProviderException,
    381                 InvalidKeyException, SignatureException
    382     {
    383         return verify("BC");
    384     }
    385 
    386     public boolean verify(
    387         String provider)
    388         throws NoSuchAlgorithmException, NoSuchProviderException,
    389                 InvalidKeyException, SignatureException
    390     {
    391         Signature   sig = null;
    392 
    393         try
    394         {
    395             sig = Signature.getInstance(sigAlgId.getObjectId().getId(), provider);
    396         }
    397         catch (NoSuchAlgorithmException e)
    398         {
    399             //
    400             // try an alternate
    401             //
    402             if (oids.get(sigAlgId.getObjectId()) != null)
    403             {
    404                 String  signatureAlgorithm = (String)oids.get(sigAlgId.getObjectId());
    405 
    406                 sig = Signature.getInstance(signatureAlgorithm, provider);
    407             }
    408             else
    409             {
    410                 throw e;
    411             }
    412         }
    413 
    414         sig.initVerify(this.getPublicKey(provider));
    415 
    416         try
    417         {
    418             ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
    419             DEROutputStream         dOut = new DEROutputStream(bOut);
    420 
    421             dOut.writeObject(reqInfo);
    422 
    423             sig.update(bOut.toByteArray());
    424         }
    425         catch (Exception e)
    426         {
    427             throw new SecurityException("exception encoding TBS cert request - " + e);
    428         }
    429 
    430         return sig.verify(sigBits.getBytes());
    431     }
    432 
    433     /**
    434      * return a DER encoded byte array representing this object
    435      */
    436     public byte[] getEncoded()
    437     {
    438         ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
    439         DEROutputStream         dOut = new DEROutputStream(bOut);
    440 
    441         try
    442         {
    443             dOut.writeObject(this);
    444         }
    445         catch (IOException e)
    446         {
    447             throw new RuntimeException(e.toString());
    448         }
    449 
    450         return bOut.toByteArray();
    451     }
    452 }
    453