Mercurial > hg > release > thermostat-1.0
view common/core/src/main/java/com/redhat/thermostat/common/ssl/SSLContextFactory.java @ 1412:a0592d702416
Update copyright year in release branch.
reviewed-by: neugens
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2014-June/009965.html
PR1821
author | Jon VanAlten <jon.vanalten@redhat.com> |
---|---|
date | Tue, 03 Jun 2014 11:55:56 -0600 |
parents | 082514261a09 |
children |
line wrap: on
line source
/* * Copyright 2012-2014 Red Hat, Inc. * * This file is part of Thermostat. * * Thermostat is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * Thermostat is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Thermostat; see the file COPYING. If not see * <http://www.gnu.org/licenses/>. * * Linking this code with other modules is making a combined work * based on this code. Thus, the terms and conditions of the GNU * General Public License cover the whole combination. * * As a special exception, the copyright holders of this code give * you permission to link this code with independent modules to * produce an executable, regardless of the license terms of these * independent modules, and to copy and distribute the resulting * executable under terms of your choice, provided that you also * meet, for each linked independent module, the terms and conditions * of the license of that module. An independent module is a module * which is not derived from or based on this code. If you modify * this code, you may extend this exception to your version of the * library, but you are not obligated to do so. If you do not wish * to do so, delete this exception statement from your version. */ package com.redhat.thermostat.common.ssl; import java.io.File; import java.security.GeneralSecurityException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.util.ArrayList; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509KeyManager; import com.redhat.thermostat.common.internal.JSSEKeyManager; import com.redhat.thermostat.common.internal.KeyStoreProvider; import com.redhat.thermostat.common.internal.TrustManagerFactory; import com.redhat.thermostat.common.internal.DelegateSSLSocketFactory; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.shared.config.InvalidConfigurationException; import com.redhat.thermostat.shared.config.SSLConfiguration; public class SSLContextFactory { private static final Logger logger = LoggingUtils.getLogger(SSLContextFactory.class); private static final String PROTOCOL_TLSv12 = "TLSv1.2"; private static final String PROTOCOL_TLSv11 = "TLSv1.1"; private static final String PROTOCOL_TLSv10 = "TLSv1"; private static final String TLS_PROVIDER = "SunJSSE"; private static final String ALGORITHM = "SunX509"; private static SSLContext serverContext; private static SSLContext clientContext; /** * * @return An initialized SSLContext * @throws SslInitException * @throws InvalidConfigurationException */ public static SSLContext getServerContext(SSLConfiguration sslConf) throws SslInitException, InvalidConfigurationException { if (serverContext != null) { return serverContext; } initServerContext(sslConf); return serverContext; } /** * * @return An initialized SSLContext with Thermostat's only X509TrustManager * registered. * @throws SslInitException if SSL initialization failed. */ public static SSLContext getClientContext(SSLConfiguration sslConf) throws SslInitException { if (clientContext != null) { return clientContext; } initClientContext(sslConf); return clientContext; } public static SSLSocketFactory wrapSSLFactory(SSLSocketFactory socketFactory, SSLParameters params) { return new DelegateSSLSocketFactory(socketFactory, params); } public static SSLParameters getSSLParameters(SSLContext ctxt) { SSLParameters params = ctxt.getDefaultSSLParameters(); ArrayList<String> protocols = new ArrayList<String>( Arrays.asList(params.getProtocols())); // Do not send an SSL-2.0-compatible Client Hello. protocols.remove("SSLv2Hello"); params.setProtocols(protocols.toArray(new String[protocols.size()])); ArrayList<String> ciphers = new ArrayList<String>(Arrays.asList(params .getCipherSuites())); ciphers.retainAll(Arrays .asList("TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_RC4_128_SHA1", "SSL_RSA_WITH_RC4_128_MD5", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV")); params.setCipherSuites(ciphers.toArray(new String[ciphers.size()])); return params; } private static void initClientContext(SSLConfiguration sslConf) throws SslInitException { SSLContext clientCtxt = null; try { clientCtxt = getContextInstance(); // Don't need key managers for client mode clientCtxt.init(null, getTrustManagers(sslConf), new SecureRandom()); } catch (KeyManagementException e) { throw new SslInitException(e); } clientContext = clientCtxt; } private static void initServerContext(SSLConfiguration sslConf) throws SslInitException, InvalidConfigurationException { SSLContext serverCtxt = null; File trustStoreFile = sslConf.getKeystoreFile(); String keyStorePassword = sslConf.getKeyStorePassword(); KeyStore ks = KeyStoreProvider.getKeyStore(trustStoreFile, keyStorePassword); if (ks == null) { // This is bad news. We need a proper key store for retrieving the // server certificate. logReason(trustStoreFile); throw new SslInitException( "Failed to initialize server side SSL context"); } try { serverCtxt = getContextInstance(); // Initialize the SSLContext to work with our key and trust managers. serverCtxt.init(getKeyManagers(ks, keyStorePassword), getTrustManagers(sslConf), new SecureRandom()); } catch (GeneralSecurityException e) { throw new SslInitException(e); } serverContext = serverCtxt; } private static TrustManager[] getTrustManagers(SSLConfiguration sslConf) throws SslInitException { TrustManager tm = TrustManagerFactory.getTrustManager(sslConf); return new TrustManager[] { tm }; } private static KeyManager[] getKeyManagers(KeyStore ks, String keystorePassword) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, NoSuchProviderException { // Set up key manager factory to use our key store KeyManagerFactory kmf = KeyManagerFactory.getInstance(ALGORITHM, TLS_PROVIDER); kmf.init(ks, keystorePassword.toCharArray()); KeyManager[] rawKeyManagers = kmf.getKeyManagers(); KeyManager kms[] = new KeyManager[rawKeyManagers.length]; for (int i = 0; i < rawKeyManagers.length; i++) { // Wrap with our keymanager, so that propperly aliased key is // used in keystore. kms[i] = new JSSEKeyManager((X509KeyManager)rawKeyManagers[i]); } return kms; } private static void logReason(File trustStoreFile) { String detail = "Reason: no keystore file specified!"; if (trustStoreFile != null) { if (!trustStoreFile.exists()) { detail = "Reason: keystore file '" + trustStoreFile.toString() + "' does not exist!"; } else { detail = "Reason: illegal keystore password!"; } } logger.log(Level.SEVERE, "Failed to load keystore. " + detail); } private static SSLContext getContextInstance() { // Create the context. Specify the SunJSSE provider to avoid // picking up third-party providers. Try the TLS 1.2 provider // first, TLS 1.1 second and then fall back to TLS 1.0. SSLContext ctx; try { ctx = SSLContext.getInstance(PROTOCOL_TLSv12, TLS_PROVIDER); } catch (NoSuchAlgorithmException e) { try { ctx = SSLContext.getInstance(PROTOCOL_TLSv11, TLS_PROVIDER); } catch (NoSuchAlgorithmException ex) { try { ctx = SSLContext.getInstance(PROTOCOL_TLSv10, TLS_PROVIDER); } catch (NoSuchAlgorithmException exptn) { // The TLS 1.0 provider should always be available. throw new AssertionError(exptn); } catch (NoSuchProviderException exptn) { // The SunJSSE provider should always be available. throw new AssertionError(exptn); } } catch (NoSuchProviderException ex) { // The SunJSSE provider should always be available. throw new AssertionError(e); } } catch (NoSuchProviderException e) { // The SunJSSE provider should always be available. throw new AssertionError(e); } return ctx; } }