001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.net.ssl; 018 019import org.apache.logging.log4j.core.config.plugins.Plugin; 020import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 021import org.apache.logging.log4j.core.config.plugins.PluginElement; 022import org.apache.logging.log4j.core.config.plugins.PluginFactory; 023import org.apache.logging.log4j.status.StatusLogger; 024 025import javax.net.ssl.KeyManager; 026import javax.net.ssl.KeyManagerFactory; 027import javax.net.ssl.SSLContext; 028import javax.net.ssl.SSLServerSocketFactory; 029import javax.net.ssl.SSLSocketFactory; 030import javax.net.ssl.TrustManager; 031import javax.net.ssl.TrustManagerFactory; 032import java.security.KeyManagementException; 033import java.security.KeyStoreException; 034import java.security.NoSuchAlgorithmException; 035import java.security.UnrecoverableKeyException; 036 037/** 038 * SSL Configuration 039 */ 040@Plugin(name = "Ssl", category = "Core", printObject = true) 041public class SslConfiguration { 042 private static final StatusLogger LOGGER = StatusLogger.getLogger(); 043 private final KeyStoreConfiguration keyStoreConfig; 044 private final TrustStoreConfiguration trustStoreConfig; 045 private final SSLContext sslContext; 046 private final String protocol; 047 private final boolean verifyHostName; 048 049 private SslConfiguration( 050 final String protocol, final KeyStoreConfiguration keyStoreConfig, 051 final TrustStoreConfiguration trustStoreConfig, final boolean verifyHostName) { 052 this.keyStoreConfig = keyStoreConfig; 053 this.trustStoreConfig = trustStoreConfig; 054 this.protocol = protocol == null ? SslConfigurationDefaults.PROTOCOL : protocol; 055 this.verifyHostName = verifyHostName; 056 this.sslContext = this.createSslContext(); 057 } 058 059 public SSLSocketFactory getSslSocketFactory() { 060 return sslContext.getSocketFactory(); 061 } 062 063 public SSLServerSocketFactory getSslServerSocketFactory() { 064 return sslContext.getServerSocketFactory(); 065 } 066 067 public boolean isVerifyHostName() { 068 return verifyHostName; 069 } 070 071 private SSLContext createSslContext() { 072 SSLContext context = null; 073 074 try { 075 context = createSslContextBasedOnConfiguration(); 076 LOGGER.debug("Creating SSLContext with the given parameters"); 077 } 078 catch (final TrustStoreConfigurationException e) { 079 context = createSslContextWithTrustStoreFailure(); 080 } 081 catch (final KeyStoreConfigurationException e) { 082 context = createSslContextWithKeyStoreFailure(); 083 } 084 return context; 085 } 086 087 private SSLContext createSslContextWithTrustStoreFailure() { 088 SSLContext context; 089 090 try { 091 context = createSslContextWithDefaultTrustManagerFactory(); 092 LOGGER.debug("Creating SSLContext with default truststore"); 093 } 094 catch (final KeyStoreConfigurationException e) { 095 context = createDefaultSslContext(); 096 LOGGER.debug("Creating SSLContext with default configuration"); 097 } 098 return context; 099 } 100 101 private SSLContext createSslContextWithKeyStoreFailure() { 102 SSLContext context; 103 104 try { 105 context = createSslContextWithDefaultKeyManagerFactory(); 106 LOGGER.debug("Creating SSLContext with default keystore"); 107 } 108 catch (final TrustStoreConfigurationException e) { 109 context = createDefaultSslContext(); 110 LOGGER.debug("Creating SSLContext with default configuration"); 111 } 112 return context; 113 } 114 115 private SSLContext createSslContextBasedOnConfiguration() throws KeyStoreConfigurationException, TrustStoreConfigurationException { 116 return createSslContext(false, false); 117 } 118 119 private SSLContext createSslContextWithDefaultKeyManagerFactory() throws TrustStoreConfigurationException { 120 try { 121 return createSslContext(true, false); 122 } catch (final KeyStoreConfigurationException dummy) { 123 LOGGER.debug("Exception occured while using default keystore. This should be a BUG"); 124 return null; 125 } 126 } 127 128 private SSLContext createSslContextWithDefaultTrustManagerFactory() throws KeyStoreConfigurationException { 129 try { 130 return createSslContext(false, true); 131 } 132 catch (final TrustStoreConfigurationException dummy) { 133 LOGGER.debug("Exception occured while using default truststore. This should be a BUG"); 134 return null; 135 } 136 } 137 138 private SSLContext createDefaultSslContext() { 139 try { 140 return SSLContext.getDefault(); 141 } catch (final NoSuchAlgorithmException e) { 142 LOGGER.error("Failed to create an SSLContext with default configuration"); 143 return null; 144 } 145 } 146 147 private SSLContext createSslContext(final boolean loadDefaultKeyManagerFactory, final boolean loadDefaultTrustManagerFactory) 148 throws KeyStoreConfigurationException, TrustStoreConfigurationException { 149 try { 150 KeyManager[] kManagers = null; 151 TrustManager[] tManagers = null; 152 153 final SSLContext newSslContext = SSLContext.getInstance(this.protocol); 154 if (!loadDefaultKeyManagerFactory) { 155 final KeyManagerFactory kmFactory = loadKeyManagerFactory(); 156 kManagers = kmFactory.getKeyManagers(); 157 } 158 if (!loadDefaultTrustManagerFactory) { 159 final TrustManagerFactory tmFactory = loadTrustManagerFactory(); 160 tManagers = tmFactory.getTrustManagers(); 161 } 162 163 newSslContext.init(kManagers, tManagers, null); 164 return newSslContext; 165 } 166 catch (final NoSuchAlgorithmException e) { 167 LOGGER.error("No Provider supports a TrustManagerFactorySpi implementation for the specified protocol"); 168 throw new TrustStoreConfigurationException(e); 169 } 170 catch (final KeyManagementException e) { 171 LOGGER.error("Failed to initialize the SSLContext"); 172 throw new KeyStoreConfigurationException(e); 173 } 174 } 175 176 private TrustManagerFactory loadTrustManagerFactory() throws TrustStoreConfigurationException { 177 if (trustStoreConfig == null) { 178 throw new TrustStoreConfigurationException(new Exception("The trustStoreConfiguration is null")); 179 } 180 181 try { 182 return trustStoreConfig.initTrustManagerFactory(); 183 } 184 catch (final NoSuchAlgorithmException e) { 185 LOGGER.error("The specified algorithm is not available from the specified provider"); 186 throw new TrustStoreConfigurationException(e); 187 } catch (final KeyStoreException e) { 188 LOGGER.error("Failed to initialize the TrustManagerFactory"); 189 throw new TrustStoreConfigurationException(e); 190 } 191 } 192 193 private KeyManagerFactory loadKeyManagerFactory() throws KeyStoreConfigurationException { 194 if (keyStoreConfig == null) { 195 throw new KeyStoreConfigurationException(new Exception("The keyStoreConfiguration is null")); 196 } 197 198 try { 199 return keyStoreConfig.initKeyManagerFactory(); 200 } 201 catch (final NoSuchAlgorithmException e) { 202 LOGGER.error("The specified algorithm is not available from the specified provider"); 203 throw new KeyStoreConfigurationException(e); 204 } catch (final KeyStoreException e) { 205 LOGGER.error("Failed to initialize the TrustManagerFactory"); 206 throw new KeyStoreConfigurationException(e); 207 } catch (final UnrecoverableKeyException e) { 208 LOGGER.error("The key cannot be recovered (e.g. the given password is wrong)"); 209 throw new KeyStoreConfigurationException(e); 210 } 211 } 212 213 public boolean equals(final SslConfiguration config) { 214 if (config == null) { 215 return false; 216 } 217 218 boolean keyStoreEquals = false; 219 boolean trustStoreEquals = false; 220 221 if (keyStoreConfig != null) { 222 keyStoreEquals = keyStoreConfig.equals(config.keyStoreConfig); 223 } else { 224 keyStoreEquals = keyStoreConfig == config.keyStoreConfig; 225 } 226 227 if (trustStoreConfig != null) { 228 trustStoreEquals = trustStoreConfig.equals(config.trustStoreConfig); 229 } else { 230 trustStoreEquals = trustStoreConfig == config.trustStoreConfig; 231 } 232 233 return keyStoreEquals && trustStoreEquals && verifyHostName == config.verifyHostName; 234 } 235 236 /** 237 * @deprecated use {@link #createSSLConfiguration(String, KeyStoreConfiguration, TrustStoreConfiguration, boolean)} 238 */ 239 @Deprecated 240 public static SslConfiguration createSSLConfiguration( 241 final String protocol, final KeyStoreConfiguration keyStoreConfig, final TrustStoreConfiguration trustStoreConfig) { 242 return createSSLConfiguration(protocol, keyStoreConfig, trustStoreConfig, false); 243 } 244 245 /** 246 * Creates an SslConfiguration from a KeyStoreConfiguration and a TrustStoreConfiguration. 247 * @param protocol The protocol, see http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext 248 * @param keyStoreConfig The KeyStoreConfiguration. 249 * @param trustStoreConfig The TrustStoreConfiguration. 250 * @param verifyHostName Whether to enable TLS hostname verification 251 * @return a new SslConfiguration 252 */ 253 @PluginFactory 254 public static SslConfiguration createSSLConfiguration( 255 // @formatter:off 256 @PluginAttribute("protocol") final String protocol, 257 @PluginElement("KeyStore") final KeyStoreConfiguration keyStoreConfig, 258 @PluginElement("TrustStore") final TrustStoreConfiguration trustStoreConfig, 259 @PluginAttribute("verifyHostName") final boolean verifyHostName) { 260 // @formatter:on 261 return new SslConfiguration(protocol, keyStoreConfig, trustStoreConfig, verifyHostName); 262 } 263}