Home | History | Annotate | Download | only in netscape
      1 package org.bouncycastle.jce.netscape;
      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.SecureRandom;
     13 import java.security.Signature;
     14 import java.security.SignatureException;
     15 import java.security.spec.InvalidKeySpecException;
     16 import java.security.spec.X509EncodedKeySpec;
     17 
     18 import org.bouncycastle.asn1.ASN1EncodableVector;
     19 import org.bouncycastle.asn1.ASN1Encoding;
     20 import org.bouncycastle.asn1.ASN1InputStream;
     21 import org.bouncycastle.asn1.ASN1Object;
     22 import org.bouncycastle.asn1.ASN1Primitive;
     23 import org.bouncycastle.asn1.ASN1Sequence;
     24 import org.bouncycastle.asn1.DERBitString;
     25 import org.bouncycastle.asn1.DERIA5String;
     26 import org.bouncycastle.asn1.DERSequence;
     27 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
     28 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
     29 
     30 /**
     31  *
     32  *
     33  * Handles NetScape certificate request (KEYGEN), these are constructed as:
     34  * <pre><code>
     35  *   SignedPublicKeyAndChallenge ::= SEQUENCE {
     36  *     publicKeyAndChallenge    PublicKeyAndChallenge,
     37  *     signatureAlgorithm       AlgorithmIdentifier,
     38  *     signature                BIT STRING
     39  *   }
     40  * </pre>
     41  *
     42  * PublicKey's encoded-format has to be X.509.
     43  *
     44  **/
     45 public class NetscapeCertRequest
     46     extends ASN1Object
     47 {
     48     AlgorithmIdentifier    sigAlg;
     49     AlgorithmIdentifier    keyAlg;
     50     byte        sigBits [];
     51     String challenge;
     52     DERBitString content;
     53     PublicKey pubkey ;
     54 
     55     private static ASN1Sequence getReq(
     56         byte[]  r)
     57         throws IOException
     58     {
     59         ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(r));
     60 
     61         return ASN1Sequence.getInstance(aIn.readObject());
     62     }
     63 
     64     public NetscapeCertRequest(
     65         byte[]  req)
     66         throws IOException
     67     {
     68         this(getReq(req));
     69     }
     70 
     71     public NetscapeCertRequest (ASN1Sequence spkac)
     72     {
     73         try
     74         {
     75 
     76             //
     77             // SignedPublicKeyAndChallenge ::= SEQUENCE {
     78             //    publicKeyAndChallenge    PublicKeyAndChallenge,
     79             //    signatureAlgorithm    AlgorithmIdentifier,
     80             //    signature        BIT STRING
     81             // }
     82             //
     83             if (spkac.size() != 3)
     84             {
     85                 throw new IllegalArgumentException("invalid SPKAC (size):"
     86                         + spkac.size());
     87             }
     88 
     89             sigAlg = AlgorithmIdentifier.getInstance(spkac.getObjectAt(1));
     90             sigBits = ((DERBitString)spkac.getObjectAt(2)).getOctets();
     91 
     92             //
     93             // PublicKeyAndChallenge ::= SEQUENCE {
     94             //    spki            SubjectPublicKeyInfo,
     95             //    challenge        IA5STRING
     96             // }
     97             //
     98             ASN1Sequence pkac = (ASN1Sequence)spkac.getObjectAt(0);
     99 
    100             if (pkac.size() != 2)
    101             {
    102                 throw new IllegalArgumentException("invalid PKAC (len): "
    103                         + pkac.size());
    104             }
    105 
    106             challenge = ((DERIA5String)pkac.getObjectAt(1)).getString();
    107 
    108             //this could be dangerous, as ASN.1 decoding/encoding
    109             //could potentially alter the bytes
    110             content = new DERBitString(pkac);
    111 
    112             SubjectPublicKeyInfo pubkeyinfo = SubjectPublicKeyInfo.getInstance(pkac.getObjectAt(0));
    113 
    114             X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(
    115                     pubkeyinfo).getBytes());
    116 
    117             keyAlg = pubkeyinfo.getAlgorithm();
    118             pubkey = KeyFactory.getInstance(keyAlg.getAlgorithm().getId(), "BC")
    119                     .generatePublic(xspec);
    120 
    121         }
    122         catch (Exception e)
    123         {
    124             throw new IllegalArgumentException(e.toString());
    125         }
    126     }
    127 
    128     public NetscapeCertRequest(
    129         String challenge,
    130         AlgorithmIdentifier signing_alg,
    131         PublicKey pub_key) throws NoSuchAlgorithmException,
    132             InvalidKeySpecException, NoSuchProviderException
    133     {
    134 
    135         this.challenge = challenge;
    136         sigAlg = signing_alg;
    137         pubkey = pub_key;
    138 
    139         ASN1EncodableVector content_der = new ASN1EncodableVector();
    140         content_der.add(getKeySpec());
    141         //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject()));
    142         content_der.add(new DERIA5String(challenge));
    143 
    144         try
    145         {
    146             content = new DERBitString(new DERSequence(content_der));
    147         }
    148         catch (IOException e)
    149         {
    150             throw new InvalidKeySpecException("exception encoding key: " + e.toString());
    151         }
    152     }
    153 
    154     public String getChallenge()
    155     {
    156         return challenge;
    157     }
    158 
    159     public void setChallenge(String value)
    160     {
    161         challenge = value;
    162     }
    163 
    164     public AlgorithmIdentifier getSigningAlgorithm()
    165     {
    166         return sigAlg;
    167     }
    168 
    169     public void setSigningAlgorithm(AlgorithmIdentifier value)
    170     {
    171         sigAlg = value;
    172     }
    173 
    174     public AlgorithmIdentifier getKeyAlgorithm()
    175     {
    176         return keyAlg;
    177     }
    178 
    179     public void setKeyAlgorithm(AlgorithmIdentifier value)
    180     {
    181         keyAlg = value;
    182     }
    183 
    184     public PublicKey getPublicKey()
    185     {
    186         return pubkey;
    187     }
    188 
    189     public void setPublicKey(PublicKey value)
    190     {
    191         pubkey = value;
    192     }
    193 
    194     public boolean verify(String challenge) throws NoSuchAlgorithmException,
    195             InvalidKeyException, SignatureException, NoSuchProviderException
    196     {
    197         if (!challenge.equals(this.challenge))
    198         {
    199             return false;
    200         }
    201 
    202         //
    203         // Verify the signature .. shows the response was generated
    204         // by someone who knew the associated private key
    205         //
    206         Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(),
    207                 "BC");
    208         sig.initVerify(pubkey);
    209         sig.update(content.getBytes());
    210 
    211         return sig.verify(sigBits);
    212     }
    213 
    214     public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException,
    215             InvalidKeyException, SignatureException, NoSuchProviderException,
    216             InvalidKeySpecException
    217     {
    218         sign(priv_key, null);
    219     }
    220 
    221     public void sign(PrivateKey priv_key, SecureRandom rand)
    222             throws NoSuchAlgorithmException, InvalidKeyException,
    223             SignatureException, NoSuchProviderException,
    224             InvalidKeySpecException
    225     {
    226         Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(),
    227                 "BC");
    228 
    229         if (rand != null)
    230         {
    231             sig.initSign(priv_key, rand);
    232         }
    233         else
    234         {
    235             sig.initSign(priv_key);
    236         }
    237 
    238         ASN1EncodableVector pkac = new ASN1EncodableVector();
    239 
    240         pkac.add(getKeySpec());
    241         pkac.add(new DERIA5String(challenge));
    242 
    243         try
    244         {
    245             sig.update(new DERSequence(pkac).getEncoded(ASN1Encoding.DER));
    246         }
    247         catch (IOException ioe)
    248         {
    249             throw new SignatureException(ioe.getMessage());
    250         }
    251 
    252         sigBits = sig.sign();
    253     }
    254 
    255     private ASN1Primitive getKeySpec() throws NoSuchAlgorithmException,
    256             InvalidKeySpecException, NoSuchProviderException
    257     {
    258         ByteArrayOutputStream baos = new ByteArrayOutputStream();
    259 
    260         ASN1Primitive obj = null;
    261         try
    262         {
    263 
    264             baos.write(pubkey.getEncoded());
    265             baos.close();
    266 
    267             ASN1InputStream derin = new ASN1InputStream(
    268                     new ByteArrayInputStream(baos.toByteArray()));
    269 
    270             obj = derin.readObject();
    271         }
    272         catch (IOException ioe)
    273         {
    274             throw new InvalidKeySpecException(ioe.getMessage());
    275         }
    276         return obj;
    277     }
    278 
    279     public ASN1Primitive toASN1Primitive()
    280     {
    281         ASN1EncodableVector spkac = new ASN1EncodableVector();
    282         ASN1EncodableVector pkac = new ASN1EncodableVector();
    283 
    284         try
    285         {
    286             pkac.add(getKeySpec());
    287         }
    288         catch (Exception e)
    289         {
    290             //ignore
    291         }
    292 
    293         pkac.add(new DERIA5String(challenge));
    294 
    295         spkac.add(new DERSequence(pkac));
    296         spkac.add(sigAlg);
    297         spkac.add(new DERBitString(sigBits));
    298 
    299         return new DERSequence(spkac);
    300     }
    301 }
    302