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.KeyStore;
21  import java.security.KeyStoreException;
22  import java.security.NoSuchAlgorithmException;
23  import java.security.UnrecoverableKeyException;
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  
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", 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      public SSLSocketFactory getSslSocketFactory() {
59          return sslContext.getSocketFactory();
60      }
61  
62      public SSLServerSocketFactory getSslServerSocketFactory() {
63          return sslContext.getServerSocketFactory();
64      }
65  
66      private SSLContext createSslContext() {
67          SSLContext context = null;
68  
69          try {
70              context = createSslContextBasedOnConfiguration();
71              LOGGER.debug("Creating SSLContext with the given parameters");
72          }
73          catch (final TrustStoreConfigurationException e) {
74              context = createSslContextWithTrustStoreFailure();
75          }
76          catch (final KeyStoreConfigurationException e) {
77              context = createSslContextWithKeyStoreFailure();
78          }
79          return context;
80      }
81  
82      private SSLContext createSslContextWithTrustStoreFailure() {
83          SSLContext context;
84  
85          try {
86              context = createSslContextWithDefaultTrustManagerFactory();
87              LOGGER.debug("Creating SSLContext with default truststore");
88          }
89          catch (final KeyStoreConfigurationException e) {
90              context = createDefaultSslContext();
91              LOGGER.debug("Creating SSLContext with default configuration");
92          }
93          return context;
94      }
95  
96      private SSLContext createSslContextWithKeyStoreFailure() {
97          SSLContext context;
98  
99          try {
100             context = createSslContextWithDefaultKeyManagerFactory();
101             LOGGER.debug("Creating SSLContext with default keystore");
102         }
103         catch (final TrustStoreConfigurationException e) {
104             context = createDefaultSslContext();
105             LOGGER.debug("Creating SSLContext with default configuration");
106         }
107         return context;
108     }
109 
110     private SSLContext createSslContextBasedOnConfiguration() throws KeyStoreConfigurationException, TrustStoreConfigurationException {
111         return createSslContext(false, false);
112     }
113 
114     private SSLContext createSslContextWithDefaultKeyManagerFactory() throws TrustStoreConfigurationException {
115         try {
116             return createSslContext(true, false);
117         } catch (final KeyStoreConfigurationException dummy) {
118              LOGGER.debug("Exception occured while using default keystore. This should be a BUG");
119              return null;
120         }
121     }
122 
123     private SSLContext createSslContextWithDefaultTrustManagerFactory() throws KeyStoreConfigurationException {
124         try {
125             return createSslContext(false, true);
126         }
127         catch (final TrustStoreConfigurationException dummy) {
128             LOGGER.debug("Exception occured while using default truststore. This should be a BUG");
129             return null;
130         }
131     }
132 
133     private SSLContext createDefaultSslContext() {
134         try {
135             return SSLContext.getDefault();
136         } catch (final NoSuchAlgorithmException e) {
137             LOGGER.error("Failed to create an SSLContext with default configuration");
138             return null;
139         }
140     }
141 
142     private SSLContext createSslContext(final boolean loadDefaultKeyManagerFactory, final boolean loadDefaultTrustManagerFactory)
143             throws KeyStoreConfigurationException, TrustStoreConfigurationException {
144         try {
145             KeyManager[] kManagers = null;
146             TrustManager[] tManagers = null;
147 
148             final SSLContext newSslContext = SSLContext.getInstance(this.protocol);
149             if (!loadDefaultKeyManagerFactory) {
150                 final KeyManagerFactory kmFactory = loadKeyManagerFactory();
151                 kManagers = kmFactory.getKeyManagers();
152             }
153             if (!loadDefaultTrustManagerFactory) {
154                 final TrustManagerFactory tmFactory = loadTrustManagerFactory();
155                 tManagers = tmFactory.getTrustManagers();
156             }
157 
158             newSslContext.init(kManagers, tManagers, null);
159             return newSslContext;
160         }
161         catch (final NoSuchAlgorithmException e) {
162             LOGGER.error("No Provider supports a TrustManagerFactorySpi implementation for the specified protocol");
163             throw new TrustStoreConfigurationException(e);
164         }
165         catch (final KeyManagementException e) {
166             LOGGER.error("Failed to initialize the SSLContext");
167             throw new KeyStoreConfigurationException(e);
168         }
169     }
170 
171     private TrustManagerFactory loadTrustManagerFactory() throws TrustStoreConfigurationException {
172         if (trustStoreConfig == null) {
173             throw new TrustStoreConfigurationException(new Exception("The trustStoreConfiguration is null"));
174         }
175 
176         try {
177             return trustStoreConfig.initTrustManagerFactory();
178         }
179         catch (final NoSuchAlgorithmException e) {
180             LOGGER.error("The specified algorithm is not available from the specified provider");
181             throw new TrustStoreConfigurationException(e);
182         } catch (final KeyStoreException e) {
183             LOGGER.error("Failed to initialize the TrustManagerFactory");
184             throw new TrustStoreConfigurationException(e);
185         }
186     }
187 
188     private KeyManagerFactory loadKeyManagerFactory() throws KeyStoreConfigurationException {
189         if (keyStoreConfig == null) {
190             throw new KeyStoreConfigurationException(new Exception("The keyStoreConfiguration is null"));
191         }
192 
193         try {
194             return keyStoreConfig.initKeyManagerFactory();
195         }
196         catch (final NoSuchAlgorithmException e) {
197             LOGGER.error("The specified algorithm is not available from the specified provider");
198             throw new KeyStoreConfigurationException(e);
199         } catch (final KeyStoreException e) {
200             LOGGER.error("Failed to initialize the TrustManagerFactory");
201             throw new KeyStoreConfigurationException(e);
202         } catch (final UnrecoverableKeyException e) {
203             LOGGER.error("The key cannot be recovered (e.g. the given password is wrong)");
204             throw new KeyStoreConfigurationException(e);
205         }
206     }
207 
208     public boolean equals(final SslConfiguration config) {
209         if (config == null) {
210             return false;
211         }
212 
213         boolean keyStoreEquals = false;
214         boolean trustStoreEquals = false;
215 
216         if (keyStoreConfig != null) {
217             keyStoreEquals = keyStoreConfig.equals(config.keyStoreConfig);
218         } else {
219             keyStoreEquals = keyStoreConfig == config.keyStoreConfig;
220         }
221 
222         if (trustStoreConfig != null) {
223             trustStoreEquals = trustStoreConfig.equals(config.trustStoreConfig);
224         } else {
225             trustStoreEquals = trustStoreConfig == config.trustStoreConfig;
226         }
227 
228         return keyStoreEquals && trustStoreEquals;
229     }
230 
231     /**
232      * Creates an SslConfiguration from a KeyStoreConfiguration and a TrustStoreConfiguration.
233      * @param protocol The protocol, see http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext
234      * @param keyStoreConfig The KeyStoreConfiguration.
235      * @param trustStoreConfig The TrustStoreConfiguration.
236      * @return a new SslConfiguration
237      */
238     @PluginFactory
239     public static SslConfiguration createSSLConfiguration(
240             // @formatter:off
241             @PluginAttribute("protocol") final String protocol,
242             @PluginElement("KeyStore") final KeyStoreConfiguration keyStoreConfig, 
243             @PluginElement("TrustStore") final TrustStoreConfiguration trustStoreConfig) {
244             // @formatter:on
245         return new SslConfiguration(protocol, keyStoreConfig, trustStoreConfig);
246     }
247 }