View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  
19  package org.apache.geronimo.util.jce;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.security.InvalidKeyException;
25  import java.security.KeyFactory;
26  import java.security.NoSuchAlgorithmException;
27  import java.security.NoSuchProviderException;
28  import java.security.PrivateKey;
29  import java.security.PublicKey;
30  import java.security.Signature;
31  import java.security.SignatureException;
32  import java.security.spec.InvalidKeySpecException;
33  import java.security.spec.X509EncodedKeySpec;
34  import java.util.Hashtable;
35  
36  import javax.security.auth.x500.X500Principal;
37  
38  import org.apache.geronimo.util.asn1.ASN1InputStream;
39  import org.apache.geronimo.util.asn1.ASN1Sequence;
40  import org.apache.geronimo.util.asn1.ASN1Set;
41  import org.apache.geronimo.util.asn1.DERBitString;
42  import org.apache.geronimo.util.asn1.DERObjectIdentifier;
43  import org.apache.geronimo.util.asn1.DEROutputStream;
44  import org.apache.geronimo.util.asn1.pkcs.PKCSObjectIdentifiers;
45  import org.apache.geronimo.util.asn1.pkcs.CertificationRequest;
46  import org.apache.geronimo.util.asn1.pkcs.CertificationRequestInfo;
47  import org.apache.geronimo.util.asn1.x509.AlgorithmIdentifier;
48  import org.apache.geronimo.util.asn1.x509.SubjectPublicKeyInfo;
49  import org.apache.geronimo.util.asn1.x509.X509Name;
50  import org.apache.geronimo.util.asn1.x9.X9ObjectIdentifiers;
51  
52  /**
53   * A class for verifying and creating PKCS10 Certification requests.
54   * <pre>
55   * CertificationRequest ::= SEQUENCE {
56   *   certificationRequestInfo  CertificationRequestInfo,
57   *   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
58   *   signature                 BIT STRING
59   * }
60   *
61   * CertificationRequestInfo ::= SEQUENCE {
62   *   version             INTEGER { v1(0) } (v1,...),
63   *   subject             Name,
64   *   subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
65   *   attributes          [0] Attributes{{ CRIAttributes }}
66   *  }
67   *
68   *  Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
69   *
70   *  Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
71   *    type    ATTRIBUTE.&id({IOSet}),
72   *    values  SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
73   *  }
74   * </pre>
75   */
76  public class PKCS10CertificationRequest
77      extends CertificationRequest
78  {
79      private static Hashtable            algorithms = new Hashtable();
80      private static Hashtable            oids = new Hashtable();
81  
82      static
83      {
84          algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
85          algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
86          algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.1"));
87          algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
88          algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
89          algorithms.put("RSAWITHMD5", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
90          algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
91          algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
92          algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
93          algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
94          algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
95          algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
96          algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
97          algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
98          algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
99          algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
100         algorithms.put("RSAWITHSHA1", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
101         algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
102         algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
103         algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
104         algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
105         algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
106         algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
107 
108         //
109         // reverse mappings
110         //
111         oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
112         oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
113         oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
114         oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
115         oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
116 
117         oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
118         oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
119         oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.1"), "MD5WIDHRSA");
120         oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "DSAWITHSHA1");
121         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "DSAWITHSHA1");
122     }
123 
124     private static ASN1Sequence toDERSequence(
125         byte[]  bytes)
126     {
127         try
128         {
129             ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
130             ASN1InputStream         dIn = new ASN1InputStream(bIn);
131 
132             return (ASN1Sequence)dIn.readObject();
133         }
134         catch (Exception e)
135         {
136             throw new IllegalArgumentException("badly encoded request");
137         }
138     }
139 
140     /**
141      * construct a PKCS10 certification request from a DER encoded
142      * byte stream.
143      */
144     public PKCS10CertificationRequest(
145         byte[]  bytes)
146     {
147         super(toDERSequence(bytes));
148     }
149 
150     public PKCS10CertificationRequest(
151         ASN1Sequence  sequence)
152     {
153         super(sequence);
154     }
155 
156     /**
157      * create a PKCS10 certfication request using the BC provider.
158      */
159     public PKCS10CertificationRequest(
160         String              signatureAlgorithm,
161         X509Name            subject,
162         PublicKey           key,
163         ASN1Set             attributes,
164         PrivateKey          signingKey)
165         throws NoSuchAlgorithmException, NoSuchProviderException,
166                 InvalidKeyException, SignatureException
167     {
168         this(signatureAlgorithm, subject, key, attributes, signingKey, null);
169     }
170 
171     private static X509Name convertName(
172         X500Principal	name)
173     {
174         try
175         {
176             return new X509Principal(name.getEncoded());
177         }
178         catch (IOException e)
179         {
180             throw new IllegalArgumentException("can't convert name");
181         }
182     }
183 
184     /**
185      * create a PKCS10 certfication request using the BC provider.
186      */
187     public PKCS10CertificationRequest(
188         String              signatureAlgorithm,
189         X500Principal       subject,
190         PublicKey           key,
191         ASN1Set             attributes,
192         PrivateKey          signingKey)
193         throws NoSuchAlgorithmException, NoSuchProviderException,
194                 InvalidKeyException, SignatureException
195     {
196         this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, null);
197     }
198 
199     /**
200      * create a PKCS10 certfication request using the named provider.
201      */
202     public PKCS10CertificationRequest(
203         String              signatureAlgorithm,
204         X500Principal       subject,
205         PublicKey           key,
206         ASN1Set             attributes,
207         PrivateKey          signingKey,
208         String              provider)
209         throws NoSuchAlgorithmException, NoSuchProviderException,
210                 InvalidKeyException, SignatureException
211     {
212         this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, provider);
213     }
214 
215     /**
216      * create a PKCS10 certfication request using the named provider.
217      */
218     public PKCS10CertificationRequest(
219         String              signatureAlgorithm,
220         X509Name            subject,
221         PublicKey           key,
222         ASN1Set             attributes,
223         PrivateKey          signingKey,
224         String              provider)
225         throws NoSuchAlgorithmException, NoSuchProviderException,
226                 InvalidKeyException, SignatureException
227     {
228         DERObjectIdentifier sigOID = (DERObjectIdentifier)algorithms.get(signatureAlgorithm.toUpperCase());
229 
230         if (sigOID == null)
231         {
232             throw new IllegalArgumentException("Unknown signature type requested");
233         }
234 
235         if (subject == null)
236         {
237             throw new IllegalArgumentException("subject must not be null");
238         }
239 
240         if (key == null)
241         {
242             throw new IllegalArgumentException("public key must not be null");
243         }
244 
245         this.sigAlgId = new AlgorithmIdentifier(sigOID, null);
246 
247         byte[]                  bytes = key.getEncoded();
248         ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
249         ASN1InputStream         dIn = new ASN1InputStream(bIn);
250 
251         try
252         {
253             this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo((ASN1Sequence)dIn.readObject()), attributes);
254         }
255         catch (IOException e)
256         {
257             throw new IllegalArgumentException("can't encode public key");
258         }
259 
260         Signature sig = null;
261 
262         try
263         {
264             if (provider == null) {
265                 sig = Signature.getInstance(sigAlgId.getObjectId().getId());
266             }
267             else {
268                 sig = Signature.getInstance(sigAlgId.getObjectId().getId(), provider);
269             }
270         }
271         catch (NoSuchAlgorithmException e)
272         {
273             if (provider == null) {
274                 sig = Signature.getInstance(signatureAlgorithm);
275             }
276             else {
277                 sig = Signature.getInstance(signatureAlgorithm, provider);
278             }
279         }
280 
281         sig.initSign(signingKey);
282 
283         try
284         {
285             ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
286             DEROutputStream         dOut = new DEROutputStream(bOut);
287 
288             dOut.writeObject(reqInfo);
289 
290             sig.update(bOut.toByteArray());
291         }
292         catch (Exception e)
293         {
294             throw new SecurityException("exception encoding TBS cert request - " + e);
295         }
296 
297         this.sigBits = new DERBitString(sig.sign());
298     }
299 
300     /**
301      * return the public key associated with the certification request -
302      * the public key is created using the BC provider.
303      */
304     public PublicKey getPublicKey()
305         throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException
306     {
307         return getPublicKey(null);
308     }
309 
310     public PublicKey getPublicKey(
311         String  provider)
312         throws NoSuchAlgorithmException, NoSuchProviderException,
313                 InvalidKeyException
314     {
315         SubjectPublicKeyInfo    subjectPKInfo = reqInfo.getSubjectPublicKeyInfo();
316 
317         try
318         {
319             X509EncodedKeySpec      xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getBytes());
320             AlgorithmIdentifier     keyAlg = subjectPKInfo.getAlgorithmId ();
321             try {
322 
323                 if (provider == null) {
324                     return KeyFactory.getInstance(keyAlg.getObjectId().getId ()).generatePublic(xspec);
325                 }
326                 else {
327                     return KeyFactory.getInstance(keyAlg.getObjectId().getId (), provider).generatePublic(xspec);
328                 }
329 
330             } catch (NoSuchAlgorithmException e) {
331                 // if we can't resolve this via the OID, just as for the RSA algorithm.  This is all
332                 // Geronimo requires anyway.
333                 if (provider == null) {
334                     return KeyFactory.getInstance("RSA").generatePublic(xspec);
335                 }
336                 else {
337                     return KeyFactory.getInstance("RSA", provider).generatePublic(xspec);
338                 }
339             }
340         }
341         catch (InvalidKeySpecException e)
342         {
343             throw new InvalidKeyException("error decoding public key");
344         }
345     }
346 
347     /**
348      * verify the request using the BC provider.
349      */
350     public boolean verify()
351         throws NoSuchAlgorithmException, NoSuchProviderException,
352                 InvalidKeyException, SignatureException
353     {
354         return verify(null);
355     }
356 
357     public boolean verify(
358         String provider)
359         throws NoSuchAlgorithmException, NoSuchProviderException,
360                 InvalidKeyException, SignatureException
361     {
362         Signature   sig = null;
363 
364         try
365         {
366             if (provider == null) {
367                 sig = Signature.getInstance(sigAlgId.getObjectId().getId());
368             }
369             else {
370                 sig = Signature.getInstance(sigAlgId.getObjectId().getId(), provider);
371             }
372         }
373         catch (NoSuchAlgorithmException e)
374         {
375             //
376             // try an alternate
377             //
378             if (oids.get(sigAlgId.getObjectId().getId()) != null)
379             {
380                 String  signatureAlgorithm = (String)oids.get(sigAlgId.getObjectId().getId());
381 
382                 if (provider == null) {
383                     sig = Signature.getInstance(signatureAlgorithm);
384                 }
385                 else {
386                     sig = Signature.getInstance(signatureAlgorithm, provider);
387                 }
388             }
389         }
390 
391         sig.initVerify(this.getPublicKey(provider));
392 
393         try
394         {
395             ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
396             DEROutputStream         dOut = new DEROutputStream(bOut);
397 
398             dOut.writeObject(reqInfo);
399 
400             sig.update(bOut.toByteArray());
401         }
402         catch (Exception e)
403         {
404             throw new SecurityException("exception encoding TBS cert request - " + e);
405         }
406 
407         return sig.verify(sigBits.getBytes());
408     }
409 
410     /**
411      * return a DER encoded byte array representing this object
412      */
413     public byte[] getEncoded()
414     {
415         ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
416         DEROutputStream         dOut = new DEROutputStream(bOut);
417 
418         try
419         {
420             dOut.writeObject(this);
421         }
422         catch (IOException e)
423         {
424             throw new RuntimeException(e.toString());
425         }
426 
427         return bOut.toByteArray();
428     }
429 }