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