View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.net.ssl;
18  
19  import org.apache.logging.log4j.core.config.plugins.Plugin;
20  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
21  import org.apache.logging.log4j.core.config.plugins.PluginElement;
22  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
23  import org.apache.logging.log4j.status.StatusLogger;
24  
25  import javax.net.ssl.KeyManager;
26  import javax.net.ssl.KeyManagerFactory;
27  import javax.net.ssl.SSLContext;
28  import javax.net.ssl.SSLServerSocketFactory;
29  import javax.net.ssl.SSLSocketFactory;
30  import javax.net.ssl.TrustManager;
31  import javax.net.ssl.TrustManagerFactory;
32  import java.security.KeyManagementException;
33  import java.security.KeyStoreException;
34  import java.security.NoSuchAlgorithmException;
35  import java.security.UnrecoverableKeyException;
36  
37  /**
38   *  SSL Configuration
39   */
40  @Plugin(name = "Ssl", category = "Core", printObject = true)
41  public class SslConfiguration {
42      private static final StatusLogger LOGGER = StatusLogger.getLogger();
43      private final KeyStoreConfiguration keyStoreConfig;
44      private final TrustStoreConfiguration trustStoreConfig;
45      private final SSLContext sslContext;
46      private final String protocol;
47      private final boolean verifyHostName;
48  
49      private SslConfiguration(
50              final String protocol, final KeyStoreConfiguration keyStoreConfig,
51              final TrustStoreConfiguration trustStoreConfig, final boolean verifyHostName) {
52          this.keyStoreConfig = keyStoreConfig;
53          this.trustStoreConfig = trustStoreConfig;
54          this.protocol = protocol == null ? SslConfigurationDefaults.PROTOCOL : protocol;
55          this.verifyHostName = verifyHostName;
56          this.sslContext = this.createSslContext();
57      }
58  
59      public SSLSocketFactory getSslSocketFactory() {
60          return sslContext.getSocketFactory();
61      }
62  
63      public SSLServerSocketFactory getSslServerSocketFactory() {
64          return sslContext.getServerSocketFactory();
65      }
66  
67      public boolean isVerifyHostName() {
68          return verifyHostName;
69      }
70  
71      private SSLContext createSslContext() {
72          SSLContext context = null;
73  
74          try {
75              context = createSslContextBasedOnConfiguration();
76              LOGGER.debug("Creating SSLContext with the given parameters");
77          }
78          catch (final TrustStoreConfigurationException e) {
79              context = createSslContextWithTrustStoreFailure();
80          }
81          catch (final KeyStoreConfigurationException e) {
82              context = createSslContextWithKeyStoreFailure();
83          }
84          return context;
85      }
86  
87      private SSLContext createSslContextWithTrustStoreFailure() {
88          SSLContext context;
89  
90          try {
91              context = createSslContextWithDefaultTrustManagerFactory();
92              LOGGER.debug("Creating SSLContext with default truststore");
93          }
94          catch (final KeyStoreConfigurationException e) {
95              context = createDefaultSslContext();
96              LOGGER.debug("Creating SSLContext with default configuration");
97          }
98          return context;
99      }
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 }