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