001 /*
002 * $Header$
003 * $Revision: 129 $
004 * $Date: 2007-11-14 19:21:33 -0800 (Wed, 14 Nov 2007) $
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
030 package org.apache.commons.httpclient.contrib.ssl;
031
032 import org.apache.commons.ssl.HttpSecureProtocol;
033 import org.apache.commons.ssl.KeyMaterial;
034 import org.apache.commons.ssl.TrustMaterial;
035
036 import java.io.IOException;
037 import java.net.URL;
038 import java.security.GeneralSecurityException;
039
040 /**
041 * <p/>
042 * AuthSSLProtocolSocketFactory can be used to validate the identity of the HTTPS
043 * server against a list of trusted certificates and to authenticate to the HTTPS
044 * server using a private key.
045 * </p>
046 * <p/>
047 * <p/>
048 * AuthSSLProtocolSocketFactory will enable server authentication when supplied with
049 * a {@link java.security.KeyStore truststore} file containg one or several trusted certificates.
050 * The client secure socket will reject the connection during the SSL session handshake
051 * if the target HTTPS server attempts to authenticate itself with a non-trusted
052 * certificate.
053 * </p>
054 * <p/>
055 * <p/>
056 * Use JDK keytool utility to import a trusted certificate and generate a truststore file:
057 * <pre>
058 * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
059 * </pre>
060 * </p>
061 * <p/>
062 * <p/>
063 * AuthSSLProtocolSocketFactory will enable client authentication when supplied with
064 * a {@link java.security.KeyStore keystore} file containg a private key/public certificate pair.
065 * The client secure socket will use the private key to authenticate itself to the target
066 * HTTPS server during the SSL session handshake if requested to do so by the server.
067 * The target HTTPS server will in its turn verify the certificate presented by the client
068 * in order to establish client's authenticity
069 * </p>
070 * <p/>
071 * <p/>
072 * Use the following sequence of actions to generate a keystore file
073 * </p>
074 * <ul>
075 * <li>
076 * <p/>
077 * Use JDK keytool utility to generate a new key
078 * <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
079 * For simplicity use the same password for the key as that of the keystore
080 * </p>
081 * </li>
082 * <li>
083 * <p/>
084 * Issue a certificate signing request (CSR)
085 * <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
086 * </p>
087 * </li>
088 * <li>
089 * <p/>
090 * Send the certificate request to the trusted Certificate Authority for signature.
091 * One may choose to act as her own CA and sign the certificate request using a PKI
092 * tool, such as OpenSSL.
093 * </p>
094 * </li>
095 * <li>
096 * <p/>
097 * Import the trusted CA root certificate
098 * <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
099 * </p>
100 * </li>
101 * <li>
102 * <p/>
103 * Import the PKCS#7 file containg the complete certificate chain
104 * <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
105 * </p>
106 * </li>
107 * <li>
108 * <p/>
109 * Verify the content the resultant keystore file
110 * <pre>keytool -list -v -keystore my.keystore</pre>
111 * </p>
112 * </li>
113 * </ul>
114 * <p/>
115 * Example of using custom protocol socket factory for a specific host:
116 * <pre>
117 * Protocol authhttps = new Protocol("https",
118 * new AuthSSLProtocolSocketFactory(
119 * new URL("file:my.keystore"), "mypassword",
120 * new URL("file:my.truststore"), "mypassword"), 443);
121 * <p/>
122 * HttpClient client = new HttpClient();
123 * client.getHostConfiguration().setHost("localhost", 443, authhttps);
124 * // use relative url only
125 * GetMethod httpget = new GetMethod("/");
126 * client.executeMethod(httpget);
127 * </pre>
128 * </p>
129 * <p/>
130 * Example of using custom protocol socket factory per default instead of the standard one:
131 * <pre>
132 * Protocol authhttps = new Protocol("https",
133 * new AuthSSLProtocolSocketFactory(
134 * new URL("file:my.keystore"), "mypassword",
135 * new URL("file:my.truststore"), "mypassword"), 443);
136 * Protocol.registerProtocol("https", authhttps);
137 * <p/>
138 * HttpClient client = new HttpClient();
139 * GetMethod httpget = new GetMethod("https://localhost/");
140 * client.executeMethod(httpget);
141 * </pre>
142 * </p>
143 *
144 * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a>
145 * <p/>
146 * <p/>
147 * DISCLAIMER: HttpClient developers DO NOT actively support this component.
148 * The component is provided as a reference material, which may be inappropriate
149 * for use without additional customization.
150 * </p>
151 */
152
153 public class AuthSSLProtocolSocketFactory extends HttpSecureProtocol {
154
155 /**
156 * Constructor for AuthSSLProtocolSocketFactory. Either a keystore or truststore file
157 * must be given. Otherwise SSL context initialization error will result.
158 *
159 * @param keystoreUrl URL of the keystore file. May be <tt>null</tt> if HTTPS client
160 * authentication is not to be used.
161 * @param keystorePassword Password to unlock the keystore. IMPORTANT: this implementation
162 * assumes that the same password is used to protect the key and the keystore itself.
163 * @param truststoreUrl URL of the truststore file. May be <tt>null</tt> if HTTPS server
164 * authentication is not to be used.
165 * @param truststorePassword Password to unlock the truststore.
166 */
167 public AuthSSLProtocolSocketFactory(final URL keystoreUrl,
168 final String keystorePassword,
169 final URL truststoreUrl,
170 final String truststorePassword)
171 throws GeneralSecurityException, IOException {
172
173 super();
174
175 // prepare key material
176 if (keystoreUrl != null) {
177 char[] ksPass = null;
178 if (keystorePassword != null) {
179 ksPass = keystorePassword.toCharArray();
180 }
181 KeyMaterial km = new KeyMaterial(keystoreUrl, ksPass);
182 super.setKeyMaterial(km);
183 }
184
185 // prepare trust material1
186 if (truststoreUrl != null) {
187 char[] tsPass = null;
188 if (truststorePassword != null) {
189 tsPass = truststorePassword.toCharArray();
190 }
191 TrustMaterial tm = new KeyMaterial(truststoreUrl, tsPass);
192 super.setTrustMaterial(tm);
193 }
194 }
195
196 }