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.io.FileNotFoundException;
020import java.io.IOException;
021import java.io.InputStream;
022import java.security.KeyStore;
023import java.security.KeyStoreException;
024import java.security.NoSuchAlgorithmException;
025import java.security.cert.CertificateException;
026import java.util.Arrays;
027import java.util.Objects;
028
029import org.apache.logging.log4j.core.config.ConfigurationSource;
030import org.apache.logging.log4j.core.util.NetUtils;
031
032/**
033 * Configuration of the KeyStore
034 */
035public class AbstractKeyStoreConfiguration extends StoreConfiguration<KeyStore> {
036
037    private final KeyStore keyStore;
038    private final String keyStoreType;
039
040    public AbstractKeyStoreConfiguration(final String location, final PasswordProvider passwordProvider, final String keyStoreType)
041            throws StoreConfigurationException {
042        super(location, passwordProvider);
043        this.keyStoreType = keyStoreType == null ? SslConfigurationDefaults.KEYSTORE_TYPE : keyStoreType;
044        this.keyStore = this.load();
045    }
046
047    /**
048     * @deprecated Use {@link #AbstractKeyStoreConfiguration(String, PasswordProvider, String)} instead
049     */
050    @Deprecated
051    public AbstractKeyStoreConfiguration(final String location, final char[] password, final String keyStoreType)
052            throws StoreConfigurationException {
053        this(location, new MemoryPasswordProvider(password), keyStoreType);
054    }
055
056    /**
057     * @deprecated Use {@link #AbstractKeyStoreConfiguration(String, PasswordProvider, String)} instead
058     */
059    @Deprecated
060    public AbstractKeyStoreConfiguration(final String location, final String password, final String keyStoreType)
061            throws StoreConfigurationException {
062        this(location, new MemoryPasswordProvider(password == null ? null : password.toCharArray()), keyStoreType);
063    }
064
065    @Override
066    protected KeyStore load() throws StoreConfigurationException {
067        final String loadLocation = this.getLocation();
068        final char[] password = this.getPasswordAsCharArray();
069        LOGGER.debug("Loading keystore from location {}", loadLocation);
070        try {
071            final KeyStore ks = KeyStore.getInstance(this.keyStoreType);
072            if (loadLocation == null) {
073                if (keyStoreType.equalsIgnoreCase(JKS) || keyStoreType.equalsIgnoreCase(PKCS12)) {
074                    throw new IOException("The location is null");
075                }
076                ks.load(null, password);
077                LOGGER.debug("KeyStore successfully loaded");
078                return ks;
079            }
080            try (final InputStream fin = openInputStream(loadLocation)) {
081                ks.load(fin, password);
082                LOGGER.debug("KeyStore successfully loaded from location {}", loadLocation);
083                return ks;
084            }
085        } catch (final CertificateException e) {
086            LOGGER.error("No Provider supports a KeyStoreSpi implementation for the specified type {} for location {}", this.keyStoreType, loadLocation, e);
087            throw new StoreConfigurationException(loadLocation, e);
088        } catch (final NoSuchAlgorithmException e) {
089            LOGGER.error("The algorithm used to check the integrity of the keystore cannot be found for location {}", loadLocation, e);
090            throw new StoreConfigurationException(loadLocation, e);
091        } catch (final KeyStoreException e) {
092            LOGGER.error("KeyStoreException for location {}", loadLocation, e);
093            throw new StoreConfigurationException(loadLocation, e);
094        } catch (final FileNotFoundException e) {
095            LOGGER.error("The keystore file {} is not found", loadLocation, e);
096            throw new StoreConfigurationException(loadLocation, e);
097        } catch (final IOException e) {
098            LOGGER.error("Something is wrong with the format of the keystore or the given password for location {}", loadLocation, e);
099            throw new StoreConfigurationException(loadLocation, e);
100        } finally {
101            if (password != null) {
102                Arrays.fill(password, '\0');
103            }
104        }
105    }
106
107    private InputStream openInputStream(final String filePathOrUri) {
108        return ConfigurationSource.fromUri(NetUtils.toURI(filePathOrUri)).getInputStream();
109    }
110
111    public KeyStore getKeyStore() {
112        return this.keyStore;
113    }
114
115    @Override
116    public int hashCode() {
117        final int prime = 31;
118        int result = super.hashCode();
119        result = prime * result + ((keyStore == null) ? 0 : keyStore.hashCode());
120        result = prime * result + ((keyStoreType == null) ? 0 : keyStoreType.hashCode());
121        return result;
122    }
123
124    @Override
125    public boolean equals(final Object obj) {
126        if (this == obj) {
127            return true;
128        }
129        if (!super.equals(obj)) {
130            return false;
131        }
132        if (getClass() != obj.getClass()) {
133            return false;
134        }
135        final AbstractKeyStoreConfiguration other = (AbstractKeyStoreConfiguration) obj;
136        if (!Objects.equals(keyStore, other.keyStore)) {
137            return false;
138        }
139        if (!Objects.equals(keyStoreType, other.keyStoreType)) {
140            return false;
141        }
142        return true;
143    }
144
145    public String getKeyStoreType() {
146        return keyStoreType;
147    }
148
149}