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.&lt;n&gt;=org.bouncycastle.jce.provider.BouncyCastleProvider
51  * </code>
52  * </pre>
53  * Where &lt;n&gt; 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