001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.util.jce;
019
020 import java.io.ByteArrayInputStream;
021 import java.io.ByteArrayOutputStream;
022 import java.io.IOException;
023 import java.security.InvalidKeyException;
024 import java.security.KeyFactory;
025 import java.security.NoSuchAlgorithmException;
026 import java.security.NoSuchProviderException;
027 import java.security.PrivateKey;
028 import java.security.PublicKey;
029 import java.security.Signature;
030 import java.security.SignatureException;
031 import java.security.spec.InvalidKeySpecException;
032 import java.security.spec.X509EncodedKeySpec;
033 import java.util.Hashtable;
034
035 import javax.security.auth.x500.X500Principal;
036
037 import org.apache.geronimo.util.asn1.ASN1InputStream;
038 import org.apache.geronimo.util.asn1.ASN1Sequence;
039 import org.apache.geronimo.util.asn1.ASN1Set;
040 import org.apache.geronimo.util.asn1.DERBitString;
041 import org.apache.geronimo.util.asn1.DERObjectIdentifier;
042 import org.apache.geronimo.util.asn1.DEROutputStream;
043 import org.apache.geronimo.util.asn1.pkcs.PKCSObjectIdentifiers;
044 import org.apache.geronimo.util.asn1.pkcs.CertificationRequest;
045 import org.apache.geronimo.util.asn1.pkcs.CertificationRequestInfo;
046 import org.apache.geronimo.util.asn1.x509.AlgorithmIdentifier;
047 import org.apache.geronimo.util.asn1.x509.SubjectPublicKeyInfo;
048 import org.apache.geronimo.util.asn1.x509.X509Name;
049 import org.apache.geronimo.util.asn1.x9.X9ObjectIdentifiers;
050
051 /**
052 * A class for verifying and creating PKCS10 Certification requests.
053 * <pre>
054 * CertificationRequest ::= SEQUENCE {
055 * certificationRequestInfo CertificationRequestInfo,
056 * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
057 * signature BIT STRING
058 * }
059 *
060 * CertificationRequestInfo ::= SEQUENCE {
061 * version INTEGER { v1(0) } (v1,...),
062 * subject Name,
063 * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
064 * attributes [0] Attributes{{ CRIAttributes }}
065 * }
066 *
067 * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
068 *
069 * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
070 * type ATTRIBUTE.&id({IOSet}),
071 * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
072 * }
073 * </pre>
074 */
075 public class PKCS10CertificationRequest
076 extends CertificationRequest
077 {
078 private static Hashtable algorithms = new Hashtable();
079 private static Hashtable oids = new Hashtable();
080
081 static
082 {
083 algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
084 algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
085 algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.1"));
086 algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
087 algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
088 algorithms.put("RSAWITHMD5", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
089 algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
090 algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
091 algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
092 algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
093 algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
094 algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
095 algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
096 algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
097 algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
098 algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
099 algorithms.put("RSAWITHSHA1", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
100 algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
101 algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
102 algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
103 algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
104 algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
105 algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
106
107 //
108 // reverse mappings
109 //
110 oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
111 oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
112 oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
113 oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
114 oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
115
116 oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
117 oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
118 oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.1"), "MD5WIDHRSA");
119 oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "DSAWITHSHA1");
120 oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "DSAWITHSHA1");
121 }
122
123 private static ASN1Sequence toDERSequence(
124 byte[] bytes)
125 {
126 try
127 {
128 ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
129 ASN1InputStream dIn = new ASN1InputStream(bIn);
130
131 return (ASN1Sequence)dIn.readObject();
132 }
133 catch (Exception e)
134 {
135 throw new IllegalArgumentException("badly encoded request", e);
136 }
137 }
138
139 /**
140 * construct a PKCS10 certification request from a DER encoded
141 * byte stream.
142 */
143 public PKCS10CertificationRequest(
144 byte[] bytes)
145 {
146 super(toDERSequence(bytes));
147 }
148
149 public PKCS10CertificationRequest(
150 ASN1Sequence sequence)
151 {
152 super(sequence);
153 }
154
155 /**
156 * create a PKCS10 certfication request using the BC provider.
157 */
158 public PKCS10CertificationRequest(
159 String signatureAlgorithm,
160 X509Name subject,
161 PublicKey key,
162 ASN1Set attributes,
163 PrivateKey signingKey)
164 throws NoSuchAlgorithmException, NoSuchProviderException,
165 InvalidKeyException, SignatureException
166 {
167 this(signatureAlgorithm, subject, key, attributes, signingKey, null);
168 }
169
170 private static X509Name convertName(
171 X500Principal name)
172 {
173 try
174 {
175 return new X509Principal(name.getEncoded());
176 }
177 catch (IOException e)
178 {
179 throw new IllegalArgumentException("can't convert name", e);
180 }
181 }
182
183 /**
184 * create a PKCS10 certfication request using the BC provider.
185 */
186 public PKCS10CertificationRequest(
187 String signatureAlgorithm,
188 X500Principal subject,
189 PublicKey key,
190 ASN1Set attributes,
191 PrivateKey signingKey)
192 throws NoSuchAlgorithmException, NoSuchProviderException,
193 InvalidKeyException, SignatureException
194 {
195 this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, null);
196 }
197
198 /**
199 * create a PKCS10 certfication request using the named provider.
200 */
201 public PKCS10CertificationRequest(
202 String signatureAlgorithm,
203 X500Principal subject,
204 PublicKey key,
205 ASN1Set attributes,
206 PrivateKey signingKey,
207 String provider)
208 throws NoSuchAlgorithmException, NoSuchProviderException,
209 InvalidKeyException, SignatureException
210 {
211 this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, provider);
212 }
213
214 /**
215 * create a PKCS10 certfication request using the named provider.
216 */
217 public PKCS10CertificationRequest(
218 String signatureAlgorithm,
219 X509Name subject,
220 PublicKey key,
221 ASN1Set attributes,
222 PrivateKey signingKey,
223 String provider)
224 throws NoSuchAlgorithmException, NoSuchProviderException,
225 InvalidKeyException, SignatureException
226 {
227 DERObjectIdentifier sigOID = (DERObjectIdentifier)algorithms.get(signatureAlgorithm.toUpperCase());
228
229 if (sigOID == null)
230 {
231 throw new IllegalArgumentException("Unknown signature type requested");
232 }
233
234 if (subject == null)
235 {
236 throw new IllegalArgumentException("subject must not be null");
237 }
238
239 if (key == null)
240 {
241 throw new IllegalArgumentException("public key must not be null");
242 }
243
244 this.sigAlgId = new AlgorithmIdentifier(sigOID, null);
245
246 byte[] bytes = key.getEncoded();
247 ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
248 ASN1InputStream dIn = new ASN1InputStream(bIn);
249
250 try
251 {
252 this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo((ASN1Sequence)dIn.readObject()), attributes);
253 }
254 catch (IOException e)
255 {
256 throw new IllegalArgumentException("can't encode public key", e);
257 }
258
259 Signature sig = null;
260
261 try
262 {
263 if (provider == null) {
264 sig = Signature.getInstance(sigAlgId.getObjectId().getId());
265 }
266 else {
267 sig = Signature.getInstance(sigAlgId.getObjectId().getId(), provider);
268 }
269 }
270 catch (NoSuchAlgorithmException e)
271 {
272 if (provider == null) {
273 sig = Signature.getInstance(signatureAlgorithm);
274 }
275 else {
276 sig = Signature.getInstance(signatureAlgorithm, provider);
277 }
278 }
279
280 sig.initSign(signingKey);
281
282 try
283 {
284 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
285 DEROutputStream dOut = new DEROutputStream(bOut);
286
287 dOut.writeObject(reqInfo);
288
289 sig.update(bOut.toByteArray());
290 }
291 catch (Exception e)
292 {
293 throw new SecurityException("exception encoding TBS cert request - " + e.getMessage(), e);
294 }
295
296 this.sigBits = new DERBitString(sig.sign());
297 }
298
299 /**
300 * return the public key associated with the certification request -
301 * the public key is created using the BC provider.
302 */
303 public PublicKey getPublicKey()
304 throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException
305 {
306 return getPublicKey(null);
307 }
308
309 public PublicKey getPublicKey(
310 String provider)
311 throws NoSuchAlgorithmException, NoSuchProviderException,
312 InvalidKeyException
313 {
314 SubjectPublicKeyInfo subjectPKInfo = reqInfo.getSubjectPublicKeyInfo();
315
316 try
317 {
318 X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getBytes());
319 AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithmId ();
320 try {
321
322 if (provider == null) {
323 return KeyFactory.getInstance(keyAlg.getObjectId().getId ()).generatePublic(xspec);
324 }
325 else {
326 return KeyFactory.getInstance(keyAlg.getObjectId().getId (), provider).generatePublic(xspec);
327 }
328
329 } catch (NoSuchAlgorithmException e) {
330 // if we can't resolve this via the OID, just as for the RSA algorithm. This is all
331 // Geronimo requires anyway.
332 if (provider == null) {
333 return KeyFactory.getInstance("RSA").generatePublic(xspec);
334 }
335 else {
336 return KeyFactory.getInstance("RSA", provider).generatePublic(xspec);
337 }
338 }
339 }
340 catch (InvalidKeySpecException e)
341 {
342 throw (InvalidKeyException)new InvalidKeyException("error decoding public key").initCause(e);
343 }
344 }
345
346 /**
347 * verify the request using the BC provider.
348 */
349 public boolean verify()
350 throws NoSuchAlgorithmException, NoSuchProviderException,
351 InvalidKeyException, SignatureException
352 {
353 return verify(null);
354 }
355
356 public boolean verify(
357 String provider)
358 throws NoSuchAlgorithmException, NoSuchProviderException,
359 InvalidKeyException, SignatureException
360 {
361 Signature sig = null;
362
363 try
364 {
365 if (provider == null) {
366 sig = Signature.getInstance(sigAlgId.getObjectId().getId());
367 }
368 else {
369 sig = Signature.getInstance(sigAlgId.getObjectId().getId(), provider);
370 }
371 }
372 catch (NoSuchAlgorithmException e)
373 {
374 //
375 // try an alternate
376 //
377 if (oids.get(sigAlgId.getObjectId().getId()) != null)
378 {
379 String signatureAlgorithm = (String)oids.get(sigAlgId.getObjectId().getId());
380
381 if (provider == null) {
382 sig = Signature.getInstance(signatureAlgorithm);
383 }
384 else {
385 sig = Signature.getInstance(signatureAlgorithm, provider);
386 }
387 }
388 }
389
390 sig.initVerify(this.getPublicKey(provider));
391
392 try
393 {
394 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
395 DEROutputStream dOut = new DEROutputStream(bOut);
396
397 dOut.writeObject(reqInfo);
398
399 sig.update(bOut.toByteArray());
400 }
401 catch (Exception e)
402 {
403 throw (SecurityException)new SecurityException("exception encoding TBS cert request - " + e.getMessage()).initCause(e);
404 }
405
406 return sig.verify(sigBits.getBytes());
407 }
408
409 /**
410 * return a DER encoded byte array representing this object
411 */
412 public byte[] getEncoded()
413 {
414 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
415 DEROutputStream dOut = new DEROutputStream(bOut);
416
417 try
418 {
419 dOut.writeObject(this);
420 }
421 catch (IOException e)
422 {
423 throw new RuntimeException(e.getMessage(), e);
424 }
425
426 return bOut.toByteArray();
427 }
428 }