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

neil_a_wilson
23.44.2007 ab94ee3be44c717c93bfc63da2b89fc174a8a725
Add a new SSL trust manager that can be used to interactively prompt the user
about whether a given SSL certificate should be trusted. This will be used for
all of our client tools in the case when no trust store is available and the
user has not requested the "--trustAll" option.

OpenDS Issue Number: 1274
1 files added
2 files modified
317 ■■■■■ changed files
opends/src/server/org/opends/server/messages/ToolMessages.java 96 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/PromptTrustManager.java 217 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/SSLConnectionFactory.java 4 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -33,6 +33,7 @@
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.tools.ToolConstants.*;
import static org.opends.server.util.DynamicConstants.*;
import static org.opends.server.util.ServerConstants.*;
@@ -7568,6 +7569,74 @@
  /**
   * The message ID for the message that will be used if the prompt trust
   * manager is asked about trusting a client certificate.  This does not take
   * any arguments.
   */
  public static final int MSGID_PROMPTTM_REJECTING_CLIENT_CERT =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 795;
  /**
   * The message ID for the message that will be used if the server did not
   * present a certificate chain.  This does not take any arguments.
   */
  public static final int MSGID_PROMPTTM_NO_SERVER_CERT_CHAIN =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 796;
  /**
   * The message ID for the message that will be used if the server certificate
   * is expired.  This takes a single argument, which is a string representation
   * of the "notAfter" date.
   */
  public static final int MSGID_PROMPTTM_CERT_EXPIRED =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 797;
  /**
   * The message ID for the message that will be used if the server certificate
   * is not yet valid.  This takes a single argument, which is a string
   * representation of the "notBefore" date.
   */
  public static final int MSGID_PROMPTTM_CERT_NOT_YET_VALID =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 798;
  /**
   * The message ID for the message that will be used to provide details about
   * the server certificate.  This takes four arguments, which are the string
   * representations of the certificate's subject DN, issuer DN, validity start
   * date, and validity end date.
   */
  public static final int MSGID_PROMPTTM_SERVER_CERT =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 799;
  /**
   * The message ID for the message that will be used to prompt the user to
   * enter "yes" or "no".  This does not take any arguments.
   */
  public static final int MSGID_PROMPTTM_YESNO_PROMPT =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 800;
  /**
   * The message ID for the message that will be used if the user rejected the
   * certificate presented by the server.  This does not take any arguments.
   */
  public static final int MSGID_PROMPTTM_USER_REJECTED =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 801;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
   */
@@ -9886,6 +9955,33 @@
    registerMessage(MSGID_LISTBACKENDS_CANNOT_DETERMINE_BASES_FOR_BACKEND,
                    "Unable to determine the set of base DNs defined in " +
                    "backend configuration entry %s:  %s.");
    registerMessage(MSGID_PROMPTTM_REJECTING_CLIENT_CERT,
                    "Rejecting client certificate chain because the prompt " +
                    "trust manager may only be used to trust server " +
                    "certificates.");
    registerMessage(MSGID_PROMPTTM_NO_SERVER_CERT_CHAIN,
                    "WARNING:  The server did not present a certificate " +
                    "chain.  Do you still wish to attempt connecting to the " +
                    "target server?");
    registerMessage(MSGID_PROMPTTM_CERT_EXPIRED,
                    "WARNING:  The server certificate is expired (expiration " +
                    "time:  %s).");
    registerMessage(MSGID_PROMPTTM_CERT_NOT_YET_VALID,
                    "WARNING:  The server certificate will not be valid " +
                    "until %s.");
    registerMessage(MSGID_PROMPTTM_SERVER_CERT,
                    "The server is using the following certificate:  " + EOL +
                    "    Subject DN:  %s" + EOL +
                    "    Issuer DN:  %s" + EOL +
                    "    Validity:  %s through %s" + EOL +
                    "Do you wish to trust this certificate and continue " +
                    "connecting to the server?");
    registerMessage(MSGID_PROMPTTM_YESNO_PROMPT,
                    "Please enter \"yes\" or \"no\":  ");
    registerMessage(MSGID_PROMPTTM_USER_REJECTED,
                    "The server certificate has been rejected by the user.");
  }
}
opends/src/server/org/opends/server/tools/PromptTrustManager.java
New file
@@ -0,0 +1,217 @@
/*
 * 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.tools;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.messages.ToolMessages.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * This class provides an implementation of an X.509 trust manager which will
 * interactively prompt the user (via the CLI) whether a given certificate
 * should be trusted.  It should only be used by interactive command-line tools,
 * since it will block until it gets a response from the user.
 * <BR><BR>
 * Note that this class is only intended for client-side use, and therefore may
 * not be used by a server to determine whether a client certificate is trusted.
 */
