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.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 public static final String SIGNATURE_ALGORITHM = "SHA256withRSA"; 046 public static final String HMAC_ALGORITHM = "HmacSHA256"; 047 public static final String JCEKS_KEYSTORE_TYPE = "JCEKS"; 048 049 private KeyStoreHandlerDecorator keyStoreHandler; 050 private Signature verifier; 051 private Signature signer; 052 053 /** 054 * Creates the storage with a keystore handler, initialized to verify only. 055 * 056 * @param keyStoreHandler 057 * Handler of a keystore. 058 * @param privateKey 059 * The private key used to initialize the signer 060 */ 061 public KeyStoreSecureStorage(KeyStoreHandler keyStoreHandler, PrivateKey privateKey) { 062 this(keyStoreHandler, null, privateKey); 063 } 064 065 /** 066 * Creates the storage with a keystore handler, initialized to verify only. 067 * 068 * @param keyStoreHandler 069 * Handler of a keystore. 070 * @param publicKey 071 * The public key used to initialize the verifier 072 */ 073 public KeyStoreSecureStorage(KeyStoreHandler keyStoreHandler, PublicKey publicKey) { 074 this(keyStoreHandler, publicKey, null); 075 } 076 077 /** 078 * Creates the storage with a keystore handler, initialized to verify only. 079 * 080 * @param keyStoreHandler 081 * Handler of a keystore. 082 * @param publicKey 083 * The public key used to initialize the verifier 084 * @param privateKey 085 * The private key used to initialize the signer 086 */ 087 public KeyStoreSecureStorage(KeyStoreHandler keyStoreHandler, PublicKey publicKey, PrivateKey privateKey) { 088 setKeyStoreHandler(keyStoreHandler); 089 090 if (privateKey != null) { 091 try { 092 signer = Signature.getInstance(KeyStoreSecureStorage.SIGNATURE_ALGORITHM); 093 signer.initSign(privateKey); 094 } catch (InvalidKeyException | NoSuchAlgorithmException e) { 095 throw new IllegalArgumentException(e); 096 } 097 } 098 099 if (publicKey != null) { 100 try { 101 verifier = Signature.getInstance(KeyStoreSecureStorage.SIGNATURE_ALGORITHM); 102 verifier.initVerify(publicKey); 103 } catch (InvalidKeyException | NoSuchAlgorithmException e) { 104 throw new IllegalArgumentException(e); 105 } 106 } 107 } 108 109 public void setKeyStoreHandler(KeyStoreHandler keyStoreHandler) { 110 this.keyStoreHandler = new KeyStoreHandlerDecorator(keyStoreHandler); 111 } 112 113 @Override 114 public String getPassword() { 115 return keyStoreHandler.getPassword(); 116 } 117 118 @Override 119 public SecretKey readCurrentKey() throws SecureStorageException { 120 return keyStoreHandler.readSecretKeyFromKeyStore(KeyStoreSecureStorage.ENTRY_CURRENT_KEY); 121 } 122 123 @Override 124 public SecretKey readInitialKey() throws SecureStorageException { 125 return keyStoreHandler.readSecretKeyFromKeyStore(KeyStoreSecureStorage.ENTRY_INITIAL_KEY); 126 } 127 128 @Override 129 public void writeCurrentSignatureKey(SecretKey key) throws SecureStorageException { 130 keyStoreHandler.writeToKeyStore(key, KeyStoreSecureStorage.ENTRY_CURRENT_SIGNATURE, keyStoreHandler.getPassword()); 131 try { 132 keyStoreHandler.store(); 133 } catch (Exception ex) { 134 throw new SecureStorageException(ex); 135 } 136 } 137 138 @Override 139 public void writeCurrentKey(SecretKey key) throws SecureStorageException { 140 writeKey(key, KeyStoreSecureStorage.ENTRY_CURRENT_KEY); 141 } 142 143 144 @Override 145 public void writeInitialKey(SecretKey key) throws SecureStorageException { 146 writeKey(key, KeyStoreSecureStorage.ENTRY_INITIAL_KEY); 147 } 148 149 private void writeKey(SecretKey key, String alias) throws SecureStorageException { 150 keyStoreHandler.writeToKeyStore(key, alias, keyStoreHandler.getPassword()); 151 try { 152 keyStoreHandler.store(); 153 } catch (Exception ex) { 154 throw new SecureStorageException(ex); 155 } 156 } 157 158 @Override 159 public byte[] sign(byte[] signedData) throws SecureStorageException { 160 try { 161 signer.update(signedData); 162 return signer.sign(); 163 } catch (SignatureException e) { 164 throw new SecureStorageException(e); 165 } 166 } 167 168 @Override 169 public boolean verify(byte[] signedData, byte[] signature) throws SecureStorageException { 170 try { 171 verifier.update(signedData); 172 return verifier.verify(signature); 173 } catch (SignatureException e) { 174 throw new SecureStorageException(e); 175 } 176 } 177}