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