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