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.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 /** 085 * Get the public key with the given alias. 086 * @param alias The alias. 087 * @return The key. 088 * @throws SecureStorageException If the key could not be read. 089 */ 090 public PublicKey readPublicKeyFromKeyStore(String alias) throws SecureStorageException { 091 try { 092 KeyStore store = getStore(); 093 Certificate certificate = store.getCertificate(alias); 094 return certificate.getPublicKey(); 095 } catch (KeyStoreException ex) { 096 throw new SecureStorageException("Error when reading public key: " + alias, ex); 097 } 098 } 099 100 /** 101 * Get a private key for the alias using the default password from {@link #getPassword()}. 102 * @param alias The alias. 103 * @return The key. 104 * @throws SecureStorageException If the key could not be read. 105 */ 106 public PrivateKey readPrivateKeyFromKeyStore(String alias) throws SecureStorageException { 107 return readPrivateKeyFromKeyStore(alias, getPassword()); 108 } 109 110 /** 111 * Get the private key with the given alias. 112 * @param alias The alias. 113 * @param password The password to use to access the keystore. 114 * @return The key. 115 * @throws SecureStorageException If the key could not be read. 116 */ 117 public PrivateKey readPrivateKeyFromKeyStore(String alias, String password) throws SecureStorageException { 118 try { 119 KeyStore store = getStore(); 120 KeyStore.ProtectionParameter params = password != null 121 ? new KeyStore.PasswordProtection(password.toCharArray()) 122 : null; 123 KeyStore.PrivateKeyEntry keyentry = (KeyStore.PrivateKeyEntry) store.getEntry(alias, params); 124 return keyentry != null ? keyentry.getPrivateKey() : null; 125 } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException ex) { 126 throw new SecureStorageException(ex); 127 } 128 } 129 130 /** 131 * Get the secret key with the given alias using the default password from {@link #getPassword()}. 132 * @param alias The alias. 133 * @return The key. 134 * @throws SecureStorageException If the key could not be read. 135 */ 136 public SecretKey readSecretKeyFromKeyStore(String alias) throws SecureStorageException { 137 return readSecretKeyFromKeyStore(alias, getPassword()); 138 } 139 140 /** 141 * Get the secret key with the given alias. 142 * @param alias The alias. 143 * @param password The password to use to access the keystore. 144 * @return The key. 145 * @throws SecureStorageException If the key could not be read. 146 */ 147 public SecretKey readSecretKeyFromKeyStore(String alias, String password) throws SecureStorageException { 148 try { 149 KeyStore store = getStore(); 150 KeyStore.ProtectionParameter params = new KeyStore.PasswordProtection(password.toCharArray()); 151 KeyStore.SecretKeyEntry keyentry = (KeyStore.SecretKeyEntry) store.getEntry(alias, params); 152 return keyentry != null ? keyentry.getSecretKey() : null; 153 } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) { 154 throw new SecureStorageException(e); 155 } 156 } 157 158 @Override 159 public KeyStore getStore() { 160 return delegate.getStore(); 161 } 162 163 @Override 164 public void setStore(KeyStore keystore) throws Exception { 165 delegate.setStore(keystore); 166 } 167 168 @Override 169 public String getPassword() { 170 return delegate.getPassword(); 171 } 172 173 @Override 174 public String getLocation() { 175 return delegate.getLocation(); 176 } 177 178 @Override 179 public String getType() { 180 return delegate.getType(); 181 } 182 183 @Override 184 public void store() throws Exception { 185 delegate.store(); 186 } 187 188}