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}