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