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-2016 ForgeRock AS.
015 */
016package org.forgerock.audit.secure;
017
018import java.security.InvalidKeyException;
019import java.security.NoSuchAlgorithmException;
020import java.security.PrivateKey;
021import java.security.PublicKey;
022import java.security.Signature;
023import java.security.SignatureException;
024
025import javax.crypto.SecretKey;
026
027
028/**
029 * Implementation of a secure storage using a keystore.
030 */
031public class KeyStoreSecureStorage implements SecureStorage {
032
033    /** The initial key used to calculate the HEADER_HMAC. */
034    public static final String ENTRY_INITIAL_KEY = "InitialKey";
035
036    /** The alias to lookup the private/public signature key into the keystore. */
037    public static final String ENTRY_SIGNATURE = "Signature";
038
039    /** The last signature inserted into the file. */
040    public static final String ENTRY_CURRENT_SIGNATURE = "CurrentSignature";
041
042    /** The current key used to calculate the HEADER_HMAC. */
043    public static final String ENTRY_CURRENT_KEY = "CurrentKey";
044
045    /** The algorithm to use for signing and verifying. */
046    public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
047    /** The HMAC algorithm to use. */
048    public static final String HMAC_ALGORITHM = "HmacSHA256";
049    /** The name of the Java Cryptography Extension KeyStore (JCEKS) type. */
050    public static final String JCEKS_KEYSTORE_TYPE = "JCEKS";
051
052    private KeyStoreHandlerDecorator keyStoreHandler;
053    private Signature verifier;
054    private Signature signer;
055
056    /**
057     * Creates the storage with a keystore handler, initialized to verify only.
058     *
059     * @param keyStoreHandler
060     *            Handler of a keystore.
061     * @param privateKey
062     *            The private key used to initialize the signer
063     */
064    public KeyStoreSecureStorage(KeyStoreHandler keyStoreHandler, PrivateKey privateKey) {
065        this(keyStoreHandler, null, privateKey);
066    }
067
068    /**
069     * Creates the storage with a keystore handler, initialized to verify only.
070     *
071     * @param keyStoreHandler
072     *            Handler of a keystore.
073     * @param publicKey
074     *            The public key used to initialize the verifier
075     */
076    public KeyStoreSecureStorage(KeyStoreHandler keyStoreHandler, PublicKey publicKey) {
077        this(keyStoreHandler, publicKey, null);
078    }
079
080    /**
081     * Creates the storage with a keystore handler, initialized to verify only.
082     *
083     * @param keyStoreHandler
084     *            Handler of a keystore.
085     * @param publicKey
086     *            The public key used to initialize the verifier
087     * @param privateKey
088     *            The private key used to initialize the signer
089     */
090    public KeyStoreSecureStorage(KeyStoreHandler keyStoreHandler, PublicKey publicKey, PrivateKey privateKey) {
091        setKeyStoreHandler(keyStoreHandler);
092
093        if (privateKey != null) {
094            try {
095                signer = Signature.getInstance(KeyStoreSecureStorage.SIGNATURE_ALGORITHM);
096                signer.initSign(privateKey);
097            } catch (InvalidKeyException | NoSuchAlgorithmException e) {
098                throw new IllegalArgumentException(e);
099            }
100        }
101
102        if (publicKey != null) {
103            try {
104                verifier = Signature.getInstance(KeyStoreSecureStorage.SIGNATURE_ALGORITHM);
105                verifier.initVerify(publicKey);
106            } catch (InvalidKeyException | NoSuchAlgorithmException e) {
107                throw new IllegalArgumentException(e);
108            }
109        }
110    }
111
112    /**
113     * Set the key store handler.
114     * @param keyStoreHandler The handler.
115     */
116    public void setKeyStoreHandler(KeyStoreHandler keyStoreHandler) {
117        this.keyStoreHandler = new KeyStoreHandlerDecorator(keyStoreHandler);
118    }
119
120    @Override
121    public String getPassword() {
122        return keyStoreHandler.getPassword();
123    }
124
125    @Override
126    public SecretKey readCurrentKey() throws SecureStorageException {
127        return keyStoreHandler.readSecretKeyFromKeyStore(KeyStoreSecureStorage.ENTRY_CURRENT_KEY);
128    }
129
130    @Override
131    public SecretKey readInitialKey() throws SecureStorageException {
132        return keyStoreHandler.readSecretKeyFromKeyStore(KeyStoreSecureStorage.ENTRY_INITIAL_KEY);
133    }
134
135    @Override
136    public void writeCurrentSignatureKey(SecretKey key) throws SecureStorageException {
137        keyStoreHandler.writeToKeyStore(key, KeyStoreSecureStorage.ENTRY_CURRENT_SIGNATURE,
138                keyStoreHandler.getPassword());
139        try {
140            keyStoreHandler.store();
141        } catch (Exception ex) {
142            throw new SecureStorageException(ex);
143        }
144    }
145
146    @Override
147    public void writeCurrentKey(SecretKey key) throws SecureStorageException {
148        writeKey(key, KeyStoreSecureStorage.ENTRY_CURRENT_KEY);
149    }
150
151
152    @Override
153    public void writeInitialKey(SecretKey key) throws SecureStorageException {
154        writeKey(key, KeyStoreSecureStorage.ENTRY_INITIAL_KEY);
155    }
156
157    private void writeKey(SecretKey key, String alias) throws SecureStorageException {
158        keyStoreHandler.writeToKeyStore(key, alias, keyStoreHandler.getPassword());
159        try {
160            keyStoreHandler.store();
161        } catch (Exception ex) {
162            throw new SecureStorageException(ex);
163        }
164    }
165
166    @Override
167    public byte[] sign(byte[] signedData) throws SecureStorageException {
168        try {
169            signer.update(signedData);
170            return signer.sign();
171        } catch (SignatureException e) {
172            throw new SecureStorageException(e);
173        }
174    }
175
176    @Override
177    public boolean verify(byte[] signedData, byte[] signature) throws SecureStorageException {
178        try {
179            verifier.update(signedData);
180            return verifier.verify(signature);
181        } catch (SignatureException e) {
182            throw new SecureStorageException(e);
183        }
184    }
185}