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 2010 Sun Microsystems, Inc. 015 * Portions copyright 2012-2016 ForgeRock AS. 016 */ 017package org.forgerock.opendj.ldap; 018 019import java.io.FileInputStream; 020import java.io.IOException; 021import java.net.Socket; 022import java.security.GeneralSecurityException; 023import java.security.KeyStore; 024import java.security.NoSuchAlgorithmException; 025import java.security.Principal; 026import java.security.PrivateKey; 027import java.security.cert.X509Certificate; 028 029import javax.net.ssl.KeyManager; 030import javax.net.ssl.KeyManagerFactory; 031import javax.net.ssl.SSLEngine; 032import javax.net.ssl.X509ExtendedKeyManager; 033import javax.net.ssl.X509KeyManager; 034 035import org.forgerock.util.Reject; 036 037/** This class contains methods for creating common types of key manager. */ 038public final class KeyManagers { 039 040 private static final String KEY_STORE_PROVIDER = "javax.net.ssl.keyStoreProvider"; 041 private static final String KEY_STORE_TYPE = "javax.net.ssl.keyStoreType"; 042 private static final String KEY_STORE_FILE = "javax.net.ssl.keyStore"; 043 private static final String KEY_STORE_PASSWORD = "javax.net.ssl.keyStorePassword"; 044 private static volatile X509KeyManager jvmKeyManager; 045 046 /** 047 * This class implements an X.509 key manager that will be used to wrap an 048 * existing key manager and makes it possible to configure which 049 * certificate(s) should be used for client and/or server operations. The 050 * certificate selection will be based on the alias (also called the 051 * nickname) of the certificate. 052 */ 053 private static final class SelectCertificate extends X509ExtendedKeyManager { 054 private final String alias; 055 private final X509KeyManager keyManager; 056 057 private SelectCertificate(final X509KeyManager keyManager, final String alias) { 058 this.keyManager = keyManager; 059 this.alias = alias; 060 } 061 062 @Override 063 public String chooseClientAlias(final String[] keyType, final Principal[] issuers, 064 final Socket socket) { 065 for (final String type : keyType) { 066 final String[] clientAliases = keyManager.getClientAliases(type, issuers); 067 if (clientAliases != null) { 068 for (final String clientAlias : clientAliases) { 069 if (clientAlias.equals(alias)) { 070 return alias; 071 } 072 } 073 } 074 } 075 076 return null; 077 } 078 079 @Override 080 public String chooseEngineClientAlias(final String[] keyType, final Principal[] issuers, 081 final SSLEngine engine) { 082 for (final String type : keyType) { 083 final String[] clientAliases = keyManager.getClientAliases(type, issuers); 084 if (clientAliases != null) { 085 for (final String clientAlias : clientAliases) { 086 if (clientAlias.equals(alias)) { 087 return alias; 088 } 089 } 090 } 091 } 092 093 return null; 094 } 095 096 @Override 097 public String chooseEngineServerAlias(final String keyType, final Principal[] issuers, 098 final SSLEngine engine) { 099 final String[] serverAliases = keyManager.getServerAliases(keyType, issuers); 100 if (serverAliases != null) { 101 for (final String serverAlias : serverAliases) { 102 if (serverAlias.equalsIgnoreCase(alias)) { 103 return serverAlias; 104 } 105 } 106 } 107 108 return null; 109 } 110 111 @Override 112 public String chooseServerAlias(final String keyType, final Principal[] issuers, 113 final Socket socket) { 114 final String[] serverAliases = keyManager.getServerAliases(keyType, issuers); 115 if (serverAliases != null) { 116 for (final String serverAlias : serverAliases) { 117 if (serverAlias.equals(alias)) { 118 return alias; 119 } 120 } 121 } 122 123 return null; 124 } 125 126 @Override 127 public X509Certificate[] getCertificateChain(final String alias) { 128 return keyManager.getCertificateChain(alias); 129 } 130 131 @Override 132 public String[] getClientAliases(final String keyType, final Principal[] issuers) { 133 return keyManager.getClientAliases(keyType, issuers); 134 } 135 136 @Override 137 public PrivateKey getPrivateKey(final String alias) { 138 return keyManager.getPrivateKey(alias); 139 } 140 141 @Override 142 public String[] getServerAliases(final String keyType, final Principal[] issuers) { 143 return keyManager.getServerAliases(keyType, issuers); 144 } 145 } 146 147 /** 148 * Creates a new {@code X509KeyManager} which will use the named key store 149 * file for retrieving certificates. It will use the default key store 150 * format for the JVM (e.g. {@code JKS}) and will not use a password to open 151 * the key store. 152 * 153 * @param file 154 * The key store file name. 155 * @return A new {@code X509KeyManager} which will use the named key store 156 * file for retrieving certificates. 157 * @throws GeneralSecurityException 158 * If the key store could not be loaded, perhaps due to 159 * incorrect format, or missing algorithms. 160 * @throws IOException 161 * If the key store file could not be found or could not be 162 * read. 163 * @throws NullPointerException 164 * If {@code file} was {@code null}. 165 */ 166 public static X509KeyManager useKeyStoreFile(final String file) 167 throws GeneralSecurityException, IOException { 168 return useKeyStoreFile(file, null, null); 169 } 170 171 /** 172 * Creates a new {@code X509KeyManager} which will use the named key store 173 * file for retrieving certificates. It will use the provided key store 174 * format and password. 175 * 176 * @param file 177 * The key store file name. 178 * @param password 179 * The key store password, which may be {@code null}. 180 * @param format 181 * The key store format, which may be {@code null} to indicate 182 * that the default key store format for the JVM (e.g. 183 * {@code JKS}) should be used. 184 * @return A new {@code X509KeyManager} which will use the named key store 185 * file for retrieving certificates. 186 * @throws GeneralSecurityException 187 * If the key store could not be loaded, perhaps due to 188 * incorrect format, or missing algorithms. 189 * @throws IOException 190 * If the key store file could not be found or could not be 191 * read. 192 * @throws NullPointerException 193 * If {@code file} was {@code null}. 194 */ 195 public static X509KeyManager useKeyStoreFile(final String file, final char[] password, 196 final String format) throws GeneralSecurityException, IOException { 197 return useKeyStoreFile(file, password, format, null); 198 } 199 200 /** 201 * Creates a new {@code X509KeyManager} which will use the named key store 202 * file for retrieving certificates. It will use the provided key store 203 * format and password. 204 * 205 * @param keyStoreFile 206 * The key store file name. 207 * @param password 208 * The key store password, which may be {@code null}. 209 * @param format 210 * The key store format, which may be {@code null} to indicate that the default key store format for the 211 * JVM (e.g. {@code JKS}) should be used. 212 * @param provider 213 * The key store provider, which may be {@code null} to indicate that the default key store provider for 214 * the JVM should be used. 215 * @return A new {@code X509KeyManager} which will use the named key store file for retrieving certificates. 216 * @throws GeneralSecurityException 217 * If the key store could not be loaded, perhaps due to incorrect format, or missing algorithms. 218 * @throws IOException 219 * If the key store file could not be found or could not be read. 220 * @throws NullPointerException 221 * If {@code file} was {@code null}. 222 */ 223 public static X509KeyManager useKeyStoreFile(final String keyStoreFile, final char[] password, 224 final String format, String provider) throws GeneralSecurityException, IOException { 225 Reject.ifNull(keyStoreFile); 226 227 final String keyStoreFormat = format != null ? format : KeyStore.getDefaultType(); 228 final KeyStore keyStore = provider != null 229 ? KeyStore.getInstance(keyStoreFormat, provider) 230 : KeyStore.getInstance(keyStoreFormat); 231 232 try (FileInputStream fis = new FileInputStream(keyStoreFile)) { 233 keyStore.load(fis, password); 234 } 235 236 return getX509KeyManager(keyStore, password); 237 } 238 239 /** 240 * Creates a new {@code X509KeyManager} which will use a PKCS#11 token for 241 * retrieving certificates. 242 * 243 * @param password 244 * The password to use for accessing the PKCS#11 token, which may 245 * be {@code null} if no password is required. 246 * @return A new {@code X509KeyManager} which will use a PKCS#11 token for 247 * retrieving certificates. 248 * @throws GeneralSecurityException 249 * If the PKCS#11 token could not be accessed, perhaps due to 250 * incorrect password, or missing algorithms. 251 * @throws IOException 252 * If the PKCS#11 token could not be found or could not be read. 253 */ 254 public static X509KeyManager usePKCS11Token(final char[] password) 255 throws GeneralSecurityException, IOException { 256 final KeyStore keyStore = KeyStore.getInstance("PKCS11"); 257 keyStore.load(null, password); 258 return getX509KeyManager(keyStore, password); 259 } 260 261 private static X509KeyManager getX509KeyManager(final KeyStore keyStore, final char[] password) 262 throws GeneralSecurityException { 263 final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 264 kmf.init(keyStore, password); 265 266 for (final KeyManager km : kmf.getKeyManagers()) { 267 if (km instanceof X509KeyManager) { 268 return (X509KeyManager) km; 269 } 270 } 271 throw new NoSuchAlgorithmException(); 272 } 273 274 /** 275 * Creates a new {@code X509KeyManager} which will use the JVM's default keystore for retrieving certificates. 276 * 277 * @return A new {@code X509KeyManager} which will use the JVM's default keystore for retrieving certificates or 278 * {@code null} if the necessary JVM settings are missing. 279 * @throws GeneralSecurityException 280 * If the key store could not be loaded, perhaps due to incorrect format, or missing algorithms. 281 * @throws IOException 282 * If the key store file could not be found or could not be read. 283 */ 284 public static X509KeyManager useJvmDefaultKeyStore() throws GeneralSecurityException, IOException { 285 if (jvmKeyManager == null) { 286 final String keyStoreFile = System.getProperty(KEY_STORE_FILE); 287 if (keyStoreFile != null) { 288 synchronized (KeyManagers.class) { 289 if (jvmKeyManager == null) { 290 final String keyStoreProvider = System.getProperty(KEY_STORE_PROVIDER); 291 final String keyStoreType = System.getProperty(KEY_STORE_TYPE, KeyStore.getDefaultType()); 292 final String keyStorePassword = System.getProperty(KEY_STORE_PASSWORD); 293 294 jvmKeyManager = useKeyStoreFile(keyStoreFile, 295 keyStorePassword != null ? keyStorePassword.toCharArray() : null, 296 keyStoreType, keyStoreProvider); 297 } 298 } 299 } 300 } 301 302 return jvmKeyManager; 303 } 304 305 /** 306 * Returns a new {@code X509KeyManager} which selects the named certificate 307 * from the provided {@code X509KeyManager}. 308 * 309 * @param alias 310 * The nickname of the certificate that should be selected for 311 * operations involving this key manager. 312 * @param keyManager 313 * The key manager to be filtered. 314 * @return The filtered key manager. 315 * @throws NullPointerException 316 * If {@code keyManager} or {@code alias} was {@code null}. 317 */ 318 public static X509KeyManager useSingleCertificate(final String alias, 319 final X509KeyManager keyManager) { 320 Reject.ifNull(alias, keyManager); 321 return new SelectCertificate(keyManager, alias); 322 } 323 324 /** Prevent instantiation. */ 325 private KeyManagers() { 326 // Nothing to do. 327 } 328}