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"); } } }