Dig into Https client connection in Android

Dig into Https client connection in Android

Table of Contents

  • reference resources
  • Java Keytool
  • Certificate formats
  • Use Https in Android Client
  • Java SSLContext
  • Two ways SSL verification
  • TLSDemo

2 Java Keytool

Java keystore is like a database which store certificates and private keys and protect them by a password maybe. There are at least three formats of that, JKS, PKCS12, JCEKS, and many more.
But in this tutorial, I only consider two formats of that JKS which is the Java's default format and BKS which is the Android's default format.

How to import a certificate to the BKS style KeyStore? First step was to prepare your certificate at least, the PEM format and DER format is ok. Then to download bcprov-jdk16-146.jar. after that use following command to import an X590 certificate into the keystore.

keytool -importcert -v -trustcacerts -file "my_server_cert.der" -alias key_alias -keystore "my.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-146.jar" -storetype BKS

Import an PEM X509 certificate into JKS keystore:

keytool -importcert -v -trustcacerts -file "cas.pem" -alias cas_alias -keystore "cas.jks" -storetype JKS

The default export format of keytool is der format.

keytool -exportcert -alias cas_alias -keystore "cas.jks" > cas.der

3 Certificate formats

The certificate which I mentioned here are all reference to X509 format, which is not just the most wildly used, but also the standard in the PKI industry. The evidence is that there is Certificate interface in the JDK, but with just only one child implementation, X509Certificate class.

Now, go back to the point, there are two X509 Certificate formats here, PEM and CER, they are equivalent same things. PEM is base64 encoded format, CER is the binary format.

Using the following cmds to download and convert between each other.

#download pem certificate by guntls
gnutls-cli --print-cert www.youwebsite.com | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'

#download pem certificate by openssl
openssl s_client -connect ${HOST}:${PORT} </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'

# convert DER binary format certificate to PEM base64 encoded format
openssl x509 -inform der -in cas.der -outform pem -out cas.pem

# convert PEM base64 encoded format certificate to DER binary format
openssl x509 -inform pem -in cas.pem -outform der -out cas.der

4 Use Https in Android Client

Before going that, you need to figure out how many http clients in Android. Basically, there are only two http clients available in Android, HttpUrlConnection and AndroidHttpClient, which are provided by the system. While HttpUrlConnection is the barely the only one left now, because AndroidHttpClient and its sibling, DefaultHttpClient and its parent HttpClient are all deprecated in Android 2.3. So choose HttpUrlConnection if you wanna wrote any http client code.

And the most of the 3rd party Http Clients are developed above them, Volley, and what ever, except Square's OkHttp, which implements its own http stack.

5 Java SSLContext

I think to use SSL programming in java is to understand SSLContext and its related classes KeyManager, TrustManager, KeyManagerFactory, TrustManagerFactory, and SSLSocketFactory.
Here is just a piece of code:

KeyStore keyStore = null;
try {
    keyStore = KeyStore.getInstance("BKS");
    keyStore.load(in, passwd.toCharArray());
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
    tmf.init(keyStore);

    TrustManager[] tms = tmf.getTrustManagers();

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tms, null);
    SSLSocketFactory ssf = sslContext.getSocketFactory();

} catch (KeyStoreException e) {
    e.printStackTrace();
} catch (CertificateException e) {
    e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

While that's not enough, that's why I wrote following demo TLSDemo.

5 Two-ways SSL verification

Two-ways certificate verification is also named the client side verification, it is part of SSL/TLS
standards. 

The normal SSL request process is the client connected to the server and ask for its certificate, the one-way verification. The two-ways verification is the server send the request to client, ask for client's certificate after the normal one-way certificate request.

In this case, the client side must be configured just like the server side, the certificates links and also its private key. In the Android, the client side configuration is really simple, just init the SSLContext with the right KeyManger, check the TLSDemo.

6 TLSDemo

I wrote this demo TLSDemo to illustrate how to use SSL client in Android. It illustrates following puzzles:
  • How to import certificates in PEM format.
  • How to import certificates in BKS type Keystore.
  • How to connect https sites with HttpUrlConnection.
There are still some faults in this demo, the HttpClient https connection is not implemented actually, because of the already deprecated api was so incompatible, for example, HttpClient is the apache's http client interface, so its SSLSocketFactory is not compatible with the javax.net.SSLSocketFactory. I already give up to implement the HttpClient implementation, may be the best reference is android_volley_example.

Except the unfinished HttpClient part, TLSDemo is still a good reference of how to use https in UrlConnection, and how SSLContext works?

Comments

Popular posts from this blog

Bluedroid stack in android

How to setup a NAT server?

Network programming in elisp