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

lutoff
11.50.2007 58d668e476b45ccdac9fce119f398d151d292ebe
Fix for issue #2240
1 files added
4 files modified
677 ■■■■■ changed files
opendj-sdk/opends/src/ads/org/opends/admin/ads/util/ApplicationTrustManager.java 29 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/ads/org/opends/admin/ads/util/OpendsCertificationException.java 96 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/messages/messages/utility.properties 17 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java 109 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/util/cli/LDAPConnectionConsoleInteraction.java 426 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/ads/org/opends/admin/ads/util/ApplicationTrustManager.java
@@ -163,7 +163,10 @@
      lastRefusedChain = chain;
      lastRefusedAuthType = authType;
      lastRefusedCause = Cause.NOT_TRUSTED;
      throw ce;
      OpendsCertificationException e = new OpendsCertificationException(
          chain);
      e.initCause(ce);
      throw e;
    }
    if (!explicitlyAccepted)
@@ -177,7 +180,10 @@
        lastRefusedChain = chain;
        lastRefusedAuthType = authType;
        lastRefusedCause = Cause.HOST_NAME_MISMATCH;
        throw ce;
        OpendsCertificationException e = new OpendsCertificationException(
            chain);
        e.initCause(ce);
        throw e;
      }
    }
  }
@@ -214,7 +220,9 @@
      lastRefusedChain = chain;
      lastRefusedAuthType = authType;
      lastRefusedCause = Cause.NOT_TRUSTED;
      throw ce;
      OpendsCertificationException e = new OpendsCertificationException(chain);
      e.initCause(ce);
      throw e;
    }
    if (!explicitlyAccepted)
@@ -228,7 +236,10 @@
        lastRefusedChain = chain;
        lastRefusedAuthType = authType;
        lastRefusedCause = Cause.HOST_NAME_MISMATCH;
        throw ce;
        OpendsCertificationException e = new OpendsCertificationException(
            chain);
        e.initCause(ce);
        throw e;
      }
    }
  }
@@ -334,8 +345,8 @@
    }
    if (!found)
    {
      throw new CertificateException(
          "Certificate not in list of accepted certificates");
      throw new OpendsCertificationException(
          "Certificate not in list of accepted certificates", chain);
    }
  }
@@ -368,8 +379,10 @@
      if (!matches)
      {
        throw new CertificateException("Hostname mismatch between host name "+
            host+" and subject DN: "+chain[0].getSubjectX500Principal());
        throw new OpendsCertificationException(
            "Hostname mismatch between host name " + host
                + " and subject DN: " + chain[0].getSubjectX500Principal(),
            chain);
      }
    }
  }
opendj-sdk/opends/src/ads/org/opends/admin/ads/util/OpendsCertificationException.java
New file
@@ -0,0 +1,96 @@
/*
 * 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.admin.ads.util;
//
// J2SE
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate ;
/**
 * When a remote client (dsconfig for instance) wants to establish a
 * remote connection with opends server through a secure connection,
 * and if the certificate is not known, the SSL handcheck fails and
 * this exception is thrown. This allows to get the certificate chain
 * which is unknown.
 */
public class OpendsCertificationException extends CertificateException
{
  /**
   * The serial version UUID.
   */
  private static final long serialVersionUID = 1151044344529478436L;
  // ------------------
  // Private certificate chain
  // ------------------
  private X509Certificate[] chain;
  // ------------------
  // Constructor
  // ------------------
  /**
   * Build a new OpendsCertificationException object.
   *
   * @param chain the certificate chain which is unknown and has caused
   *        the SSL handcheck failure.
   */
  public OpendsCertificationException(X509Certificate[] chain)
  {
    super();
    this.chain = chain;
  }
  /**
   * Build a new OpendsCertificationException object.
   *
   * @param msg the detail message string of this exception.
   *
   * @param chain the certificate chain which is unknown and has caused
   *        the SSL handcheck failure.
   */
  public OpendsCertificationException(String msg, X509Certificate[] chain)
  {
    super(msg);
    this.chain = chain;
  }
  /**
   * Return the certificate chain which is unknown and has caused
   * the SSL handcheck failure.
   *
   * @return the certificate chain which is unknown and has caused
   *        the SSL handcheck failure.
   */
  public X509Certificate[] getChain()
  {
    return chain;
  }
}
opendj-sdk/opends/src/messages/messages/utility.properties
@@ -506,8 +506,8 @@
INFO_LDAP_CONN_PROMPT_SECURITY_LDAP_226=LDAP
INFO_LDAP_CONN_PROMPT_SECURITY_USE_SSL_227=LDAP with SSL
INFO_LDAP_CONN_PROMPT_SECURITY_USE_START_TSL_228=LDAP with StartTSL
INFO_LDAP_CONN_PROMPT_SECURITY_USE_TRUST_ALL_229=Do you want to automatically \
  trust the server certificate?
