1.Warnings About Using SSLSocket Directly
So far, the examples have focused on HTTPS using HttpsURLConnection
. Sometimes apps need to use SSL separate from HTTP. For example, an email app might use SSL variants of SMTP, POP3, or IMAP. In those cases, the app would want to use SSLSocket
directly, much the same way that HttpsURLConnection
does internally.
The techniques described so far to deal with certificate verification issues also apply to SSLSocket
. In fact, when using a custom TrustManager
, what is passed to HttpsURLConnection
is an SSLSocketFactory
. So if you need to use a custom TrustManager
with an SSLSocket
, follow the same steps and use thatSSLSocketFactory
to create your SSLSocket
.
Caution: SSLSocket
does not perform hostname verification. It is up the your app to do its own hostname verification, preferably by calling getDefaultHostnameVerifier()
with the expected hostname. Further beware that HostnameVerifier.verify()
doesn't throw an exception on error but instead returns a boolean result that you must explicitly check.
Here is an example showing how you can do this. It shows that when connecting to gmail.com port 443 without SNI support, you'll receive a certificate for mail.google.com. This is expected in this case, so check to make sure that the certificate is indeed for mail.google.com:
1 // Open SSLSocket directly to gmail.com 2 SocketFactory sf = SSLSocketFactory.getDefault(); 3 SSLSocket socket = (SSLSocket) sf.createSocket("gmail.com", 443); 4 HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier(); 5 SSLSession s = socket.getSession(); 6 7 // Verify that the certicate hostname is for mail.google.com 8 // This is due to lack of SNI support in the current SSLSocket. 9 if (!hv.verify("mail.google.com", s)) { 10 throw new SSLHandshakeException("Expected mail.google.com, " 11 "found " + s.getPeerPrincipal()); 12 } 13 14 // At this point SSLSocket performed certificate verificaiton and 15 // we have performed hostname verification, so it is safe to proceed. 16 17 // ... use socket ... 18 socket.close();
2.Blacklisting
SSL relies heavily on CAs to issue certificates to only the properly verified owners of servers and domains. In rare cases, CAs are either tricked or, in the case of Comodo or DigiNotar, breached, resulting in the certificates for a hostname to be issued to someone other than the owner of the server or domain.
In order to mitigate this risk, Android has the ability to blacklist certain certificates or even whole CAs. While this list was historically built into the operating system, starting in Android 4.2 this list can be remotely updated to deal with future compromises.
3.Pinning
An app can further protect itself from fraudulently issued certificates by a technique known as pinning. This is basically using the example provided in the unknown CA case above to restrict an app's trusted CAs to a small set known to be used by the app's servers. This prevents the compromise of one of the other 100+ CAs in the system from resulting in a breach of the apps secure channel.
4.Client Certificates
This article has focused on the user of SSL to secure communications with servers. SSL also supports the notion of client certificates that allow the server to validate the identity of a client. While beyond the scope of this article, the techniques involved are similar to specifying a custom TrustManager
. See the discussion about creating a custom KeyManager
in the documentation for HttpsURLConnection
.