How do I accept a self-signed certificate in Java on Android?
A code sample would be perfect.
I've looked everywhere on the Internet and while some people claim to have found the solution, it either does not work or there is no sample code to back it up.
Unless I missed something, the other answers on this page are DANGEROUS, and are functionally equivalent to not using SSL at all. If you trust self-signed certificates without doing further checks to make sure the certificates are the ones that you are expecting, then anyone can create a self-signed certificate and can pretend to be your server. At that point, you have no real security.
The only legitimate way to do this (without writing a full SSL stack) is to add an additional trusted anchor to be trusted during the certificate verification process. Both involve hard-coding the trusted anchor certificate into your app and adding it to whatever trusted anchors that the OS provides (or else you won't be able to connect to your site if you get a real certificate).
I'm aware of two ways to do this:
Create a custom trust store as described at http://www.ibm.com/developerworks/java/library/j-customssl/#8
Create a custom instance of X509TrustManager and override the getAcceptedIssuers method to return an array that contains your certificate:
Note that this code is completely untested and may not even compile, but should at least steer you in the right direction.
I faced this issue yesterday, while migrating our company's RESTful API to HTTPS, but using self-signed SSL certificates.
I've looking everywhere, but all the "correct" marked answers I've found consisted of disabling certificate validation, clearly overriding all the sense of SSL.
I finally came to a solution:
Create Local KeyStore
To enable your app to validate your self-signed certificates, you need to provide a custom keystore with the certificates in a manner that Android can trust your endpoint.
The format for such custom keystores is "BKS" from BouncyCastle, so you need the 1.46 version of BouncyCastleProvider that you can download here.
You also need your self-signed certificate, I will assume it's named
self_cert.pem
.Now the command for creating your keystore is:
PATH_TO_KEYSTORE
points to a file where your keystore will be created. It MUST NOT EXIST.PATH_TO_bcprov-jdk15on-146.jar.JAR
is the path to the downloaded .jar libary.STOREPASS
is your newly created keystore password.Copy your newly created keystore from
PATH_TO_KEYSTORE
tores/raw/certs.bks
(certs.bks is just the file name; you can use whatever name you wish)Create a key in
res/values/strings.xml
withCreate a this class that inherits
DefaultHttpClient
Now simply use an instance of
**MyHttpClient**
as you would with**DefaultHttpClient**
to make your HTTPS queries, and it will use and validate correctly your self-signed SSL certificates.On Android,
HttpProtocolParams
acceptsProtocolVersion
rather thanHttpVersion
.Brian Yarger's answer works in Android 2.2 as well if you modify the bigger createSocket method overload as follows. It took me a while to get self-signed SSLs working.
@Chris - Posting this as an answer since I can't add comments (yet). I'm wondering if your approach is supposed to work when using a webView. I can't get it do so on Android 2.3 - instead I just get a white screen.
After some more searching, I came across this simple fix for handling SSL errors in a webView which worked like a charm for me.
In the handler I check to see if I'm in a special dev mode and call handler.proceed(), otherwise I call handler.cancel(). This allows me to do development against a self-signed cert on a local website.
I have this functionality in exchangeIt, which connects to Microsoft exchange via WebDav. Here's some code to create an HttpClient which will connect to self signed cert's via SSL:
The EasySSLSocketFactory is here, and the EasyX509TrustManager is here.
The code for exchangeIt is open source, and hosted on googlecode here, if you have any issues. I'm not actively working on it anymore, but the code should work.
Note that since Android 2.2 the process has changed a bit, so check this to make the code above work.