INFO_LDAP_CONN_PROMPT_SECURITY_USE_TRUST_ALL_229=Automatically \
  trust
INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PATH_230=Truststore path:
INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PASSWORD_231=Password for \
  truststore '%s':
@@ -531,3 +531,16 @@
INFO_LDAP_CONN_PROMPT_SECURITY_PROTOCOL_DEFAULT_CHOICE_243=%d
SEVERE_ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH_244=The provided path \
  is not valid
INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_METHOD_245=How do you want to trust the server certificate?
INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_246=Use a truststore
INFO_LDAP_CONN_PROMPT_SECURITY_MANUAL_CHECK_247=Manually validate
INFO_LDAP_CONN_PROMPT_SECURITY_SERVER_CERTIFICATE_248=Server Certificate:
INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_249=%s
INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_250=Do you trust this server certificate?
INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_NO_251=No
INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_SESSION_252=Yes, for this session only
INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_ALWAYS_253=Yes, also add it to a truststore
INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_DETAILS_254=View certificate details
INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_USER_DN_255 =User DN  : %s
INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_VALIDITY_256=Validity : From '%s'%n             To '%s'
INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_ISSUER_257  =Issuer   : %s
opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java
@@ -26,8 +26,9 @@
 */
package org.opends.server.tools.dsconfig;
import org.opends.admin.ads.util.ConnectionUtils;
import org.opends.admin.ads.util.OpendsCertificationException;
import static org.opends.messages.DSConfigMessages.*;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
@@ -101,38 +102,96 @@
      {
        InitialLdapContext ctx;
        String ldapsUrl = "ldaps://" + hostName + ":" + portNumber;
        try
        while (true)
        {
          ctx = ConnectionUtils.createLdapsContext(ldapsUrl, bindDN,
              bindPassword, ConnectionUtils.getDefaultLDAPTimeout(), null,
              trustManager, keyManager);
          conn = JNDIDirContextAdaptor.adapt(ctx);
        }
        catch (NamingException e)
        {
          Message message = ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(
              hostName, String.valueOf(portNumber));
          throw new ClientException(LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR,
              message) ;
          try
          {
            ctx = ConnectionUtils.createLdapsContext(ldapsUrl, bindDN,
                bindPassword, ConnectionUtils.getDefaultLDAPTimeout(), null,
                trustManager, keyManager);
            conn = JNDIDirContextAdaptor.adapt(ctx);
            break;
          }
          catch (NamingException e)
          {
            if ( app.isInteractive() && ci.isTrustStoreInMemory())
            {
              if ((e.getRootCause() != null)
                  && (e.getRootCause().getCause()
                      instanceof OpendsCertificationException))
              {
                OpendsCertificationException oce =
                  (OpendsCertificationException) e.getRootCause().getCause();
                  if (ci.checkServerCertificate(oce.getChain()))
                  {
                    // If the certificate is trusted, update the trust manager.
                    trustManager = ci.getTrustManager();
                    // Try to connect again.
                    continue ;
                  }
              }
              else
              {
                Message message = ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(
                    hostName, String.valueOf(portNumber));
                throw new ClientException(
                    LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR, message);
              }
            }
            Message message = ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(
                hostName, String.valueOf(portNumber));
            throw new ClientException(
                LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR, message);
          }
        }
      }
      else if (ci.useStartTLS())
      {
        InitialLdapContext ctx;
        String ldapUrl = "ldap://" + hostName + ":" + portNumber;
        try
        while (true)
        {
          ctx = ConnectionUtils.createStartTLSContext(ldapUrl, bindDN,
              bindPassword, ConnectionUtils.getDefaultLDAPTimeout(), null,
              trustManager, keyManager, null);
          conn = JNDIDirContextAdaptor.adapt(ctx);
        }
        catch (NamingException e)
        {
          Message message = ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(
              hostName, String.valueOf(portNumber));
          throw new ClientException(LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR,
              message) ;
          try
          {
            ctx = ConnectionUtils.createStartTLSContext(ldapUrl, bindDN,
                bindPassword, ConnectionUtils.getDefaultLDAPTimeout(), null,
                trustManager, keyManager, null);
            conn = JNDIDirContextAdaptor.adapt(ctx);
            break;
          }
          catch (NamingException e)
          {
            if ( app.isInteractive() && ci.isTrustStoreInMemory())
            {
              if ((e.getRootCause() != null)
                  && (e.getRootCause().getCause()
                      instanceof OpendsCertificationException))
              {
                OpendsCertificationException oce =
                  (OpendsCertificationException) e.getRootCause().getCause();
                  if (ci.checkServerCertificate(oce.getChain()))
                  {
                    // If the certificate is trusted, update the trust manager.
                    trustManager = ci.getTrustManager();
                    // Try to connect again.
                    continue ;
                  }
              }
              else
              {
                Message message = ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(
                    hostName, String.valueOf(portNumber));
                throw new ClientException(
                    LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR, message);
              }
            }
            Message message = ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(
                hostName, String.valueOf(portNumber));
            throw new ClientException(
                LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR, message);
          }
        }
      }
      else
