Android SSL issues - java

I am having problems in connecting server using ssl from android emulater. I have created public key using portecle(bks).When i used to connect server,authentication is not taking place.Logcat is not showing any error but ssl connection is not working.
My Source Code:
import android.content.Context;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import com.myclinicmyway.*;
import java.io.InputStream;
import java.security.KeyStore;
public class MyHttpClient extends DefaultHttpClient {
public final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
//"http", PlainSocketFactory.getSocketFactory(), 80
#Override protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}// end of client connection
private SSLSocketFactory newSslSocketFactory() {
try {
KeyStore trusted = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.docinbangalorefinals);
try {
trusted.load(in, "docinbangalore".toCharArray());
} finally {
in.close();
}
return new SSLSocketFactory(trusted);
}
catch (Exception e) {
throw new AssertionError(e);
}// end of catch
}// end of ssl socket
}// end of clas

I got the solution.Following code worked for me.
public class MyHttpClient extends DefaultHttpClient {
final Context context;
TrustManager easyTrustManager = new 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;
}
};
public MyHttpClient(Context context) {
this.context = context;
}
#Override protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private MySSLSocketFactory newSslSocketFactory() {
try {
KeyStore trusted = KeyStore.getInstance("BKS");
try {
trusted.load(null, null);
} finally {
}
MySSLSocketFactory sslfactory = new MySSLSocketFactory(trusted);
sslfactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
return sslfactory;
} catch (Exception e) {
throw new AssertionError(e);
}
}
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
#Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
#Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
}

Related

Spring Boot socket-io-client v1 does not emit to the socket.io server with ssl

We were using socket.io server v2.3.0 without SSL. The js frontend client and the spring boot client were sending and receiving messages using that socket.io server.
Now, we are using SSL. The js frontend is working properly but the spring boot client does not emit any messages to the socket.io server. Here is my source code for emitting messages to the socket.io server. It was working without ssl. I changed the URL and set HTTPS for that.
IO.Options options = new IO.Options();
options.transports = new String[]{"websocket"};
options.reconnectionAttempts = 2;
options.reconnectionDelay = 1000;
options.timeout = 500;
final Socket socket = IO.socket(socketServerURL, options);
socket.on(Socket.EVENT_CONNECT, args1 -> socket.send("hello..."));
socket.on("connected", objects -> System.out.println("Server connected: " + objects[0].toString()));
socket.on("push_data_event", objects -> System.out.println("Server:" + objects[0].toString()));
socket.on("myBroadcast", objects -> System.out.println("Server:" + objects[0].toString()));
socket.connect();
socket.emit("chanel_name", message);
What is the problem? the versions are like the following:
Socket server:2.3.0
Socket js client: 2.3.0
Socket io-client: 1.0.0
The problem is solved by adding a static class and pass the options of the socket to this function. It adds some parameters to the option and solves the problem.
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
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;
import io.socket.client.IO;
import okhttp3.OkHttpClient;
public class SocketSSL {
public static OkHttpClient getOkHttpClient() {
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new 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 new X509Certificate[0];
}
}}, new java.security.SecureRandom());
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
builder.sslSocketFactory(sc.getSocketFactory(), new 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 new X509Certificate[0];
}
});
return builder.build();
} catch (NoSuchAlgorithmException | KeyManagementException ex) {
ex.printStackTrace();
}
return null;
}
public static void set(IO.Options options) {
OkHttpClient okHttpClient = getOkHttpClient();
IO.setDefaultOkHttpWebSocketFactory(okHttpClient);
IO.setDefaultOkHttpCallFactory(okHttpClient);
options.callFactory = okHttpClient;
options.webSocketFactory = okHttpClient;
}
}
The source code changed to the following:
IO.Options options = new IO.Options();
options.transports = new String[]{"websocket"};
options.reconnectionAttempts = 2;
options.reconnectionDelay = 1000;
options.timeout = 500;
options.rememberUpgrade = true;
options.secure = true;
//usage of the class
SocketSSL.set(options);
final Socket socket = IO.socket(socketServerURL, options);
socket.on(Socket.EVENT_CONNECT, args1 -> socket.send("hello..."));
socket.on("connected", objects -> System.out.println("Server connected: " + objects[0].toString()));
socket.on("push_data_event", objects -> System.out.println("Server:" + objects[0].toString()));
socket.on("myBroadcast", objects -> System.out.println("Server:" + objects[0].toString()));
socket.connect();
socket.emit("chanel_name", message);

How to fix SSLProtocolException: handshake alert: unrecognized_name without disabling SNI

