1 package org.bouncycastle.jce.provider; 2 3 import java.io.IOException; 4 import java.security.AccessController; 5 import java.security.PrivateKey; 6 import java.security.PrivilegedAction; 7 import java.security.Provider; 8 import java.security.PublicKey; 9 import java.util.HashMap; 10 import java.util.Iterator; 11 import java.util.Map; 12 13 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 14 import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers; 15 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 16 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 17 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 18 import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; 19 import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; 20 import org.bouncycastle.jcajce.provider.symmetric.util.ClassUtil; 21 import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; 22 import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; 23 import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; 24 import org.bouncycastle.pqc.jcajce.provider.lms.LMSKeyFactorySpi; 25 import org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceCCA2KeyFactorySpi; 26 import org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceKeyFactorySpi; 27 import org.bouncycastle.pqc.jcajce.provider.newhope.NHKeyFactorySpi; 28 import org.bouncycastle.pqc.jcajce.provider.qtesla.QTESLAKeyFactorySpi; 29 import org.bouncycastle.pqc.jcajce.provider.rainbow.RainbowKeyFactorySpi; 30 import org.bouncycastle.pqc.jcajce.provider.sphincs.Sphincs256KeyFactorySpi; 31 import org.bouncycastle.pqc.jcajce.provider.xmss.XMSSKeyFactorySpi; 32 import org.bouncycastle.pqc.jcajce.provider.xmss.XMSSMTKeyFactorySpi; 33 34 /** 35 * To add the provider at runtime use: 36 * <pre> 37 * import java.security.Security; 38 * import org.bouncycastle.jce.provider.BouncyCastleProvider; 39 * 40 * Security.addProvider(new BouncyCastleProvider()); 41 * </pre> 42 * The provider can also be configured as part of your environment via 43 * static registration by adding an entry to the java.security properties 44 * file (found in $JAVA_HOME/jre/lib/security/java.security, where 45 * $JAVA_HOME is the location of your JDK/JRE distribution). You'll find 46 * detailed instructions in the file but basically it comes down to adding 47 * a line: 48 * <pre> 49 * <code> 50 * security.provider.<n>=org.bouncycastle.jce.provider.BouncyCastleProvider 51 * </code> 52 * </pre> 53 * Where <n> is the preference you want the provider at (1 being the 54 * most preferred). 55 * <p>Note: JCE algorithm names should be upper-case only so the case insensitive 56 * test for getInstance works. 57 */ 58 public final class BouncyCastleProvider extends Provider 59 implements ConfigurableProvider 60 { 61 private static String info = "BouncyCastle Security Provider v1.69"; 62 63 public static final String PROVIDER_NAME = "BC"; 64 65 public static final ProviderConfiguration CONFIGURATION = new BouncyCastleProviderConfiguration(); 66 67 private static final Map keyInfoConverters = new HashMap(); 68 69 private static final Class revChkClass = ClassUtil.loadClass(BouncyCastleProvider.class, "java.security.cert.PKIXRevocationChecker"); 70 71 /* 72 * Configurable symmetric ciphers 73 */ 74 private static final String SYMMETRIC_PACKAGE = "org.bouncycastle.jcajce.provider.symmetric."; 75 76 private static final String[] SYMMETRIC_GENERIC = 77 { 78 "PBEPBKDF1", "PBEPBKDF2", "PBEPKCS12", "TLSKDF", "SCRYPT" 79 }; 80 81 private static final String[] SYMMETRIC_MACS = 82 { 83 "SipHash", "SipHash128", "Poly1305" 84 }; 85 86 private static final String[] SYMMETRIC_CIPHERS = 87 { 88 "AES", "ARC4", "ARIA", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede", 89 "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5", 90 "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "SM4", "TEA", "Twofish", "Threefish", 91 "VMPC", "VMPCKSA3", "XTEA", "XSalsa20", "OpenSSLPBKDF", "DSTU7624", "GOST3412_2015", "Zuc" 92 }; 93 94 /* 95 * Configurable asymmetric ciphers 96 */ 97 private static final String ASYMMETRIC_PACKAGE = "org.bouncycastle.jcajce.provider.asymmetric."; 98 99 // this one is required for GNU class path - it needs to be loaded first as the 100 // later ones configure it. 101 private static final String[] ASYMMETRIC_GENERIC = 102 { 103 "X509", "IES", "COMPOSITE" 104 }; 105 106 private static final String[] ASYMMETRIC_CIPHERS = 107 { 108 "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145", "GM", "EdEC" 109 }; 110 111 /* 112 * Configurable digests 113 */ 114 private static final String DIGEST_PACKAGE = "org.bouncycastle.jcajce.provider.digest."; 115 private static final String[] DIGESTS = 116 { 117 "GOST3411", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", 118 "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b", "Blake2s", "DSTU7564", 119 "Haraka" 120 }; 121 122 /* 123 * Configurable keystores 124 */ 125 private static final String KEYSTORE_PACKAGE = "org.bouncycastle.jcajce.provider.keystore."; 126 private static final String[] KEYSTORES = 127 { 128 "BC", "BCFKS", "PKCS12" 129 }; 130 131 /* 132 * Configurable secure random 133 */ 134 private static final String SECURE_RANDOM_PACKAGE = "org.bouncycastle.jcajce.provider.drbg."; 135 private static final String[] SECURE_RANDOMS = 136 { 137 "DRBG" 138 }; 139 140 /** 141 * Construct a new provider. This should only be required when 142 * using runtime registration of the provider using the 143 * <code>Security.addProvider()</code> mechanism. 144 */ BouncyCastleProvider()145 public BouncyCastleProvider() 146 { 147 super(PROVIDER_NAME, 1.69, info); 148 149 AccessController.doPrivileged(new PrivilegedAction() 150 { 151 public Object run() 152 { 153 setup(); 154 return null; 155 } 156 }); 157 } 158 setup()159 private void setup() 160 { 161 loadAlgorithms(DIGEST_PACKAGE, DIGESTS); 162 163 loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_GENERIC); 164 165 loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_MACS); 166 167 loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_CIPHERS); 168 169 loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_GENERIC); 170 171 loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_CIPHERS); 172 173 loadAlgorithms(KEYSTORE_PACKAGE, KEYSTORES); 174 175 loadAlgorithms(SECURE_RANDOM_PACKAGE, SECURE_RANDOMS); 176 177 loadPQCKeys(); // so we can handle certificates containing them. 178 179 // 180 // X509Store 181 // 182 put("X509Store.CERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertCollection"); 183 put("X509Store.ATTRIBUTECERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreAttrCertCollection"); 184 put("X509Store.CRL/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCRLCollection"); 185 put("X509Store.CERTIFICATEPAIR/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertPairCollection"); 186 187 put("X509Store.CERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCerts"); 188 put("X509Store.CRL/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCRLs"); 189 put("X509Store.ATTRIBUTECERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPAttrCerts"); 190 put("X509Store.CERTIFICATEPAIR/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCertPairs"); 191 192 // 193 // X509StreamParser 194 // 195 put("X509StreamParser.CERTIFICATE", "org.bouncycastle.jce.provider.X509CertParser"); 196 put("X509StreamParser.ATTRIBUTECERTIFICATE", "org.bouncycastle.jce.provider.X509AttrCertParser"); 197 put("X509StreamParser.CRL", "org.bouncycastle.jce.provider.X509CRLParser"); 198 put("X509StreamParser.CERTIFICATEPAIR", "org.bouncycastle.jce.provider.X509CertPairParser"); 199 200 // 201 // cipher engines 202 // 203 put("Cipher.BROKENPBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithMD5AndDES"); 204 205 put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES"); 206 207 208 put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish"); 209 210 // Certification Path API 211 if (revChkClass != null) 212 { 213 put("CertPathValidator.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathValidatorSpi"); 214 put("CertPathBuilder.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathBuilderSpi"); 215 put("CertPathValidator.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi_8"); 216 put("CertPathBuilder.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi_8"); 217 put("CertPathValidator.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi_8"); 218 put("CertPathBuilder.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi_8"); 219 } 220 else 221 { 222 put("CertPathValidator.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathValidatorSpi"); 223 put("CertPathBuilder.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathBuilderSpi"); 224 put("CertPathValidator.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi"); 225 put("CertPathBuilder.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi"); 226 put("CertPathValidator.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi"); 227 put("CertPathBuilder.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi"); 228 } 229 put("CertStore.Collection", "org.bouncycastle.jce.provider.CertStoreCollectionSpi"); 230 put("CertStore.LDAP", "org.bouncycastle.jce.provider.X509LDAPCertStoreSpi"); 231 put("CertStore.Multi", "org.bouncycastle.jce.provider.MultiCertStoreSpi"); 232 put("Alg.Alias.CertStore.X509LDAP", "LDAP"); 233 } 234 loadAlgorithms(String packageName, String[] names)235 private void loadAlgorithms(String packageName, String[] names) 236 { 237 for (int i = 0; i != names.length; i++) 238 { 239 Class clazz = ClassUtil.loadClass(BouncyCastleProvider.class, packageName + names[i] + "$Mappings"); 240 241 if (clazz != null) 242 { 243 try 244 { 245 ((AlgorithmProvider)clazz.newInstance()).configure(this); 246 } 247 catch (Exception e) 248 { // this should never ever happen!! 249 throw new InternalError("cannot create instance of " 250 + packageName + names[i] + "$Mappings : " + e); 251 } 252 } 253 } 254 } 255 loadPQCKeys()256 private void loadPQCKeys() 257 { 258 addKeyInfoConverter(PQCObjectIdentifiers.sphincs256, new Sphincs256KeyFactorySpi()); 259 addKeyInfoConverter(PQCObjectIdentifiers.newHope, new NHKeyFactorySpi()); 260 addKeyInfoConverter(PQCObjectIdentifiers.xmss, new XMSSKeyFactorySpi()); 261 addKeyInfoConverter(IsaraObjectIdentifiers.id_alg_xmss, new XMSSKeyFactorySpi()); 262 addKeyInfoConverter(PQCObjectIdentifiers.xmss_mt, new XMSSMTKeyFactorySpi()); 263 addKeyInfoConverter(IsaraObjectIdentifiers.id_alg_xmssmt, new XMSSMTKeyFactorySpi()); 264 addKeyInfoConverter(PQCObjectIdentifiers.mcEliece, new McElieceKeyFactorySpi()); 265 addKeyInfoConverter(PQCObjectIdentifiers.mcElieceCca2, new McElieceCCA2KeyFactorySpi()); 266 addKeyInfoConverter(PQCObjectIdentifiers.rainbow, new RainbowKeyFactorySpi()); 267 addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_p_I, new QTESLAKeyFactorySpi()); 268 addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_p_III, new QTESLAKeyFactorySpi()); 269 addKeyInfoConverter(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig, new LMSKeyFactorySpi()); 270 } 271 setParameter(String parameterName, Object parameter)272 public void setParameter(String parameterName, Object parameter) 273 { 274 synchronized (CONFIGURATION) 275 { 276 ((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter); 277 } 278 } 279 hasAlgorithm(String type, String name)280 public boolean hasAlgorithm(String type, String name) 281 { 282 return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name); 283 } 284 addAlgorithm(String key, String value)285 public void addAlgorithm(String key, String value) 286 { 287 if (containsKey(key)) 288 { 289 throw new IllegalStateException("duplicate provider key (" + key + ") found"); 290 } 291 292 put(key, value); 293 } 294 addAlgorithm(String type, ASN1ObjectIdentifier oid, String className)295 public void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className) 296 { 297 addAlgorithm(type + "." + oid, className); 298 addAlgorithm(type + ".OID." + oid, className); 299 } 300 addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)301 public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter) 302 { 303 synchronized (keyInfoConverters) 304 { 305 keyInfoConverters.put(oid, keyInfoConverter); 306 } 307 } 308 getKeyInfoConverter(ASN1ObjectIdentifier oid)309 public AsymmetricKeyInfoConverter getKeyInfoConverter(ASN1ObjectIdentifier oid) 310 { 311 return (AsymmetricKeyInfoConverter)keyInfoConverters.get(oid); 312 } 313 addAttributes(String key, Map<String, String> attributeMap)314 public void addAttributes(String key, Map<String, String> attributeMap) 315 { 316 for (Iterator it = attributeMap.keySet().iterator(); it.hasNext();) 317 { 318 String attributeName = (String)it.next(); 319 String attributeKey = key + " " + attributeName; 320 if (containsKey(attributeKey)) 321 { 322 throw new IllegalStateException("duplicate provider attribute key (" + attributeKey + ") found"); 323 } 324 325 put(attributeKey, attributeMap.get(attributeName)); 326 } 327 } 328 getAsymmetricKeyInfoConverter(ASN1ObjectIdentifier algorithm)329 private static AsymmetricKeyInfoConverter getAsymmetricKeyInfoConverter(ASN1ObjectIdentifier algorithm) 330 { 331 synchronized (keyInfoConverters) 332 { 333 return (AsymmetricKeyInfoConverter)keyInfoConverters.get(algorithm); 334 } 335 } 336 getPublicKey(SubjectPublicKeyInfo publicKeyInfo)337 public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo) 338 throws IOException 339 { 340 AsymmetricKeyInfoConverter converter = getAsymmetricKeyInfoConverter(publicKeyInfo.getAlgorithm().getAlgorithm()); 341 342 if (converter == null) 343 { 344 return null; 345 } 346 347 return converter.generatePublic(publicKeyInfo); 348 } 349 getPrivateKey(PrivateKeyInfo privateKeyInfo)350 public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo) 351 throws IOException 352 { 353 AsymmetricKeyInfoConverter converter = getAsymmetricKeyInfoConverter(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm()); 354 355 if (converter == null) 356 { 357 return null; 358 } 359 360 return converter.generatePrivate(privateKeyInfo); 361 } 362 } 363