001/*
002 * Copyright 2008-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2018 Ping Identity Corporation
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  @Override()
131  public final synchronized String[] getClientAliases(final String keyType,
132                                          final Principal[] issuers)
133  {
134    final LinkedHashSet<String> clientAliases = new LinkedHashSet<String>();
135
136    for (final X509KeyManager m : keyManagers)
137    {
138      final String[] aliases = m.getClientAliases(keyType, issuers);
139      if (aliases != null)
140      {
141        clientAliases.addAll(Arrays.asList(aliases));
142      }
143    }
144
145    if (clientAliases.isEmpty())
146    {
147      return null;
148    }
149    else
150    {
151      final String[] aliases = new String[clientAliases.size()];
152      return clientAliases.toArray(aliases);
153    }
154  }
155
156
157
158  /**
159   * Retrieves the nickname of the certificate that a client should use to
160   * authenticate to a server.
161   *
162   * @param  keyType  The list of key algorithm names that may be used.
163   * @param  issuers  The list of acceptable issuer certificate subjects.  It
164   *                  may be {@code null} if any issuer may be used.
165   * @param  socket   The socket to be used.  It may be {@code null} if the
166   *                  certificate may be for any socket.
167   *
168   * @return  The nickname of the certificate to use, or {@code null} if no
169   *          appropriate certificate is found.
170   */
171  @Override()
172  public final synchronized String chooseClientAlias(final String[] keyType,
173                                        final Principal[] issuers,
174                                        final Socket socket)
175  {
176    if (certificateAlias == null)
177    {
178      for (final X509KeyManager m : keyManagers)
179      {
180        final String alias = m.chooseClientAlias(keyType, issuers, socket);
181        if (alias != null)
182        {
183          return alias;
184        }
185      }
186
187      return null;
188    }
189    else
190    {
191      for (final String s : keyType)
192      {
193        for (final X509KeyManager m : keyManagers)
194        {
195          final String[] aliases = m.getClientAliases(s, issuers);
196          if (aliases != null)
197          {
198            for (final String alias : aliases)
199            {
200              if (alias.equals(certificateAlias))
201              {
202                return certificateAlias;
203              }
204            }
205          }
206        }
207      }
208
209      return null;
210    }
211  }
212
213
214
215  /**
216   * Retrieves the nickname of the certificate that a client should use to
217   * authenticate to a server.
218   *
219   * @param  keyType  The list of key algorithm names that may be used.
220   * @param  issuers  The list of acceptable issuer certificate subjects.  It
221   *                  may be {@code null} if any issuer may be used.
222   * @param  engine   The SSL engine to be used.  It may be {@code null} if the
223   *                  certificate may be for any engine.
224   *
225   * @return  The nickname of the certificate to use, or {@code null} if no
226   *          appropriate certificate is found.
227   */
228  @Override()
229  public final synchronized String chooseEngineClientAlias(
230                                        final String[] keyType,
231                                        final Principal[] issuers,
232                                        final SSLEngine engine)
233  {
234    if (certificateAlias == null)
235    {
236      for (final X509KeyManager m : keyManagers)
237      {
238        if (m instanceof X509ExtendedKeyManager)
239        {
240          final X509ExtendedKeyManager em = (X509ExtendedKeyManager) m;
241          final String alias =
242               em.chooseEngineClientAlias(keyType, issuers, engine);
243          if (alias != null)
244          {
245            return alias;
246          }
247        }
248        else
249        {
250          final String alias = m.chooseClientAlias(keyType, issuers, null);
251          if (alias != null)
252          {
253            return alias;
254          }
255        }
256      }
257
258      return null;
259    }
260    else
261    {
262      for (final String s : keyType)
263      {
264        for (final X509KeyManager m : keyManagers)
265        {
266          final String[] aliases = m.getClientAliases(s, issuers);
267          if (aliases != null)
268          {
269            for (final String alias : aliases)
270            {
271              if (alias.equals(certificateAlias))
272              {
273                return certificateAlias;
274              }
275            }
276          }
277        }
278      }
279
280      return null;
281    }
282  }
283
284
285
286  /**
287   * Retrieves the nicknames of the server certificates of the specified type
288   * contained in the key store.
289   *
290   * @param  keyType  The key algorithm name for which to retrieve the available
291   *                  certificate nicknames.
292   * @param  issuers  The list of acceptable issuer certificate subjects.  It
293   *                  may be {@code null} if any issuer may be used.
294   *
295   * @return  The nicknames of the server certificates, or {@code null} if none
296   *          were found in the key store.
297   */
298  @Override()
299  public final synchronized String[] getServerAliases(final String keyType,
300                                          final Principal[] issuers)
301  {
302    final LinkedHashSet<String> serverAliases = new LinkedHashSet<String>();
303
304    for (final X509KeyManager m : keyManagers)
305    {
306      final String[] aliases = m.getServerAliases(keyType, issuers);
307      if (aliases != null)
308      {
309        serverAliases.addAll(Arrays.asList(aliases));
310      }
311    }
312
313    if (serverAliases.isEmpty())
314    {
315      return null;
316    }
317    else
318    {
319      final String[] aliases = new String[serverAliases.size()];
320      return serverAliases.toArray(aliases);
321    }
322  }
323
324
325
326  /**
327   * Retrieves the nickname of the certificate that a server should use to
328   * authenticate to a client.
329   *
330   * @param  keyType  The key algorithm name that may be used.
331   * @param  issuers  The list of acceptable issuer certificate subjects.  It
332   *                  may be {@code null} if any issuer may be used.
333   * @param  socket   The socket to be used.  It may be {@code null} if the
334   *                  certificate may be for any socket.
335   *
336   * @return  The nickname of the certificate to use, or {@code null} if no
337   *          appropriate certificate is found.
338   */
339  @Override()
340  public final synchronized String chooseServerAlias(final String keyType,
341                                        final Principal[] issuers,
342                                        final Socket socket)
343  {
344    if (certificateAlias == null)
345    {
346      for (final X509KeyManager m : keyManagers)
347      {
348        final String alias = m.chooseServerAlias(keyType, issuers, socket);
349        if (alias != null)
350        {
351          return alias;
352        }
353      }
354
355      return null;
356    }
357    else
358    {
359      for (final X509KeyManager m : keyManagers)
360      {
361        final String[] aliases = m.getServerAliases(keyType, issuers);
362        if (aliases != null)
363        {
364          for (final String alias : aliases)
365          {
366            if (alias.equals(certificateAlias))
367            {
368              return certificateAlias;
369            }
370          }
371        }
372      }
373
374      return null;
375    }
376  }
377
378
379
380  /**
381   * Retrieves the nickname of the certificate that a server should use to
382   * authenticate to a client.
383   *
384   * @param  keyType  The key algorithm name that may be used.
385   * @param  issuers  The list of acceptable issuer certificate subjects.  It
386   *                  may be {@code null} if any issuer may be used.
387   * @param  engine   The SSL engine to be used.  It may be {@code null} if the
388   *                  certificate may be for any engine.
389   *
390   * @return  The nickname of the certificate to use, or {@code null} if no
391   *          appropriate certificate is found.
392   */
393  @Override()
394  public final synchronized String chooseEngineServerAlias(final String keyType,
395                                        final Principal[] issuers,
396                                        final SSLEngine engine)
397  {
398    if (certificateAlias == null)
399    {
400      for (final X509KeyManager m : keyManagers)
401      {
402        if (m instanceof X509ExtendedKeyManager)
403        {
404          final X509ExtendedKeyManager em = (X509ExtendedKeyManager) m;
405          final String alias =
406               em.chooseEngineServerAlias(keyType, issuers, engine);
407          if (alias != null)
408          {
409            return alias;
410          }
411        }
412        else
413        {
414          final String alias = m.chooseServerAlias(keyType, issuers, null);
415          if (alias != null)
416          {
417            return alias;
418          }
419        }
420      }
421
422      return null;
423    }
424    else
425    {
426      for (final X509KeyManager m : keyManagers)
427      {
428        final String[] aliases = m.getServerAliases(keyType, issuers);
429        if (aliases != null)
430        {
431          for (final String alias : aliases)
432          {
433            if (alias.equals(certificateAlias))
434            {
435              return certificateAlias;
436            }
437          }
438        }
439      }
440
441      return null;
442    }
443  }
444
445
446
447  /**
448   * Retrieves the certificate chain for the certificate with the given
449   * nickname.
450   *
451   * @param  alias  The nickname of the certificate for which to retrieve the
452   *                certificate chain.
453   *
454   * @return  The certificate chain for the certificate with the given nickname,
455   *          or {@code null} if the requested certificate cannot be found.
456   */
457  @Override()
458  public final synchronized X509Certificate[] getCertificateChain(
459                                                   final String alias)
460  {
461    for (final X509KeyManager m : keyManagers)
462    {
463      final X509Certificate[] chain = m.getCertificateChain(alias);
464      if (chain != null)
465      {
466        return chain;
467      }
468    }
469
470    return null;
471  }
472
473
474
475  /**
476   * Retrieves the private key for the specified certificate.
477   *
478   * @param  alias  The nickname of the certificate for which to retrieve the
479   *                private key.
480   *
481   * @return  The private key for the requested certificate, or {@code null} if
482   *          the requested certificate cannot be found.
483   */
484  @Override()
485  public final synchronized PrivateKey getPrivateKey(final String alias)
486  {
487    for (final X509KeyManager m : keyManagers)
488    {
489      final PrivateKey key = m.getPrivateKey(alias);
490      if (key != null)
491      {
492        return key;
493      }
494    }
495
496    return null;
497  }
498}