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 java.util.Arrays; 036import java.util.SortedSet; 037import javax.net.ssl.KeyManager; 038import javax.net.ssl.SSLEngine; 039import javax.net.ssl.X509ExtendedKeyManager; 040import javax.net.ssl.X509KeyManager; 041 042import static org.opends.messages.ExtensionMessages.INFO_MISSING_KEY_TYPE_IN_ALIASES; 043 044/** 045 * This class implements an X.509 key manager that will be used to wrap an 046 * existing key manager and makes it possible to configure which certificate(s) 047 * should be used for client and/or server operations. The certificate 048 * selection will be based on the alias (also called the nickname) of the 049 * certificate. 050 */ 051@org.opends.server.types.PublicAPI( 052 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 053 mayInstantiate=true, 054 mayExtend=false, 055 mayInvoke=true) 056public final class SelectableCertificateKeyManager 057 extends X509ExtendedKeyManager 058{ 059 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 060 061 /** The aliases of the certificates that should be selected from the key manager. */ 062 private final SortedSet<String> aliases; 063 064 /** The key manager that is wrapped by this key manager. */ 065 private final X509KeyManager keyManager; 066 067 /** Provide additional troubleshooting aid to localize a misconfigured SSL connection. */ 068 private final String componentName; 069 070 private SelectableCertificateKeyManager(X509KeyManager keyManager, SortedSet<String> aliases, String componentName) 071 { 072 super(); 073 this.keyManager = keyManager; 074 this.aliases = aliases; 075 this.componentName = componentName; 076 } 077 078 private SelectableCertificateKeyManager(X509KeyManager keyManager, String alias) 079 { 080 super(); 081 this.keyManager = keyManager; 082 this.aliases = CollectionUtils.newTreeSet(alias); 083 this.componentName = "[unkown]"; 084 } 085 086 /** 087 * Chooses the alias of the client certificate that should be used based on 088 * the provided criteria. This will either return the preferred alias 089 * configured for this key manager, or {@code null} if no client certificate 090 * with that alias is configured in the underlying key manager. 091 * 092 * @param keyType The set of key algorithm names, ordered with the most 093 * preferred key type first. 094 * @param issuers The list of acceptable issuer subject names, or 095 * {@code null} if any issuer may be used. 096 * @param socket The socket to be used for this connection. 097 * 098 * @return The alias configured for this key manager, or {@code null} if no 099 * such client certificate is available with that alias. 100 */ 101 @Override 102 public String chooseClientAlias(String[] keyType, Principal[] issuers, 103 Socket socket) 104 { 105 return findClientAlias(keyType, issuers); 106 } 107 108 private String findClientAlias(String keyType[], Principal[] issuers) 109 { 110 for(String type : keyType) 111 { 112 final String clientAlias = findAlias(keyManager.getClientAliases(type, issuers)); 113 if ( clientAlias != null ) 114 { 115 return clientAlias; 116 } 117 } 118 logger.debug(INFO_MISSING_KEY_TYPE_IN_ALIASES, componentName, aliases.toString(), Arrays.toString(keyType)); 119 return null; 120 } 121 122 private String findAlias(String[] candidates) 123 { 124 if (candidates == null) 125 { 126 return null; 127 } 128 for (String alias : candidates) 129 { 130 for (String certificateAlias : aliases) 131 { 132 if (certificateAlias.equalsIgnoreCase(alias)) 133 { 134 return alias; 135 } 136 } 137 } 138 return null; 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 findClientAlias(keyType, issuers); 161 } 162 163 /** 164 * Chooses the alias of the server certificate that should be used based on 165 * the provided criteria. This will either return the preferred alias 166 * configured for this key manager, or {@code null} if no server certificate 167 * with that alias is configured in the underlying key manager. 168 * 169 * @param keyType The public key type for the certificate. 170 * @param issuers The list of acceptable issuer subject names, or 171 * {@code null} if any issuer may be used. 172 * @param socket The socket to be used for this connection. 173 * 174 * @return The alias configured for this key manager, or {@code null} if no 175 * such server certificate is available with that alias. 176 */ 177 @Override 178 public String chooseServerAlias(String keyType, Principal[] issuers, 179 Socket socket) 180 { 181 return findServerAlias(new String[] { keyType }, issuers); 182 } 183 184 private String findServerAlias(String keyType[], Principal[] issuers) 185 { 186 for (String type : keyType) 187 { 188 final String serverAlias = findAlias(keyManager.getServerAliases(type, issuers)); 189 if (serverAlias != null) 190 { 191 return serverAlias; 192 } 193 } 194 logger.debug(INFO_MISSING_KEY_TYPE_IN_ALIASES, componentName, aliases.toString(), Arrays.toString(keyType)); 195 return null; 196 } 197 198 /** 199 * Chooses the alias of the server certificate that should be used based on 200 * the provided criteria. This will either return the preferred alias 201 * configured for this key manager, or {@code null} if no server certificate 202 * with that alias is configured in the underlying key manager. 203 * Note that the returned alias can be transformed in lowercase, depending 204 * on the KeyStore implementation. It is recommended not to use aliases in a 205 * KeyStore that only differ in case. 206 * 207 * @param keyType The public key type for the certificate. 208 * @param issuers The list of acceptable issuer subject names, or 209 * {@code null} if any issuer may be used. 210 * @param engine The SSL engine to be used for this connection. 211 * 212 * @return The alias configured for this key manager, or {@code null} if no 213 * such server certificate is available with that alias. 214 */ 215 @Override 216 public String chooseEngineServerAlias(String keyType, Principal[] issuers, 217 SSLEngine engine) 218 { 219 return findServerAlias(new String[] { keyType }, issuers); 220 } 221 222 /** 223 * Retrieves the certificate chain for the provided alias. 224 * 225 * @param alias The alias for the certificate chain to retrieve. 226 * 227 * @return The certificate chain for the provided alias, or {@code null} if 228 * no certificate is associated with the provided alias. 229 */ 230 @Override 231 public X509Certificate[] getCertificateChain(String alias) 232 { 233 return keyManager.getCertificateChain(alias); 234 } 235 236 /** 237 * Retrieves the set of certificate aliases that may be used for client 238 * authentication with the given public key type and set of issuers. 239 * 240 * @param keyType The public key type for the aliases to retrieve. 241 * @param issuers The list of acceptable issuer subject names, or 242 * {@code null} if any issuer may be used. 243 * 244 * @return The set of certificate aliases that may be used for client 245 * authentication with the given public key type and set of issuers, 246 * or {@code null} if there were none. 247 */ 248 @Override 249 public String[] getClientAliases(String keyType, Principal[] issuers) 250 { 251 return keyManager.getClientAliases(keyType, issuers); 252 } 253 254 /** 255 * Retrieves the private key for the provided alias. 256 * 257 * @param alias The alias for the private key to return. 258 * 259 * @return The private key for the provided alias, or {@code null} if no 260 * private key is available for the provided alias. 261 */ 262 @Override 263 public PrivateKey getPrivateKey(String alias) 264 { 265 return keyManager.getPrivateKey(alias); 266 } 267 268 /** 269 * Retrieves the set of certificate aliases that may be used for server 270 * authentication with the given public key type and set of issuers. 271 * 272 * @param keyType The public key type for the aliases to retrieve. 273 * @param issuers The list of acceptable issuer subject names, or 274 * {@code null} if any issuer may be used. 275 * 276 * @return The set of certificate aliases that may be used for server 277 * authentication with the given public key type and set of issuers, 278 * or {@code null} if there were none. 279 */ 280 @Override 281 public String[] getServerAliases(String keyType, Principal[] issuers) 282 { 283 return keyManager.getServerAliases(keyType, issuers); 284 } 285 286 /** 287 * Wraps the provided set of key managers in selectable certificate key 288 * managers using the provided alias. 289 * 290 * @param keyManagers The set of key managers to be wrapped. 291 * @param aliases The aliases to use for selecting the desired 292 * certificate. 293 * @param componentName Name of the component to which is associated this key manager 294 * 295 * @return A key manager array 296 */ 297 public static KeyManager[] wrap(KeyManager[] keyManagers, 298 SortedSet<String> aliases, String componentName) 299 { 300 final KeyManager[] newKeyManagers = new KeyManager[keyManagers.length]; 301 for (int i=0; i < keyManagers.length; i++) 302 { 303 newKeyManagers[i] = new SelectableCertificateKeyManager( 304 (X509KeyManager) keyManagers[i], aliases, componentName); 305 } 306 307 return newKeyManagers; 308 } 309 310 /** 311 * Wraps the provided set of key managers in selectable certificate key 312 * managers using the provided alias. 313 * 314 * @param keyManagers The set of key managers to be wrapped. 315 * @param aliases The aliases to use for selecting the desired 316 * certificate. 317 * 318 * @return A key manager array 319 */ 320 public static KeyManager[] wrap(KeyManager[] keyManagers, SortedSet<String> aliases) { 321 return wrap(keyManagers, aliases, "[unknown]"); 322 } 323}