Apache Camel Http and SSL - java

I have been trying to get a 2-way ssl/https proxy working with Camel. I have been able to set up the Jetty Component using 2-way ssl and am now attempting to get it working with the Http4 component to complete the client side of the proxy.
When I route the jetty traffic to a log component, all is well and the 2 way ssl trust chain is fine. When I throw in the Http4 component, it blows up with a peer not authenticated exception. I am using Camel 2.7.0
Here is what I have so far
public static void main(String[] args) throws Exception {
CamelContext context = new DefaultCamelContext();
JettyHttpComponent jetty = context.getComponent("jetty", JettyHttpComponent.class);
SslSelectChannelConnector sslConnector = new SslSelectChannelConnector();
sslConnector.setPort(9443);
sslConnector.setKeystore("/home/brian/jboss.keystore");
sslConnector.setKeyPassword("changeit");
sslConnector.setTruststore("/home/brian/jboss.truststore");
sslConnector.setTrustPassword("changeit");
sslConnector.setPassword("changeit");
sslConnector.setNeedClientAuth(true);
Map<Integer, SslSelectChannelConnector> connectors = new HashMap<Integer, SslSelectChannelConnector>();
connectors.put(9443, sslConnector);
jetty.setSslSocketConnectors(connectors);
final Endpoint jettyEndpoint = jetty.createEndpoint("jetty:https://localhost:9443/service");
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new FileInputStream(new File("/home/brian/User2.p12")), "Password1234!".toCharArray());
X509KeyManager keyManager = new CTSKeyManager(keystore, "user2", "Password1234!".toCharArray());
KeyManager[] keyManagers = new KeyManager[] { keyManager };
X509TrustManager trustManager = new EasyTrustManager();
TrustManager[] trustManagers = new TrustManager[] { trustManager };
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(keyManagers, trustManagers, null);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("https", 443, new SSLSocketFactory(sslcontext,
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)));
HttpComponent http4 = context.getComponent("http4", HttpComponent.class);
http4.setClientConnectionManager(new ThreadSafeClientConnManager(registry));
final Endpoint https4Endpoint = http4
.createEndpoint("https4://soafa-lite-staging:443/axis2/services/SigActService?bridgeEndpoint=true&throwExceptionOnFailure=false");
context.addRoutes(new RouteBuilder() {
#Override
public void configure() {
from(jettyEndpoint).to(https4Endpoint);
}
});
context.start();
context.stop();
}
private static class EasyTrustManager implements X509TrustManager {
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
private static class CTSKeyManager extends X509ExtendedKeyManager {
private final KeyStore keystore;
private final char[] privateKeyPassword;
private final String privateKeyAlias;
public CTSKeyManager(KeyStore keystore, String privateKeyAlias, char[] privateKeyPassword) {
this.keystore = keystore;
this.privateKeyAlias = privateKeyAlias;
this.privateKeyPassword = privateKeyPassword;
}
#Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
String[] serverAliases = null;
try {
List<String> aliasList = new ArrayList<String>();
int count = 0;
Enumeration<String> aliases = keystore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
aliasList.add(alias);
count++;
}
serverAliases = aliasList.toArray(new String[count]);
} catch (Exception e) {
}
return serverAliases;
}
#Override
public PrivateKey getPrivateKey(String alias) {
PrivateKey privateKey = null;
try {
privateKey = (PrivateKey) keystore.getKey(alias, privateKeyPassword);
} catch (Exception e) {
}
return privateKey;
}
#Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return privateKeyAlias == null ? null : new String[] { privateKeyAlias };
}
#Override
public X509Certificate[] getCertificateChain(String alias) {
X509Certificate[] x509 = null;
try {
Certificate[] certs = keystore.getCertificateChain(alias);
if (certs == null || certs.length == 0) {
return null;
}
x509 = new X509Certificate[certs.length];
for (int i = 0; i < certs.length; i++) {
x509[i] = (X509Certificate) certs[i];
}
} catch (Exception e) {
}
return x509;
}
#Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
return privateKeyAlias;
}
#Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
return privateKeyAlias;
}
#Override
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
return privateKeyAlias;
}
#Override
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {
return privateKeyAlias;
}
}
}
As far as I can tell, the trust should be fine between all keystores/truststores used on both sides of the proxy connections.
Here is my stack trace
[ qtp25584663-14] HttpProducer DEBUG Executing http POST method: https4://soafa-lite-staging:443/axis2/services/SigActService?bridgeEndpoint=true&throwExceptionOnFailure=false
[ qtp25584663-14] DefaultErrorHandler DEBUG Failed delivery for exchangeId: ID-ubuntu-46528-1303140195358-0-1. On delivery attempt: 0 caught: javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
[ qtp25584663-14] DefaultErrorHandler ERROR Failed delivery for exchangeId: ID-ubuntu-46528-1303140195358-0-1. Exhausted after delivery attempt: 1 caught: javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:390)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:561)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at org.apache.camel.component.http4.HttpProducer.executeMethod(HttpProducer.java:187)
at org.apache.camel.component.http4.HttpProducer.process(HttpProducer.java:101)
at org.apache.camel.impl.converter.AsyncProcessorTypeConverter$ProcessorToAsyncProcessorBridge.process(AsyncProcessorTypeConverter.java:50)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
at org.apache.camel.processor.SendProcessor$2.doInAsyncProducer(SendProcessor.java:104)
at org.apache.camel.impl.ProducerCache.doInAsyncProducer(ProducerCache.java:272)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:98)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
at org.apache.camel.processor.DelegateAsyncProcessor.processNext(DelegateAsyncProcessor.java:98)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:89)
at org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:99)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
at org.apache.camel.processor.RedeliveryErrorHandler.processErrorHandler(RedeliveryErrorHandler.java:299)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:208)
at org.apache.camel.processor.DefaultChannel.process(DefaultChannel.java:269)
at org.apache.camel.processor.UnitOfWorkProcessor.process(UnitOfWorkProcessor.java:109)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
at org.apache.camel.processor.DelegateAsyncProcessor.processNext(DelegateAsyncProcessor.java:98)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:89)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:68)
at org.apache.camel.component.jetty.CamelContinuationServlet.service(CamelContinuationServlet.java:109)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:534)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1351)
at org.eclipse.jetty.servlets.MultiPartFilter.doFilter(MultiPartFilter.java:97)
at org.apache.camel.component.jetty.CamelMultipartFilter.doFilter(CamelMultipartFilter.java:41)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1322)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:473)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:929)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:403)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:864)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:114)
at org.eclipse.jetty.server.Server.handle(Server.java:352)
at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:596)
at org.eclipse.jetty.server.HttpConnection$RequestHandler.content(HttpConnection.java:1068)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:805)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:218)
at org.eclipse.jetty.server.HttpConnection.handle(HttpConnection.java:426)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:508)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.access$000(SelectChannelEndPoint.java:34)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:40)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:451)
at java.lang.Thread.run(Thread.java:662)

