ACK! Before we get started, if you are on Windows, then you will need to get Cygwin. If you are on Linux or a Mac, then you are good to go.
http://www.bouncycastle.org/latest_releases.html -> bcprov-jdk16-146.jar
http://www.google.com/ig/api?weather=73102
https://www.google.com/ig/api?weather=73102
This is because the certificate used on this page is trusted by default within Android. To view this....
adb pull /system/etc/security/cacerts.bks cacerts.bks
To view the certs in the bks file
keytool -keystore cacerts.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath C:\tools\bcprov-jdk16-146.jar -storepass changeit -v -list
To import a certificate (not used in this talk)
keytool -keystore cacerts.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath C:\bcprov.jar -storepass changeit -importcert -trustcacerts -alias CACERT -file root.crt
Problem with HTTPS Get - Certificate error
You can modify the cacerts.bks file in a root phone, but not otherwise (that I have found)
This all came about from GeoTrust RootCA not being a trusted CA, I have found where they should be trusted starting in 2.3 (Looks like Google is open to the idea of continuing to add more root CA's - http://code.google.com/p/android/issues/detail?id=10985 )
The certificate chain can get jacked up and possibly work in a desktop browser but not on your phone. The certificate chain needs to be in a linear progression up to the rootCA and I had problems with this as well on my test site where I didn't have the certificate chain quite right.
Per Crazy Bob - "Android has built-in support for the Bouncy Castle keystore format (BKS)." So even though you reference the JAR when working with keytool on your dev machine, it is not needed to have your app use the JAR.
Get an empty BKS keystore - before we can do anything with this keystore we *have* to 'load' it. This is done by passing in a null stream. It basically loads it to nothing. Create an instance of our own SSLSocketFactory, a few things go on here. First off, the HostnameVerifier checks the hostname of the URL against what is contained within the CN field of the certificate. We tell our SocketFactory to allow any/all hostnames. Others are possible such as:
- Browser which will accept a.b.example.com for *.example.com.
- Strict - will not accept a.example.com for *.example.com ... it must be an exact/perfect match
- checkClientTrusted is called to determine if a client using a certificate as authentication is trusted or not
- checkServerTrusted is called when connecting to a server (like what we are doing) and if it is trusted
- getAcceptedIssuers is for client auth, the list of accepted issuers of client authentication based certificates (not what we are interested in)
Next up is HttpParams - I have yet to dig down into the source to figure out how all this is used, but it will not work if you set this to null :)
Just a simple connection manager by passing in the params and registry. You can use SingleClientConnManager or ThreadSafeClientConnManager, since this is a simple app/example I'm going with SingleClientConnManager.
Then easy enough, create a DefaultHttpClient with the connection manager and params.
Using this set up, there will be no validation on any part of the certificate (expiration date, name/CN ...etc) - this seems to be what some people like, but I *really* do not want this when sensitive data is being transmitted.
So now onto SSL/HTTPS.
Get certificate, create BKS store, use in project
Now HTTPS Get works - okay - we are done, goodnight everybody.
keytool and openssl to the rescue
Side note about certificates, DER is a binary form (usually crt extension), when you see BEGIN CERTIFICATE/END CERTIFICATE this a PEM file (a base64 DER encoded file - see Wikipedia).
You can download the certificate through the browser or use this command, this will require a little copy/pasting
openssl s_client -showcerts -connect test.nuisto.com:443 > certs.txt
I have a small script to do this part:
keytool -import -v -trustcacerts -alias 0 -file <(openssl x509 -in theServerCertificate.pem) -keystore $CERTSTORE -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath $JAR -storepass ez24get
Now we are ready to get back into Android/Java code!
View different information regarding SSL of a site
openssl s_client -connect test.nuisto.com:443
Basically the start of it all (that I can find) - this guy must be wicked smart to figure this out with almost nothing showing these problems beforehand (again - that I can find)
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
A competitor to Crazy Bob's article
http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/
If I ever see/meet Antoine or Crazy Bob - I'm buying them a beer.
Great article about the differences between HttpUrlConnection & DefaultHttpClient
http://android-developers.blogspot.com/2011/09/androids-http-clients.html
HttpURLConnection can't do POST with authorization/authentication (one year old)
http://code.google.com/p/android/issues/detail?id=4326
What I use for Basic Authentication, base64 encoding
http://www.androidcoder.org/blog/android-http-request-basic-authentication/
I could not get Preemptive Authentication to work - example
http://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.0.1/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java
This references many open issues ranging from rootCA's, to intermediate problems (out of order certificates as I mentioned earlier)
http://www.mcbsys.com/techblog/2010/12/android-certificates/