001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.tools;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.io.BufferedReader;
033    import java.io.InputStreamReader;
034    import java.io.IOException;
035    import java.security.cert.CertificateException;
036    import java.security.cert.X509Certificate;
037    import java.util.Date;
038    import javax.net.ssl.TrustManager;
039    import javax.net.ssl.X509TrustManager;
040    
041    import static org.opends.messages.ToolMessages.*;
042    import static org.opends.server.util.StaticUtils.*;
043    
044    
045    
046    /**
047     * This class provides an implementation of an X.509 trust manager which will
048     * interactively prompt the user (via the CLI) whether a given certificate
049     * should be trusted.  It should only be used by interactive command-line tools,
050     * since it will block until it gets a response from the user.
051     * <BR><BR>
052     * Note that this class is only intended for client-side use, and therefore may
053     * not be used by a server to determine whether a client certificate is trusted.
054     */
055    public class PromptTrustManager
056           implements X509TrustManager
057    {
058    
059    
060    
061      // The singleton trust manager array for this class.
062      private static TrustManager[] trustManagerArray =
063           new TrustManager[] { new PromptTrustManager() };
064    
065    
066    
067      /**
068       * Creates a new instance of this prompt trust manager.
069       */
070      private PromptTrustManager()
071      {
072        // No implementation is required.
073      }
074    
075    
076    
077      /**
078       * Retrieves the trust manager array that should be used to initialize an SSL
079       * context in cases where the user should be interactively prompted about
080       * whether to trust the server certificate.
081       *
082       * @return  The trust manager array that should be used to initialize an SSL
083       *          context in cases where the user should be interactively prompted
084       *          about whether to trust the server certificate.
085       */
086      public static TrustManager[] getTrustManagers()
087      {
088        return trustManagerArray;
089      }
090    
091    
092    
093      /**
094       * Determines whether an SSL client with the provided certificate chain should
095       * be trusted.  This implementation is not intended for server-side use, and
096       * therefore this method will always throw an exception.
097       *
098       * @param  chain     The certificate chain for the SSL client.
099       * @param  authType  The authentication type based on the client certificate.
100       *
101       * @throws  CertificateException  To indicate that the provided client
102       *                                certificate is not trusted.
103       */
104      public void checkClientTrusted(X509Certificate[] chain, String authType)
105             throws CertificateException
106      {
107        Message message = ERR_PROMPTTM_REJECTING_CLIENT_CERT.get();
108        throw new CertificateException(message.toString());
109      }
110    
111    
112    
113      /**
114       * Determines whether an SSL server with the provided certificate chain should
115       * be trusted.  In this case, the user will be interactively prompted as to
116       * whether the certificate should be trusted.
117       *
118       * @param  chain     The certificate chain for the SSL server.
119       * @param  authType  The key exchange algorithm used.
120       *
121       * @throws  CertificateException  If the user rejects the certificate.
122       */
123      public void checkServerTrusted(X509Certificate[] chain, String authType)
124             throws CertificateException
125      {
126        if ((chain == null) || (chain.length == 0))
127        {
128          System.out.println(WARN_PROMPTTM_NO_SERVER_CERT_CHAIN.get());
129        }
130        else
131        {
132          Date currentDate   = new Date();
133          Date notAfterDate  = chain[0].getNotAfter();
134          Date notBeforeDate = chain[0].getNotBefore();
135    
136          if (currentDate.after(notAfterDate))
137          {
138            Message message = WARN_PROMPTTM_CERT_EXPIRED.get(
139                    String.valueOf(notAfterDate));
140            System.err.println(message);
141          }
142          else if (currentDate.before(notBeforeDate))
143          {
144            Message message = WARN_PROMPTTM_CERT_NOT_YET_VALID.get(
145                    String.valueOf(notBeforeDate));
146            System.err.println(message);
147          }
148    
149          System.out.println(INFO_PROMPTTM_SERVER_CERT.get(
150                  chain[0].getSubjectDN().getName(),
151                  chain[0].getIssuerDN().getName(),
152                  String.valueOf(notBeforeDate),
153                  String.valueOf(notAfterDate)));
154        }
155    
156    
157        Message prompt = INFO_PROMPTTM_YESNO_PROMPT.get();
158        BufferedReader reader =
159             new BufferedReader(new InputStreamReader(System.in));
160        while (true)
161        {
162          try
163          {
164            System.out.print(prompt);
165            String line = reader.readLine().toLowerCase();
166            if (line.equals("y") || line.equals("yes"))
167            {
168              // Returning without an exception is sufficient to consider the
169              // certificate trusted.
170              return;
171            }
172            else if (line.equals("n") || line.equals("no"))
173            {
174              Message message = ERR_PROMPTTM_USER_REJECTED.get();
175              throw new CertificateException(message.toString());
176            }
177          } catch (IOException ioe) {}
178    
179          System.out.println();
180        }
181      }
182    
183    
184    
185      /**
186       * Retrieves the set of certificate authority certificates which are trusted
187       * for authenticating peers.
188       *
189       * @return  An empty array, since we don't care what certificates are
190       *          presented because we will always prompt the user.
191       */
192      public X509Certificate[] getAcceptedIssuers()
193      {
194        return new X509Certificate[0];
195      }
196    }
197