Https Connection Android

JavaAndroidSsl

Java Problem Overview


I am doing a https post and I'm getting an exception of ssl exception Not trusted server certificate. If i do normal http it is working perfectly fine. Do I have to accept the server certificate somehow?

Java Solutions


Solution 1 - Java

This is what I am doing. It simply doesn't check the certificate anymore.

// always verify the host - dont check for certificate
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
	public boolean verify(String hostname, SSLSession session) {
		return true;
	}
};

/**
 * Trust every server - dont check for any certificate
 */
private static void trustAllHosts() {
	// Create a trust manager that does not validate certificate chains
	TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
		public java.security.cert.X509Certificate[] getAcceptedIssuers() {
			return new java.security.cert.X509Certificate[] {};
		}

		public void checkClientTrusted(X509Certificate[] chain,
				String authType) throws CertificateException {
		}

		public void checkServerTrusted(X509Certificate[] chain,
				String authType) throws CertificateException {
		}
	} };

	// Install the all-trusting trust manager
	try {
		SSLContext sc = SSLContext.getInstance("TLS");
		sc.init(null, trustAllCerts, new java.security.SecureRandom());
		HttpsURLConnection
				.setDefaultSSLSocketFactory(sc.getSocketFactory());
	} catch (Exception e) {
		e.printStackTrace();
	}
}

and

	HttpURLConnection http = null;
	
	if (url.getProtocol().toLowerCase().equals("https")) {
	    trustAllHosts();
		HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
		https.setHostnameVerifier(DO_NOT_VERIFY);
		http = https;
	} else {
		http = (HttpURLConnection) url.openConnection();
	}

Solution 2 - Java

I'm making a guess, but if you want an actual handshake to occur, you have to let android know of your certificate. If you want to just accept no matter what, then use this pseudo-code to get what you need with the Apache HTTP Client:

SchemeRegistry schemeRegistry = new SchemeRegistry ();

schemeRegistry.register (new Scheme ("http",
    PlainSocketFactory.getSocketFactory (), 80));
schemeRegistry.register (new Scheme ("https",
    new CustomSSLSocketFactory (), 443));

ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager (
    params, schemeRegistry);


return new DefaultHttpClient (cm, params);

CustomSSLSocketFactory:

public class CustomSSLSocketFactory extends org.apache.http.conn.ssl.SSLSocketFactory
{
private SSLSocketFactory FACTORY = HttpsURLConnection.getDefaultSSLSocketFactory ();

public CustomSSLSocketFactory ()
    {
    super(null);
    try
        {
        SSLContext context = SSLContext.getInstance ("TLS");
        TrustManager[] tm = new TrustManager[] { new FullX509TrustManager () };
        context.init (null, tm, new SecureRandom ());
            
        FACTORY = context.getSocketFactory ();
        }
    catch (Exception e)
        {
        e.printStackTrace();
        }
    }

public Socket createSocket() throws IOException
{
    return FACTORY.createSocket();
}

 // TODO: add other methods like createSocket() and getDefaultCipherSuites().
 // Hint: they all just make a call to member FACTORY 
}

FullX509TrustManager is a class that implements javax.net.ssl.X509TrustManager, yet none of the methods actually perform any work, get a sample here.

Good Luck!

Solution 3 - Java

While trying to answer this question I found a better tutorial. With it you don't have to compromise the certificate check.

http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html

*I did not write this but thanks to Bob Lee for the work

Solution 4 - Java

You can also look at my blog article, very similar to crazybobs.

This solution also doesn't compromise certificate checking and explains how to add the trusted certs in your own keystore.

http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/

Solution 5 - Java

http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html

Courtesy Maduranga

When developing an application that uses https, your test server doesn't have a valid SSL certificate. Or sometimes the web site is using a self-signed certificate or the web site is using free SSL certificate. So if you try to connect to the server using Apache HttpClient, you will get a exception telling that the "peer not authenticated". Though it is not a good practice to trust all the certificates in a production software, you may have to do so according to the situation. This solution resolves the exception caused by "peer not authenticated".

But before we go to the solution, I must warn you that this is not a good idea for a production application. This will violate the purpose of using a security certificate. So unless you have a good reason or if you are sure that this will not cause any problem, don't use this solution.

Normally you create a HttpClient like this.

