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.ASN1Encodable;
     19 import org.bouncycastle.asn1.ASN1EncodableVector;
     20 import org.bouncycastle.asn1.ASN1InputStream;
     21 import org.bouncycastle.asn1.ASN1Sequence;
     22 import org.bouncycastle.asn1.DERBitString;
     23 import org.bouncycastle.asn1.DERIA5String;
     24 import org.bouncycastle.asn1.DERObject;
     25 import org.bouncycastle.asn1.DEROutputStream;
     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 ASN1Encodable
     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 = new AlgorithmIdentifier((ASN1Sequence)spkac
     90                     .getObjectAt(1));
     91             sigBits = ((DERBitString)spkac.getObjectAt(2)).getBytes();
     92 
     93             //
     94             // PublicKeyAndChallenge ::= SEQUENCE {
     95             //    spki            SubjectPublicKeyInfo,
     96             //    challenge        IA5STRING
     97             // }
     98             //
     99             ASN1Sequence pkac = (ASN1Sequence)spkac.getObjectAt(0);
    100 
    101             if (pkac.size() != 2)
    102             {
    103                 throw new IllegalArgumentException("invalid PKAC (len): "
    104                         + pkac.size());
    105             }
    106 
    107             challenge = ((DERIA5String)pkac.getObjectAt(1)).getString();
    108 
    109             //this could be dangerous, as ASN.1 decoding/encoding
    110             //could potentially alter the bytes
    111             content = new DERBitString(pkac);
    112 
    113             SubjectPublicKeyInfo pubkeyinfo = new SubjectPublicKeyInfo(
    114                     (ASN1Sequence)pkac.getObjectAt(0));
    115 
    116             X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(
    117                     pubkeyinfo).getBytes());
    118 
    119             keyAlg = pubkeyinfo.getAlgorithmId();
    120             pubkey = KeyFactory.getInstance(keyAlg.getObjectId().getId(), "BC")
    121                     .generatePublic(xspec);
    122 
    123         }
    124         catch (Exception e)
    125         {
    126             throw new IllegalArgumentException(e.toString());
    127         }
    128     }
    129 
    130     public NetscapeCertRequest(
    131         String challenge,
    132         AlgorithmIdentifier signing_alg,
    133         PublicKey pub_key) throws NoSuchAlgorithmException,
    134             InvalidKeySpecException, NoSuchProviderException
    135     {
    136 
    137         this.challenge = challenge;
    138         sigAlg = signing_alg;
    139         pubkey = pub_key;
    140 
    141         ASN1EncodableVector content_der = new ASN1EncodableVector();
    142         content_der.add(getKeySpec());
    143         //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject()));
    144         content_der.add(new DERIA5String(challenge));
    145 
    146         content = new DERBitString(new DERSequence(content_der));
    147     }
    148 
    149     public String getChallenge()
    150     {
    151         return challenge;
    152     }
    153 
    154     public void setChallenge(String value)
    155     {
    156         challenge = value;
    157     }
    158 
    159     public AlgorithmIdentifier getSigningAlgorithm()
    160     {
    161         return sigAlg;
    162     }
    163 
    164     public void setSigningAlgorithm(AlgorithmIdentifier value)
    165     {
    166         sigAlg = value;
    167     }
    168 
    169     public AlgorithmIdentifier getKeyAlgorithm()
    170     {
    171         return keyAlg;
    172     }
    173 
    174     public void setKeyAlgorithm(AlgorithmIdentifier value)
    175     {
    176         keyAlg = value;
    177     }
    178 
    179     public PublicKey getPublicKey()
    180     {
    181         return pubkey;
    182     }
    183 
    184     public void setPublicKey(PublicKey value)
    185     {
    186         pubkey = value;
    187     }
    188 
    189     public boolean verify(String challenge) throws NoSuchAlgorithmException,
    190             InvalidKeyException, SignatureException, NoSuchProviderException
    191     {
    192         if (!challenge.equals(this.challenge))
    193         {
    194             return false;
    195         }
    196 
    197         //
    198         // Verify the signature .. shows the response was generated
    199         // by someone who knew the associated private key
    200         //
    201         Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(),
    202                 "BC");
    203         sig.initVerify(pubkey);
    204         sig.update(content.getBytes());
    205 
    206         return sig.verify(sigBits);
    207     }
    208 
    209     public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException,
    210             InvalidKeyException, SignatureException, NoSuchProviderException,
    211             InvalidKeySpecException
    212     {
    213         sign(priv_key, null);
    214     }
    215 
    216     public void sign(PrivateKey priv_key, SecureRandom rand)
    217             throws NoSuchAlgorithmException, InvalidKeyException,
    218             SignatureException, NoSuchProviderException,
    219             InvalidKeySpecException
    220     {
    221         Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(),
    222                 "BC");
    223 
    224         if (rand != null)
    225         {
    226             sig.initSign(priv_key, rand);
    227         }
    228         else
    229         {
    230             sig.initSign(priv_key);
    231         }
    232 
    233         ASN1EncodableVector pkac = new ASN1EncodableVector();
    234 
    235         pkac.add(getKeySpec());
    236         pkac.add(new DERIA5String(challenge));
    237 
    238         try
    239         {
    240             sig.update(new DERSequence(pkac).getEncoded(ASN1Encodable.DER));
    241         }
    242         catch (IOException ioe)
    243         {
    244             throw new SignatureException(ioe.getMessage());
    245         }
    246 
    247         sigBits = sig.sign();
    248     }
    249 
    250     private DERObject getKeySpec() throws NoSuchAlgorithmException,
    251             InvalidKeySpecException, NoSuchProviderException
    252     {
    253         ByteArrayOutputStream baos = new ByteArrayOutputStream();
    254 
    255         DERObject obj = null;
    256         try
    257         {
    258 
    259             baos.write(pubkey.getEncoded());
    260             baos.close();
    261 
    262             ASN1InputStream derin = new ASN1InputStream(
    263                     new ByteArrayInputStream(baos.toByteArray()));
    264 
    265             obj = derin.readObject();
    266         }
    267         catch (IOException ioe)
    268         {
    269             throw new InvalidKeySpecException(ioe.getMessage());
    270         }
    271         return obj;
    272     }
    273 
    274     public DERObject toASN1Object()
    275     {
    276         ASN1EncodableVector spkac = new ASN1EncodableVector();
    277         ASN1EncodableVector pkac = new ASN1EncodableVector();
    278 
    279         try
    280         {
    281             pkac.add(getKeySpec());
    282         }
    283         catch (Exception e)
    284         {
    285             //ignore
    286         }
    287 
    288         pkac.add(new DERIA5String(challenge));
    289 
    290         spkac.add(new DERSequence(pkac));
    291         spkac.add(sigAlg);
    292         spkac.add(new DERBitString(sigBits));
    293 
    294         return new DERSequence(spkac);
    295     }
    296 }
    297