Java tutorial
package org.bouncycastle.jsse.provider; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.Security; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider; import org.bouncycastle.util.Strings; @SuppressWarnings("serial") public class BouncyCastleJsseProvider extends Provider { public static final String PROVIDER_NAME = "BCJSSE"; private static final double PROVIDER_VERSION = 1.0010; private static final String PROVIDER_INFO = "Bouncy Castle JSSE Provider Version 1.0.10"; private Map<String, BcJsseService> serviceMap = new HashMap<String, BcJsseService>(); private Map<String, EngineCreator> creatorMap = new HashMap<String, EngineCreator>(); private final boolean isInFipsMode; public BouncyCastleJsseProvider() { super(PROVIDER_NAME, PROVIDER_VERSION, PROVIDER_INFO); this.isInFipsMode = configure(false, new JcaTlsCryptoProvider()); } public BouncyCastleJsseProvider(Provider provider) { this(false, provider); } public BouncyCastleJsseProvider(boolean fipsMode, Provider provider) { super(PROVIDER_NAME, PROVIDER_VERSION, PROVIDER_INFO); this.isInFipsMode = configure(fipsMode, new JcaTlsCryptoProvider().setProvider(provider)); } public BouncyCastleJsseProvider(String config) { super(PROVIDER_NAME, PROVIDER_VERSION, PROVIDER_INFO); config = config.trim(); boolean fipsMode = false; String cryptoName = config; int colonPos = config.indexOf(':'); if (colonPos >= 0) { String first = config.substring(0, colonPos).trim(); String second = config.substring(colonPos + 1).trim(); fipsMode = first.equalsIgnoreCase("fips"); cryptoName = second; } JcaTlsCryptoProvider cryptoProvider; try { cryptoProvider = createCryptoProvider(cryptoName); } catch (GeneralSecurityException e) { throw new IllegalArgumentException("unable to set up TlsCrypto: " + e.getMessage(), e); } this.isInFipsMode = configure(fipsMode, cryptoProvider); } public BouncyCastleJsseProvider(boolean fipsMode, JcaTlsCryptoProvider tlsCryptoProvider) { super(PROVIDER_NAME, PROVIDER_VERSION, PROVIDER_INFO); this.isInFipsMode = configure(fipsMode, tlsCryptoProvider); } // for Java 11 public Provider configure(String configArg) { return new BouncyCastleJsseProvider(configArg); } private JcaTlsCryptoProvider createCryptoProvider(String cryptoName) throws GeneralSecurityException { if (cryptoName.equalsIgnoreCase("default")) { return new JcaTlsCryptoProvider(); } Provider provider = Security.getProvider(cryptoName); if (provider != null) { return new JcaTlsCryptoProvider().setProvider(provider); } try { Class<?> cryptoProviderClass = Class.forName(cryptoName); // the TlsCryptoProvider/Provider class named requires a no-args constructor Object cryptoProviderInstance = cryptoProviderClass.newInstance(); if (cryptoProviderInstance instanceof JcaTlsCryptoProvider) { return (JcaTlsCryptoProvider) cryptoProviderInstance; } if (cryptoProviderInstance instanceof Provider) { return new JcaTlsCryptoProvider().setProvider((Provider) cryptoProviderInstance); } throw new IllegalArgumentException("unrecognized class: " + cryptoName); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("unable to find Provider/TlsCrypto class: " + cryptoName); } catch (InstantiationException e) { throw new IllegalArgumentException( "unable to create Provider/TlsCrypto class '" + cryptoName + "': " + e.getMessage(), e); } catch (IllegalAccessException e) { throw new IllegalArgumentException( "unable to create Provider/TlsCrypto class '" + cryptoName + "': " + e.getMessage(), e); } } private boolean configure(final boolean fipsMode, final JcaTlsCryptoProvider cryptoProvider) { // TODO[jsse]: should X.509 be an alias. addAlgorithmImplementation("KeyManagerFactory.X.509", "org.bouncycastle.jsse.provider.KeyManagerFactory", new EngineCreator() { public Object createInstance(Object constructorParameter) { return new ProvKeyManagerFactorySpi(); } }); addAlias("Alg.Alias.KeyManagerFactory.X509", "X.509"); addAlias("Alg.Alias.KeyManagerFactory.PKIX", "X.509"); addAlgorithmImplementation("TrustManagerFactory.PKIX", "org.bouncycastle.jsse.provider.TrustManagerFactory", new EngineCreator() { public Object createInstance(Object constructorParameter) { return new ProvTrustManagerFactorySpi(cryptoProvider.getHelper()); } }); addAlias("Alg.Alias.TrustManagerFactory.X.509", "PKIX"); addAlias("Alg.Alias.TrustManagerFactory.X509", "PKIX"); addAlgorithmImplementation("SSLContext.TLS", "org.bouncycastle.jsse.provider.SSLContext.TLS", new EngineCreator() { public Object createInstance(Object constructorParameter) { return new ProvSSLContextSpi(fipsMode, cryptoProvider, null); } }); addAlgorithmImplementation("SSLContext.TLSV1", "org.bouncycastle.jsse.provider.SSLContext.TLSv1", new EngineCreator() { public Object createInstance(Object constructorParameter) { return new ProvSSLContextSpi(fipsMode, cryptoProvider, new String[] { "TLSv1" }); } }); addAlgorithmImplementation("SSLContext.TLSV1.1", "org.bouncycastle.jsse.provider.SSLContext.TLSv1_1", new EngineCreator() { public Object createInstance(Object constructorParameter) { return new ProvSSLContextSpi(fipsMode, cryptoProvider, new String[] { "TLSv1.1", "TLSv1" }); } }); addAlgorithmImplementation("SSLContext.TLSV1.2", "org.bouncycastle.jsse.provider.SSLContext.TLSv1_2", new EngineCreator() { public Object createInstance(Object constructorParameter) { return new ProvSSLContextSpi(fipsMode, cryptoProvider, new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }); } }); // TODO[tls13] // addAlgorithmImplementation("SSLContext.TLSV1.3", "org.bouncycastle.jsse.provider.SSLContext.TLSv1_3", // new EngineCreator() // { // public Object createInstance(Object constructorParameter) // { // return new ProvSSLContextSpi(fipsMode, cryptoProvider, new String[]{ "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1" }); // } // }); addAlgorithmImplementation("SSLContext.DEFAULT", "org.bouncycastle.jsse.provider.SSLContext.Default", new EngineCreator() { public Object createInstance(Object constructorParameter) throws GeneralSecurityException { return new DefaultSSLContextSpi(fipsMode, cryptoProvider); } }); addAlias("Alg.Alias.SSLContext.SSL", "TLS"); addAlias("Alg.Alias.SSLContext.SSLV3", "TLSV1"); return fipsMode; } void addAttribute(String key, String attributeName, String attributeValue) { String attributeKey = key + " " + attributeName; if (containsKey(attributeKey)) { throw new IllegalStateException("duplicate provider attribute key (" + attributeKey + ") found"); } put(attributeKey, attributeValue); } void addAlgorithmImplementation(String key, String className, EngineCreator creator) { if (containsKey(key)) { throw new IllegalStateException("duplicate provider key (" + key + ") found"); } addAttribute(key, "ImplementedIn", "Software"); put(key, className); creatorMap.put(className, creator); } void addAlias(String key, String value) { if (containsKey(key)) { throw new IllegalStateException("duplicate provider key (" + key + ") found"); } put(key, value); } public synchronized final Provider.Service getService(String type, String algorithm) { String upperCaseAlgName = Strings.toUpperCase(algorithm); BcJsseService service = serviceMap.get(type + "." + upperCaseAlgName); if (service == null) { String aliasString = "Alg.Alias." + type + "."; String realName = (String) this.get(aliasString + upperCaseAlgName); if (realName == null) { realName = upperCaseAlgName; } String className = (String) this.get(type + "." + realName); if (className == null) { return null; } String attributeKeyStart = type + "." + upperCaseAlgName + " "; List<String> aliases = new ArrayList<String>(); Map<String, String> attributes = new HashMap<String, String>(); for (Object key : this.keySet()) { String sKey = (String) key; if (sKey.startsWith(aliasString)) { if (this.get(key).equals(algorithm)) { aliases.add(sKey.substring(aliasString.length())); } } if (sKey.startsWith(attributeKeyStart)) { attributes.put(sKey.substring(attributeKeyStart.length()), (String) this.get(sKey)); } } service = new BcJsseService(this, type, upperCaseAlgName, className, aliases, getAttributeMap(attributes), creatorMap.get(className)); serviceMap.put(type + "." + upperCaseAlgName, service); } return service; } public synchronized final Set<Provider.Service> getServices() { Set<Provider.Service> serviceSet = super.getServices(); Set<Provider.Service> bcServiceSet = new HashSet<Provider.Service>(); for (Provider.Service service : serviceSet) { bcServiceSet.add(getService(service.getType(), service.getAlgorithm())); } return bcServiceSet; } private static final Map<Map<String, String>, Map<String, String>> attributeMaps = new HashMap<Map<String, String>, Map<String, String>>(); private static Map<String, String> getAttributeMap(Map<String, String> attributeMap) { Map<String, String> attrMap = attributeMaps.get(attributeMap); if (attrMap != null) { return attrMap; } attributeMaps.put(attributeMap, attributeMap); return attributeMap; } public boolean isFipsMode() { return isInFipsMode; } private static class BcJsseService extends Provider.Service { private final EngineCreator creator; /** * Construct a new service. * * @param provider the provider that offers this service * @param type the type of this service * @param algorithm the algorithm name * @param className the name of the class implementing this service * @param aliases List of aliases or null if algorithm has no aliases * @param attributes Map of attributes or null if this implementation * has no attributes * @throws NullPointerException if provider, type, algorithm, or * className is null */ public BcJsseService(Provider provider, String type, String algorithm, String className, List<String> aliases, Map<String, String> attributes, EngineCreator creator) { super(provider, type, algorithm, className, aliases, attributes); this.creator = creator; } public Object newInstance(Object constructorParameter) throws NoSuchAlgorithmException { try { Object instance = creator.createInstance(constructorParameter); if (instance == null) { throw new NoSuchAlgorithmException( "No such algorithm in FIPS approved mode: " + getAlgorithm()); } return instance; } catch (NoSuchAlgorithmException e) { throw e; } catch (Exception e) { throw new NoSuchAlgorithmException( "Unable to invoke creator for " + getAlgorithm() + ": " + e.getMessage(), e); } } } }