org.apache.commons.httpclient.contrib.ssl
Class TrustSSLProtocolSocketFactory

java.lang.Object
  extended by javax.net.SocketFactory
      extended by javax.net.ssl.SSLSocketFactory
          extended by org.apache.commons.ssl.SSLClient
              extended by org.apache.commons.ssl.HttpSecureProtocol
                  extended by org.apache.commons.httpclient.contrib.ssl.TrustSSLProtocolSocketFactory
All Implemented Interfaces:
org.apache.commons.httpclient.protocol.ProtocolSocketFactory, org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory

public class TrustSSLProtocolSocketFactory
extends HttpSecureProtocol

TrustSSLProtocolSocketFactory allows you exercise full control over the HTTPS server certificates you are going to trust. Instead of relying on the Certificate Authorities already present in "jre/lib/security/cacerts", TrustSSLProtocolSocketFactory only trusts the public certificates you provide to its constructor.

TrustSSLProtocolSocketFactory can be used to create SSL Sockets that accepts self-signed certificates. Unlike EasySSLProtocolSocketFactory, TrustSSLProtocolSocketFactory can be used in production. This is because it forces you to pre-install the self-signed certificate you are going to trust locally.

TrustSSLProtocolSocketFactory can parse both Java Keystore Files (*.jks) and base64 PEM encoded public certificates (*.pem).

Example of using TrustSSLProtocolSocketFactory

 1.  First we must find the certificate we want to trust.  In this example
     we'll use gmail.google.com's certificate.
 

openssl s_client -showcerts -connect gmail.google.com:443

2. Cut & paste into a "cert.pem" any certificates you are interested in trusting in accordance with your security policies. In this example I'll actually use the current "gmail.google.com" certificate (instead of the Thawte CA certificate that signed the gmail certificate - that would be too boring) - but it expires on June 7th, 2006, so this example won't be useful for very long!

Here's what my "cert.pem" file looks like:

-----BEGIN CERTIFICATE----- MIIDFjCCAn+gAwIBAgIDP3PeMA0GCSqGSIb3DQEBBAUAMEwxCzAJBgNVBAYTAlpB MSUwIwYDVQQKExxUaGF3dGUgQ29uc3VsdGluZyAoUHR5KSBMdGQuMRYwFAYDVQQD Ew1UaGF3dGUgU0dDIENBMB4XDTA1MDYwNzIyMTI1N1oXDTA2MDYwNzIyMTI1N1ow ajELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1v dW50YWluIFZpZXcxEzARBgNVBAoTCkdvb2dsZSBJbmMxGTAXBgNVBAMTEGdtYWls Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALoRiWYW0hZw 9TSn3s9912syZg1CP2TaC86PU1Ao2qf3pVu7Mx10Wl8W+aKZrQlvrYjTwku4sEh+ 9uI+gWnfmCd0OyVcXr1eFOGCYiiyaPv79Wtb0m0d8GuiRSJhYkZGzGlgFViws2vR BAMCD2fdp7WGJUVGYOO+s52dgAMUHQXxAgMBAAGjgecwgeQwKAYDVR0lBCEwHwYI KwYBBQUHAwEGCCsGAQUFBwMCBglghkgBhvhCBAEwNgYDVR0fBC8wLTAroCmgJ4Yl aHR0cDovL2NybC50aGF3dGUuY29tL1RoYXd0ZVNHQ0NBLmNybDByBggrBgEFBQcB AQRmMGQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0ZS5jb20wPgYIKwYB BQUHMAKGMmh0dHA6Ly93d3cudGhhd3RlLmNvbS9yZXBvc2l0b3J5L1RoYXd0ZV9T R0NfQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEEBQADgYEAktM1l1cV ebi+Uo6fCE/eLnvvY6QbNNCsU5Pi9B5E1BlEUG+AGpgzE2cSPw1N4ZZb+2AWWwjx H8/IrJ143KZZXM49ri3Z2e491Jj8qitrMauT7/hb16Jw6I02/74/do4TtHu/Eifr EZCaSOobSHGeufHjlqlC3ehC4Bx4mLexIMk= -----END CERTIFICATE-----

3. Run "openssl x509" to analyze the certificate more deeply. This helps us answer questions like "Do we really want to trust it? When does it expire? What's the value of the CN (Common Name) field?".

"openssl x509" is also super cool, and will impress all your friends, coworkers, family, and that cute girl at the starbucks. :-)

If you dig through "man x509" you'll find this example. Run it:

openssl x509 -in cert.pem -noout -text

4. Rename "cert.pem" to "gmail.pem" so that step 5 works.

5. Setup the TrustSSLProtocolSocketFactory to trust "gmail.google.com" for URLS of the form "https-gmail://" - but don't trust anything else when using "https-gmail://":

