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