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 legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2008-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2009 Parametric Technology Corporation (PTC)
026 *      Portions Copyright 2014-2015 ForgeRock AS
027 */
028
029package org.opends.admin.ads.util;
030
031import java.net.Socket;
032import java.security.KeyStore;
033import java.security.KeyStoreException;
034import java.security.NoSuchAlgorithmException;
035import java.security.NoSuchProviderException;
036import java.security.Principal;
037import java.security.PrivateKey;
038import java.security.UnrecoverableKeyException;
039import java.security.cert.X509Certificate;
040
041import org.forgerock.i18n.LocalizableMessage;
042import org.forgerock.i18n.slf4j.LocalizedLogger;
043
044import javax.net.ssl.KeyManager;
045import javax.net.ssl.KeyManagerFactory;
046import javax.net.ssl.TrustManagerFactory;
047import javax.net.ssl.X509KeyManager;
048
049import org.opends.server.util.Platform;
050
051
052/**
053 * This class is in charge of checking whether the certificates that are
054 * presented are trusted or not.
055 * This implementation tries to check also that the subject DN of the
056 * certificate corresponds to the host passed using the setHostName method.
057 *
058 * The constructor tries to use a default TrustManager from the system and if
059 * it cannot be retrieved this class will only accept the certificates
060 * explicitly accepted by the user (and specified by calling acceptCertificate).
061 *
062 * NOTE: this class is not aimed to be used when we have connections in parallel.
063 */
064public class ApplicationKeyManager implements X509KeyManager
065{
066  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
067
068  /**
069   * The default keyManager.
070   */
071  private X509KeyManager keyManager;
072
073  /**
074   * The default constructor.
075   * @param keystore The keystore to use for this keymanager.
076   * @param password The keystore password to use for this keymanager.
077   */
078  public ApplicationKeyManager(KeyStore keystore, char[] password)
079  {
080    KeyManagerFactory kmf = null;
081    String userSpecifiedAlgo =
082      System.getProperty("org.opends.admin.keymanageralgo");
083    String userSpecifiedProvider =
084      System.getProperty("org.opends.admin.keymanagerprovider");
085
086    //Handle IBM specific cases if the user did not specify a algorithm and/or
087    //provider.
088    if(userSpecifiedAlgo == null && Platform.isVendor("IBM"))
089    {
090      userSpecifiedAlgo = "IbmX509";
091    }
092    if(userSpecifiedProvider == null && Platform.isVendor("IBM"))
093    {
094      userSpecifiedProvider = "IBMJSSE2";
095    }
096
097    // Have some fallbacks to choose the provider and algorith of the key
098    // manager.  First see if the user wanted to use something specific,
099    // then try with the SunJSSE provider and SunX509 algorithm. Finally,
100    // fallback to the default algorithm of the JVM.
101    String[] preferredProvider =
102        { userSpecifiedProvider, "SunJSSE", null, null };
103    String[] preferredAlgo =
104        { userSpecifiedAlgo, "SunX509", "SunX509",
105          TrustManagerFactory.getDefaultAlgorithm() };
106
107    for (int i=0; i<preferredProvider.length && keyManager == null; i++)
108    {
109      String provider = preferredProvider[i];
110      String algo = preferredAlgo[i];
111      if (algo == null)
112      {
113        continue;
114      }
115      try
116      {
117        if (provider != null)
118        {
119          kmf = KeyManagerFactory.getInstance(algo, provider);
120        }
121        else
122        {
123          kmf = KeyManagerFactory.getInstance(algo);
124        }
125        kmf.init(keystore, password);
126        KeyManager kms[] = kmf.getKeyManagers();
127        /*
128         * Iterate over the returned keymanagers, look for an instance
129         * of X509KeyManager. If found, use that as our "default" key
130         * manager.
131         */
132        for (int j = 0; j < kms.length; j++)
133        {
134          if (kms[i] instanceof X509KeyManager)
135          {
136            keyManager = (X509KeyManager) kms[j];
137            break;
138          }
139        }
140      }
141      catch (NoSuchAlgorithmException e)
142      {
143        // Nothing to do. Maybe we should avoid this and be strict, but we are
144        // in a best effort mode.
145        logger.warn(LocalizableMessage.raw("Error with the algorithm", e));
146      }
147      catch (KeyStoreException e)
148      {
149        // Nothing to do. Maybe we should avoid this and be strict, but we are
150        // in a best effort mode.
151        logger.warn(LocalizableMessage.raw("Error with the keystore", e));
152      }
153      catch (UnrecoverableKeyException e)
154      {
155        // Nothing to do. Maybe we should avoid this and be strict, but we are
156        // in a best effort mode.
157        logger.warn(LocalizableMessage.raw("Error with the key", e));
158      }
159      catch (NoSuchProviderException e)
160      {
161        // Nothing to do. Maybe we should avoid this and be strict, but we are
162        // in a best effort mode.
163        logger.warn(LocalizableMessage.raw("Error with the provider", e));
164      }
165    }
166  }
167
168
169  /**
170   * Choose an alias to authenticate the client side of a secure
171   * socket given the public key type and the list of certificate
172   * issuer authorities recognized by the peer (if any).
173   *
174   * @param keyType
175   *          the key algorithm type name(s), ordered with the
176   *          most-preferred key type first.
177   * @param issuers
178   *          the list of acceptable CA issuer subject names or null
179   *          if it does not matter which issuers are used.
180   * @param socket
181   *          the socket to be used for this connection. This
182   *          parameter can be null, in which case this method will
183   *          return the most generic alias to use.
184   * @return the alias name for the desired key, or null if there are
185   *         no matches.
186   */
187  public String chooseClientAlias(String[] keyType, Principal[] issuers,
188      Socket socket)
189  {
190    if (keyManager != null)
191    {
192      return keyManager.chooseClientAlias(keyType, issuers, socket);
193    }
194    return null;
195  }
196
197  /**
198   * Choose an alias to authenticate the client side of a secure
199   * socket given the public key type and the list of certificate
200   * issuer authorities recognized by the peer (if any).
201   *
202   * @param keyType
203   *          the key algorithm type name(s), ordered with the
204   *          most-preferred key type first.
205   * @param issuers
206   *          the list of acceptable CA issuer subject names or null
207   *          if it does not matter which issuers are used.
208   * @param socket
209   *          the socket to be used for this connection. This
210   *          parameter can be null, in which case this method will
211   *          return the most generic alias to use.
212   * @return the alias name for the desired key, or null if there are
213   *         no matches.
214   */
215  public String chooseServerAlias(String keyType, Principal[] issuers,
216      Socket socket)
217  {
218    if (keyManager != null)
219    {
220      return keyManager.chooseServerAlias(keyType, issuers, socket);
221    }
222    return null;
223  }
224
225  /**
226   * Returns the certificate chain associated with the given alias.
227   *
228   * @param alias
229   *          the alias name
230   * @return the certificate chain (ordered with the user's
231   *         certificate first and the root certificate authority
232   *         last), or null if the alias can't be found.
233   */
234  public X509Certificate[] getCertificateChain(String alias)
235  {
236    if (keyManager != null)
237    {
238      return keyManager.getCertificateChain(alias);
239    }
240    return null;
241  }
242
243  /**
244   * Get the matching aliases for authenticating the server side of a
245   * secure socket given the public key type and the list of
246   * certificate issuer authorities recognized by the peer (if any).
247   *
248   * @param keyType
249   *          the key algorithm type name
250   * @param issuers
251   *          the list of acceptable CA issuer subject names or null
252   *          if it does not matter which issuers are used.
253   * @return an array of the matching alias names, or null if there
254   *         were no matches.
255   */
256  public String[] getClientAliases(String keyType, Principal[] issuers)
257  {
258    if (keyManager != null)
259    {
260      return keyManager.getClientAliases(keyType, issuers);
261    }
262    return null;
263  }
264
265  /**
266   * Returns the key associated with the given alias.
267   *
268   * @param alias
269   *          the alias name
270   * @return the requested key, or null if the alias can't be found.
271   */
272  public PrivateKey getPrivateKey(String alias)
273  {
274    if (keyManager != null)
275    {
276      return keyManager.getPrivateKey(alias);
277    }
278    return null;
279  }
280
281  /**
282   * Get the matching aliases for authenticating the server side of a
283   * secure socket given the public key type and the list of
284   * certificate issuer authorities recognized by the peer (if any).
285   *
286   * @param keyType
287   *          the key algorithm type name
288   * @param issuers
289   *          the list of acceptable CA issuer subject names or null
290   *          if it does not matter which issuers are used.
291   * @return an array of the matching alias names, or null if there
292   *         were no matches.
293   */
294  public String[] getServerAliases(String keyType, Principal[] issuers)
295  {
296    if (keyManager != null)
297    {
298      return keyManager.getServerAliases(keyType, issuers);
299    }
300    return null;
301  }
302}