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