Ok working now, as it turns out, I had a fundamental misunderstanding of endpoints and protocols within Camel. I should have been registering a scheme with the the https4 protocol and setting my SSLSocketFactory/SSLContext on it. Since it Was registering a scheme with https it was never been using by the Http4 component.
Here is my working solution with 2 caveats.
Why can't I pass in a SchemeRegistry to the ThreadSafeClientConnManager and it is not used when constructing the HttpClient? I have to the HttpClientConfigurer instead
Jetty has an issue where the Keystore and Truststore must be set by path on the SslSelectChannelConnector instead of via SSLContext (bug is in at least jetty 7.2.2 and 7.4.0 ->latest)
Code:
public class CamelProxy {
/**
* #param args
*/
public static void main(String[] args) throws Exception {
CamelContext context = new DefaultCamelContext();
final Endpoint jettyEndpoint = configureJetty(context);
final Endpoint https4Endpoint = configureHttpClient(context);
context.addRoutes(new RouteBuilder() {
#Override
public void configure() {
from(jettyEndpoint).to("log:com.smithforge.request?showAll=true").to(https4Endpoint);
}
});
context.start();
context.stop();
}
private static Endpoint configureHttpClient(CamelContext context) throws Exception {
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new FileInputStream(new File("/home/brian/User2.p12")), "Password1234!".toCharArray());
KeyStore truststore = KeyStore.getInstance("JKS");
truststore.load(new FileInputStream(new File("/home/brian/jboss.truststore")), "changeit".toCharArray());
KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("SunX509");
keyFactory.init(keystore, "Password1234!".toCharArray());
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("SunX509");
trustFactory.init(truststore);
SSLContext sslcontext = SSLContext.getInstance("TLSv1");
sslcontext.init(keyFactory.getKeyManagers(), trustFactory.getTrustManagers(), null);
SSLSocketFactory factory = new SSLSocketFactory(sslcontext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
SchemeRegistry registry = new SchemeRegistry();
final Scheme scheme = new Scheme("https4", 443, factory);
registry.register(scheme);
HttpComponent http4 = context.getComponent("http4", HttpComponent.class);
http4.setHttpClientConfigurer(new HttpClientConfigurer() {
#Override
public void configureHttpClient(HttpClient client) {
client.getConnectionManager().getSchemeRegistry().register(scheme);
}
});
http4.setClientConnectionManager(new ThreadSafeClientConnManager());
return http4
.createEndpoint("https4://soafa-lite-staging:443/axis2/services/SigActService?bridgeEndpoint=true&throwExceptionOnFailure=false");
}
private static Endpoint configureJetty(CamelContext context) throws Exception {
JettyHttpComponent jetty = context.getComponent("jetty", JettyHttpComponent.class);
SslSelectChannelConnector sslConnector = new SslSelectChannelConnector();
sslConnector.setPort(4443);
sslConnector.setKeystore("/home/brian/jboss.keystore");
sslConnector.setKeyPassword("changeit");
sslConnector.setTruststore("/home/brian/jboss.truststore");
sslConnector.setTrustPassword("changeit");
sslConnector.setPassword("changeit");
sslConnector.setNeedClientAuth(true);
sslConnector.setAllowRenegotiate(true);
Map<Integer, SslSelectChannelConnector> connectors = new HashMap<Integer, SslSelectChannelConnector>();
connectors.put(4443, sslConnector);
jetty.setSslSocketConnectors(connectors);
return jetty.createEndpoint("jetty:https://localhost:4443/service");
}
// .to("log:com.smithforge.response?showHeaders=true");
}

