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 }