001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2015 ForgeRock AS.
015 */
016package org.forgerock.audit.secure;
017
018import java.security.KeyStore;
019import java.security.KeyStoreException;
020import java.security.NoSuchAlgorithmException;
021import java.security.PrivateKey;
022import java.security.PublicKey;
023import java.security.UnrecoverableEntryException;
024import java.security.cert.Certificate;
025
026import javax.crypto.SecretKey;
027
028/**
029 * Decorate a {@link KeyStoreHandler} in order to add some commons utility methods to read or write keystore's entries.
030 */
031public class KeyStoreHandlerDecorator implements KeyStoreHandler {
032
033    private final KeyStoreHandler delegate;
034
035    /**
036     * Constructs a new {@literal KeyStoreHandlerDecorator}
037     * @param delegate the {@literal KeyStoreHandler} to decorate.
038     */
039    public KeyStoreHandlerDecorator(KeyStoreHandler delegate) {
040        this.delegate = delegate;
041    }
042
043    /**
044     * Writes to the secret storage using the same password than the {@literal KeyStoreHandler}.
045     *
046     * @param secretKey
047     *            The data to be written to the secret storage
048     * @param alias
049     *            The kind of cryptoMaterial, whether it is a signature or a key
050     * @throws SecureStorageException
051     *             if it fails to write secret data from secret store
052     */
053    public void writeToKeyStore(SecretKey secretKey, String alias) throws SecureStorageException {
054         writeToKeyStore(secretKey, alias, getPassword());
055     }
056
057    /**
058     * Writes to the secret storage.
059     *
060     * @param secretKey
061     *            The data to be written to the secret storage
062     * @param alias
063     *            The kind of cryptoMaterial, whether it is a signature or a key
064     * @param password
065     *            The password to read the key
066     * @throws SecureStorageException
067     *             if it fails to write secret data from secret store
068     */
069     public void writeToKeyStore(SecretKey secretKey, String alias, String password) throws SecureStorageException {
070        // Note that it need JCEKS to support secret keys.
071        try {
072            KeyStore store = getStore();
073            if (store.containsAlias(alias)) {
074                store.deleteEntry(alias);
075            }
076            KeyStore.SecretKeyEntry secKeyEntry = new KeyStore.SecretKeyEntry(secretKey);
077            KeyStore.ProtectionParameter params = new KeyStore.PasswordProtection(password.toCharArray());
078            store.setEntry(alias, secKeyEntry, params);
079        } catch (Exception ex) {
080            throw new SecureStorageException(ex);
081        }
082    }
083
084    public PublicKey readPublicKeyFromKeyStore(String alias) throws SecureStorageException {
085        try {
086            KeyStore store = getStore();
087            Certificate certificate = store.getCertificate(alias);
088            return certificate.getPublicKey();
089        } catch (KeyStoreException ex) {
090            throw new SecureStorageException("Error when reading public key: " + alias, ex);
091        }
092    }
093
094    public PrivateKey readPrivateKeyFromKeyStore(String alias) throws SecureStorageException {
095        return readPrivateKeyFromKeyStore(alias, getPassword());
096    }
097
098    public PrivateKey readPrivateKeyFromKeyStore(String alias, String password) throws SecureStorageException {
099        try {
100            KeyStore store = getStore();
101            KeyStore.ProtectionParameter params = password != null ?
102                    new KeyStore.PasswordProtection(password.toCharArray()) : null;
103            KeyStore.PrivateKeyEntry keyentry = (KeyStore.PrivateKeyEntry) store.getEntry(alias, params);
104            return keyentry != null ? keyentry.getPrivateKey() : null;
105        } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException ex) {
106            throw new SecureStorageException(ex);
107        }
108    }
109
110    public SecretKey readSecretKeyFromKeyStore(String alias) throws SecureStorageException {
111        return readSecretKeyFromKeyStore(alias, getPassword());
112    }
113
114    public SecretKey readSecretKeyFromKeyStore(String alias, String password) throws SecureStorageException {
115        try {
116            KeyStore store = getStore();
117            KeyStore.ProtectionParameter params = new KeyStore.PasswordProtection(password.toCharArray());
118            KeyStore.SecretKeyEntry keyentry = (KeyStore.SecretKeyEntry) store.getEntry(alias, params);
119            return keyentry != null ? keyentry.getSecretKey() : null;
120        } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) {
121            throw new SecureStorageException(e);
122        }
123    }
124
125    @Override
126    public KeyStore getStore() {
127        return delegate.getStore();
128    }
129
130    @Override
131    public void setStore(KeyStore keystore) throws Exception {
132        delegate.setStore(keystore);
133    }
134
135    @Override
136    public String getPassword() {
137        return delegate.getPassword();
138    }
139
140    @Override
141    public String getLocation() {
142        return delegate.getLocation();
143    }
144
145    @Override
146    public String getType() {
147        return delegate.getType();
148    }
149
150    @Override
151    public void store() throws Exception {
152        delegate.store();
153    }
154
155}