I got to work a ssl proxy with the following code
The route
public class MyRouteBuilder extends RouteBuilder {
public void configure() {
configureSslForJetty();
configureSslForHttp4();
from("jetty:https://0.0.0.0:4443/topython/?matchOnUriPrefix=true")
.to("https4://backend.fake.com:4444/?q=ssl&bridgeEndpoint=true&throwExceptionOnFailure=false");
}
...
Configuration for jetty (provide a certificate when we are acting as a server)
private void configureSslForJetty()
{
KeyStoreParameters ksp = new KeyStoreParameters();
ksp.setResource("c:\\Projects\\blah\\fakefilter.jks");
ksp.setPassword("123456");
KeyManagersParameters kmp = new KeyManagersParameters();
kmp.setKeyStore(ksp);
kmp.setKeyPassword("export-password");
SSLContextParameters scp = new SSLContextParameters();
scp.setKeyManagers(kmp);
JettyHttpComponent jettyComponent = getContext().getComponent("jetty", JettyHttpComponent.class);
jettyComponent.setSslContextParameters(scp);
}
Configuration for https4 (what certificate signers do we trust when acting as a client)
private void configureSslForHttp4()
{
KeyStoreParameters trust_ksp = new KeyStoreParameters();
trust_ksp.setResource("c:\\Projects\\blah\\fakeca.jks");
trust_ksp.setPassword("123456");
TrustManagersParameters trustp = new TrustManagersParameters();
trustp.setKeyStore(trust_ksp);
SSLContextParameters scp = new SSLContextParameters();
scp.setTrustManagers(trustp);
HttpComponent httpComponent = getContext().getComponent("https4", HttpComponent.class);
httpComponent.setSslContextParameters(scp);
}
}
Things worth noting
you need to configure component https4 not http4
-Djavax.net.debug=ssl in the command line provided lots of helpful logging

Looks like you're having problems with 'unsafe ssl renegotiation'. Please verify that you're using the latest JDK/JRE (at least 1.6.0_24).

Related

Consuming Java / Spring rest service using HTTPs(and certificate)