opendj-sdk/opends/src/server/org/opends/server/util/cli/LDAPConnectionConsoleInteraction.java
@@ -43,7 +43,11 @@
import java.net.UnknownHostException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.X509Certificate;
/**
 * Supports interacting with a user through the command line to
@@ -69,6 +73,12 @@
  // the Console application
  private ConsoleApplication app;
  // Indicate if the truststore in in memory
  private boolean trustStoreInMemory = false;
  // The truststore to use for the SSL or STARTTLS connection
  private KeyStore truststore;
  /**
   * Enumeration description protocols for interactive CLI choices.
   */
@@ -118,6 +128,105 @@
  }
  /**
   * Enumeration description protocols for interactive CLI choices.
   */
  private enum TrustMethod
  {
    TRUSTALL(1, INFO_LDAP_CONN_PROMPT_SECURITY_USE_TRUST_ALL.get()),
    TRUSTSTORE(2,INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE.get()),
    DISPLAY_CERTIFICATE(3,INFO_LDAP_CONN_PROMPT_SECURITY_MANUAL_CHECK.get());
    private Integer choice;
    private Message msg;
    /**
     * Private constructor.
     *
     * @param i
     *          the menu return value.
     * @param s
     *          the message message.
     */
    private TrustMethod(int i, Message msg)
    {
      choice = new Integer(i);
      this.msg = msg;
    }
    /**
     * Returns the choice number.
     *
     * @return the attribute name.
     */
    public Integer getChoice()
    {
      return choice;
    }
    /**
     * Return the menu message.
     *
     * @return the menu message.
     */
    public Message getMenuMessage()
    {
      return msg;
    }
  }
  /**
   * Enumeration description server certificate trust option.
   */
  private enum TrustOption
  {
    UNTRUSTED(1, INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_NO.get()),
    SESSION(2,INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_SESSION.get()),
    PERMAMENT(3,INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_ALWAYS.get()),
    CERTIFICATE_DETAILS(4,
        INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_DETAILS.get());
    private Integer choice;
    private Message msg;
    /**
     * Private constructor.
     *
     * @param i
     *          the menu return value.
     * @param s
     *          the message message.
     */
    private TrustOption(int i, Message msg)
    {
      choice = new Integer(i);
      this.msg = msg;
    }
    /**
     * Returns the choice number.
     *
     * @return the attribute name.
     */
    public Integer getChoice()
    {
      return choice;
    }
    /**
     * Return the menu message.
     *
     * @return the menu message.
     */
    public Message getMenuMessage()
    {
      return msg;
    }
  }
  /**
   * Constructs a parameterized instance.
   *
   * @param app console application
@@ -480,8 +589,25 @@
  private ApplicationTrustManager getTrustManagerInternal()
  throws ArgumentException
  {
    boolean trustAll = secureArgsList.trustAllArg.isPresent();
    if (app.isInteractive() && !secureArgsList.trustAllArg.isPresent())
    // If we have the trustALL flag, don't do anything
    // just return null
    if (secureArgsList.trustAllArg.isPresent())
    {
      return null;
    }
      // Check if some trust manager info are set
    boolean weDontKnowTheTrustMethod =
      !(  secureArgsList.trustAllArg.isPresent()
          ||
          secureArgsList.trustStorePathArg.isPresent()
          ||
          secureArgsList.trustStorePasswordArg.isPresent()
          ||
          secureArgsList.trustStorePasswordFileArg.isPresent()
        );
    boolean askForTrustStore = false;
    if (app.isInteractive() && weDontKnowTheTrustMethod)
    {
      if (!isHeadingDisplayed)
      {
@@ -491,29 +617,73 @@
        isHeadingDisplayed = true;
      }
      app.println();
      MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app);
      builder.setPrompt(INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_METHOD.get());
      TrustMethod defaultTrustMethod = TrustMethod.DISPLAY_CERTIFICATE;
      for (TrustMethod t : TrustMethod.values())
      {
        int i = builder.addNumberedOption(t.getMenuMessage(), MenuResult
            .success(t.getChoice()));
        if (t.equals(defaultTrustMethod))
        {
          builder.setDefault(
              INFO_LDAP_CONN_PROMPT_SECURITY_PROTOCOL_DEFAULT_CHOICE
                  .get(new Integer(i)), MenuResult.success(t.getChoice()));
        }
      }
      Menu<Integer> menu = builder.toMenu();
      trustStoreInMemory = false;
      try
      {
        app.println();
        trustAll = app.confirmAction(
                INFO_LDAP_CONN_PROMPT_SECURITY_USE_TRUST_ALL.get(), false);
        MenuResult<Integer> result = menu.run();
        if (result.isSuccess())
        {
          if (result.getValue().equals(TrustMethod.TRUSTALL.getChoice()))
          {
            // If we have the trustALL flag, don't do anything
            // just return null
            return null;
          }
          else if (result.getValue().equals(
              TrustMethod.TRUSTSTORE.getChoice()))
          {
            // We have to ask for truststore info
            askForTrustStore = true;
          }
          else if (result.getValue().equals(
              TrustMethod.DISPLAY_CERTIFICATE.getChoice()))
          {
            // The certificate will be displayed to the user
            askForTrustStore = false;
            trustStoreInMemory = true;
          }
          else
          {
            // Should never happen.
            throw new RuntimeException();
          }
        }
        else
        {
          // Should never happen.
          throw new RuntimeException();
        }
      }
      catch (CLIException e)
      {
        // Should never happen.
        throw new RuntimeException(e);
      }
    }
    // Trust everything, so no trust manager
    if (trustAll)
    {
      return null;
      }
    }
    // If we not trust all server certificates, we have to get info
    // about truststore. First get the truststore path.
    String truststorePath = secureArgsList.trustStorePathArg.getValue();
    if (app.isInteractive() && !secureArgsList.trustStorePathArg.isPresent())
    if (app.isInteractive() && !secureArgsList.trustStorePathArg.isPresent()
        && askForTrustStore)
    {
      if (!isHeadingDisplayed)
      {
@@ -610,17 +780,24 @@
    // We'we got all the information to get the truststore manager
    try
    {
      FileInputStream fos = new FileInputStream(truststorePath);
      KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
      if (truststorePassword != null)
      truststore = KeyStore.getInstance(KeyStore.getDefaultType());
      if (truststorePath != null)
      {
        truststore.load(fos, truststorePassword.toCharArray());
        FileInputStream fos = new FileInputStream(truststorePath);
        if (truststorePassword != null)
        {
          truststore.load(fos, truststorePassword.toCharArray());
        }
        else
        {
          truststore.load(fos, null);
        }
        fos.close();
      }
      else
      {
        truststore.load(fos, null);
        truststore.load(null, null);
      }
      fos.close();
      return new ApplicationTrustManager(truststore);
    }
    catch (Exception e)
@@ -890,6 +1067,217 @@
    return this.keyManager;
  }
  /**
   * Indicate if the truststore is in memory.
   *
   * @return true if the truststore is in memory.
   */
  public boolean isTrustStoreInMemory() {
    return this.trustStoreInMemory;
  }
  /**
   * Indicate if the certificate chain can be trusted.
   *
   * @param chain The certificate chain to validate
   * @return true if the server certificate is trusted.
   */
  public boolean checkServerCertificate(X509Certificate[] chain)
  {
    app.println();
    app.println(INFO_LDAP_CONN_PROMPT_SECURITY_SERVER_CERTIFICATE.get());
    app.println();
    for (int i = 0; i < chain.length; i++)
    {
      // Certificate DN
      app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_USER_DN.get(
          chain[i].getSubjectDN().toString()));
      // certificate validity
      app.println(
          INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_VALIDITY.get(
              chain[i].getNotBefore().toString(),
              chain[i].getNotAfter().toString()));
      // certificate Issuer
      app.println(
          INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_ISSUER.get(
              chain[i].getIssuerDN().toString()));
      if (i+1 <chain.length)
      {
        app.println();
        app.println();
      }
    }
    MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app);
    builder.setPrompt(INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION.get());
    TrustOption defaultTrustMethod = TrustOption.SESSION ;
    for (TrustOption t : TrustOption.values())
    {
      int i = builder.addNumberedOption(t.getMenuMessage(), MenuResult
          .success(t.getChoice()));
      if (t.equals(defaultTrustMethod))
      {
        builder.setDefault(
            INFO_LDAP_CONN_PROMPT_SECURITY_PROTOCOL_DEFAULT_CHOICE
                .get(new Integer(i)), MenuResult.success(t.getChoice()));
      }
    }
    app.println();
    app.println();
    Menu<Integer> menu = builder.toMenu();
    while (true)
    {
      try
      {
        MenuResult<Integer> result = menu.run();
        if (result.isSuccess())
        {
          if (result.getValue().equals(TrustOption.UNTRUSTED.getChoice()))
          {
            return false;
          }
          if ((result.getValue().equals(TrustOption.CERTIFICATE_DETAILS
              .getChoice())))
          {
            for (int i = 0; i < chain.length; i++)
            {
              app.println();
              app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE
                  .get(chain[i].toString()));
            }
            continue;
          }
          // We should add it in the memory truststore
          for (int i = 0; i < chain.length; i++)
          {
            String alias = chain[i].getSubjectDN().getName();
            try
            {
              truststore.setCertificateEntry(alias, chain[i]);
            }
            catch (KeyStoreException e1)
            {
              // What should we do else?
              return false;
            }
          }
          // Update the trust manager
          trustManager = new ApplicationTrustManager(truststore);
          if (result.getValue().equals(TrustOption.PERMAMENT.getChoice()))
          {
            ValidationCallback<String> callback =
              new ValidationCallback<String>()
            {
              public String validate(ConsoleApplication app, String input)
                  throws CLIException
              {
                String ninput = input.trim();
                if (ninput.length() == 0)
                {
                  app.println();
                  app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH
                      .get());
                  app.println();
                  return null;
                }
                File f = new File(ninput);
                if (!f.isDirectory())
                {
                  return ninput;
                }
                else
                {
                  app.println();
                  app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH
                      .get());
                  app.println();
                  return null;
                }
              }
            };
            String truststorePath;
            try
            {
              app.println();
              truststorePath = app.readValidatedInput(
                  INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PATH.get(),
                  callback);
            }
            catch (CLIException e)
            {
              return true;
            }
            // Read the password from the stdin.
            String truststorePassword;
            try
            {
              app.println();
              Message prompt = INFO_LDAP_CONN_PROMPT_SECURITY_KEYSTORE_PASSWORD
                  .get(truststorePath);
              truststorePassword = app.readPassword(prompt);
            }
            catch (Exception e)
            {
              return true;
            }
            try
            {
              KeyStore ts = KeyStore.getInstance("JKS");
              FileInputStream fis;
              try
              {
                fis = new FileInputStream(truststorePath);
              }
              catch (FileNotFoundException e)
              {
                fis = null;
              }
              ts.load(fis, truststorePassword.toCharArray());
              if (fis != null)
              {
                fis.close();
              }
              for (int i = 0; i < chain.length; i++)
              {
                String alias = chain[i].getSubjectDN().getName();
                ts.setCertificateEntry(alias, chain[i]);
              }
              FileOutputStream fos = new FileOutputStream(truststorePath);
              ts.store(fos, truststorePassword.toCharArray());
              if (fos != null)
              {
                fos.close();
              }
            }
            catch (Exception e)
            {
              return true;
            }
          }
          return true;
        }
        else
        {
          // Should never happen.
          throw new RuntimeException();
        }
      }
      catch (CLIException cliE)
      {
        throw new RuntimeException(cliE);
      }
    }
  }
}