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