public class PromptTrustManager
       implements X509TrustManager
{
  /**
   * The fully-qualified name of this class for debugging purposes.
   */
  private static final String CLASS_NAME =
       "org.opends.server.tools.PromptTrustManager";
  // The singleton trust manager array for this class.
  private static TrustManager[] trustManagerArray =
       new TrustManager[] { new PromptTrustManager() };
  /**
   * Creates a new instance of this prompt trust manager.
   */
  private PromptTrustManager()
  {
    assert debugConstructor(CLASS_NAME);
    // No implementation is required.
  }
  /**
   * Retrieves the trust manager array that should be used to initialize an SSL
   * context in cases where the user should be interactively prompted about
   * whether to trust the server certificate.
   *
   * @return  The trust manager array that should be used to initialize an SSL
   *          context in cases where the user should be interactively prompted
   *          about whether to trust the server certificate.
   */
  public static TrustManager[] getTrustManagers()
  {
    assert debugEnter(CLASS_NAME, "getTrustManagers");
    return trustManagerArray;
  }
  /**
   * Determines whether an SSL client with the provided certificate chain should
   * be trusted.  This implementation is not intended for server-side use, and
   * therefore this method will always throw an exception.
   *
   * @param  chain     The certificate chain for the SSL client.
   * @param  authType  The authentication type based on the client certificate.
   *
   * @throws  CertificateException  To indicate that the provided client
   *                                certificate is not trusted.
   */
  public void checkClientTrusted(X509Certificate[] chain, String authType)
         throws CertificateException
  {
    assert debugEnter(CLASS_NAME, "checkClientTrusted",
                      String.valueOf(chain), String.valueOf(authType));
    int    msgID   = MSGID_PROMPTTM_REJECTING_CLIENT_CERT;
    String message = getMessage(msgID);
    throw new CertificateException(message);
  }
  /**
   * Determines whether an SSL server with the provided certificate chain should
   * be trusted.  In this case, the user will be interactively prompted as to
   * whether the certificate should be trusted.
   *
   * @param  chain     The certificate chain for the SSL server.
   * @param  authType  The key exchange algorithm used.
   *
   * @throws  CertificateException  If the user rejects the certificate.
   */
  public void checkServerTrusted(X509Certificate[] chain, String authType)
         throws CertificateException
  {
    assert debugEnter(CLASS_NAME, "checkServerTrusted",
                      String.valueOf(chain), String.valueOf(authType));
    if ((chain == null) || (chain.length == 0))
    {
      System.out.println(getMessage(MSGID_PROMPTTM_NO_SERVER_CERT_CHAIN));
    }
    else
    {
      Date currentDate   = new Date();
      Date notAfterDate  = chain[0].getNotAfter();
      Date notBeforeDate = chain[0].getNotBefore();
      if (currentDate.after(notAfterDate))
      {
        int    msgID   = MSGID_PROMPTTM_CERT_EXPIRED;
        String message = getMessage(msgID, String.valueOf(notAfterDate));
        System.err.println(message);
      }
      else if (currentDate.before(notBeforeDate))
      {
        int    msgID   = MSGID_PROMPTTM_CERT_NOT_YET_VALID;
        String message = getMessage(msgID, String.valueOf(notBeforeDate));
        System.err.println(message);
      }
      System.out.println(getMessage(MSGID_PROMPTTM_SERVER_CERT,
                                    chain[0].getSubjectDN().getName(),
                                    chain[0].getIssuerDN().getName(),
                                    String.valueOf(notBeforeDate),
                                    String.valueOf(notAfterDate)));
    }
    String prompt = getMessage(MSGID_PROMPTTM_YESNO_PROMPT);
    BufferedReader reader =
         new BufferedReader(new InputStreamReader(System.in));
    while (true)
    {
      try
      {
        System.out.print(prompt);
        String line = reader.readLine().toLowerCase();
        if (line.equals("y") || line.equals("yes"))
        {
          // Returning without an exception is sufficient to consider the
          // certificate trusted.
          return;
        }
        else if (line.equals("n") || line.equals("no"))
        {
          int msgID = MSGID_PROMPTTM_USER_REJECTED;
          String message = getMessage(msgID);
          throw new CertificateException(message);
        }
      } catch (IOException ioe) {}
      System.out.println();
    }
  }
  /**
   * Retrieves the set of certificate authority certificates which are trusted
   * for authenticating peers.
   *
   * @return  An empty array, since we don't care what certificates are
   *          presented because we will always prompt the user.
   */
  public X509Certificate[] getAcceptedIssuers()
  {
    assert debugEnter(CLASS_NAME, "getAcceptedIssuers");
    return new X509Certificate[0];
  }
}
opends/src/server/org/opends/server/tools/SSLConnectionFactory.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;
@@ -97,6 +97,8 @@
        BlindTrustManagerProvider blindTrustProvider =
            new BlindTrustManagerProvider();
        trustManagers = blindTrustProvider.getTrustManagers();
      } else if (trustStorePath == null) {
        trustManagers = PromptTrustManager.getTrustManagers();
      } else
      {
        trustManagers = getTrustManagers(KeyStore.getDefaultType(),