I have to consume a rest service which is running on HTTPs. The producer has given me the certificate and method arguments. Could you please let me know how to consume the service and how to use the certificate in code. I am using Spring 4, Java 8. Please share the code snippet.
If it is just an one way SSL where consumer validates the identity of the service, you simply need to import the certificate provided by the service(producers certificate) to you trust store (CACerts file) or write your own trust manager.
For 2 Way SSL where service also authenticate the client's identity, you not only need to validate the identity of the service, you also need to send your certificate to the service so that service can take decision on it.
Following snippet is for 2 way SSL, but you can easily adopt it to 1 way SSL by commenting out the portion which sends client certicate to the server.
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager(){
public X509Certificate[] getAcceptedIssuers(){return null;}
public void checkClientTrusted(X509Certificate[] certs, String authType){}
public void checkServerTrusted(X509Certificate[] certs, String authType){}
}};
// Install the all-trusting trust manager
RestTemplate restTemplate = new RestTemplate();
try {
String keyPassphrase = "changeit";
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(new FileInputStream("c:\\jks\\client.jks"), keyPassphrase.toCharArray());
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(keyStore, keyPassphrase.toCharArray());
KeyManager[] keyManager = kmfactory.getKeyManagers();
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(keyManager, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
if (hostname.equals("localhost")) {
return true;
}
return false;
}
});
} catch (Exception e) {
;
}
System.out.println("Testing listAllUsers API-----------");
restTemplate.setErrorHandler(new ResponseErrorHandler(){
#Override
public void handleError(ClientHttpResponse rs) throws IOException {
InputStream in = rs.getBody();
String str = new String("");
int len =0;
while((len = in.available()) > 0){
byte[] bytes = new byte[len];
in.read(bytes);
str = str + new String (bytes, "UTF-8");
}
System.out.println(str);
}
#Override
public boolean hasError(ClientHttpResponse rs) throws IOException {
return false;
}
});
try{
String usersMap = restTemplate.getForObject(REST_SERVICE_URI+"/user/shailendra/", String.class);`

Request with automatic or user selection of appropriate client certificate

I'm developing an hybrid cordova app which might connect to different servers. Some of them do require a client certificate.
On an Android mobile the corresponding root cert + client certificate is installed.
On Chrome browser I get the following dialog to choose the corresponding client certificate for the Web connection.
With the cordova plugin cordova-client-cert-authentication the same dialog pops up for Http(s) requests within the WebView.
My question is how to achieve a automatic certificate selection on Http(s) requests on the native Android platform without explicitly declaring the corresponding client certificate. Or is there something similiar to the user selection of certificate like implemented on Chrome?
This is the current implementation, which throws a handshake exception:
try {
URL url = new URL( versionUrl );
HttpsURLConnection urlConnection = ( HttpsURLConnection ) url.openConnection();
urlConnection.setConnectTimeout( 10000 );
InputStream in = urlConnection.getInputStream();
}
catch(Exception e)
{
//javax.net.ssl.SSLHandshakeException: Handshake failed
}
You can use a certificate previously installed in Android KeyChain (the system key store) extending X509ExtendedKeyManager to configure the SSLContext used by URLConnection
The certificate is referenced by an alias that you need. To prompt user for selection with a dialog similar to chrome use:
KeyChain.choosePrivateKeyAlias(this, this, // Callback
new String[] {"RSA", "DSA"}, // Any key types.
null, // Any issuers.
null, // Any host
-1, // Any port
DEFAULT_ALIAS);
This is the code to configure the SSL connection using a custom KeyManager. It uses the default TrustManager and HostnameVerifier. You will need to configure them if the server is using a self signed certificate not present in Android default truststore (trusting all certificates is not recommended)
//Configure trustManager if needed
TrustManager[] trustManagers = null;
//Configure keyManager to select the private key and the certificate chain from KeyChain
KeyManager keyManager = KeyChainKeyManager.fromAlias(
context, mClientCertAlias);
//Configure SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(new KeyManager[] {keyManager}, trustManagers, null);
//Perform the connection
URL url = new URL( versionUrl );
HttpsURLConnection urlConnection = ( HttpsURLConnection ) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
//urlConnection.setHostnameVerifier(hostnameVerifier); //Configure hostnameVerifier if needed
urlConnection.setConnectTimeout( 10000 );
InputStream in = urlConnection.getInputStream();
Finally here you have and a full implementation of the custom X509ExtendedKeyManager extracted from here and here that is in charge of selecting the client certificate. I have extracted the required code.
public static class KeyChainKeyManager extends X509ExtendedKeyManager {
private final String mClientAlias;
private final X509Certificate[] mCertificateChain;
private final PrivateKey mPrivateKey;
/**
* Builds an instance of a KeyChainKeyManager using the given certificate alias.
* If for any reason retrieval of the credentials from the system {#link android.security.KeyChain} fails,
* a {#code null} value will be returned.
*/
public static KeyChainKeyManager fromAlias(Context context, String alias)
throws CertificateException {
X509Certificate[] certificateChain;
try {
certificateChain = KeyChain.getCertificateChain(context, alias);
} catch (KeyChainException e) {
throw new CertificateException(e);
} catch (InterruptedException e) {
throw new CertificateException(e);
}
PrivateKey privateKey;
try {
privateKey = KeyChain.getPrivateKey(context, alias);
} catch (KeyChainException e) {
throw new CertificateException(e);
} catch (InterruptedException e) {
throw new CertificateException(e);
}
if (certificateChain == null || privateKey == null) {
throw new CertificateException("Can't access certificate from keystore");
}
return new KeyChainKeyManager(alias, certificateChain, privateKey);
}
private KeyChainKeyManager(
String clientAlias, X509Certificate[] certificateChain, PrivateKey privateKey) {
mClientAlias = clientAlias;
mCertificateChain = certificateChain;
mPrivateKey = privateKey;
}
#Override
public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) {
return mClientAlias;
}
#Override
public X509Certificate[] getCertificateChain(String alias) {
return mCertificateChain;
}
#Override
public PrivateKey getPrivateKey(String alias) {
return mPrivateKey;
}
#Override
public final String chooseServerAlias( String keyType, Principal[] issuers, Socket socket) {
// not a client SSLSocket callback
throw new UnsupportedOperationException();
}
#Override
public final String[] getClientAliases(String keyType, Principal[] issuers) {
// not a client SSLSocket callback
throw new UnsupportedOperationException();
}
#Override
public final String[] getServerAliases(String keyType, Principal[] issuers) {
// not a client SSLSocket callback
throw new UnsupportedOperationException();
}
}
}
I did not test it. Report any error!
If your URLs are still in development stage (not production version), you can skip those SSL/NON-SSL certificates installing to access the URLs.
Here is how to skip SSL validation :
Call when activity onCreate() or where your need before accessing URL.
public static void skipSSLValidation() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
/* Create a new array with room for an additional trusted certificate. */
return new X509Certificate[0];
}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
#Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
// pass
}
}
Note : If your HTTPS URLs are valid, you will no require to use server-generated certificates. You should using this method for testing/development only. For release/production you don't have to use this method.

Does OkHttp support accepting self-signed SSL certs?

I'm working for a customer who has a server with self-signed SSL cert.
I'm using Retrofit + CustomClient using wrapped OkHttp client:
RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(Config.BASE_URL + Config.API_VERSION)
.setClient(new CustomClient(new OkClient(), context))
.build();
Does OkHttp support calling Self-Signed SSL cert server by default?
By the way. Which client is using Retrofit by default? I thought it was OkHttp but when I researched a bit more I realized I needed to import OkHttp dependencies
Yes, It does.
Retrofit allows you to set your custom HTTP client, that is configured to your needs.
As for self-signed SSL certs there is a discussion here. The link contains code samples to add self-signed SSL to Android's DefaultHttpClient and to load this client to Retrofit.
If you need OkHttpClient to accept self signed SSL, you need to pass it custom javax.net.ssl.SSLSocketFactory instance via setSslSocketFactory(SSLSocketFactory sslSocketFactory) method.
The easiest method to get a socket factory is to get one from javax.net.ssl.SSLContext as discussed here.
Here is a sample for configuring OkHttpClient:
OkHttpClient client = new OkHttpClient();
KeyStore keyStore = readKeyStore(); //your method to obtain KeyStore
SSLContext sslContext = SSLContext.getInstance("SSL");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "keystore_pass".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(),trustManagerFactory.getTrustManagers(), new SecureRandom());
client.setSslSocketFactory(sslContext.getSocketFactory());
Updated code for okhttp3 (using builder):
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory())
.build();
the client here is now configured to use certificates from your KeyStore. However it will only trust the certificates in your KeyStore and will not trust anything else, even if your system trust them by default. (If you have only self signed certs in your KeyStore and try to connect to Google main page via HTTPS you will get SSLHandshakeException).
You can obtain KeyStore instance from file as seen in docs:
KeyStore readKeyStore() {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
// get user password and file input stream
char[] password = getPassword();
java.io.FileInputStream fis = null;
try {
fis = new java.io.FileInputStream("keyStoreName");
ks.load(fis, password);
} finally {
if (fis != null) {
fis.close();
}
}
return ks;
}
If you are on android you can put it in res/raw folder and get it from a Context instance using
fis = context.getResources().openRawResource(R.raw.your_keystore_filename);
There are several discussions on how to create your keystore. For example here
Another thing to note, if you pre-install the CA on the device, you can make regular https calls with OKHttp, and no special ssl hoops. The key is to add the network security configs to your manifest.
The key for me to know to do this was that I was getting the following exception.
"Trust anchor for certification path not found."
Here is a good article from Google about how to configure it.
https://developer.android.com/training/articles/security-config
Here is an example of my network_security_config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="user"/>
<certificates src="system"/>
</trust-anchors>
</base-config>
</network-security-config>
For okhttp3.OkHttpClient Version com.squareup.okhttp3:okhttp:3.2.0 you have to use the code below :
import okhttp3.Call;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
......
OkHttpClient.Builder clientBuilder = client.newBuilder().readTimeout(LOGIN_TIMEOUT_SEC, TimeUnit.SECONDS);
boolean allowUntrusted = true;
if ( allowUntrusted) {
Log.w(TAG,"**** Allow untrusted SSL connection ****");
final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] cArrr = new X509Certificate[0];
return cArrr;
}
#Override
public void checkServerTrusted(final X509Certificate[] chain,
final String authType) throws CertificateException {
}
#Override
public void checkClientTrusted(final X509Certificate[] chain,
final String authType) throws CertificateException {
}
}};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
clientBuilder.sslSocketFactory(sslContext.getSocketFactory());
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
Log.d(TAG, "Trust Host :" + hostname);
return true;
}
};
clientBuilder.hostnameVerifier( hostnameVerifier);
}
final Call call = clientBuilder.build().newCall(request);
Two methods from our app to get OkHttpClient 3.0 instance that recognizes your self-signed certificates from your keystore (uses prepared pkcs12 certificate file in your Android project "raw" resources folder):
private static OkHttpClient getSSLClient(Context context) throws
NoSuchAlgorithmException,
KeyStoreException,
KeyManagementException,
CertificateException,
IOException {
OkHttpClient client;
SSLContext sslContext;
SSLSocketFactory sslSocketFactory;
TrustManager[] trustManagers;
TrustManagerFactory trustManagerFactory;
X509TrustManager trustManager;
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(readKeyStore(context));
trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
}
trustManager = (X509TrustManager) trustManagers[0];
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{trustManager}, null);
sslSocketFactory = sslContext.getSocketFactory();
client = new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.build();
return client;
}
/**
* Get keys store. Key file should be encrypted with pkcs12 standard. It can be done with standalone encrypting java applications like "keytool". File password is also required.
*
* #param context Activity or some other context.
* #return Keys store.
* #throws KeyStoreException
* #throws CertificateException
* #throws NoSuchAlgorithmException
* #throws IOException
*/
private static KeyStore readKeyStore(Context context) throws
KeyStoreException,
CertificateException,
NoSuchAlgorithmException,
IOException {
KeyStore keyStore;
char[] PASSWORD = "12345678".toCharArray();
ArrayList<InputStream> certificates;
int certificateIndex;
InputStream certificate;
certificates = new ArrayList<>();
certificates.add(context.getResources().openRawResource(R.raw.ssl_pkcs12));
keyStore = KeyStore.getInstance("pkcs12");
for (Certificate certificate : certificates) {
try {
keyStore.load(certificate, PASSWORD);
} finally {
if (certificate != null) {
certificate.close();
}
}
}
return keyStore;
}
I had the same problem and I fixed it with the okhttp client as follow:
1.) Add the certificate file to src/main/res/raw/, which includes this content:
-----BEGIN CERTIFICATE-----
...=
-----END CERTIFICATE-----
2.) Instanciate the okHttpClient:
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(getSslContext(context).getSocketFactory())
.build();
3.) Here is the used getSslContext(Context context) method:
SSLContext getSslContext(Context context) throws Exception {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); // "BKS"
ks.load(null, null);
InputStream is = context.getResources().openRawResource(R.raw.certificate);
String certificate = Converter.convertStreamToString(is);
// generate input stream for certificate factory
InputStream stream = IOUtils.toInputStream(certificate);
// CertificateFactory
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// certificate
Certificate ca;
try {
ca = cf.generateCertificate(stream);
} finally {
is.close();
}
ks.setCertificateEntry("my-ca", ca);
// TrustManagerFactory
String algorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
// Create a TrustManager that trusts the CAs in our KeyStore
tmf.init(ks);
// Create a SSLContext with the certificate that uses tmf (TrustManager)
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
return sslContext;
}
If there is the need to add multiple certificates to the SslContext, here is the solution.
Against Retrofit 1.9 I was able to accept any certificate with the following strategy: use at your own risk! Accepting any certificate is dangerous and you should understand the consequences. Some relevant parts come from org.apache.http.ssl, so you may require some imports here.
// ...
Client httpClient = getHttpClient();
RestAdapter adapter = new RestAdapter.Builder()
.setClient(httpClient)
// ... the rest of your builder setup
.build();
// ...
private Client getHttpClient() {
try {
// Allow self-signed (and actually any) SSL certificate to be trusted in this context
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
sslContext.getSocketFactory();
SSLSocketFactory sf = sslContext.getSocketFactory();
OkHttpClient client = new OkHttpClient();
client.setSslSocketFactory(sf);
return new OkClient(client);
} catch (Exception e) {
throw new RuntimeException("Failed to create new HTTP client", e);
}
}
I know that this post is quite old, bui i want to share the solution that worked for me with the latest update of OkHttp, the 3.12.1 version in the time i'm writing.
First of all you need to obtain the KeyStore object that will be then added to the TrustManager:
/**
* #param context The Android context to be used for retrieving the keystore from raw resource
* #return the KeyStore read or null on error
*/
private static KeyStore readKeyStore(Context context) {
char[] password = "keystore_password".toCharArray();
// for non-android usage:
// try(FileInputStream is = new FileInputStream(keystoreName)) {
try(InputStream is = context.getResources().openRawResource(R.raw.keystore)) {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(is, password);
return ks;
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
return null;
}
Now you can get the builded OkHttpClient with the self-signed certificate in your keystore:
/**
* #param context The Android context used to obtain the KeyStore
* #return the builded OkHttpClient or null on error
*/
public static OkHttpClient getOkHttpClient(Context context) {
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(readKeyStore(context));
X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{trustManager}, null);
return new OkHttpClient.Builder()
.hostnameVerifier((hostname, session) -> {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
/* Never return true without verifying the hostname, otherwise you will be vulnerable
to man in the middle attacks. */
return hv.verify("your_hostname_here", session);
})
.sslSocketFactory(sslContext.getSocketFactory(), trustManager)
.build();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Remember that it is highly discouraged to return always true in the hostnameVerifier to avoid risk of man in the middle attacks.
I find answer from :
https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java
It uses HandshakeCertificates to add certificates.
HandshakeCertificates certificates = new HandshakeCertificates.Builder()
.addTrustedCertificate(letsEncryptCertificateAuthority)
.addTrustedCertificate(entrustRootCertificateAuthority)
.addTrustedCertificate(comodoRsaCertificationAuthority)
// Uncomment if standard certificates are also required.
//.addPlatformTrustedCertificates()
.build();
client = new OkHttpClient.Builder()
.sslSocketFactory(certificates.sslSocketFactory(), certificates.trustManager())
.build();
If you have trust certificates in store, you can use it as below:
.......
List<X509Certificate> certificates = getCertificatesFromTrustStore();
Builder certificateBuilder = new HandshakeCertificates.Builder();
for (X509Certificate x509Certificate : certificates) {
certificateBuilder.addTrustedCertificate(x509Certificate);
}
HandshakeCertificates handshakeCertificates = certificateBuilder.build();
.......
//To get certificates from a keystore
private List<X509Certificate> getCertificatesFromTrustStore() throws Exception {
KeyStore truststore = KeyStore.getInstance("JKS");
truststore.load(new FileInputStream("d:\certs.jsk"), "mypassword".toCharArray());
PKIXParameters params = new PKIXParameters(truststore);
Set<TrustAnchor> trustAnchors = params.getTrustAnchors();
LOG.debug("{} certificates found in {} which will be used", trustAnchors.size(), trustStorePath);
List<X509Certificate> certificates = trustAnchors.stream()
.map(TrustAnchor::getTrustedCert)
.collect(Collectors.toList());
return certificates;
}
If you need to provide your own certificate, you can pass it like this:
Manifest:
<application android:networkSecurityConfig="#xml/network_security_config"
... >
res/xml/network_security_config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="#raw/your_PEM_formatted_cert" />
<certificates src="user" />
<certificates src="system" />
</trust-anchors>
</base-config>
The following piece of code allows you to create an OkHttp client that can be used with Retrofit. Mailmustdie's answer is "better" in the sense that it is more secure, but the code snippet below is faster to implement
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.ResponseBody;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import okio.BufferedSink;
import retrofit.client.Header;
import retrofit.client.OkClient;
import retrofit.client.Request;
import retrofit.client.Response;
import retrofit.mime.TypedInput;
import retrofit.mime.TypedOutput;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class TrustingOkClient extends OkClient {
static final int CONNECT_TIMEOUT_MILLIS = 15 * 1000; // 15s
static final int READ_TIMEOUT_MILLIS = 20 * 1000; // 20s
private static OkHttpClient generateDefaultOkHttp() {
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
client.setReadTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
final TrustManager[] certs = new TrustManager[]{new X509TrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkServerTrusted(final X509Certificate[] chain,
final String authType) throws CertificateException {
}
#Override
public void checkClientTrusted(final X509Certificate[] chain,
final String authType) throws CertificateException {
}
}};
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("TLS");
ctx.init(null, certs, new SecureRandom());
} catch (final java.security.GeneralSecurityException ex) {
}
try {
final HostnameVerifier hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(final String hostname,
final SSLSession session) {
return true;
}
};
client.setHostnameVerifier(hostnameVerifier);
client.setSslSocketFactory(ctx.getSocketFactory());
} catch (final Exception e) {
}
return client;
}
private final OkHttpClient client;
public TrustingOkClient() {
this(generateDefaultOkHttp());
}
public TrustingOkClient(OkHttpClient client) {
if (client == null) throw new NullPointerException("client == null");
this.client = client;
}
#Override public Response execute(Request request) throws IOException {
return parseResponse(client.newCall(createRequest(request)).execute());
}
static com.squareup.okhttp.Request createRequest(Request request) {
com.squareup.okhttp.Request.Builder builder = new com.squareup.okhttp.Request.Builder()
.url(request.getUrl())
.method(request.getMethod(), createRequestBody(request.getBody()));
List<Header> headers = request.getHeaders();
for (int i = 0, size = headers.size(); i < size; i++) {
Header header = headers.get(i);
String value = header.getValue();
if (value == null) value = "";
builder.addHeader(header.getName(), value);
}
return builder.build();
}
static Response parseResponse(com.squareup.okhttp.Response response) {
return new Response(response.request().urlString(), response.code(), response.message(),
createHeaders(response.headers()), createResponseBody(response.body()));
}
private static RequestBody createRequestBody(final TypedOutput body) {
if (body == null) {
return null;
}
final MediaType mediaType = MediaType.parse(body.mimeType());
return new RequestBody() {
#Override public MediaType contentType() {
return mediaType;
}
#Override public void writeTo(BufferedSink sink) throws IOException {
body.writeTo(sink.outputStream());
}
#Override public long contentLength() {
return body.length();
}
};
}
private static TypedInput createResponseBody(final ResponseBody body) {
try {
if (body.contentLength() == 0) {
return null;
}
return new TypedInput() {
#Override public String mimeType() {
MediaType mediaType = body.contentType();
return mediaType == null ? null : mediaType.toString();
}
#Override public long length() {
try {
return body.contentLength();
} catch (Exception exception) {
System.out.println(exception.toString());
}
throw new Error("createResponseBody has invalid length for its response");
}
#Override public InputStream in() throws IOException {
return body.byteStream();
}
};
} catch (Exception exception) {
System.out.println(exception.toString());
}
throw new Error("createResponseBody has invalid content length for its response");
}
private static List<Header> createHeaders(Headers headers) {
int size = headers.size();
List<Header> headerList = new ArrayList<Header>(size);
for (int i = 0; i < size; i++) {
headerList.add(new Header(headers.name(i), headers.value(i)));
}
return headerList;
}
}

Soap SSL handshake

My client is successfully getting response from server through HTTP.
SOAPConnectionFactory sfc = SOAPConnectionFactory.newInstance();
SOAPConnection connection = sfc.createConnection();
SOAPMessage soapMessageResponse = connection.call(soapRequest, new URL(serviceLocation));
I want SSL communication between client/server.
In another project I am successfully creating SSLSocketFactory from a KeyStore and TrustManagerFactory for SSL handshake.
How can I use SSLSocketFactory code in webservice client to make client SSL communication successful to call server.
I'm pretty sure it will use the default SSLContext. You can change that with SSLContext.setDefault().
SSLContext c = SSLContext.getInstance("SSL");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(yourKeystore);
TrustManager tm = tmf.getTrustManagers()[0];
tm.
c.init(null, tm, null);
Here are some other values for the string parameters above.
If you need more complete control, you can implement your own subclass of SSLContext which returns your own implementation of SSLSocketFactory and set that SSLContext as the default:
public class MySSLContext extends SSLContext {
private SSLContext wrapped;
private SSLSocketFactory mySocketFactory;
public MySSLContext(SSLContext toWrap, SSLSocketFactory mySocketFactory) {
wrapped = toWrap;
this.mySocketFactory = mySocketFactory;
}
public SSLSocketFactory getSocketFactory() {
return mySocketFactory;
}
public SSLSessionContext getClientSessionContext() {
return wrapped;
}
// other delegates
}
Hi if you add this code your webservice class ı think your problem will be solve .
`
//just put it your somewhere
public static class miTM implements javax.net.ssl.TrustManager,
javax.net.ssl.X509TrustManager {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
}
// CAll This function in your webservice class .
private static void trustAllHttpsCertificates() throws Exception {
// Create a trust manager that does not validate certificate chains:
javax.net.ssl.TrustManager[] trustAllCerts =
new javax.net.ssl.TrustManager[1];
javax.net.ssl.TrustManager tm = new miTM();
trustAllCerts[0] = tm;
javax.net.ssl.SSLContext sc =
javax.net.ssl.SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(
sc.getSocketFactory());
}
This line of code will not work in case of SSL.
SOAPMessage soapMessageResponse = connection.call(soapRequest, new URL(serviceLocation));
Create trustmanager and keymanagers from here.
In order to get response through SSL from axis2 webservice you need to open streams like given here

SSL/TLS error ("no cipher suites in common") with Netty when trying to establish a secure connection between a frontend and a backend

I want to secure a TCP connection between a backend and a frontend. We use Netty to establish a TCP connection which works pretty well. Now, we want to secure this connection by using SSL/TLS. For that reason I created a certificate request:
openssl req -newkey rsa:2048 -keyout key.pem -out request.pem -subj '/C=DE/O=XX/ST=XX/L=XX/O=XX/OU=XX/CN=someaddress.de/emailAddress=support#xxx.de'
The certificate was then created by the CA.
The keystore was created with:
keytool -import -alias xxx -keystore xxx.keystore -file cert-xxx.pem
Server with Netty at the backend:
public StatefulTcpServer(MessageHandler messageHandler, int port, KeyStore keyStore, String keyStorePassword) {
this.messageHandler = messageHandler;
factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
allChannels = new DefaultChannelGroup("clients");
initTLS(keyStore, keyStorePassword);
ServerBootstrap bootstrap = new ServerBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = Channels.pipeline();
if (sslContext != null) {
SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(false);
sslEngine.setEnabledCipherSuites(new String[] {
"TLS_RSA_WITH_AES_128_CBC_SHA"
});
pipeline.addLast("ssl", new SslHandler(sslEngine));
}
pipeline.addLast("compressor", new ZlibEncoder());
pipeline.addLast("decompressor", new ZlibDecoder());
pipeline.addLast("decoder", new JBossSerializationDecoder());
pipeline.addLast("encoder", new JBossSerializationEncoder());
pipeline.addLast("handler", StatefulTcpServer.this);
return pipeline;
}
});
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.bind(new InetSocketAddress(port));
}
private void initTLS(KeyStore keyStore, String keyStorePassword) {
try {
if (keyStore != null) {
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyStorePassword.toCharArray());
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
}
}
catch (GeneralSecurityException e) {
logger.error("TLS connection could not be established", e);
sslContext = null;
}
}
Server with Netty in the frontend:
public void init(String backendHost, int backendPort, int timeOutSecs, boolean useTLS,
boolean acceptOnlyTrustworthyCertsForTLS) throws ConnectionFailedException {
channelFactory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
if (useTLS) {
initTLS(acceptOnlyTrustworthyCertsForTLS);
}
ClientBootstrap bootstrap = new ClientBootstrap(channelFactory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = Channels.pipeline();
if (sslContext != null) {
SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(true);
sslEngine.setEnabledCipherSuites(new String[] {
"TLS_RSA_WITH_AES_128_CBC_SHA"
});
pipeline.addLast("ssl", new SslHandler(sslEngine));
}
pipeline.addLast("compressor", new ZlibEncoder());
pipeline.addLast("decompressor", new ZlibDecoder());
pipeline.addLast("decoder", new JBossSerializationDecoder());
pipeline.addLast("encoder", new JBossSerializationEncoder());
pipeline.addLast("handler", StatefulTcpBackendCommunicator.this);
return pipeline;
}
});
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true);
channelFuture = bootstrap.connect(new InetSocketAddress(backendHost, backendPort));
try {
boolean connected = channelFuture.await(timeOutSecs * 1000);
if (!connected || !channelFuture.isSuccess()) {
throw new ConnectionFailedException();
}
}
catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
private void initTLS(boolean acceptOnlyTrustworthyCertsForTLS) {
try {
TrustManager[] trustManagers;
if (acceptOnlyTrustworthyCertsForTLS) {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory
.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
trustManagers = trustManagerFactory.getTrustManagers();
}
else {
trustManagers = new TrustManager[] {
new X509TrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
return;
}
#Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
return;
}
}
};
}
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, new SecureRandom());
}
catch (GeneralSecurityException e) {
logger.error("TLS connection could not be established. TLS is not used!", e);
sslContext = null;
}
}
When trying to establish the connection between frontend and backend I get an exception:
javax.net.ssl.SSLHandshakeException: no cipher suites in common
This post was unfortunately not helpful. Is there something wrong with the configuration of the servers? Or do I use the wrong certificate type?

Categories

Resources