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 }