NetscapeCertRequest.java revision e1142c149e244797ce73b0e7fad40816e447a817
1package org.bouncycastle.jce.netscape;
2
3import java.io.ByteArrayInputStream;
4import java.io.ByteArrayOutputStream;
5import java.io.IOException;
6import java.security.InvalidKeyException;
7import java.security.KeyFactory;
8import java.security.NoSuchAlgorithmException;
9import java.security.NoSuchProviderException;
10import java.security.PrivateKey;
11import java.security.PublicKey;
12import java.security.SecureRandom;
13import java.security.Signature;
14import java.security.SignatureException;
15import java.security.spec.InvalidKeySpecException;
16import java.security.spec.X509EncodedKeySpec;
17
18import org.bouncycastle.asn1.ASN1EncodableVector;
19import org.bouncycastle.asn1.ASN1Encoding;
20import org.bouncycastle.asn1.ASN1InputStream;
21import org.bouncycastle.asn1.ASN1Object;
22import org.bouncycastle.asn1.ASN1Primitive;
23import org.bouncycastle.asn1.ASN1Sequence;
24import org.bouncycastle.asn1.DERBitString;
25import org.bouncycastle.asn1.DERIA5String;
26import org.bouncycastle.asn1.DERSequence;
27import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
28import 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 **/
45public 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 = 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        try
147        {
148            content = new DERBitString(new DERSequence(content_der));
149        }
150        catch (IOException e)
151        {
152            throw new InvalidKeySpecException("exception encoding key: " + e.toString());
153        }
154    }
155
156    public String getChallenge()
157    {
158        return challenge;
159    }
160
161    public void setChallenge(String value)
162    {
163        challenge = value;
164    }
165
166    public AlgorithmIdentifier getSigningAlgorithm()
167    {
168        return sigAlg;
169    }
170
171    public void setSigningAlgorithm(AlgorithmIdentifier value)
172    {
173        sigAlg = value;
174    }
175
176    public AlgorithmIdentifier getKeyAlgorithm()
177    {
178        return keyAlg;
179    }
180
181    public void setKeyAlgorithm(AlgorithmIdentifier value)
182    {
183        keyAlg = value;
184    }
185
186    public PublicKey getPublicKey()
187    {
188        return pubkey;
189    }
190
191    public void setPublicKey(PublicKey value)
192    {
193        pubkey = value;
194    }
195
196    public boolean verify(String challenge) throws NoSuchAlgorithmException,
197            InvalidKeyException, SignatureException, NoSuchProviderException
198    {
199        if (!challenge.equals(this.challenge))
200        {
201            return false;
202        }
203
204        //
205        // Verify the signature .. shows the response was generated
206        // by someone who knew the associated private key
207        //
208        Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(),
209                "BC");
210        sig.initVerify(pubkey);
211        sig.update(content.getBytes());
212
213        return sig.verify(sigBits);
214    }
215
216    public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException,
217            InvalidKeyException, SignatureException, NoSuchProviderException,
218            InvalidKeySpecException
219    {
220        sign(priv_key, null);
221    }
222
223    public void sign(PrivateKey priv_key, SecureRandom rand)
224            throws NoSuchAlgorithmException, InvalidKeyException,
225            SignatureException, NoSuchProviderException,
226            InvalidKeySpecException
227    {
228        Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(),
229                "BC");
230
231        if (rand != null)
232        {
233            sig.initSign(priv_key, rand);
234        }
235        else
236        {
237            sig.initSign(priv_key);
238        }
239
240        ASN1EncodableVector pkac = new ASN1EncodableVector();
241
242        pkac.add(getKeySpec());
243        pkac.add(new DERIA5String(challenge));
244
245        try
246        {
247            sig.update(new DERSequence(pkac).getEncoded(ASN1Encoding.DER));
248        }
249        catch (IOException ioe)
250        {
251            throw new SignatureException(ioe.getMessage());
252        }
253
254        sigBits = sig.sign();
255    }
256
257    private ASN1Primitive getKeySpec() throws NoSuchAlgorithmException,
258            InvalidKeySpecException, NoSuchProviderException
259    {
260        ByteArrayOutputStream baos = new ByteArrayOutputStream();
261
262        ASN1Primitive obj = null;
263        try
264        {
265
266            baos.write(pubkey.getEncoded());
267            baos.close();
268
269            ASN1InputStream derin = new ASN1InputStream(
270                    new ByteArrayInputStream(baos.toByteArray()));
271
272            obj = derin.readObject();
273        }
274        catch (IOException ioe)
275        {
276            throw new InvalidKeySpecException(ioe.getMessage());
277        }
278        return obj;
279    }
280
281    public ASN1Primitive toASN1Primitive()
282    {
283        ASN1EncodableVector spkac = new ASN1EncodableVector();
284        ASN1EncodableVector pkac = new ASN1EncodableVector();
285
286        try
287        {
288            pkac.add(getKeySpec());
289        }
290        catch (Exception e)
291        {
292            //ignore
293        }
294
295        pkac.add(new DERIA5String(challenge));
296
297        spkac.add(new DERSequence(pkac));
298        spkac.add(sigAlg);
299        spkac.add(new DERBitString(sigBits));
300
301        return new DERSequence(spkac);
302    }
303}
304