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