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    private final KeyStore keyStore;
037    private final String keyStoreType;
038
039    public AbstractKeyStoreConfiguration(final String location, final PasswordProvider passwordProvider, final String keyStoreType)
040            throws StoreConfigurationException {
041        super(location, passwordProvider);
042        this.keyStoreType = keyStoreType == null ? SslConfigurationDefaults.KEYSTORE_TYPE : keyStoreType;
043        this.keyStore = this.load();
044    }
045
046    /**
047     * @deprecated Use {@link #AbstractKeyStoreConfiguration(String, PasswordProvider, String)} instead
048     */
049    @Deprecated
050    public AbstractKeyStoreConfiguration(final String location, final char[] password, final String keyStoreType)
051            throws StoreConfigurationException {
052        this(location, new MemoryPasswordProvider(password), keyStoreType);
053    }
054
055    /**
056     * @deprecated Use {@link #AbstractKeyStoreConfiguration(String, PasswordProvider, String)} instead
057     */
058    @Deprecated
059    public AbstractKeyStoreConfiguration(final String location, final String password, final String keyStoreType)
060            throws StoreConfigurationException {
061        this(location, new MemoryPasswordProvider(password == null ? null : password.toCharArray()), keyStoreType);
062    }
063
064    @Override
065    protected KeyStore load() throws StoreConfigurationException {
066        final String loadLocation = this.getLocation();
067        LOGGER.debug("Loading keystore from location {}", loadLocation);
068        try {
069            if (loadLocation == null) {
070                throw new IOException("The location is null");
071            }
072            try (final InputStream fin = openInputStream(loadLocation)) {
073                final KeyStore ks = KeyStore.getInstance(this.keyStoreType);
074                final char[] password = this.getPasswordAsCharArray();
075                try {
076                    ks.load(fin, password);
077                } finally {
078                    if (password != null) {
079                        Arrays.fill(password, '\0');
080                    }
081                }
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        }
101    }
102
103    private InputStream openInputStream(final String filePathOrUri) {
104        return ConfigurationSource.fromUri(NetUtils.toURI(filePathOrUri)).getInputStream();
105    }
106
107    public KeyStore getKeyStore() {
108        return this.keyStore;
109    }
110
111    @Override
112    public int hashCode() {
113        final int prime = 31;
114        int result = super.hashCode();
115        result = prime * result + ((keyStore == null) ? 0 : keyStore.hashCode());
116        result = prime * result + ((keyStoreType == null) ? 0 : keyStoreType.hashCode());
117        return result;
118    }
119
120    @Override
121    public boolean equals(final Object obj) {
122        if (this == obj) {
123            return true;
124        }
125        if (!super.equals(obj)) {
126            return false;
127        }
128        if (getClass() != obj.getClass()) {
129            return false;
130        }
131        final AbstractKeyStoreConfiguration other = (AbstractKeyStoreConfiguration) obj;
132        if (!Objects.equals(keyStore, other.keyStore)) {
133            return false;
134        }
135        if (!Objects.equals(keyStoreType, other.keyStoreType)) {
136            return false;
137        }
138        return true;
139    }
140
141    public String getKeyStoreType() {
142        return keyStoreType;
143    }
144
145}