blob: d675024b2c5d928910bba1cc9dd9baae4aa83404 [file] [log] [blame]
package org.bouncycastle.jce.provider;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.Certificate;
import java.security.cert.CertificateParsingException;
import java.security.cert.PKIXParameters;
import java.security.cert.PolicyQualifierInfo;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLSelector;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.DSAPublicKeySpec;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
// BEGIN android-added
import org.apache.harmony.xnet.provider.jsse.IndexedPKIXParameters;
// END android-added
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1OutputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEREnumerated;
import org.bouncycastle.asn1.DERGeneralizedTime;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.isismtt.ISISMTTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.CRLNumber;
import org.bouncycastle.asn1.x509.CRLReason;
import org.bouncycastle.asn1.x509.CertificateList;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509Extensions;
// BEGIN android-removed
// import org.bouncycastle.jce.X509LDAPCertStoreParameters;
// END android-removed
import org.bouncycastle.jce.exception.ExtCertPathValidatorException;
import org.bouncycastle.util.Selector;
import org.bouncycastle.util.StoreException;
import org.bouncycastle.x509.ExtendedPKIXBuilderParameters;
import org.bouncycastle.x509.ExtendedPKIXParameters;
// BEGIN android-removed
// import org.bouncycastle.x509.X509AttributeCertStoreSelector;
// END android-removed
import org.bouncycastle.x509.X509AttributeCertificate;
import org.bouncycastle.x509.X509CRLStoreSelector;
import org.bouncycastle.x509.X509CertStoreSelector;
import org.bouncycastle.x509.X509Store;
public class CertPathValidatorUtilities
{
protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
protected static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
protected static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
protected static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
protected static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
protected static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
protected static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
protected static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
protected static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
protected static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
protected static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
protected static final String ANY_POLICY = "2.5.29.32.0";
protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
/*
* key usage bits
*/
protected static final int KEY_CERT_SIGN = 5;
protected static final int CRL_SIGN = 6;
protected static final String[] crlReasons = new String[] {
"unspecified",
"keyCompromise",
"cACompromise",
"affiliationChanged",
"superseded",
"cessationOfOperation",
"certificateHold",
"unknown",
"removeFromCRL",
"privilegeWithdrawn",
"aACompromise" };
// BEGIN android-removed
// /**
// * Search the given Set of TrustAnchor's for one that is the
// * issuer of the given X509 certificate. Uses the default provider
// * for signature verification.
// *
// * @param cert the X509 certificate
// * @param trustAnchors a Set of TrustAnchor's
// *
// * @return the <code>TrustAnchor</code> object if found or
// * <code>null</code> if not.
// *
// * @exception AnnotatedException
// * if a TrustAnchor was found but the signature verification
// * on the given certificate has thrown an exception.
// */
// protected static TrustAnchor findTrustAnchor(
// X509Certificate cert,
// Set trustAnchors)
// throws AnnotatedException
// {
// return findTrustAnchor(cert, trustAnchors, null);
// }
// END android-removed
// BEGIN android-changed
/**
* Search the given Set of TrustAnchor's for one that is the
* issuer of the given X509 certificate. Uses the specified
* provider for signature verification, or the default provider
* if null.
*
* @param cert the X509 certificate
* @param params used to find the trust anchors and signature provider
*
* @return the <code>TrustAnchor</code> object if found or
* <code>null</code> if not.
*
* @exception AnnotatedException
* if a TrustAnchor was found but the signature verification
* on the given certificate has thrown an exception.
*/
protected static TrustAnchor findTrustAnchor(
X509Certificate cert,
PKIXParameters params)
throws AnnotatedException
// END android-changed
{
// BEGIN android-changed
// If we have a trust anchor index, use it.
if (params instanceof IndexedPKIXParameters) {
try {
IndexedPKIXParameters indexed = (IndexedPKIXParameters) params;
return indexed.findTrustAnchor(cert);
} catch (CertPathValidatorException e) {
throw new AnnotatedException(e.getMessage(), e);
}
}
// END android-changed
TrustAnchor trust = null;
PublicKey trustPublicKey = null;
Exception invalidKeyEx = null;
X509CertSelector certSelectX509 = new X509CertSelector();
X500Principal certIssuer = getEncodedIssuerPrincipal(cert);
try
{
certSelectX509.setSubject(certIssuer.getEncoded());
}
catch (IOException ex)
{
throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
}
// BEGIN android-changed
Iterator iter = params.getTrustAnchors().iterator();
// END android-changed
// BEGIN android-added
byte[] certBytes = null;
try {
certBytes = cert.getEncoded();
} catch (Exception e) {
// ignore, just continue
}
// END android-added
while (iter.hasNext() && trust == null)
{
trust = (TrustAnchor) iter.next();
// BEGIN android-changed
X509Certificate trustCert = trust.getTrustedCert();
// END android-changed
// BEGIN android-added
// If the trust anchor is identical to the certificate we're
// done. Just return the anchor.
// There is similar code in PKIXCertPathValidatorSpi.
try {
byte[] trustBytes = trustCert.getEncoded();
if (certBytes != null && Arrays.equals(trustBytes, certBytes)) {
return trust;
}
} catch (Exception e) {
// ignore, continue and verify the certificate
}
// END android-added
// BEGIN android-changed
if (trustCert != null)
{
if (certSelectX509.match(trustCert))
{
trustPublicKey = trustCert.getPublicKey();
}
else
{
trust = null;
}
}
// END android-changed
else if (trust.getCAName() != null
&& trust.getCAPublicKey() != null)
{
try
{
X500Principal caName = new X500Principal(trust.getCAName());
if (certIssuer.equals(caName))
{
trustPublicKey = trust.getCAPublicKey();
}
else
{
trust = null;
}
}
catch (IllegalArgumentException ex)
{
trust = null;
}
}
else
{
trust = null;
}
if (trustPublicKey != null)
{
try
{
// BEGIN android-changed
verifyX509Certificate(cert, trustPublicKey, params.getSigProvider());
// END android-changed
}
catch (Exception ex)
{
invalidKeyEx = ex;
trust = null;
}
}
}
if (trust == null && invalidKeyEx != null)
{
throw new AnnotatedException("TrustAnchor found but certificate validation failed.", invalidKeyEx);
}
return trust;
}
protected static void addAdditionalStoresFromAltNames(
X509Certificate cert,
ExtendedPKIXParameters pkixParams)
throws CertificateParsingException
{
// if in the IssuerAltName extension an URI
// is given, add an additinal X.509 store
if (cert.getIssuerAlternativeNames() != null)
{
Iterator it = cert.getIssuerAlternativeNames().iterator();
while (it.hasNext())
{
// look for URI
List list = (List) it.next();
// BEGIN android-changed
if (list.get(0).equals(Integer.valueOf(GeneralName.uniformResourceIdentifier)))
// END android-changed
{
// found
String temp = (String) list.get(1);
CertPathValidatorUtilities.addAdditionalStoreFromLocation(temp, pkixParams);
}
}
}
}
/**
* Returns the issuer of an attribute certificate or certificate.
* @param cert The attribute certificate or certificate.
* @return The issuer as <code>X500Principal</code>.
*/
protected static X500Principal getEncodedIssuerPrincipal(
Object cert)
{
if (cert instanceof X509Certificate)
{
return ((X509Certificate)cert).getIssuerX500Principal();
}
else
{
return (X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0];
}
}
protected static Date getValidDate(PKIXParameters paramsPKIX)
{
Date validDate = paramsPKIX.getDate();
if (validDate == null)
{
validDate = new Date();
}
return validDate;
}
protected static X500Principal getSubjectPrincipal(X509Certificate cert)
{
return cert.getSubjectX500Principal();
}
protected static boolean isSelfIssued(X509Certificate cert)
{
return cert.getSubjectDN().equals(cert.getIssuerDN());
}
/**
* Extract the value of the given extension, if it exists.
*
* @param ext
* The extension object.
* @param oid
* The object identifier to obtain.
* @throws AnnotatedException
* if the extension cannot be read.
*/
protected static DERObject getExtensionValue(
java.security.cert.X509Extension ext,
String oid)
throws AnnotatedException
{
byte[] bytes = ext.getExtensionValue(oid);
if (bytes == null)
{
return null;
}
return getObject(oid, bytes);
}
private static DERObject getObject(
String oid,
byte[] ext)
throws AnnotatedException
{
try
{
ASN1InputStream aIn = new ASN1InputStream(ext);
ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
aIn = new ASN1InputStream(octs.getOctets());
return aIn.readObject();
}
catch (Exception e)
{
throw new AnnotatedException("exception processing extension " + oid, e);
}
}
protected static X500Principal getIssuerPrincipal(X509CRL crl)
{
return crl.getIssuerX500Principal();
}
protected static AlgorithmIdentifier getAlgorithmIdentifier(
PublicKey key)
throws CertPathValidatorException
{
try
{
ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
return info.getAlgorithmId();
}
catch (Exception e)
{
throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e);
}
}
// crl checking
/**
* Return a Collection of all CRLs found in the X509Store's that are
* matching the crlSelect criteriums.
*
* @param crlSelect a {@link X509CRLStoreSelector} object that will be used
* to select the CRLs
* @param crlStores a List containing only
* {@link org.bouncycastle.x509.X509Store X509Store} objects.
* These are used to search for CRLs
*
* @return a Collection of all found {@link X509CRL X509CRL} objects. May be
* empty but never <code>null</code>.
*/
protected static final Collection findCRLs(X509CRLStoreSelector crlSelect,
List crlStores) throws AnnotatedException
{
Set crls = new HashSet();
Iterator iter = crlStores.iterator();
AnnotatedException lastException = null;
boolean foundValidStore = false;
while (iter.hasNext())
{
Object obj = iter.next();
if (obj instanceof X509Store)
{
X509Store store = (X509Store)obj;
try
{
crls.addAll(store.getMatches(crlSelect));
foundValidStore = true;
}
catch (StoreException e)
{
lastException = new AnnotatedException(
"Exception searching in X.509 CRL store.", e);
}
}
else
{
CertStore store = (CertStore)obj;
try
{
crls.addAll(store.getCRLs(crlSelect));
foundValidStore = true;
}
catch (CertStoreException e)
{
lastException = new AnnotatedException(
"Exception searching in X.509 CRL store.", e);
}
}
}
if (!foundValidStore && lastException != null)
{
throw lastException;
}
return crls;
}
//
// policy checking
//
protected static final Set getQualifierSet(ASN1Sequence qualifiers)
throws CertPathValidatorException
{
Set pq = new HashSet();
if (qualifiers == null)
{
return pq;
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
Enumeration e = qualifiers.getObjects();
while (e.hasMoreElements())
{
try
{
aOut.writeObject(e.nextElement());
pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
}
catch (IOException ex)
{
throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
}
bOut.reset();
}
return pq;
}
protected static PKIXPolicyNode removePolicyNode(
PKIXPolicyNode validPolicyTree,
List [] policyNodes,
PKIXPolicyNode _node)
{
PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
if (validPolicyTree == null)
{
return null;
}
if (_parent == null)
{
for (int j = 0; j < policyNodes.length; j++)
{
policyNodes[j] = new ArrayList();
}
return null;
}
else
{
_parent.removeChild(_node);
removePolicyNodeRecurse(policyNodes, _node);
return validPolicyTree;
}
}
private static void removePolicyNodeRecurse(
List [] policyNodes,
PKIXPolicyNode _node)
{
policyNodes[_node.getDepth()].remove(_node);
if (_node.hasChildren())
{
Iterator _iter = _node.getChildren();
while (_iter.hasNext())
{
PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
removePolicyNodeRecurse(policyNodes, _child);
}
}
}
protected static boolean processCertD1i(
int index,
List [] policyNodes,
DERObjectIdentifier pOid,
Set pq)
{
List policyNodeVec = policyNodes[index - 1];
for (int j = 0; j < policyNodeVec.size(); j++)
{
PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
Set expectedPolicies = node.getExpectedPolicies();
if (expectedPolicies.contains(pOid.getId()))
{
Set childExpectedPolicies = new HashSet();
childExpectedPolicies.add(pOid.getId());
PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
index,
childExpectedPolicies,
node,
pq,
pOid.getId(),
false);
node.addChild(child);
policyNodes[index].add(child);
return true;
}
}
return false;
}
protected static void processCertD1ii(
int index,
List [] policyNodes,
DERObjectIdentifier _poid,
Set _pq)
{
List policyNodeVec = policyNodes[index - 1];
for (int j = 0; j < policyNodeVec.size(); j++)
{
PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
if (ANY_POLICY.equals(_node.getValidPolicy()))
{
Set _childExpectedPolicies = new HashSet();
_childExpectedPolicies.add(_poid.getId());
PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
index,
_childExpectedPolicies,
_node,
_pq,
_poid.getId(),
false);
_node.addChild(_child);
policyNodes[index].add(_child);
return;
}
}
}
protected static void prepareNextCertB1(
int i,
List[] policyNodes,
String id_p,
Map m_idp,
X509Certificate cert
) throws AnnotatedException,CertPathValidatorException
{
boolean idp_found = false;
Iterator nodes_i = policyNodes[i].iterator();
while (nodes_i.hasNext())
{
PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
if (node.getValidPolicy().equals(id_p))
{
idp_found = true;
node.expectedPolicies = (Set)m_idp.get(id_p);
break;
}
}
if (!idp_found)
{
nodes_i = policyNodes[i].iterator();
while (nodes_i.hasNext())
{
PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
if (ANY_POLICY.equals(node.getValidPolicy()))
{
Set pq = null;
ASN1Sequence policies = null;
try
{
policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES));
}
catch (Exception e)
{
throw
new AnnotatedException("Certificate policies cannot be decoded.", e);
}
Enumeration e = policies.getObjects();
while (e.hasMoreElements())
{
PolicyInformation pinfo = null;
try
{
pinfo = PolicyInformation.getInstance(e.nextElement());
}
catch (Exception ex)
{
throw new AnnotatedException("Policy information cannot be decoded.", ex);
}
if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
{
try
{
pq = getQualifierSet(pinfo.getPolicyQualifiers());
}
catch (CertPathValidatorException ex)
{
throw new ExtCertPathValidatorException(
"Policy qualifier info set could not be built.", ex);
}
break;
}
}
boolean ci = false;
if (cert.getCriticalExtensionOIDs() != null)
{
ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
}
PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
if (ANY_POLICY.equals(p_node.getValidPolicy()))
{
PKIXPolicyNode c_node = new PKIXPolicyNode(
new ArrayList(), i,
(Set)m_idp.get(id_p),
p_node, pq, id_p, ci);
p_node.addChild(c_node);
policyNodes[i].add(c_node);
}
break;
}
}
}
}
protected static PKIXPolicyNode prepareNextCertB2(
int i,
List[] policyNodes,
String id_p,
PKIXPolicyNode validPolicyTree)
{
Iterator nodes_i = policyNodes[i].iterator();
while (nodes_i.hasNext())
{
PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
if (node.getValidPolicy().equals(id_p))
{
PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
p_node.removeChild(node);
nodes_i.remove();
for (int k = (i - 1); k >= 0; k--)
{
List nodes = policyNodes[k];
for (int l = 0; l < nodes.size(); l++)
{
PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
if (!node2.hasChildren())
{
validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
if (validPolicyTree == null)
{
break;
}
}
}
}
}
}
return validPolicyTree;
}
protected static boolean isAnyPolicy(
Set policySet)
{
return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
}
protected static void addAdditionalStoreFromLocation(String location,
ExtendedPKIXParameters pkixParams)
{
if (pkixParams.isAdditionalLocationsEnabled())
{
try
{
// BEGIN android-removed
// if (location.startsWith("ldap://"))
// {
// // ldap://directory.d-trust.net/CN=D-TRUST
// // Qualified CA 2003 1:PN,O=D-Trust GmbH,C=DE
// // skip "ldap://"
// location = location.substring(7);
// // after first / baseDN starts
// String base = null;
// String url = null;
// if (location.indexOf("/") != -1)
// {
// base = location.substring(location.indexOf("/"));
// // URL
// url = "ldap://"
// + location.substring(0, location.indexOf("/"));
// }
// else
// {
// url = "ldap://" + location;
// }
// // use all purpose parameters
// X509LDAPCertStoreParameters params = new X509LDAPCertStoreParameters.Builder(
// url, base).build();
// pkixParams.addAdditionalStore(X509Store.getInstance(
// "CERTIFICATE/LDAP", params, "BC"));
// pkixParams.addAdditionalStore(X509Store.getInstance(
// "CRL/LDAP", params, "BC"));
// pkixParams.addAdditionalStore(X509Store.getInstance(
// "ATTRIBUTECERTIFICATE/LDAP", params, "BC"));
// pkixParams.addAdditionalStore(X509Store.getInstance(
// "CERTIFICATEPAIR/LDAP", params, "BC"));
// }
// END android-removed
}
catch (Exception e)
{
// cannot happen
throw new RuntimeException("Exception adding X.509 stores.");
}
}
}
/**
* Return a Collection of all certificates or attribute certificates found
* in the X509Store's that are matching the certSelect criteriums.
*
* @param certSelect a {@link Selector} object that will be used to select
* the certificates
* @param certStores a List containing only {@link X509Store} objects. These
* are used to search for certificates.
*
* @return a Collection of all found {@link X509Certificate} or
* {@link org.bouncycastle.x509.X509AttributeCertificate} objects.
* May be empty but never <code>null</code>.
*/
protected static Collection findCertificates(X509CertStoreSelector certSelect,
List certStores) throws AnnotatedException
{
Set certs = new HashSet();
Iterator iter = certStores.iterator();
while (iter.hasNext())
{
Object obj = iter.next();
if (obj instanceof X509Store)
{
X509Store certStore = (X509Store)obj;
try
{
certs.addAll(certStore.getMatches(certSelect));
}
catch (StoreException e)
{
throw
new AnnotatedException(
"Problem while picking certificates from X.509 store.", e);
}
}
else
{
CertStore certStore = (CertStore)obj;
try
{
certs.addAll(certStore.getCertificates(certSelect));
}
catch (CertStoreException e)
{
throw new AnnotatedException(
"Problem while picking certificates from certificate store.",
e);
}
}
}
return certs;
}
// BEGIN android-removed
// protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect,
// List certStores)
// throws AnnotatedException
// {
// Set certs = new HashSet();
// Iterator iter = certStores.iterator();
//
// while (iter.hasNext())
// {
// Object obj = iter.next();
//
// if (obj instanceof X509Store)
// {
// X509Store certStore = (X509Store)obj;
// try
// {
// certs.addAll(certStore.getMatches(certSelect));
// }
// catch (StoreException e)
// {
// throw
//
// new AnnotatedException(
// "Problem while picking certificates from X.509 store.", e);
// }
// }
// }
// return certs;
// }
// END android-removed
protected static void addAdditionalStoresFromCRLDistributionPoint(
CRLDistPoint crldp, ExtendedPKIXParameters pkixParams)
throws AnnotatedException
{
if (crldp != null)
{
DistributionPoint dps[] = null;
try
{
dps = crldp.getDistributionPoints();
}
catch (Exception e)
{
throw new AnnotatedException(
"Distribution points could not be read.", e);
}
for (int i = 0; i < dps.length; i++)
{
DistributionPointName dpn = dps[i].getDistributionPoint();
// look for URIs in fullName
if (dpn != null)
{
if (dpn.getType() == DistributionPointName.FULL_NAME)
{
GeneralName[] genNames = GeneralNames.getInstance(
dpn.getName()).getNames();
// look for an URI
for (int j = 0; j < genNames.length; j++)
{
if (genNames[j].getTagNo() == GeneralName.uniformResourceIdentifier)
{
String location = DERIA5String.getInstance(
genNames[j].getName()).getString();
CertPathValidatorUtilities
.addAdditionalStoreFromLocation(location,
pkixParams);
}
}
}
}
}
}
}
/**
* Add the CRL issuers from the cRLIssuer field of the distribution point or
* from the certificate if not given to the issuer criterion of the
* <code>selector</code>.
* <p>
* The <code>issuerPrincipals</code> are a collection with a single
* <code>X500Principal</code> for <code>X509Certificate</code>s. For
* {@link X509AttributeCertificate}s the issuer may contain more than one
* <code>X500Principal</code>.
*
* @param dp The distribution point.
* @param issuerPrincipals The issuers of the certificate or attribute
* certificate which contains the distribution point.
* @param selector The CRL selector.
* @param pkixParams The PKIX parameters containing the cert stores.
* @throws AnnotatedException if an exception occurs while processing.
* @throws ClassCastException if <code>issuerPrincipals</code> does not
* contain only <code>X500Principal</code>s.
*/
protected static void getCRLIssuersFromDistributionPoint(
DistributionPoint dp,
Collection issuerPrincipals,
X509CRLSelector selector,
ExtendedPKIXParameters pkixParams)
throws AnnotatedException
{
List issuers = new ArrayList();
// indirect CRL
if (dp.getCRLIssuer() != null)
{
GeneralName genNames[] = dp.getCRLIssuer().getNames();
// look for a DN
for (int j = 0; j < genNames.length; j++)
{
if (genNames[j].getTagNo() == GeneralName.directoryName)
{
try
{
issuers.add(new X500Principal(genNames[j].getName()
.getDERObject().getEncoded()));
}
catch (IOException e)
{
throw new AnnotatedException(
"CRL issuer information from distribution point cannot be decoded.",
e);
}
}
}
}
else
{
/*
* certificate issuer is CRL issuer, distributionPoint field MUST be
* present.
*/
if (dp.getDistributionPoint() == null)
{
throw new AnnotatedException(
"CRL issuer is omitted from distribution point but no distributionPoint field present.");
}
// add and check issuer principals
for (Iterator it=issuerPrincipals.iterator(); it.hasNext();)
{
issuers.add((X500Principal)it.next());
}
}
// TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid
// distributionPoint
// if (dp.getDistributionPoint() != null)
// {
// // look for nameRelativeToCRLIssuer
// if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
// {
// // append fragment to issuer, only one
// // issuer can be there, if this is given
// if (issuers.size() != 1)
// {
// throw new AnnotatedException(
// "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
// }
// DEREncodable relName = dp.getDistributionPoint().getName();
// Iterator it = issuers.iterator();
// List issuersTemp = new ArrayList(issuers.size());
// while (it.hasNext())
// {
// Enumeration e = null;
// try
// {
// e = ASN1Sequence.getInstance(
// new ASN1InputStream(((X500Principal) it.next())
// .getEncoded()).readObject()).getObjects();
// }
// catch (IOException ex)
// {
// throw new AnnotatedException(
// "Cannot decode CRL issuer information.", ex);
// }
// ASN1EncodableVector v = new ASN1EncodableVector();
// while (e.hasMoreElements())
// {
// v.add((DEREncodable) e.nextElement());
// }
// v.add(relName);
// issuersTemp.add(new X500Principal(new DERSequence(v)
// .getDEREncoded()));
// }
// issuers.clear();
// issuers.addAll(issuersTemp);
// }
// }
Iterator it = issuers.iterator();
while (it.hasNext())
{
try
{
selector.addIssuerName(((X500Principal)it.next()).getEncoded());
}
catch (IOException ex)
{
throw new AnnotatedException(
"Cannot decode CRL issuer information.", ex);
}
}
}
private static BigInteger getSerialNumber(
Object cert)
{
if (cert instanceof X509Certificate)
{
return ((X509Certificate) cert).getSerialNumber();
}
else
{
return ((X509AttributeCertificate) cert).getSerialNumber();
}
}
protected static void getCertStatus(
Date validDate,
X509CRL crl,
Object cert,
CertStatus certStatus)
throws AnnotatedException
{
// use BC X509CRLObject so that indirect CRLs are supported
X509CRLObject bcCRL = null;
try
{
bcCRL = new X509CRLObject(new CertificateList((ASN1Sequence) ASN1Sequence.fromByteArray(crl.getEncoded())));
}
catch (Exception exception)
{
throw new AnnotatedException("Bouncy Castle X509CRLObject could not be created.", exception);
}
// use BC X509CRLEntryObject, so that getCertificateIssuer() is
// supported.
X509CRLEntryObject crl_entry = (X509CRLEntryObject) bcCRL.getRevokedCertificate(getSerialNumber(cert));
if (crl_entry != null
&& (getEncodedIssuerPrincipal(cert).equals(crl_entry.getCertificateIssuer()) || getEncodedIssuerPrincipal(cert)
.equals(getIssuerPrincipal(crl))))
{
DEREnumerated reasonCode = null;
if (crl_entry.hasExtensions())
{
try
{
reasonCode = DEREnumerated
.getInstance(CertPathValidatorUtilities
.getExtensionValue(crl_entry,
X509Extensions.ReasonCode.getId()));
}
catch (Exception e)
{
new AnnotatedException(
"Reason code CRL entry extension could not be decoded.",
e);
}
}
// for reason keyCompromise, caCompromise, aACompromise or
// unspecified
if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
|| reasonCode == null
|| reasonCode.getValue().intValue() == 0
|| reasonCode.getValue().intValue() == 1
|| reasonCode.getValue().intValue() == 2
|| reasonCode.getValue().intValue() == 8)
{
// (i) or (j) (1)
if (reasonCode != null)
{
certStatus.setCertStatus(reasonCode.getValue().intValue());
}
// (i) or (j) (2)
else
{
certStatus.setCertStatus(CRLReason.unspecified);
}
certStatus.setRevocationDate(crl_entry.getRevocationDate());
}
}
}
/**
* Fetches delta CRLs according to RFC 3280 section 5.2.4.
*
* @param currentDate The date for which the delta CRLs must be valid.
* @param paramsPKIX The extended PKIX parameters.
* @param completeCRL The complete CRL the delta CRL is for.
* @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
* @throws AnnotatedException if an exception occurs while picking the delta
* CRLs.
*/
protected static Set getDeltaCRLs(Date currentDate,
ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL)
throws AnnotatedException
{
X509CRLStoreSelector deltaSelect = new X509CRLStoreSelector();
if (paramsPKIX.getDate() != null)
{
deltaSelect.setDateAndTime(paramsPKIX.getDate());
}
else
{
deltaSelect.setDateAndTime(currentDate);
}
// 5.2.4 (a)
try
{
deltaSelect.addIssuerName(CertPathValidatorUtilities
.getIssuerPrincipal(completeCRL).getEncoded());
}
catch (IOException e)
{
new AnnotatedException("Cannot extract issuer from CRL.", e);
}
BigInteger completeCRLNumber = null;
try
{
DERObject derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL,
CRL_NUMBER);
if (derObject != null)
{
completeCRLNumber = CRLNumber.getInstance(derObject).getPositiveValue();
}
}
catch (Exception e)
{
throw new AnnotatedException(
"CRL number extension could not be extracted from CRL.", e);
}
// 5.2.4 (b)
byte[] idp = null;
try
{
idp = completeCRL.getExtensionValue(ISSUING_DISTRIBUTION_POINT);
}
catch (Exception e)
{
throw new AnnotatedException(
"Issuing distribution point extension value could not be read.",
e);
}
// 5.2.4 (d)
deltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber
.add(BigInteger.valueOf(1)));
deltaSelect.setIssuingDistributionPoint(idp);
deltaSelect.setIssuingDistributionPointEnabled(true);
// 5.2.4 (c)
deltaSelect.setMaxBaseCRLNumber(completeCRLNumber);
Set temp = new HashSet();
// find delta CRLs
try
{
temp.addAll(CertPathValidatorUtilities.findCRLs(deltaSelect, paramsPKIX.getAdditionalStores()));
temp.addAll(CertPathValidatorUtilities.findCRLs(deltaSelect, paramsPKIX.getStores()));
temp.addAll(CertPathValidatorUtilities.findCRLs(deltaSelect, paramsPKIX.getCertStores()));
}
catch (AnnotatedException e)
{
throw new AnnotatedException("Could not search for delta CRLs.", e);
}
Set result = new HashSet();
for (Iterator it = temp.iterator(); it.hasNext();)
{
X509CRL crl = (X509CRL)it.next();
if (isDeltaCRL(crl))
{
result.add(crl);
}
}
return result;
}
private static boolean isDeltaCRL(X509CRL crl)
{
Set critical = crl.getCriticalExtensionOIDs();
return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
}
/**
* Fetches complete CRLs according to RFC 3280.
*
* @param dp The distribution point for which the complete CRL
* @param cert The <code>X509Certificate</code> or
* {@link org.bouncycastle.x509.X509AttributeCertificate} for
* which the CRL should be searched.
* @param currentDate The date for which the delta CRLs must be valid.
* @param paramsPKIX The extended PKIX parameters.
* @return A <code>Set</code> of <code>X509CRL</code>s with complete
* CRLs.
* @throws AnnotatedException if an exception occurs while picking the CRLs
* or no CRLs are found.
*/
protected static Set getCompleteCRLs(DistributionPoint dp, Object cert,
Date currentDate, ExtendedPKIXParameters paramsPKIX)
throws AnnotatedException
{
X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
try
{
Set issuers = new HashSet();
if (cert instanceof X509AttributeCertificate)
{
issuers.add(((X509AttributeCertificate)cert)
.getIssuer().getPrincipals()[0]);
}
else
{
issuers.add(getEncodedIssuerPrincipal(cert));
}
CertPathValidatorUtilities.getCRLIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX);
}
catch (AnnotatedException e)
{
new AnnotatedException(
"Could not get issuer information from distribution point.", e);
}
if (cert instanceof X509Certificate)
{
crlselect.setCertificateChecking((X509Certificate)cert);
}
else if (cert instanceof X509AttributeCertificate)
{
crlselect.setAttrCertificateChecking((X509AttributeCertificate)cert);
}
if (paramsPKIX.getDate() != null)
{
crlselect.setDateAndTime(paramsPKIX.getDate());
}
else
{
crlselect.setDateAndTime(currentDate);
}
crlselect.setCompleteCRLEnabled(true);
Set crls = new HashSet();
try
{
crls.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getStores()));
crls.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getAdditionalStores()));
crls.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getCertStores()));
}
catch (AnnotatedException e)
{
throw new AnnotatedException("Could not search for CRLs.", e);
}
if (crls.isEmpty())
{
if (cert instanceof X509AttributeCertificate)
{
X509AttributeCertificate aCert = (X509AttributeCertificate)cert;
throw new AnnotatedException("No CRLs found for issuer \"" + aCert.getIssuer().getPrincipals()[0] + "\"");
}
else
{
X509Certificate xCert = (X509Certificate)cert;
throw new AnnotatedException("No CRLs found for issuer \"" + xCert.getIssuerX500Principal() + "\"");
}
}
return crls;
}
protected static Date getValidCertDateFromValidityModel(
ExtendedPKIXParameters paramsPKIX, CertPath certPath, int index)
throws AnnotatedException
{
if (paramsPKIX.getValidityModel() == ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
{
// if end cert use given signing/encryption/... time
if (index <= 0)
{
return CertPathValidatorUtilities.getValidDate(paramsPKIX);
// else use time when previous cert was created
}
else
{
if (index - 1 == 0)
{
DERGeneralizedTime dateOfCertgen = null;
try
{
byte[] extBytes = ((X509Certificate)certPath.getCertificates().get(index - 1)).getExtensionValue(ISISMTTObjectIdentifiers.id_isismtt_at_dateOfCertGen.getId());
if (extBytes != null)
{
dateOfCertgen = DERGeneralizedTime.getInstance(ASN1Object.fromByteArray(extBytes));
}
}
catch (IOException e)
{
throw new AnnotatedException(
"Date of cert gen extension could not be read.");
}
catch (IllegalArgumentException e)
{
throw new AnnotatedException(
"Date of cert gen extension could not be read.");
}
if (dateOfCertgen != null)
{
try
{
return dateOfCertgen.getDate();
}
catch (ParseException e)
{
throw new AnnotatedException(
"Date from date of cert gen extension could not be parsed.",
e);
}
}
return ((X509Certificate) certPath.getCertificates().get(
index - 1)).getNotBefore();
}
else
{
return ((X509Certificate) certPath.getCertificates().get(
index - 1)).getNotBefore();
}
}
}
else
{
return getValidDate(paramsPKIX);
}
}
/**
* Return the next working key inheriting DSA parameters if necessary.
* <p>
* This methods inherits DSA parameters from the indexed certificate or
* previous certificates in the certificate chain to the returned
* <code>PublicKey</code>. The list is searched upwards, meaning the end
* certificate is at position 0 and previous certificates are following.
* </p>
* <p>
* If the indexed certificate does not contain a DSA key this method simply
* returns the public key. If the DSA key already contains DSA parameters
* the key is also only returned.
* </p>
*
* @param certs The certification path.
* @param index The index of the certificate which contains the public key
* which should be extended with DSA parameters.
* @return The public key of the certificate in list position
* <code>index</code> extended with DSA parameters if applicable.
* @throws AnnotatedException if DSA parameters cannot be inherited.
*/
protected static PublicKey getNextWorkingKey(List certs, int index)
throws CertPathValidatorException
{
Certificate cert = (Certificate) certs.get(index);
PublicKey pubKey = cert.getPublicKey();
if (!(pubKey instanceof DSAPublicKey))
{
return pubKey;
}
DSAPublicKey dsaPubKey = (DSAPublicKey) pubKey;
if (dsaPubKey.getParams() != null)
{
return dsaPubKey;
}
for (int i = index + 1; i < certs.size(); i++)
{
X509Certificate parentCert = (X509Certificate)certs.get(i);
pubKey = parentCert.getPublicKey();
if (!(pubKey instanceof DSAPublicKey))
{
throw new CertPathValidatorException(
"DSA parameters cannot be inherited from previous certificate.");
}
DSAPublicKey prevDSAPubKey = (DSAPublicKey) pubKey;
if (prevDSAPubKey.getParams() == null)
{
continue;
}
DSAParams dsaParams = prevDSAPubKey.getParams();
DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
try
{
KeyFactory keyFactory = KeyFactory.getInstance("DSA", "BC");
return keyFactory.generatePublic(dsaPubKeySpec);
}
catch (Exception exception)
{
throw new RuntimeException(exception.getMessage());
}
}
throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
}
/**
* Find the issuer certificates of a given certificate.
*
* @param cert
* The certificate for which an issuer should be found.
* @param pkixParams
* @return A <code>Collection</code> object containing the issuer
* <code>X509Certificate</code>s. Never <code>null</code>.
*
* @exception AnnotatedException
* if an error occurs.
*/
protected static Collection findIssuerCerts(
X509Certificate cert,
ExtendedPKIXBuilderParameters pkixParams)
throws AnnotatedException
{
X509CertStoreSelector certSelect = new X509CertStoreSelector();
Set certs = new HashSet();
try
{
certSelect.setSubject(cert.getIssuerX500Principal().getEncoded());
}
catch (IOException ex)
{
throw new AnnotatedException(
"Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
}
Iterator iter;
try
{
List matches = new ArrayList();
matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getCertStores()));
matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getStores()));
matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getAdditionalStores()));
iter = matches.iterator();
}
catch (AnnotatedException e)
{
throw new AnnotatedException("Issuer certificate cannot be searched.", e);
}
X509Certificate issuer = null;
while (iter.hasNext())
{
issuer = (X509Certificate) iter.next();
// issuer cannot be verified because possible DSA inheritance
// parameters are missing
certs.add(issuer);
}
return certs;
}
protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
String sigProvider)
throws GeneralSecurityException
{
if (sigProvider == null)
{
cert.verify(publicKey);
}
else
{
cert.verify(publicKey, sigProvider);
}
}
}