I've made a crawler application that for some website fail to connect due to the error "handshake alert: unrecognized_name".
Most of the solutions I found is by disabling the SNI extension(jsse.enableSNIExtension=false). But this creates problems with the domains that require SNI enabled.
How can I disable it only for some domains?
To do the crawling I'm using Jsoup, and because I'm also using proxies I've added this code at startup.
private static void disableSslVerification() {
TrustManager[] trustAllCertificates = new TrustManager[] {
new X509TrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
return null; // Not relevant.
}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Do nothing. Just allow them all.
}
#Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// Do nothing. Just allow them all.
}
}
};
HostnameVerifier trustAllHostnames = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true; // Just allow them all.
}
};
try {
System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");
// System.setProperty("jsse.enableSNIExtension", "false");
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCertificates, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(trustAllHostnames);
}
catch (GeneralSecurityException e) {
throw new ExceptionInInitializerError(e);
}
}
As you can see the SNIextension is commented. I would appreciate an example.
The url I'm trying to access is the next one.
https://www.ocinerioshopping.es/
I managed to solve the issue by extending the SSLSocketConnection and by sending null instead of the hostname when the createSocket is called. That way java disables the SNI. Then I just pass a instance of the new class to Jsoup where I know the SNI will fail.
import javax.net.ssl.*;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public class CustomSSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory defaultFactory;
public CustomSSLSocketFactory() throws IOException {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init((KeyManager[])null, trustAllCerts, new SecureRandom());
defaultFactory = sslContext.getSocketFactory();
} catch (KeyManagementException | NoSuchAlgorithmException var3) {
throw new IOException("Can't create unsecure trust manager");
}
}
#Override
public String[] getDefaultCipherSuites() {
return defaultFactory.getDefaultCipherSuites();
}
#Override
public String[] getSupportedCipherSuites() {
return defaultFactory.getSupportedCipherSuites();
}
#Override
public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
//magic happens here, we send null as hostname
return defaultFactory.createSocket(socket, null, i, b);
}
#Override
public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
return defaultFactory.createSocket(s,i);
}
#Override
public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
return defaultFactory.createSocket(s,i,inetAddress,i1);
}
#Override
public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
return defaultFactory.createSocket(inetAddress, i);
}
#Override
public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
return defaultFactory.createSocket(inetAddress,i, inetAddress1, i1);
}
}
Jsoup initialization.
Connection conn = Jsoup.connect(url);
conn.sslSocketFactory(new CustomSSLSocketFactory());

Client certificate authentication with com.sun.net.httpsserver

