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 java.security.KeyManagementException;
20  import java.security.KeyStoreException;
21  import java.security.NoSuchAlgorithmException;
22  import java.security.UnrecoverableKeyException;
23  
24  import javax.net.ssl.KeyManager;
25  import javax.net.ssl.KeyManagerFactory;
26  import javax.net.ssl.SSLContext;
27  import javax.net.ssl.SSLServerSocketFactory;
28  import javax.net.ssl.SSLSocketFactory;
29  import javax.net.ssl.TrustManager;
30  import javax.net.ssl.TrustManagerFactory;
31  
32  import org.apache.logging.log4j.core.Core;
33  import org.apache.logging.log4j.core.config.plugins.Plugin;
34  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
35  import org.apache.logging.log4j.core.config.plugins.PluginElement;
36  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
37  import org.apache.logging.log4j.status.StatusLogger;
38  
39  /**
40   *  SSL Configuration
41   */
42  @Plugin(name = "Ssl", category = Core.CATEGORY_NAME, printObject = true)
43  public class SslConfiguration {
44      private static final StatusLogger LOGGER = StatusLogger.getLogger();
45      private final KeyStoreConfiguration keyStoreConfig;
46      private final TrustStoreConfiguration trustStoreConfig;
47      private final SSLContext sslContext;
48      private final String protocol;
49      private final boolean verifyHostName;
50  
51      private SslConfiguration(final String protocol, final KeyStoreConfiguration keyStoreConfig,
52              final TrustStoreConfiguration trustStoreConfig, boolean verifyHostName) {
53          this.keyStoreConfig = keyStoreConfig;
54          this.trustStoreConfig = trustStoreConfig;
55          this.protocol = protocol == null ? SslConfigurationDefaults.PROTOCOL : protocol;
56          this.sslContext = this.createSslContext();
57          this.verifyHostName = verifyHostName;
58      }
59  
60      /**
61       * Clears the secret fields in this object but still allow it to operate normally.
62       */
63      public void clearSecrets() {
64          if (this.keyStoreConfig != null) {
65              this.keyStoreConfig.clearSecrets();
66          }
67          if (this.trustStoreConfig != null) {
68              this.trustStoreConfig.clearSecrets();
69          }
70      }
71  
72      public SSLSocketFactory getSslSocketFactory() {
73          return sslContext.getSocketFactory();
74      }
75  
76      public SSLServerSocketFactory getSslServerSocketFactory() {
77          return sslContext.getServerSocketFactory();
78      }
79  
80      private SSLContext createSslContext() {
81          SSLContext context = null;
82  
83          try {
84              context = createSslContextBasedOnConfiguration();
85              LOGGER.debug("Creating SSLContext with the given parameters");
86          }
87          catch (final TrustStoreConfigurationException e) {
88              context = createSslContextWithTrustStoreFailure();
89          }
90          catch (final KeyStoreConfigurationException e) {
91              context = createSslContextWithKeyStoreFailure();
92          }
93          return context;
94      }
95  
96      private SSLContext createSslContextWithTrustStoreFailure() {
97          SSLContext context;
98  
99          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 }