blob: f5d6711e76160cfea99db927543efa77776deeed [file] [log] [blame]
package org.bouncycastle.jce.provider;
import java.io.IOException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.PublicKey;
import java.security.cert.CertPath;
import java.security.cert.CertPathParameters;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorResult;
import java.security.cert.CertPathValidatorSpi;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.PKIXCertPathChecker;
import java.security.cert.PKIXCertPathValidatorResult;
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
import java.security.cert.X509CRLSelector;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
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;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DEREncodable;
import org.bouncycastle.asn1.DEREnumerated;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralSubtree;
import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
import org.bouncycastle.asn1.x509.NameConstraints;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.X509Extensions;
/**
* CertPathValidatorSpi implemenation for X.509 Certificate validation ala rfc 3280<br />
**/
public class PKIXCertPathValidatorSpi extends CertPathValidatorSpi
{
private static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
private static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
private static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
private static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
private static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
private static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
private static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
private static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
private static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
private static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
private static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
private static final String ANY_POLICY = "2.5.29.32.0";
/*
* key usage bits
*/
private static final int KEY_CERT_SIGN = 5;
private static final int CRL_SIGN = 6;
private static final String[] crlReasons = new String[] {
"unspecified",
"keyCompromise",
"cACompromise",
"affiliationChanged",
"superseded",
"cessationOfOperation",
"certificateHold",
"unknown",
"removeFromCRL",
"privilegeWithdrawn",
"aACompromise" };
public CertPathValidatorResult engineValidate(
CertPath certPath,
CertPathParameters params)
throws CertPathValidatorException, InvalidAlgorithmParameterException
{
if (!(params instanceof PKIXParameters))
{
throw new InvalidAlgorithmParameterException("params must be a PKIXParameters instance");
}
PKIXParameters paramsPKIX = (PKIXParameters)params;
if (paramsPKIX.getTrustAnchors() == null)
{
throw new InvalidAlgorithmParameterException("trustAnchors is null, this is not allowed for path validation");
}
//
// 6.1.1 - inputs
//
//
// (a)
//
List certs = certPath.getCertificates();
int n = certs.size();
if (certs.isEmpty())
{
throw new CertPathValidatorException("CertPath is empty", null, certPath, 0);
}
//
// (b)
//
Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX);
//
// (c)
//
Set userInitialPolicySet = paramsPKIX.getInitialPolicies();
//
// (d)
//
X509Certificate lastCert = (X509Certificate)certs.get(certs.size() - 1);
// BEGIN android-changed
TrustAnchor trust = CertPathValidatorUtilities.findTrustAnchor(lastCert,
certPath, certs.size() - 1, paramsPKIX);
// END android-changed
if (trust == null)
{
throw new CertPathValidatorException("TrustAnchor for CertPath not found.", null, certPath, -1);
}
//
// (e), (f), (g) are part of the paramsPKIX object.
//
Iterator certIter;
int index = 0;
int i;
//
// 6.1.2 - setup
//
//
// (a)
//
List [] policyNodes = new ArrayList[n + 1];
for (int j = 0; j < policyNodes.length; j++)
{
policyNodes[j] = new ArrayList();
}
Set policySet = new HashSet();
policySet.add(ANY_POLICY);
PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(), ANY_POLICY, false);
policyNodes[0].add(validPolicyTree);
//
// (b)
//
Set permittedSubtreesDN = new HashSet();
Set permittedSubtreesEmail = new HashSet();
Set permittedSubtreesIP = new HashSet();
//
// (c)
//
Set excludedSubtreesDN = new HashSet();
Set excludedSubtreesEmail = new HashSet();
Set excludedSubtreesIP = new HashSet();
//
// (d)
//
int explicitPolicy;
Set acceptablePolicies = null;
if (paramsPKIX.isExplicitPolicyRequired())
{
explicitPolicy = 0;
}
else
{
explicitPolicy = n + 1;
}
//
// (e)
//
int inhibitAnyPolicy;
if (paramsPKIX.isAnyPolicyInhibited())
{
inhibitAnyPolicy = 0;
}
else
{
inhibitAnyPolicy = n + 1;
}
//
// (f)
//
int policyMapping;
if (paramsPKIX.isPolicyMappingInhibited())
{
policyMapping = 0;
}
else
{
policyMapping = n + 1;
}
//
// (g), (h), (i), (j)
//
PublicKey workingPublicKey;
X500Principal workingIssuerName;
X509Certificate sign = trust.getTrustedCert();
boolean trustAnchorInChain = false;
try
{
if (sign != null)
{
workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
workingPublicKey = sign.getPublicKey();
// There is similar code in CertPathValidatorUtilities.
try {
byte[] trustBytes = sign.getEncoded();
byte[] certBytes = lastCert.getEncoded();
trustAnchorInChain = Arrays.equals(trustBytes, certBytes);
} catch(Exception e) {
// ignore, continue with trustAnchorInChain being false
}
}
else
{
workingIssuerName = new X500Principal(trust.getCAName());
workingPublicKey = trust.getCAPublicKey();
}
}
catch (IllegalArgumentException ex)
{
throw new CertPathValidatorException("TrustAnchor subjectDN: " + ex.toString());
}
AlgorithmIdentifier workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
DERObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId();
DEREncodable workingPublicKeyParameters = workingAlgId.getParameters();
//
// (k)
//
int maxPathLength = n;
//
// 6.1.3
//
Iterator tmpIter;
int tmpInt;
if (paramsPKIX.getTargetCertConstraints() != null
&& !paramsPKIX.getTargetCertConstraints().match((X509Certificate)certs.get(0)))
{
throw new CertPathValidatorException("target certificate in certpath does not match targetcertconstraints", null, certPath, 0);
}
//
// initialise CertPathChecker's
//
List pathCheckers = paramsPKIX.getCertPathCheckers();
certIter = pathCheckers.iterator();
while (certIter.hasNext())
{
((PKIXCertPathChecker)certIter.next()).init(false);
}
X509Certificate cert = null;
for (index = certs.size() - 1; index >= 0 ; index--)
{
try
{
//
// i as defined in the algorithm description
//
i = n - index;
//
// set certificate to be checked in this round
// sign and workingPublicKey and workingIssuerName are set
// at the end of the for loop and initialied the
// first time from the TrustAnchor
//
cert = (X509Certificate)certs.get(index);
//
// 6.1.3
//
//
// (a) verify
//
try
{
// (a) (1)
//
if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
{
cert.verify(workingPublicKey, "BC");
}
}
catch (GeneralSecurityException e)
{
throw new CertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
}
try
{
// (a) (2)
//
cert.checkValidity(validDate);
}
catch (CertificateExpiredException e)
{
throw new CertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
}
catch (CertificateNotYetValidException e)
{
throw new CertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
}
//
// (a) (3)
//
if (paramsPKIX.isRevocationEnabled())
{
checkCRLs(paramsPKIX, cert, validDate, sign, workingPublicKey);
}
//
// (a) (4) name chaining
//
if (!CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).equals(workingIssuerName))
{
throw new CertPathValidatorException(
"IssuerName(" + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert) +
") does not match SubjectName(" + workingIssuerName +
") of signing certificate", null, certPath, index);
}
//
// (b), (c) permitted and excluded subtree checking.
//
if (!(CertPathValidatorUtilities.isSelfIssued(cert) && (i < n)))
{
X500Principal principal = CertPathValidatorUtilities.getSubjectPrincipal(cert);
ASN1InputStream aIn = new ASN1InputStream(principal.getEncoded());
ASN1Sequence dns;
try
{
dns = (ASN1Sequence)aIn.readObject();
}
catch (IOException e)
{
throw new CertPathValidatorException("exception extracting subject name when checking subtrees");
}
CertPathValidatorUtilities.checkPermittedDN(permittedSubtreesDN, dns);
CertPathValidatorUtilities.checkExcludedDN(excludedSubtreesDN, dns);
ASN1Sequence altName = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, SUBJECT_ALTERNATIVE_NAME);
if (altName != null)
{
for (int j = 0; j < altName.size(); j++)
{
ASN1TaggedObject o = (ASN1TaggedObject)altName.getObjectAt(j);
switch(o.getTagNo())
{
case 1:
String email = DERIA5String.getInstance(o, true).getString();
CertPathValidatorUtilities.checkPermittedEmail(permittedSubtreesEmail, email);
CertPathValidatorUtilities.checkExcludedEmail(excludedSubtreesEmail, email);
break;
case 4:
ASN1Sequence altDN = ASN1Sequence.getInstance(o, true);
CertPathValidatorUtilities.checkPermittedDN(permittedSubtreesDN, altDN);
CertPathValidatorUtilities.checkExcludedDN(excludedSubtreesDN, altDN);
break;
case 7:
byte[] ip = ASN1OctetString.getInstance(o, true).getOctets();
CertPathValidatorUtilities.checkPermittedIP(permittedSubtreesIP, ip);
CertPathValidatorUtilities.checkExcludedIP(excludedSubtreesIP, ip);
}
}
}
}
//
// (d) policy Information checking against initial policy and
// policy mapping
//
ASN1Sequence certPolicies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, CERTIFICATE_POLICIES);
if (certPolicies != null && validPolicyTree != null)
{
//
// (d) (1)
//
Enumeration e = certPolicies.getObjects();
Set pols = new HashSet();
while (e.hasMoreElements())
{
PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
DERObjectIdentifier pOid = pInfo.getPolicyIdentifier();
pols.add(pOid.getId());
if (!ANY_POLICY.equals(pOid.getId()))
{
Set pq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
boolean match = CertPathValidatorUtilities.processCertD1i(i, policyNodes, pOid, pq);
if (!match)
{
CertPathValidatorUtilities.processCertD1ii(i, policyNodes, pOid, pq);
}
}
}
if (acceptablePolicies == null || acceptablePolicies.contains(ANY_POLICY))
{
acceptablePolicies = pols;
}
else
{
Iterator it = acceptablePolicies.iterator();
Set t1 = new HashSet();
while (it.hasNext())
{
Object o = it.next();
if (pols.contains(o))
{
t1.add(o);
}
}
acceptablePolicies = t1;
}
//
// (d) (2)
//
if ((inhibitAnyPolicy > 0) || ((i < n) && CertPathValidatorUtilities.isSelfIssued(cert)))
{
e = certPolicies.getObjects();
while (e.hasMoreElements())
{
PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
if (ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
{
Set _apq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
List _nodes = policyNodes[i - 1];
for (int k = 0; k < _nodes.size(); k++)
{
PKIXPolicyNode _node = (PKIXPolicyNode)_nodes.get(k);
Iterator _policySetIter = _node.getExpectedPolicies().iterator();
while (_policySetIter.hasNext())
{
Object _tmp = _policySetIter.next();
String _policy;
if (_tmp instanceof String)
{
_policy = (String)_tmp;
}
else if (_tmp instanceof DERObjectIdentifier)
{
_policy = ((DERObjectIdentifier)_tmp).getId();
}
else
{
continue;
}
boolean _found = false;
Iterator _childrenIter = _node.getChildren();
while (_childrenIter.hasNext())
{
PKIXPolicyNode _child = (PKIXPolicyNode)_childrenIter.next();
if (_policy.equals(_child.getValidPolicy()))
{
_found = true;
}
}
if (!_found)
{
Set _newChildExpectedPolicies = new HashSet();
_newChildExpectedPolicies.add(_policy);
PKIXPolicyNode _newChild = new PKIXPolicyNode(new ArrayList(),
i,
_newChildExpectedPolicies,
_node,
_apq,
_policy,
false);
_node.addChild(_newChild);
policyNodes[i].add(_newChild);
}
}
}
break;
}
}
}
//
// (d) (3)
//
for (int j = (i - 1); j >= 0; j--)
{
List nodes = policyNodes[j];
for (int k = 0; k < nodes.size(); k++)
{
PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
if (!node.hasChildren())
{
validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, node);
if (validPolicyTree == null)
{
break;
}
}
}
}
//
// d (4)
//
Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
if (criticalExtensionOids != null)
{
boolean critical = criticalExtensionOids.contains(CERTIFICATE_POLICIES);
List nodes = policyNodes[i];
for (int j = 0; j < nodes.size(); j++)
{
PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j);
node.setCritical(critical);
}
}
}
//
// (e)
//
if (certPolicies == null)
{
validPolicyTree = null;
}
//
// (f)
//
if (explicitPolicy <= 0 && validPolicyTree == null)
{
throw new CertPathValidatorException("No valid policy tree found when one expected.");
}
//
// 6.1.4
//
if (i != n) // if not at the end-entity certificate
{
if (cert != null && cert.getVersion() == 1)
{
if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
{
throw new CertPathValidatorException(
"Version 1 certs can't be used as intermediate certificates");
}
}
//
//
// (a) check the policy mappings
//
DERObject pm = CertPathValidatorUtilities.getExtensionValue(cert, POLICY_MAPPINGS);
if (pm != null)
{
ASN1Sequence mappings = (ASN1Sequence)pm;
for (int j = 0; j < mappings.size(); j++)
{
ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
DERObjectIdentifier issuerDomainPolicy = (DERObjectIdentifier)mapping.getObjectAt(0);
DERObjectIdentifier subjectDomainPolicy = (DERObjectIdentifier)mapping.getObjectAt(1);
if (ANY_POLICY.equals(issuerDomainPolicy.getId()))
{
throw new CertPathValidatorException("IssuerDomainPolicy is anyPolicy");
}
if (ANY_POLICY.equals(subjectDomainPolicy.getId()))
{
throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy");
}
}
}
// (b)
//
if (pm != null)
{
ASN1Sequence mappings = (ASN1Sequence)pm;
Map m_idp = new HashMap();
Set s_idp = new HashSet();
for (int j = 0; j < mappings.size(); j++)
{
ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
String id_p = ((DERObjectIdentifier)mapping.getObjectAt(0)).getId();
String sd_p = ((DERObjectIdentifier)mapping.getObjectAt(1)).getId();
Set tmp;
if (!m_idp.containsKey(id_p))
{
tmp = new HashSet();
tmp.add(sd_p);
m_idp.put(id_p, tmp);
s_idp.add(id_p);
}
else
{
tmp = (Set)m_idp.get(id_p);
tmp.add(sd_p);
}
}
Iterator it_idp = s_idp.iterator();
while (it_idp.hasNext())
{
String id_p = (String)it_idp.next();
//
// (1)
//
if (policyMapping > 0)
{
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 = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(
cert, CERTIFICATE_POLICIES);
Enumeration e = policies.getObjects();
while (e.hasMoreElements())
{
PolicyInformation pinfo = PolicyInformation.getInstance(e.nextElement());
if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
{
pq = CertPathValidatorUtilities.getQualifierSet(pinfo.getPolicyQualifiers());
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;
}
}
}
//
// (2)
//
}
else if (policyMapping <= 0)
{
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 = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, node2);
if (validPolicyTree == null)
{
break;
}
}
}
}
}
}
}
}
}
//
// (g) handle the name constraints extension
//
ASN1Sequence ncSeq = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, NAME_CONSTRAINTS);
if (ncSeq != null)
{
NameConstraints nc = new NameConstraints(ncSeq);
//
// (g) (1) permitted subtrees
//
ASN1Sequence permitted = nc.getPermittedSubtrees();
if (permitted != null)
{
Enumeration e = permitted.getObjects();
while (e.hasMoreElements())
{
GeneralSubtree subtree = GeneralSubtree.getInstance(e.nextElement());
GeneralName base = subtree.getBase();
switch(base.getTagNo())
{
case 1:
permittedSubtreesEmail = CertPathValidatorUtilities.intersectEmail(permittedSubtreesEmail, DERIA5String.getInstance(base.getName()).getString());
break;
case 4:
permittedSubtreesDN = CertPathValidatorUtilities.intersectDN(permittedSubtreesDN, (ASN1Sequence)base.getName());
break;
case 7:
permittedSubtreesIP = CertPathValidatorUtilities.intersectIP(permittedSubtreesIP, ASN1OctetString.getInstance(base.getName()).getOctets());
break;
}
}
}
//
// (g) (2) excluded subtrees
//
ASN1Sequence excluded = nc.getExcludedSubtrees();
if (excluded != null)
{
Enumeration e = excluded.getObjects();
while (e.hasMoreElements())
{
GeneralSubtree subtree = GeneralSubtree.getInstance(e.nextElement());
GeneralName base = subtree.getBase();
switch(base.getTagNo())
{
case 1:
excludedSubtreesEmail = CertPathValidatorUtilities.unionEmail(excludedSubtreesEmail, DERIA5String.getInstance(base.getName()).getString());
break;
case 4:
excludedSubtreesDN = CertPathValidatorUtilities.unionDN(excludedSubtreesDN, (ASN1Sequence)base.getName());
break;
case 7:
excludedSubtreesIP = CertPathValidatorUtilities.unionIP(excludedSubtreesIP, ASN1OctetString.getInstance(base.getName()).getOctets());
break;
}
}
}
}
//
// (h)
//
if (!CertPathValidatorUtilities.isSelfIssued(cert))
{
//
// (1)
//
if (explicitPolicy != 0)
{
explicitPolicy--;
}
//
// (2)
//
if (policyMapping != 0)
{
policyMapping--;
}
//
// (3)
//
if (inhibitAnyPolicy != 0)
{
inhibitAnyPolicy--;
}
}
//
// (i)
//
ASN1Sequence pc = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, POLICY_CONSTRAINTS);
if (pc != null)
{
Enumeration policyConstraints = pc.getObjects();
while (policyConstraints.hasMoreElements())
{
ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
switch (constraint.getTagNo())
{
case 0:
tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
if (tmpInt < explicitPolicy)
{
explicitPolicy = tmpInt;
}
break;
case 1:
tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
if (tmpInt < policyMapping)
{
policyMapping = tmpInt;
}
break;
}
}
}
//
// (j)
//
DERInteger iap = (DERInteger)CertPathValidatorUtilities.getExtensionValue(cert, INHIBIT_ANY_POLICY);
if (iap != null)
{
int _inhibitAnyPolicy = iap.getValue().intValue();
if (_inhibitAnyPolicy < inhibitAnyPolicy)
{
inhibitAnyPolicy = _inhibitAnyPolicy;
}
}
//
// (k)
//
BasicConstraints bc = BasicConstraints.getInstance(
CertPathValidatorUtilities.getExtensionValue(cert, BASIC_CONSTRAINTS));
if (bc != null)
{
if (!(bc.isCA()))
{
throw new CertPathValidatorException("Not a CA certificate");
}
}
else
{
if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
{
throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints");
}
}
//
// (l)
//
if (!CertPathValidatorUtilities.isSelfIssued(cert))
{
if (maxPathLength <= 0)
{
throw new CertPathValidatorException("Max path length not greater than zero");
}
maxPathLength--;
}
//
// (m)
//
if (bc != null)
{
BigInteger _pathLengthConstraint = bc.getPathLenConstraint();
if (_pathLengthConstraint != null)
{
int _plc = _pathLengthConstraint.intValue();
if (_plc < maxPathLength)
{
maxPathLength = _plc;
}
}
}
//
// (n)
//
boolean[] _usage = cert.getKeyUsage();
if ((_usage != null) && !_usage[5])
{
throw new CertPathValidatorException(
"Issuer certificate keyusage extension is critical an does not permit key signing.\n",
null, certPath, index);
}
//
// (o)
//
if (cert.getCriticalExtensionOIDs() != null)
{
Set criticalExtensions = new HashSet(cert.getCriticalExtensionOIDs());
// these extensions are handle by the algorithem
criticalExtensions.remove(KEY_USAGE);
criticalExtensions.remove(CERTIFICATE_POLICIES);
criticalExtensions.remove(POLICY_MAPPINGS);
criticalExtensions.remove(INHIBIT_ANY_POLICY);
criticalExtensions.remove(ISSUING_DISTRIBUTION_POINT);
criticalExtensions.remove(DELTA_CRL_INDICATOR);
criticalExtensions.remove(POLICY_CONSTRAINTS);
criticalExtensions.remove(BASIC_CONSTRAINTS);
criticalExtensions.remove(SUBJECT_ALTERNATIVE_NAME);
criticalExtensions.remove(NAME_CONSTRAINTS);
tmpIter = pathCheckers.iterator();
while (tmpIter.hasNext())
{
try
{
((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
}
catch (CertPathValidatorException e)
{
throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
}
}
if (!criticalExtensions.isEmpty())
{
throw new CertPathValidatorException(
"Certificate has unsupported critical extension", null, certPath, index);
}
}
}
// set signing certificate for next round
sign = cert;
workingPublicKey = sign.getPublicKey();
try
{
workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
}
catch (IllegalArgumentException ex)
{
throw new CertPathValidatorException(sign.getSubjectDN().getName() + " :" + ex.toString());
}
workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
workingPublicKeyAlgorithm = workingAlgId.getObjectId();
workingPublicKeyParameters = workingAlgId.getParameters();
}
catch (AnnotatedException e)
{
throw new CertPathValidatorException(e.getMessage(), e.getUnderlyingException(), certPath, index);
}
}
//
// 6.1.5 Wrap-up procedure
//
//
// (a)
//
if (!CertPathValidatorUtilities.isSelfIssued(cert) && (explicitPolicy != 0))
{
explicitPolicy--;
}
//
// (b)
//
try
{
ASN1Sequence pc = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, POLICY_CONSTRAINTS);
if (pc != null)
{
Enumeration policyConstraints = pc.getObjects();
while (policyConstraints.hasMoreElements())
{
ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
switch (constraint.getTagNo())
{
case 0:
tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
if (tmpInt == 0)
{
explicitPolicy = 0;
}
break;
}
}
}
}
catch (AnnotatedException e)
{
throw new CertPathValidatorException(e.getMessage(), e.getUnderlyingException(), certPath, index);
}
//
// (c) (d) and (e) are already done
//
//
// (f)
//
Set criticalExtensions = cert.getCriticalExtensionOIDs();
if (criticalExtensions != null)
{
criticalExtensions = new HashSet(criticalExtensions);
// these extensions are handle by the algorithm
criticalExtensions.remove(KEY_USAGE);
criticalExtensions.remove(CERTIFICATE_POLICIES);
criticalExtensions.remove(POLICY_MAPPINGS);
criticalExtensions.remove(INHIBIT_ANY_POLICY);
criticalExtensions.remove(ISSUING_DISTRIBUTION_POINT);
criticalExtensions.remove(DELTA_CRL_INDICATOR);
criticalExtensions.remove(POLICY_CONSTRAINTS);
criticalExtensions.remove(BASIC_CONSTRAINTS);
criticalExtensions.remove(SUBJECT_ALTERNATIVE_NAME);
criticalExtensions.remove(NAME_CONSTRAINTS);
}
else
{
criticalExtensions = new HashSet();
}
tmpIter = pathCheckers.iterator();
while (tmpIter.hasNext())
{
try
{
((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
}
catch (CertPathValidatorException e)
{
throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
}
}
if (!criticalExtensions.isEmpty())
{
throw new CertPathValidatorException(
"Certificate has unsupported critical extension", null, certPath, index);
}
//
// (g)
//
PKIXPolicyNode intersection;
//
// (g) (i)
//
if (validPolicyTree == null)
{
if (paramsPKIX.isExplicitPolicyRequired())
{
throw new CertPathValidatorException("Explicit policy requested but none available.");
}
intersection = null;
}
else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g) (ii)
{
if (paramsPKIX.isExplicitPolicyRequired())
{
if (acceptablePolicies.isEmpty())
{
throw new CertPathValidatorException("Explicit policy requested but none available.");
}
else
{
Set _validPolicyNodeSet = new HashSet();
for (int j = 0; j < policyNodes.length; j++)
{
List _nodeDepth = policyNodes[j];
for (int k = 0; k < _nodeDepth.size(); k++)
{
PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
if (ANY_POLICY.equals(_node.getValidPolicy()))
{
Iterator _iter = _node.getChildren();
while (_iter.hasNext())
{
_validPolicyNodeSet.add(_iter.next());
}
}
}
}
Iterator _vpnsIter = _validPolicyNodeSet.iterator();
while (_vpnsIter.hasNext())
{
PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
String _validPolicy = _node.getValidPolicy();
if (!acceptablePolicies.contains(_validPolicy))
{
//validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, _node);
}
}
if (validPolicyTree != null)
{
for (int j = (n - 1); j >= 0; j--)
{
List nodes = policyNodes[j];
for (int k = 0; k < nodes.size(); k++)
{
PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
if (!node.hasChildren())
{
validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, node);
}
}
}
}
}
}
intersection = validPolicyTree;
}
else
{
//
// (g) (iii)
//
// This implementation is not exactly same as the one described in RFC3280.
// However, as far as the validation result is concerned, both produce
// adequate result. The only difference is whether AnyPolicy is remain
// in the policy tree or not.
//
// (g) (iii) 1
//
Set _validPolicyNodeSet = new HashSet();
for (int j = 0; j < policyNodes.length; j++)
{
List _nodeDepth = policyNodes[j];
for (int k = 0; k < _nodeDepth.size(); k++)
{
PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
if (ANY_POLICY.equals(_node.getValidPolicy()))
{
Iterator _iter = _node.getChildren();
while (_iter.hasNext())
{
PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
if (!ANY_POLICY.equals(_c_node.getValidPolicy()))
{
_validPolicyNodeSet.add(_c_node);
}
}
}
}
}
//
// (g) (iii) 2
//
Iterator _vpnsIter = _validPolicyNodeSet.iterator();
while (_vpnsIter.hasNext())
{
PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
String _validPolicy = _node.getValidPolicy();
if (!userInitialPolicySet.contains(_validPolicy))
{
validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, _node);
}
}
//
// (g) (iii) 4
//
if (validPolicyTree != null)
{
for (int j = (n - 1); j >= 0; j--)
{
List nodes = policyNodes[j];
for (int k = 0; k < nodes.size(); k++)
{
PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
if (!node.hasChildren())
{
validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, node);
}
}
}
}
intersection = validPolicyTree;
}
if ((explicitPolicy > 0) || (intersection != null))
{
return new PKIXCertPathValidatorResult(trust, intersection, workingPublicKey);
}
throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index);
}
private void checkCRLs(PKIXParameters paramsPKIX, X509Certificate cert, Date validDate, X509Certificate sign, PublicKey workingPublicKey)
throws AnnotatedException
{
X509CRLSelector crlselect;
crlselect = new X509CRLSelector();
try
{
crlselect.addIssuerName(CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).getEncoded());
}
catch (IOException e)
{
throw new AnnotatedException("Cannot extract issuer from certificate: " + e, e);
}
crlselect.setCertificateChecking(cert);
Iterator crl_iter = CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getCertStores()).iterator();
boolean validCrlFound = false;
X509CRLEntry crl_entry;
while (crl_iter.hasNext())
{
X509CRL crl = (X509CRL)crl_iter.next();
if (cert.getNotAfter().after(crl.getThisUpdate()))
{
if (crl.getNextUpdate() == null
|| validDate.before(crl.getNextUpdate()))
{
validCrlFound = true;
}
if (sign != null)
{
boolean[] keyusage = sign.getKeyUsage();
if (keyusage != null
&& (keyusage.length < 7 || !keyusage[CRL_SIGN]))
{
throw new AnnotatedException(
"Issuer certificate keyusage extension does not permit crl signing.\n" + sign);
}
}
try
{
crl.verify(workingPublicKey, "BC");
}
catch (Exception e)
{
throw new AnnotatedException("can't verify CRL: " + e, e);
}
crl_entry = crl.getRevokedCertificate(cert.getSerialNumber());
if (crl_entry != null
&& !validDate.before(crl_entry.getRevocationDate()))
{
String reason = null;
if (crl_entry.hasExtensions())
{
DEREnumerated reasonCode = DEREnumerated.getInstance(CertPathValidatorUtilities.getExtensionValue(crl_entry, X509Extensions.ReasonCode.getId()));
if (reasonCode != null)
{
reason = crlReasons[reasonCode.getValue().intValue()];
}
}
String message = "Certificate revocation after " + crl_entry.getRevocationDate();
if (reason != null)
{
message += ", reason: " + reason;
}
throw new AnnotatedException(message);
}
//
// check the DeltaCRL indicator, base point and the issuing distribution point
//
DERObject idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
DERObject dci = CertPathValidatorUtilities.getExtensionValue(crl, DELTA_CRL_INDICATOR);
if (dci != null)
{
X509CRLSelector baseSelect = new X509CRLSelector();
try
{
baseSelect.addIssuerName(CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded());
}
catch (IOException e)
{
throw new AnnotatedException("can't extract issuer from certificate: " + e, e);
}
baseSelect.setMinCRLNumber(((DERInteger)dci).getPositiveValue());
baseSelect.setMaxCRLNumber(((DERInteger)CertPathValidatorUtilities.getExtensionValue(crl, CRL_NUMBER)).getPositiveValue().subtract(BigInteger.valueOf(1)));
boolean foundBase = false;
Iterator it = CertPathValidatorUtilities.findCRLs(baseSelect, paramsPKIX.getCertStores()).iterator();
while (it.hasNext())
{
X509CRL base = (X509CRL)it.next();
DERObject baseIdp = CertPathValidatorUtilities.getExtensionValue(base, ISSUING_DISTRIBUTION_POINT);
if (idp == null)
{
if (baseIdp == null)
{
foundBase = true;
break;
}
}
else
{
if (idp.equals(baseIdp))
{
foundBase = true;
break;
}
}
}
if (!foundBase)
{
throw new AnnotatedException("No base CRL for delta CRL");
}
}
if (idp != null)
{
IssuingDistributionPoint p = IssuingDistributionPoint.getInstance(idp);
BasicConstraints bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, BASIC_CONSTRAINTS));
if (p.onlyContainsUserCerts() && (bc != null && bc.isCA()))
{
throw new AnnotatedException("CA Cert CRL only contains user certificates");
}
if (p.onlyContainsCACerts() && (bc == null || !bc.isCA()))
{
throw new AnnotatedException("End CRL only contains CA certificates");
}
if (p.onlyContainsAttributeCerts())
{
throw new AnnotatedException("onlyContainsAttributeCerts boolean is asserted");
}
}
}
}
if (!validCrlFound)
{
throw new AnnotatedException("no valid CRL found");
}
}
}