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

Matthew Swift
25.33.2012 263d085885df024dca9250cc03c807912b0a7662
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/KeyManagers.java
@@ -6,17 +6,16 @@
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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/opendj3/legal-notices/CDDLv1_0.txt.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * 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
@@ -28,372 +27,298 @@
package org.forgerock.opendj.ldap;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.security.*;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.net.ssl.*;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;
import com.forgerock.opendj.util.Validator;
/**
 * This class contains methods for creating common types of key manager.
 */
public final class KeyManagers
{
  /**
   * 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.
   */
  private static final class SelectCertificate extends X509ExtendedKeyManager
  {
    private final String alias;
    private final X509KeyManager keyManager;
    private SelectCertificate(final X509KeyManager keyManager,
        final String alias)
    {
      this.keyManager = keyManager;
      this.alias = alias;
    }
public final class KeyManagers {
    /**
     * {@inheritDoc}
     * 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 String chooseClientAlias(final String[] keyType,
        final Principal[] issuers, final Socket socket)
    {
      for (final String type : keyType)
      {
        final String[] clientAliases = keyManager.getClientAliases(type,
            issuers);
        if (clientAliases != null)
        {
          for (final String clientAlias : clientAliases)
          {
            if (clientAlias.equals(alias))
            {
              return alias;
    private static final class SelectCertificate extends X509ExtendedKeyManager {
        private final String alias;
        private final X509KeyManager keyManager;
        private SelectCertificate(final X509KeyManager keyManager, final String alias) {
            this.keyManager = keyManager;
            this.alias = alias;
        }
        /**
         * {@inheritDoc}
         */
        public String chooseClientAlias(final String[] keyType, final Principal[] issuers,
                final Socket socket) {
            for (final String type : keyType) {
                final String[] clientAliases = keyManager.getClientAliases(type, issuers);
                if (clientAliases != null) {
                    for (final String clientAlias : clientAliases) {
                        if (clientAlias.equals(alias)) {
                            return alias;
                        }
                    }
                }
            }
          }
            return null;
        }
      }
      return null;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public String chooseEngineClientAlias(final String[] keyType,
        final Principal[] issuers, final SSLEngine engine)
    {
      for (final String type : keyType)
      {
        final String[] clientAliases = keyManager.getClientAliases(type,
            issuers);
        if (clientAliases != null)
        {
          for (final String clientAlias : clientAliases)
          {
            if (clientAlias.equals(alias))
            {
              return alias;
        /**
         * {@inheritDoc}
         */
        @Override
        public String chooseEngineClientAlias(final String[] keyType, final Principal[] issuers,
                final SSLEngine engine) {
            for (final String type : keyType) {
                final String[] clientAliases = keyManager.getClientAliases(type, issuers);
                if (clientAliases != null) {
                    for (final String clientAlias : clientAliases) {
                        if (clientAlias.equals(alias)) {
                            return alias;
                        }
                    }
                }
            }
          }
            return null;
        }
      }
      return null;
    }
        /**
         * {@inheritDoc}
         */
        @Override
        public String chooseEngineServerAlias(final String keyType, final Principal[] issuers,
                final SSLEngine engine) {
            final String[] serverAliases = keyManager.getServerAliases(keyType, issuers);
            if (serverAliases != null) {
                for (final String serverAlias : serverAliases) {
                    if (serverAlias.equalsIgnoreCase(alias)) {
                        return serverAlias;
                    }
                }
            }
    /**
     * {@inheritDoc}
     */
    @Override
    public String chooseEngineServerAlias(final String keyType,
        final Principal[] issuers, final SSLEngine engine)
    {
      final String[] serverAliases = keyManager.getServerAliases(keyType,
          issuers);
      if (serverAliases != null)
      {
        for (final String serverAlias : serverAliases)
        {
          if (serverAlias.equalsIgnoreCase(alias))
          {
            return serverAlias;
          }
            return null;
        }
      }
      return null;
    }
        /**
         * {@inheritDoc}
         */
        public String chooseServerAlias(final String keyType, final Principal[] issuers,
                final Socket socket) {
            final String[] serverAliases = keyManager.getServerAliases(keyType, issuers);
            if (serverAliases != null) {
                for (final String serverAlias : serverAliases) {
                    if (serverAlias.equals(alias)) {
                        return alias;
                    }
                }
            }
    /**
     * {@inheritDoc}
     */
    public String chooseServerAlias(final String keyType,
        final Principal[] issuers, final Socket socket)
    {
      final String[] serverAliases = keyManager.getServerAliases(keyType,
          issuers);
      if (serverAliases != null)
      {
        for (final String serverAlias : serverAliases)
        {
          if (serverAlias.equals(alias))
          {
            return alias;
          }
            return null;
        }
      }
      return null;
    }
    /**
     * {@inheritDoc}
     */
    public X509Certificate[] getCertificateChain(final String alias)
    {
      return keyManager.getCertificateChain(alias);
    }
    /**
     * {@inheritDoc}
     */
    public String[] getClientAliases(final String keyType,
        final Principal[] issuers)
    {
      return keyManager.getClientAliases(keyType, issuers);
    }
    /**
     * {@inheritDoc}
     */
    public PrivateKey getPrivateKey(final String alias)
    {
      return keyManager.getPrivateKey(alias);
    }
    /**
     * {@inheritDoc}
     */
    public String[] getServerAliases(final String keyType,
        final Principal[] issuers)
    {
      return keyManager.getServerAliases(keyType, issuers);
    }
  }
  /**
   * Creates a new {@code X509KeyManager} which will use the named key store
   * file for retrieving certificates. It will use the default key store format
   * for the JVM (e.g. {@code JKS}) and will not use a password to open the key
   * store.
   *
   * @param file
   *          The key store file name.
   * @return A new {@code X509KeyManager} which will use the named key store
   *         file for retrieving certificates.
   * @throws GeneralSecurityException
   *           If the key store could not be loaded, perhaps due to incorrect
   *           format, or missing algorithms.
   * @throws IOException
   *           If the key store file could not be found or could not be read.
   * @throws NullPointerException
   *           If {@code file} was {@code null}.
   */
  public static X509KeyManager useKeyStoreFile(final String file)
      throws GeneralSecurityException, IOException
  {
    return useKeyStoreFile(file, null, null);
  }
  /**
   * Creates a new {@code X509KeyManager} which will use the named key store
   * file for retrieving certificates. It will use the provided key store format
   * and password.
   *
   * @param file
   *          The key store file name.
   * @param password
   *          The key store password, which may be {@code null}.
   * @param format
   *          The key store format, which may be {@code null} to indicate that
   *          the default key store format for the JVM (e.g. {@code JKS}) should
   *          be used.
   * @return A new {@code X509KeyManager} which will use the named key store
   *         file for retrieving certificates.
   * @throws GeneralSecurityException
   *           If the key store could not be loaded, perhaps due to incorrect
   *           format, or missing algorithms.
   * @throws IOException
   *           If the key store file could not be found or could not be read.
   * @throws NullPointerException
   *           If {@code file} was {@code null}.
   */
  public static X509KeyManager useKeyStoreFile(final String file,
      final char[] password, final String format)
      throws GeneralSecurityException, IOException
  {
    Validator.ensureNotNull(file);
    final File keyStoreFile = new File(file);
    final String keyStoreFormat = format != null ? format : KeyStore
        .getDefaultType();
    final KeyStore keyStore = KeyStore.getInstance(keyStoreFormat);
    FileInputStream fos = null;
    try
    {
      fos = new FileInputStream(keyStoreFile);
      keyStore.load(fos, password);
    }
    finally
    {
      if (fos != null)
      {
        try
        {
          fos.close();
        /**
         * {@inheritDoc}
         */
        public X509Certificate[] getCertificateChain(final String alias) {
            return keyManager.getCertificateChain(alias);
        }
        catch (final IOException ignored)
        {
          // Ignore.
        /**
         * {@inheritDoc}
         */
        public String[] getClientAliases(final String keyType, final Principal[] issuers) {
            return keyManager.getClientAliases(keyType, issuers);
        }
      }
        /**
         * {@inheritDoc}
         */
        public PrivateKey getPrivateKey(final String alias) {
            return keyManager.getPrivateKey(alias);
        }
        /**
         * {@inheritDoc}
         */
        public String[] getServerAliases(final String keyType, final Principal[] issuers) {
            return keyManager.getServerAliases(keyType, issuers);
        }
    }
    final KeyManagerFactory kmf = KeyManagerFactory
        .getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(keyStore, password);
    X509KeyManager x509km = null;
    for (final KeyManager km : kmf.getKeyManagers())
    {
      if (km instanceof X509KeyManager)
      {
        x509km = (X509KeyManager) km;
        break;
      }
    /**
     * Creates a new {@code X509KeyManager} which will use the named key store
     * file for retrieving certificates. It will use the default key store
     * format for the JVM (e.g. {@code JKS}) and will not use a password to open
     * the key store.
     *
     * @param file
     *            The key store file name.
     * @return A new {@code X509KeyManager} which will use the named key store
     *         file for retrieving certificates.
     * @throws GeneralSecurityException
     *             If the key store could not be loaded, perhaps due to
     *             incorrect format, or missing algorithms.
     * @throws IOException
     *             If the key store file could not be found or could not be
     *             read.
     * @throws NullPointerException
     *             If {@code file} was {@code null}.
     */
    public static X509KeyManager useKeyStoreFile(final String file)
            throws GeneralSecurityException, IOException {
        return useKeyStoreFile(file, null, null);
    }
    if (x509km == null)
    {
      throw new NoSuchAlgorithmException();
    /**
     * Creates a new {@code X509KeyManager} which will use the named key store
     * file for retrieving certificates. It will use the provided key store
     * format and password.
     *
     * @param file
     *            The key store file name.
     * @param password
     *            The key store password, which may be {@code null}.
     * @param format
     *            The key store format, which may be {@code null} to indicate
     *            that the default key store format for the JVM (e.g.
     *            {@code JKS}) should be used.
     * @return A new {@code X509KeyManager} which will use the named key store
     *         file for retrieving certificates.
     * @throws GeneralSecurityException
     *             If the key store could not be loaded, perhaps due to
     *             incorrect format, or missing algorithms.
     * @throws IOException
     *             If the key store file could not be found or could not be
     *             read.
     * @throws NullPointerException
     *             If {@code file} was {@code null}.
     */
    public static X509KeyManager useKeyStoreFile(final String file, final char[] password,
            final String format) throws GeneralSecurityException, IOException {
        Validator.ensureNotNull(file);
        final File keyStoreFile = new File(file);
        final String keyStoreFormat = format != null ? format : KeyStore.getDefaultType();
        final KeyStore keyStore = KeyStore.getInstance(keyStoreFormat);
        FileInputStream fos = null;
        try {
            fos = new FileInputStream(keyStoreFile);
            keyStore.load(fos, password);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (final IOException ignored) {
                    // Ignore.
                }
            }
        }
        final KeyManagerFactory kmf =
                KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, password);
        X509KeyManager x509km = null;
        for (final KeyManager km : kmf.getKeyManagers()) {
            if (km instanceof X509KeyManager) {
                x509km = (X509KeyManager) km;
                break;
            }
        }
        if (x509km == null) {
            throw new NoSuchAlgorithmException();
        }
        return x509km;
    }
    return x509km;
  }
    /**
     * Creates a new {@code X509KeyManager} which will use a PKCS#11 token for
     * retrieving certificates.
     *
     * @param password
     *            The password to use for accessing the PKCS#11 token, which may
     *            be {@code null} if no password is required.
     * @return A new {@code X509KeyManager} which will use a PKCS#11 token for
     *         retrieving certificates.
     * @throws GeneralSecurityException
     *             If the PKCS#11 token could not be accessed, perhaps due to
     *             incorrect password, or missing algorithms.
     * @throws IOException
     *             If the PKCS#11 token could not be found or could not be read.
     */
    public static X509KeyManager usePKCS11Token(final char[] password)
            throws GeneralSecurityException, IOException {
        final KeyStore keyStore = KeyStore.getInstance("PKCS11");
        keyStore.load(null, password);
        final KeyManagerFactory kmf =
                KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, password);
        X509KeyManager x509km = null;
        for (final KeyManager km : kmf.getKeyManagers()) {
            if (km instanceof X509KeyManager) {
                x509km = (X509KeyManager) km;
                break;
            }
        }
        if (x509km == null) {
            throw new NoSuchAlgorithmException();
        }
  /**
   * Creates a new {@code X509KeyManager} which will use a PKCS#11 token for
   * retrieving certificates.
   *
   * @param password
   *          The password to use for accessing the PKCS#11 token, which may be
   *          {@code null} if no password is required.
   * @return A new {@code X509KeyManager} which will use a PKCS#11 token for
   *         retrieving certificates.
   * @throws GeneralSecurityException
   *           If the PKCS#11 token could not be accessed, perhaps due to
   *           incorrect password, or missing algorithms.
   * @throws IOException
   *           If the PKCS#11 token could not be found or could not be read.
   */
  public static X509KeyManager usePKCS11Token(final char[] password)
      throws GeneralSecurityException, IOException
  {
    final KeyStore keyStore = KeyStore.getInstance("PKCS11");
    keyStore.load(null, password);
    final KeyManagerFactory kmf = KeyManagerFactory
        .getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(keyStore, password);
    X509KeyManager x509km = null;
    for (final KeyManager km : kmf.getKeyManagers())
    {
      if (km instanceof X509KeyManager)
      {
        x509km = (X509KeyManager) km;
        break;
      }
        return x509km;
    }
    if (x509km == null)
    {
      throw new NoSuchAlgorithmException();
    /**
     * Returns a new {@code X509KeyManager} which selects the named certificate
     * from the provided {@code X509KeyManager}.
     *
     * @param alias
     *            The nickname of the certificate that should be selected for
     *            operations involving this key manager.
     * @param keyManager
     *            The key manager to be filtered.
     * @return The filtered key manager.
     * @throws NullPointerException
     *             If {@code keyManager} or {@code alias} was {@code null}.
     */
    public static X509KeyManager useSingleCertificate(final String alias,
            final X509KeyManager keyManager) {
        Validator.ensureNotNull(alias, keyManager);
        return new SelectCertificate(keyManager, alias);
    }
    return x509km;
  }
  /**
   * Returns a new {@code X509KeyManager} which selects the named certificate
   * from the provided {@code X509KeyManager}.
   *
   * @param alias
   *          The nickname of the certificate that should be selected for
   *          operations involving this key manager.
   * @param keyManager
   *          The key manager to be filtered.
   * @return The filtered key manager.
   * @throws NullPointerException
   *           If {@code keyManager} or {@code alias} was {@code null}.
   */
  public static X509KeyManager useSingleCertificate(final String alias,
      final X509KeyManager keyManager)
  {
    Validator.ensureNotNull(alias, keyManager);
    return new SelectCertificate(keyManager, alias);
  }
  // Prevent insantiation.
  private KeyManagers()
  {
    // Nothing to do.
  }
    // Prevent insantiation.
    private KeyManagers() {
        // Nothing to do.
    }
}