I have combined client-certificate-with-com-sun-net-httpserver-httpsserver
with simple-java-https-server but I always get the error message
SSL-Peer could not be verified.
I call setWantClientAuth(true) and verify Authentification by calling
Certificate[] peerCerts = pHttpsExchange.getSSLSession().getPeerCertificates();
The server is running with JDK 1.8 and the client is running on Android. The server Code is:
package de.org.vnetz;
import java.io.*;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import com.sun.net.httpserver.*;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.net.ssl.SSLContext;
import javax.security.auth.x500.X500Principal;
import java.security.cert.Certificate;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class clsHTTPSServer {
final static String SERVER_PWD = "xxxxxx";
final static String KST_SERVER = "server.jks";
final static String TST_SERVER = "servertrust.jks";
private static final int PORT = 9999;
public static class MyHandler implements HttpHandler {
// whether to use client cert authentication
private final boolean useClientCertAuth = true;
private List<LdapName> allowedPrincipals = new ArrayList<LdapName>();
private final boolean extendedClientCheck = true;
private static final String CLIENTAUTH_OID = "1.3.6.1.5.5.7.3.2";
#Override
public void handle(HttpExchange t) throws IOException {
String response = "Hallo Natalie!";
HttpsExchange httpsExchange = (HttpsExchange) t;
boolean auth;
try
{
checkAuthentication(httpsExchange);
auth = true;
}
catch (Exception ex)
{
response = ex.getMessage();
auth = false;
}
boolean res = httpsExchange.getSSLSession().isValid();
if (res) {
String qry = httpsExchange.getRequestURI().getQuery();
if (qry!=null && qry.startsWith("qry=")) {
httpsExchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
httpsExchange.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
else
{
httpsExchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
httpsExchange.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write((response + " no query!").getBytes());
os.close();
}
}
}
// Verify https certs if its Https request and we have SSL auth enabled. Will be called before
// handling the request
protected void checkAuthentication(HttpExchange pHttpExchange) throws SecurityException {
// Cast will always work since this handler is only used for Http
HttpsExchange httpsExchange = (HttpsExchange) pHttpExchange;
if (useClientCertAuth) {
checkCertForClientUsage(httpsExchange);
checkCertForAllowedPrincipals(httpsExchange);
}
}
// Check the cert's principal against the list of given allowedPrincipals.
// If no allowedPrincipals are given than every principal is allowed.
// If an empty list as allowedPrincipals is given, no one is allowed to access
private void checkCertForClientUsage(HttpsExchange pHttpsExchange) {
try {
String host = pHttpsExchange.getSSLSession().getPeerHost();
//Principal p = pHttpsExchange.getSSLSession().getPeerPrincipal();
String pr = pHttpsExchange.getSSLSession().getProtocol();
Certificate[] peerCerts = pHttpsExchange.getSSLSession().getPeerCertificates();
if (peerCerts != null && peerCerts.length > 0) {
X509Certificate clientCert = (X509Certificate) peerCerts[0];
// We required that the extended key usage must be present if we are using
// client cert authentication
if (extendedClientCheck &&
(clientCert.getExtendedKeyUsage() == null || !clientCert.getExtendedKeyUsage().contains(CLIENTAUTH_OID))) {
throw new SecurityException("No extended key usage available");
}
}
} catch (ClassCastException e) {
throw new SecurityException("No X509 client certificate");
} catch (CertificateParsingException e) {
throw new SecurityException("Can't parse client cert");
} catch (SSLPeerUnverifiedException e) {
throw new SecurityException("SSL Peer couldn't be verified");
}
}
private void checkCertForAllowedPrincipals(HttpsExchange pHttpsExchange) {
if (allowedPrincipals != null) {
X500Principal certPrincipal;
try {
certPrincipal = (X500Principal) pHttpsExchange.getSSLSession().getPeerPrincipal();
Set<Rdn> certPrincipalRdns = getPrincipalRdns(certPrincipal);
for (LdapName principal : allowedPrincipals) {
for (Rdn rdn : principal.getRdns()) {
if (!certPrincipalRdns.contains(rdn)) {
throw new SecurityException("Principal " + certPrincipal + " not allowed");
}
}
}
} catch (SSLPeerUnverifiedException e) {
throw new SecurityException("SSLPeer unverified");
} catch (ClassCastException e) {
throw new SecurityException("Internal: Invalid Principal class provided " + e);
}
}
}
private Set<Rdn> getPrincipalRdns(X500Principal principal) {
try {
LdapName certAsLdapName =new LdapName(principal.getName());
return new HashSet<Rdn>(certAsLdapName.getRdns());
} catch (InvalidNameException e) {
throw new SecurityException("Cannot parse '" + principal + "' as LDAP name");
}
}
}
/**
* #param args
*/
public static void main(String[] args) throws Exception {
try {
// setup the socket address
InetSocketAddress address = new InetSocketAddress(PORT);
// initialise the HTTPS server
HttpsServer httpsServer = HttpsServer.create(address, 0);
SSLContext sslContext = SSLContext.getInstance("TLS");
// initialise the keystore
// char[] password = "password".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream(KST_SERVER);// ("testkey.jks");
ks.load(fis, SERVER_PWD.toCharArray());// password);
// setup the key manager factory
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, SERVER_PWD.toCharArray());
// setup the trust manager factory
// TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
// tmf.init(ks);
KeyStore ts = KeyStore.getInstance("JKS");
ts.load(new FileInputStream(TST_SERVER), SERVER_PWD.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
// setup the HTTPS context and parameters
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLParameters sslp = sslContext.getSupportedSSLParameters();
//sslp.setNeedClientAuth(true);
sslp.setWantClientAuth(true);
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
public void configure(HttpsParameters params) {
try {
// initialise the SSL context
SSLContext c = SSLContext.getDefault();
SSLEngine engine = c.createSSLEngine();
//params.setNeedClientAuth(true);
params.setWantClientAuth(true);
params.setCipherSuites(engine.getEnabledCipherSuites());
params.setProtocols(engine.getEnabledProtocols());
// get the default parameters
SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
SSLParameters sslParams = sslContext.getDefaultSSLParameters();
//sslParams.setNeedClientAuth(true);
sslParams.setWantClientAuth(true);
params.setSSLParameters(defaultSSLParameters);
} catch (Exception ex) {
System.out.println("Failed to create HTTPS port");
}
}
});
httpsServer.createContext("/test", new MyHandler());
httpsServer.setExecutor(
new ThreadPoolExecutor(4, 80, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000))); // creates
// a
// default
// executor
httpsServer.start();
} catch (Exception exception) {
System.out.println("Failed to create HTTPS server on port " + 62112 + " of localhost");
exception.printStackTrace();
}
}
}
The client code is:
package vnetz.de.org.vnetz;
import android.content.Context;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.SocketException;
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class clsHTTPS {
private static final String MYURL = "https://localhost:9999/test?qry=test";
static String NO_KEYSTORE = "";
static String UNAUTH_KEYSTORE = "unauthclient.bks"; // Doesn't exist in server trust store, should fail authentication.
static String AUTH_KEYSTORE = "authclient.bks"; // Exists in server trust store, should pass authentication.
static String TRUSTSTORE = "clienttrust.bks";
static String CLIENT_PWD = "xxxxxx";
private static Context context = null;
public clsHTTPS(Context context) {
this.context = context;
}
public static void main(String[] args) throws Exception {
}
public String connect(String jksFile) {
try {
String https_url = MYURL;
URL url;
url = new URL(https_url);
HttpsURLConnection.setDefaultHostnameVerifier(new NullHostNameVerifier());
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(getSSLFactory(jksFile));
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setUseCaches(false);
// Print response
//SSLContext context = SSLContext.getInstance("TLS");
//context.init(null, new X509TrustManager[]{new NullX509TrustManager()}, new SecureRandom());
//HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
BufferedReader bir = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sbline = new StringBuilder();
String line;
while ((line = bir.readLine()) != null) {
System.out.println(line);
sbline.append(line);
}
bir.close();
conn.disconnect();
return sbline.toString();
} catch (SSLHandshakeException | SocketException e) {
System.out.println(e.getMessage());
System.out.println("");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static SSLSocketFactory getSSLFactory(String jksFile) throws Exception {
// Create key store
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
KeyManager[] kmfs = null;
if (jksFile.length() > 0) {
keyStore.load(context.getAssets().open(jksFile), CLIENT_PWD.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, CLIENT_PWD.toCharArray());
kmfs = kmf.getKeyManagers();
}
// create trust store (validates the self-signed server!)
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(context.getAssets().open(TRUSTSTORE), CLIENT_PWD.toCharArray());
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmfs, trustFactory.getTrustManagers(), null);
return sslContext.getSocketFactory();
}
private class NullHostNameVerifier implements HostnameVerifier
{
#Override
public boolean verify(String s, SSLSession sslSession)
{
return s.equalsIgnoreCase("localhost");
}
}
private class NullX509TrustManager implements X509TrustManager
{
#Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException
{
}
#Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException
{
}
#Override
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[0];
}
}
}
'Peer not verified' in a server means that the client didn't send a certificate, which probably means that its signer isn't in your server's truststore. When the server requests the client certificate, it supplies a list of acceptable signers, and the client must not send a certificate that isn't signed by one of those.
Or else the server didn't ask for a client certificate at all. Doesn't apply in this case.
In your case it would be a lot simpler to use needClientAuth, as that will just fail the handshake without you having to get as a far as getPeerCertificates().
NB:
The SSLSession is valid, otherwise you wouldn't have an SSL connection. The only way it becomes invalid is if you call invalidate(), which causes a full re-handshake on the next I/O. You're testing the wrong thing.
Checking for allowed principals is authorization, not authentication.

