org.bouncycastle.jsse.provider.BouncyCastleJsseProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of impersonator Show documentation
Show all versions of impersonator Show documentation
Spoof TLS/JA3/JA4 and HTTP/2 fingerprints in Java
package org.bouncycastle.jsse.provider;
import java.security.AccessController;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedAction;
import java.security.Provider;
import java.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
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 String JSSE_CONFIG_PROPERTY = "org.bouncycastle.jsse.config";
private static final double PROVIDER_VERSION = 1.0019;
private static final String PROVIDER_INFO = "Bouncy Castle JSSE Provider Version 1.0.19";
private final Map serviceMap = new ConcurrentHashMap();
private final Map creatorMap = new HashMap();
private final boolean isInFipsMode;
public BouncyCastleJsseProvider()
{
this(getPropertyValue(JSSE_CONFIG_PROPERTY, "default"));
}
public BouncyCastleJsseProvider(boolean fipsMode)
{
super(PROVIDER_NAME, PROVIDER_VERSION, PROVIDER_INFO);
this.isInFipsMode = configure(fipsMode, 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 JcaTlsCryptoProvider: " + 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/JcaTlsCryptoProvider class: " + cryptoName);
}
catch (InstantiationException e)
{
throw new IllegalArgumentException("unable to create Provider/JcaTlsCryptoProvider class '" + cryptoName + "': " + e.getMessage(), e);
}
catch (IllegalAccessException e)
{
throw new IllegalArgumentException("unable to create Provider/JcaTlsCryptoProvider 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(fipsMode, cryptoProvider.getHelper());
}
});
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(fipsMode, 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, specifyClientProtocols("TLSv1"));
}
});
addAlgorithmImplementation("SSLContext.TLSV1.1", "org.bouncycastle.jsse.provider.SSLContext.TLSv1_1",
new EngineCreator()
{
public Object createInstance(Object constructorParameter)
{
return new ProvSSLContextSpi(fipsMode, cryptoProvider, specifyClientProtocols("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,
specifyClientProtocols("TLSv1.2", "TLSv1.1", "TLSv1"));
}
});
addAlgorithmImplementation("SSLContext.TLSV1.3", "org.bouncycastle.jsse.provider.SSLContext.TLSv1_3",
new EngineCreator()
{
public Object createInstance(Object constructorParameter)
{
return new ProvSSLContextSpi(fipsMode, cryptoProvider,
specifyClientProtocols("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");
}
doPut(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");
doPut(key, className);
creatorMap.put(className, creator);
}
void addAlias(String key, String value)
{
if (containsKey(key))
{
throw new IllegalStateException("duplicate provider key (" + key + ") found");
}
doPut(key, value);
}
public final Provider.Service getService(String type, String algorithm)
{
String upperCaseAlgName = Strings.toUpperCase(algorithm);
String serviceKey = type + "." + upperCaseAlgName;
BcJsseService service = serviceMap.get(serviceKey);
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 + "." + realName + " ";
List aliases = new ArrayList();
Map attributes = new HashMap();
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));
}
}
synchronized (this)
{
if (!serviceMap.containsKey(serviceKey))
{
service = new BcJsseService(this, type, upperCaseAlgName, className, aliases, getAttributeMap(attributes), creatorMap.get(className));
serviceMap.put(serviceKey, service);
}
else
{
service = serviceMap.get(serviceKey);
}
}
}
return service;
}
public synchronized final Set getServices()
{
Set serviceSet = super.getServices();
Set bcServiceSet = new HashSet();
for (Provider.Service service: serviceSet)
{
bcServiceSet.add(getService(service.getType(), service.getAlgorithm()));
}
return bcServiceSet;
}
private static final Map