tags:

views:

499

answers:

8

I have looked into various posts about how to retrieve something via HTTPS on Android, from a server that uses a self-signed certificate. However, none of them seem to work - they all fail to remove the "javax.net.ssl.SSLException: Not trusted server certificate" message.

It is not an option to modify the server to have a trusted certificate, and it is also not an option to make the server certificate match the server's IP address.

Note, that the server will not have a DNS name, it will only have an IP-address. The GET request looks something like this:

https://username:[email protected]:443/blabla/index.php?param=1&param2=3

I am fully aware that this solution is prone to man-in-the-middle attacks etc.

So, the solution must ignore the lack of trust in the certificate, and ignore the hostname mismatch.

Does anybody know the code, that does this, using Java for Android?

There are plenty of attempts to explain this on stackoverflow.com, and plenty of code snippets, but they don't seem to work, and nobody has provided one block of code that solves this, as far as I can see. It would be interesting to know if somebody really solved this, or if Android simply blocks certificates that are not trusted.

+4  A: 

If you're using an HttpsURLConnection, then try calling setHostnameVerifier on it before connect(), and passing it a HostnameVerifier that just accepts regardless of veracity.

Yuliy
I tried that, but it does not remove the error message.
Lars D
It works for me but admittedly in Java. Are you sure you called it before doing any I/O with the connection?
EJP
Lars D
What happens if you try to connect to the same server using Java on a non-android device?
Yuliy
Yuliy, your question would only make sense if I had one piece of code that fails, and I tried to fix that piece of code. But I tried many different pieces of code, from stackoverflow.com and other places. Some of them probably work outside Android, some maybe not. That would not help me. The goal is to find a complete code snippet for Android, that is known to work.
Lars D
Lars, I'm asking to try and determine if the fact that it's on android is a red herring. That's what trying to perform the SSL connection from a desktop java client would do.
Yuliy
Yuliy, if you have some code that you know works on Java in general, you are welcome to post it, and I will try it. But please post the full code.
Lars D
+2  A: 

If you have an access to the devices you can add the certificate to a keystore. See more informations here.

On the other hand you can use this method, but I think it's kind of ugly.


Resources :

On the same topic :

Colin Hebert
The I already tried the two source code snippets that you linked to, but both report that the server certificate is not trusted, it seems as if it simply doesn't work.
Lars D
I also tried some of the code in the "HTTPS connection android" thread - with the same result. What bothers me, is that all those that try to help, don't provide one code snippet that works, and if I combine the code snippets that they provide, it doesn't work.
Lars D
Adding the certificate to a keystore is one workaround, but it is a tedious process because it would require that the client knows the server configuration, and that is an unwanted assumption.
Lars D
As I see it the best way to deal with it is to rewrite your own `SSLSocketFactory` if you don't want to use a keystore. This tutorial explain in details how to do it : http://mobile.synyx.de/2010/06/android-and-self-signed-ssl-certificates/
Colin Hebert
This should be a one-liner in a normal framework, I wonder why nobody seems to have a code snippet to paste in.
Lars D
As you said, it's against the purpose of SSL to accept any certificate. So obviously there is no easy way to deal with it. The best way to do thing as I said above is to use the keystore method. There is an interesting article from Bob lee on this particular subject on its blog, he used bouncy castle to handle the keystore part : http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
Colin Hebert
Good programming tools always make it easy to test your code, and nobody wants to spend time on installing a trusted certificate for a simple test that is not related to production and does not need security. Just like we may use telnet to test an SMTP or HTTP server, it needs to be easy to download something from an HTTPS server, disabling security.
Lars D
Concerning development I always either manually added the self signed certificate or created my own CA. It's not that hard to create and it really helps to see how it will work in production. Anyway, did you read the link in my previous comment ? It allows you to use easily a keystore.
Colin Hebert
In my case, the server certificate is not necessarily known at the time of installing the Android app. That nobody seems to have source code to do this, starts to make me believe that Android is not capable of doing this.
Lars D
+5  A: 

I made an app that uses self-signed or trust all certs. The source is here: http://code.google.com/p/meneameandroid/source/browse/#svn/trunk/src/meneameApp/src/com/dcg/auth and free to use :P

Just use the HttpManager and create the SSL factory using the trust all one: http://code.google.com/p/meneameandroid/source/browse/trunk/src/meneameApp/src/com/dcg/util/HttpManager.java

Moss
+1  A: 

You can do it quiet securely: http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html

Maciek Sawicki
A: 

Have you been able to find a solution to this? I have tried at least 50 different approaches that I found scattered around the web that all claimed to fix this. None of them worked.

metalideath
Nope, not yet - but I didn't try the solutions here. I hope to get time to try that, soon.
Lars D
A: 

If you ask me, do it the secure way.

Found a good tutorial http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/ and it's really not that difficult to implement.

Also the tutorial recommended by Maciek is very good.

I tested it, and it works in my app without problems.

saxos
+1  A: 

As you correctly point out, there are two issues: a) the certificate isn't trusted, and b) the name on the certificate doesn't match the hostname.

WARNING: for anybody else arriving at this answer, this is a dirty, horrible hack and you must not use it for anything that matters. SSL/TLS without authentication is worse than no encryption at all - reading and modifying your "encrypted" data is trivial for an attacker and you wouldn't even know it was happening.

Still with me? I feared so...

a) is solved by creating a custom SSLContext whose TrustManager accepts anything:

SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[] {
  new X509TrustManager() {
    public void checkClientTrusted(X509Certificate[] chain, String authType) {}
    public void checkServerTrusted(X509Certificate[] chain, String authType) {}
    public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
  }
}, null);
HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());

and b) by creating a HostnameVerifier which allows the connection to proceed even though the cert doesn't match the hostname:

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

Both must happen right at the beginning of your code, before you start messing around with HttpsURLConnections and so on. This works both in Android and the regular JRE. Enjoy.

SimonJ
A: 

None of these worked for me (aggravated by the Thawte bug as well see http://bit.ly/bypAk2). Eventually I got it fixed with http://stackoverflow.com/questions/1217141/self-signed-ssl-acceptance-android and http://stackoverflow.com/questions/2899079/custom-ssl-handling-stopped-working-on-android-2-2-froyo

aspinei