1package org.bouncycastle.operator.jcajce; 2 3import java.io.ByteArrayInputStream; 4import java.io.IOException; 5import java.security.AlgorithmParameters; 6import java.security.GeneralSecurityException; 7import java.security.KeyFactory; 8import java.security.MessageDigest; 9import java.security.NoSuchAlgorithmException; 10import java.security.NoSuchProviderException; 11import java.security.PublicKey; 12import java.security.Signature; 13import java.security.cert.CertificateException; 14import java.security.cert.CertificateFactory; 15import java.security.cert.X509Certificate; 16import java.security.spec.InvalidKeySpecException; 17import java.security.spec.PSSParameterSpec; 18import java.security.spec.X509EncodedKeySpec; 19import java.util.HashMap; 20import java.util.Map; 21 22import javax.crypto.Cipher; 23 24import org.bouncycastle.asn1.ASN1Encodable; 25import org.bouncycastle.asn1.ASN1ObjectIdentifier; 26import org.bouncycastle.asn1.DERNull; 27// BEGIN android-removed 28// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; 29// END android-removed 30import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; 31import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; 32import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; 33import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; 34import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 35import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; 36import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; 37import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 38import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 39import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 40import org.bouncycastle.cert.X509CertificateHolder; 41import org.bouncycastle.jcajce.JcaJceHelper; 42import org.bouncycastle.jcajce.JcaJceUtils; 43import org.bouncycastle.operator.OperatorCreationException; 44 45class OperatorHelper 46{ 47 private static final Map oids = new HashMap(); 48 private static final Map asymmetricWrapperAlgNames = new HashMap(); 49 private static final Map symmetricWrapperAlgNames = new HashMap(); 50 private static final Map symmetricKeyAlgNames = new HashMap(); 51 52 static 53 { 54 // 55 // reverse mappings 56 // 57 oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA"); 58 oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA"); 59 oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA"); 60 oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA"); 61 oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA"); 62 // BEGIN android-removed 63 // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410"); 64 // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410"); 65 // END android-removed 66 67 oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA"); 68 // BEGIN android-removed 69 // oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA"); 70 // END android-removed 71 oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA"); 72 oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA"); 73 oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA"); 74 oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA"); 75 oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA"); 76 oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA"); 77 oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA"); 78 oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA"); 79 oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA"); 80 oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA"); 81 82 oids.put(OIWObjectIdentifiers.idSHA1, "SHA-1"); 83 oids.put(NISTObjectIdentifiers.id_sha224, "SHA-224"); 84 oids.put(NISTObjectIdentifiers.id_sha256, "SHA-256"); 85 oids.put(NISTObjectIdentifiers.id_sha384, "SHA-384"); 86 oids.put(NISTObjectIdentifiers.id_sha512, "SHA-512"); 87 oids.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD-128"); 88 oids.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD-160"); 89 oids.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD-256"); 90 91 asymmetricWrapperAlgNames.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding"); 92 93 symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWrap"); 94 symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2Wrap"); 95 symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes128_wrap, "AESWrap"); 96 symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes192_wrap, "AESWrap"); 97 symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes256_wrap, "AESWrap"); 98 symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia128_wrap, "CamelliaWrap"); 99 symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia192_wrap, "CamelliaWrap"); 100 symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia256_wrap, "CamelliaWrap"); 101 symmetricWrapperAlgNames.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, "SEEDWrap"); 102 symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede"); 103 104 symmetricKeyAlgNames.put(NISTObjectIdentifiers.aes, "AES"); 105 symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes128_CBC, "AES"); 106 symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes192_CBC, "AES"); 107 symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes256_CBC, "AES"); 108 symmetricKeyAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede"); 109 symmetricKeyAlgNames.put(PKCSObjectIdentifiers.RC2_CBC, "RC2"); 110 } 111 112 private JcaJceHelper helper; 113 114 OperatorHelper(JcaJceHelper helper) 115 { 116 this.helper = helper; 117 } 118 119 Cipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm, Map extraAlgNames) 120 throws OperatorCreationException 121 { 122 try 123 { 124 String cipherName = null; 125 126 if (!extraAlgNames.isEmpty()) 127 { 128 cipherName = (String)extraAlgNames.get(algorithm); 129 } 130 131 if (cipherName == null) 132 { 133 cipherName = (String)asymmetricWrapperAlgNames.get(algorithm); 134 } 135 136 if (cipherName != null) 137 { 138 try 139 { 140 // this is reversed as the Sun policy files now allow unlimited strength RSA 141 return helper.createCipher(cipherName); 142 } 143 catch (NoSuchAlgorithmException e) 144 { 145 // try alternate for RSA 146 if (cipherName.equals("RSA/ECB/PKCS1Padding")) 147 { 148 try 149 { 150 return helper.createCipher("RSA/NONE/PKCS1Padding"); 151 } 152 catch (NoSuchAlgorithmException ex) 153 { 154 // Ignore 155 } 156 } 157 // Ignore 158 } 159 } 160 161 return helper.createCipher(algorithm.getId()); 162 } 163 catch (GeneralSecurityException e) 164 { 165 throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e); 166 } 167 } 168 169 Cipher createSymmetricWrapper(ASN1ObjectIdentifier algorithm) 170 throws OperatorCreationException 171 { 172 try 173 { 174 String cipherName = (String)symmetricWrapperAlgNames.get(algorithm); 175 176 if (cipherName != null) 177 { 178 try 179 { 180 // this is reversed as the Sun policy files now allow unlimited strength RSA 181 return helper.createCipher(cipherName); 182 } 183 catch (NoSuchAlgorithmException e) 184 { 185 // Ignore 186 } 187 } 188 return helper.createCipher(algorithm.getId()); 189 } 190 catch (GeneralSecurityException e) 191 { 192 throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e); 193 } 194 } 195 196 AlgorithmParameters createAlgorithmParameters(AlgorithmIdentifier cipherAlgId) 197 throws OperatorCreationException 198 { 199 AlgorithmParameters parameters; 200 201 if (cipherAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption)) 202 { 203 return null; 204 } 205 206 try 207 { 208 parameters = helper.createAlgorithmParameters(cipherAlgId.getAlgorithm().getId()); 209 } 210 catch (NoSuchAlgorithmException e) 211 { 212 return null; // There's a good chance there aren't any! 213 } 214 catch (NoSuchProviderException e) 215 { 216 throw new OperatorCreationException("cannot create algorithm parameters: " + e.getMessage(), e); 217 } 218 219 try 220 { 221 parameters.init(cipherAlgId.getParameters().toASN1Primitive().getEncoded()); 222 } 223 catch (IOException e) 224 { 225 throw new OperatorCreationException("cannot initialise algorithm parameters: " + e.getMessage(), e); 226 } 227 228 return parameters; 229 } 230 231 MessageDigest createDigest(AlgorithmIdentifier digAlgId) 232 throws GeneralSecurityException 233 { 234 MessageDigest dig; 235 236 try 237 { 238 dig = helper.createDigest(getDigestAlgName(digAlgId.getAlgorithm())); 239 } 240 catch (NoSuchAlgorithmException e) 241 { 242 // 243 // try an alternate 244 // 245 if (oids.get(digAlgId.getAlgorithm()) != null) 246 { 247 String digestAlgorithm = (String)oids.get(digAlgId.getAlgorithm()); 248 249 dig = helper.createDigest(digestAlgorithm); 250 } 251 else 252 { 253 throw e; 254 } 255 } 256 257 return dig; 258 } 259 260 Signature createSignature(AlgorithmIdentifier sigAlgId) 261 throws GeneralSecurityException 262 { 263 Signature sig; 264 265 try 266 { 267 sig = helper.createSignature(getSignatureName(sigAlgId)); 268 } 269 catch (NoSuchAlgorithmException e) 270 { 271 // 272 // try an alternate 273 // 274 if (oids.get(sigAlgId.getAlgorithm()) != null) 275 { 276 String signatureAlgorithm = (String)oids.get(sigAlgId.getAlgorithm()); 277 278 sig = helper.createSignature(signatureAlgorithm); 279 } 280 else 281 { 282 throw e; 283 } 284 } 285 286 return sig; 287 } 288 289 public Signature createRawSignature(AlgorithmIdentifier algorithm) 290 { 291 Signature sig; 292 293 try 294 { 295 String algName = getSignatureName(algorithm); 296 297 algName = "NONE" + algName.substring(algName.indexOf("WITH")); 298 299 sig = helper.createSignature(algName); 300 301 // RFC 4056 302 // When the id-RSASSA-PSS algorithm identifier is used for a signature, 303 // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params. 304 if (algorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) 305 { 306 AlgorithmParameters params = helper.createAlgorithmParameters(algName); 307 308 JcaJceUtils.loadParameters(params, algorithm.getParameters()); 309 310 PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class); 311 sig.setParameter(spec); 312 } 313 } 314 catch (Exception e) 315 { 316 return null; 317 } 318 319 return sig; 320 } 321 322 private static String getSignatureName( 323 AlgorithmIdentifier sigAlgId) 324 { 325 ASN1Encodable params = sigAlgId.getParameters(); 326 327 if (params != null && !DERNull.INSTANCE.equals(params)) 328 { 329 if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) 330 { 331 RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params); 332 return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1"; 333 } 334 } 335 336 if (oids.containsKey(sigAlgId.getAlgorithm())) 337 { 338 return (String)oids.get(sigAlgId.getAlgorithm()); 339 } 340 341 return sigAlgId.getAlgorithm().getId(); 342 } 343 344 private static String getDigestAlgName( 345 ASN1ObjectIdentifier digestAlgOID) 346 { 347 if (PKCSObjectIdentifiers.md5.equals(digestAlgOID)) 348 { 349 return "MD5"; 350 } 351 else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID)) 352 { 353 return "SHA1"; 354 } 355 else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID)) 356 { 357 return "SHA224"; 358 } 359 else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID)) 360 { 361 return "SHA256"; 362 } 363 else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID)) 364 { 365 return "SHA384"; 366 } 367 else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID)) 368 { 369 return "SHA512"; 370 } 371 // BEGIN android-removed 372 // else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID)) 373 // { 374 // return "RIPEMD128"; 375 // } 376 // else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID)) 377 // { 378 // return "RIPEMD160"; 379 // } 380 // else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID)) 381 // { 382 // return "RIPEMD256"; 383 // } 384 // else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID)) 385 // { 386 // return "GOST3411"; 387 // } 388 // END android-removed 389 else 390 { 391 return digestAlgOID.getId(); 392 } 393 } 394 395 public X509Certificate convertCertificate(X509CertificateHolder certHolder) 396 throws CertificateException 397 { 398 399 try 400 { 401 CertificateFactory certFact = helper.createCertificateFactory("X.509"); 402 403 return (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded())); 404 } 405 catch (IOException e) 406 { 407 throw new OpCertificateException("cannot get encoded form of certificate: " + e.getMessage(), e); 408 } 409 catch (NoSuchAlgorithmException e) 410 { 411 throw new OpCertificateException("cannot create certificate factory: " + e.getMessage(), e); 412 } 413 catch (NoSuchProviderException e) 414 { 415 throw new OpCertificateException("cannot find factory provider: " + e.getMessage(), e); 416 } 417 } 418 419 public PublicKey convertPublicKey(SubjectPublicKeyInfo publicKeyInfo) 420 throws OperatorCreationException 421 { 422 try 423 { 424 KeyFactory keyFact = helper.createKeyFactory(publicKeyInfo.getAlgorithm().getAlgorithm().getId()); 425 426 return keyFact.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded())); 427 } 428 catch (IOException e) 429 { 430 throw new OperatorCreationException("cannot get encoded form of key: " + e.getMessage(), e); 431 } 432 catch (NoSuchAlgorithmException e) 433 { 434 throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e); 435 } 436 catch (NoSuchProviderException e) 437 { 438 throw new OperatorCreationException("cannot find factory provider: " + e.getMessage(), e); 439 } 440 catch (InvalidKeySpecException e) 441 { 442 throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e); 443 } 444 } 445 446 // TODO: put somewhere public so cause easily accessed 447 private static class OpCertificateException 448 extends CertificateException 449 { 450 private Throwable cause; 451 452 public OpCertificateException(String msg, Throwable cause) 453 { 454 super(msg); 455 456 this.cause = cause; 457 } 458 459 public Throwable getCause() 460 { 461 return cause; 462 } 463 } 464 465 String getKeyAlgorithmName(ASN1ObjectIdentifier oid) 466 { 467 468 String name = (String)symmetricKeyAlgNames.get(oid); 469 470 if (name != null) 471 { 472 return name; 473 } 474 475 return oid.getId(); 476 } 477} 478