HttpClient httpclient = new DefaultHttpClient();

But you have to change the way you create the HttpClient.

First you have to create a class extending org.apache.http.conn.ssl.SSLSocketFactory.

import org.apache.http.conn.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

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();
    }
}

Then create a method like this.

public HttpClient getNewHttpClient() {
     try {
         KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
         trustStore.load(null, null);

         SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
         sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

         HttpParams params = new BasicHttpParams();
         HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
         HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

         SchemeRegistry registry = new SchemeRegistry();
         registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
         registry.register(new Scheme("https", sf, 443));

         ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

         return new DefaultHttpClient(ccm, params);
     } catch (Exception e) {
         return new DefaultHttpClient();
     }
}

Then you can create the HttpClient.

HttpClient httpclient = getNewHttpClient();

If you are trying to send a post request to a login page the rest of the code would be like this.

private URI url = new URI("url of the action of the form");
HttpPost httppost =  new HttpPost(url);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();  
nameValuePairs.add(new BasicNameValuePair("username", "user"));  
nameValuePairs.add(new BasicNameValuePair("password", "password"));
try {
    httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
    HttpResponse response = httpclient.execute(httppost);
    HttpEntity entity = response.getEntity();
    InputStream is = entity.getContent();
} catch (UnsupportedEncodingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (ClientProtocolException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

You get the html page to the InputStream. Then you can do whatever you want with the returned html page.

But here you will face a problem. If you want to manage a session using cookies, you will not be able to do it with this method. If you want to get the cookies, you will have to do it via a browser. Then only you will receive cookies.

Solution 6 - Java

If you are using a StartSSL or Thawte certificate, it will fail for Froyo and older versions. You can use a newer version's CAcert repository instead of trusting every certificate.

Solution 7 - Java

Solution 8 - Java

Any of this answers didn't work for me so here is code which trust any certificates.

import java.io.IOException;

	import java.net.Socket;
	import java.security.KeyManagementException;
	import java.security.KeyStoreException;
	import java.security.NoSuchAlgorithmException;
	import java.security.UnrecoverableKeyException;
	import java.security.cert.CertificateException;
	import java.security.cert.X509Certificate;

	import javax.net.ssl.SSLContext;
	import javax.net.ssl.TrustManager;
	import javax.net.ssl.X509TrustManager;

	import org.apache.http.client.ClientProtocolException;
	import org.apache.http.client.HttpClient;
	import org.apache.http.client.methods.HttpPost;
	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.conn.ssl.X509HostnameVerifier;
	import org.apache.http.impl.client.DefaultHttpClient;
	import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
	import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

	public class HttpsClientBuilder {
		public static DefaultHttpClient getBelieverHttpsClient() {
				
			DefaultHttpClient client = null;
	 
			SchemeRegistry Current_Scheme = new SchemeRegistry();
			Current_Scheme.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
			try {
				Current_Scheme.register(new Scheme("https", new Naive_SSLSocketFactory(), 8443));
			} catch (KeyManagementException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnrecoverableKeyException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (KeyStoreException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			HttpParams Current_Params = new BasicHttpParams();
			int timeoutConnection = 8000;
			HttpConnectionParams.setConnectionTimeout(Current_Params, timeoutConnection);
			int timeoutSocket = 10000;
			HttpConnectionParams.setSoTimeout(Current_Params, timeoutSocket);
			ThreadSafeClientConnManager Current_Manager = new ThreadSafeClientConnManager(Current_Params, Current_Scheme);
			client = new DefaultHttpClient(Current_Manager, Current_Params);
			//HttpPost httpPost = new HttpPost(url);
			//client.execute(httpPost);

		 return client;
		 }

	public static class Naive_SSLSocketFactory extends SSLSocketFactory
	{
		protected SSLContext Cur_SSL_Context = SSLContext.getInstance("TLS");

		public Naive_SSLSocketFactory ()
		        throws NoSuchAlgorithmException, KeyManagementException,
		        KeyStoreException, UnrecoverableKeyException
		{
			super(null, null, null, null, null, (X509HostnameVerifier)null);
			Cur_SSL_Context.init(null, new TrustManager[] { new X509_Trust_Manager() }, null);
		}

		@Override
		public Socket createSocket(Socket socket, String host, int port,
		        boolean autoClose) throws IOException
		{
			return Cur_SSL_Context.getSocketFactory().createSocket(socket, host, port, autoClose);
		}

		@Override
		public Socket createSocket() throws IOException
		{
			return Cur_SSL_Context.getSocketFactory().createSocket();
		}
	}

	private static class X509_Trust_Manager implements X509TrustManager
	{

		public void checkClientTrusted(X509Certificate[] chain, String authType)
				throws CertificateException {
			// TODO Auto-generated method stub
			
		}

		public void checkServerTrusted(X509Certificate[] chain, String authType)
				throws CertificateException {
			// TODO Auto-generated method stub
			
		}

		public X509Certificate[] getAcceptedIssuers() {
			// TODO Auto-generated method stub
			return null;
		}

	};
}

Solution 9 - Java

I don't know about the Android specifics for ssl certificates, but it would make sense that Android won't accept a self signed ssl certificate off the bat. I found this post from android forums which seems to be addressing the same issue: http://androidforums.com/android-applications/950-imap-self-signed-ssl-certificates.html

Solution 10 - Java

This is a known problem with Android 2.x. I was struggling with this problem for a week until I came across the following question, which not only gives a good background of the problem but also provides a working and effective solution devoid of any security holes.

https://stackoverflow.com/questions/9574870/no-peer-certificate-error-in-android-2-3-but-not-in-4

Solution 11 - Java

For some reason the solution mentioned for httpClient above didn't worked for me. At the end I was able to make it work by correctly overriding the method when implementing the custom SSLSocketFactory class.

@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) 
                              throws IOException, UnknownHostException 
    {
    return sslFactory.createSocket(socket, host, port, autoClose);
}

@Override
public Socket createSocket() throws IOException {
    return sslFactory.createSocket();
}

This is how it worked perfectly for me. You can see the full custom class and implementing on the following thread: http://blog.syedgakbar.com/2012/07/21/android-https-and-not-trusted-server-certificate-error/

Solution 12 - Java

I make this class and found

package com.example.fakessl;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;

import android.util.Log;

public class CertificadoAceptar {
	private static TrustManager[] trustManagers;

	public static class _FakeX509TrustManager implements
			javax.net.ssl.X509TrustManager {
		private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};

		public void checkClientTrusted(X509Certificate[] arg0, String arg1)
				throws CertificateException {
		}

		public void checkServerTrusted(X509Certificate[] arg0, String arg1)
				throws CertificateException {
		}

		public boolean isClientTrusted(X509Certificate[] chain) {
			return (true);
		}

		public boolean isServerTrusted(X509Certificate[] chain) {
			return (true);
		}

		public X509Certificate[] getAcceptedIssuers() {
			return (_AcceptedIssuers);
		}
	}

	public static void allowAllSSL() {

		javax.net.ssl.HttpsURLConnection
				.setDefaultHostnameVerifier(new HostnameVerifier() {
					public boolean verify(String hostname, SSLSession session) {
						return true;
					}
				});

		javax.net.ssl.SSLContext context = null;

		if (trustManagers == null) {
			trustManagers = new javax.net.ssl.TrustManager[] { new _FakeX509TrustManager() };
		}

		try {
			context = javax.net.ssl.SSLContext.getInstance("TLS");
			context.init(null, trustManagers, new SecureRandom());
		} catch (NoSuchAlgorithmException e) {
			Log.e("allowAllSSL", e.toString());
		} catch (KeyManagementException e) {
			Log.e("allowAllSSL", e.toString());
		}
		javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context
				.getSocketFactory());
	}
}

in you code white this

CertificadoAceptar ca = new CertificadoAceptar();
ca.allowAllSSL();
HttpsTransportSE Transport = new HttpsTransportSE("iphost or host name", 8080, "/WS/wsexample.asmx?WSDL", 30000);

Solution 13 - Java

Sources that helped me get to work with my self signed certificate on my AWS Apache server and connect with HttpsURLConnection from android device:

SSL on aws instance - amazon tutorial on ssl
Android Security with HTTPS and SSL - creating your own trust manager on client for accepting your certificate
Creating self signed certificate - easy script for creating your certificates

Then I did the following:

  1. Made sure the server supports https (sudo yum install -y mod24_ssl)
  2. Put this script in a file create_my_certs.sh:

> #!/bin/bash > FQDN=$1 >
> # make directories to work from > mkdir -p server/ client/ all/ >
> # Create your very own Root Certificate Authority > openssl genrsa
> -out all/my-private-root-ca.privkey.pem
> 2048 >
> # Self-sign your Root Certificate Authority > # Since this is private, the details can be as bogus as you like > openssl req
> -x509
> -new
> -nodes
> -key all/my-private-root-ca.privkey.pem
> -days 1024
> -out all/my-private-root-ca.cert.pem
> -subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com" >
> # Create a Device Certificate for each domain, > # such as example.com, *.example.com, awesome.example.com > # NOTE: You MUST match CN to the domain name or ip address you want to use > openssl genrsa
> -out all/privkey.pem
> 2048 >
> # Create a request from your Device, which your Root CA will sign > openssl req -new
> -key all/privkey.pem
> -out all/csr.pem
> -subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}" >
> # Sign the request from Device with your Root CA > openssl x509
> -req -in all/csr.pem
> -CA all/my-private-root-ca.cert.pem
> -CAkey all/my-private-root-ca.privkey.pem
> -CAcreateserial
> -out all/cert.pem
> -days 500 >
> # Put things in their proper place > rsync -a all/{privkey,cert}.pem server/ > cat all/cert.pem > server/fullchain.pem # we have no intermediates in this case > rsync -a all/my-private-root-ca.cert.pem server/ > rsync -a all/my-private-root-ca.cert.pem client/

  1. Run bash create_my_certs.sh yourdomain.com

  2. Place the certificates in their proper place on the server (you can find configuration in /etc/httpd/conf.d/ssl.conf). All these should be set:
    SSLCertificateFile
    SSLCertificateKeyFile
    SSLCertificateChainFile
    SSLCACertificateFile

  3. Restart httpd using sudo service httpd restart and make sure httpd started:
    Stopping httpd: [ OK ]
    Starting httpd: [ OK ]

  4. Copy my-private-root-ca.cert to your android project assets folder

  5. Create your trust manager:

    SSLContext SSLContext;

    CertificateFactory cf = CertificateFactory.getInstance("X.509"); InputStream caInput = context.getAssets().open("my-private-root-ca.cert.pem"); Certificate ca; try { ca = cf.generateCertificate(caInput); } 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 = SSLContext.getInstance("TLS");
       SSSLContext.init(null, tmf.getTrustManagers(), null);
    
  6. And make the connection using HttpsURLConnection:

    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setSSLSocketFactory(SSLContext.getSocketFactory());

  7. Thats it, try your https connection.

