001/*
002 * Copyright 2008-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2008-2024 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-2024 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.io.File;
041import java.lang.reflect.Constructor;
042import java.lang.reflect.Method;
043import java.security.KeyStoreException;
044import java.security.KeyStore;
045import java.security.Provider;
046import java.security.Security;
047import javax.net.ssl.KeyManager;
048import javax.net.ssl.KeyManagerFactory;
049
050import com.unboundid.util.CryptoHelper;
051import com.unboundid.util.Debug;
052import com.unboundid.util.NotMutable;
053import com.unboundid.util.NotNull;
054import com.unboundid.util.Nullable;
055import com.unboundid.util.StaticUtils;
056import com.unboundid.util.ThreadSafety;
057import com.unboundid.util.ThreadSafetyLevel;
058
059import static com.unboundid.util.ssl.SSLMessages.*;
060
061
062
063/**
064 * This class provides an SSL key manager that may be used to interact with
065 * PKCS #11 tokens.
066 */
067@NotMutable()
068@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
069public final class PKCS11KeyManager
070       extends WrapperKeyManager
071{
072  /**
073   * The default key store type to use when accessing PKCS #11 tokens.
074   */
075  @NotNull public static final String DEFAULT_KEY_STORE_TYPE = "PKCS11";
076
077
078
079  /**
080   * The fully-qualified name of the default provider class
081   * ({@code sun.security.pkcs11.SunPKCS11}) to use when accessing PKCS #11
082   * tokens.
083   */
084  @NotNull public static final String DEFAULT_PROVIDER_CLASS =
085       "sun.security.pkcs11.SunPKCS11";
086
087
088
089  /**
090   * The provider service type that will be used for key store implementations.
091   */
092  @NotNull private static final String SERVICE_TYPE_KEY_STORE = "KeyStore";
093
094
095
096  /**
097   * The name used for the SunJSSE provider.
098   */
099  @NotNull private static final String SUN_JSSE_PROVIDER_NAME = "SunJSSE";
100
101
102
103  /**
104   * The JSSE provider that should be used when interacting with PKCS #11
105   * tokens.  This may be {@code null} if we can't automatically determine an
106   * appropriate provider.
107   */
108  @Nullable private static final Provider PKCS11_JSSE_PROVIDER;
109  static
110  {
111    // NOTE:  Even when we're operating in FIPS 140-2-compliant mode, we will
112    // likely want to use the SunJSSE provider in conjunction with PKCS #11
113    // tokens because the Bouncy Castle FIPS-compliant BCJSSE provider does not
114    // work well in conjunction with PKCS #11 tokens.
115    final Provider sunJSSEProvider =
116         Security.getProvider(SUN_JSSE_PROVIDER_NAME);
117    if (sunJSSEProvider != null)
118    {
119      PKCS11_JSSE_PROVIDER = sunJSSEProvider;
120    }
121    else
122    {
123      // Select the first provider that offers support for TLSv1.3.  If we
124      // can't find one, then select the first provider that offer support for
125      // TLSv1.2.
126      Provider tls13Provider = null;
127      Provider tls12Provider = null;
128      for (final Provider provider : Security.getProviders())
129      {
130        if (provider.getService(SSLUtil.PROVIDER_SERVICE_TYPE_SSL_CONTEXT,
131             SSLUtil.SSL_PROTOCOL_TLS_1_3) != null)
132        {
133          tls13Provider = provider;
134          break;
135        }
136        else if (provider.getService(SSLUtil.PROVIDER_SERVICE_TYPE_SSL_CONTEXT,
137             SSLUtil.SSL_PROTOCOL_TLS_1_2) != null)
138        {
139          tls12Provider = provider;
140        }
141      }
142
143      if (tls13Provider != null)
144      {
145        PKCS11_JSSE_PROVIDER = tls13Provider;
146      }
147      else
148      {
149        PKCS11_JSSE_PROVIDER = tls12Provider;
150      }
151    }
152  }
153
154
155
156  /**
157   * Creates a new instance of this PKCS #11 key manager with the provided
158   * information.
159   *
160   * @param  keyStorePIN        The user PIN to use to access the PKCS #11
161   *                            token.  This may be {@code null} if no PIN is
162   *                            required.
163   * @param  certificateAlias   The nickname for the key entry to use in the
164   *                            PKCS #11 token.  It may be {@code null} if any
165   *                            acceptable entry may be used.
166   *
167   * @throws  KeyStoreException  If a problem occurs while initializing this key
168   *                             manager.
169   */
170  public PKCS11KeyManager(@Nullable final char[] keyStorePIN,
171                          @Nullable final String certificateAlias)
172         throws KeyStoreException
173  {
174    this(getProvider(null, null, null, false), null, keyStorePIN,
175         certificateAlias);
176  }
177
178
179
180  /**
181   * Creates a new instance of this PKCS11 key manager with the provided
182   * information.
183   *
184   * @param  providerClassName   The fully-qualified name of the Java class that
185   *                             implements the provider to use to interact with
186   *                             the PKCS #11 module.  If this is {@code null},
187   *                             then the key manager will attempt to
188   *                             automatically identify the appropriate
189   *                             provider.
190   * @param  providerConfigFile  A file that contains the configuration to use
191   *                             for the provider.  This may be {@code null} if
192   *                             no provider configuration is needed, or if the
193   *                             provider is already properly instantiated.
194   * @param  keyStoreType        The name of the key store type to use when
195   *                             interacting with the PKCS #11 token.  If this
196   *                             is {@code null}, then a default key store type
197   *                             of {@code PKCS11} will be used.
198   * @param  keyStorePIN         The user PIN to use to access the PKCS #11
199   *                             token.  This may be {@code null} if no PIN is
200   *                             required.
201   * @param  certificateAlias    The nickname for the key entry to use in the
202   *                             PKCS #11 token.  It may be {@code null} if any
203   *                             acceptable entry may be used.
204   *
205   * @throws  KeyStoreException  If a problem occurs while initializing this
206   *                             key manager.
207   */
208  public PKCS11KeyManager(@Nullable final String providerClassName,
209                          @Nullable final File providerConfigFile,
210                          @Nullable final String keyStoreType,
211                          @Nullable final char[] keyStorePIN,
212                          @Nullable final String certificateAlias)
213         throws KeyStoreException
214  {
215    this(getProvider(providerClassName, providerConfigFile, keyStoreType,
216              false),
217         keyStoreType, keyStorePIN, certificateAlias);
218  }
219
220
221
222  /**
223   * Creates a new instance of this PKCS11 key manager with the provided
224   * information.
225   *
226   * @param  provider            The Java security provider to use to access the
227   *                             PKCS #11 token.  It must not be {@code null}.
228   * @param  keyStoreType        The name of the key store type to use when
229   *                             interacting with the PKCS #11 token.  If this
230   *                             is {@code null}, then a default key store type
231   *                             of {@code PKCS11} will be used.
232   * @param  keyStorePIN         The user PIN to use to access the PKCS #11
233   *                             token.  This may be {@code null} if no PIN is
234   *                             required.
235   * @param  certificateAlias    The nickname for the key entry to use in the
236   *                             PKCS #11 token.  It may be {@code null} if any
237   *                             acceptable entry may be used.
238   *
239   * @throws  KeyStoreException  If a problem occurs while initializing this
240   *                             key manager.
241   */
242  public PKCS11KeyManager(@NotNull final Provider provider,
243                          @Nullable final String keyStoreType,
244                          @Nullable final char[] keyStorePIN,
245                          @Nullable final String certificateAlias)
246         throws KeyStoreException
247  {
248    super(getKeyManagers(provider, keyStoreType, keyStorePIN),
249         certificateAlias);
250  }
251
252
253
254  /**
255   * Retrieves an instance of a Java security provider that may be used to
256   * interact with a PKCS #11 token.  If a suitable new provider instance is
257   * created, then it will be added to the JVM's configured list of providers.
258   *
259   * @param  providerClassName        The fully-qualified name of the Java class
260   *                                  to use for the provider.  If this is
261   *                                  {@code null}, then an attempt will be made
262   *                                  to automatically identify the appropriate
263   *                                  provider class.
264   * @param  providerConfigFile       A file that contains the configuration to
265   *                                  use for the provider.  This may be
266   *                                  {@code null} if no provider configuration
267   *                                  is needed, or if the provider is already
268   *                                  properly instantiated.
269   * @param  keyStoreType             The name of the key store type to use when
270   *                                  interacting with the PKCS #11 token.  If
271   *                                  this is {@code null}, then a default key
272   *                                  store type of {@code PKCS11} will be used.
273   * @param  alwaysCreateNewInstance  Indicates whether to always create a new
274   *                                  instance of the provider, even
275   *
276   * @return  The provider instance that should be used to interact with a
277   *          PKCS #11 token.
278   *
279   * @throws  KeyStoreException  If a problem occurs while retrieving the
280   */
281  @NotNull()
282  public static Provider getProvider(@Nullable final String providerClassName,
283                                     @Nullable final File providerConfigFile,
284                                     @Nullable final String keyStoreType,
285                                     final boolean alwaysCreateNewInstance)
286         throws KeyStoreException
287  {
288    final String ksType;
289    if (keyStoreType == null)
290    {
291      ksType = DEFAULT_KEY_STORE_TYPE;
292    }
293    else
294    {
295      ksType = keyStoreType;
296    }
297
298
299    // If no provider class was specified, then try to automatically determine
300    // the provider class to use.  Otherwise, try to load the provider class.
301    final Class<?> providerClass;
302    final Provider[] providers = Security.getProviders();
303    if (providerClassName == null)
304    {
305      providerClass = inferProviderClass(providers, ksType);
306    }
307    else
308    {
309      try
310      {
311        providerClass = Class.forName(providerClassName);
312      }
313      catch (final Exception e)
314      {
315        Debug.debugException(e);
316        throw new KeyStoreException(
317             ERR_PCKS11_NO_SUCH_PROVIDER_CLASS.get(providerClassName,
318                  StaticUtils.getExceptionMessage(e)), e);
319      }
320    }
321
322
323    // See if any of the already defined providers has the identified class.  If
324    // there is already a provider of that type loaded, and if it advertises
325    // support for the desired key store type, and if we either don't have a
326    // configuration file or don't need to always create a new instance, then
327    // just use the existing provider.
328    //
329    // don't need to always
330    // create a new instance, then just use the existing provider.
331    Provider provider = null;
332    for (final Provider p : providers)
333    {
334      if (p.getClass().getName().equals(providerClass.getName()))
335      {
336        provider = p;
337        if ((p.getService(SERVICE_TYPE_KEY_STORE, ksType) != null) &&
338             ((providerConfigFile == null) || (! alwaysCreateNewInstance)))
339        {
340          return p;
341        }
342        break;
343      }
344    }
345
346
347    // At this point, we know that we're going to need to create a new instance
348    // of the provider.  Get the default constructor for the provider class, if
349    // there is one.
350    Constructor<?> defaultConstructor = null;
351    try
352    {
353      defaultConstructor = providerClass.getConstructor();
354    }
355    catch (final Exception e)
356    {
357      Debug.debugException(e);
358    }
359
360
361    // If we don't have a configuration file, then there must be a default
362    // constructor.  Invoke it to create the provider, and make sure that it
363    // advertises support for the target key store type.
364    if (providerConfigFile == null)
365    {
366      if (defaultConstructor == null)
367      {
368        throw new KeyStoreException(
369             ERR_PKCS11_NO_DEFAULT_CONSTRUCTOR_NO_CONFIG.get(
370                  providerClass.getName(), ksType));
371      }
372
373      try
374      {
375        provider = (Provider) defaultConstructor.newInstance();
376      }
377      catch (final Exception e)
378      {
379        Debug.debugException(e);
380        throw new KeyStoreException(
381             ERR_PKCS11_CANNOT_INVOKE_DEFAULT_CONSTRUCTOR.get(
382                  providerClass.getName(), ksType,
383                  StaticUtils.getExceptionMessage(e)),
384             e);
385      }
386
387      if (provider.getService(SERVICE_TYPE_KEY_STORE, ksType) == null)
388      {
389        throw new KeyStoreException(
390             ERR_PKCS11_DEFAULT_CONSTRUCTOR_NO_KS_TYPE.get(
391                  providerClass.getName(), ksType));
392      }
393      else
394      {
395        Security.addProvider(provider);
396        return provider;
397      }
398    }
399
400
401    // We know that we need to configure the provider.  If the provider offers
402    // a public configure(String) method, then use it to accomplish that.
403    if (defaultConstructor != null)
404    {
405      Method configureMethod = null;
406      try
407      {
408        configureMethod = providerClass.getMethod("configure", String.class);
409      }
410      catch (final Exception e)
411      {
412        Debug.debugException(e);
413      }
414
415      if (configureMethod != null)
416      {
417        if (provider == null)
418        {
419          try
420          {
421            provider = (Provider) defaultConstructor.newInstance();
422          }
423          catch (final Exception e)
424          {
425            Debug.debugException(e);
426            throw new KeyStoreException(
427                 ERR_PKCS11_CANNOT_INVOKE_DEFAULT_CONSTRUCTOR.get(
428                      providerClass.getName(), ksType,
429                      StaticUtils.getExceptionMessage(e)),
430                 e);
431          }
432        }
433
434        final Provider configuredProvider;
435        try
436        {
437          configuredProvider = (Provider) configureMethod.invoke(provider,
438               providerConfigFile.getAbsolutePath());
439        }
440        catch (final Exception e)
441        {
442          Debug.debugException(e);
443          throw new KeyStoreException(
444               ERR_PKCS11_CANNOT_CONFIGURE_PROVIDER.get(
445                    providerClass.getName(),
446                    providerConfigFile.getAbsolutePath(),
447                    StaticUtils.getExceptionMessage(e)),
448               e);
449        }
450
451        if (configuredProvider.getService(SERVICE_TYPE_KEY_STORE, ksType) ==
452             null)
453        {
454          throw new KeyStoreException(
455               ERR_PKCS11_CONFIGURED_PROVIDER_NO_KS_TYPE.get(
456                    providerClass.getName(), ksType,
457                    providerConfigFile.getAbsolutePath()));
458        }
459        else
460        {
461          Security.addProvider(configuredProvider);
462          return configuredProvider;
463        }
464      }
465    }
466
467
468    // If we've gotten here, then our last hope is that there's a public
469    // constructor that takes a single String argument.  If there is, then
470    // invoke it with the path to the configuration file to create the provider.
471    final Constructor<?> stringConstructor;
472    try
473    {
474      stringConstructor = providerClass.getConstructor(String.class);
475    }
476    catch (final Exception e)
477    {
478      Debug.debugException(e);
479      throw new KeyStoreException(
480           ERR_PKCS11_NO_STRING_CONSTRUCTOR.get(providerClass.getName(),
481                providerConfigFile.getAbsolutePath(), ksType),
482           e);
483    }
484
485    final Provider configuredProvider;
486    try
487    {
488      configuredProvider = (Provider) stringConstructor.newInstance(
489           providerConfigFile.getAbsolutePath());
490    }
491    catch (final Exception e)
492    {
493      Debug.debugException(e);
494      throw new KeyStoreException(
495           ERR_PKCS11_CANNOT_INVOKE_STRING_CONSTRUCTOR.get(
496                providerClass.getName(), providerConfigFile.getAbsolutePath(),
497                ksType, StaticUtils.getExceptionMessage(e)),
498           e);
499    }
500
501
502    // Make sure that the configured provider advertises support for the
503    // key store type.
504    if (configuredProvider.getService(SERVICE_TYPE_KEY_STORE, ksType) == null)
505    {
506      throw new KeyStoreException(
507           ERR_PKCS11_CONFIGURED_PROVIDER_NO_KS_TYPE.get(
508                providerClass.getName(), ksType,
509                providerConfigFile.getAbsolutePath()));
510    }
511    else
512    {
513      Security.addProvider(configuredProvider);
514      return configuredProvider;
515    }
516  }
517
518
519
520  /**
521   * Attempts to infer the class for the PKCS #11 provider to use.
522   *
523   * @param  providers     The set of providers that have already been loaded in
524   *                       the JVM.  This must not be {@code null}.
525   * @param  keyStoreType  The name of the key store type to use when
526   *                       interacting with the PKCS #11 token.  This must not
527   *                       be {@code null}.
528   *
529   * @return  The class to use for the PKCS #11 provider.
530   *
531   * @throws  KeyStoreException  If no suitable class can be identified.
532   */
533  @NotNull()
534  private static Class<?> inferProviderClass(
535               @NotNull final Provider[] providers,
536               @NotNull final String keyStoreType)
537          throws KeyStoreException
538  {
539    // First, see if there is already a provider defined in the JVM that already
540    // advertises support for the specified key store type.
541    for (final Provider p : providers)
542    {
543      if (p.getService(SERVICE_TYPE_KEY_STORE, keyStoreType) != null)
544      {
545        return p.getClass();
546      }
547    }
548
549
550    // See if there is already a provider defined in the JVM whose provider or
551    // class name contains the string "PKCS11".
552    for (final Provider p : providers)
553    {
554      final Class<?> providerClass = p.getClass();
555      if (StaticUtils.toUpperCase(p.getName()).contains("PKCS11") ||
556           StaticUtils.toUpperCase(providerClass.getName()).contains("PKCS11"))
557      {
558        return providerClass;
559      }
560    }
561
562
563    // We couldn't find an existing provider that looks like it might support
564    // PKCS #11, so try to use the default provider class.
565    try
566    {
567      return Class.forName(DEFAULT_PROVIDER_CLASS);
568    }
569    catch (final Exception e)
570    {
571      Debug.debugException(e);
572      throw new KeyStoreException(
573           ERR_PKCS11_CANNOT_INFER_PROVIDER_CLASS.get(
574                DEFAULT_PROVIDER_CLASS),
575           e);
576    }
577  }
578
579
580
581  /**
582   * Retrieves the set of key managers that will be wrapped by this key manager.
583   *
584   * @param  provider      The Java security provider to use to access the PKCS
585   *                       #11 token.  It must not be {@code null}.
586   * @param  keyStoreType  The name of the key store type to use when
587   *                       interacting with the PKCS #11 token.  If this is
588   *                       {@code null}, then a default key store type of
589   *                       {@code PKCS11} will be used.
590   * @param  keyStorePIN   The user PIN to use to access the PKCS #11 token.
591   *                       This may be {@code null} if no PIN is required.
592   *
593   * @return  The set of key managers that will be wrapped by this key manager.
594   *
595   * @throws  KeyStoreException  If a problem occurs while initializing this key
596   *                             manager.
597   */
598  @NotNull()
599  private static KeyManager[] getKeyManagers(
600               @NotNull final Provider provider,
601               @Nullable final String keyStoreType,
602               @Nullable final char[] keyStorePIN)
603          throws KeyStoreException
604  {
605    final String ksType;
606    if (keyStoreType == null)
607    {
608      ksType = DEFAULT_KEY_STORE_TYPE;
609    }
610    else
611    {
612      ksType = keyStoreType;
613    }
614
615    final KeyStore ks = CryptoHelper.getKeyStore(ksType, provider);
616    try
617    {
618      ks.load(null, keyStorePIN);
619    }
620    catch (final Exception e)
621    {
622      Debug.debugException(e);
623
624      throw new KeyStoreException(
625           ERR_PKCS11_CANNOT_ACCESS.get(StaticUtils.getExceptionMessage(e)), e);
626    }
627
628    try
629    {
630      final KeyManagerFactory factory = CryptoHelper.getKeyManagerFactory();
631      factory.init(ks, keyStorePIN);
632      return factory.getKeyManagers();
633    }
634    catch (final Exception e)
635    {
636      Debug.debugException(e);
637
638      throw new KeyStoreException(
639           ERR_PKCS11_CANNOT_GET_KEY_MANAGERS.get(
640                StaticUtils.getExceptionMessage(e)),
641           e);
642    }
643  }
644
645
646
647  /**
648   * Retrieves an instance of a Java security provider that should be used when
649   * performing JSSE-related operations in conjunction with PKCS #11 tokens.
650   * The JVM's preferred JSSE provider may not be the best choice when using a
651   * PKCS #11 token (including when operating in FIPS-compliant mode).
652   *
653   * @return  An instance of a Java security provider that should be used when
654   *          performing JSSE-related operations in conjunction with PKCS #11
655   *          tokens.  It may be {@code null} if the best provider cannot be
656   *          determined.
657   */
658  @Nullable()
659  public static Provider getPKCS11JSSESProvider()
660  {
661    return PKCS11_JSSE_PROVIDER;
662  }
663}