mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
28.01.2007 d3a10338d643cf04e89e577ba496c547e0bf7516
Add a new key manager which provides the ability to specify which certificate
should be presented based on its alias (aka its nickname). This is used both
by server-side code which needs to present a certificate to clients, as well as
by client-side code which needs to present a certificate to the server.

OpenDS Issue Number: 1292
1 files added
19 files modified
890 ■■■■■ changed files
opends/resource/config/config.ldif 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/api/ClientConnection.java 18 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java 16 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/ToolMessages.java 13 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java 22 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java 17 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java 18 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPCompare.java 20 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPDelete.java 22 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPModify.java 22 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPPasswordModify.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPSearch.java 20 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/SSLConnectionFactory.java 10 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/StopDS.java 20 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/util/SelectableCertificateKeyManager.java 315 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java 17 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPCompareTestCase.java 112 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPModifyTestCase.java 110 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPSearchTestCase.java 110 ●●●●● patch | view | raw | blame | history
opends/resource/config/config.ldif
@@ -374,7 +374,7 @@
ds-cfg-connection-handler-enabled: true
ds-cfg-use-ssl: false
ds-cfg-listen-port: 1689
ds-cfg-ssl-cert-nickname: adm-server-cert
ds-cfg-ssl-cert-nickname: server-cert
dn: cn=Entry Cache,cn=config
objectClass: top
opends/src/server/org/opends/server/api/ClientConnection.java
@@ -1488,6 +1488,24 @@
  /**
   * Retrieves the alias of the server certificate that should be used
   * for operations requiring a server certificate.  The default
   * implementation returns {@code null} to indicate that any alias is
   * acceptable.
   *
   * @return  The alias of the server certificate that should be used
   *          for operations requring a server certificate, or
   *          {@code null} if any alias is acceptable.
   */
  public String getCertificateAlias()
  {
    // In the default implementation, we'll return null.
    return null;
  }
  /**
   * Retrieves a string representation of this client connection.
   *
   * @return  A string representation of this client connection.
opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java
@@ -50,6 +50,7 @@
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.InitializationException;
import org.opends.server.types.SSLClientAuthPolicy;
import org.opends.server.util.SelectableCertificateKeyManager;
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.messages.ExtensionsMessages.*;
@@ -195,8 +196,19 @@
    {
      // FIXME -- Is it bad to create a new SSLContext for each connection?
      sslContext = SSLContext.getInstance(SSL_CONTEXT_INSTANCE_NAME);
      sslContext.init(keyManagerProvider.getKeyManagers(),
                      trustManagerProvider.getTrustManagers(), null);
      String alias = clientConnection.getCertificateAlias();
      if (alias == null)
      {
        sslContext.init(keyManagerProvider.getKeyManagers(),
                        trustManagerProvider.getTrustManagers(), null);
      }
      else
      {
        sslContext.init(SelectableCertificateKeyManager.wrap(
                             keyManagerProvider.getKeyManagers(), alias),
                        trustManagerProvider.getTrustManagers(), null);
      }
    }
    catch (Exception e)
    {
opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -7655,6 +7655,17 @@
  public static final int MSGID_STOPDS_CHECK_STOPPABILITY =
      CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 804;
  /**
   * The message ID for the message that will be used as the description of the
   * certNickname argument.  This does not take any arguments.
   */
  public static final int MSGID_DESCRIPTION_CERT_NICKNAME =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 805;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
@@ -8117,6 +8128,8 @@
                    "Certificate keystore PIN");
    registerMessage(MSGID_DESCRIPTION_KEYSTOREPASSWORD_FILE,
                    "Certificate keystore PIN file");
    registerMessage(MSGID_DESCRIPTION_CERT_NICKNAME,
                    "Nickname of certificate for SSL client authentication");
    registerMessage(MSGID_DESCRIPTION_TRUSTSTOREPASSWORD,
                    "Certificate trust store PIN");
    registerMessage(MSGID_DESCRIPTION_TRUSTSTOREPASSWORD_FILE,
opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java
@@ -1062,9 +1062,9 @@
      if (certNameAttr == null)
      {
        //
        // This is fine -- we'll just use the default.
        // This is fine -- we'll just let the server pick one.
        certNameAttr = new StringConfigAttribute(ATTR_SSL_CERT_NICKNAME,
            getMessage(msgID), false, false, false, DEFAULT_SSL_CERT_NICKNAME);
            getMessage(msgID), false, false, false, (String) null);
      }
      return certNameAttr;
    }
opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java
@@ -32,6 +32,7 @@
import java.rmi.registry.Registry;
import java.util.HashMap;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.SSLContext;
@@ -48,6 +49,8 @@
import org.opends.server.types.DebugLogCategory;
import org.opends.server.types.DebugLogSeverity;
import org.opends.server.util.SelectableCertificateKeyManager;
import static org.opends.server.loggers.Debug.*;
/**
@@ -320,15 +323,30 @@
        // ---------------------
        //
        // Get a Server socket factory
        KeyManager[] keyManagers;
        KeyManagerProvider provider = jmxConnectionHandler.keyManagerProvider;
        if (provider == null)
        {
          provider = new NullKeyManagerProvider();
          keyManagers = new NullKeyManagerProvider().getKeyManagers();
        }
        else
        {
          String nickname = jmxConnectionHandler.sslServerCertNickname;
          if (nickname == null)
          {
            keyManagers = provider.getKeyManagers();
          }
          else
          {
            keyManagers =
                 SelectableCertificateKeyManager.wrap(provider.getKeyManagers(),
                                                      nickname);
          }
        }
        SSLContext ctx = SSLContext.getInstance("TLSv1");
        ctx.init(
            provider.getKeyManagers(),
            keyManagers,
            null,
            null);
        SSLSocketFactory ssf = ctx.getSocketFactory();
opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -2653,5 +2653,22 @@
    return connectionHandler.getTrustManagerProviderDN();
  }
  /**
   * Retrieves the alias of the server certificate that should be used
   * for operations requiring a server certificate.  The default
   * implementation returns {@code null} to indicate that any alias is
   * acceptable.
   *
   * @return  The alias of the server certificate that should be used
   *          for operations requring a server certificate, or
   *          {@code null} if any alias is acceptable.
   */
  public String getCertificateAlias()
  {
    return connectionHandler.getSSLServerCertNickname();
  }
}
opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -901,8 +901,8 @@
           configEntry.getConfigAttribute(certNameStub);
      if (certNameAttr == null)
      {
        // This is fine -- we'll just use the default.
        sslServerCertNickname = DEFAULT_SSL_CERT_NICKNAME;
        // This is fine -- We'll just let the server pick one.
        sslServerCertNickname = null;
      }
      else
      {
@@ -1792,6 +1792,20 @@
  /**
   * Retrieves the nickname of the server certificate that should be used in
   * conjunction with this LDAP connection handler.
   *
   * @return  The nickname of the server certificate that should be used in
   *          conjunction with this LDAP connection handler.
   */
  public String getSSLServerCertNickname()
  {
    return sslServerCertNickname;
  }
  /**
   * Retrieves the maximum ASN.1 element value length that will be allowed by
   * this connection handler.
   *
opends/src/server/org/opends/server/tools/LDAPCompare.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
@@ -343,6 +343,7 @@
    StringArgument    assertionFilter        = null;
    StringArgument    bindDN                 = null;
    StringArgument    bindPassword           = null;
    StringArgument    certNickname           = null;
    StringArgument    controlStr             = null;
    StringArgument    encodingStr            = null;
    StringArgument    filename               = null;
@@ -438,6 +439,11 @@
                                 MSGID_DESCRIPTION_KEYSTOREPASSWORD_FILE);
      argParser.addArgument(keyStorePasswordFile);
      certNickname = new StringArgument("certnickname", 'N', "certNickname",
                                        false, false, true, "{nickname}", null,
                                        null, MSGID_DESCRIPTION_CERT_NICKNAME);
      argParser.addArgument(certNickname);
      trustStorePath = new StringArgument("trustStorePath", 'P',
                                          "trustStorePath", false, false, true,
                                          "{trustStorePath}", null, null,
@@ -796,9 +802,19 @@
      SSLConnectionFactory sslConnectionFactory = null;
      if(connectionOptions.useSSL() || connectionOptions.useStartTLS())
      {
        String clientAlias;
        if (certNickname.isPresent())
        {
          clientAlias = certNickname.getValue();
        }
        else
        {
          clientAlias = null;
        }
        sslConnectionFactory = new SSLConnectionFactory();
        sslConnectionFactory.init(trustAll.isPresent(), keyStorePathValue,
                                  keyStorePasswordValue,
                                  keyStorePasswordValue, clientAlias,
                                  trustStorePathValue, trustStorePasswordValue);
        connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
      }
opends/src/server/org/opends/server/tools/LDAPDelete.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
@@ -323,6 +323,7 @@
    IntegerArgument   version                = null;
    StringArgument    bindDN                 = null;
    StringArgument    bindPassword           = null;
    StringArgument    certNickname           = null;
    StringArgument    controlStr             = null;
    StringArgument    encodingStr            = null;
    StringArgument    filename               = null;
@@ -415,6 +416,11 @@
                                 MSGID_DESCRIPTION_KEYSTOREPASSWORD_FILE);
      argParser.addArgument(keyStorePasswordFile);
      certNickname = new StringArgument("certnickname", 'N', "certNickname",
                                        false, false, true, "{nickname}", null,
                                        null, MSGID_DESCRIPTION_CERT_NICKNAME);
      argParser.addArgument(certNickname);
      trustStorePath = new StringArgument("trustStorePath", 'P',
                                          "trustStorePath", false, false, true,
                                          "{trustStorePath}", null, null,
@@ -679,10 +685,20 @@
      SSLConnectionFactory sslConnectionFactory = null;
      if(connectionOptions.useSSL() || connectionOptions.useStartTLS())
      {
        String clientAlias;
        if (certNickname.isPresent())
        {
          clientAlias = certNickname.getValue();
        }
        else
        {
          clientAlias = null;
        }
        sslConnectionFactory = new SSLConnectionFactory();
        sslConnectionFactory.init(trustAll.isPresent(), keyStorePathValue,
                                  keyStorePasswordValue, trustStorePathValue,
                                  trustStorePasswordValue);
                                  keyStorePasswordValue, clientAlias,
                                  trustStorePathValue, trustStorePasswordValue);
        connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
      }
opends/src/server/org/opends/server/tools/LDAPModify.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
@@ -581,6 +581,7 @@
    StringArgument    assertionFilter        = null;
    StringArgument    bindDN                 = null;
    StringArgument    bindPassword           = null;
    StringArgument    certNickname           = null;
    StringArgument    controlStr             = null;
    StringArgument    encodingStr            = null;
    StringArgument    filename               = null;
@@ -677,6 +678,11 @@
                                 MSGID_DESCRIPTION_KEYSTOREPASSWORD_FILE);
      argParser.addArgument(keyStorePasswordFile);
      certNickname = new StringArgument("certnickname", 'N', "certNickname",
                                        false, false, true, "{nickname}", null,
                                        null, MSGID_DESCRIPTION_CERT_NICKNAME);
      argParser.addArgument(certNickname);
      trustStorePath = new StringArgument("trustStorePath", 'P',
                                          "trustStorePath", false, false, true,
                                          "{trustStorePath}", null, null,
@@ -1022,10 +1028,20 @@
      SSLConnectionFactory sslConnectionFactory = null;
      if(connectionOptions.useSSL() || connectionOptions.useStartTLS())
      {
        String clientAlias;
        if (certNickname.isPresent())
        {
          clientAlias = certNickname.getValue();
        }
        else
        {
          clientAlias = null;
        }
        sslConnectionFactory = new SSLConnectionFactory();
        sslConnectionFactory.init(trustAll.isPresent(), keyStorePathValue,
                                  keyStorePasswordValue, trustStorePathValue,
                                  trustStorePasswordValue);
                                  keyStorePasswordValue, clientAlias,
                                  trustStorePathValue, trustStorePasswordValue);
        connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
      }
opends/src/server/org/opends/server/tools/LDAPPasswordModify.java
@@ -550,7 +550,7 @@
      {
        SSLConnectionFactory sslConnectionFactory = new SSLConnectionFactory();
        sslConnectionFactory.init(sslBlindTrust.isPresent(),
                                  sslKeyStore.getValue(), keyPIN,
                                  sslKeyStore.getValue(), keyPIN, null,
                                  sslTrustStore.getValue(), trustPIN);
        connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
      }
opends/src/server/org/opends/server/tools/LDAPSearch.java
@@ -584,6 +584,7 @@
    StringArgument    baseDN                   = null;
    StringArgument    bindDN                   = null;
    StringArgument    bindPassword             = null;
    StringArgument    certNickname             = null;
    StringArgument    controlStr               = null;
    StringArgument    dereferencePolicy        = null;
    StringArgument    encodingStr              = null;
@@ -690,6 +691,11 @@
                                 MSGID_DESCRIPTION_KEYSTOREPASSWORD_FILE);
      argParser.addArgument(keyStorePasswordFile);
      certNickname = new StringArgument("certnickname", 'N', "certNickname",
                                        false, false, true, "{nickname}", null,
                                        null, MSGID_DESCRIPTION_CERT_NICKNAME);
      argParser.addArgument(certNickname);
      trustStorePath = new StringArgument("trustStorePath", 'P',
                                  "trustStorePath", false, false, true,
                                  "{trustStorePath}", null, null,
@@ -1315,10 +1321,20 @@
      SSLConnectionFactory sslConnectionFactory = null;
      if(connectionOptions.useSSL() || connectionOptions.useStartTLS())
      {
        String clientAlias;
        if (certNickname.isPresent())
        {
          clientAlias = certNickname.getValue();
        }
        else
        {
          clientAlias = null;
        }
        sslConnectionFactory = new SSLConnectionFactory();
        sslConnectionFactory.init(trustAll.isPresent(), keyStorePathValue,
                                  keyStorePasswordValue, trustStorePathValue,
                                  trustStorePasswordValue);
                                  keyStorePasswordValue, clientAlias,
                                  trustStorePathValue, trustStorePasswordValue);
        connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
      }
opends/src/server/org/opends/server/tools/SSLConnectionFactory.java
@@ -41,6 +41,7 @@
import javax.net.ssl.TrustManagerFactory;
import org.opends.server.extensions.BlindTrustManagerProvider;
import org.opends.server.util.SelectableCertificateKeyManager;
import static org.opends.server.messages.ToolMessages.*;
import static org.opends.server.messages.MessageHandler.*;
@@ -74,6 +75,7 @@
   * @param  keyStorePath        The path to the key store file.
   * @param  keyStorePassword    The PIN to use to access the key store
   *                             contents.
   * @param  clientAlias         The alias to use for the client certificate.
   * @param  trustStorePath      The path to the trust store file.
   * @param  trustStorePassword  The PIN to use to access the trust store
   *                             contents.
@@ -82,7 +84,7 @@
   *                                  connection factory.
   */
  public void init(boolean trustAll, String keyStorePath,
                   String keyStorePassword,
                   String keyStorePassword, String clientAlias,
                   String trustStorePath, String trustStorePassword)
         throws SSLConnectionException
  {
@@ -108,6 +110,12 @@
      {
        keyManagers = getKeyManagers(KeyStore.getDefaultType(), null,
                          keyStorePath, keyStorePassword);
        if (clientAlias != null)
        {
          keyManagers = SelectableCertificateKeyManager.wrap(keyManagers,
                                                             clientAlias);
        }
      }
      ctx.init(keyManagers, trustManagers, new java.security.SecureRandom());
opends/src/server/org/opends/server/tools/StopDS.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
@@ -176,6 +176,7 @@
    IntegerArgument   port;
    StringArgument    bindDN;
    StringArgument    bindPW;
    StringArgument    certNickname;
    StringArgument    host;
    StringArgument    keyStoreFile;
    StringArgument    keyStorePW;
@@ -276,6 +277,11 @@
                                             MSGID_STOPDS_DESCRIPTION_KSPWFILE);
      argParser.addArgument(keyStorePWFile);
      certNickname = new StringArgument("certnickname", 'N', "certNickname",
                                        false, false, true, "{nickname}", null,
                                        null, MSGID_DESCRIPTION_CERT_NICKNAME);
      argParser.addArgument(certNickname);
      trustStoreFile = new StringArgument("truststorefile", 'P',
                                          "trustStoreFile", false, false, true,
                                          "{trustStoreFile}", null, null,
@@ -490,9 +496,19 @@
    {
      try
      {
        String clientAlias;
        if (certNickname.isPresent())
        {
          clientAlias = certNickname.getValue();
        }
        else
        {
          clientAlias = null;
        }
        SSLConnectionFactory sslConnectionFactory = new SSLConnectionFactory();
        sslConnectionFactory.init(trustAll.isPresent(), keyStoreFile.getValue(),
                                  keyStorePW.getValue(),
                                  keyStorePW.getValue(), clientAlias,
                                  trustStoreFile.getValue(),
                                  trustStorePW.getValue());
opends/src/server/org/opends/server/util/SelectableCertificateKeyManager.java
New file
@@ -0,0 +1,315 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.util;
import java.net.Socket;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;
/**
 * This class implements an X.509 key manager that will be used to wrap an
 * existing key manager and makes it possible to configure which certificate(s)
 * should be used for client and/or server operations.  The certificate
 * selection will be based on the alias (also called the nickname) of the
 * certificate.
 */
public class SelectableCertificateKeyManager
       extends X509ExtendedKeyManager
{
  // The alias of the certificate that should be selected from the key manager.
  private String alias;
  // The key manager that is wrapped by this key manager.
  private X509KeyManager keyManager;
  /**
   * Creates a new instance of this key manager that will wrap the provided key
   * manager and use the certificate with the specified alias.
   *
   * @param  keyManager  The key manager to be wrapped by this key manager.
   * @param  alias       The nickname of the certificate that should be
   *                     selected for operations involving this key manager.
   */
  public SelectableCertificateKeyManager(X509KeyManager keyManager,
                                         String alias)
  {
    super();
    this.keyManager = keyManager;
    this.alias      = alias;
  }
  /**
   * Chooses the alias of the client certificate that should be used based on
   * the provided critieria.  This will either return the preferred alias
   * configured for this key manager, or {@code null} if no client certificate
   * with that alias is configured in the underlying key manager.
   *
   * @param  keyType  The set of key algorithm names, ordered with the most
   *                  preferred key type first.
   * @param  issuers  The list of acceptable issuer subject names, or
   *                  {@code null} if any issuer may be used.
   * @param  socket   The socket to be used for this connection.
   *
   * @return  The alias configured for this key manager, or {@code null} if no
   *          such client certificate is available with that alias.
   */
  public String chooseClientAlias(String[] keyType, Principal[] issuers,
                                  Socket socket)
  {
    for (String type : keyType)
    {
      String[] clientAliases = keyManager.getClientAliases(type, issuers);
      if (clientAliases != null)
      {
        for (String clientAlias : clientAliases)
        {
          if (clientAlias.equals(alias))
          {
            return alias;
          }
        }
      }
    }
    return null;
  }
  /**
   * Chooses the alias of the client certificate that should be used based on
   * the provided critieria.  This will either return the preferred alias
   * configured for this key manager, or {@code null} if no client certificate
   * with that alias is configured in the underlying key manager.
   *
   * @param  keyType  The set of key algorithm names, ordered with the most
   *                  preferred key type first.
   * @param  issuers  The list of acceptable issuer subject names, or
   *                  {@code null} if any issuer may be used.
   * @param  engine   The SSL engine to be used for this connection.
   *
   * @return  The alias configured for this key manager, or {@code null} if no
   *          such client certificate is available with that alias.
   */
  public String chooseEngineClientAlias(String[] keyType, Principal[] issuers,
                                        SSLEngine engine)
  {
    for (String type : keyType)
    {
      String[] clientAliases = keyManager.getClientAliases(type, issuers);
      if (clientAliases != null)
      {
        for (String clientAlias : clientAliases)
        {
          if (clientAlias.equals(alias))
          {
            return alias;
          }
        }
      }
    }
    return null;
  }
  /**
   * Chooses the alias of the server certificate that should be used based on
   * the provided critieria.  This will either return the preferred alias
   * configured for this key manager, or {@code null} if no server certificate
   * with that alias is configured in the underlying key manager.
   *
   * @param  keyType  The public key type for the certificate.
   * @param  issuers  The list of acceptable issuer subject names, or
   *                  {@code null} if any issuer may be used.
   * @param  socket   The socket to be used for this connection.
   *
   * @return  The alias configured for this key manager, or {@code null} if no
   *          such server certificate is available with that alias.
   */
  public String chooseServerAlias(String keyType, Principal[] issuers,
                                  Socket socket)
  {
    String[] serverAliases = keyManager.getServerAliases(keyType, issuers);
    if (serverAliases != null)
    {
      for (String serverAlias : serverAliases)
      {
        if (serverAlias.equals(alias))
        {
          return alias;
        }
      }
    }
    return null;
  }
  /**
   * Chooses the alias of the server certificate that should be used based on
   * the provided critieria.  This will either return the preferred alias
   * configured for this key manager, or {@code null} if no server certificate
   * with that alias is configured in the underlying key manager.
   *
   * @param  keyType  The public key type for the certificate.
   * @param  issuers  The list of acceptable issuer subject names, or
   *                  {@code null} if any issuer may be used.
   * @param  engine   The SSL engine to be used for this connection.
   *
   * @return  The alias configured for this key manager, or {@code null} if no
   *          such server certificate is available with that alias.
   */
  public String chooseEngineServerAlias(String keyType, Principal[] issuers,
                                        SSLEngine engine)
  {
    String[] serverAliases = keyManager.getServerAliases(keyType, issuers);
    if (serverAliases != null)
    {
      for (String serverAlias : serverAliases)
      {
        if (serverAlias.equals(alias))
        {
          return alias;
        }
      }
    }
    return null;
  }
  /**
   * Retrieves the certificate chain for the provided alias.
   *
   * @param  alias  The alias for the certificate chain to retrieve.
   *
   * @return  The certificate chain for the provided alias, or {@code null} if
   *          no certificate is associated with the provided alias.
   */
  public X509Certificate[] getCertificateChain(String alias)
  {
    return keyManager.getCertificateChain(alias);
  }
  /**
   * Retrieves the set of certificate aliases that may be used for client
   * authentication with the given public key type and set of issuers.
   *
   * @param  keyType  The public key type for the aliases to retrieve.
   * @param  issuers  The list of acceptable issuer subject names, or
   *                  {@code null} if any issuer may be used.
   *
   * @return  The set of certificate aliases that may be used for client
   *          authentication with the given public key type and set of issuers,
   *          or {@code null} if there were none.
   */
  public String[] getClientAliases(String keyType, Principal[] issuers)
  {
    return keyManager.getClientAliases(keyType, issuers);
  }
  /**
   * Retrieves the private key for the provided alias.
   *
   * @param  alias  The alias for the private key to return.
   *
   * @return  The private key for the provided alias, or {@code null} if no
   *          private key is available for the provided alias.
   */
  public PrivateKey getPrivateKey(String alias)
  {
    return keyManager.getPrivateKey(alias);
  }
  /**
   * Retrieves the set of certificate aliases that may be used for server
   * authentication with the given public key type and set of issuers.
   *
   * @param  keyType  The public key type for the aliases to retrieve.
   * @param  issuers  The list of acceptable issuer subject names, or
   *                  {@code null} if any issuer may be used.
   *
   * @return  The set of certificate aliases that may be used for server
   *          authentication with the given public key type and set of issuers,
   *          or {@code null} if there were none.
   */
  public String[] getServerAliases(String keyType, Principal[] issuers)
  {
    return keyManager.getServerAliases(keyType, issuers);
  }
  /**
   * Wraps the provided set of key managers in selectable certificate key
   * managers using the provided alias.
   *
   * @param  keyManagers  The set of key managers to be wrapped.
   * @param  alias        The alias to use for selecting the desired
   *                      certificate.
   *
   * @return  A key manager array
   */
  public static X509ExtendedKeyManager[] wrap(KeyManager[] keyManagers,
                                              String alias)
  {
    X509ExtendedKeyManager[] newKeyManagers =
         new X509ExtendedKeyManager[keyManagers.length];
    for (int i=0; i < keyManagers.length; i++)
    {
      newKeyManagers[i] = new SelectableCertificateKeyManager(
                                   (X509KeyManager) keyManagers[i], alias);
    }
    return newKeyManagers;
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
@@ -2471,7 +2471,8 @@
    SSLConnectionFactory factory = new SSLConnectionFactory();
    factory.init(false, keyStorePath, "password", trustStorePath, "password");
    factory.init(false, keyStorePath, "password", "client-cert",
                 trustStorePath, "password");
    Socket s = factory.createSocket("127.0.0.1",
@@ -2541,7 +2542,8 @@
    SSLConnectionFactory factory = new SSLConnectionFactory();
    factory.init(false, keyStorePath, "password", trustStorePath, "password");
    factory.init(false, keyStorePath, "password", "client-cert", trustStorePath,
                 "password");
    Socket s = factory.createSocket("127.0.0.1",
@@ -2609,7 +2611,8 @@
    SSLConnectionFactory factory = new SSLConnectionFactory();
    factory.init(false, keyStorePath, "password", trustStorePath, "password");
    factory.init(false, keyStorePath, "password", "client-cert", trustStorePath,
                 "password");
    Socket s = factory.createSocket("127.0.0.1",
@@ -2683,7 +2686,8 @@
    SSLConnectionFactory factory = new SSLConnectionFactory();
    factory.init(false, keyStorePath, "password", trustStorePath, "password");
    factory.init(false, keyStorePath, "password", "client-cert", trustStorePath,
                 "password");
    Socket s = factory.createSocket("127.0.0.1",
@@ -4205,7 +4209,8 @@
    SSLConnectionFactory factory = new SSLConnectionFactory();
    factory.init(false, keyStorePath, "password", trustStorePath, "password");
    factory.init(false, keyStorePath, "password", "client-cert", trustStorePath,
                 "password");
    Socket s = factory.createSocket("127.0.0.1",
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPCompareTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
@@ -636,6 +636,116 @@
  /**
   * Tests a simple LDAP compare over SSL using a trust store and SASL EXTERNAL
   * authentication when explicitly specifying a valid client certificate.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testSimpleCompareSSLTrustStoreSASLExternalValidClientCert()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "givenName: Test",
         "ds-privilege-name: bypass-acl",
         "sn: User");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    AddOperation addOperation =
         conn.processAdd(e.getDN(), e.getObjectClasses(), e.getUserAttributes(),
                         e.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    String keyStorePath   = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.keystore";
    String trustStorePath = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.truststore";
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapsPort()),
      "-Z",
      "-K", keyStorePath,
      "-W", "password",
      "-N", "client-cert",
      "-P", trustStorePath,
      "-r",
      "cn:Test User",
      "cn=Test User,o=test"
    };
    assertEquals(LDAPCompare.mainCompare(args, false, null, System.err), 0);
  }
  /**
   * Tests a simple LDAP compare over SSL using a trust store and SASL EXTERNAL
   * authentication when explicitly specifying an invalid client certificate.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testSimpleCompareSSLTrustStoreSASLExternalInvalidClientCert()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "givenName: Test",
         "ds-privilege-name: bypass-acl",
         "sn: User");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    AddOperation addOperation =
         conn.processAdd(e.getDN(), e.getObjectClasses(), e.getUserAttributes(),
                         e.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    String keyStorePath   = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.keystore";
    String trustStorePath = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.truststore";
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapsPort()),
      "-Z",
      "-K", keyStorePath,
      "-W", "password",
      "-N", "invalid",
      "-P", trustStorePath,
      "-r",
      "cn:Test User",
      "cn=Test User,o=test"
    };
    assertFalse(LDAPCompare.mainCompare(args, false, null, null) == 0);
  }
  /**
   * Tests a simple LDAP compare using StartTLS with a trust store and SASL
   * EXTERNAL authentication.
   *
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPModifyTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
@@ -562,6 +562,114 @@
  /**
   * Tests a simple modify operation over SSL using a trust store and SASL
   * EXTERNAL while explicitly specifying a valid client certificate.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testSSLTrustStoreSASLExternalValidClientCert()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "givenName: Test",
         "ds-privilege-name: bypass-acl",
         "sn: User");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    AddOperation addOperation =
         conn.processAdd(e.getDN(), e.getObjectClasses(), e.getUserAttributes(),
                         e.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    String keyStorePath   = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.keystore";
    String trustStorePath = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.truststore";
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapsPort()),
      "-Z",
      "-K", keyStorePath,
      "-W", "password",
      "-N", "client-cert",
      "-P", trustStorePath,
      "-r",
      "-f", modifyFilePath
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
  }
  /**
   * Tests a simple modify operation over SSL using a trust store and SASL
   * EXTERNAL while explicitly specifying an invalid client certificate.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testSSLTrustStoreSASLExternalInvalidClientCert()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "givenName: Test",
         "ds-privilege-name: bypass-acl",
         "sn: User");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    AddOperation addOperation =
         conn.processAdd(e.getDN(), e.getObjectClasses(), e.getUserAttributes(),
                         e.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    String keyStorePath   = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.keystore";
    String trustStorePath = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.truststore";
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapsPort()),
      "-Z",
      "-K", keyStorePath,
      "-W", "password",
      "-N", "invalid",
      "-P", trustStorePath,
      "-r",
      "-f", modifyFilePath
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests a simple modify operation with StartTLS using a trust store and SASL
   * EXTERNAL.
   *
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPSearchTestCase.java
@@ -714,6 +714,116 @@
  /**
   * Tests a simple LDAP search over SSL using a trust store and SASL EXTERNAL
   * authentication when explicitly specifying a valid client certificate.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testSimpleSearchSSLTrustStoreSASLExternalValidClientCert()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "givenName: Test",
         "sn: User");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    AddOperation addOperation =
         conn.processAdd(e.getDN(), e.getObjectClasses(), e.getUserAttributes(),
                         e.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    String keyStorePath   = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.keystore";
    String trustStorePath = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.truststore";
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapsPort()),
      "-Z",
      "-K", keyStorePath,
      "-W", "password",
      "-N", "client-cert",
      "-P", trustStorePath,
      "-r",
      "-b", "",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests a simple LDAP search over SSL using a trust store and SASL EXTERNAL
   * authentication when explicitly specifying an invalid client certificate.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testSimpleSearchSSLTrustStoreSASLExternalInvalidClientCert()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "givenName: Test",
         "sn: User");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    AddOperation addOperation =
         conn.processAdd(e.getDN(), e.getObjectClasses(), e.getUserAttributes(),
                         e.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    String keyStorePath   = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.keystore";
    String trustStorePath = DirectoryServer.getServerRoot() + File.separator +
                            "config" + File.separator + "client.truststore";
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapsPort()),
      "-Z",
      "-K", keyStorePath,
      "-W", "password",
      "-N", "invalid",
      "-P", trustStorePath,
      "-r",
      "-b", "",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Tests a simple LDAP search using StartTLS with a trust store and SASL
   * EXTERNAL authentication.
   *