HTTPS GET (SSL) with Android and self-signed server certificate
Asked Answered
L

7

33

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.

Lucent answered 21/9, 2010 at 15:16 Comment(1)
None of these worked for me (aggravated by the Thawte bug as well see bit.ly/bypAk2). Eventually I got it fixed with #1217641 and #2899579Inner
C
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.

Confiteor answered 28/9, 2010 at 14:12 Comment(4)
Like @Lars D says, other solutions on SO do not work, but this one does, thanks a lot!Oldfangled
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!Gesture
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_NULLPrintable
SSLPeerUnverifiedException : No peer certificateRelief
P
38

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.

Portaltoportal answered 24/10, 2010 at 12:19 Comment(1)
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...Cockspur
V
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.

Verbatim answered 21/9, 2010 at 15:55 Comment(6)
It works for me but admittedly in Java. Are you sure you called it before doing any I/O with the connection?Valise
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...Lucent
What happens if you try to connect to the same server using Java on a non-android device?Verbatim
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.Lucent
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.Verbatim
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.Lucent
J
6

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

Jori answered 28/9, 2010 at 20:21 Comment(0)
B
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 :

Brawn answered 25/9, 2010 at 7:30 Comment(9)
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.Lucent
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.Lucent
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.Lucent
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 : mobile.synyx.de/2010/06/…Brawn
This should be a one-liner in a normal framework, I wonder why nobody seems to have a code snippet to paste in.Lucent
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 : blog.crazybob.org/2010/02/…Brawn
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.Lucent
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.Brawn
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.Lucent
S
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.

Spirit answered 23/10, 2010 at 21:10 Comment(0)
I
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

Ishtar answered 13/8, 2015 at 19:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.