Android: Trusting SSL certificates

Two weeks ago I got the task to establish TLS secured connections via certificates to a service endpoint.
I thought it’s not a big deal, because the endpoint already uses an EV certificate from a trusted CA (SwissSign) in Switzerland. Therefore I shouldn’t have to worry that the certificate would be considered as untrusted so I don’t have to import it to the trusted certs in the  Java  key store etc.
FAIL! I’ve got a security exception, cert is not trusted. Same problem when I visit the website with the browser. Ok, that’s bad, SwissSign is not such a big player like thawte, so, it needs some time till it will be added to the android trusted CA list. But, when I visit thawte.com, their cert is also not trusted by android. WTF?
Windows Phone and iPhone trust my SwissSign CA and don’t complain.

So, let’s ask google, stackoverflow and the blogosphere. Found a lot of solutions how to disable certificate checking entirely.
Yeah, great, this will solve my problem, my connection will be “secure” and everyone will be able to intercept my connection and inject his own certificate. But I finally found the solution with help from other sites and some testing and debugging.

The Solution

The following main steps are required to achieve a secured connection from trusted Certification Authorities.

  1. Grab all required certificates (root and any intermediate CA’s)
  2. Create a keystore with keytool and the BouncyCastle provider and import the certs
  3. Load the keystore in your android app and use it for the secured connections
    • Don’t use the standard java.net.ssl.HttpsURLConnection for the secure connection. Use the Apache HttpClient (Version 4 atm) library, which is already built-in in android. It’s built on top of the java connection libraries and is, in my opinion, faster, better modularized and easier to understand.

Step 1: Grab the certs

You have to obtain all certificates that build a chain from the endpoint certificate the whole way up to the Root CA. This means, any (if present) Intermediate CA certs and also the Root CA cert. You don’t need to obtain the endpoint certificate.
You can obtain those certs from the chain (if provided) included in the endpoint certificate or from the official site of the issuer (in my case SwissSign).

Ensure that you save the obtained certificates in the Base64 encoded X.509 format. The content should look similar to this:

-----BEGIN CERTIFICATE-----
MIIGqTC.....
-----END CERTIFICATE-----

Step 2: Create the keystore

Download the BouncyCastle Provider and store it to a known location.
Also ensure that you can invoke the keytool command (usually located under the bin folder of your JRE installation).

Now import the obtained certs (don’t import the endpoint cert) into a BouncyCastle formatted keystore.
I didn’t tested it, but I think the order of importing the certificates is important. This means, import the lowermost Intermediate CA certificate first and then all the way up to the Root CA certificate.

With the following command a new keystore (if not already present) with the password mysecret will be created and the Intermediate CA certificate will be imported. I also defined the BouncyCastle provider, where it can be found on my file system and the keystore format. Execute this command for each certificate in the chain.

keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

Verify if the certificates were imported correctly into the keystore:

keytool -list -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

Should output the whole chain:

RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43

Now you can copy the keystore as a raw resource in your android app under res/raw/

Step 3: Use the keystore in your app

First of all we have to create a custom Apache HttpClient that uses our keystore for HTTPS connections:

public class MyHttpClient extends DefaultHttpClient {

	final Context context;

	public MyHttpClient(Context context) {
		this.context = context;
	}

	@Override
	protected ClientConnectionManager createClientConnectionManager() {
		SchemeRegistry registry = new SchemeRegistry();
		registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
		// Register for port 443 our SSLSocketFactory with our keystore
		// to the ConnectionManager
		registry.register(new Scheme("https", newSslSocketFactory(), 443));
		return new SingleClientConnManager(getParams(), registry);
	}

	private SSLSocketFactory newSslSocketFactory() {
		try {
			// Get an instance of the Bouncy Castle KeyStore format
			KeyStore trusted = KeyStore.getInstance("BKS");
			// Get the raw resource, which contains the keystore with
			// your trusted certificates (root and any intermediate certs)
			InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
			try {
				// Initialize the keystore with the provided trusted certificates
				// Also provide the password of the keystore
				trusted.load(in, "mysecret".toCharArray());
			} finally {
				in.close();
			}
			// Pass the keystore to the SSLSocketFactory. The factory is responsible
			// for the verification of the server certificate.
			SSLSocketFactory sf = new SSLSocketFactory(trusted);
			// Hostname verification from certificate
			// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
			sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
			return sf;
		} catch (Exception e) {
			throw new AssertionError(e);
		}
	}
}

We have created our custom HttpClient, now we can just use it for secure connections. For example when we make a GET call to a REST resource.

// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();

That’s it. Took me long to figure it out, hope this helps and saves you that time.

I really hope that the android platform will implement a better mechanism in future releases for defining which Certification Authorities should be trusted or not or just expand their own trusted CA list. If they don’t, I can’t believe they will get good acceptance from the business sector. Ok, you can control which certificates you want to trust in your app, but you still can’t add thawte as a trusted CA in the android keystore and your browser will always complain about an untrusted CA. The only way I know to eliminate this problem is to root your phone (very user friendly) and add your CA manually to the android keystore.

Feel free to comment.

