001 /**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package org.apache.geronimo.util.jce;
020
021 import java.io.ByteArrayInputStream;
022 import java.io.ByteArrayOutputStream;
023 import java.io.IOException;
024 import java.security.InvalidKeyException;
025 import java.security.KeyFactory;
026 import java.security.NoSuchAlgorithmException;
027 import java.security.NoSuchProviderException;
028 import java.security.PrivateKey;
029 import java.security.PublicKey;
030 import java.security.Signature;
031 import java.security.SignatureException;
032 import java.security.spec.InvalidKeySpecException;
033 import java.security.spec.X509EncodedKeySpec;
034 import java.util.Hashtable;
035
036 import javax.security.auth.x500.X500Principal;
037
038 import org.apache.geronimo.util.asn1.ASN1InputStream;
039 import org.apache.geronimo.util.asn1.ASN1Sequence;
040 import org.apache.geronimo.util.asn1.ASN1Set;
041 import org.apache.geronimo.util.asn1.DERBitString;
042 import org.apache.geronimo.util.asn1.DERObjectIdentifier;
043 import org.apache.geronimo.util.asn1.DEROutputStream;
044 import org.apache.geronimo.util.asn1.pkcs.PKCSObjectIdentifiers;
045 import org.apache.geronimo.util.asn1.pkcs.CertificationRequest;
046 import org.apache.geronimo.util.asn1.pkcs.CertificationRequestInfo;
047 import org.apache.geronimo.util.asn1.x509.AlgorithmIdentifier;
048 import org.apache.geronimo.util.asn1.x509.SubjectPublicKeyInfo;
049 import org.apache.geronimo.util.asn1.x509.X509Name;
050 import org.apache.geronimo.util.asn1.x9.X9ObjectIdentifiers;
051
052 /**
053 * A class for verifying and creating PKCS10 Certification requests.
054 * <pre>
055 * CertificationRequest ::= SEQUENCE {
056 * certificationRequestInfo CertificationRequestInfo,
057 * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
058 * signature BIT STRING
059 * }
060 *
061 * CertificationRequestInfo ::= SEQUENCE {
062 * version INTEGER { v1(0) } (v1,...),
063 * subject Name,
064 * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
065 * attributes [0] Attributes{{ CRIAttributes }}
066 * }
067 *
068 * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
069 *
070 * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
071 * type ATTRIBUTE.&id({IOSet}),
072 * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
073 * }
074 * </pre>
075 */
076 public class PKCS10CertificationRequest
077 extends CertificationRequest
078 {
079 private static Hashtable algorithms = new Hashtable();
080 private static Hashtable oids = new Hashtable();
081
082 static
083 {
084 algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
085 algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
086 algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.1"));
087 algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
088 algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
089 algorithms.put("RSAWITHMD5", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
090 algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
091 algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
092 algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
093 algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
094 algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
095 algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
096 algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
097 algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
098 algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
099 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 }