TrustSSLProtocolSocketFactory sf = new TrustSSLProtocolSocketFactory( "/path/to/gmail.pem" ); Protocol trustHttps = new Protocol("https-gmail", sf, 443); Protocol.registerProtocol("https-gmail", trustHttps);

HttpClient client = new HttpClient(); GetMethod httpget = new GetMethod("https-gmail://gmail.google.com/"); client.executeMethod(httpget);

6. Notice that "https-gmail://" cannot connect to "www.wellsfargo.com" - the server's certificate isn't trusted! It would still work using regular "https://" because Java would use the "jre/lib/security/cacerts" file.

httpget = new GetMethod("https-gmail://www.wellsfargo.com/"); client.executeMethod(httpget);

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found

7. Of course "https-gmail://" cannot connect to hosts where the CN field in the certificate doesn't match the hostname. The same is supposed to be true of regular "https://", but HTTPClient is a bit lenient.

httpget = new GetMethod("https-gmail://gmail.com/"); client.executeMethod(httpget);

javax.net.ssl.SSLException: hostname in certificate didn't match: <gmail.com> != <gmail.google.com>

8. You can use "*.jks" files instead of "*.pem" if you prefer. Use the 2nd constructor in that case to pass along the JKS password:

new TrustSSLProtocolSocketFactory( "/path/to/gmail.jks", "my_password".toCharArray() );

Since:
17-Feb-2006
Author:
Credit Union Central of British Columbia, www.cucbc.com, juliusdavies@cucbc.com

DISCLAIMER: HttpClient developers DO NOT actively support this component. The component is provided as a reference material, which may be inappropriate for use without additional customization.


Constructor Summary
TrustSSLProtocolSocketFactory(java.lang.String pathToTrustStore)
           
TrustSSLProtocolSocketFactory(java.lang.String pathToTrustStore, char[] password)
           
 
Method Summary
 
Methods inherited from class org.apache.commons.ssl.HttpSecureProtocol
createSocket
 
Methods inherited from class org.apache.commons.ssl.SSLClient
addTrustMaterial, createSocket, createSocket, createSocket, createSocket, createSocket, createSocket, createSocket, getAssociatedCertificateChain, getCheckCRL, getCheckExpiry, getCheckHostname, getConnectTimeout, getCurrentServerChain, getDefaultCipherSuites, getDefaultProtocol, getEnabledCiphers, getEnabledProtocols, getHostnameVerifier, getNeedClientAuth, getSoTimeout, getSSLContext, getSSLWrapperFactory, getSupportedCipherSuites, getTrustChain, getUseClientMode, getWantClientAuth, isSecure, setCheckCRL, setCheckExpiry, setCheckHostname, setConnectTimeout, setDefaultProtocol, setDnsOverride, setEnabledCiphers, setEnabledProtocols, setHostnameVerifier, setIsSecure, setKeyMaterial, setNeedClientAuth, setSoTimeout, setSSLWrapperFactory, setTrustMaterial, setUseClientMode, setWantClientAuth, useDefaultJavaCiphers, useStrongCiphers
 
Methods inherited from class javax.net.ssl.SSLSocketFactory
getDefault
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 
Methods inherited from interface org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory
createSocket
 
Methods inherited from interface org.apache.commons.httpclient.protocol.ProtocolSocketFactory
createSocket, createSocket
 

Constructor Detail

TrustSSLProtocolSocketFactory

public TrustSSLProtocolSocketFactory(java.lang.String pathToTrustStore)
                              throws java.security.GeneralSecurityException,
                                     java.io.IOException
Parameters:
pathToTrustStore - Path to either a ".jks" Java Key Store, or a ".pem" base64 encoded certificate. If it's a ".pem" base64 certificate, the file must start with "------BEGIN CERTIFICATE-----", and must end with "-------END CERTIFICATE--------".
Throws:
java.security.GeneralSecurityException
java.io.IOException

TrustSSLProtocolSocketFactory

public TrustSSLProtocolSocketFactory(java.lang.String pathToTrustStore,
                                     char[] password)
                              throws java.security.GeneralSecurityException,
                                     java.io.IOException
Parameters:
pathToTrustStore - Path to either a ".jks" Java Key Store, or a ".pem" base64 encoded certificate. If it's a ".pem" base64 certificate, the file must start with "------BEGIN CERTIFICATE-----", and must end with "-------END CERTIFICATE--------".
password - Password to open the ".jks" file. If "truststore" is a ".pem" file, then password can be null; if password isn't null and we're using a ".pem" file, then technically, this becomes the password to open up the special in-memory keystore we create to hold the ".pem" file, but it's not important at all.
Throws:
java.security.cert.CertificateException
java.security.KeyStoreException
java.io.IOException
java.security.NoSuchAlgorithmException
java.security.KeyManagementException
java.security.GeneralSecurityException