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}