001/*
002 * Copyright 2008-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.util.ssl;
022
023
024
025import java.net.Socket;
026import java.security.Principal;
027import java.security.PrivateKey;
028import java.security.cert.X509Certificate;
029import java.util.Arrays;
030import java.util.LinkedHashSet;
031import javax.net.ssl.KeyManager;
032import javax.net.ssl.SSLEngine;
033import javax.net.ssl.X509ExtendedKeyManager;
034import javax.net.ssl.X509KeyManager;
035
036import com.unboundid.util.NotExtensible;
037import com.unboundid.util.ThreadSafety;
038import com.unboundid.util.ThreadSafetyLevel;
039
040
041
042/**
043 * This class provides an SSL key manager that may be used to wrap a provided
044 * set of key managers.  It provides the ability to select the desired
045 * certificate based on a given nickname.
046 */
047@NotExtensible()
048@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
049public abstract class WrapperKeyManager
050       extends X509ExtendedKeyManager
051{
052  // The nickname of the certificate that should be selected.
053  private final String certificateAlias;
054
055  // The set of key managers that will be used to perform the processing.
056  private final X509KeyManager[] keyManagers;
057
058
059
060  /**
061   * Creates a new instance of this wrapper key manager with the provided
062   * information.
063   *
064   * @param  keyManagers       The set of key managers to be wrapped.  It must
065   *                           not be {@code null} or empty, and it must contain
066   *                           only X509KeyManager instances.
067   * @param  certificateAlias  The nickname of the certificate that should be
068   *                           selected.  It may be {@code null} if any
069   *                           acceptable certificate found may be used.
070   */
071  protected WrapperKeyManager(final KeyManager[] keyManagers,
072                              final String certificateAlias)
073  {
074    this.certificateAlias = certificateAlias;
075
076    this.keyManagers = new X509KeyManager[keyManagers.length];
077    for (int i=0; i < keyManagers.length; i++)
078    {
079      this.keyManagers[i] = (X509KeyManager) keyManagers[i];
080    }
081  }
082
083
084
085  /**
086   * Creates a new instance of this wrapper key manager with the provided
087   * information.
088   *
089   * @param  keyManagers       The set of key managers to be wrapped.  It must
090   *                           not be {@code null} or empty.
091   * @param  certificateAlias  The nickname of the certificate that should be
092   *                           selected.  It may be {@code null} if any
093   *                           acceptable certificate found may be used.
094   */
095  protected WrapperKeyManager(final X509KeyManager[] keyManagers,
096                              final String certificateAlias)
097  {
098    this.keyManagers      = keyManagers;
099    this.certificateAlias = certificateAlias;
100  }
101
102
103
104  /**
105   * Retrieves the nickname of the certificate that should be selected.
106   *
107   * @return  The nickname of the certificate that should be selected, or
108   *          {@code null} if any acceptable certificate found in the key store
109   *          may be used.
110   */
111  public String getCertificateAlias()
112  {
113    return certificateAlias;
114  }
115
116
117
118  /**
119   * Retrieves the nicknames of the client certificates of the specified type
120   * contained in the key store.
121   *
122   * @param  keyType  The key algorithm name for which to retrieve the available
123   *                  certificate nicknames.
124   * @param  issuers  The list of acceptable issuer certificate subjects.  It
125   *                  may be {@code null} if any issuer may be used.
126   *
127   * @return  The nicknames of the client certificates, or {@code null} if none
128   *          were found in the key store.
129   */
130  public final synchronized String[] getClientAliases(final String keyType,
131                                          final Principal[] issuers)
132  {
133    final LinkedHashSet<String> clientAliases = new LinkedHashSet<String>();
134
135    for (final X509KeyManager m : keyManagers)
136    {
137      final String[] aliases = m.getClientAliases(keyType, issuers);
138      if (aliases != null)
139      {
140        clientAliases.addAll(Arrays.asList(aliases));
141      }
142    }
143
144    if (clientAliases.isEmpty())
145    {
146      return null;
147    }
148    else
149    {
150      final String[] aliases = new String[clientAliases.size()];
151      return clientAliases.toArray(aliases);
152    }
153  }
154
155
156
157  /**
158   * Retrieves the nickname of the certificate that a client should use to
159   * authenticate to a server.
160   *
161   * @param  keyType  The list of key algorithm names that may be used.
162   * @param  issuers  The list of acceptable issuer certificate subjects.  It
163   *                  may be {@code null} if any issuer may be used.
164   * @param  socket   The socket to be used.  It may be {@code null} if the
165   *                  certificate may be for any socket.
166   *
167   * @return  The nickname of the certificate to use, or {@code null} if no
168   *          appropriate certificate is found.
169   */
170  public final synchronized String chooseClientAlias(final String[] keyType,
171                                        final Principal[] issuers,
172                                        final Socket socket)
173  {
174    if (certificateAlias == null)
175    {
176      for (final X509KeyManager m : keyManagers)
177      {
178        final String alias = m.chooseClientAlias(keyType, issuers, socket);
179        if (alias != null)
180        {
181          return alias;
182        }
183      }
184
185      return null;
186    }
187    else
188    {
189      for (final String s : keyType)
190      {
191        for (final X509KeyManager m : keyManagers)
192        {
193          final String[] aliases = m.getClientAliases(s, issuers);
194          if (aliases != null)
195          {
196            for (final String alias : aliases)
197            {
198              if (alias.equals(certificateAlias))
199              {
200                return certificateAlias;
201              }
202            }
203          }
204        }
205      }
206
207      return null;
208    }
209  }
210
211
212
213  /**
214   * Retrieves the nickname of the certificate that a client should use to
215   * authenticate to a server.
216   *
217   * @param  keyType  The list of key algorithm names that may be used.
218   * @param  issuers  The list of acceptable issuer certificate subjects.  It
219   *                  may be {@code null} if any issuer may be used.
220   * @param  engine   The SSL engine to be used.  It may be {@code null} if the
221   *                  certificate may be for any engine.
222   *
223   * @return  The nickname of the certificate to use, or {@code null} if no
224   *          appropriate certificate is found.
225   */
226  @Override()
227  public final synchronized String chooseEngineClientAlias(
228                                        final String[] keyType,
229                                        final Principal[] issuers,
230                                        final SSLEngine engine)
231  {
232    if (certificateAlias == null)
233    {
234      for (final X509KeyManager m : keyManagers)
235      {
236        if (m instanceof X509ExtendedKeyManager)
237        {
238          final X509ExtendedKeyManager em = (X509ExtendedKeyManager) m;
239          final String alias =
240               em.chooseEngineClientAlias(keyType, issuers, engine);
241          if (alias != null)
242          {
243            return alias;
244          }
245        }
246        else
247        {
248          final String alias = m.chooseClientAlias(keyType, issuers, null);
249          if (alias != null)
250          {
251            return alias;
252          }
253        }
254      }
255
256      return null;
257    }
258    else
259    {
260      for (final String s : keyType)
261      {
262        for (final X509KeyManager m : keyManagers)
263        {
264          final String[] aliases = m.getClientAliases(s, issuers);
265          if (aliases != null)
266          {
267            for (final String alias : aliases)
268            {
269              if (alias.equals(certificateAlias))
270              {
271                return certificateAlias;
272              }
273            }
274          }
275        }
276      }
277
278      return null;
279    }
280  }
281
282
283
284  /**
285   * Retrieves the nicknames of the server certificates of the specified type
286   * contained in the key store.
287   *
288   * @param  keyType  The key algorithm name for which to retrieve the available
289   *                  certificate nicknames.
290   * @param  issuers  The list of acceptable issuer certificate subjects.  It
291   *                  may be {@code null} if any issuer may be used.
292   *
293   * @return  The nicknames of the server certificates, or {@code null} if none
294   *          were found in the key store.
295   */
296  public final synchronized String[] getServerAliases(final String keyType,
297                                          final Principal[] issuers)
298  {
299    final LinkedHashSet<String> serverAliases = new LinkedHashSet<String>();
300
301    for (final X509KeyManager m : keyManagers)
302    {
303      final String[] aliases = m.getServerAliases(keyType, issuers);
304      if (aliases != null)
305      {
306        serverAliases.addAll(Arrays.asList(aliases));
307      }
308    }
309
310    if (serverAliases.isEmpty())
311    {
312      return null;
313    }
314    else
315    {
316      final String[] aliases = new String[serverAliases.size()];
317      return serverAliases.toArray(aliases);
318    }
319  }
320
321
322
323  /**
324   * Retrieves the nickname of the certificate that a server should use to
325   * authenticate to a client.
326   *
327   * @param  keyType  The key algorithm name that may be used.
328   * @param  issuers  The list of acceptable issuer certificate subjects.  It
329   *                  may be {@code null} if any issuer may be used.
330   * @param  socket   The socket to be used.  It may be {@code null} if the
331   *                  certificate may be for any socket.
332   *
333   * @return  The nickname of the certificate to use, or {@code null} if no
334   *          appropriate certificate is found.
335   */
336  public final synchronized String chooseServerAlias(final String keyType,
337                                        final Principal[] issuers,
338                                        final Socket socket)
339  {
340    if (certificateAlias == null)
341    {
342      for (final X509KeyManager m : keyManagers)
343      {
344        final String alias = m.chooseServerAlias(keyType, issuers, socket);
345        if (alias != null)
346        {
347          return alias;
348        }
349      }
350
351      return null;
352    }
353    else
354    {
355      for (final X509KeyManager m : keyManagers)
356      {
357        final String[] aliases = m.getServerAliases(keyType, issuers);
358        if (aliases != null)
359        {
360          for (final String alias : aliases)
361          {
362            if (alias.equals(certificateAlias))
363            {
364              return certificateAlias;
365            }
366          }
367        }
368      }
369
370      return null;
371    }
372  }
373
374
375
376  /**
377   * Retrieves the nickname of the certificate that a server should use to
378   * authenticate to a client.
379   *
380   * @param  keyType  The key algorithm name that may be used.
381   * @param  issuers  The list of acceptable issuer certificate subjects.  It
382   *                  may be {@code null} if any issuer may be used.
383   * @param  engine   The SSL engine to be used.  It may be {@code null} if the
384   *                  certificate may be for any engine.
385   *
386   * @return  The nickname of the certificate to use, or {@code null} if no
387   *          appropriate certificate is found.
388   */
389  @Override()
390  public final synchronized String chooseEngineServerAlias(final String keyType,
391                                        final Principal[] issuers,
392                                        final SSLEngine engine)
393  {
394    if (certificateAlias == null)
395    {
396      for (final X509KeyManager m : keyManagers)
397      {
398        if (m instanceof X509ExtendedKeyManager)
399        {
400          final X509ExtendedKeyManager em = (X509ExtendedKeyManager) m;
401          final String alias =
402               em.chooseEngineServerAlias(keyType, issuers, engine);
403          if (alias != null)
404          {
405            return alias;
406          }
407        }
408        else
409        {
410          final String alias = m.chooseServerAlias(keyType, issuers, null);
411          if (alias != null)
412          {
413            return alias;
414          }
415        }
416      }
417
418      return null;
419    }
420    else
421    {
422      for (final X509KeyManager m : keyManagers)
423      {
424        final String[] aliases = m.getServerAliases(keyType, issuers);
425        if (aliases != null)
426        {
427          for (final String alias : aliases)
428          {
429            if (alias.equals(certificateAlias))
430            {
431              return certificateAlias;
432            }
433          }
434        }
435      }
436
437      return null;
438    }
439  }
440
441
442
443  /**
444   * Retrieves the certificate chain for the certificate with the given
445   * nickname.
446   *
447   * @param  alias  The nickname of the certificate for which to retrieve the
448   *                certificate chain.
449   *
450   * @return  The certificate chain for the certificate with the given nickname,
451   *          or {@code null} if the requested certificate cannot be found.
452   */
453  public final synchronized X509Certificate[] getCertificateChain(
454                                                   final String alias)
455  {
456    for (final X509KeyManager m : keyManagers)
457    {
458      final X509Certificate[] chain = m.getCertificateChain(alias);
459      if (chain != null)
460      {
461        return chain;
462      }
463    }
464
465    return null;
466  }
467
468
469
470  /**
471   * Retrieves the private key for the specified certificate.
472   *
473   * @param  alias  The nickname of the certificate for which to retrieve the
474   *                private key.
475   *
476   * @return  The private key for the requested certificate, or {@code null} if
477   *          the requested certificate cannot be found.
478   */
479  public final synchronized PrivateKey getPrivateKey(final String alias)
480  {
481    for (final X509KeyManager m : keyManagers)
482    {
483      final PrivateKey key = m.getPrivateKey(alias);
484      if (key != null)
485      {
486        return key;
487      }
488    }
489
490    return null;
491  }
492}