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  
50      private SslConfiguration(final String protocol, final KeyStoreConfiguration keyStoreConfig,
51              final TrustStoreConfiguration trustStoreConfig) {
52          this.keyStoreConfig = keyStoreConfig;
53          this.trustStoreConfig = trustStoreConfig;
54          this.protocol = protocol == null ? SslConfigurationDefaults.PROTOCOL : protocol;
55          this.sslContext = this.createSslContext();
56      }
57  
58      /**
59       * Clears the secret fields in this object but still allow it to operate normally.
60       */
61      public void clearSecrets() {
62          if (this.keyStoreConfig != null) {
63              this.keyStoreConfig.clearSecrets();
64          }
65          if (this.trustStoreConfig != null) {
66              this.trustStoreConfig.clearSecrets();
67          }
68      }
69      
70      public SSLSocketFactory getSslSocketFactory() {
71          return sslContext.getSocketFactory();
72      }
73  
74      public SSLServerSocketFactory getSslServerSocketFactory() {
75          return sslContext.getServerSocketFactory();
76      }
77  
78      private SSLContext createSslContext() {
79          SSLContext context = null;
80  
81          try {
82              context = createSslContextBasedOnConfiguration();
83              LOGGER.debug("Creating SSLContext with the given parameters");
84          }
85          catch (final TrustStoreConfigurationException e) {
86              context = createSslContextWithTrustStoreFailure();
87          }
88          catch (final KeyStoreConfigurationException e) {
89              context = createSslContextWithKeyStoreFailure();
90          }
91          return context;
92      }
93  
94      private SSLContext createSslContextWithTrustStoreFailure() {
95          SSLContext context;
96  
97          try {
98              context = createSslContextWithDefaultTrustManagerFactory();
99              LOGGER.debug("Creating SSLContext with default truststore");
100         }
101         catch (final KeyStoreConfigurationException e) {
102             context = createDefaultSslContext();
103             LOGGER.debug("Creating SSLContext with default configuration");
104         }
105         return context;
106     }
107 
108     private SSLContext createSslContextWithKeyStoreFailure() {
109         SSLContext context;
110 
111         try {
112             context = createSslContextWithDefaultKeyManagerFactory();
113             LOGGER.debug("Creating SSLContext with default keystore");
114         }
115         catch (final TrustStoreConfigurationException e) {
116             context = createDefaultSslContext();
117             LOGGER.debug("Creating SSLContext with default configuration");
118         }
119         return context;
120     }
121 
122     private SSLContext createSslContextBasedOnConfiguration() throws KeyStoreConfigurationException, TrustStoreConfigurationException {
123         return createSslContext(false, false);
124     }
125 
126     private SSLContext createSslContextWithDefaultKeyManagerFactory() throws TrustStoreConfigurationException {
127         try {
128             return createSslContext(true, false);
129         } catch (final KeyStoreConfigurationException dummy) {
130              LOGGER.debug("Exception occured while using default keystore. This should be a BUG");
131              return null;
132         }
133     }
134 
135     private SSLContext createSslContextWithDefaultTrustManagerFactory() throws KeyStoreConfigurationException {
136         try {
137             return createSslContext(false, true);
138         }
139         catch (final TrustStoreConfigurationException dummy) {
140             LOGGER.debug("Exception occured while using default truststore. This should be a BUG");
141             return null;
142         }
143     }
144 
145     private SSLContext createDefaultSslContext() {
146         try {
147             return SSLContext.getDefault();
148         } catch (final NoSuchAlgorithmException e) {
149             LOGGER.error("Failed to create an SSLContext with default configuration", e);
150             return null;
151         }
152     }
153 
154     private SSLContext createSslContext(final boolean loadDefaultKeyManagerFactory, final boolean loadDefaultTrustManagerFactory)
155             throws KeyStoreConfigurationException, TrustStoreConfigurationException {
156         try {
157             KeyManager[] kManagers = null;
158             TrustManager[] tManagers = null;
159 
160             final SSLContext newSslContext = SSLContext.getInstance(this.protocol);
161             if (!loadDefaultKeyManagerFactory) {
162                 final KeyManagerFactory kmFactory = loadKeyManagerFactory();
163                 kManagers = kmFactory.getKeyManagers();
164             }
165             if (!loadDefaultTrustManagerFactory) {
166                 final TrustManagerFactory tmFactory = loadTrustManagerFactory();
167                 tManagers = tmFactory.getTrustManagers();
168             }
169 
170             newSslContext.init(kManagers, tManagers, null);
171             return newSslContext;
172         }
173         catch (final NoSuchAlgorithmException e) {
174             LOGGER.error("No Provider supports a TrustManagerFactorySpi implementation for the specified protocol", e);
175             throw new TrustStoreConfigurationException(e);
176         }
177         catch (final KeyManagementException e) {
178             LOGGER.error("Failed to initialize the SSLContext", e);
179             throw new KeyStoreConfigurationException(e);
180         }
181     }
182 
183     private TrustManagerFactory loadTrustManagerFactory() throws TrustStoreConfigurationException {
184         if (trustStoreConfig == null) {
185             throw new TrustStoreConfigurationException(new Exception("The trustStoreConfiguration is null"));
186         }
187 
188         try {
189             return trustStoreConfig.initTrustManagerFactory();
190         }
191         catch (final NoSuchAlgorithmException e) {
192             LOGGER.error("The specified algorithm is not available from the specified provider", e);
193             throw new TrustStoreConfigurationException(e);
194         } catch (final KeyStoreException e) {
195             LOGGER.error("Failed to initialize the TrustManagerFactory", e);
196             throw new TrustStoreConfigurationException(e);
197         }
198     }
199 
200     private KeyManagerFactory loadKeyManagerFactory() throws KeyStoreConfigurationException {
201         if (keyStoreConfig == null) {
202             throw new KeyStoreConfigurationException(new Exception("The keyStoreConfiguration is null"));
203         }
204 
205         try {
206             return keyStoreConfig.initKeyManagerFactory();
207         }
208         catch (final NoSuchAlgorithmException e) {
209             LOGGER.error("The specified algorithm is not available from the specified provider", e);
210             throw new KeyStoreConfigurationException(e);
211         } catch (final KeyStoreException e) {
212             LOGGER.error("Failed to initialize the TrustManagerFactory", e);
213             throw new KeyStoreConfigurationException(e);
214         } catch (final UnrecoverableKeyException e) {
215             LOGGER.error("The key cannot be recovered (e.g. the given password is wrong)", e);
216             throw new KeyStoreConfigurationException(e);
217         }
218     }
219 
220     /**
221      * Creates an SslConfiguration from a KeyStoreConfiguration and a TrustStoreConfiguration.
222      * 
223      * @param protocol The protocol, see http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext
224      * @param keyStoreConfig The KeyStoreConfiguration.
225      * @param trustStoreConfig The TrustStoreConfiguration.
226      * @return a new SslConfiguration
227      */
228     @PluginFactory
229     public static SslConfiguration createSSLConfiguration(
230             // @formatter:off
231             @PluginAttribute("protocol") final String protocol,
232             @PluginElement("KeyStore") final KeyStoreConfiguration keyStoreConfig, 
233             @PluginElement("TrustStore") final TrustStoreConfiguration trustStoreConfig) {
234             // @formatter:on
235         return new SslConfiguration(protocol, keyStoreConfig, trustStoreConfig);
236     }
237 
238     @Override
239     public int hashCode() {
240         final int prime = 31;
241         int result = 1;
242         result = prime * result + ((keyStoreConfig == null) ? 0 : keyStoreConfig.hashCode());
243         result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
244         result = prime * result + ((sslContext == null) ? 0 : sslContext.hashCode());
245         result = prime * result + ((trustStoreConfig == null) ? 0 : trustStoreConfig.hashCode());
246         return result;
247     }
248 
249     @Override
250     public boolean equals(final Object obj) {
251         if (this == obj) {
252             return true;
253         }
254         if (obj == null) {
255             return false;
256         }
257         if (getClass() != obj.getClass()) {
258             return false;
259         }
260         final SslConfiguration other = (SslConfiguration) obj;
261         if (keyStoreConfig == null) {
262             if (other.keyStoreConfig != null) {
263                 return false;
264             }
265         } else if (!keyStoreConfig.equals(other.keyStoreConfig)) {
266             return false;
267         }
268         if (protocol == null) {
269             if (other.protocol != null) {
270                 return false;
271             }
272         } else if (!protocol.equals(other.protocol)) {
273             return false;
274         }
275         if (sslContext == null) {
276             if (other.sslContext != null) {
277                 return false;
278             }
279         } else if (!sslContext.equals(other.sslContext)) {
280             return false;
281         }
282         if (trustStoreConfig == null) {
283             if (other.trustStoreConfig != null) {
284                 return false;
285             }
286         } else if (!trustStoreConfig.equals(other.trustStoreConfig)) {
287             return false;
288         }
289         return true;
290     }
291 
292     public KeyStoreConfiguration getKeyStoreConfig() {
293         return keyStoreConfig;
294     }
295 
296     public TrustStoreConfiguration getTrustStoreConfig() {
297         return trustStoreConfig;
298     }
299 
300     public SSLContext getSslContext() {
301         return sslContext;
302     }
303 
304     public String getProtocol() {
305         return protocol;
306     }
307 }