Solution 14 - Java

Probably you can try something like this. This helped me

    SslContextFactory sec = new SslContextFactory();
    sec.setValidateCerts(false);
    sec.setTrustAll(true);
    
    org.eclipse.jetty.websocket.client.WebSocketClient client = new WebSocketClient(sec);

Solution 15 - Java

Just use this method as your HTTPClient:

public static  HttpClient getNewHttpClient() {
    try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);

        SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        return new DefaultHttpClient(ccm, params);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSam97305421562View Question on Stackoverflow
Solution 1 - JavaUlrich SchellerView Answer on Stackoverflow
Solution 2 - JavaNateView Answer on Stackoverflow
Solution 3 - JavabajohnsView Answer on Stackoverflow
Solution 4 - JavasaxosView Answer on Stackoverflow
Solution 5 - JavaAshishView Answer on Stackoverflow
Solution 6 - JavaJuan SánchezView Answer on Stackoverflow
Solution 7 - JavaAdrian SpineiView Answer on Stackoverflow
Solution 8 - JavaSpeiseView Answer on Stackoverflow
Solution 9 - JavaMatti LyraView Answer on Stackoverflow
Solution 10 - JavaalumatView Answer on Stackoverflow
Solution 11 - JavaSyed Ghulam AkbarView Answer on Stackoverflow
Solution 12 - JavaErick GuardadoView Answer on Stackoverflow
Solution 13 - JavaMikeLView Answer on Stackoverflow
Solution 14 - JavamzaverukView Answer on Stackoverflow
Solution 15 - JavaSerCnaView Answer on Stackoverflow