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 */
017package org.apache.logging.log4j.core.net.ssl;
018
019import java.security.KeyStoreException;
020import java.security.NoSuchAlgorithmException;
021import java.security.UnrecoverableKeyException;
022import java.util.Arrays;
023
024import javax.net.ssl.KeyManagerFactory;
025
026import org.apache.logging.log4j.core.Core;
027import org.apache.logging.log4j.core.config.plugins.Plugin;
028import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
029import org.apache.logging.log4j.core.config.plugins.PluginFactory;
030
031/**
032 * Configuration of the KeyStore
033 */
034@Plugin(name = "KeyStore", category = Core.CATEGORY_NAME, printObject = true)
035public class KeyStoreConfiguration extends AbstractKeyStoreConfiguration {
036
037    private final String keyManagerFactoryAlgorithm;
038
039    /**
040     *
041     * @throws StoreConfigurationException Thrown if this instance cannot load the KeyStore.
042     */
043    public KeyStoreConfiguration(final String location,
044                                 final PasswordProvider  passwordProvider,
045                                 final String keyStoreType,
046                                 final String keyManagerFactoryAlgorithm) throws StoreConfigurationException {
047        super(location, passwordProvider, keyStoreType);
048        this.keyManagerFactoryAlgorithm = keyManagerFactoryAlgorithm == null ? KeyManagerFactory.getDefaultAlgorithm()
049                : keyManagerFactoryAlgorithm;
050    }
051
052    /**
053     *
054     * @throws StoreConfigurationException Thrown if this instance cannot load the KeyStore.
055     * @deprecated use {@link #KeyStoreConfiguration(String, PasswordProvider, String, String)} instead
056     */
057    public KeyStoreConfiguration(final String location,
058                                 final char[] password,
059                                 final String keyStoreType,
060                                 final String keyManagerFactoryAlgorithm) throws StoreConfigurationException {
061        this(location, new MemoryPasswordProvider(password), keyStoreType, keyManagerFactoryAlgorithm);
062        if (password != null) {
063            Arrays.fill(password, '\0');
064        }
065    }
066
067    /**
068     *
069     * @throws StoreConfigurationException Thrown if this instance cannot load the KeyStore.
070     * @deprecated Use {@link #KeyStoreConfiguration(String, PasswordProvider, String, String)} instead
071     */
072    @Deprecated
073    public KeyStoreConfiguration(final String location, final String password, final String keyStoreType,
074            final String keyManagerFactoryAlgorithm) throws StoreConfigurationException {
075        this(location, new MemoryPasswordProvider(password == null ? null : password.toCharArray()), keyStoreType,
076                keyManagerFactoryAlgorithm);
077    }
078
079    /**
080     * Creates a KeyStoreConfiguration.
081     *
082     * @param location
083     *        The location of the KeyStore, a file path, URL or resource.
084     * @param password
085     *        The password to access the KeyStore.
086     * @param keyStoreType
087     *        The KeyStore type, null defaults to {@code "JKS"}.
088     * @param keyManagerFactoryAlgorithm
089     *         The standard name of the requested algorithm. See the Java Secure Socket Extension Reference Guide for information about these names.
090     * @return a new KeyStoreConfiguration
091     * @throws StoreConfigurationException Thrown if this call cannot load the KeyStore.
092     */
093    @PluginFactory
094    public static KeyStoreConfiguration createKeyStoreConfiguration(
095            // @formatter:off
096            @PluginAttribute("location") final String location,
097            @PluginAttribute(value = "password", sensitive = true) final char[] password,
098            @PluginAttribute("passwordEnvironmentVariable") final String passwordEnvironmentVariable,
099            @PluginAttribute("passwordFile") final String passwordFile,
100            @PluginAttribute("type") final String keyStoreType,
101            @PluginAttribute("keyManagerFactoryAlgorithm") final String keyManagerFactoryAlgorithm) throws StoreConfigurationException {
102            // @formatter:on
103
104        if (password != null && passwordEnvironmentVariable != null && passwordFile != null) {
105            throw new StoreConfigurationException("You MUST set only one of 'password', 'passwordEnvironmentVariable' or 'passwordFile'.");
106        }
107        try {
108            // @formatter:off
109            PasswordProvider provider = passwordFile != null
110                    ? new FilePasswordProvider(passwordFile)
111                    : passwordEnvironmentVariable != null
112                            ? new EnvironmentPasswordProvider(passwordEnvironmentVariable)
113                            // the default is memory char[] array, which may be null
114                            : new MemoryPasswordProvider(password);
115            // @formatter:on
116            if (password != null) {
117                Arrays.fill(password, '\0');
118            }
119            return new KeyStoreConfiguration(location, provider, keyStoreType, keyManagerFactoryAlgorithm);
120        } catch (Exception ex) {
121            throw new StoreConfigurationException("Could not configure KeyStore", ex);
122        }
123    }
124
125    /**
126     * @deprecated use {@link #createKeyStoreConfiguration(String, char[], String, String, String, String)}
127     */
128    public static KeyStoreConfiguration createKeyStoreConfiguration(
129            // @formatter:off
130            final String location,
131            final char[] password,
132            final String keyStoreType,
133            final String keyManagerFactoryAlgorithm) throws StoreConfigurationException {
134            // @formatter:on
135        return createKeyStoreConfiguration(location, password, null, null, keyStoreType, keyManagerFactoryAlgorithm);
136    }
137
138    /**
139     * Creates a KeyStoreConfiguration.
140     *
141     * @param location The location of the KeyStore, a file path, URL or resource.
142     * @param password The password to access the KeyStore.
143     * @param keyStoreType The KeyStore type, null defaults to {@code "JKS"}.
144     * @param keyManagerFactoryAlgorithm The standard name of the requested algorithm. See the Java Secure Socket
145     * Extension Reference Guide for information about these names.
146     * @return a new KeyStoreConfiguration
147     * @throws StoreConfigurationException Thrown if this call cannot load the KeyStore.
148     * @deprecated Use createKeyStoreConfiguration(String, char[], String, String)
149     */
150    @Deprecated
151    public static KeyStoreConfiguration createKeyStoreConfiguration(
152            // @formatter:off
153            final String location,
154            final String password,
155            final String keyStoreType,
156            final String keyManagerFactoryAlgorithm) throws StoreConfigurationException {
157            // @formatter:on
158        return createKeyStoreConfiguration(location,
159                (password == null ? null : password.toCharArray()),
160                keyStoreType,
161                keyManagerFactoryAlgorithm);
162    }
163
164    public KeyManagerFactory initKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException,
165            KeyStoreException {
166        final KeyManagerFactory kmFactory = KeyManagerFactory.getInstance(this.keyManagerFactoryAlgorithm);
167        char[] password = this.getPasswordAsCharArray();
168        try {
169            kmFactory.init(this.getKeyStore(), password);
170        } finally {
171            if (password != null) {
172                Arrays.fill(password, '\0');
173            }
174        }
175        return kmFactory;
176    }
177
178    @Override
179    public int hashCode() {
180        final int prime = 31;
181        int result = super.hashCode();
182        result = prime * result + ((keyManagerFactoryAlgorithm == null) ? 0 : keyManagerFactoryAlgorithm.hashCode());
183        return result;
184    }
185
186    @Override
187    public boolean equals(final Object obj) {
188        if (this == obj) {
189            return true;
190        }
191        if (!super.equals(obj)) {
192            return false;
193        }
194        if (getClass() != obj.getClass()) {
195            return false;
196        }
197        final KeyStoreConfiguration other = (KeyStoreConfiguration) obj;
198        if (keyManagerFactoryAlgorithm == null) {
199            if (other.keyManagerFactoryAlgorithm != null) {
200                return false;
201            }
202        } else if (!keyManagerFactoryAlgorithm.equals(other.keyManagerFactoryAlgorithm)) {
203            return false;
204        }
205        return true;
206    }
207
208    public String getKeyManagerFactoryAlgorithm() {
209        return keyManagerFactoryAlgorithm;
210    }
211}