001/* 002 * Copyright 2008-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.util.ssl; 022 023 024 025import java.io.File; 026import java.io.FileInputStream; 027import java.io.Serializable; 028import java.security.KeyStore; 029import java.security.KeyStoreException; 030import javax.net.ssl.KeyManager; 031import javax.net.ssl.KeyManagerFactory; 032 033import com.unboundid.util.Debug; 034import com.unboundid.util.NotMutable; 035import com.unboundid.util.StaticUtils; 036import com.unboundid.util.ThreadSafety; 037import com.unboundid.util.ThreadSafetyLevel; 038import com.unboundid.util.Validator; 039 040import static com.unboundid.util.ssl.SSLMessages.*; 041 042 043 044/** 045 * This class provides an SSL key manager that may be used to retrieve 046 * certificates from a key store file. By default it will use the default key 047 * store format for the JVM (e.g., "JKS" for Sun-provided Java implementations), 048 * but alternate formats like PKCS12 may be used. 049 */ 050@NotMutable() 051@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 052public final class KeyStoreKeyManager 053 extends WrapperKeyManager 054 implements Serializable 055{ 056 /** 057 * The serial version UID for this serializable class. 058 */ 059 private static final long serialVersionUID = -5202641256733094253L; 060 061 062 063 // The path to the key store file. 064 private final String keyStoreFile; 065 066 // The format to use for the key store file. 067 private final String keyStoreFormat; 068 069 070 071 /** 072 * Creates a new instance of this key store key manager that provides the 073 * ability to retrieve certificates from the specified key store file. It 074 * will use the default key store format. 075 * 076 * @param keyStoreFile The path to the key store file to use. It must not 077 * be {@code null}. 078 * @param keyStorePIN The PIN to use to access the contents of the key 079 * store. It may be {@code null} if no PIN is required. 080 * 081 * @throws KeyStoreException If a problem occurs while initializing this key 082 * manager. 083 */ 084 public KeyStoreKeyManager(final File keyStoreFile, final char[] keyStorePIN) 085 throws KeyStoreException 086 { 087 this(keyStoreFile.getAbsolutePath(), keyStorePIN, null, null); 088 } 089 090 091 092 /** 093 * Creates a new instance of this key store key manager that provides the 094 * ability to retrieve certificates from the specified key store file. It 095 * will use the default key store format. 096 * 097 * @param keyStoreFile The path to the key store file to use. It must not 098 * be {@code null}. 099 * @param keyStorePIN The PIN to use to access the contents of the key 100 * store. It may be {@code null} if no PIN is required. 101 * 102 * @throws KeyStoreException If a problem occurs while initializing this key 103 * manager. 104 */ 105 public KeyStoreKeyManager(final String keyStoreFile, final char[] keyStorePIN) 106 throws KeyStoreException 107 { 108 this(keyStoreFile, keyStorePIN, null, null); 109 } 110 111 112 113 /** 114 * Creates a new instance of this key store key manager that provides the 115 * ability to retrieve certificates from the specified key store file. 116 * 117 * @param keyStoreFile The path to the key store file to use. It must 118 * not be {@code null}. 119 * @param keyStorePIN The PIN to use to access the contents of the key 120 * store. It may be {@code null} if no PIN is 121 * required. 122 * @param keyStoreFormat The format to use for the key store. It may be 123 * {@code null} if the default format should be 124 * used. 125 * @param certificateAlias The nickname of the certificate that should be 126 * selected. It may be {@code null} if any 127 * acceptable certificate found in the keystore may 128 * be used. 129 * 130 * @throws KeyStoreException If a problem occurs while initializing this key 131 * manager. 132 */ 133 public KeyStoreKeyManager(final File keyStoreFile, final char[] keyStorePIN, 134 final String keyStoreFormat, 135 final String certificateAlias) 136 throws KeyStoreException 137 { 138 this(keyStoreFile.getAbsolutePath(), keyStorePIN, keyStoreFormat, 139 certificateAlias); 140 } 141 142 143 144 /** 145 * Creates a new instance of this key store key manager that provides the 146 * ability to retrieve certificates from the specified key store file. 147 * 148 * @param keyStoreFile The path to the key store file to use. It must 149 * not be {@code null}. 150 * @param keyStorePIN The PIN to use to access the contents of the key 151 * store. It may be {@code null} if no PIN is 152 * required. 153 * @param keyStoreFormat The format to use for the key store. It may be 154 * {@code null} if the default format should be 155 * used. 156 * @param certificateAlias The nickname of the certificate that should be 157 * selected. It may be {@code null} if any 158 * acceptable certificate found in the keystore may 159 * be used. 160 * 161 * @throws KeyStoreException If a problem occurs while initializing this key 162 * manager. 163 */ 164 public KeyStoreKeyManager(final String keyStoreFile, final char[] keyStorePIN, 165 final String keyStoreFormat, 166 final String certificateAlias) 167 throws KeyStoreException 168 { 169 super(getKeyManagers(keyStoreFile, keyStorePIN, keyStoreFormat), 170 certificateAlias); 171 172 this.keyStoreFile = keyStoreFile; 173 174 if (keyStoreFormat == null) 175 { 176 this.keyStoreFormat = KeyStore.getDefaultType(); 177 } 178 else 179 { 180 this.keyStoreFormat = keyStoreFormat; 181 } 182 } 183 184 185 186 /** 187 * Retrieves the set of key managers that will be wrapped by this key manager. 188 * 189 * @param keyStoreFile The path to the key store file to use. It must 190 * not be {@code null}. 191 * @param keyStorePIN The PIN to use to access the contents of the key 192 * store. It may be {@code null} if no PIN is 193 * required. 194 * @param keyStoreFormat The format to use for the key store. It may be 195 * {@code null} if the default format should be 196 * used. 197 * 198 * @return The set of key managers that will be wrapped by this key manager. 199 * 200 * @throws KeyStoreException If a problem occurs while initializing this key 201 * manager. 202 */ 203 private static KeyManager[] getKeyManagers(final String keyStoreFile, 204 final char[] keyStorePIN, 205 final String keyStoreFormat) 206 throws KeyStoreException 207 { 208 Validator.ensureNotNull(keyStoreFile); 209 210 String type = keyStoreFormat; 211 if (type == null) 212 { 213 type = KeyStore.getDefaultType(); 214 } 215 216 final File f = new File(keyStoreFile); 217 if (! f.exists()) 218 { 219 throw new KeyStoreException(ERR_KEYSTORE_NO_SUCH_FILE.get(keyStoreFile)); 220 } 221 222 final KeyStore ks = KeyStore.getInstance(type); 223 FileInputStream inputStream = null; 224 try 225 { 226 inputStream = new FileInputStream(f); 227 ks.load(inputStream, keyStorePIN); 228 } 229 catch (final Exception e) 230 { 231 Debug.debugException(e); 232 233 throw new KeyStoreException( 234 ERR_KEYSTORE_CANNOT_LOAD.get(keyStoreFile, type, String.valueOf(e)), 235 e); 236 } 237 finally 238 { 239 if (inputStream != null) 240 { 241 try 242 { 243 inputStream.close(); 244 } 245 catch (final Exception e) 246 { 247 Debug.debugException(e); 248 } 249 } 250 } 251 252 try 253 { 254 final KeyManagerFactory factory = KeyManagerFactory.getInstance( 255 KeyManagerFactory.getDefaultAlgorithm()); 256 factory.init(ks, keyStorePIN); 257 return factory.getKeyManagers(); 258 } 259 catch (final Exception e) 260 { 261 Debug.debugException(e); 262 263 throw new KeyStoreException( 264 ERR_KEYSTORE_CANNOT_GET_KEY_MANAGERS.get(keyStoreFile, 265 keyStoreFormat, StaticUtils.getExceptionMessage(e)), 266 e); 267 } 268 } 269 270 271 272 /** 273 * Retrieves the path to the key store file to use. 274 * 275 * @return The path to the key store file to use. 276 */ 277 public String getKeyStoreFile() 278 { 279 return keyStoreFile; 280 } 281 282 283 284 /** 285 * Retrieves the name of the key store file format. 286 * 287 * @return The name of the key store file format. 288 */ 289 public String getKeyStoreFormat() 290 { 291 return keyStoreFormat; 292 } 293}