KeyChainSet.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
eclipseme.core.internal.signing |
![]() |
![]() |
EclipseME |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
********************************************************************
*
* File : KeyChainSet.java
* Package : eclipseme.core.internal.signing
* System : eclipseme.core
* Author : Kevin Hunter
* Description : This class manages the private key and certificate
* used to sign a MIDlet suite.
*
* Copyright (c) 2004 Kevin Hunter
* All Rights Reserved.
* Licensed under the Eclipse Public License - v 1.0
* For more information see http://www.eclipse.org/legal/epl-v10.html
*
*
* CVS
* $$Source: /cvsroot/eclipseme/eclipseme.core/src/eclipseme/core/internal/signing/KeyChainSet.java,v $$
* $$Author: kdhunter $$
* $$Date: 2004/12/07 02:42:54 $$
* $$Revision: 1.4 $$
*
********************************************************************
*/
package eclipseme.core.internal.signing;
import java.io.IOException;
import java.io.InputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.eclipse.core.runtime.CoreException;
import eclipseme.core.EclipseMECoreErrors;
/**
* KeyChainSet
*
* This class manages a PrivateKey and an optional associated X509
* certificate chain. This class handles all the work of loading
* the key and the certificate chain from a keystore. Instances of
* this class cannot be created directly - the <code>getInstance</code>
* factory functions have to be used to load the contained data from
* a keystore.
*
* <p>Note that,
* to make things easier for the code using this class, all low-level
* exceptions that the crypto classes can throw are wrapped in
* an instance of <code>KeyChainSetException</code>.</p>
*
*/
public class KeyChainSet
{
private PrivateKey m_key; // key used for signing
private X509Certificate[] m_certChain; // certificate chain for key
private String m_strProvider; // optional provider for crypto classes
/**
* This constructor is private so that one is forced to obtain
* an instance of KeyChainSet using the factory functions.
*
* @param key Instance of <code>PrivateKey</code> that will
* be used to sign the MIDlet suite.
* @param certChain Array of <code>X509Certificate</code> objects
* that provide the validation certificate chain
* for <code>key</code>.
*/
private KeyChainSet(PrivateKey key, X509Certificate[] certChain, String strProvider)
{
m_key = key;
m_certChain = certChain;
m_strProvider = strProvider;
}
/**
* Returns the <code>PrivateKey</code> managed by this object.
*
* @return An instance of <code>java.security.PrivateKey</code>. This is
* guaranteed not to be null.
*/
public PrivateKey getKey()
{
return(m_key);
}
/**
* Returns the (optional) <code>X509Certificate</code> chain managed
* by this object. If a chain is present, the first entry in the array
* will be the certificate for the associated <code>PrivateKey</code>,
* and subsequent entries in the chain will be "parent" certificates,
* tracing back to the root certificate.
*
* @return Array of <code>java.security.cert.X509Certificate</code>
* objects. May be null.
*/
public X509Certificate[] getCertificateChain()
{
return(m_certChain);
}
/**
* Returns the (optional) provider string. Will be <code>null</code>
* if the system default provider is being used.
*
* @return
*/
public String getProvider()
{
return(m_strProvider);
}
/**
* Creates a <code>KeyChainSet</code> object from the specified keystore
* stream, loading the key specified by <code>strKeyAlias</code>
*
* @param isKeyStore <code>InputStream</code> containing the
* keystore from which the key is to be loaded.
* @param strKeyStorePass Password for the keystore as a whole.
* @param strKeyAlias Alias identifying the key within the keystore
* @param strKeyPass Password for the specific key.
* @return <code>KeyChainSet</code> containing the private key identified by
* <code>strKeyAlias</code> along with the matching certificate chain,
* if it is present.
*
* @throws KeyChainSetException
* @throws IOException
*/
public static KeyChainSet getInstance( InputStream keyStoreStream,
String strKeyStorePass,
String strKeyAlias,
String strKeyPass)
throws CoreException
{
return(getInstance(keyStoreStream, null, null, strKeyStorePass, strKeyAlias, strKeyPass));
}
/**
* Creates a <code>KeyChainSet</code> object from the specified keystore
* stream, loading the key specified by <code>strKeyAlias</code>. This version
* of the factory function allows non-default keystore types and keystore
* providers to be specified.
*
* @param isKeyStore <code>InputStream</code> containing the
* keystore from which the key is to be loaded.
* @param strKeyStoreType String identifying the particular keystore type
* being accessed. If <code>null</code>, the system
* default keystore type is assumed.
* @param strKeyStoreProvider String identifying the particular keystore provider.
* If <code>null</code>, the preferred implementation for
* the specified type will be used.
* @param strKeyStorePass Password for the keystore as a whole.
* @param strKeyAlias Alias identifying the key within the keystore
* @param strKeyPass Password for the specific key.
* @return <code>KeyChainSet</code> containing the private key identified by
* <code>strKeyAlias</code> along with the matching certificate chain,
* if it is present.
*
* @throws KeyChainSetException
* @throws IOException
*/
public static KeyChainSet getInstance( InputStream keyStoreStream,
String strKeyStoreType,
String strKeyStoreProvider,
String strKeyStorePass,
String strKeyAlias,
String strKeyPass)
throws CoreException
{
KeyStore store = null;
PrivateKey theKey = null;
X509Certificate[] orderedCertChain = null;
if (strKeyStoreProvider != null)
{
if (strKeyStoreProvider.length() == 0)
{
strKeyStoreProvider = null;
}
}
if (strKeyStoreType != null)
{
if (strKeyStoreType.length() == 0)
{
strKeyStoreType = null;
}
}
try
{
/*
* "null" is allowed for the key store type. In that case,
* we simply use the default key store type, which is "jks"
* for most JRE's. (This is the Sun default keystore type)
*/
if (strKeyStoreType == null)
{
strKeyStoreType = KeyStore.getDefaultType();
}
/*
* "null" is also allowed for the provider. It is possible
* to register non-default providers (e.g. bouncycastle) by
* configuring the JDK or JRE appropriately. This operation
* can throw a KeyStoreException if the key store type is
* not available. The second form can also thow a
* NoSuchProviderException.
*/
if (strKeyStoreProvider == null)
{
store = KeyStore.getInstance(strKeyStoreType);
}
else
{
store = KeyStore.getInstance(strKeyStoreType, strKeyStoreProvider);
}
/*
* Load the keystore data. This can throw an IOException, if the
* keystore file isn't validly formed, a NoSuchAlgorithmException
* if the algorithm used to check the integrity of the keystore
* can't be found, or a CertificateException if any of the certificates
* in the store can't be loaded.
*/
store.load(keyStoreStream, strKeyStorePass.toCharArray());
/*
* Load the key. This will return "null" if the key alias doesn't
* exist or doesn't reference a key. It will throw an UnrecoverableKeyException
* if the wrong password is provided, a NoSuchAlgorithmException if the
* algorithm for recovering the key cannot be found. In addition, the
* signature specifies that it could throw a KeyStoreException if the
* store wasn't initialized, but that shouldn't happen for us.
*/
Key k = store.getKey(strKeyAlias, strKeyPass.toCharArray());
if (k == null)
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_KEY_NOT_FOUND);
}
if (!(k instanceof PrivateKey))
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_BAD_KEY_TYPE);
}
theKey = (PrivateKey)k;
/*
* At this point, we've recovered the key, now try to recover the
* certificate chain. We will get null back from both of these
* if there isn't a certificate associated with the key.
*/
Certificate[] rawChain = store.getCertificateChain(strKeyAlias);
Certificate rawCert = store.getCertificate(strKeyAlias);
if (rawChain != null && rawCert != null)
{
/*
* Make sure we're dealing with X509Certificate instances
*/
if (!(rawCert instanceof X509Certificate))
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_INVALID_CERTIFICATE_CHAIN);
}
X509Certificate baseCert = (X509Certificate)rawCert;
X509Certificate[] certChain = new X509Certificate[rawChain.length];
int i;
for (i = 0; i < rawChain.length; i++)
{
if (rawChain[i] instanceof X509Certificate)
{
certChain[i] = (X509Certificate)rawChain[i];
}
else
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_INVALID_CERTIFICATE_CHAIN);
}
}
/*
* Apparently, judging from other code I've seen, if there's a
* multi-certificate chain, the chain members might not be returned
* in the correct order. This code will reorder the items in
* the certificate chain so that each certificate is immediately
* followed by its "parent" certificate.
*/
if (certChain[0].equals(baseCert))
{
orderedCertChain = certChain;
}
else
{
orderedCertChain = new X509Certificate[rawChain.length];
orderedCertChain[0] = baseCert;
for (i = 1; i < rawChain.length; i++)
{
orderedCertChain[i] = findParentCertificate(orderedCertChain[i-1], certChain);
if (orderedCertChain[i] == null)
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_INVALID_CERTIFICATE_CHAIN);
}
}
}
}
}
catch(IOException ioe)
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_BAD_KEYSTORE_OR_PASSWORD);
}
catch(KeyStoreException kse)
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_KEYSTORE_TYPE_NOT_AVAILABLE, kse);
}
catch(NoSuchProviderException nspe)
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_PROVIDER_NOT_CONFIGURED, nspe);
}
catch(NoSuchAlgorithmException nsae)
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_MISSING_KEYSTORE_INTEGRITY_ALGORITHM, nsae);
}
catch(CertificateException ce)
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_COULDNT_LOAD_CERTIFICATE, ce);
}
catch(UnrecoverableKeyException uke)
{
EclipseMECoreErrors.throwCoreExceptionError(EclipseMECoreErrors.SIGNING_INVALID_KEY_PASSWORD, uke);
}
KeyChainSet kcs = new KeyChainSet(theKey, orderedCertChain, strKeyStoreProvider);
return(kcs);
}
/**
* This routine searches a certificate array to find the certificate
* that is the "parent" for a particular certificate. Note that, as a side
* effect, the "parent" entry in the array is "nulled out" to improve
* performance during the operation.
*
* @param child The certificate whose parent is to be found.
* @param chain The certificate array to be searched.
* @return The parent certificate, or <code>null</code> if one cannot be found.
* (Indicates an error).
*/
private static X509Certificate findParentCertificate(X509Certificate child, X509Certificate[] chain)
{
Principal issuer = child.getIssuerDN();
X509Certificate retval = null;
for (int i = 0; i < chain.length; i++)
{
if (chain[i] != null)
{
Principal certDN = chain[i].getSubjectDN();
if (certDN.equals(issuer))
{
retval = chain[i];
chain[i] = null;
break;
}
}
}
return(retval);
}
/**
* Sets the <code>PrivateKey</code> managed by this object. Primarily included
* for unit testing purposes - under normal circumstances, the key should only
* be set via the <code>getInstance</code> methods.
*
* @param value
*/
/*package*/ void setKey(PrivateKey value)
{
m_key = value;
}
/**
* Sets the certificate chain managed by this object. Primarily included
* for unit testing purposes - under normal circumstances, the key should only
* be set via the <code>getInstance</code> methods.
*
* @param value
*/
/*package*/ void setCertificateChain(X509Certificate[] value)
{
m_certChain = value;
}
/**
* Sets the provider string managed by this object. Primarily included
* for unit testing purposes - under normal circumstances, the key should only
* be set via the <code>getInstance</code> methods.
*
* @param value
*/
/*package*/ void setProvider(String value)
{
m_strProvider = value;
}
}
/*
********************************************************************
* CVS History:
* $$Log: KeyChainSet.java,v $
* $Revision 1.4 2004/12/07 02:42:54 kdhunter
* $Switched from custom exception classes to CoreException
* $in signing routines.
* $Set up basic error code and error message handling, including
* $prep for internationalization
* $
* $Revision 1.3 2004/11/27 21:13:54 kdhunter
* $Handle case when empty strings get passed instead of nulls
* $
* $Revision 1.2 2004/11/26 20:53:26 kdhunter
* $Added package access methods for unit test purposes
* $
* $Revision 1.1 2004/11/26 14:59:22 kdhunter
* $Moved here from original "external" package
* $$
*
********************************************************************
*/
The table below shows all metrics for KeyChainSet.java.