Converting SSL code from regular Java application to SSL code for Android

I have a regular java application that connects to my java server using the following code:
KeyStore ks = KeyStore.getInstance("JKS");
InputStream inputStream = getClass().getResourceAsStream("cert.jks");
ks.load(inputStream, "password".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
SSLContext ssc = SSLContext.getInstance("TLS");
ssc.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory factory = ssc.getSocketFactory();
Socket socket = new Socket(Proxy.NO_PROXY);
InetAddress host = InetAddress.getByName("<ip address of server">);
int port = <some port>;
socket.connect(new InetSocketAddress(host, port));
SSLSocket ssls = (SSLSocket)factory.createSocket(socket, host.getHostAddress(), port, false);
ssls.setUseClientMode(true);
ssls.setNeedClientAuth(false);
ssls.startHandshake();
And everything works fine. However, since Android doesn't support JKS Keystores or SunX509, I've had to make some changes. I've converted the JKS certificate to a BKS certificate using bouncy castle (hat tip to: How to create a BKS (BouncyCastle) format Java Keystore that contains a client certificate chain) and used the TrustManagerFactory's default algorithm, so now my code looks like this:
KeyStore ks = KeyStore.getInstance("BKS");
android.content.res.Resources res = <getter for resources>;
InputStream inputStream = res.openRawResources(R.raw.cert); //The converted bks certificate stored in the raw directory
ks.load(inputStream, "password".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
SSLContext ssc = SSLContext.getInstance("TLS");
ssc.init(null, tmf.getTrustManagers(), null);
... same as above ...
ssls.startHandshake();
However, the above code throws an exception at the last line of startHandshake:
javax.net.ssl.SSLHandshakeException: Connection closed by peer at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method) at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)
What's the issue here? Is there any additional information that can help?
For your requirement, you can refer to the following sample code from the Google's tranining docs:
Security with HTTPS and SSL
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection =
(HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);
InputStream inputStream = getClass().getResourceAsStream("cert.bks"); //The converted bks certificate
You should put your cert.bks file into /res/raw directory, then open the file with getResources().openRawResource(R.raw.cert);.
EDIT:
I think you are not specifying the provider when you are loading the truststore.
KeyStore keyStore = KeyStore.getInstance("BKS", BouncyCastleProvider.PROVIDER_NAME);
And if you forgot, you need to add the SpongyCastle provider in your Application class.
public class CustomApplication
extends Application {
static {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
}
And add that to your AndroidManifest.xml
<application
android:allowBackup="true"
android:name=".application.CustomApplication"
But if that still doesn't work, what you can try to do is adding the following classes from the source of Apache HttpClient (it's apache-licensed so you can do that):
Args.java
.
import java.util.Collection;
class Args {
public static void check(final boolean expression, final String message) {
if (!expression) {
throw new IllegalArgumentException(message);
}
}
public static void check(final boolean expression, final String message, final Object... args) {
if (!expression) {
throw new IllegalArgumentException(String.format(message, args));
}
}
public static void check(final boolean expression, final String message, final Object arg) {
if (!expression) {
throw new IllegalArgumentException(String.format(message, arg));
}
}
public static <T> T notNull(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
return argument;
}
public static <T extends CharSequence> T notEmpty(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (TextUtils.isEmpty(argument)) {
throw new IllegalArgumentException(name + " may not be empty");
}
return argument;
}
public static <T extends CharSequence> T notBlank(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (TextUtils.isBlank(argument)) {
throw new IllegalArgumentException(name + " may not be blank");
}
return argument;
}
public static <T extends CharSequence> T containsNoBlanks(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (TextUtils.containsBlanks(argument)) {
throw new IllegalArgumentException(name + " may not contain blanks");
}
return argument;
}
public static <E, T extends Collection<E>> T notEmpty(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (argument.isEmpty()) {
throw new IllegalArgumentException(name + " may not be empty");
}
return argument;
}
public static int positive(final int n, final String name) {
if (n <= 0) {
throw new IllegalArgumentException(name + " may not be negative or zero");
}
return n;
}
public static long positive(final long n, final String name) {
if (n <= 0) {
throw new IllegalArgumentException(name + " may not be negative or zero");
}
return n;
}
public static int notNegative(final int n, final String name) {
if (n < 0) {
throw new IllegalArgumentException(name + " may not be negative");
}
return n;
}
public static long notNegative(final long n, final String name) {
if (n < 0) {
throw new IllegalArgumentException(name + " may not be negative");
}
return n;
}
}
PrivateKeyDetails.java
.
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* [...add this back]
*/
import java.security.cert.X509Certificate;
import java.util.Arrays;
/**
* Private key details.
*
* #since 4.4
*/
public final class PrivateKeyDetails {
private final String type;
private final X509Certificate[] certChain;
public PrivateKeyDetails(final String type, final X509Certificate[] certChain) {
super();
this.type = Args.notNull(type, "Private key type");
this.certChain = certChain;
}
public String getType() {
return type;
}
public X509Certificate[] getCertChain() {
return certChain;
}
#Override
public String toString() {
return type + ':' + Arrays.toString(certChain);
}
}
PrivateKeyStrategy.java
.
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) [...add this back]
*
*/
import java.net.Socket;
import java.util.Map;
/**
* A strategy allowing for a choice of an alias during SSL authentication.
*
* #since 4.4
*/
public interface PrivateKeyStrategy {
/**
* Determines what key material to use for SSL authentication.
*
* #param aliases available private key material
* #param socket socket used for the connection. Please note this parameter can be {#code null}
* if key material is applicable to any socket.
*/
String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket);
}
SSLContextBuilder.java
.
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) [...add this back]
*
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509TrustManager;
/**
* Builder for {#link javax.net.ssl.SSLContext} instances.
* <p>
* Please note: the default Oracle JSSE implementation of {#link SSLContext#init(KeyManager[], TrustManager[], SecureRandom)}
* accepts multiple key and trust managers, however only only first matching type is ever used.
* See for example:
* <a href="http://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLContext.html#init%28javax.net.ssl.KeyManager[],%20javax.net.ssl.TrustManager[],%20java.security.SecureRandom%29">
* SSLContext.html#init
* </a>
*
* #since 4.4
*/
public class SSLContextBuilder {
static final String TLS = "TLS";
private String protocol;
private final Set<KeyManager> keymanagers;
private final Set<TrustManager> trustmanagers;
private SecureRandom secureRandom;
public static SSLContextBuilder create() {
return new SSLContextBuilder();
}
public SSLContextBuilder() {
super();
this.keymanagers = new LinkedHashSet<KeyManager>();
this.trustmanagers = new LinkedHashSet<TrustManager>();
}
public SSLContextBuilder useProtocol(final String protocol) {
this.protocol = protocol;
return this;
}
public SSLContextBuilder setSecureRandom(final SecureRandom secureRandom) {
this.secureRandom = secureRandom;
return this;
}
public SSLContextBuilder loadTrustMaterial(
final KeyStore truststore,
final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
final TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmfactory.init(truststore);
final TrustManager[] tms = tmfactory.getTrustManagers();
if (tms != null) {
if (trustStrategy != null) {
for (int i = 0; i < tms.length; i++) {
final TrustManager tm = tms[i];
if (tm instanceof X509TrustManager) {
tms[i] = new TrustManagerDelegate(
(X509TrustManager) tm, trustStrategy);
}
}
}
for (final TrustManager tm : tms) {
this.trustmanagers.add(tm);
}
}
return this;
}
public SSLContextBuilder loadTrustMaterial(
final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
return loadTrustMaterial(null, trustStrategy);
}
public SSLContextBuilder loadTrustMaterial(
final File file,
final char[] storePassword,
final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
Args.notNull(file, "Truststore file");
final KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
final FileInputStream instream = new FileInputStream(file);
try {
trustStore.load(instream, storePassword);
} finally {
instream.close();
}
return loadTrustMaterial(trustStore, trustStrategy);
}
public SSLContextBuilder loadTrustMaterial(
final File file,
final char[] storePassword) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
return loadTrustMaterial(file, storePassword, null);
}
public SSLContextBuilder loadTrustMaterial(
final File file) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
return loadTrustMaterial(file, null);
}
public SSLContextBuilder loadTrustMaterial(
final URL url,
final char[] storePassword,
final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
Args.notNull(url, "Truststore URL");
final KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
final InputStream instream = url.openStream();
try {
trustStore.load(instream, storePassword);
} finally {
instream.close();
}
return loadTrustMaterial(trustStore, trustStrategy);
}
public SSLContextBuilder loadTrustMaterial(
final URL url,
final char[] storePassword) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
return loadTrustMaterial(url, storePassword, null);
}
public SSLContextBuilder loadKeyMaterial(
final KeyStore keystore,
final char[] keyPassword,
final PrivateKeyStrategy aliasStrategy)
throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
final KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(keystore, keyPassword);
final KeyManager[] kms = kmfactory.getKeyManagers();
if (kms != null) {
if (aliasStrategy != null) {
for (int i = 0; i < kms.length; i++) {
final KeyManager km = kms[i];
if (km instanceof X509ExtendedKeyManager) {
kms[i] = new KeyManagerDelegate((X509ExtendedKeyManager) km, aliasStrategy);
}
}
}
for (final KeyManager km : kms) {
keymanagers.add(km);
}
}
return this;
}
public SSLContextBuilder loadKeyMaterial(
final KeyStore keystore,
final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
return loadKeyMaterial(keystore, keyPassword, null);
}
public SSLContextBuilder loadKeyMaterial(
final File file,
final char[] storePassword,
final char[] keyPassword,
final PrivateKeyStrategy aliasStrategy) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
Args.notNull(file, "Keystore file");
final KeyStore identityStore = KeyStore.getInstance(KeyStore.getDefaultType());
final FileInputStream instream = new FileInputStream(file);
try {
identityStore.load(instream, storePassword);
} finally {
instream.close();
}
return loadKeyMaterial(identityStore, keyPassword, aliasStrategy);
}
public SSLContextBuilder loadKeyMaterial(
final File file,
final char[] storePassword,
final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
return loadKeyMaterial(file, storePassword, keyPassword, null);
}
public SSLContextBuilder loadKeyMaterial(
final URL url,
final char[] storePassword,
final char[] keyPassword,
final PrivateKeyStrategy aliasStrategy) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
Args.notNull(url, "Keystore URL");
final KeyStore identityStore = KeyStore.getInstance(KeyStore.getDefaultType());
final InputStream instream = url.openStream();
try {
identityStore.load(instream, storePassword);
} finally {
instream.close();
}
return loadKeyMaterial(identityStore, keyPassword, aliasStrategy);
}
public SSLContextBuilder loadKeyMaterial(
final URL url,
final char[] storePassword,
final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
return loadKeyMaterial(url, storePassword, keyPassword, null);
}
protected void initSSLContext(
final SSLContext sslcontext,
final Collection<KeyManager> keyManagers,
final Collection<TrustManager> trustManagers,
final SecureRandom secureRandom) throws KeyManagementException {
sslcontext.init(
!keyManagers.isEmpty() ? keyManagers.toArray(new KeyManager[keyManagers.size()]) : null,
!trustManagers.isEmpty() ? trustManagers.toArray(new TrustManager[trustManagers.size()]) : null,
secureRandom);
}
public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
final SSLContext sslcontext = SSLContext.getInstance(
this.protocol != null ? this.protocol : TLS);
initSSLContext(sslcontext, keymanagers, trustmanagers, secureRandom);
return sslcontext;
}
static class TrustManagerDelegate implements X509TrustManager {
private final X509TrustManager trustManager;
private final TrustStrategy trustStrategy;
TrustManagerDelegate(final X509TrustManager trustManager, final TrustStrategy trustStrategy) {
super();
this.trustManager = trustManager;
this.trustStrategy = trustStrategy;
}
#Override
public void checkClientTrusted(
final X509Certificate[] chain, final String authType) throws CertificateException {
this.trustManager.checkClientTrusted(chain, authType);
}
#Override
public void checkServerTrusted(
final X509Certificate[] chain, final String authType) throws CertificateException {
if (!this.trustStrategy.isTrusted(chain, authType)) {
this.trustManager.checkServerTrusted(chain, authType);
}
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return this.trustManager.getAcceptedIssuers();
}
}
static class KeyManagerDelegate extends X509ExtendedKeyManager {
private final X509ExtendedKeyManager keyManager;
private final PrivateKeyStrategy aliasStrategy;
KeyManagerDelegate(final X509ExtendedKeyManager keyManager, final PrivateKeyStrategy aliasStrategy) {
super();
this.keyManager = keyManager;
this.aliasStrategy = aliasStrategy;
}
#Override
public String[] getClientAliases(
final String keyType, final Principal[] issuers) {
return this.keyManager.getClientAliases(keyType, issuers);
}
public Map<String, PrivateKeyDetails> getClientAliasMap(
final String[] keyTypes, final Principal[] issuers) {
final Map<String, PrivateKeyDetails> validAliases = new HashMap<String, PrivateKeyDetails>();
for (final String keyType: keyTypes) {
final String[] aliases = this.keyManager.getClientAliases(keyType, issuers);
if (aliases != null) {
for (final String alias: aliases) {
validAliases.put(alias,
new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
}
}
}
return validAliases;
}
public Map<String, PrivateKeyDetails> getServerAliasMap(
final String keyType, final Principal[] issuers) {
final Map<String, PrivateKeyDetails> validAliases = new HashMap<String, PrivateKeyDetails>();
final String[] aliases = this.keyManager.getServerAliases(keyType, issuers);
if (aliases != null) {
for (final String alias: aliases) {
validAliases.put(alias,
new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
}
}
return validAliases;
}
#Override
public String chooseClientAlias(
final String[] keyTypes, final Principal[] issuers, final Socket socket) {
final Map<String, PrivateKeyDetails> validAliases = getClientAliasMap(keyTypes, issuers);
return this.aliasStrategy.chooseAlias(validAliases, socket);
}
#Override
public String[] getServerAliases(
final String keyType, final Principal[] issuers) {
return this.keyManager.getServerAliases(keyType, issuers);
}
#Override
public String chooseServerAlias(
final String keyType, final Principal[] issuers, final Socket socket) {
final Map<String, PrivateKeyDetails> validAliases = getServerAliasMap(keyType, issuers);
return this.aliasStrategy.chooseAlias(validAliases, socket);
}
#Override
public X509Certificate[] getCertificateChain(final String alias) {
return this.keyManager.getCertificateChain(alias);
}
#Override
public PrivateKey getPrivateKey(final String alias) {
return this.keyManager.getPrivateKey(alias);
}
#Override
public String chooseEngineClientAlias(
final String[] keyTypes, final Principal[] issuers, final SSLEngine sslEngine) {
final Map<String, PrivateKeyDetails> validAliases = getClientAliasMap(keyTypes, issuers);
return this.aliasStrategy.chooseAlias(validAliases, null);
}
#Override
public String chooseEngineServerAlias(
final String keyType, final Principal[] issuers, final SSLEngine sslEngine) {
final Map<String, PrivateKeyDetails> validAliases = getServerAliasMap(keyType, issuers);
return this.aliasStrategy.chooseAlias(validAliases, null);
}
}
}
TextUtils.java
.
/**
* #since 4.3
*/
final class TextUtils {
/**
* Returns true if the parameter is null or of zero length
*/
public static boolean isEmpty(final CharSequence s) {
if (s == null) {
return true;
}
return s.length() == 0;
}
/**
* Returns true if the parameter is null or contains only whitespace
*/
public static boolean isBlank(final CharSequence s) {
if (s == null) {
return true;
}
for (int i = 0; i < s.length(); i++) {
if (!Character.isWhitespace(s.charAt(i))) {
return false;
}
}
return true;
}
/**
* #since 4.4
*/
public static boolean containsBlanks(final CharSequence s) {
if (s == null) {
return false;
}
for (int i = 0; i < s.length(); i++) {
if (Character.isWhitespace(s.charAt(i))) {
return true;
}
}
return false;
}
}
TrustAllStrategy.java
.
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* Created on 2015.06.02..
*/
public class TrustAllStrategy implements TrustStrategy {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
}
TrustSelfSignedStrategy.java
.
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* [...add this back]
*
*/
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* A trust strategy that accepts self-signed certificates as trusted. Verification of all other
* certificates is done by the trust manager configured in the SSL context.
*
* #since 4.1
*/
public class TrustSelfSignedStrategy implements TrustStrategy {
public static final TrustSelfSignedStrategy INSTANCE = new TrustSelfSignedStrategy();
#Override
public boolean isTrusted(
final X509Certificate[] chain, final String authType) throws CertificateException {
return chain.length == 1;
}
}
TrustStrategy.java
.
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) [...add this back]
*/
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* A strategy to establish trustworthiness of certificates without consulting the trust manager
* configured in the actual SSL context. This interface can be used to override the standard
* JSSE certificate verification process.
*
* #since 4.4
*/
public interface TrustStrategy {
/**
* Determines whether the certificate chain can be trusted without consulting the trust manager
* configured in the actual SSL context. This method can be used to override the standard JSSE
* certificate verification process.
* <p/>
* Please note that, if this method returns {#code false}, the trust manager configured
* in the actual SSL context can still clear the certificate as trusted.
*
* #param chain the peer certificate chain
* #param authType the authentication type based on the client certificate
* #return {#code true} if the certificate can be trusted without verification by
* the trust manager, {#code false} otherwise.
* #throws CertificateException thrown if the certificate is not trusted or invalid.
*/
boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException;
}
Once you add these, you can build your SSLContext like so:
SSLContextBuilder sslContextBuilder = SSLContextBuilder.create();
KeyStore keyStore = KeyStore.getInstance("BKS", BouncyCastleProvider.PROVIDER_NAME);
android.content.res.Resources res = <getter for resources>;
InputStream inputStream = res.openRawResources(R.raw.cert);
keyStore.load(inputStream, trustStorePassword);
sslContextBuilder.loadTrustMaterial(keyStore, trustStorePassword);
SSLContext sslContext = sslContextBuilder.build();
//okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
EDIT: Testing certificate
keyStore.load(byteArrayInputStream, keyStorePassword);
Certificate[] certificates = keyStore.getCertificateChain("key-alias"); //you need to know the alias
if(certificates.length > 0) {
Certificate certificate = certificates[0];
X509Certificate x509Certificate = (X509Certificate) certificate;
Log.d(TAG,
"Certificate found with DN [" + x509Certificate.getSubjectDN() + "]");

Java SSL: how to disable hostname verification

Is there a way for the standard java SSL sockets to disable hostname verfication for ssl connections with a property? The only way I found until now, is to write a hostname verifier which returns true all the time.
Weblogic provides this possibility, it is possible to disable the hostname verification with the following property:
-Dweblogic.security.SSL.ignoreHostnameVerify
It should be possible to create custom java agent that overrides default HostnameVerifier:
import javax.net.ssl.*;
import java.lang.instrument.Instrumentation;
public class LenientHostnameVerifierAgent {
public static void premain(String args, Instrumentation inst) {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
}
}
Then just add -javaagent:LenientHostnameVerifierAgent.jar to program's java startup arguments.
The answer from #Nani doesn't work anymore with Java 1.8u181. You still need to use your own TrustManager, but it needs to be a X509ExtendedTrustManager instead of a X509TrustManager:
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;
public class Test {
public static void main (String [] args) throws IOException {
// This URL has a certificate with a wrong name
URL url = new URL ("https://wrong.host.badssl.com/");
try {
// opening a connection will fail
url.openConnection ().connect ();
} catch (SSLHandshakeException e) {
System.out.println ("Couldn't open connection: " + e.getMessage ());
}
// Bypassing the SSL verification to execute our code successfully
disableSSLVerification ();
// now we can open the connection
url.openConnection ().connect ();
System.out.println ("successfully opened connection to " + url + ": " + ((HttpURLConnection) url.openConnection ()).getResponseCode ());
}
// Method used for bypassing SSL verification
public static void disableSSLVerification () {
TrustManager [] trustAllCerts = new TrustManager [] {new X509ExtendedTrustManager () {
#Override
public void checkClientTrusted (X509Certificate [] chain, String authType, Socket socket) {
}
#Override
public void checkServerTrusted (X509Certificate [] chain, String authType, Socket socket) {
}
#Override
public void checkClientTrusted (X509Certificate [] chain, String authType, SSLEngine engine) {
}
#Override
public void checkServerTrusted (X509Certificate [] chain, String authType, SSLEngine engine) {
}
#Override
public java.security.cert.X509Certificate [] getAcceptedIssuers () {
return null;
}
#Override
public void checkClientTrusted (X509Certificate [] certs, String authType) {
}
#Override
public void checkServerTrusted (X509Certificate [] certs, String authType) {
}
}};
SSLContext sc = null;
try {
sc = SSLContext.getInstance ("SSL");
sc.init (null, trustAllCerts, new java.security.SecureRandom ());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace ();
}
HttpsURLConnection.setDefaultSSLSocketFactory (sc.getSocketFactory ());
}
}
There is no hostname verification in standard Java SSL sockets or indeed SSL, so that's why you can't set it at that level. Hostname verification is part of HTTPS (RFC 2818): that's why it manifests itself as javax.net.ssl.HostnameVerifier, which is applied to an HttpsURLConnection.
I also had the same problem while accessing RESTful web services. And I their with the below code to overcome the issue:
public class Test {
//Bypassing the SSL verification to execute our code successfully
static {
disableSSLVerification();
}
public static void main(String[] args) {
//Access HTTPS URL and do something
}
//Method used for bypassing SSL verification
public static void disableSSLVerification() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
SSLContext sc = null;
try {
sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}
}
It worked for me. try it!!
In case you're using apache's http-client 4:
SSLConnectionSocketFactory sslConnectionSocketFactory =
new SSLConnectionSocketFactory(sslContext,
new String[] { "TLSv1.2" }, null, new HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
#user207421 is right, there is no hostname verification in standard Java SSL sockets or indeed SSL.
But X509ExtendedTrustManager implement the host name check logic(see it's javadoc). To disable this, We can set SSLParameters .endpointIdentificationAlgorithm to null as JDK AbstractAsyncSSLConnection did:
if (!disableHostnameVerification)
sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); // default is null
disableHostnameVerification is read from property: jdk.internal.httpclient.disableHostnameVerification。
How to modify SSLParameters Object is dependends on the specify soft you use。
as spring webflux WebClient:
HttpClient httpClient = HttpClient.create()
.secure(sslContextSpec ->
sslContextSpec
.sslContext(sslContext)
.handlerConfigurator(sslHandler -> {
SSLEngine engine = sslHandler.engine();
SSLParameters newSslParameters = engine.getSSLParameters(); // 返回的是一个新对象
// 参考:https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java#L116
newSslParameters.setEndpointIdentificationAlgorithm(null);
engine.setSSLParameters(newSslParameters);
})
)
WebClient webclient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();

Categories