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