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
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
332
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
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 }