34

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:password@anyIPAddress/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.

Sandip Armal Patil
  • 6,241
  • 21
  • 93
  • 160
Lars D
  • 8,483
  • 7
  • 34
  • 37
  • 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 – Adrian Spinei Oct 31 '10 at 16:10

7 Answers7

39

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
  • 21,076
  • 1
  • 35
  • 50
  • 4
    The question already mentioned the security issues. However when you fought your way through a keystore and sorting the certificates and - hours later - still have problems because a "GlobalTrust CA, Inc." is not the same as "GlobalTrust CA Inc." (no comma) you start thinking if the data is sensible at all - and I am very thankful for the code snippet to "disable security". At least for the prototype... – BurninLeo Jun 19 '12 at 13:27
38

I made an app that uses self-signed or trust all certs. The source is here and free to use :P

Just use the HttpManager and create the SSL factory using the trust all one. Sample code found here.

Josh Correia
  • 3,807
  • 3
  • 33
  • 50
Moss
  • 6,002
  • 1
  • 35
  • 40
  • Like @Lars D says, other solutions on SO do not work, but this one does, thanks a lot! – Tim Büthe Nov 09 '10 at 12:39
  • I'm so happy, I could cry. This code was the first solution that worked after much searching. Thanks x1000 for open sourcing your code! – devunwired Dec 19 '10 at 22:35
  • can't seem to make this work. I changed SSLSocketFactory in HttpManager to "TrustAllSSLSocketFactory", but I keep getting "java.security.cert.certpathvalidatorexception: trust anchor for certification path not found. Return an invalid session with invalid cipher suite of SSL_NULL_WITH_NULL_NULL – Evan R. Sep 14 '12 at 19:33
  • SSLPeerUnverifiedException : No peer certificate – uLYsseus Feb 21 '14 at 15:56
7

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
  • 17,381
  • 6
  • 41
  • 47
  • It works for me but admittedly in Java. Are you sure you called it before doing any I/O with the connection? – user207421 Sep 22 '10 at 07:47
  • I have tried many different code snippets, which all replace the hostname verifier and do different kinds of SSL certificate ignoring, but the certificate error message keeps coming, no matter which code snippet I copy. It does not make sense for me to publish specific source code, because I have tried several different solutions - what I would like to see, is something that works on Android. Somebody must have solved the problem before, and there should be able to copy & paste some source code... – Lars D Sep 22 '10 at 14:11
  • What happens if you try to connect to the same server using Java on a non-android device? – Yuliy Sep 22 '10 at 15:48
  • 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 Sep 22 '10 at 19:27
  • 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 Sep 22 '10 at 19:34
  • 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 Sep 25 '10 at 07:14
6

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

Maciek Sawicki
  • 6,717
  • 9
  • 34
  • 48
2

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 :

Community
  • 1
  • 1
Colin Hebert
  • 91,525
  • 15
  • 160
  • 151
  • 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 Sep 25 '10 at 10:21
  • 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 Sep 25 '10 at 10:24
  • 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 Sep 25 '10 at 10:26
  • 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 Sep 25 '10 at 10:40
  • 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 Sep 25 '10 at 11:56
  • 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 Sep 25 '10 at 12:16
  • 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 Sep 25 '10 at 12:43
  • 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 Sep 25 '10 at 13:13
  • 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 Sep 26 '10 at 11:37
1

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
  • 2,467
  • 1
  • 20
  • 21
0

I made an app that uses self-signed certificate 4 month ago here is the code i hope it helps: https://bitbucket.org/momo0002/tlsdemo.git

moji
  • 267
  • 5
  • 15