001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.net.ssl;
018    
019    import java.security.KeyManagementException;
020    import java.security.KeyStore;
021    import java.security.KeyStoreException;
022    import java.security.NoSuchAlgorithmException;
023    import java.security.UnrecoverableKeyException;
024    
025    import javax.net.ssl.KeyManager;
026    import javax.net.ssl.KeyManagerFactory;
027    import javax.net.ssl.SSLContext;
028    import javax.net.ssl.SSLServerSocketFactory;
029    import javax.net.ssl.SSLSocketFactory;
030    import javax.net.ssl.TrustManager;
031    import javax.net.ssl.TrustManagerFactory;
032    
033    import org.apache.logging.log4j.core.config.plugins.Plugin;
034    import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
035    import org.apache.logging.log4j.core.config.plugins.PluginElement;
036    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
037    import org.apache.logging.log4j.status.StatusLogger;
038    
039    /**
040     *  SSL Configuration
041     */
042    @Plugin(name = "Ssl", category = "Core", printObject = true)
043    public class SslConfiguration {
044        private static final StatusLogger LOGGER = StatusLogger.getLogger();
045        private final KeyStoreConfiguration keyStoreConfig;
046        private final TrustStoreConfiguration trustStoreConfig;
047        private final SSLContext sslContext;
048        private final String protocol;
049    
050        private SslConfiguration(String protocol, KeyStoreConfiguration keyStoreConfig,
051                TrustStoreConfiguration trustStoreConfig) {
052            this.keyStoreConfig = keyStoreConfig;
053            this.trustStoreConfig = trustStoreConfig;
054            this.protocol = protocol == null ? SslConfigurationDefaults.PROTOCOL : protocol;
055            this.sslContext = this.createSslContext();
056        }
057    
058        public SSLSocketFactory getSslSocketFactory() {
059            return sslContext.getSocketFactory();
060        }
061    
062        public SSLServerSocketFactory getSslServerSocketFactory() {
063            return sslContext.getServerSocketFactory();
064        }
065    
066        private SSLContext createSslContext() {
067            SSLContext context = null;
068    
069            try {
070                context = createSslContextBasedOnConfiguration();
071                LOGGER.debug("Creating SSLContext with the given parameters");
072            }
073            catch (TrustStoreConfigurationException e) {
074                context = createSslContextWithTrustStoreFailure();
075            }
076            catch (KeyStoreConfigurationException e) {
077                context = createSslContextWithKeyStoreFailure();
078            }
079            return context;
080        }
081    
082        private SSLContext createSslContextWithTrustStoreFailure() {
083            SSLContext context;
084    
085            try {
086                context = createSslContextWithDefaultTrustManagerFactory();
087                LOGGER.debug("Creating SSLContext with default truststore");
088            }
089            catch (KeyStoreConfigurationException e) {
090                context = createDefaultSslContext();
091                LOGGER.debug("Creating SSLContext with default configuration");
092            }
093            return context;
094        }
095    
096        private SSLContext createSslContextWithKeyStoreFailure() {
097            SSLContext context;
098    
099            try {
100                context = createSslContextWithDefaultKeyManagerFactory();
101                LOGGER.debug("Creating SSLContext with default keystore");
102            }
103            catch (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 (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 (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 (NoSuchAlgorithmException e) {
137                LOGGER.error("Failed to create an SSLContext with default configuration");
138                return null;
139            }
140        }
141    
142        private SSLContext createSslContext(boolean loadDefaultKeyManagerFactory, boolean loadDefaultTrustManagerFactory)
143                throws KeyStoreConfigurationException, TrustStoreConfigurationException {
144            try {
145                KeyManager[] kManagers = null;
146                TrustManager[] tManagers = null;
147    
148                SSLContext newSslContext = SSLContext.getInstance(this.protocol);
149                if (!loadDefaultKeyManagerFactory) {
150                    KeyManagerFactory kmFactory = loadKeyManagerFactory();
151                    kManagers = kmFactory.getKeyManagers();
152                }
153                if (!loadDefaultTrustManagerFactory) {
154                    TrustManagerFactory tmFactory = loadTrustManagerFactory();
155                    tManagers = tmFactory.getTrustManagers();
156                }
157    
158                newSslContext.init(kManagers, tManagers, null);
159                return newSslContext;
160            }
161            catch (NoSuchAlgorithmException e) {
162                LOGGER.error("No Provider supports a TrustManagerFactorySpi implementation for the specified protocol");
163                throw new TrustStoreConfigurationException(e);
164            }
165            catch (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 (NoSuchAlgorithmException e) {
180                LOGGER.error("The specified algorithm is not available from the specified provider");
181                throw new TrustStoreConfigurationException(e);
182            } catch (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 (NoSuchAlgorithmException e) {
197                LOGGER.error("The specified algorithm is not available from the specified provider");
198                throw new KeyStoreConfigurationException(e);
199            } catch (KeyStoreException e) {
200                LOGGER.error("Failed to initialize the TrustManagerFactory");
201                throw new KeyStoreConfigurationException(e);
202            } catch (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(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") String protocol,
242                @PluginElement("KeyStore") KeyStoreConfiguration keyStoreConfig, 
243                @PluginElement("TrustStore") TrustStoreConfiguration trustStoreConfig) {
244                // @formatter:on
245            return new SslConfiguration(protocol, keyStoreConfig, trustStoreConfig);
246        }
247    }