001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2008-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2015 ForgeRock AS. 026 */ 027package org.opends.server.util; 028 029import org.forgerock.i18n.slf4j.LocalizedLogger; 030 031import java.net.Socket; 032import java.security.Principal; 033import java.security.PrivateKey; 034import java.security.cert.X509Certificate; 035import javax.net.ssl.KeyManager; 036import javax.net.ssl.SSLEngine; 037import javax.net.ssl.X509ExtendedKeyManager; 038import javax.net.ssl.X509KeyManager; 039 040import static org.opends.messages.ExtensionMessages.INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS; 041 042/** 043 * This class implements an X.509 key manager that will be used to wrap an 044 * existing key manager and makes it possible to configure which certificate(s) 045 * should be used for client and/or server operations. The certificate 046 * selection will be based on the alias (also called the nickname) of the 047 * certificate. 048 */ 049@org.opends.server.types.PublicAPI( 050 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 051 mayInstantiate=true, 052 mayExtend=false, 053 mayInvoke=true) 054public final class SelectableCertificateKeyManager 055 extends X509ExtendedKeyManager 056{ 057 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 058 059 /** The alias of the certificate that should be selected from the key manager. */ 060 private final String alias; 061 062 /** The key manager that is wrapped by this key manager. */ 063 private final X509KeyManager keyManager; 064 065 /** Provide additional troubleshooting aid to localize a misconfigured SSL connection. */ 066 private final String componentName; 067 068 069 /** 070 * Creates a new instance of this key manager that will wrap the provided key 071 * manager and use the certificate with the specified alias. 072 * 073 * @param keyManager The key manager to be wrapped by this key manager. 074 * @param alias The nickname of the certificate that should be 075 * selected for operations involving this key manager. 076 * @param componentName Name of the component to which is associated this key manager 077 */ 078 public SelectableCertificateKeyManager(X509KeyManager keyManager, 079 String alias, String componentName) 080 { 081 super(); 082 083 this.keyManager = keyManager; 084 this.alias = alias; 085 this.componentName = componentName; 086 } 087 088 /** 089 * Creates a new instance of this key manager that will wrap the provided key 090 * manager and use the certificate with the specified alias. 091 * 092 * @param keyManager The key manager to be wrapped by this key manager. 093 * @param alias The nickname of the certificate that should be 094 * selected for operations involving this key manager. 095 */ 096 public SelectableCertificateKeyManager(X509KeyManager keyManager, 097 String alias) 098 { 099 this(keyManager, alias, "[unknown]"); 100 } 101 102 103 /** 104 * Chooses the alias of the client certificate that should be used based on 105 * the provided criteria. This will either return the preferred alias 106 * configured for this key manager, or {@code null} if no client certificate 107 * with that alias is configured in the underlying key manager. 108 * 109 * @param keyType The set of key algorithm names, ordered with the most 110 * preferred key type first. 111 * @param issuers The list of acceptable issuer subject names, or 112 * {@code null} if any issuer may be used. 113 * @param socket The socket to be used for this connection. 114 * 115 * @return The alias configured for this key manager, or {@code null} if no 116 * such client certificate is available with that alias. 117 */ 118 public String chooseClientAlias(String[] keyType, Principal[] issuers, 119 Socket socket) 120 { 121 for (String type : keyType) 122 { 123 String[] clientAliases = keyManager.getClientAliases(type, issuers); 124 if (clientAliases != null) 125 { 126 for (String clientAlias : clientAliases) 127 { 128 if (clientAlias.equals(alias)) 129 { 130 return alias; 131 } 132 } 133 } 134 } 135 logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, componentName, keyType, alias); 136 return null; 137 } 138 139 140 141 /** 142 * Chooses the alias of the client certificate that should be used based on 143 * the provided criteria. This will either return the preferred alias 144 * configured for this key manager, or {@code null} if no client certificate 145 * with that alias is configured in the underlying key manager. 146 * 147 * @param keyType The set of key algorithm names, ordered with the most 148 * preferred key type first. 149 * @param issuers The list of acceptable issuer subject names, or 150 * {@code null} if any issuer may be used. 151 * @param engine The SSL engine to be used for this connection. 152 * 153 * @return The alias configured for this key manager, or {@code null} if no 154 * such client certificate is available with that alias. 155 */ 156 @Override 157 public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, 158 SSLEngine engine) 159 { 160 return chooseClientAlias(keyType, issuers, null); 161 } 162 163 164 165 /** 166 * Chooses the alias of the server certificate that should be used based on 167 * the provided criteria. This will either return the preferred alias 168 * configured for this key manager, or {@code null} if no server certificate 169 * with that alias is configured in the underlying key manager. 170 * 171 * @param keyType The public key type for the certificate. 172 * @param issuers The list of acceptable issuer subject names, or 173 * {@code null} if any issuer may be used. 174 * @param socket The socket to be used for this connection. 175 * 176 * @return The alias configured for this key manager, or {@code null} if no 177 * such server certificate is available with that alias. 178 */ 179 public String chooseServerAlias(String keyType, Principal[] issuers, 180 Socket socket) 181 { 182 String[] serverAliases = keyManager.getServerAliases(keyType, issuers); 183 if (serverAliases != null) 184 { 185 for (String serverAlias : serverAliases) 186 { 187 if (serverAlias.equals(alias)) 188 { 189 return alias; 190 } 191 } 192 } 193 194 logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, componentName, keyType, alias); 195 return null; 196 } 197 198 199 200 /** 201 * Chooses the alias of the server certificate that should be used based on 202 * the provided criteria. This will either return the preferred alias 203 * configured for this key manager, or {@code null} if no server certificate 204 * with that alias is configured in the underlying key manager. 205 * Note that the returned alias can be transformed in lowercase, depending 206 * on the KeyStore implementation. It is recommended not to use aliases in a 207 * KeyStore that only differ in case. 208 * 209 * @param keyType The public key type for the certificate. 210 * @param issuers The list of acceptable issuer subject names, or 211 * {@code null} if any issuer may be used. 212 * @param engine The SSL engine to be used for this connection. 213 * 214 * @return The alias configured for this key manager, or {@code null} if no 215 * such server certificate is available with that alias. 216 */ 217 @Override 218 public String chooseEngineServerAlias(String keyType, Principal[] issuers, 219 SSLEngine engine) 220 { 221 String[] serverAliases = keyManager.getServerAliases(keyType, issuers); 222 if (serverAliases != null) 223 { 224 for (String serverAlias : serverAliases) 225 { 226 if (serverAlias.equalsIgnoreCase(alias)) 227 { 228 return serverAlias; 229 } 230 } 231 } 232 233 logger.warn(INFO_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, componentName, keyType, alias); 234 return null; 235 } 236 237 238 239 /** 240 * Retrieves the certificate chain for the provided alias. 241 * 242 * @param alias The alias for the certificate chain to retrieve. 243 * 244 * @return The certificate chain for the provided alias, or {@code null} if 245 * no certificate is associated with the provided alias. 246 */ 247 public X509Certificate[] getCertificateChain(String alias) 248 { 249 return keyManager.getCertificateChain(alias); 250 } 251 252 253 254 /** 255 * Retrieves the set of certificate aliases that may be used for client 256 * authentication with the given public key type and set of issuers. 257 * 258 * @param keyType The public key type for the aliases to retrieve. 259 * @param issuers The list of acceptable issuer subject names, or 260 * {@code null} if any issuer may be used. 261 * 262 * @return The set of certificate aliases that may be used for client 263 * authentication with the given public key type and set of issuers, 264 * or {@code null} if there were none. 265 */ 266 public String[] getClientAliases(String keyType, Principal[] issuers) 267 { 268 return keyManager.getClientAliases(keyType, issuers); 269 } 270 271 272 273 /** 274 * Retrieves the private key for the provided alias. 275 * 276 * @param alias The alias for the private key to return. 277 * 278 * @return The private key for the provided alias, or {@code null} if no 279 * private key is available for the provided alias. 280 */ 281 public PrivateKey getPrivateKey(String alias) 282 { 283 return keyManager.getPrivateKey(alias); 284 } 285 286 287 288 /** 289 * Retrieves the set of certificate aliases that may be used for server 290 * authentication with the given public key type and set of issuers. 291 * 292 * @param keyType The public key type for the aliases to retrieve. 293 * @param issuers The list of acceptable issuer subject names, or 294 * {@code null} if any issuer may be used. 295 * 296 * @return The set of certificate aliases that may be used for server 297 * authentication with the given public key type and set of issuers, 298 * or {@code null} if there were none. 299 */ 300 public String[] getServerAliases(String keyType, Principal[] issuers) 301 { 302 return keyManager.getServerAliases(keyType, issuers); 303 } 304 305 306 307 /** 308 * Wraps the provided set of key managers in selectable certificate key 309 * managers using the provided alias. 310 * 311 * @param keyManagers The set of key managers to be wrapped. 312 * @param alias The alias to use for selecting the desired 313 * certificate. 314 * @param componentName Name of the component to which is associated this key manager 315 * 316 * @return A key manager array 317 */ 318 public static X509ExtendedKeyManager[] wrap(KeyManager[] keyManagers, 319 String alias, String componentName) 320 { 321 X509ExtendedKeyManager[] newKeyManagers = 322 new X509ExtendedKeyManager[keyManagers.length]; 323 for (int i=0; i < keyManagers.length; i++) 324 { 325 newKeyManagers[i] = new SelectableCertificateKeyManager( 326 (X509KeyManager) keyManagers[i], alias, componentName); 327 } 328 329 return newKeyManagers; 330 } 331 332 /** 333 * Wraps the provided set of key managers in selectable certificate key 334 * managers using the provided alias. 335 * 336 * @param keyManagers The set of key managers to be wrapped. 337 * @param alias The alias to use for selecting the desired 338 * certificate. 339 * 340 * @return A key manager array 341 */ 342 public static X509ExtendedKeyManager[] wrap(KeyManager[] keyManagers, String alias) { 343 return wrap(keyManagers, alias, "[unknown]"); 344 } 345}