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.config.plugins.Plugin;
33  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
34  import org.apache.logging.log4j.core.config.plugins.PluginElement;
35  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
36  import org.apache.logging.log4j.status.StatusLogger;
37  
38  /**
39   *  SSL Configuration
40   */
41  @Plugin(name = "Ssl", category = "Core", printObject = true)
42  public class SslConfiguration {
43      private static final StatusLogger LOGGER = StatusLogger.getLogger();
44      private final KeyStoreConfiguration keyStoreConfig;
45      private final TrustStoreConfiguration trustStoreConfig;
46      private final SSLContext sslContext;
47      private final String protocol;
48  
49      private SslConfiguration(final String protocol, final KeyStoreConfiguration keyStoreConfig,
50              final TrustStoreConfiguration trustStoreConfig) {
51          this.keyStoreConfig = keyStoreConfig;
52          this.trustStoreConfig = trustStoreConfig;
53          this.protocol = protocol == null ? SslConfigurationDefaults.PROTOCOL : protocol;
54          this.sslContext = this.createSslContext();
55      }
56  
57      public SSLSocketFactory getSslSocketFactory() {
58          return sslContext.getSocketFactory();
59      }
60  
61      public SSLServerSocketFactory getSslServerSocketFactory() {
62          return sslContext.getServerSocketFactory();
63      }
64  
65      private SSLContext createSslContext() {
66          SSLContext context = null;
67  
68          try {
69              context = createSslContextBasedOnConfiguration();
70              LOGGER.debug("Creating SSLContext with the given parameters");
71          }
72          catch (final TrustStoreConfigurationException e) {
73              context = createSslContextWithTrustStoreFailure();
74          }
75          catch (final KeyStoreConfigurationException e) {
76              context = createSslContextWithKeyStoreFailure();
77          }
78          return context;
79      }
80  
81      private SSLContext createSslContextWithTrustStoreFailure() {
82          SSLContext context;
83  
84          try {
85              context = createSslContextWithDefaultTrustManagerFactory();
86              LOGGER.debug("Creating SSLContext with default truststore");
87          }
88          catch (final KeyStoreConfigurationException e) {
89              context = createDefaultSslContext();
90              LOGGER.debug("Creating SSLContext with default configuration");
91          }
92          return context;
93      }
94  
95      private SSLContext createSslContextWithKeyStoreFailure() {
96          SSLContext context;
97  
98          try {
99              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", e);
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", e);
162             throw new TrustStoreConfigurationException(e);
163         }
164         catch (final KeyManagementException e) {
165             LOGGER.error("Failed to initialize the SSLContext", e);
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", e);
180             throw new TrustStoreConfigurationException(e);
181         } catch (final KeyStoreException e) {
182             LOGGER.error("Failed to initialize the TrustManagerFactory", e);
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", e);
197             throw new KeyStoreConfigurationException(e);
198         } catch (final KeyStoreException e) {
199             LOGGER.error("Failed to initialize the TrustManagerFactory", e);
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)", e);
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 }