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 java.security.KeyManagementException; 020import java.security.KeyStoreException; 021import java.security.NoSuchAlgorithmException; 022import java.security.UnrecoverableKeyException; 023 024import javax.net.ssl.KeyManager; 025import javax.net.ssl.KeyManagerFactory; 026import javax.net.ssl.SSLContext; 027import javax.net.ssl.SSLServerSocketFactory; 028import javax.net.ssl.SSLSocketFactory; 029import javax.net.ssl.TrustManager; 030import javax.net.ssl.TrustManagerFactory; 031 032import org.apache.logging.log4j.core.Core; 033import org.apache.logging.log4j.core.config.plugins.Plugin; 034import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 035import org.apache.logging.log4j.core.config.plugins.PluginElement; 036import org.apache.logging.log4j.core.config.plugins.PluginFactory; 037import org.apache.logging.log4j.status.StatusLogger; 038 039/** 040 * SSL Configuration 041 */ 042@Plugin(name = "Ssl", category = Core.CATEGORY_NAME, printObject = true) 043public class SslConfiguration { 044 private static final StatusLogger LOGGER = StatusLogger.getLogger(); 045 private final KeyStoreConfiguration keyStoreConfig; 046 private final TrustStoreConfiguration trustStoreConfig; 047 private final SSLContext sslContext; 048 private final String protocol; 049 private final boolean verifyHostName; 050 051 private SslConfiguration(final String protocol, final KeyStoreConfiguration keyStoreConfig, 052 final TrustStoreConfiguration trustStoreConfig, boolean verifyHostName) { 053 this.keyStoreConfig = keyStoreConfig; 054 this.trustStoreConfig = trustStoreConfig; 055 this.protocol = protocol == null ? SslConfigurationDefaults.PROTOCOL : protocol; 056 this.sslContext = this.createSslContext(); 057 this.verifyHostName = verifyHostName; 058 } 059 060 /** 061 * Clears the secret fields in this object but still allow it to operate normally. 062 */ 063 public void clearSecrets() { 064 if (this.keyStoreConfig != null) { 065 this.keyStoreConfig.clearSecrets(); 066 } 067 if (this.trustStoreConfig != null) { 068 this.trustStoreConfig.clearSecrets(); 069 } 070 } 071 072 public SSLSocketFactory getSslSocketFactory() { 073 return sslContext.getSocketFactory(); 074 } 075 076 public SSLServerSocketFactory getSslServerSocketFactory() { 077 return sslContext.getServerSocketFactory(); 078 } 079 080 private SSLContext createSslContext() { 081 SSLContext context = null; 082 083 try { 084 context = createSslContextBasedOnConfiguration(); 085 LOGGER.debug("Creating SSLContext with the given parameters"); 086 } 087 catch (final TrustStoreConfigurationException e) { 088 context = createSslContextWithTrustStoreFailure(); 089 } 090 catch (final KeyStoreConfigurationException e) { 091 context = createSslContextWithKeyStoreFailure(); 092 } 093 return context; 094 } 095 096 private SSLContext createSslContextWithTrustStoreFailure() { 097 SSLContext context; 098 099 try { 100 context = createSslContextWithDefaultTrustManagerFactory(); 101 LOGGER.debug("Creating SSLContext with default truststore"); 102 } 103 catch (final KeyStoreConfigurationException e) { 104 context = createDefaultSslContext(); 105 LOGGER.debug("Creating SSLContext with default configuration"); 106 } 107 return context; 108 } 109 110 private SSLContext createSslContextWithKeyStoreFailure() { 111 SSLContext context; 112 113 try { 114 context = createSslContextWithDefaultKeyManagerFactory(); 115 LOGGER.debug("Creating SSLContext with default keystore"); 116 } 117 catch (final TrustStoreConfigurationException e) { 118 context = createDefaultSslContext(); 119 LOGGER.debug("Creating SSLContext with default configuration"); 120 } 121 return context; 122 } 123 124 private SSLContext createSslContextBasedOnConfiguration() throws KeyStoreConfigurationException, TrustStoreConfigurationException { 125 return createSslContext(false, false); 126 } 127 128 private SSLContext createSslContextWithDefaultKeyManagerFactory() throws TrustStoreConfigurationException { 129 try { 130 return createSslContext(true, false); 131 } catch (final KeyStoreConfigurationException dummy) { 132 LOGGER.debug("Exception occured while using default keystore. This should be a BUG"); 133 return null; 134 } 135 } 136 137 private SSLContext createSslContextWithDefaultTrustManagerFactory() throws KeyStoreConfigurationException { 138 try { 139 return createSslContext(false, true); 140 } 141 catch (final TrustStoreConfigurationException dummy) { 142 LOGGER.debug("Exception occured while using default truststore. This should be a BUG"); 143 return null; 144 } 145 } 146 147 private SSLContext createDefaultSslContext() { 148 try { 149 return SSLContext.getDefault(); 150 } catch (final NoSuchAlgorithmException e) { 151 LOGGER.error("Failed to create an SSLContext with default configuration", e); 152 return null; 153 } 154 } 155 156 private SSLContext createSslContext(final boolean loadDefaultKeyManagerFactory, final boolean loadDefaultTrustManagerFactory) 157 throws KeyStoreConfigurationException, TrustStoreConfigurationException { 158 try { 159 KeyManager[] kManagers = null; 160 TrustManager[] tManagers = null; 161 162 final SSLContext newSslContext = SSLContext.getInstance(this.protocol); 163 if (!loadDefaultKeyManagerFactory) { 164 final KeyManagerFactory kmFactory = loadKeyManagerFactory(); 165 kManagers = kmFactory.getKeyManagers(); 166 } 167 if (!loadDefaultTrustManagerFactory) { 168 final TrustManagerFactory tmFactory = loadTrustManagerFactory(); 169 tManagers = tmFactory.getTrustManagers(); 170 } 171 172 newSslContext.init(kManagers, tManagers, null); 173 return newSslContext; 174 } 175 catch (final NoSuchAlgorithmException e) { 176 LOGGER.error("No Provider supports a TrustManagerFactorySpi implementation for the specified protocol", e); 177 throw new TrustStoreConfigurationException(e); 178 } 179 catch (final KeyManagementException e) { 180 LOGGER.error("Failed to initialize the SSLContext", e); 181 throw new KeyStoreConfigurationException(e); 182 } 183 } 184 185 private TrustManagerFactory loadTrustManagerFactory() throws TrustStoreConfigurationException { 186 if (trustStoreConfig == null) { 187 throw new TrustStoreConfigurationException(new Exception("The trustStoreConfiguration is null")); 188 } 189 190 try { 191 return trustStoreConfig.initTrustManagerFactory(); 192 } 193 catch (final NoSuchAlgorithmException e) { 194 LOGGER.error("The specified algorithm is not available from the specified provider", e); 195 throw new TrustStoreConfigurationException(e); 196 } catch (final KeyStoreException e) { 197 LOGGER.error("Failed to initialize the TrustManagerFactory", e); 198 throw new TrustStoreConfigurationException(e); 199 } 200 } 201 202 private KeyManagerFactory loadKeyManagerFactory() throws KeyStoreConfigurationException { 203 if (keyStoreConfig == null) { 204 throw new KeyStoreConfigurationException(new Exception("The keyStoreConfiguration is null")); 205 } 206 207 try { 208 return keyStoreConfig.initKeyManagerFactory(); 209 } 210 catch (final NoSuchAlgorithmException e) { 211 LOGGER.error("The specified algorithm is not available from the specified provider", e); 212 throw new KeyStoreConfigurationException(e); 213 } catch (final KeyStoreException e) { 214 LOGGER.error("Failed to initialize the TrustManagerFactory", e); 215 throw new KeyStoreConfigurationException(e); 216 } catch (final UnrecoverableKeyException e) { 217 LOGGER.error("The key cannot be recovered (e.g. the given password is wrong)", e); 218 throw new KeyStoreConfigurationException(e); 219 } 220 } 221 222 /** 223 * Creates an SslConfiguration from a KeyStoreConfiguration and a TrustStoreConfiguration. 224 * 225 * @param protocol The protocol, see http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext 226 * @param keyStoreConfig The KeyStoreConfiguration. 227 * @param trustStoreConfig The TrustStoreConfiguration. 228 * @return a new SslConfiguration 229 */ 230 @PluginFactory 231 public static SslConfiguration createSSLConfiguration( 232 // @formatter:off 233 @PluginAttribute("protocol") final String protocol, 234 @PluginElement("KeyStore") final KeyStoreConfiguration keyStoreConfig, 235 @PluginElement("TrustStore") final TrustStoreConfiguration trustStoreConfig) { 236 // @formatter:on 237 return new SslConfiguration(protocol, keyStoreConfig, trustStoreConfig, false); 238 } 239 240 /** 241 * Creates an SslConfiguration from a KeyStoreConfiguration and a TrustStoreConfiguration. 242 * 243 * @param protocol The protocol, see http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext 244 * @param keyStoreConfig The KeyStoreConfiguration. 245 * @param trustStoreConfig The TrustStoreConfiguration. 246 * @return a new SslConfiguration 247 * @since 2.12 248 */ 249 public static SslConfiguration createSSLConfiguration( 250 // @formatter:off 251 @PluginAttribute("protocol") final String protocol, 252 @PluginElement("KeyStore") final KeyStoreConfiguration keyStoreConfig, 253 @PluginElement("TrustStore") final TrustStoreConfiguration trustStoreConfig, 254 @PluginElement("verifyHostName") final boolean verifyHostName) { 255 // @formatter:on 256 return new SslConfiguration(protocol, keyStoreConfig, trustStoreConfig, verifyHostName); 257 } 258 259 @Override 260 public int hashCode() { 261 final int prime = 31; 262 int result = 1; 263 result = prime * result + ((keyStoreConfig == null) ? 0 : keyStoreConfig.hashCode()); 264 result = prime * result + ((protocol == null) ? 0 : protocol.hashCode()); 265 result = prime * result + ((sslContext == null) ? 0 : sslContext.hashCode()); 266 result = prime * result + ((trustStoreConfig == null) ? 0 : trustStoreConfig.hashCode()); 267 return result; 268 } 269 270 @Override 271 public boolean equals(final Object obj) { 272 if (this == obj) { 273 return true; 274 } 275 if (obj == null) { 276 return false; 277 } 278 if (getClass() != obj.getClass()) { 279 return false; 280 } 281 final SslConfiguration other = (SslConfiguration) obj; 282 if (keyStoreConfig == null) { 283 if (other.keyStoreConfig != null) { 284 return false; 285 } 286 } else if (!keyStoreConfig.equals(other.keyStoreConfig)) { 287 return false; 288 } 289 if (protocol == null) { 290 if (other.protocol != null) { 291 return false; 292 } 293 } else if (!protocol.equals(other.protocol)) { 294 return false; 295 } 296 if (sslContext == null) { 297 if (other.sslContext != null) { 298 return false; 299 } 300 } else if (!sslContext.equals(other.sslContext)) { 301 return false; 302 } 303 if (trustStoreConfig == null) { 304 if (other.trustStoreConfig != null) { 305 return false; 306 } 307 } else if (!trustStoreConfig.equals(other.trustStoreConfig)) { 308 return false; 309 } 310 return true; 311 } 312 313 public KeyStoreConfiguration getKeyStoreConfig() { 314 return keyStoreConfig; 315 } 316 317 public TrustStoreConfiguration getTrustStoreConfig() { 318 return trustStoreConfig; 319 } 320 321 public SSLContext getSslContext() { 322 return sslContext; 323 } 324 325 public String getProtocol() { 326 return protocol; 327 } 328 329 public boolean isVerifyHostName() { 330 return verifyHostName; 331 } 332}