diff options
Diffstat (limited to 'libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java')
-rw-r--r-- | libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java | 2182 |
1 files changed, 2182 insertions, 0 deletions
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java new file mode 100644 index 000000000..fef14a6be --- /dev/null +++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java @@ -0,0 +1,2182 @@ +package org.spongycastle.jce.provider; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.PublicKey; +import java.security.cert.CRLException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertPath; +import java.security.cert.CertPathParameters; +import java.security.cert.CertPathValidatorSpi; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorResult; +import java.security.cert.PolicyQualifierInfo; +import java.security.cert.X509Certificate; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLEntry; +import java.security.cert.X509CRLSelector; +import java.security.cert.X509CertSelector; +import java.security.cert.PKIXParameters; +import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.TrustAnchor; +import java.security.cert.PKIXParameters; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.util.ArrayList; +import java.util.Collection; +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 java.util.TimeZone; + +import org.spongycastle.jce.X509Principal; +import org.spongycastle.jce.PrincipalUtil; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1OutputStream; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1TaggedObject; +import org.spongycastle.asn1.BERConstructedOctetString; +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.DEREnumerated; +import org.spongycastle.asn1.DERIA5String; +import org.spongycastle.asn1.DERInteger; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.DERObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.BasicConstraints; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralSubtree; +import org.spongycastle.asn1.x509.IssuingDistributionPoint; +import org.spongycastle.asn1.x509.NameConstraints; +import org.spongycastle.asn1.x509.PolicyInformation; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.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" }; + + /** + * extract the value of the given extension, if it exists. + */ + private ASN1Primitive 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 ASN1Primitive 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 (IOException e) + { + throw new AnnotatedException("exception processing extension " + oid, e); + } + } + + private boolean withinDNSubtree( + ASN1Sequence dns, + ASN1Sequence subtree) + { + if (subtree.size() < 1) + { + return false; + } + + if (subtree.size() > dns.size()) + { + return false; + } + + for (int j = subtree.size() - 1; j >= 0; j--) + { + if (!subtree.getObjectAt(j).equals(dns.getObjectAt(j))) + { + return false; + } + } + + return true; + } + + private void checkPermittedDN( + Set permitted, + ASN1Sequence dns) + throws CertPathValidatorException + { + if (permitted.isEmpty()) + { + return; + } + + Iterator it = permitted.iterator(); + + while (it.hasNext()) + { + ASN1Sequence subtree = (ASN1Sequence)it.next(); + + if (withinDNSubtree(dns, subtree)) + { + return; + } + } + + throw new CertPathValidatorException("Subject distinguished name is not from a permitted subtree"); + } + + private void checkExcludedDN( + Set excluded, + ASN1Sequence dns) + throws CertPathValidatorException + { + if (excluded.isEmpty()) + { + return; + } + + Iterator it = excluded.iterator(); + + while (it.hasNext()) + { + ASN1Sequence subtree = (ASN1Sequence)it.next(); + + if (withinDNSubtree(dns, subtree)) + { + throw new CertPathValidatorException("Subject distinguished name is from an excluded subtree"); + } + } + } + + private Set intersectDN( + Set permitted, + ASN1Sequence dn) + { + if (permitted.isEmpty()) + { + permitted.add(dn); + + return permitted; + } + else + { + Set intersect = new HashSet(); + + Iterator _iter = permitted.iterator(); + while (_iter.hasNext()) + { + ASN1Sequence subtree = (ASN1Sequence)_iter.next(); + + if (withinDNSubtree(dn, subtree)) + { + intersect.add(dn); + } + else if (withinDNSubtree(subtree, dn)) + { + intersect.add(subtree); + } + } + + return intersect; + } + } + + private Set unionDN( + Set excluded, + ASN1Sequence dn) + { + if (excluded.isEmpty()) + { + excluded.add(dn); + + return excluded; + } + else + { + Set intersect = new HashSet(); + + Iterator _iter = excluded.iterator(); + while (_iter.hasNext()) + { + ASN1Sequence subtree = (ASN1Sequence)_iter.next(); + + if (withinDNSubtree(dn, subtree)) + { + intersect.add(subtree); + } + else if (withinDNSubtree(subtree, dn)) + { + intersect.add(dn); + } + else + { + intersect.add(subtree); + intersect.add(dn); + } + } + + return intersect; + } + } + + private Set intersectEmail( + Set permitted, + String email) + { + String _sub = email.substring(email.indexOf('@') + 1); + + if (permitted.isEmpty()) + { + permitted.add(_sub); + + return permitted; + } + else + { + Set intersect = new HashSet(); + + Iterator _iter = permitted.iterator(); + while (_iter.hasNext()) + { + String _permitted = (String)_iter.next(); + + if (_sub.endsWith(_permitted)) + { + intersect.add(_sub); + } + else if (_permitted.endsWith(_sub)) + { + intersect.add(_permitted); + } + } + + return intersect; + } + } + + private Set unionEmail( + Set excluded, + String email) + { + String _sub = email.substring(email.indexOf('@') + 1); + + if (excluded.isEmpty()) + { + excluded.add(_sub); + return excluded; + } + else + { + Set intersect = new HashSet(); + + Iterator _iter = excluded.iterator(); + while (_iter.hasNext()) + { + String _excluded = (String)_iter.next(); + + if (_sub.endsWith(_excluded)) + { + intersect.add(_excluded); + } + else if (_excluded.endsWith(_sub)) + { + intersect.add(_sub); + } + else + { + intersect.add(_excluded); + intersect.add(_sub); + } + } + + return intersect; + } + } + + private Set intersectIP( + Set permitted, + byte[] ip) + { + // TBD + return permitted; + } + + private Set unionIP( + Set excluded, + byte[] ip) + { + // TBD + return excluded; + } + + private void checkPermittedEmail( + Set permitted, + String email) + throws CertPathValidatorException + { + if (permitted.isEmpty()) + { + return; + } + + String sub = email.substring(email.indexOf('@') + 1); + Iterator it = permitted.iterator(); + + while (it.hasNext()) + { + String str = (String)it.next(); + + if (sub.endsWith(str)) + { + return; + } + } + + throw new CertPathValidatorException("Subject email address is not from a permitted subtree"); + } + + private void checkExcludedEmail( + Set excluded, + String email) + throws CertPathValidatorException + { + if (excluded.isEmpty()) + { + return; + } + + String sub = email.substring(email.indexOf('@') + 1); + Iterator it = excluded.iterator(); + + while (it.hasNext()) + { + String str = (String)it.next(); + if (sub.endsWith(str)) + { + throw new CertPathValidatorException("Subject email address is from an excluded subtree"); + } + } + } + + private void checkPermittedIP( + Set permitted, + byte[] ip) + throws CertPathValidatorException + { + if (permitted.isEmpty()) + { + return; + } + + // TODO: ??? Something here + } + + private void checkExcludedIP( + Set excluded, + byte[] ip) + throws CertPathValidatorException + { + if (excluded.isEmpty()) + { + return; + } + + // TODO, check RFC791 and RFC1883 for IP bytes definition. + } + + private 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 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); + } + } + } + + private boolean isSelfIssued( + X509Certificate cert) + { + return cert.getSubjectDN().equals(cert.getIssuerDN()); + } + + private boolean isAnyPolicy( + Set policySet) + { + return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty(); + } + + private AlgorithmIdentifier getAlgorithmIdentifier( + PublicKey key) + throws CertPathValidatorException + { + try + { + ASN1InputStream aIn = new ASN1InputStream( + new ByteArrayInputStream(key.getEncoded())); + + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject()); + + return info.getAlgorithmId(); + } + catch (IOException e) + { + throw new CertPathValidatorException("exception processing public key"); + } + } + + private 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((ASN1Encodable)e.nextElement()); + + pq.add(new PolicyQualifierInfo(bOut.toByteArray())); + } + catch (IOException ex) + { + throw new CertPathValidatorException("exception building qualifier set: " + ex); + } + + bOut.reset(); + } + + return pq; + } + + private 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; + } + + private 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); + Set _expectedPolicies = _node.getExpectedPolicies(); + + 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; + } + } + } + + 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 = getValidDate(paramsPKIX); + + // + // (c) + // + Set userInitialPolicySet = paramsPKIX.getInitialPolicies(); + + // + // (d) + // + TrustAnchor trust = findTrustAnchor((X509Certificate)certs.get(certs.size() - 1), certPath, certs.size() - 1, paramsPKIX.getTrustAnchors()); + + 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; + //Certificate for each interation of the validation loop + //Signature information for each iteration of the validation loop + Set subTreeContraints = new HashSet(); + Set subTreeExcludes = new HashSet(); + + // + // 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; + X509Principal workingIssuerName; + + X509Certificate sign = trust.getTrustedCert(); + try + { + if (sign != null) + { + workingIssuerName = getSubjectPrincipal(sign); + workingPublicKey = sign.getPublicKey(); + } + else + { + workingIssuerName = new X509Principal(trust.getCAName()); + workingPublicKey = trust.getCAPublicKey(); + } + } + catch (IllegalArgumentException ex) + { + throw new CertPathValidatorException("TrustAnchor subjectDN: " + ex.toString()); + } + catch (AnnotatedException ex) + { + throw new CertPathValidatorException(ex.getMessage(), ex.getUnderlyingException(), certPath, index); + } + + AlgorithmIdentifier workingAlgId = getAlgorithmIdentifier(workingPublicKey); + DERObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId(); + ASN1Encodable 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) + // + cert.verify(workingPublicKey, "SC"); + } + catch (Exception 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 (!getEncodedIssuerPrincipal(cert).equals(workingIssuerName)) + { + throw new CertPathValidatorException( + "IssuerName(" + getEncodedIssuerPrincipal(cert) + + ") does not match SubjectName(" + workingIssuerName + + ") of signing certificate", null, certPath, index); + } + + // + // (b), (c) permitted and excluded subtree checking. + // + if (!(isSelfIssued(cert) && (i < n))) + { + X509Principal principal = getSubjectPrincipal(cert); + ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(principal.getEncoded())); + ASN1Sequence dns; + + try + { + dns = (ASN1Sequence)aIn.readObject(); + } + catch (IOException e) + { + throw new CertPathValidatorException("exception extracting subject name when checking subtrees"); + } + + checkPermittedDN(permittedSubtreesDN, dns); + + checkExcludedDN(excludedSubtreesDN, dns); + + ASN1Sequence altName = (ASN1Sequence)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(); + + checkPermittedEmail(permittedSubtreesEmail, email); + checkExcludedEmail(excludedSubtreesEmail, email); + break; + case 4: + ASN1Sequence altDN = ASN1Sequence.getInstance(o, true); + + checkPermittedDN(permittedSubtreesDN, altDN); + checkExcludedDN(excludedSubtreesDN, altDN); + break; + case 7: + byte[] ip = ASN1OctetString.getInstance(o, true).getOctets(); + + checkPermittedIP(permittedSubtreesIP, ip); + checkExcludedIP(excludedSubtreesIP, ip); + } + } + } + } + + // + // (d) policy Information checking against initial policy and + // policy mapping + // + ASN1Sequence certPolicies = (ASN1Sequence)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 = getQualifierSet(pInfo.getPolicyQualifiers()); + + boolean match = processCertD1i(i, policyNodes, pOid, pq); + + if (!match) + { + 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) && isSelfIssued(cert))) + { + e = certPolicies.getObjects(); + + while (e.hasMoreElements()) + { + PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement()); + + if (ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId())) + { + Set _apq = 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 = 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 (cert != null && cert.getVersion() == 1) + { + throw new CertPathValidatorException( + "Version 1 certs can't be used as CA ones"); + } + + // + // + // (a) check the policy mappings + // + ASN1Primitive pm = 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)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 = 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 = removePolicyNode(validPolicyTree, policyNodes, node2); + if (validPolicyTree == null) + { + break; + } + } + } + } + } + } + } + } + } + + // + // (g) handle the name constraints extension + // + ASN1Sequence ncSeq = (ASN1Sequence)getExtensionValue(cert, NAME_CONSTRAINTS); + if (ncSeq != null) + { + NameConstraints nc = NameConstraints.getInstance(ncSeq); + + // + // (g) (1) permitted subtrees + // + GeneralSubtree[] permitted = nc.getPermittedSubtrees(); + if (permitted != null) + { + for (int indx = 0; indx != permitted.length; indx++) + { + GeneralSubtree subtree = permitted[indx]; + GeneralName base = subtree.getBase(); + + switch(base.getTagNo()) + { + case 1: + permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail, DERIA5String.getInstance(base.getName()).getString()); + break; + case 4: + permittedSubtreesDN = intersectDN(permittedSubtreesDN, (ASN1Sequence)base.getName()); + break; + case 7: + permittedSubtreesIP = intersectIP(permittedSubtreesIP, BERConstructedOctetString.fromSequence((ASN1Sequence)base.getName()).getOctets()); + break; + } + } + } + + // + // (g) (2) excluded subtrees + // + GeneralSubtree[] excluded = nc.getExcludedSubtrees(); + if (excluded != null) + { + for (int indx = 0; indx != excluded.length; indx++) + { + GeneralSubtree subtree = excluded[indx]; + GeneralName base = subtree.getBase(); + + switch(base.getTagNo()) + { + case 1: + excludedSubtreesEmail = unionEmail(excludedSubtreesEmail, DERIA5String.getInstance(base.getName()).getString()); + break; + case 4: + excludedSubtreesDN = unionDN(excludedSubtreesDN, (ASN1Sequence)base.getName()); + break; + case 7: + excludedSubtreesIP = unionIP(excludedSubtreesIP, BERConstructedOctetString.fromSequence((ASN1Sequence)base.getName()).getOctets()); + break; + } + } + } + } + + // + // (h) + // + if (!isSelfIssued(cert)) + { + // + // (1) + // + if (explicitPolicy != 0) + { + explicitPolicy--; + } + + // + // (2) + // + if (policyMapping != 0) + { + policyMapping--; + } + + // + // (3) + // + if (inhibitAnyPolicy != 0) + { + inhibitAnyPolicy--; + } + } + + // + // (i) + // + ASN1Sequence pc = (ASN1Sequence)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)getExtensionValue(cert, INHIBIT_ANY_POLICY); + + if (iap != null) + { + int _inhibitAnyPolicy = iap.getValue().intValue(); + + if (_inhibitAnyPolicy < inhibitAnyPolicy) + { + inhibitAnyPolicy = _inhibitAnyPolicy; + } + } + + // + // (k) + // + BasicConstraints bc = BasicConstraints.getInstance( + getExtensionValue(cert, BASIC_CONSTRAINTS)); + if (bc != null) + { + if (!(bc.isCA())) + { + throw new CertPathValidatorException("Not a CA certificate"); + } + } + else + { + throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints"); + } + + // + // (l) + // + if (!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) + // + 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 = getSubjectPrincipal(sign); + } + catch (IllegalArgumentException ex) + { + throw new CertPathValidatorException(sign.getSubjectDN().getName() + " :" + ex.toString()); + } + workingAlgId = 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 (!isSelfIssued(cert) && (explicitPolicy != 0)) + { + explicitPolicy--; + } + + // + // (b) + // + try + { + ASN1Sequence pc = (ASN1Sequence)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 (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 = 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 = 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 = 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 Date getValidDate( + PKIXParameters paramsPKIX) + { + Date validDate = paramsPKIX.getDate(); + + if (validDate == null) + { + validDate = new Date(); + } + + return validDate; + } + + private void checkCRLs(PKIXParameters paramsPKIX, X509Certificate cert, Date validDate, X509Certificate sign, PublicKey workingPublicKey) + throws AnnotatedException + { + X509CRLSelector crlselect; + crlselect = new X509CRLSelector(); + + try + { + crlselect.addIssuerName(getEncodedIssuerPrincipal(cert).getEncoded()); + } + catch (IOException e) + { + throw new AnnotatedException("Cannot extract issuer from certificate: " + e, e); + } + + crlselect.setCertificateChecking(cert); + + Iterator crl_iter = 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, "SC"); + } + 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(getExtensionValue(crl_entry, X509Extensions.ReasonCode.getId())); + if (reasonCode != null) + { + reason = crlReasons[reasonCode.getValue().intValue()]; + } + } + + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + String message = "Certificate revocation after " + df.format(crl_entry.getRevocationDate()); + + if (reason != null) + { + message += ", reason: " + reason; + } + + throw new AnnotatedException(message); + } + + // + // check the DeltaCRL indicator, base point and the issuing distribution point + // + ASN1Primitive idp = getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT); + ASN1Primitive dci = getExtensionValue(crl, DELTA_CRL_INDICATOR); + + if (dci != null) + { + X509CRLSelector baseSelect = new X509CRLSelector(); + + try + { + baseSelect.addIssuerName(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)getExtensionValue(crl, CRL_NUMBER)).getPositiveValue().subtract(BigInteger.valueOf(1))); + + boolean foundBase = false; + Iterator it = findCRLs(baseSelect, paramsPKIX.getCertStores()).iterator(); + while (it.hasNext()) + { + X509CRL base = (X509CRL)it.next(); + + ASN1Primitive baseIdp = 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(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"); + } + } + + /** + * Return a Collection of all CRLs found in the + * CertStore's that are matching the crlSelect criteriums. + * + * @param certSelector a {@link CertSelector CertSelector} + * object that will be used to select the certificates + * @param certStores a List containing only {@link CertStore + * CertStore} objects. These are used to search for + * CRLs + * + * @return a Collection of all found {@link CRL CRL} + * objects. May be empty but never <code>null</code>. + */ + private Collection findCRLs( + X509CRLSelector crlSelect, + List crlStores) + throws AnnotatedException + { + Set crls = new HashSet(); + Iterator iter = crlStores.iterator(); + + while (iter.hasNext()) + { + CertStore certStore = (CertStore)iter.next(); + + try + { + crls.addAll(certStore.getCRLs(crlSelect)); + } + catch (CertStoreException e) + { + throw new AnnotatedException("cannot extract crl: " + e, e); + } + } + + return crls; + } + + /** + * Search the given Set of TrustAnchor's for one that is the + * issuer of the fiven X509 certificate. + * + * @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 CertPathValidatorException if a TrustAnchor was + * found but the signature verification on the given certificate + * has thrown an exception. This Exception can be obtainted with + * <code>getCause()</code> method. + **/ + final TrustAnchor findTrustAnchor( + X509Certificate cert, + CertPath certPath, + int index, + Set trustAnchors) + throws CertPathValidatorException + { + Iterator iter = trustAnchors.iterator(); + TrustAnchor trust = null; + PublicKey trustPublicKey = null; + Exception invalidKeyEx = null; + + X509CertSelector certSelectX509 = new X509CertSelector(); + + try + { + certSelectX509.setSubject(getEncodedIssuerPrincipal(cert).getEncoded()); + } + catch (IOException ex) + { + throw new CertPathValidatorException(ex); + } + catch (AnnotatedException ex) + { + throw new CertPathValidatorException(ex.getUnderlyingException()); + } + + while (iter.hasNext() && trust == null) + { + trust = (TrustAnchor)iter.next(); + if (trust.getTrustedCert() != null) + { + if (certSelectX509.match(trust.getTrustedCert())) + { + trustPublicKey = trust.getTrustedCert().getPublicKey(); + } + else + { + trust = null; + } + } + else if (trust.getCAName() != null + && trust.getCAPublicKey() != null) + { + try + { + X509Principal certIssuer = getEncodedIssuerPrincipal(cert); + X509Principal caName = new X509Principal(trust.getCAName()); + if (certIssuer.equals(caName)) + { + trustPublicKey = trust.getCAPublicKey(); + } + else + { + trust = null; + } + } + catch (AnnotatedException ex) + { + throw new CertPathValidatorException(ex.getMessage(), ex.getUnderlyingException(), certPath, index); + } + catch (IllegalArgumentException ex) + { + trust = null; + } + } + else + { + trust = null; + } + + if (trustPublicKey != null) + { + try + { + cert.verify(trustPublicKey); + } + catch (Exception ex) + { + invalidKeyEx = ex; + trust = null; + } + } + } + + if (trust == null && invalidKeyEx != null) + { + throw new CertPathValidatorException("TrustAnchor found but certificate validation failed.", invalidKeyEx, certPath, index); + } + + return trust; + } + + private X509Principal getIssuerPrincipal(X509CRL crl) + throws AnnotatedException + { + try + { + return PrincipalUtil.getIssuerX509Principal(crl); + } + catch (CRLException e) + { + throw new AnnotatedException("can't get CRL issuer principal", e); + } + } + + private X509Principal getEncodedIssuerPrincipal(X509Certificate cert) + throws AnnotatedException + { + try + { + return PrincipalUtil.getIssuerX509Principal(cert); + } + catch (CertificateEncodingException e) + { + throw new AnnotatedException("can't get issuer principal.", e); + } + } + + private X509Principal getSubjectPrincipal(X509Certificate cert) + throws AnnotatedException + { + try + { + return PrincipalUtil.getSubjectX509Principal(cert); + } + catch (CertificateEncodingException e) + { + throw new AnnotatedException("can't get subject principal.", e); + } + } +} |