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 }