001/* 002 * $Header$ 003 * $Revision: 168 $ 004 * $Date: 2014-05-06 16:25:46 -0700 (Tue, 06 May 2014) $ 005 * 006 * ==================================================================== 007 * 008 * Copyright 2002-2006 The Apache Software Foundation 009 * 010 * Licensed under the Apache License, Version 2.0 (the "License"); 011 * you may not use this file except in compliance with the License. 012 * You may obtain a copy of the License at 013 * 014 * http://www.apache.org/licenses/LICENSE-2.0 015 * 016 * Unless required by applicable law or agreed to in writing, software 017 * distributed under the License is distributed on an "AS IS" BASIS, 018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 019 * See the License for the specific language governing permissions and 020 * limitations under the License. 021 * ==================================================================== 022 * 023 * This software consists of voluntary contributions made by many 024 * individuals on behalf of the Apache Software Foundation. For more 025 * information on the Apache Software Foundation, please see 026 * <http://www.apache.org/>. 027 * 028 */ 029 030package org.apache.commons.httpclient.contrib.ssl; 031 032import org.apache.commons.ssl.HttpSecureProtocol; 033import org.apache.commons.ssl.KeyMaterial; 034import org.apache.commons.ssl.TrustMaterial; 035 036import java.io.IOException; 037import java.net.URL; 038import java.security.GeneralSecurityException; 039import java.security.KeyStoreException; 040 041/** 042 * <p/> 043 * AuthSSLProtocolSocketFactory can be used to validate the identity of the HTTPS 044 * server against a list of trusted certificates and to authenticate to the HTTPS 045 * server using a private key. 046 * </p> 047 * <p/> 048 * <p/> 049 * AuthSSLProtocolSocketFactory will enable server authentication when supplied with 050 * a {@link java.security.KeyStore truststore} file containg one or several trusted certificates. 051 * The client secure socket will reject the connection during the SSL session handshake 052 * if the target HTTPS server attempts to authenticate itself with a non-trusted 053 * certificate. 054 * </p> 055 * <p/> 056 * <p/> 057 * Use JDK keytool utility to import a trusted certificate and generate a truststore file: 058 * <pre> 059 * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore 060 * </pre> 061 * </p> 062 * <p/> 063 * <p/> 064 * AuthSSLProtocolSocketFactory will enable client authentication when supplied with 065 * a {@link java.security.KeyStore keystore} file containg a private key/public certificate pair. 066 * The client secure socket will use the private key to authenticate itself to the target 067 * HTTPS server during the SSL session handshake if requested to do so by the server. 068 * The target HTTPS server will in its turn verify the certificate presented by the client 069 * in order to establish client's authenticity 070 * </p> 071 * <p/> 072 * <p/> 073 * Use the following sequence of actions to generate a keystore file 074 * </p> 075 * <ul> 076 * <li> 077 * <p/> 078 * Use JDK keytool utility to generate a new key 079 * <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre> 080 * For simplicity use the same password for the key as that of the keystore 081 * </p> 082 * </li> 083 * <li> 084 * <p/> 085 * Issue a certificate signing request (CSR) 086 * <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre> 087 * </p> 088 * </li> 089 * <li> 090 * <p/> 091 * Send the certificate request to the trusted Certificate Authority for signature. 092 * One may choose to act as her own CA and sign the certificate request using a PKI 093 * tool, such as OpenSSL. 094 * </p> 095 * </li> 096 * <li> 097 * <p/> 098 * Import the trusted CA root certificate 099 * <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre> 100 * </p> 101 * </li> 102 * <li> 103 * <p/> 104 * Import the PKCS#7 file containg the complete certificate chain 105 * <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre> 106 * </p> 107 * </li> 108 * <li> 109 * <p/> 110 * Verify the content the resultant keystore file 111 * <pre>keytool -list -v -keystore my.keystore</pre> 112 * </p> 113 * </li> 114 * </ul> 115 * <p/> 116 * Example of using custom protocol socket factory for a specific host: 117 * <pre> 118 * Protocol authhttps = new Protocol("https", 119 * new AuthSSLProtocolSocketFactory( 120 * new URL("file:my.keystore"), "mypassword", 121 * new URL("file:my.truststore"), "mypassword"), 443); 122 * <p/> 123 * HttpClient client = new HttpClient(); 124 * client.getHostConfiguration().setHost("localhost", 443, authhttps); 125 * // use relative url only 126 * GetMethod httpget = new GetMethod("/"); 127 * client.executeMethod(httpget); 128 * </pre> 129 * </p> 130 * <p/> 131 * Example of using custom protocol socket factory per default instead of the standard one: 132 * <pre> 133 * Protocol authhttps = new Protocol("https", 134 * new AuthSSLProtocolSocketFactory( 135 * new URL("file:my.keystore"), "mypassword", 136 * new URL("file:my.truststore"), "mypassword"), 443); 137 * Protocol.registerProtocol("https", authhttps); 138 * <p/> 139 * HttpClient client = new HttpClient(); 140 * GetMethod httpget = new GetMethod("https://localhost/"); 141 * client.executeMethod(httpget); 142 * </pre> 143 * </p> 144 * 145 * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a> 146 * <p/> 147 * <p/> 148 * DISCLAIMER: HttpClient developers DO NOT actively support this component. 149 * The component is provided as a reference material, which may be inappropriate 150 * for use without additional customization. 151 * </p> 152 */ 153 154public class AuthSSLProtocolSocketFactory extends HttpSecureProtocol { 155 156 /** 157 * Constructor for AuthSSLProtocolSocketFactory. Either a keystore or truststore file 158 * must be given. Otherwise SSL context initialization error will result. 159 * 160 * @param keystoreUrl URL of the keystore file. May be <tt>null</tt> if HTTPS client 161 * authentication is not to be used. 162 * @param keystorePassword Password to unlock the keystore. IMPORTANT: this implementation 163 * assumes that the same password is used to protect the key and the keystore itself. 164 * @param truststoreUrl URL of the truststore file. May be <tt>null</tt> if HTTPS server 165 * authentication is not to be used. 166 * @param truststorePassword Password to unlock the truststore. 167 */ 168 public AuthSSLProtocolSocketFactory(final URL keystoreUrl, 169 final String keystorePassword, 170 final URL truststoreUrl, 171 final String truststorePassword) 172 throws GeneralSecurityException, IOException { 173 174 super(); 175 176 // prepare key material 177 if (keystoreUrl != null) { 178 char[] ksPass = null; 179 if (keystorePassword != null) { 180 ksPass = keystorePassword.toCharArray(); 181 } 182 KeyMaterial km = new KeyMaterial(keystoreUrl, ksPass); 183 super.setKeyMaterial(km); 184 } 185 186 // prepare trust material 187 if (truststoreUrl != null) { 188 char[] tsPass = null; 189 if (truststorePassword != null) { 190 tsPass = truststorePassword.toCharArray(); 191 } 192 TrustMaterial tm; 193 try { 194 tm = new KeyMaterial(truststoreUrl, tsPass); 195 } catch (KeyStoreException kse) { 196 // KeyMaterial constructor blows up in no keys found, 197 // so we fall back to TrustMaterial constructor instead. 198 tm = new TrustMaterial(truststoreUrl, tsPass); 199 } 200 super.setTrustMaterial(tm); 201 } 202 } 203 204}