Category: android, Coding  Tags: , , ,
You can follow any responses to this entry through the RSS 2.0 feed. You can skip to the end and leave a response. Pinging is currently not allowed.
87 Responses
  1. Mur Votema says:

    OMG.
    Why is android team doing many things so complicated?!

  2. Saran says:

    Still getting:
    Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: IssuerName(CN=thawte Primary Root CA, OU=”(c) 2006 thawte, Inc. – For authorized use only”, OU=Certification Services Division, O=”thawte, Inc.”, C=US) does not match SubjectName(CN=Thawte SSL CA, O=”Thawte, Inc.”, C=US) of signing certificate
    :(

    Could you try importing and using certificates from this site:
    https://eu.battle.net/login/en/login.xml?app=armory&locale=en_US&ref=http%3A%2F%2Feu.wowarmory.com%2Fvault%2Fcalendar-feed.xml
    to see if you can get it to work?

  3. Hi Saran

    Hmm… I could reproduce your mentioned exception. Everything looks good with the certificates. I intercepted the HTTPS with Wireshark and saw something very interesting.

    The certificates are sent in the following order from the battle.net server:
    > *.battle.net
    >> thawte Primary Root CA
    >>> Thawte SSL CA (this is the intermedaite cert)

    I really can’t believe that the Cert. Path validation is so bad implemented, that the order how the server sends the certificates is important.
    But I’ve had a customer, whose server was sending the endpoint server certificate twice. And I got similar exceptions in android (IE, Chrome and Firefox weren’t complaining, they also didn’t show the duplicate in the chain). We removed the duplicate from the chain and everything worked fine.
    It’s really possible that the Cert. Path validation really depends on the correct order, which in may opinion sucks.

    I also tried in your case to import the thawte Root cert first and then the Intermediate cert into the keystore, but still got the same exception.

    Maybe you can write to battle.net to change their order, or write your own CertPathValidator or just use the crappier HttpsUrlConnection from the standard java libraries. There you can turn off certificate validation off at all (but you loose a lot of security).

    Hope this helps you a bit.

    Greetz

  4. Saran says:

    Thanks for verifying, Antoine.

    I tried reverse-importing the certs into the store, but even though I imported them in this order:
    > *.battle.net
    >> thawte Primary Root CA
    >>> Thawte SSL CA (this is the intermedaite cert)

    I got this list:
    Keystore type: BKS
    Keystore provider: BC

    Your keystore contains 3 entries

    thawte Primary Root CA, 26.10.2010., trustedCertEntry,
    Certificate fingerprint (MD5): 8C:CA:DC:0B:22:CE:F5:BE:72:AC:41:1A:11:A8:D8:12
    *.battle.net, 26.10.2010., trustedCertEntry,
    Certificate fingerprint (MD5): FC:1C:1D:FE:FF:4A:AE:EA:11:4B:54:8C:2B:F0:C1:51
    Thawte SSL CA, 26.10.2010., trustedCertEntry,
    Certificate fingerprint (MD5): EB:A3:71:66:38:5E:3E:F4:24:64:ED:97:52:E9:9F:1B

    When I used that keystore, I got a different error:

    10-26 20:43:23.743: WARN/System.err(5423): javax.net.ssl.SSLException: Not trusted server certificate
    10-26 20:43:23.743: WARN/System.err(5423): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371)
    10-26 20:43:23.753: WARN/System.err(5423): at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92)
    10-26 20:43:23.753: WARN/System.err(5423): at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381)
    10-26 20:43:23.753: WARN/System.err(5423): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:164)
    10-26 20:43:23.753: WARN/System.err(5423): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
    10-26 20:43:23.753: WARN/System.err(5423): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
    10-26 20:43:23.753: WARN/System.err(5423): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)
    10-26 20:43:23.753: WARN/System.err(5423): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
    10-26 20:43:23.763: WARN/System.err(5423): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
    10-26 20:43:23.763: WARN/System.err(5423): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
    10-26 20:43:23.763: WARN/System.err(5423): at org.homedns.saran.android.wowcalendarsync.network.NetworkUtilities.authenticateWithPass(NetworkUtilities.java:344)
    10-26 20:43:23.763: WARN/System.err(5423): at org.homedns.saran.android.wowcalendarsync.network.NetworkUtilities$1.run(NetworkUtilities.java:164)
    10-26 20:43:23.763: WARN/System.err(5423): at org.homedns.saran.android.wowcalendarsync.network.NetworkUtilities$5.run(NetworkUtilities.java:276)
    10-26 20:43:23.763: WARN/System.err(5423): Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Could not validate certificate signature.
    10-26 20:43:23.763: WARN/System.err(5423): at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)
    10-26 20:43:23.763: WARN/System.err(5423): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366)
    10-26 20:43:23.773: WARN/System.err(5423): … 12 more
    10-26 20:43:23.773: WARN/System.err(5423): Caused by: java.security.cert.CertPathValidatorException: Could not validate certificate signature.
    10-26 20:43:23.793: WARN/System.err(5423): at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:342)
    10-26 20:43:23.793: WARN/System.err(5423): at java.security.cert.CertPathValidator.validate(CertPathValidator.java:202)
    10-26 20:43:23.793: WARN/System.err(5423): at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164)
    10-26 20:43:23.793: WARN/System.err(5423): … 13 more
    10-26 20:43:23.793: WARN/System.err(5423): Caused by: java.security.SignatureException: Signature was not verified.
    10-26 20:43:23.803: WARN/System.err(5423): at org.apache.harmony.security.provider.cert.X509CertImpl.fastVerify(X509CertImpl.java:601)
    10-26 20:43:23.803: WARN/System.err(5423): at org.apache.harmony.security.provider.cert.X509CertImpl.verify(X509CertImpl.java:544)
    10-26 20:43:23.803: WARN/System.err(5423): at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:337)
    10-26 20:43:23.803: WARN/System.err(5423): … 15 more

    Using BC version you suggested and used keytool from these Java plugins (on Win7 64bit):
    jdk1.6.0_20 64bit
    jdk1.6.0_22 64bit
    jdk1.6.0_20 32bit

    I used this to retrieve certs:
    openssl s_client -connect eu.battle.net:443 -showcerts

  5. Hi Saran

    You should NOT place the *.battle.net certificate in your keystore. Your keystore should only contain the trusted issuers (the Root CA and any intermediate CA’s) and not the endpoint certificate itself.

    The check if your endpoint certificate is valid is done with several other criterias, like the hostname verification (does the cert correspond to the presented site).

    Please let me know if this is working.

  6. Saran says:

    Yes, I tried it also with only Intermediate and Root (with having tried each of them imported as 1st at one time). Same result :(

  7. Saran says:

    I’ve asked a question on StackOverflow:
    http://stackoverflow.com/questions/4115101/apache-httpclient-on-android-producing-certpathvalidatorexception-issuername

    Hopefully, someone will think of a solution…

  8. Hi Seran

    I tried to answer your question on stackoverflow. Hope it helps ;)

  9. Andreas says:

    Thanks so much for this most useful info!

  10. Nilz says:

    Hi Antoine,

    Your blog aims to tackle the exact problem I’m faced with, however I cannot get your solution to work.

    I keep getting the following in LogCat:

    11-19 15:12:34.777: ERROR/OpenSSLSocketImpl(520): Unknown error 5 during connect
    11-19 15:12:34.777: WARN/System.err(520): java.io.IOException: SSL handshake failure: I/O error during system call, Unknown error: 0
    11-19 15:12:34.786: WARN/System.err(520): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.nativeconnect(Native Method)
    11-19 15:12:34.786: WARN/System.err(520): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:305)
    11-19 15:12:34.786: WARN/System.err(520): at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92)
    11-19 15:12:34.786: WARN/System.err(520): at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:321)
    11-19 15:12:34.795: WARN/System.err(520): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:129)
    11-19 15:12:34.795: WARN/System.err(520): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
    11-19 15:12:34.795: WARN/System.err(520): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
    11-19 15:12:34.795: WARN/System.err(520): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)
    11-19 15:12:34.795: WARN/System.err(520): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
    11-19 15:12:34.795: WARN/System.err(520): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
    11-19 15:12:34.795: WARN/System.err(520): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
    11-19 15:12:34.795: WARN/System.err(520): at me.test.TempActivity.onCreate(TempActivity.java:30)
    11-19 15:12:34.805: WARN/System.err(520): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    11-19 15:12:34.805: WARN/System.err(520): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
    11-19 15:12:34.814: WARN/System.err(520): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
    11-19 15:12:34.814: WARN/System.err(520): at android.app.ActivityThread.access$2200(ActivityThread.java:119)
    11-19 15:12:34.814: WARN/System.err(520): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
    11-19 15:12:34.814: WARN/System.err(520): at android.os.Handler.dispatchMessage(Handler.java:99)
    11-19 15:12:34.814: WARN/System.err(520): at android.os.Looper.loop(Looper.java:123)
    11-19 15:12:34.814: WARN/System.err(520): at android.app.ActivityThread.main(ActivityThread.java:4363)
    11-19 15:12:34.814: WARN/System.err(520): at java.lang.reflect.Method.invokeNative(Native Method)
    11-19 15:12:34.814: WARN/System.err(520): at java.lang.reflect.Method.invoke(Method.java:521)
    11-19 15:12:34.814: WARN/System.err(520): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    11-19 15:12:34.814: WARN/System.err(520): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    11-19 15:12:34.826: WARN/System.err(520): at dalvik.system.NativeStart.main(Native Method)

    Have you seen this before? Do you know what it means. Unfortunately I cannot share the certificate with you, but I can tell you that is was a p12 certificate which I exported to a X509 in windows xp.

    I really need help on this issue, any guidance would be a great help.

    Cheers,
    Nilz.

  11. Vlad says:

    I tried to implemented and getting error. Any ideas?
    Here is my cert list

    {2df05992-4d0f-48af-9d89-342c0af1d238}, Nov 19, 2010, PrivateKeyEntry,
    Certificate fingerprint (MD5): 90:99:AC:3E:0A:22:7C:81:26:EC:6F:F4:04:F5:BB:A5
    GeotrustCA, Nov 19, 2010, trustedCertEntry,
    Certificate fingerprint (MD5): 67:CB:9D:C0:13:24:8A:82:9B:B2:17:1E:D1:1B:EC:D4

    11-19 12:34:42.577: WARN/System.err(4233): java.net.SocketException: The operation timed out
    11-19 12:34:42.587: WARN/System.err(4233): at org.apache.harmony.luni.platform.OSNetworkSystem.connectStreamWithTimeoutSocketImpl(Native Method)
    11-19 12:34:42.587: WARN/System.err(4233): at org.apache.harmony.luni.platform.OSNetworkSystem.connect(OSNetworkSystem.java:115)
    11-19 12:34:42.597: WARN/System.err(4233): at org.apache.harmony.luni.net.PlainSocketImpl.connect(PlainSocketImpl.java:244)
    11-19 12:34:42.597: WARN/System.err(4233): at org.apache.harmony.luni.net.PlainSocketImpl.connect(PlainSocketImpl.java:533)
    11-19 12:34:42.607: WARN/System.err(4233): at java.net.Socket.connect(Socket.java:1055)
    11-19 12:34:42.607: WARN/System.err(4233): at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:119)
    11-19 12:34:42.607: WARN/System.err(4233): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:143)
    11-19 12:34:42.617: WARN/System.err(4233): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
    11-19 12:34:42.617: WARN/System.err(4233): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
    11-19 12:34:42.617: WARN/System.err(4233): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)
    11-19 12:34:42.617: WARN/System.err(4233): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
    11-19 12:34:42.617: WARN/System.err(4233): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
    11-19 12:34:42.617: WARN/System.err(4233): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)

  12. Nick says:

    I am very please with your tutorial; it is very thorough, but I am having flaky success.

    I am trying to use it to access Google’s login url: https://www.google.com/accounts/ClientLogin.

    I built everything just the way you detailed. Then the first time I ran it I got the expected response, but every time after that I got “javax.net.ssl.SSLException: Not trusted server certificate”.

    I’ve managed to get the desired response about 3 times, but nothing I change seems to have an effect. I sure would appreciate your help. I don’t know why Android makes this so difficult.

  13. swapnil says:

    Hi,

    I like to know how google manage security certificate on Android. Reason i am asking is i came across a webcast by google for android and in that they mention storing certificate on Android device and using it instead of passing it everytime and accordingly this reduces data connection overhead.

    I am trying to achieve something similar.. i dont want to pass and receive server/client secure certificate everytime.
    My application is kind of pushengine without google PUSH API.

    Awaiting your views.

  14. Hi there

    Sorry for the late response, I was away for a couple of days.

    @Nilz:
    Never seen this error before. Can you provide some code (of the SSL Factory)? Maybe this helps: http://stackoverflow.com/questions/2899079/custom-ssl-handling-stopped-working-on-android-2-2-froyo

    @Vlad:
    The error is indicating that your operation timed out. Does your app executes the request to the server? You could intercept the traffic between the emulator and server for example with Wireshark. Sometimes the reply from the server could also be helpful.

    @Nick:
    Thanks.
    I think the Google ClientLogin uses a different approach.
    http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html

    @swapnil:
    Do you have the link or name of the mentioned webcast?
    I think I didn’t understand your question. What do you mean with storing the certificate and not passing it every time? The certificates are just passed during the establishment of the secure connection. After the cert. exchange (when all certificates are considered as trusted and valid) session keys are generated to secure the actual data. The session keys are valid until the connection closes.

    Found an useful link: http://tokudu.com/2010/how-to-implement-push-notifications-for-android/

    Greetz
    Antoine

  15. Gergo says:

    Hi Antoine

    a very nice tutorial. Thank for that.
    My question is regarding client authentication. As far as i saw, the Apache HttpClient cannot handle this situation. When using only Server Auth, it works perfect , but when setting the Server to authenticate the client it fails.Do you know something about it ?
    I am trying it now the “Java way” with SSL Socket , but it fails too with ” Not trusted Server certifiate :(
    PLZ drop me an email if you have knowledge about turials or articles dealing with that problem

    Thanks in advance
    Gergo

  16. Gergo says:

    Hi Antoine
    i figured out the problem with the “Not Trusted server certificate”
    It was the TrustManager. For some reason i do not know, The Trustmanager could not authenticate the certificate of the server. I have implemented my own.
    Client authentication works now.
    but if you have any idea how to do it with the Apache HttpClient, please drop me some line
    Thanks
    Gergo

  17. Lys says:

    Hi,
    I found your post while looking for a solution to a similar problem. What I need is to connect to the remote server and download the cert for my app to use. Basically steps 1 and 2 but within the app itself. Any thoughts on how to do that?
    Thanks

  18. Martin says:

    Hi,
    very useful, but I’m getting stuck with a 404 reply in the response. Have you any ideas to the reason for this?
    Wireshark shows a encrypted data load, length 288, which could corespond to the expected return from the Webservice

    Thanks

  19. @Gergo
    Hmm… AFAIK the Apache HttpClient is not able to handle client authentication with cert.

    @Lys
    Didn’t look very deep into those links.
    How to create your own keystore:
    http://www.coderanch.com/t/133048/Security/do-programmatically-create-keystore-import
    How to obtain the certificate from the site:
    http://helpdesk.objects.com.au/java/how-do-i-programatically-extract-a-certificate-from-a-site-and-add-it-to-my-keystore

    @Martin
    Can you access your resource via browser (without 404)?
    Maybe your HTTP headers are wrong and the server returns a 404 (but another error code would be much more appropriate in this case). In my opinion 288 bytes is not very much. Maybe the 404 error itself.

    You can try two approaches to see what’s going on with the response:
    1. If you have the private key of the webservice (I doubt that) you can encrypt the traffic with Wireshark. See http://htluo.blogspot.com/2009/01/decrypt-https-traffic-with-wireshark.html
    2. This is the PITA alternative, but you DON’T need the private key from the webservice. You can download fiddler2 (www.fiddler2.com), add the proxy certificate from fiddler (or create a new one to match the hostname to your webservice) to the app keystore. Then add an argument in your Android Emulator to use the fiddler proxy to connect to the webservice. See http://mrrask.wordpress.com/2009/10/01/setting-up-the-android-emulator-for-http-debugging-using-fiddler2/ Your app in the emulator will connect to fiddler and there you can see the decrypted payload.

  20. pyko says:

    Hi Antonie,
    Firstly, thanks heaps for this post – it’s really really helpful & well written too! :D

    Implemented your solution and bumping into similar problem to Nick – where the authentication is quite flaky :( though i’m not authing with Google accounts…

    Without changing anything, sometimes logging in will work first attempt… other times it requires several attempts to work..

    Looking at my stacktrace, I would’ve thought I got the order wrong…but I double checked that and what doesn’t make sense is that it sometimes works….
    javax.net.ssl.SSLException: Not trusted server certificate
    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371)
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92)
    at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381)
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:164)
    ….etc….
    Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: IssuerName(CN=thawte Primary Root CA, OU=”(c) 2006 thawte, Inc. – For authorized use only”, OU=Certification Services Division, O=”thawte, Inc.”, C=US) does not match SubjectName(CN=Thawte SSL CA, O=”Thawte, Inc.”, C=US) of signing certificate
    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)
    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366)
    … 24 more
    Caused by: java.security.cert.CertPathValidatorException: IssuerName(CN=thawte Primary Root CA, OU=”(c) 2006 thawte, Inc. – For authorized use only”, OU=Certification Services Division, O=”thawte, Inc.”, C=US) does not match SubjectName(CN=Thawte SSL CA, O=”Thawte, Inc.”, C=US) of signing certificate
    at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:373)
    at java.security.cert.CertPathValidator.validate(CertPathValidator.java:202)
    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164)
    … 25 more

  21. Martin says:

    Hi again,
    the Ws can be browsed both on real device/emulator and from pc without problems. Cert chain is exported from firefox (https://google.com/accounts Worked this way).

    http works fine. I’ll investigate the output from wireshark

    Thnx
    martin

  22. Martin says:

    no difference between wireshark output from http and https

    very strange

  23. allen says:

    Hey everyone,

    I think I was able to find a fix to the sporadic nature of this solution. For those who used Antoine’s solution, but get inconsistent behavior, try importing just the root cert into your keystore and not the intermediate cert. not sure if this only worked for our setup with our servers, but it worked for us. I noticed all the exceptions I got were because it was trying to compare the root cert against the intermediate. Hope that helps!

  24. Martin says:

    Hi,
    I finally found a solution for the 404 problem.
    the Webservice I’m calling is a .Net wcf service on an Intranet server, and the config of the ws was the problem.

    After doing a binding modification (http://www.codemeit.com/wcf/wcf-wsdl-xsdimport-schemalocations-link-to-local-machine-name-not-domain-name-while-hosted-in-iis.html)
    a super simple config file solved the problem

    I tried many other config solutions, but this one worked for me. Hope this can help others

    /Martin

  25. @pyko
    I think that the order of the present certificates could still be the problem, especially when you are connecting to an endpoint, which is behind a web farm. One miss configured web server could send the certificates in the wrong order, another one not.
    Check with Wireshark etc. if the order is correct.

    If you are not able to change the certificate order of the webserver, you could change the order programmatically.

    More info about changing the order programmatically can be found on this stackoverflow topic: http://stackoverflow.com/questions/4115101/apache-httpclient-on-android-producing-certpathvalidatorexception-issuername/4199518#4199518

    @allen:
    AFAIK every involved certificate must be in the keystore. Never tried to remove the intermediate cert. But I could imagine, that if the order of the certificates is sent wrong from the webserver, for example the first entry is the Root CA and not the Intermediate, then the Bouncy Castle checks only against the one and only Root CA certificate in the keystore and completes the checking. But this is just an assumption. You can also look at the link that I posted to pyko.

  26. Teresa says:

    Hi Antoine,

    Very pleased with this tutorial. In my app, I am trying to send a soap request using ksoap2, which is working fine in my test environment. If I am trying to connect to a secured site, getting ‘Not trusted server certificate’. I dont want to bypass the certificate check like it was mentioned in some of the blogs. Is it possible to implement your solution with soap. Here is how I am sending the request.

    HttpsTransportSE transport = new HttpsTransportSE(URL, 443, “”, 60000);
    transport.call(SOAP_ACTION, envelope);

    Appreciate your help.

    Thanks,
    Teresa

  27. Matt says:

    Any luck finding an answer to Teresa’s question? I’m having the same problem. I’m fairly sure the 3rd parameter is the keystore with the certificate, but i’m not sure how to find that? Can you help?

    Thanks,
    Matt

  28. pyko says:

    @allen & @Antoine
    Strangely enough just importing the root CA worked! I am able to login successfully everytime now (assuming I enter the correct credentials of course)

  29. @Martin
    I’m glad that you solved the problem. Thank you for commenting the solution here.

    @pyko
    Thank you very much for your testing.

    @Teresa & @Matt
    I’m sorry. I have no idea how to solve this one. Never used ksoap2. I can’t find any useful reference for the parameters in the HttpsTransportSE constructor. Maybe this entry helps a bit: http://stackoverflow.com/questions/2248147/andoird-ksoap2-https-problem/4438993#4438993

    Keep on going and please let me know if you found a solution. Thanks

  30. steff says:

    Hi, very nice howto.

    But I’ve got a weird one. I created a self-signed certificate. It works flawlessly for all clients over WiFi. However, it fails on SOME devices over 3G/GPRS with CONNECTION_TIMED_OUT or CONNECTION_REFUSED exception. Any pieces of advice?

    Also posted this on http://stackoverflow.com/questions/5172857/https-connection-works-over-wifi-wlan-but-not-for-3g-gprs-umts

    Thanks in advance,
    steff

  31. Neil says:

    Everyone seems to know but me… how do I download the certificate(s) and intermediate certificate(s)?? Thanks.

    - Neil

  32. @steff
    Is the colleague using the same Android version as you? Did you try to establish the connection via the Apache HttpClient? If not, try it, because the java.net libraries have some difficulties in the reliability in some versions.

    @Neil
    If you cant obtain the certificate via IE or any other browser, try it with openssl, for example:
    echo | openssl s_client -connect blog.antoine.li:443 2>&1 |
    sed -ne ‘/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p’ > mycert.pem (Took this info from http://blog.crazybob.org)

  33. Andy says:

    Antoine,
    Thanks for the detailed steps. I’m trying to make a connection from an app to https://auth.startssl.com and it gives me the following error:
    WARN/System.err(1736): java.io.IOException: SSL handshake failure: Failure in SSL library, usually a protocol error

    Any help/suggestions would be greatly appreciated.

    Thanks,
    Andy

  34. Hi Andy

    Do you realize that your URL requires a client certificate authentication. This means, that not only the client expects a (valid) certificate from the webserver, also the webserver expects a certificate from the client for authentication.

    Do you provide such a certificate in your code?

  35. Syed says:

    You are GOD!

  36. Syed says:

    You say to import the intermediate certificates, so all the intermediate certificates import into one file?

  37. @Syed
    Thanks for your compliment, but if I were GOD, we shouldn’t worry about certificate issues on android anymore ;)

    Yes, you need to import each intermediate certificate and at last the root certificate into a single keystore file. The order of your import is important (interm. cert first…)

  38. zealot says:

    Hi, thanks for your detailed blog.

    I am facing a problem: I use tomcat as web server, but it only accepts JKS, PKCS11 and PKCS12; while on Android, only BKS is supported. So if I use keytool to generate a JKS format certificate and keystore, but it cannot be used by Android. Is there any way to do conversions? Like, to convert JKS to BKS? or another question is Android can use PKCS12 certificate? If so, how to convert JKS to PKCS12?

    Thank you very much! You did an excellent job!

  39. elioncho says:

    Hello,

    I’m trying to connect to a webservice through my android application.
    In which order should I add these certs to my app’s keystore?

    1 Subject CN=*.heroku.com, O=”Heroku, Inc.”, L=San Francisco,
    ST=California, C=US
    Issuer CN=DigiCert High Assurance CA-3, OU=www.digicert.com,
    O=DigiCert Inc, C=US

    2 Subject CN=DigiCert High Assurance CA-3, OU=www.digicert.com,
    O=DigiCert Inc, C=US
    Issuer CN=DigiCert High Assurance EV Root CA, OU=www.digicert.com,
    O=DigiCert Inc, C=US

    3 Subject CN=DigiCert High Assurance EV Root CA, OU=www.digicert.com,
    O=DigiCert Inc, C=US
    Issuer CN=Entrust.net Secure Server Certification Authority,
    OU=(c) 1999 Entrust.net Limited, OU=www.entrust.net/CPS incorp. by
    ref. (limits liab.), O=Entrust.net, C=US

  40. @elioncho
    You need to import the lowermost intermediate certificate (in your case this is cert 2) first. The root ca (cert 3) must be imported at last.
    You don’t need to import your wildcard certificate (cert 1) at all into the keystore.

    But please note: As I can see, your root CA cert (cert 3) is probably not a root certificate at all, because the subject and issuer names are different. A root CA cert have the same subject and issuer name (because the Root CA issues a certificate for itself). Please check if you have the right Root CA cert.

  41. elioncho says:

    @Antoine I did as you told me in your message, but I keep getting an error. The error messages are below ( By the way, when I was adding the root ca the following message was returned: “Certificate already exists in system-wide CA keystore under alias “.

    I don’t understand all that issuer-subject relation, but I have fetched other sites certificates and I found its a common pattern to not match at all. BTW, I downloaded the root and intermediate certificate from Digicert.

    Below are the error messages (TrustAnchor for CertPath not found error seems suspicious, any ideas?)

    Thank you for your time!

    04-29 17:05:51.081: WARN/System.err(228): javax.net.ssl.SSLException: Not trusted server certificate
    04-29 17:05:51.101: WARN/System.err(228): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360)
    04-29 17:05:51.111: WARN/System.err(228): at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92)
    04-29 17:05:51.111: WARN/System.err(228): at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:321)
    04-29 17:05:51.111: WARN/System.err(228): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:129)
    04-29 17:05:51.111: WARN/System.err(228): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
    04-29 17:05:51.111: WARN/System.err(228): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
    04-29 17:05:51.121: WARN/System.err(228): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)
    04-29 17:05:51.121: WARN/System.err(228): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
    04-29 17:05:51.121: WARN/System.err(228): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
    04-29 17:05:51.131: WARN/System.err(228): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
    04-29 17:05:51.141: WARN/System.err(228): at com.android.thedescent.Score$HttpPostRequest.doInBackground(Score.java:248)
    04-29 17:05:51.141: WARN/System.err(228): at com.android.thedescent.Score$HttpPostRequest.doInBackground(Score.java:1)
    04-29 17:05:51.141: WARN/System.err(228): at android.os.AsyncTask$2.call(AsyncTask.java:185)
    04-29 17:05:51.171: WARN/System.err(228): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
    04-29 17:05:51.180: WARN/System.err(228): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
    04-29 17:05:51.180: WARN/System.err(228): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
    04-29 17:05:51.190: WARN/System.err(228): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
    04-29 17:05:51.190: WARN/System.err(228): at java.lang.Thread.run(Thread.java:1096)
    04-29 17:05:51.200: WARN/System.err(228): Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.
    04-29 17:05:51.210: WARN/System.err(228): at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)
    04-29 17:05:51.210: WARN/System.err(228): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:355)
    04-29 17:05:51.210: WARN/System.err(228): … 17 more
    04-29 17:05:51.220: WARN/System.err(228): Caused by: java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.
    04-29 17:05:51.240: WARN/System.err(228): at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:149)
    04-29 17:05:51.240: WARN/System.err(228): at java.security.cert.CertPathValidator.validate(CertPathValidator.java:211)
    04-29 17:05:51.250: WARN/System.err(228): at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164)
    04-29 17:05:51.270: WARN/System.err(228): … 18 more

  42. Subair says:

    Hi.. thanks… words can’t express my gratitude…

    Keep it up…

    Thank you very much..

  43. @elioncho
    When you imported your Root CA cert into your keystore, you most probably specified an alias that is already assigned to a cert that is already in your keystore.
    In your case, I would create a new keystore and just import the needed certificates (just specify another filename for your keystore).

    About the Issuer/Subject pattern: The issuer is the authority, which issues a certificate to a subject. For example the “DigiCert High Assurance CA-3″ issued a cert to “*.heroku.com” and the Root cert authority “DigiCert High Assurance EV Root CA” issued a cert for “DigiCert High Assurance CA-3″. So, there is a certificate chain from the lowest cert (which in your case is heroku.com) through all Intermediate CA to the Root CA. Only the Root CA cert does not match this Issuer/Subject pattern. The root cert contains the same value for the Issuer and Subject field, because it is the root (topmost instance) of the cert chain. Therefore no superior instance is available, which can issue the Root CA cert to the root instance. In this case, the Root CA instance issues a certificate to itself (so the subject field is identical with the issuer).

    So, just create a new keystore and import the intermediate CA cert first and then the Root CA cert. Don’t import your wildcard (heroku.com) cert. The keystore is just used to specify which Intermediate and Root Cert Authorities you want to trust. When your wildcart cert matches to the WHOLE chain (up to the root cert) in your keystore, it is considered as trusted (if all other validations succeeded, like expriry date etc.) and you can create a secured connection.

    NOTE: Please check, if your webserver is sending the certificates in the correct order. Further info on comment #25

  44. Andy G says:

    Just wanted to add my thanks to you – this is a far too complicated process and seems to be poorly documented elsewhere – I simply couldn’t have negotiated it without your excellent blog.

    For the record, I also had to compromise and create a keystore with only the root CA imported – as @pyko, @allen and others have said.

    Delighted to have finally made that https connection!!

  45. Rob says:

    Antoine, you’re my hero!!! Thank you so much for sharing this solution!!!

    Rob

  46. Tim in Colorado says:

    Awesome info. I just have one question:

    Why the BouncyCastle KeyStore instead of the one built-in to Android (java.security.KeyStore), like the example code you linked to does?

    If I could use the latter, that would be a HUGE gain, since the BouncyCastle provider is 1.6Mb of JAR file (I haven’t yet checked to see how much of that ends up in the final package, but that’s HUGE). I’ve already got 6Mb of app package, and I’d prefer not to make it any larger if I don’t absolutely have to.

  47. Hi Tim

    Android uses already BouncyCastle. It’s built-in in the OS. You don’t need to include the libraries to your app.

    Greetz

  48. Thanks for the clarification Antoine. Got it in and it works as expected!

  49. gkee42 says:

    Hi,

    I want to add my thanks for a useful post.

    For my 2c worth, I had some trouble creating the keystore in Ubuntu, I kept getting this error:
    keytool error: java.lang.ClassNotFoundException: org.bouncycastle.jce.provider.BouncyCastleProvider

    From googling the error I found if I moved the bouncycastle jar to $JAVA_HOME/jre/lib/ext/ then it worked.

  50. WizBribe says:

    I was wondering why I run into troubles with TLS by these days… Then I realized I used to work with a 2.2 VM and, as I’m using my old laptop while on vacation, there’s a 2.1 VM. The big difference is that StartSSL (my certs provider) appears to be a trusted provider on 2.2, not 2.1! I googled a bit and found this very useful post. As I’m used with keytool, cert chains and so on since many years, I simply go straight forward your explanation with the greatest of ease.

    Problem solved, thanks a lot.

  51. h32 says:

    Hi Antonie, did you can help me please, i’m trying to get root CA from odesk.com but always get only one the Intremedinate CA during check the bks file

  52. Mahadevan Sreenivasan says:

    Thanks a bunch for this code. This works perfect. I have one more concern though. I need to keep the ssl session resuable. Is there anyway this could be converted to SSLCertificateSocketFactory instead of SSLSocketFactory so that the session becomes cached with SSLSessionCache.

  53. bob9 says:

    Thanks for this, I have been looking around trying to find this solution for months. Only issue I had was exporting the certificates. I found the easiest way to export the certificates was to use firefox. Go to the https://www.TheURLYouWantToTrust.com in you want to trust in firefox then click then to the left of the URL to bring up the certificate information then click More Information, View Certificate, Detail Tab, Then selection the root and the intermediate certificate in the tree view to be exported and click export. I was using firefox 3.6, old but did the job. http://www.mozilla.org/en-US/firefox/all-older.html

  54. MrCalculator says:

    This article is a really good undivided. As a result of for shareing such great facts out. Ill deff be driving by more often so i an take in whats original!

  55. Chris says:

    Antoine,

    First of all thank you very much for your post on how to import and use trusted certificates in an android app. I highly appreciate it. I had a question for you. What would happen when the imported certificates expire? Do we need to deploy a new version of the android app with new certificates?

    Thanks

    Chris

  56. @Chris
    When the imported (Root and Intermediate) certs expire, they need to be replaced with newer ones.

    But AFAIK you must not deploy a new app, you could also implement a mechanism in your app to fetch a new keystore file or certificates and “install” them on the app. But I do not recommend this option due to security reasons.

  57. Anna says:

    Thank you for a great post!

    I had a problem with having a capital letter in “myKeystore.bks”. You might want to change the name in your article.

  58. I am not sure where you are getting your information, but good topic. I needs to spend some time studying more or figuring out more. Thanks for fantastic info I used to be searching for this info for my mission.

  59. ribben says:

    Hello mate, excellent tutorial…

    Please check this page’s root cert and intermediate
    https://web.itc.auth.gr/PubCookie.reply

    And also some noob question i get an error when i am trying to set HttpClient client = new MyHttpClient(getApplicationContext());

    the getApplicationContext is the error…

    I am eagerely waiting for your reply…
    Once again thanks for the great tutorial!!!

  60. MarchingHome says:

    You, sir, are my hero.

    And hereby I ++ Anna’s comment.

  61. malarprathap says:

    Hi,
    I have tried above code but i got the following exception.

    12-09 14:53:22.657: WARN/System.err(4667): javax.net.ssl.SSLException: Not trusted server certificate
    12-09 14:53:22.657: WARN/System.err(4667): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371)
    12-09 14:53:22.657: WARN/System.err(4667): at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92)
    12-09 14:53:22.657: WARN/System.err(4667): at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381)
    12-09 14:53:22.667: WARN/System.err(4667): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:164)
    12-09 14:53:22.667: WARN/System.err(4667): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
    12-09 14:53:22.667: WARN/System.err(4667): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
    12-09 14:53:22.667: WARN/System.err(4667): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)
    12-09 14:53:22.667: WARN/System.err(4667): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
    12-09 14:53:22.667: WARN/System.err(4667): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
    12-09 14:53:22.667: WARN/System.err(4667): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
    12-09 14:53:22.667: WARN/System.err(4667): at com.dev.env.RestJsonClient.connect(RestJsonClient.java:102)
    12-09 14:53:22.667: WARN/System.err(4667): at com.dev.env.HttpTestProjectActivity$1.onClick(HttpTestProjectActivity.java:32)
    12-09 14:53:22.667: WARN/System.err(4667): at android.view.View.performClick(View.java:2408)
    12-09 14:53:22.677: WARN/System.err(4667): at android.view.View$PerformClick.run(View.java:8816)
    12-09 14:53:22.677: WARN/System.err(4667): at android.os.Handler.handleCallback(Handler.java:587)
    12-09 14:53:22.677: WARN/System.err(4667): at android.os.Handler.dispatchMessage(Handler.java:92)
    12-09 14:53:22.677: WARN/System.err(4667): at android.os.Looper.loop(Looper.java:123)
    12-09 14:53:22.677: WARN/System.err(4667): at android.app.ActivityThread.main(ActivityThread.java:4627)
    12-09 14:53:22.677: WARN/System.err(4667): at java.lang.reflect.Method.invokeNative(Native Method)
    12-09 14:53:22.677: WARN/System.err(4667): at java.lang.reflect.Method.invoke(Method.java:521)
    12-09 14:53:22.677: WARN/System.err(4667): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    12-09 14:53:22.677: WARN/System.err(4667): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    12-09 14:53:22.677: WARN/System.err(4667): at dalvik.system.NativeStart.main(Native Method)
    12-09 14:53:22.677: WARN/System.err(4667): Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: IssuerName(CN=VeriSign Class 3 Public Primary Certification Authority – G5, OU=”(c) 2006 VeriSign, Inc. – For authorized use only”, OU=VeriSign Trust Network, O=”VeriSign, Inc.”, C=US) does not match SubjectName(CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com/rpa (c)06, OU=VeriSign Trust Network, O=”VeriSign, Inc.”, C=US) of signing certificate
    12-09 14:53:22.687: WARN/System.err(4667): at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)
    12-09 14:53:22.687: WARN/System.err(4667): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366)
    12-09 14:53:22.687: WARN/System.err(4667): … 22 more
    12-09 14:53:22.687: WARN/System.err(4667): Caused by: java.security.cert.CertPathValidatorException: IssuerName(CN=VeriSign Class 3 Public Primary Certification Authority – G5, OU=”(c) 2006 VeriSign, Inc. – For authorized use only”, OU=VeriSign Trust Network, O=”VeriSign, Inc.”, C=US) does not match SubjectName(CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com/rpa (c)06, OU=VeriSign Trust Network, O=”VeriSign, Inc.”, C=US) of signing certificate
    12-09 14:53:22.697: WARN/System.err(4667): at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:373)
    12-09 14:53:22.697: WARN/System.err(4667): at java.security.cert.CertPathValidator.validate(CertPathValidator.java:202)
    12-09 14:53:22.697: WARN/System.err(4667): at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164)
    12-09 14:53:22.697: WARN/System.err(4667): … 23 more

    Domain name : http://www.apptivo.com

    how to resolve this issue?

  62. Maragues says:

    Thank you so much, you helped me not only to make my app work, but to understand all this SSL mess.

  63. Pavel says:

    Please make me keystore for api.mymobigift.com

  64. Pavel says:

    I really need it.

  65. Herm says:

    In this code (from above):

    // Instantiate the custom HttpClient
    DefaultHttpClient client = new MyHttpClient(getApplicationContext());
    HttpGet get = new HttpGet(“https://www.mydomain.ch/rest/contacts/23″);
    // Execute the GET call and obtain the response
    HttpResponse getResponse = client.execute(get);
    HttpEntity responseEntity = getResponse.getEntity();

    is the url automatically encrypted? I used this code but changed it to a post method and added some params. It’s working fine, but now I’m wondering if the url and form are encrypted.

    By the way, the keystore, etc. worked perfectly for me… You saved me A LOT of time and helped me learn some things, and I very much appreciate it.

  66. Brant says:

    Thank you very much for a detailed description.

  67. admin says:

    Thanks for sharing, I will test into my android.

  68. Herm says:

    Is there ANY reason you can think of that all this code would work in Android 4 but not in 2?? I am at a total loss. It works perfectly on my phone running Android 4 but breaks in emulators and phones running 2.3 or lower.

    I keep thinking I must be doing something wrong, but then I remember that it works in 4. I’m not posting the code because I’m using your code! Also, I created a keystore with my site’s cert, loaded it into a trust manager, and that is all working – in 4, not 2.

    ANY IDEAS?!

  69. Melvin Lai says:

    Hi,

    I am having problem with this command on the bcprov-jdk16-146.jar (latest update)

    keytool -importcert -v -trustcacerts -file payserv.cer -alias IntermediateCA -keystore myKeystore.bks -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk16-146.jar -storepass test -storetype BKS

    I am getting this error:

    keytool error: java.io.FileNotFoundException: myKeystore.bks (Access is denied)
    java.io.FileNotfoundException: myKeystore.bks (Access is denied)
    at java.io.FileOutputStream.open(Native Method)
    at java.io.FileOutputStream.(Unknown source)
    at java.io.FileOutputStream.(Unknown Source)
    at sun.security.tools.KeyTool.doCommands (Unknown Source)
    at sun.security.tools.KeyTool.run(Unknown Source)
    at sun.security.tools.KeyTool.main(Unknown Source)

  70. Andrews says:

    I second Ribben on the getApplicationContext error, eclipse asks to create new method. What should I do to get around it?

    I suppose I can use POST instead of GET, right?

    Thanks for your time, the tutorial seems really useful!

  71. bram says:

    Hi,
    I am runtime exception after executing the code. creation of truststore and listing of certs in truststore are same including Bouncy castle version on device 1.34.

    I’m using : Rooted Galaxy S-I900 with 2.2.x android

    FATAL EXCEPTION: main
    java.lang.AssertionError: java.io.IOException: Wrong version of key store.
    at com.httpsurlconn.SecureHttpClient.newSslSocketFactory(SecureHttpClient.java:151)
    at com.httpsurlconn.SecureHttpClient.createClientConnectionManager(SecureHttpClient.java:125)
    at org.apache.http.impl.client.AbstractHttpClient.getConnectionManager(AbstractHttpClient.java:221)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:539)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
    at com.httpsurlconn.HttpsurlconnActivity.onCreate(HttpsurlconnActivity.java:55)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
    at android.app.ActivityThread.access$2300(ActivityThread.java:125)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:4627)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    at dalvik.system.NativeStart.main(Native Method)
    Caused by: java.io.IOException: Wrong version of key store.
    at org.bouncycastle.jce.provider.JDKKeyStore.engineLoad(JDKKeyStore.java:839)
    at java.security.KeyStore.load(KeyStore.java:676)
    at com.httpsurlconn.SecureHttpClient.newSslSocketFactory(SecureHttpClient.java:139)
    … 19 more

  72. thomas nussbaumer says:

    thanks a lot mate. This is just what i needed.

  73. WebnetMobile.com says:

    Important note: you HAVE TO stay away from v147 of Bouncy Castle or you face “Wrong version of key store” exception Stick o v146 and you will be fine:

    ftp://ftp.bouncycastle.org//pub/release1.46/bcprov-jdk16-146.jar

  74. Jim says:

    Similar to some of the later comments from users, I am having a BKS keystore problem although so far it defies solution. The 1st error I got was the “wrong version of keystore”, error listed by WebnetMobile. I found other webposts indicating “don’t use v147″ of BouncyCastle or default. So I tried using mentioned bcprov-jdk16-146.jar, but I cannot get keytool to recognize this jar. I have tried placing the jar in $JAVA_HOME/lib/ext and adding “security.provider.3=org.bouncycastle.jce.provider.BouncyCastleProvider” to java.security, w/o success. I have tried specifying a path in the keytool command:
    “keytool -genkeypair -v -alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 -keypass android -keystore /Users/djames/dropbox/bc146keystore/debug.keystore -storepass android -storetype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider –providerpath /Users/djames/dropbox/bc146keystore/bcprov-jdk16-146.jar”
    but then I get this error: “keytool error: java.lang.RuntimeException: Usage error, ?providerpath is not a legal command”. Which is odd since when I run keytool -help, it lists -providerpath as a legal command. (Although when you look on oracle website {http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html}, keytool has no option for -provider path…???) I am using MacOSX with JavaSE6 (Vendor=Apple). I tried using alternate software for creating a BKS keystore (http://portecle.sourceforge.net/) which appears successful in creating the keystore (although not even sure which version of BC it used…). However, now Eclipse (Indigo SR2) will not recognize the keystore when packaging the android apk and throws a “java.io.IOException: Invalid keystore format”, and I’m not sure why. I have added the bcprov-jdk16-146.jar to the android build path. Has anybody using Eclipse had success in using the BouncyCastle BKS format keystore with android and have any tips?

    In summary, the usual tricks working for others aren’t working for me, and I have no clue as to why. Any help greatly appreciated.

  75. Vil says:

    hi,
    i all did with your tutorial to make a ssl conection in android app. but i got

    javax.net.ssl.SSLPeerUnverifiedException: No peer certificate

    warning and then null pointer exception.
    i’ve already google it but not suitable solution for me.
    do you have any idea?

    • chipiik says:

      If you’re getting “No peer certificate” then you probably use wrong certificate. Check fingerprints in keystore and on server (e.g. in chrome web browser)

  76. I do not even know the way I finished up here, however I believed this post was good.
    I do not recognize who you’re but certainly you are going to a famous blogger when you aren’t
    already. Cheers!

  77. Joseph says:

    i tried and got wrong version of keystore exception.

  78. carrizo says:

    I’ll try this for a self-signed certificate! thanks for the information.

  79. Zed says:

    Hi !
    Thanks for the tips ! but now i have a “java.net.UnknownHostException : my.domain.name.fr” exception.

    Any idea ?

  80. Artyom says:

    Thanks a lot for the article – it helps me a lot and save my time. The only thing that should be mentioned is Bouncy Castle provider library version: currently last Java version (it is 1.47) can not work with Andoid. One of the previous releases should be used. Instead you will receive java.lang.AssertionError: java.io.IOException: Wrong version of key store.

  81. subburaj says:

    how to use the sslsession cache in this code. have implemented this code to request ssl certified url

  82. Minh Trung says:

    Thanks for your post so much. I had already connected with https!

  83. user says:

    Very useful post, thanks

  84. Prateek says:

    My company’s certficate file extension is crt,i want to convert into Base64 encoded X.509 format so that i can use it in android,how to do this?

  85. Prateek says:

    Hi Antonie,

    I have followed each and every step and have built the bks file also,have also done coding according to the details given by you but then also i am getting no peer certificate exception.What should i do now?Please help me to sort out this..

  86. Andy Res says:

    Works perfectly! Thank you alot!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>