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 */
017 package org.apache.logging.log4j.core.net.ssl;
018
019 import java.security.KeyManagementException;
020 import java.security.KeyStoreException;
021 import java.security.NoSuchAlgorithmException;
022 import java.security.UnrecoverableKeyException;
023
024 import javax.net.ssl.KeyManager;
025 import javax.net.ssl.KeyManagerFactory;
026 import javax.net.ssl.SSLContext;
027 import javax.net.ssl.SSLServerSocketFactory;
028 import javax.net.ssl.SSLSocketFactory;
029 import javax.net.ssl.TrustManager;
030 import javax.net.ssl.TrustManagerFactory;
031
032 import org.apache.logging.log4j.core.config.plugins.Plugin;
033 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
034 import org.apache.logging.log4j.core.config.plugins.PluginElement;
035 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
036 import org.apache.logging.log4j.status.StatusLogger;
037
038 /**
039 * SSL Configuration
040 */
041 @Plugin(name = "Ssl", category = "Core", printObject = true)
042 public class SslConfiguration {
043 private static final StatusLogger LOGGER = StatusLogger.getLogger();
044 private final KeyStoreConfiguration keyStoreConfig;
045 private final TrustStoreConfiguration trustStoreConfig;
046 private final SSLContext sslContext;
047 private final String protocol;
048
049 private SslConfiguration(final String protocol, final KeyStoreConfiguration keyStoreConfig,
050 final TrustStoreConfiguration trustStoreConfig) {
051 this.keyStoreConfig = keyStoreConfig;
052 this.trustStoreConfig = trustStoreConfig;
053 this.protocol = protocol == null ? SslConfigurationDefaults.PROTOCOL : protocol;
054 this.sslContext = this.createSslContext();
055 }
056
057 public SSLSocketFactory getSslSocketFactory() {
058 return sslContext.getSocketFactory();
059 }
060
061 public SSLServerSocketFactory getSslServerSocketFactory() {
062 return sslContext.getServerSocketFactory();
063 }
064
065 private SSLContext createSslContext() {
066 SSLContext context = null;
067
068 try {
069 context = createSslContextBasedOnConfiguration();
070 LOGGER.debug("Creating SSLContext with the given parameters");
071 }
072 catch (final TrustStoreConfigurationException e) {
073 context = createSslContextWithTrustStoreFailure();
074 }
075 catch (final KeyStoreConfigurationException e) {
076 context = createSslContextWithKeyStoreFailure();
077 }
078 return context;
079 }
080
081 private SSLContext createSslContextWithTrustStoreFailure() {
082 SSLContext context;
083
084 try {
085 context = createSslContextWithDefaultTrustManagerFactory();
086 LOGGER.debug("Creating SSLContext with default truststore");
087 }
088 catch (final KeyStoreConfigurationException e) {
089 context = createDefaultSslContext();
090 LOGGER.debug("Creating SSLContext with default configuration");
091 }
092 return context;
093 }
094
095 private SSLContext createSslContextWithKeyStoreFailure() {
096 SSLContext context;
097
098 try {
099 context = createSslContextWithDefaultKeyManagerFactory();
100 LOGGER.debug("Creating SSLContext with default keystore");
101 }
102 catch (final TrustStoreConfigurationException e) {
103 context = createDefaultSslContext();
104 LOGGER.debug("Creating SSLContext with default configuration");
105 }
106 return context;
107 }
108
109 private SSLContext createSslContextBasedOnConfiguration() throws KeyStoreConfigurationException, TrustStoreConfigurationException {
110 return createSslContext(false, false);
111 }
112
113 private SSLContext createSslContextWithDefaultKeyManagerFactory() throws TrustStoreConfigurationException {
114 try {
115 return createSslContext(true, false);
116 } catch (final KeyStoreConfigurationException dummy) {
117 LOGGER.debug("Exception occured while using default keystore. This should be a BUG");
118 return null;
119 }
120 }
121
122 private SSLContext createSslContextWithDefaultTrustManagerFactory() throws KeyStoreConfigurationException {
123 try {
124 return createSslContext(false, true);
125 }
126 catch (final TrustStoreConfigurationException dummy) {
127 LOGGER.debug("Exception occured while using default truststore. This should be a BUG");
128 return null;
129 }
130 }
131
132 private SSLContext createDefaultSslContext() {
133 try {
134 return SSLContext.getDefault();
135 } catch (final NoSuchAlgorithmException e) {
136 LOGGER.error("Failed to create an SSLContext with default configuration");
137 return null;
138 }
139 }
140
141 private SSLContext createSslContext(final boolean loadDefaultKeyManagerFactory, final boolean loadDefaultTrustManagerFactory)
142 throws KeyStoreConfigurationException, TrustStoreConfigurationException {
143 try {
144 KeyManager[] kManagers = null;
145 TrustManager[] tManagers = null;
146
147 final SSLContext newSslContext = SSLContext.getInstance(this.protocol);
148 if (!loadDefaultKeyManagerFactory) {
149 final KeyManagerFactory kmFactory = loadKeyManagerFactory();
150 kManagers = kmFactory.getKeyManagers();
151 }
152 if (!loadDefaultTrustManagerFactory) {
153 final TrustManagerFactory tmFactory = loadTrustManagerFactory();
154 tManagers = tmFactory.getTrustManagers();
155 }
156
157 newSslContext.init(kManagers, tManagers, null);
158 return newSslContext;
159 }
160 catch (final NoSuchAlgorithmException e) {
161 LOGGER.error("No Provider supports a TrustManagerFactorySpi implementation for the specified protocol");
162 throw new TrustStoreConfigurationException(e);
163 }
164 catch (final KeyManagementException e) {
165 LOGGER.error("Failed to initialize the SSLContext");
166 throw new KeyStoreConfigurationException(e);
167 }
168 }
169
170 private TrustManagerFactory loadTrustManagerFactory() throws TrustStoreConfigurationException {
171 if (trustStoreConfig == null) {
172 throw new TrustStoreConfigurationException(new Exception("The trustStoreConfiguration is null"));
173 }
174
175 try {
176 return trustStoreConfig.initTrustManagerFactory();
177 }
178 catch (final NoSuchAlgorithmException e) {
179 LOGGER.error("The specified algorithm is not available from the specified provider");
180 throw new TrustStoreConfigurationException(e);
181 } catch (final KeyStoreException e) {
182 LOGGER.error("Failed to initialize the TrustManagerFactory");
183 throw new TrustStoreConfigurationException(e);
184 }
185 }
186
187 private KeyManagerFactory loadKeyManagerFactory() throws KeyStoreConfigurationException {
188 if (keyStoreConfig == null) {
189 throw new KeyStoreConfigurationException(new Exception("The keyStoreConfiguration is null"));
190 }
191
192 try {
193 return keyStoreConfig.initKeyManagerFactory();
194 }
195 catch (final NoSuchAlgorithmException e) {
196 LOGGER.error("The specified algorithm is not available from the specified provider");
197 throw new KeyStoreConfigurationException(e);
198 } catch (final KeyStoreException e) {
199 LOGGER.error("Failed to initialize the TrustManagerFactory");
200 throw new KeyStoreConfigurationException(e);
201 } catch (final UnrecoverableKeyException e) {
202 LOGGER.error("The key cannot be recovered (e.g. the given password is wrong)");
203 throw new KeyStoreConfigurationException(e);
204 }
205 }
206
207 public boolean equals(final SslConfiguration config) {
208 if (config == null) {
209 return false;
210 }
211
212 boolean keyStoreEquals = false;
213 boolean trustStoreEquals = false;
214
215 if (keyStoreConfig != null) {
216 keyStoreEquals = keyStoreConfig.equals(config.keyStoreConfig);
217 } else {
218 keyStoreEquals = keyStoreConfig == config.keyStoreConfig;
219 }
220
221 if (trustStoreConfig != null) {
222 trustStoreEquals = trustStoreConfig.equals(config.trustStoreConfig);
223 } else {
224 trustStoreEquals = trustStoreConfig == config.trustStoreConfig;
225 }
226
227 return keyStoreEquals && trustStoreEquals;
228 }
229
230 /**
231 * Creates an SslConfiguration from a KeyStoreConfiguration and a TrustStoreConfiguration.
232 * @param protocol The protocol, see http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext
233 * @param keyStoreConfig The KeyStoreConfiguration.
234 * @param trustStoreConfig The TrustStoreConfiguration.
235 * @return a new SslConfiguration
236 */
237 @PluginFactory
238 public static SslConfiguration createSSLConfiguration(
239 // @formatter:off
240 @PluginAttribute("protocol") final String protocol,
241 @PluginElement("KeyStore") final KeyStoreConfiguration keyStoreConfig,
242 @PluginElement("TrustStore") final TrustStoreConfiguration trustStoreConfig) {
243 // @formatter:on
244 return new SslConfiguration(protocol, keyStoreConfig, trustStoreConfig);
245 }
246 }