001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.tools; 028 029 030 import java.io.FileInputStream; 031 import java.io.IOException; 032 import java.net.Socket; 033 import java.security.KeyStore; 034 import java.security.KeyStoreException; 035 import java.security.Provider; 036 import javax.net.ssl.KeyManager; 037 import javax.net.ssl.KeyManagerFactory; 038 import javax.net.ssl.SSLContext; 039 import javax.net.ssl.SSLSocketFactory; 040 import javax.net.ssl.TrustManager; 041 import javax.net.ssl.TrustManagerFactory; 042 import javax.net.ssl.X509TrustManager; 043 044 import org.opends.server.extensions.BlindTrustManagerProvider; 045 import org.opends.server.util.ExpirationCheckTrustManager; 046 import org.opends.server.util.SelectableCertificateKeyManager; 047 048 import static org.opends.messages.ToolMessages.*; 049 import static org.opends.server.loggers.debug.DebugLogger.*; 050 import org.opends.server.loggers.debug.DebugTracer; 051 import org.opends.server.types.DebugLogLevel; 052 053 054 /** 055 * This class provides SSL connection related utility functions. 056 */ 057 public class SSLConnectionFactory 058 { 059 /** 060 * The tracer object for the debug logger. 061 */ 062 private static final DebugTracer TRACER = getTracer(); 063 064 065 private SSLSocketFactory sslSocketFactory = null; 066 067 /** 068 * Constructor for the SSL connection factory. 069 */ 070 public SSLConnectionFactory() 071 { 072 } 073 074 /** 075 * Initialize the connection factory by creating the key and 076 * trust managers for the SSL connection. 077 * 078 * @param trustAll Indicates whether to blindly trust all 079 * certificates. 080 * @param keyStorePath The path to the key store file. 081 * @param keyStorePassword The PIN to use to access the key store 082 * contents. 083 * @param clientAlias The alias to use for the client certificate. 084 * @param trustStorePath The path to the trust store file. 085 * @param trustStorePassword The PIN to use to access the trust store 086 * contents. 087 * 088 * @throws SSLConnectionException If a problem occurs while initializing the 089 * connection factory. 090 */ 091 public void init(boolean trustAll, String keyStorePath, 092 String keyStorePassword, String clientAlias, 093 String trustStorePath, String trustStorePassword) 094 throws SSLConnectionException 095 { 096 try 097 { 098 SSLContext ctx = SSLContext.getInstance("TLS"); 099 KeyManager[] keyManagers = null; 100 TrustManager[] trustManagers = null; 101 102 if(trustAll) 103 { 104 BlindTrustManagerProvider blindTrustProvider = 105 new BlindTrustManagerProvider(); 106 trustManagers = blindTrustProvider.getTrustManagers(); 107 } else if (trustStorePath == null) { 108 trustManagers = PromptTrustManager.getTrustManagers(); 109 } else 110 { 111 TrustManager[] tmpTrustManagers = 112 getTrustManagers(KeyStore.getDefaultType(), null, trustStorePath, 113 trustStorePassword); 114 trustManagers = new TrustManager[tmpTrustManagers.length]; 115 for (int i=0; i < trustManagers.length; i++) 116 { 117 trustManagers[i] = 118 new ExpirationCheckTrustManager((X509TrustManager) 119 tmpTrustManagers[i]); 120 } 121 } 122 if(keyStorePath != null) 123 { 124 keyManagers = getKeyManagers(KeyStore.getDefaultType(), null, 125 keyStorePath, keyStorePassword); 126 127 if (clientAlias != null) 128 { 129 keyManagers = SelectableCertificateKeyManager.wrap(keyManagers, 130 clientAlias); 131 } 132 } 133 134 ctx.init(keyManagers, trustManagers, new java.security.SecureRandom()); 135 sslSocketFactory = ctx.getSocketFactory(); 136 } catch(Exception e) 137 { 138 throw new SSLConnectionException( 139 ERR_TOOLS_CANNOT_CREATE_SSL_CONNECTION.get(e.getMessage()), e); 140 } 141 } 142 143 /** 144 * Create the SSL socket connection to the specified host. 145 * 146 * @param hostName The address of the system to which the connection 147 * should be established. 148 * @param portNumber The port number to which the connection should be 149 * established. 150 * 151 * @return The SSL socket established to the specified host. 152 * 153 * @throws SSLConnectionException If a problem occurs while performing SSL 154 * negotiation. 155 * 156 * @throws IOException If a problem occurs while attempting to communicate 157 * with the server. 158 */ 159 public Socket createSocket(String hostName, int portNumber) 160 throws SSLConnectionException, IOException 161 { 162 if(sslSocketFactory == null) 163 { 164 165 throw new SSLConnectionException( 166 ERR_TOOLS_SSL_CONNECTION_NOT_INITIALIZED.get()); 167 } 168 return sslSocketFactory.createSocket(hostName, portNumber); 169 } 170 171 /** 172 * Create the SSL socket connection to the specified host layered over 173 * an existing socket. 174 * 175 * @param s The socket to use for the existing connection. 176 * @param hostName The address of the system to which the connection 177 * should be established. 178 * @param portNumber The port number to which the connection should be 179 * established. 180 * @param autoClose Indicates whether the underlying connection should be 181 * automatically closed when the SSL session is ended. 182 * 183 * @return The SSL socket established to the specified host. 184 * 185 * @throws SSLConnectionException If a problem occurs while performing SSL 186 * negotiation. 187 * 188 * @throws IOException If a problem occurs while attempting to communicate 189 * with the server. 190 */ 191 public Socket createSocket(Socket s, String hostName, int portNumber, 192 boolean autoClose) 193 throws SSLConnectionException, IOException 194 { 195 if(sslSocketFactory == null) 196 { 197 198 throw new SSLConnectionException( 199 ERR_TOOLS_SSL_CONNECTION_NOT_INITIALIZED.get()); 200 } 201 return sslSocketFactory.createSocket(s, hostName, portNumber, autoClose); 202 } 203 204 /** 205 * Retrieves a set of <CODE>KeyManager</CODE> objects that may be used for 206 * interactions requiring access to a key manager. 207 * 208 * @param keyStoreType The key store type to use with the specified file. 209 * @param provider The provider to use when accessing the key store. 210 * @param keyStoreFile The path to the file containing the key store data. 211 * @param keyStorePass The PIN needed to access the key store contents. 212 * 213 * @return A set of <CODE>KeyManager</CODE> objects that may be used for 214 * interactions requiring access to a key manager. 215 * 216 * @throws KeyStoreException If a problem occurs while interacting with the 217 * key store. 218 * 219 * @throws SSLConnectionException If a problem occurs while trying to load 220 * key store file. 221 */ 222 223 private KeyManager[] getKeyManagers(String keyStoreType, 224 Provider provider, 225 String keyStoreFile, 226 String keyStorePass) 227 throws KeyStoreException, SSLConnectionException 228 { 229 if(keyStoreFile == null) 230 { 231 // Lookup the file name through the JDK property. 232 keyStoreFile = getKeyStore(); 233 } 234 235 if(keyStorePass == null) 236 { 237 // Lookup the keystore PIN through the JDK property. 238 keyStorePass = getKeyStorePIN(); 239 } 240 241 KeyStore ks = null; 242 if(provider != null) 243 { 244 ks = KeyStore.getInstance(keyStoreType, provider); 245 } else 246 { 247 ks = KeyStore.getInstance(keyStoreType); 248 } 249 250 char[] keyStorePIN = null; 251 if(keyStorePass != null) 252 { 253 keyStorePIN = keyStorePass.toCharArray(); 254 } 255 256 try 257 { 258 FileInputStream inputStream = new FileInputStream(keyStoreFile); 259 ks.load(inputStream, keyStorePIN); 260 inputStream.close(); 261 262 } catch(Exception e) 263 { 264 if (debugEnabled()) 265 { 266 TRACER.debugCaught(DebugLogLevel.ERROR, e); 267 } 268 269 throw new SSLConnectionException( 270 ERR_TOOLS_CANNOT_LOAD_KEYSTORE_FILE.get(keyStoreFile), e); 271 } 272 273 try 274 { 275 String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm(); 276 KeyManagerFactory keyManagerFactory = 277 KeyManagerFactory.getInstance(keyManagerAlgorithm); 278 279 keyManagerFactory.init(ks, keyStorePIN); 280 return keyManagerFactory.getKeyManagers(); 281 } catch(Exception ke) 282 { 283 if (debugEnabled()) 284 { 285 TRACER.debugCaught(DebugLogLevel.ERROR, ke); 286 } 287 288 throw new SSLConnectionException( 289 ERR_TOOLS_CANNOT_INIT_KEYMANAGER.get(keyStoreFile), ke); 290 } 291 292 } 293 294 295 /** 296 * Retrieves a set of <CODE>TrustManager</CODE> objects that may be used for 297 * interactions requiring access to a trust manager. 298 * 299 * @param trustStoreType The trust store type to use with the specified 300 * file. 301 * @param provider The provider to use when accessing the trust store. 302 * @param trustStoreFile The path to the file containing the trust store 303 * data. 304 * @param trustStorePass The PIN needed to access the trust store contents. 305 * 306 * @return A set of <CODE>TrustManager</CODE> objects that may be used for 307 * interactions requiring access to a trust manager. 308 * 309 * @throws KeyStoreException If a problem occurs while interacting with the 310 * trust store. 311 * 312 * @throws SSLConnectionException If a problem occurs while trying to load 313 * trust store file. 314 */ 315 private TrustManager[] getTrustManagers(String trustStoreType, 316 Provider provider, 317 String trustStoreFile, 318 String trustStorePass) 319 throws KeyStoreException, SSLConnectionException 320 { 321 if(trustStoreFile == null) 322 { 323 trustStoreFile = getTrustStore(); 324 // No trust store file available. 325 if(trustStoreFile == null) 326 { 327 return null; 328 } 329 } 330 331 if(trustStorePass == null) 332 { 333 trustStorePass = getTrustStorePIN(); 334 } 335 336 KeyStore trustStore = null; 337 if(provider != null) 338 { 339 trustStore = KeyStore.getInstance(trustStoreType, provider); 340 } else 341 { 342 trustStore = KeyStore.getInstance(trustStoreType); 343 } 344 345 char[] trustStorePIN = null; 346 if(trustStorePass != null) 347 { 348 trustStorePIN = trustStorePass.toCharArray(); 349 } 350 351 try 352 { 353 FileInputStream inputStream = new FileInputStream(trustStoreFile); 354 trustStore.load(inputStream, trustStorePIN); 355 inputStream.close(); 356 } catch(Exception e) 357 { 358 if (debugEnabled()) 359 { 360 TRACER.debugCaught(DebugLogLevel.ERROR, e); 361 } 362 363 throw new SSLConnectionException( 364 ERR_TOOLS_CANNOT_LOAD_TRUSTSTORE_FILE.get(trustStoreFile), e); 365 } 366 367 try 368 { 369 String trustManagerAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); 370 TrustManagerFactory trustManagerFactory = 371 TrustManagerFactory.getInstance(trustManagerAlgorithm); 372 373 trustManagerFactory.init(trustStore); 374 return trustManagerFactory.getTrustManagers(); 375 } catch(Exception ke) 376 { 377 if (debugEnabled()) 378 { 379 TRACER.debugCaught(DebugLogLevel.ERROR, ke); 380 } 381 382 throw new SSLConnectionException( 383 ERR_TOOLS_CANNOT_INIT_TRUSTMANAGER.get(trustStoreFile), ke); 384 } 385 386 } 387 388 /** 389 * Read the KeyStore PIN from the JSSE system property. 390 * 391 * @return The PIN that should be used to access the key store. 392 */ 393 394 private String getKeyStorePIN() 395 { 396 return System.getProperty("javax.net.ssl.keyStorePassword"); 397 } 398 399 /** 400 * Read the TrustStore PIN from the JSSE system property. 401 * 402 * @return The PIN that should be used to access the trust store. 403 */ 404 405 private String getTrustStorePIN() 406 { 407 return System.getProperty("javax.net.ssl.trustStorePassword"); 408 } 409 410 /** 411 * Read the KeyStore from the JSSE system property. 412 * 413 * @return The path to the key store file. 414 */ 415 416 private String getKeyStore() 417 { 418 return System.getProperty("javax.net.ssl.keyStore"); 419 } 420 421 /** 422 * Read the TrustStore from the JSSE system property. 423 * 424 * @return The path to the trust store file. 425 */ 426 427 private String getTrustStore() 428 { 429 return System.getProperty("javax.net.ssl.trustStore"); 430 } 431 432 } 433