Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2021-2024 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2021-2024 Ping Identity Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2021-2024 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.util.ssl;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.Socket;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import javax.net.ssl.X509KeyManager;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.util.CryptoHelper;
import com.unboundid.util.Debug;
import com.unboundid.util.DebugType;
import com.unboundid.util.NotMutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;
import com.unboundid.util.ssl.cert.CertException;
import com.unboundid.util.ssl.cert.PKCS8PEMFileReader;
import com.unboundid.util.ssl.cert.PKCS8PrivateKey;
import com.unboundid.util.ssl.cert.X509PEMFileReader;
import static com.unboundid.util.ssl.SSLMessages.*;
/**
* This class provides an implementation of an X.509 key manager that can obtain
* a certificate chain and private key from PEM files. This key manager will
* only support a single entry, and the alias for that entry will be a SHA-256
* fingerprint for the certificate. However, the certificate can be retrieved
* with any (or no) alias.
*/
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class PEMFileKeyManager
implements X509KeyManager, Serializable
{
/**
* The serial version UID for this serializable class.
*/
private static final long serialVersionUID = 1973401278035832777L;
/**
* The name of the digest algorithm that will be used to generate a
* certificate fingerprint for use as the alias.
*/
@NotNull private static final String ALIAS_FINGERPRINT_ALGORITHM = "SHA-256";
// The certificate chain read from PEM files.
@NotNull private final X509Certificate[] certificateChain;
// The private key read from a PEM file.
@NotNull private final PrivateKey privateKey;
// The alias that will be used for the certificate chain.
@NotNull private final String alias;
/**
* Creates a new instance of this key manager with the provided PEM files.
*
* @param certificateChainPEMFile
* The file containing the PEM-formatted X.509 representations of
* the certificates in the certificate chain. This must not be
* {@code null}, the file must exist, and it must contain at
* least one certificate (the end entity certificate), but may
* contain additional certificates as needed for the complete
* certificate chain. Certificates should be ordered such that
* the first certificate must be the end entity certificate, and
* each subsequent certificate must be the issuer for the
* previous certificate. The chain does not need to be complete
* as long as the peer may be expected to have prior knowledge of
* any missing issuer certificates.
* @param privateKeyPEMFile
* The file containing the PEM-formatted PKCS #8 representation
* of the private key for the end entity certificate. This must
* not be {@code null}, the file must exist, and it must contain
* exactly one PEM-encoded private key. The private key must not
* be encrypted.
*
* @throws KeyStoreException If there is a problem with any of the provided
* PEM files.
*/
public PEMFileKeyManager(@NotNull final File certificateChainPEMFile,
@NotNull final File privateKeyPEMFile)
throws KeyStoreException
{
this(Collections.singletonList(certificateChainPEMFile), privateKeyPEMFile);
}
/**
* Creates a new instance of this key manager with the provided PEM files.
*
* @param certificateChainPEMFile
* The file containing the PEM-formatted X.509 representations of
* the certificates in the certificate chain. This must not be
* {@code null}, the file must exist, and it must contain at
* least one certificate (the end entity certificate), but may
* contain additional certificates as needed for the complete
* certificate chain. Certificates should be ordered such that
* the first certificate must be the end entity certificate, and
* each subsequent certificate must be the issuer for the
* previous certificate. The chain does not need to be complete
* as long as the peer may be expected to have prior knowledge of
* any missing issuer certificates.
* @param privateKeyPEMFile
* The file containing the PEM-formatted PKCS #8 representation
* of the private key for the end entity certificate. This must
* not be {@code null}, the file must exist, and it must contain
* exactly one PEM-encoded private key. The private key may
* optionally be encrypted.
* @param privateKeyEncryptionPassword
* The password needed to decrypt the private key if it is
* encrypted. This may be {@code null} if the private key is not
* encrypted.
*
* @throws KeyStoreException If there is a problem with any of the provided
* PEM files.
*/
public PEMFileKeyManager(@NotNull final File certificateChainPEMFile,
@NotNull final File privateKeyPEMFile,
@Nullable final char[] privateKeyEncryptionPassword)
throws KeyStoreException
{
this(Collections.singletonList(certificateChainPEMFile), privateKeyPEMFile,
privateKeyEncryptionPassword);
}
/**
* Creates a new instance of this key manager with the provided PEM files.
*
* @param certificateChainPEMFiles
* The files containing the PEM-formatted X.509 representations
* of the certificates in the certificate chain. This must not
* be {@code null} or empty. Each file must exist and must
* contain at least one certificate. The files will be processed
* in the order in which they are provided. The first
* certificate in the first file must be the end entity
* certificate, and each subsequent certificate must be the
* issuer for the previous certificate. The chain does not need
* to be complete as long as the peer may be expected to have
* prior knowledge of any missing issuer certificates.
* @param privateKeyPEMFile
* The file containing the PEM-formatted PKCS #8 representation
* of the private key for the end entity certificate. This must
* not be {@code null}, the file must exist, and it must contain
* exactly one PEM-encoded private key. The private key must not
* be encrypted.
*
* @throws KeyStoreException If there is a problem with any of the provided
* PEM files.
*/
public PEMFileKeyManager(@NotNull final File[] certificateChainPEMFiles,
@NotNull final File privateKeyPEMFile)
throws KeyStoreException
{
this(StaticUtils.toList(certificateChainPEMFiles), privateKeyPEMFile);
}
/**
* Creates a new instance of this key manager with the provided PEM files.
*
* @param certificateChainPEMFiles
* The files containing the PEM-formatted X.509 representations
* of the certificates in the certificate chain. This must not
* be {@code null} or empty. Each file must exist and must
* contain at least one certificate. The files will be processed
* in the order in which they are provided. The first
* certificate in the first file must be the end entity
* certificate, and each subsequent certificate must be the
* issuer for the previous certificate. The chain does not need
* to be complete as long as the peer may be expected to have
* prior knowledge of any missing issuer certificates.
* @param privateKeyPEMFile
* The file containing the PEM-formatted PKCS #8 representation
* of the private key for the end entity certificate. This must
* not be {@code null}, the file must exist, and it must contain
* exactly one PEM-encoded private key. The private key may
* optionally be encrypted.
* @param privateKeyEncryptionPassword
* The password needed to decrypt the private key if it is
* encrypted. This may be {@code null} if the private key is not
* encrypted.
*
* @throws KeyStoreException If there is a problem with any of the provided
* PEM files.
*/
public PEMFileKeyManager(@NotNull final File[] certificateChainPEMFiles,
@NotNull final File privateKeyPEMFile,
@Nullable final char[] privateKeyEncryptionPassword)
throws KeyStoreException
{
this(StaticUtils.toList(certificateChainPEMFiles), privateKeyPEMFile,
privateKeyEncryptionPassword);
}
/**
* Creates a new instance of this key manager with the provided PEM files.
*
* @param certificateChainPEMFiles
* The files containing the PEM-formatted X.509 representations
* of the certificates in the certificate chain. This must not
* be {@code null} or empty. Each file must exist and must
* contain at least one certificate. The files will be processed
* in the order in which they are provided. The first
* certificate in the first file must be the end entity
* certificate, and each subsequent certificate must be the
* issuer for the previous certificate. The chain does not need
* to be complete as long as the peer may be expected to have
* prior knowledge of any missing issuer certificates.
* @param privateKeyPEMFile
* The file containing the PEM-formatted PKCS #8 representation
* of the private key for the end entity certificate. This must
* not be {@code null}, the file must exist, and it must contain
* exactly one PEM-encoded private key. The private key must not
* be encrypted.
*
* @throws KeyStoreException If there is a problem with any of the provided
* PEM files.
*/
public PEMFileKeyManager(@NotNull final List certificateChainPEMFiles,
@NotNull final File privateKeyPEMFile)
throws KeyStoreException
{
this(certificateChainPEMFiles, privateKeyPEMFile, null);
}
/**
* Creates a new instance of this key manager with the provided PEM files.
*
* @param certificateChainPEMFiles
* The files containing the PEM-formatted X.509 representations
* of the certificates in the certificate chain. This must not
* be {@code null} or empty. Each file must exist and must
* contain at least one certificate. The files will be processed
* in the order in which they are provided. The first
* certificate in the first file must be the end entity
* certificate, and each subsequent certificate must be the
* issuer for the previous certificate. The chain does not need
* to be complete as long as the peer may be expected to have
* prior knowledge of any missing issuer certificates.
* @param privateKeyPEMFile
* The file containing the PEM-formatted PKCS #8 representation
* of the private key for the end entity certificate. This must
* not be {@code null}, the file must exist, and it must contain
* exactly one PEM-encoded private key. The private key may
* optionally be encrypted.
* @param privateKeyEncryptionPassword
* The password needed to decrypt the private key if it is
* encrypted. This may be {@code null} if the private key is not
* encrypted.
*
* @throws KeyStoreException If there is a problem with any of the provided
* PEM files.
*/
public PEMFileKeyManager(@NotNull final List certificateChainPEMFiles,
@NotNull final File privateKeyPEMFile,
@Nullable final char[] privateKeyEncryptionPassword)
throws KeyStoreException
{
Validator.ensureNotNullWithMessage(certificateChainPEMFiles,
"PEMFileKeyManager.certificateChainPEMFiles must not be null.");
Validator.ensureFalse(certificateChainPEMFiles.isEmpty(),
"PEMFileKeyManager.certificateChainPEMFiles must not be empty.");
Validator.ensureNotNullWithMessage(privateKeyPEMFile,
"PEMFileKeyManager.privateKeyPEMFile must not be null.");
certificateChain = readCertificateChain(certificateChainPEMFiles);
privateKey = readPrivateKey(privateKeyPEMFile,
privateKeyEncryptionPassword);
// Compute a SHA-256 fingerprint for the certificate to use as the alias.
try
{
final MessageDigest sha256 =
CryptoHelper.getMessageDigest(ALIAS_FINGERPRINT_ALGORITHM);
final byte[] digestBytes =
sha256.digest(certificateChain[0].getEncoded());
alias = StaticUtils.toHex(digestBytes);
}
catch (final Exception e)
{
Debug.debugException(e);
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_CANNOT_COMPUTE_ALIAS.get(
ALIAS_FINGERPRINT_ALGORITHM,
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Reads the certificate chain from the provided PEM files.
*
* @param certificateChainPEMFiles The files containing the PEM-formatted
* X.509 representations of the certificates
* in the certificate chain. This must not
* be {@code null} or empty. Each file must
* exist and must contain at least one
* certificate. The files will be processed
* in the order in which they are provided.
* The first certificate in the first file
* must be the end entity certificate, and
* each subsequent certificate must be the
* issuer for the previous certificate. The
* chain does not need to be complete as
* long as the peer may be expected to have
* prior knowledge of any missing issuer
* certificates.
*
* @return The certificate chain that was read.
*
* @throws KeyStoreException If a problem is encountered while reading the
* certificate chain.
*/
@NotNull()
private static X509Certificate[] readCertificateChain(
@NotNull final List certificateChainPEMFiles)
throws KeyStoreException
{
com.unboundid.util.ssl.cert.X509Certificate lastCert = null;
final List certList = new ArrayList<>();
for (final File f : certificateChainPEMFiles)
{
if (! f.exists())
{
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_NO_SUCH_CERT_FILE.get(
f.getAbsolutePath()));
}
boolean readCert = false;
try (final X509PEMFileReader r = new X509PEMFileReader(f))
{
while (true)
{
final com.unboundid.util.ssl.cert.X509Certificate c =
r.readCertificate();
if (c == null)
{
if (! readCert)
{
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_EMPTY_CERT_FILE.get(
f.getAbsolutePath()));
}
break;
}
readCert = true;
if ((lastCert != null) && (! c.isIssuerFor(lastCert)))
{
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_SUBSEQUENT_CERT_NOT_ISSUER.get(
c.getSubjectDN().toString(), f.getAbsolutePath(),
lastCert.getSubjectDN().toString()));
}
try
{
certList.add((X509Certificate) c.toCertificate());
}
catch (final Exception e)
{
Debug.debugException(e);
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_CANNOT_DECODE_CERT.get(
c.getSubjectDN().toString(), f.getAbsolutePath(),
StaticUtils.getExceptionMessage(e)),
e);
}
lastCert = c;
}
}
catch (final KeyStoreException e)
{
Debug.debugException(e);
throw e;
}
catch (final IOException e)
{
Debug.debugException(e);
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_ERROR_READING_FROM_FILE.get(
f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)),
e);
}
catch (final CertException e)
{
Debug.debugException(e);
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_ERROR_READING_CERT.get(
f.getAbsolutePath(), e.getMessage()),
e);
}
}
final X509Certificate[] chain = new X509Certificate[certList.size()];
return certList.toArray(chain);
}
/**
* Reads the private key from the provided PEM file.
*
*
* @param privateKeyPEMFile
* The file containing the PEM-formatted PKCS #8 representation
* of the private key for the end entity certificate. This must
* not be {@code null}, the file must exist, and it must contain
* exactly one PEM-encoded private key. The private key may
* optionally be encrypted.
* @param encryptionPassword
* The password needed to decrypt the private key if it is
* encrypted. This may be {@code null} if the private key is not
* encrypted.
*
* @return The private key that was read.
*
* @throws KeyStoreException If a problem is encountered while reading the
* certificate chain.
*/
@NotNull()
private static PrivateKey readPrivateKey(
@NotNull final File privateKeyPEMFile,
@Nullable final char[] encryptionPassword)
throws KeyStoreException
{
if (! privateKeyPEMFile.exists())
{
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_NO_SUCH_KEY_FILE.get(
privateKeyPEMFile.getAbsolutePath()));
}
try (PKCS8PEMFileReader r = new PKCS8PEMFileReader(privateKeyPEMFile))
{
final PKCS8PrivateKey privateKey = r.readPrivateKey(encryptionPassword);
if (privateKey == null)
{
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_EMPTY_KEY_FILE.get(
privateKeyPEMFile.getAbsolutePath()));
}
if (r.readPrivateKey(encryptionPassword) != null)
{
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_MULTIPLE_KEYS_IN_FILE.get(
privateKeyPEMFile.getAbsolutePath()));
}
try
{
return privateKey.toPrivateKey();
}
catch (final Exception e)
{
Debug.debugException(e);
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_CANNOT_DECODE_KEY.get(
privateKeyPEMFile.getAbsolutePath(),
StaticUtils.getExceptionMessage(e)),
e);
}
}
catch (final KeyStoreException e)
{
Debug.debugException(e);
throw e;
}
catch (final IOException e)
{
Debug.debugException(e);
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_ERROR_READING_FROM_FILE.get(
privateKeyPEMFile.getAbsolutePath(),
StaticUtils.getExceptionMessage(e)),
e);
}
catch (final CertException e)
{
Debug.debugException(e);
throw new KeyStoreException(
ERR_PEM_FILE_KEY_MANAGER_ERROR_READING_KEY.get(
privateKeyPEMFile.getAbsolutePath(), e.getMessage()),
e);
}
}
/**
* Retrieves the aliases that may be used for a client certificate chain with
* the requested settings.
*
* @param keyType The key type for the alias to retrieve. It may be
* {@code null} if any key type may be used.
* @param issuers The set of allowed issuers for the aliases to retrieve.
* It may be {@code null} if any issuers should be allowed.
*
* @return An array of the aliases that may be used for a client certificate
* chain with the requested settings, or {@code null} if the
* certificate chain does not match the requested criteria.
*/
@Override()
@Nullable()
public String[] getClientAliases(@Nullable final String keyType,
@Nullable final Principal[] issuers)
{
return getAliases(keyType, issuers);
}
/**
* Retrieves the aliases that may be used for a server certificate chain with
* the requested settings.
*
* @param keyType The key type for the alias to retrieve. It may be
* {@code null} if any key type may be used.
* @param issuers The set of allowed issuers for the aliases to retrieve.
* It may be {@code null} if any issuers should be allowed.
*
* @return An array of the aliases that may be used for a server certificate
* chain with the requested settings, or {@code null} if the
* certificate chain does not match the requested criteria.
*/
@Override()
@Nullable()
public String[] getServerAliases(@Nullable final String keyType,
@Nullable final Principal[] issuers)
{
return getAliases(keyType, issuers);
}
/**
* Retrieves the aliases that may be used for a certificate chain with the
* requested settings.
*
* @param keyType The key type for the alias to retrieve. It may be
* {@code null} if any key type may be used.
* @param issuers A list of acceptable CA issuer subject names. It may be
* {@code null} if any issuers may be used.
*
* @return An array of the aliases that may be used for a certificate chain
* with the requested settings, or {@code null} if the certificate
* chain does not match the requested criteria.
*/
@Nullable()
private String[] getAliases(@Nullable final String keyType,
@Nullable final Principal[] issuers)
{
if (! hasKeyType(keyType))
{
Debug.debug(Level.WARNING, DebugType.OTHER,
"PEMFileKeyManager.getAliases returning null because the " +
"requested keyType is '" + keyType + "' but the private " +
"key uses an algorithm of '" + privateKey.getAlgorithm() +
"'.");
return null;
}
if (! hasAnyIssuer(issuers))
{
Debug.debug(Level.WARNING, DebugType.OTHER,
"PEMFileKeyManager.getAliases returning null because " +
"certificate chain " + Arrays.toString(certificateChain) +
" does not use any of the allowed issuers " +
Arrays.toString(issuers));
return null;
}
return new String[] { alias };
}
/**
* Chooses the alias that should be used for the preferred client certificate
* chain with the requested settings.
*
* @param keyTypes The set of allowed key types for the alias to retrieve.
* It may be {@code null} if any key type may be used.
* @param issuers The set of allowed issuers for the alias to retrieve. It
* may be {@code null} if any issuers should be allowed.
* @param socket The socket with which the certificate chain will be used.
* It may be {@code null} if no socket should be taken into
* consideration.
*
* @return The alias that should be used for the preferred client certificate
* chain with the requested settings, or {@code null} if there is no
* applicable alias.
*/
@Override()
@Nullable()
public String chooseClientAlias(@Nullable final String[] keyTypes,
@Nullable final Principal[] issuers,
@Nullable final Socket socket)
{
return chooseAlias(keyTypes, issuers);
}
/**
* Chooses the alias that should be used for the preferred server certificate
* chain with the requested settings.
*
* @param keyType The key type for the alias to retrieve. It may be
* {@code null} if any key type may be u sed.
* @param issuers The set of allowed issuers for the alias to retrieve. It
* may be {@code null} if any issuers should be allowed.
* @param socket The socket with which the certificate chain will be used.
* It may be {@code null} if no socket should be taken into
* consideration.
*
* @return The alias that should be used for the preferred server certificate
* chain with the requested settings, or {@code null} if there is no
* applicable alias.
*/
@Override()
@Nullable()
public String chooseServerAlias(@Nullable final String keyType,
@Nullable final Principal[] issuers,
@Nullable final Socket socket)
{
if (keyType == null)
{
return chooseAlias(null, issuers);
}
else
{
return chooseAlias(new String[] { keyType }, issuers);
}
}
/**
* Chooses the alias that should be used for the preferred certificate chain
* with the requested settings.
*
* @param keyTypes The set of allowed key types for the alias to retrieve.
* It may be {@code null} if any key type may be used.
* @param issuers The set of allowed issuers for the alias to retrieve. It
* may be {@code null} if any issuers should be allowed.
*
* @return The alias that should be used for the preferred certificate chain
* with the requested settings, or {@code null} if there is no
* applicable alias.
*/
@Nullable()
public String chooseAlias(@Nullable final String[] keyTypes,
@Nullable final Principal[] issuers)
{
if ((keyTypes != null) && (keyTypes.length > 0))
{
boolean keyTypeFound = false;
for (final String keyType : keyTypes)
{
if (hasKeyType(keyType))
{
keyTypeFound = true;
break;
}
}
if (! keyTypeFound)
{
Debug.debug(Level.WARNING, DebugType.OTHER,
"PEMFileKeyManager.chooseAlias returning null because " +
"certificate chain " + Arrays.toString(certificateChain) +
" uses a key type of " + privateKey.getAlgorithm() +
", which does not match any of the allowed key types of " +
Arrays.toString(keyTypes));
return null;
}
}
if (! hasAnyIssuer(issuers))
{
Debug.debug(Level.WARNING, DebugType.OTHER,
"PEMFileKeyManager.chooseAlias returning null because " +
"certificate chain " + Arrays.toString(certificateChain) +
" does not use any of the allowed issuers " +
Arrays.toString(issuers));
return null;
}
return alias;
}
/**
* Indicates whether the certificate chain has the specified key type.
*
* @param keyType The key type for which to make the determination. It may
* be {@code null} if the key type does not matter.
*
* @return {@code true} if the certificate chain has the specified key type
* (or if the key type does not matter), or {@code false} if not.
*/
private boolean hasKeyType(@Nullable final String keyType)
{
return ((keyType == null) ||
privateKey.getAlgorithm().equalsIgnoreCase(keyType));
}
/**
* Indicates whether the certificate chain has any of the issuers in the
* provided array.
*
* @param issuers The array of acceptable issuers. It may be
* {@code null} if the set of issuers does not matter.
*
* @return {@code true} if the certificate chain uses one of the accepted
* issuers (or if the issuers do not matter), or {@code false} if
* not.
*/
private boolean hasAnyIssuer(@Nullable final Principal[] issuers)
{
if ((issuers == null) || (issuers.length == 0))
{
return true;
}
// Check all of the issuer certificates for the chain.
for (final Principal acceptableIssuer : issuers)
{
final String acceptableIssuerString = acceptableIssuer.toString();
for (final X509Certificate c : certificateChain)
{
final Principal certificateIssuer = c.getIssuerDN();
final String certificateIssuerString = certificateIssuer.toString();
try
{
if (DN.equals(certificateIssuerString, acceptableIssuerString))
{
return true;
}
}
catch (final Exception e)
{
Debug.debugException(e);
}
}
}
// Also check the subject DN for the first certificate in the chain.
final Principal endEntitySubject = certificateChain[0].getSubjectDN();
final String endEntitySubjectString = endEntitySubject.toString();
for (final Principal acceptableIssuer : issuers)
{
final String acceptableIssuerString = acceptableIssuer.toString();
try
{
if (DN.equals(endEntitySubjectString, acceptableIssuerString))
{
return true;
}
}
catch (final Exception e)
{
Debug.debugException(e);
}
}
return false;
}
/**
* Retrieves the certificate chain with the specified alias. Note that
* because this key manager implementation can only use a single certificate
* chain, it will always return the same chain for any alias, even if the
* requested alias is {@code null}.
*
* @param alias The alias for the certificate chain to retrieve.
*
* @return The certificate chain for this key manager.
*/
@Override()
@NotNull()
public X509Certificate[] getCertificateChain(@Nullable final String alias)
{
return Arrays.copyOf(certificateChain, certificateChain.length);
}
/**
* Retrieves the private key for the certificate chain with the specified
* alias. Note that because this key manager implementation can only use a
* single certificate chain, it will always return the same private key for
* any alias, even if the requested alias is {@code null}.
*
* @param alias The alias for the private key to retrieve.
*
* @return The private key for this key manager.
*/
@Override()
@NotNull()
public PrivateKey getPrivateKey(@Nullable final String alias)
{
return privateKey;
}
}