/*
|
* CDDL HEADER START
|
*
|
* The contents of this file are subject to the terms of the
|
* Common Development and Distribution License, Version 1.0 only
|
* (the "License"). You may not use this file except in compliance
|
* with the License.
|
*
|
* You can obtain a copy of the license at
|
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
|
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
|
* See the License for the specific language governing permissions
|
* and limitations under the License.
|
*
|
* When distributing Covered Code, include this CDDL HEADER in each
|
* file and include the License file at
|
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
|
* add the following below this CDDL HEADER, with the fields enclosed
|
* by brackets "[]" replaced with your own identifying information:
|
* Portions Copyright [yyyy] [name of copyright owner]
|
*
|
* CDDL HEADER END
|
*
|
*
|
* Copyright 2010 Sun Microsystems, Inc.
|
*/
|
|
package org.opends.sdk;
|
|
|
|
import java.io.File;
|
import java.io.FileInputStream;
|
import java.io.IOException;
|
import java.net.Socket;
|
import java.security.*;
|
import java.security.cert.X509Certificate;
|
|
import javax.net.ssl.*;
|
|
import com.sun.opends.sdk.util.Validator;
|
|
|
|
/**
|
* This class contains methods for creating common types of key manager.
|
*/
|
public final class KeyManagers
|
{
|
/**
|
* This class implements an X.509 key manager that will be used to wrap an
|
* existing key manager and makes it possible to configure which
|
* certificate(s) should be used for client and/or server operations. The
|
* certificate selection will be based on the alias (also called the nickname)
|
* of the certificate.
|
*/
|
private static final class SelectCertificate extends X509ExtendedKeyManager
|
{
|
private final String alias;
|
private final X509KeyManager keyManager;
|
|
|
|
private SelectCertificate(final X509KeyManager keyManager,
|
final String alias)
|
{
|
this.keyManager = keyManager;
|
this.alias = alias;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public String chooseClientAlias(final String[] keyType,
|
final Principal[] issuers, final Socket socket)
|
{
|
for (final String type : keyType)
|
{
|
final String[] clientAliases = keyManager.getClientAliases(type,
|
issuers);
|
if (clientAliases != null)
|
{
|
for (final String clientAlias : clientAliases)
|
{
|
if (clientAlias.equals(alias))
|
{
|
return alias;
|
}
|
}
|
}
|
}
|
|
return null;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public String chooseEngineClientAlias(final String[] keyType,
|
final Principal[] issuers, final SSLEngine engine)
|
{
|
for (final String type : keyType)
|
{
|
final String[] clientAliases = keyManager.getClientAliases(type,
|
issuers);
|
if (clientAliases != null)
|
{
|
for (final String clientAlias : clientAliases)
|
{
|
if (clientAlias.equals(alias))
|
{
|
return alias;
|
}
|
}
|
}
|
}
|
|
return null;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public String chooseEngineServerAlias(final String keyType,
|
final Principal[] issuers, final SSLEngine engine)
|
{
|
final String[] serverAliases = keyManager.getServerAliases(keyType,
|
issuers);
|
if (serverAliases != null)
|
{
|
for (final String serverAlias : serverAliases)
|
{
|
if (serverAlias.equalsIgnoreCase(alias))
|
{
|
return serverAlias;
|
}
|
}
|
}
|
|
return null;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public String chooseServerAlias(final String keyType,
|
final Principal[] issuers, final Socket socket)
|
{
|
final String[] serverAliases = keyManager.getServerAliases(keyType,
|
issuers);
|
if (serverAliases != null)
|
{
|
for (final String serverAlias : serverAliases)
|
{
|
if (serverAlias.equals(alias))
|
{
|
return alias;
|
}
|
}
|
}
|
|
return null;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public X509Certificate[] getCertificateChain(final String alias)
|
{
|
return keyManager.getCertificateChain(alias);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public String[] getClientAliases(final String keyType,
|
final Principal[] issuers)
|
{
|
return keyManager.getClientAliases(keyType, issuers);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public PrivateKey getPrivateKey(final String alias)
|
{
|
return keyManager.getPrivateKey(alias);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public String[] getServerAliases(final String keyType,
|
final Principal[] issuers)
|
{
|
return keyManager.getServerAliases(keyType, issuers);
|
}
|
}
|
|
|
|
/**
|
* Creates a new {@code X509KeyManager} which will use the named key store
|
* file for retrieving certificates. It will use the default key store format
|
* for the JVM (e.g. {@code JKS}) and will not use a password to open the key
|
* store.
|
*
|
* @param file
|
* The key store file name.
|
* @return A new {@code X509KeyManager} which will use the named key store
|
* file for retrieving certificates.
|
* @throws GeneralSecurityException
|
* If the key store could not be loaded, perhaps due to incorrect
|
* format, or missing algorithms.
|
* @throws IOException
|
* If the key store file could not be found or could not be read.
|
* @throws NullPointerException
|
* If {@code file} was {@code null}.
|
*/
|
public static X509KeyManager useKeyStoreFile(final String file)
|
throws GeneralSecurityException, IOException, NullPointerException
|
{
|
return useKeyStoreFile(file, null, null);
|
}
|
|
|
|
/**
|
* Creates a new {@code X509KeyManager} which will use the named key store
|
* file for retrieving certificates. It will use the provided key store format
|
* and password.
|
*
|
* @param file
|
* The key store file name.
|
* @param password
|
* The key store password, which may be {@code null}.
|
* @param format
|
* The key store format, which may be {@code null} to indicate that
|
* the default key store format for the JVM (e.g. {@code JKS}) should
|
* be used.
|
* @return A new {@code X509KeyManager} which will use the named key store
|
* file for retrieving certificates.
|
* @throws GeneralSecurityException
|
* If the key store could not be loaded, perhaps due to incorrect
|
* format, or missing algorithms.
|
* @throws IOException
|
* If the key store file could not be found or could not be read.
|
* @throws NullPointerException
|
* If {@code file} was {@code null}.
|
*/
|
public static X509KeyManager useKeyStoreFile(final String file,
|
final String password, final String format)
|
throws GeneralSecurityException, IOException, NullPointerException
|
{
|
Validator.ensureNotNull(file);
|
|
final File keyStoreFile = new File(file);
|
final char[] keyStorePassword = password != null ? password.toCharArray()
|
: null;
|
final String keyStoreFormat = format != null ? format : KeyStore
|
.getDefaultType();
|
|
final KeyStore keyStore = KeyStore.getInstance(keyStoreFormat);
|
|
FileInputStream fos = null;
|
try
|
{
|
fos = new FileInputStream(keyStoreFile);
|
keyStore.load(fos, keyStorePassword);
|
}
|
finally
|
{
|
if (fos != null)
|
{
|
try
|
{
|
fos.close();
|
}
|
catch (final IOException ignored)
|
{
|
// Ignore.
|
}
|
}
|
}
|
|
final KeyManagerFactory kmf = KeyManagerFactory
|
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
kmf.init(keyStore, keyStorePassword);
|
|
X509KeyManager x509km = null;
|
for (final KeyManager km : kmf.getKeyManagers())
|
{
|
if (km instanceof X509KeyManager)
|
{
|
x509km = (X509KeyManager) km;
|
break;
|
}
|
}
|
|
if (x509km == null)
|
{
|
throw new NoSuchAlgorithmException();
|
}
|
|
return x509km;
|
}
|
|
|
|
/**
|
* Creates a new {@code X509KeyManager} which will use a PKCS#11 token for
|
* retrieving certificates.
|
*
|
* @param password
|
* The password to use for accessing the PKCS#11 token, which may be
|
* {@code null} if no password is required.
|
* @return A new {@code X509KeyManager} which will use a PKCS#11 token for
|
* retrieving certificates.
|
* @throws GeneralSecurityException
|
* If the PKCS#11 token could not be accessed, perhaps due to
|
* incorrect password, or missing algorithms.
|
* @throws IOException
|
* If the PKCS#11 token could not be found or could not be read.
|
*/
|
public static X509KeyManager usePKCS11Token(final String password)
|
throws GeneralSecurityException, IOException
|
{
|
final char[] keyStorePassword = password != null ? password.toCharArray()
|
: null;
|
final KeyStore keyStore = KeyStore.getInstance("PKCS11");
|
keyStore.load(null, keyStorePassword);
|
final KeyManagerFactory kmf = KeyManagerFactory
|
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
kmf.init(keyStore, keyStorePassword);
|
|
X509KeyManager x509km = null;
|
for (final KeyManager km : kmf.getKeyManagers())
|
{
|
if (km instanceof X509KeyManager)
|
{
|
x509km = (X509KeyManager) km;
|
break;
|
}
|
}
|
|
if (x509km == null)
|
{
|
throw new NoSuchAlgorithmException();
|
}
|
|
return x509km;
|
}
|
|
|
|
/**
|
* Returns a new {@code X509KeyManager} which selects the named certificate
|
* from the provided {@code X509KeyManager}.
|
*
|
* @param alias
|
* The nickname of the certificate that should be selected for
|
* operations involving this key manager.
|
* @param keyManager
|
* The key manager to be filtered.
|
* @return The filtered key manager.
|
* @throws NullPointerException
|
* If {@code keyManager} or {@code alias} was {@code null}.
|
*/
|
public static X509KeyManager useSingleCertificate(final String alias,
|
final X509KeyManager keyManager) throws NullPointerException
|
{
|
Validator.ensureNotNull(alias, keyManager);
|
return new SelectCertificate(keyManager, alias);
|
}
|
|
|
|
// Prevent insantiation.
|
private KeyManagers()
|
{
|
// Nothing to do.
|
}
|
|
}
|