package org.bouncycastle.jce.provider; import java.io.IOException; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.PublicKey; import java.security.cert.CertPath; import java.security.cert.CertPathBuilder; import java.security.cert.CertPathBuilderException; import java.security.cert.CertPathValidatorException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.PKIXCertPathChecker; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.security.cert.X509Extension; 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.Vector; import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DEREncodable; import org.bouncycastle.asn1.DERInteger; import org.bouncycastle.asn1.DERObject; import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x509.BasicConstraints; import org.bouncycastle.asn1.x509.CRLDistPoint; import org.bouncycastle.asn1.x509.CRLReason; import org.bouncycastle.asn1.x509.DistributionPoint; import org.bouncycastle.asn1.x509.DistributionPointName; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.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; import org.bouncycastle.asn1.x509.X509Name; import org.bouncycastle.jce.exception.ExtCertPathValidatorException; import org.bouncycastle.util.Arrays; import org.bouncycastle.x509.ExtendedPKIXBuilderParameters; import org.bouncycastle.x509.ExtendedPKIXParameters; import org.bouncycastle.x509.X509CRLStoreSelector; import org.bouncycastle.x509.X509CertStoreSelector; public class RFC3280CertPathUtilities { private static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil(); /** * If the complete CRL includes an issuing distribution point (IDP) CRL * extension check the following: * <p/> * (i) If the distribution point name is present in the IDP CRL extension * and the distribution field is present in the DP, then verify that one of * the names in the IDP matches one of the names in the DP. If the * distribution point name is present in the IDP CRL extension and the * distribution field is omitted from the DP, then verify that one of the * names in the IDP matches one of the names in the cRLIssuer field of the * DP. * </p> * <p/> * (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL * extension, verify that the certificate does not include the basic * constraints extension with the cA boolean asserted. * </p> * <p/> * (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL * extension, verify that the certificate includes the basic constraints * extension with the cA boolean asserted. * </p> * <p/> * (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted. * </p> * * @param dp The distribution point. * @param cert The certificate. * @param crl The CRL. * @throws AnnotatedException if one of the conditions is not met or an error occurs. */ protected static void processCRLB2( DistributionPoint dp, Object cert, X509CRL crl) throws AnnotatedException { IssuingDistributionPoint idp = null; try { idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl, RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)); } catch (Exception e) { throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e); } // (b) (2) (i) // distribution point name is present if (idp != null) { if (idp.getDistributionPoint() != null) { // make list of names DistributionPointName dpName = IssuingDistributionPoint.getInstance(idp).getDistributionPoint(); List names = new ArrayList(); if (dpName.getType() == DistributionPointName.FULL_NAME) { GeneralName[] genNames = GeneralNames.getInstance(dpName.getName()).getNames(); for (int j = 0; j < genNames.length; j++) { names.add(genNames[j]); } } if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER) { ASN1EncodableVector vec = new ASN1EncodableVector(); try { Enumeration e = ASN1Sequence.getInstance( ASN1Sequence.fromByteArray(CertPathValidatorUtilities.getIssuerPrincipal(crl) .getEncoded())).getObjects(); while (e.hasMoreElements()) { vec.add((DEREncodable)e.nextElement()); } } catch (IOException e) { throw new AnnotatedException("Could not read CRL issuer.", e); } vec.add(dpName.getName()); names.add(new GeneralName(X509Name.getInstance(new DERSequence(vec)))); } boolean matches = false; // verify that one of the names in the IDP matches one // of the names in the DP. if (dp.getDistributionPoint() != null) { dpName = dp.getDistributionPoint(); GeneralName[] genNames = null; if (dpName.getType() == DistributionPointName.FULL_NAME) { genNames = GeneralNames.getInstance(dpName.getName()).getNames(); } if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER) { if (dp.getCRLIssuer() != null) { genNames = dp.getCRLIssuer().getNames(); } else { genNames = new GeneralName[1]; try { genNames[0] = new GeneralName(new X509Name( (ASN1Sequence)ASN1Sequence.fromByteArray(CertPathValidatorUtilities .getEncodedIssuerPrincipal(cert).getEncoded()))); } catch (IOException e) { throw new AnnotatedException("Could not read certificate issuer.", e); } } for (int j = 0; j < genNames.length; j++) { Enumeration e = ASN1Sequence.getInstance(genNames[j].getName().getDERObject()).getObjects(); ASN1EncodableVector vec = new ASN1EncodableVector(); while (e.hasMoreElements()) { vec.add((DEREncodable)e.nextElement()); } vec.add(dpName.getName()); genNames[j] = new GeneralName(new X509Name(new DERSequence(vec))); } } if (genNames != null) { for (int j = 0; j < genNames.length; j++) { if (names.contains(genNames[j])) { matches = true; break; } } } if (!matches) { throw new AnnotatedException( "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point."); } } // verify that one of the names in // the IDP matches one of the names in the cRLIssuer field of // the DP else { if (dp.getCRLIssuer() == null) { throw new AnnotatedException("Either the cRLIssuer or the distributionPoint field must " + "be contained in DistributionPoint."); } GeneralName[] genNames = dp.getCRLIssuer().getNames(); for (int j = 0; j < genNames.length; j++) { if (names.contains(genNames[j])) { matches = true; break; } } if (!matches) { throw new AnnotatedException( "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point."); } } } BasicConstraints bc = null; try { bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue((X509Extension)cert, BASIC_CONSTRAINTS)); } catch (Exception e) { throw new AnnotatedException("Basic constraints extension could not be decoded.", e); } if (cert instanceof X509Certificate) { // (b) (2) (ii) if (idp.onlyContainsUserCerts() && (bc != null && bc.isCA())) { throw new AnnotatedException("CA Cert CRL only contains user certificates."); } // (b) (2) (iii) if (idp.onlyContainsCACerts() && (bc == null || !bc.isCA())) { throw new AnnotatedException("End CRL only contains CA certificates."); } } // (b) (2) (iv) if (idp.onlyContainsAttributeCerts()) { throw new AnnotatedException("onlyContainsAttributeCerts boolean is asserted."); } } } /** * If the DP includes cRLIssuer, then verify that the issuer field in the * complete CRL matches cRLIssuer in the DP and that the complete CRL * contains an issuing distribution point extension with the indirectCRL * boolean asserted. Otherwise, verify that the CRL issuer matches the * certificate issuer. * * @param dp The distribution point. * @param cert The certificate ot attribute certificate. * @param crl The CRL for <code>cert</code>. * @throws AnnotatedException if one of the above conditions does not apply or an error * occurs. */ protected static void processCRLB1( DistributionPoint dp, Object cert, X509CRL crl) throws AnnotatedException { DERObject idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT); boolean isIndirect = false; if (idp != null) { if (IssuingDistributionPoint.getInstance(idp).isIndirectCRL()) { isIndirect = true; } } byte[] issuerBytes = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded(); boolean matchIssuer = false; if (dp.getCRLIssuer() != null) { GeneralName genNames[] = dp.getCRLIssuer().getNames(); for (int j = 0; j < genNames.length; j++) { if (genNames[j].getTagNo() == GeneralName.directoryName) { try { if (Arrays.areEqual(genNames[j].getName().getDERObject().getEncoded(), issuerBytes)) { matchIssuer = true; } } catch (IOException e) { throw new AnnotatedException( "CRL issuer information from distribution point cannot be decoded.", e); } } } if (matchIssuer && !isIndirect) { throw new AnnotatedException("Distribution point contains cRLIssuer field but CRL is not indirect."); } if (!matchIssuer) { throw new AnnotatedException("CRL issuer of CRL does not match CRL issuer of distribution point."); } } else { if (CertPathValidatorUtilities.getIssuerPrincipal(crl).equals( CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert))) { matchIssuer = true; } } if (!matchIssuer) { throw new AnnotatedException("Cannot find matching CRL issuer for certificate."); } } protected static ReasonsMask processCRLD( X509CRL crl, DistributionPoint dp) throws AnnotatedException { IssuingDistributionPoint idp = null; try { idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl, RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)); } catch (Exception e) { throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e); } // (d) (1) if (idp != null && idp.getOnlySomeReasons() != null && dp.getReasons() != null) { return new ReasonsMask(dp.getReasons().intValue()).intersect(new ReasonsMask(idp.getOnlySomeReasons() .intValue())); } // (d) (4) if ((idp == null || idp.getOnlySomeReasons() == null) && dp.getReasons() == null) { return ReasonsMask.allReasons; } // (d) (2) and (d)(3) return (dp.getReasons() == null ? ReasonsMask.allReasons : new ReasonsMask(dp.getReasons().intValue())).intersect(idp == null ? ReasonsMask.allReasons : new ReasonsMask(idp.getOnlySomeReasons().intValue())); } protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId(); protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId(); protected static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId(); protected static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId(); protected static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId(); protected static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId(); protected static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId(); protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId(); protected static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId(); protected static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId(); protected static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId(); protected static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId(); protected static final String KEY_USAGE = X509Extensions.KeyUsage.getId(); protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId(); protected static final String ANY_POLICY = "2.5.29.32.0"; /* * key usage bits */ protected static final int KEY_CERT_SIGN = 5; protected static final int CRL_SIGN = 6; /** * Obtain and validate the certification path for the complete CRL issuer. * If a key usage extension is present in the CRL issuer's certificate, * verify that the cRLSign bit is set. * * @param crl CRL which contains revocation information for the certificate * <code>cert</code>. * @param cert The attribute certificate or certificate to check if it is * revoked. * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>. * @param defaultCRLSignKey The public key of the issuer certificate * <code>defaultCRLSignCert</code>. * @param paramsPKIX paramsPKIX PKIX parameters. * @param certPathCerts The certificates on the certification path. * @return A <code>Set</code> with all keys of possible CRL issuer * certificates. * @throws AnnotatedException if the CRL is not valid or the status cannot be checked or * some error occurs. */ protected static Set processCRLF( X509CRL crl, Object cert, X509Certificate defaultCRLSignCert, PublicKey defaultCRLSignKey, ExtendedPKIXParameters paramsPKIX, List certPathCerts) throws AnnotatedException { // (f) // get issuer from CRL X509CertStoreSelector selector = new X509CertStoreSelector(); try { byte[] issuerPrincipal = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded(); selector.setSubject(issuerPrincipal); } catch (IOException e) { throw new AnnotatedException( "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e); } // get CRL signing certs Collection coll; try { coll = CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getStores()); coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getAdditionalStores())); coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getCertStores())); } catch (AnnotatedException e) { throw new AnnotatedException("Issuer certificate for CRL cannot be searched.", e); } coll.add(defaultCRLSignCert); Iterator cert_it = coll.iterator(); List validCerts = new ArrayList(); List validKeys = new ArrayList(); while (cert_it.hasNext()) { X509Certificate signingCert = (X509Certificate)cert_it.next(); /* * CA of the certificate, for which this CRL is checked, has also * signed CRL, so skip the path validation, because is already done */ if (signingCert.equals(defaultCRLSignCert)) { validCerts.add(signingCert); validKeys.add(defaultCRLSignKey); continue; } try { CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME); selector = new X509CertStoreSelector(); selector.setCertificate(signingCert); ExtendedPKIXParameters temp = (ExtendedPKIXParameters)paramsPKIX.clone(); temp.setTargetCertConstraints(selector); ExtendedPKIXBuilderParameters params = (ExtendedPKIXBuilderParameters)ExtendedPKIXBuilderParameters .getInstance(temp); /* * if signingCert is placed not higher on the cert path a * dependency loop results. CRL for cert is checked, but * signingCert is needed for checking the CRL which is dependent * on checking cert because it is higher in the cert path and so * signing signingCert transitively. so, revocation is disabled, * forgery attacks of the CRL are detected in this outer loop * for all other it must be enabled to prevent forgery attacks */ if (certPathCerts.contains(signingCert)) { params.setRevocationEnabled(false); } else { params.setRevocationEnabled(true); } List certs = builder.build(params).getCertPath().getCertificates(); validCerts.add(signingCert); validKeys.add(CertPathValidatorUtilities.getNextWorkingKey(certs, 0)); } catch (CertPathBuilderException e) { throw new AnnotatedException("Internal error.", e); } catch (CertPathValidatorException e) { throw new AnnotatedException("Public key of issuer certificate of CRL could not be retrieved.", e); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } } Set checkKeys = new HashSet(); AnnotatedException lastException = null; for (int i = 0; i < validCerts.size(); i++) { X509Certificate signCert = (X509Certificate)validCerts.get(i); boolean[] keyusage = signCert.getKeyUsage(); if (keyusage != null && (keyusage.length < 7 || !keyusage[CRL_SIGN])) { lastException = new AnnotatedException( "Issuer certificate key usage extension does not permit CRL signing."); } else { checkKeys.add(validKeys.get(i)); } } if (checkKeys.isEmpty() && lastException == null) { throw new AnnotatedException("Cannot find a valid issuer certificate."); } if (checkKeys.isEmpty() && lastException != null) { throw lastException; } return checkKeys; } protected static PublicKey processCRLG( X509CRL crl, Set keys) throws AnnotatedException { Exception lastException = null; for (Iterator it = keys.iterator(); it.hasNext();) { PublicKey key = (PublicKey)it.next(); try { crl.verify(key); return key; } catch (Exception e) { lastException = e; } } throw new AnnotatedException("Cannot verify CRL.", lastException); } protected static X509CRL processCRLH( Set deltacrls, PublicKey key) throws AnnotatedException { Exception lastException = null; for (Iterator it = deltacrls.iterator(); it.hasNext();) { X509CRL crl = (X509CRL)it.next(); try { crl.verify(key); return crl; } catch (Exception e) { lastException = e; } } if (lastException != null) { throw new AnnotatedException("Cannot verify delta CRL.", lastException); } return null; } protected static Set processCRLA1i( Date currentDate, ExtendedPKIXParameters paramsPKIX, X509Certificate cert, X509CRL crl) throws AnnotatedException { Set set = new HashSet(); if (paramsPKIX.isUseDeltasEnabled()) { CRLDistPoint freshestCRL = null; try { freshestCRL = CRLDistPoint .getInstance(CertPathValidatorUtilities.getExtensionValue(cert, FRESHEST_CRL)); } catch (AnnotatedException e) { throw new AnnotatedException("Freshest CRL extension could not be decoded from certificate.", e); } if (freshestCRL == null) { try { freshestCRL = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl, FRESHEST_CRL)); } catch (AnnotatedException e) { throw new AnnotatedException("Freshest CRL extension could not be decoded from CRL.", e); } } if (freshestCRL != null) { try { CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(freshestCRL, paramsPKIX); } catch (AnnotatedException e) { throw new AnnotatedException( "No new delta CRL locations could be added from Freshest CRL extension.", e); } // get delta CRL(s) try { set.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl)); } catch (AnnotatedException e) { throw new AnnotatedException("Exception obtaining delta CRLs.", e); } } } return set; } protected static Set[] processCRLA1ii( Date currentDate, ExtendedPKIXParameters paramsPKIX, X509Certificate cert, X509CRL crl) throws AnnotatedException { Set deltaSet = new HashSet(); X509CRLStoreSelector crlselect = new X509CRLStoreSelector(); crlselect.setCertificateChecking(cert); try { crlselect.addIssuerName(crl.getIssuerX500Principal().getEncoded()); } catch (IOException e) { throw new AnnotatedException("Cannot extract issuer from CRL." + e, e); } crlselect.setCompleteCRLEnabled(true); Set completeSet = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate); if (paramsPKIX.isUseDeltasEnabled()) { // get delta CRL(s) try { deltaSet.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl)); } catch (AnnotatedException e) { throw new AnnotatedException("Exception obtaining delta CRLs.", e); } } return new Set[] { completeSet, deltaSet}; } /** * If use-deltas is set, verify the issuer and scope of the delta CRL. * * @param deltaCRL The delta CRL. * @param completeCRL The complete CRL. * @param pkixParams The PKIX paramaters. * @throws AnnotatedException if an exception occurs. */ protected static void processCRLC( X509CRL deltaCRL, X509CRL completeCRL, ExtendedPKIXParameters pkixParams) throws AnnotatedException { if (deltaCRL == null) { return; } IssuingDistributionPoint completeidp = null; try { completeidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue( completeCRL, RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)); } catch (Exception e) { throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e); } if (pkixParams.isUseDeltasEnabled()) { // (c) (1) if (!deltaCRL.getIssuerX500Principal().equals(completeCRL.getIssuerX500Principal())) { throw new AnnotatedException("Complete CRL issuer does not match delta CRL issuer."); } // (c) (2) IssuingDistributionPoint deltaidp = null; try { deltaidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue( deltaCRL, ISSUING_DISTRIBUTION_POINT)); } catch (Exception e) { throw new AnnotatedException( "Issuing distribution point extension from delta CRL could not be decoded.", e); } boolean match = false; if (completeidp == null) { if (deltaidp == null) { match = true; } } else { if (completeidp.equals(deltaidp)) { match = true; } } if (!match) { throw new AnnotatedException( "Issuing distribution point extension from delta CRL and complete CRL does not match."); } // (c) (3) DERObject completeKeyIdentifier = null; try { completeKeyIdentifier = CertPathValidatorUtilities.getExtensionValue( completeCRL, AUTHORITY_KEY_IDENTIFIER); } catch (AnnotatedException e) { throw new AnnotatedException( "Authority key identifier extension could not be extracted from complete CRL.", e); } DERObject deltaKeyIdentifier = null; try { deltaKeyIdentifier = CertPathValidatorUtilities.getExtensionValue( deltaCRL, AUTHORITY_KEY_IDENTIFIER); } catch (AnnotatedException e) { throw new AnnotatedException( "Authority key identifier extension could not be extracted from delta CRL.", e); } if (completeKeyIdentifier == null) { throw new AnnotatedException("CRL authority key identifier is null."); } if (deltaKeyIdentifier == null) { throw new AnnotatedException("Delta CRL authority key identifier is null."); } if (!completeKeyIdentifier.equals(deltaKeyIdentifier)) { throw new AnnotatedException( "Delta CRL authority key identifier does not match complete CRL authority key identifier."); } } } protected static void processCRLI( Date validDate, X509CRL deltacrl, Object cert, CertStatus certStatus, ExtendedPKIXParameters pkixParams) throws AnnotatedException { if (pkixParams.isUseDeltasEnabled() && deltacrl != null) { CertPathValidatorUtilities.getCertStatus(validDate, deltacrl, cert, certStatus); } } protected static void processCRLJ( Date validDate, X509CRL completecrl, Object cert, CertStatus certStatus) throws AnnotatedException { if (certStatus.getCertStatus() == CertStatus.UNREVOKED) { CertPathValidatorUtilities.getCertStatus(validDate, completecrl, cert, certStatus); } } protected static PKIXPolicyNode prepareCertB( CertPath certPath, int index, List[] policyNodes, PKIXPolicyNode validPolicyTree, int policyMapping) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); int n = certs.size(); // i as defined in the algorithm description int i = n - index; // (b) // ASN1Sequence pm = null; try { pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.POLICY_MAPPINGS)); } catch (AnnotatedException ex) { throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath, index); } PKIXPolicyNode _validPolicyTree = validPolicyTree; 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 (RFC3280CertPathUtilities.ANY_POLICY.equals(node.getValidPolicy())) { Set pq = null; ASN1Sequence policies = null; try { policies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.CERTIFICATE_POLICIES); } catch (AnnotatedException e) { throw new ExtCertPathValidatorException( "Certificate policies extension could not be decoded.", e, certPath, index); } Enumeration e = policies.getObjects(); while (e.hasMoreElements()) { PolicyInformation pinfo = null; try { pinfo = PolicyInformation.getInstance(e.nextElement()); } catch (Exception ex) { throw new CertPathValidatorException( "Policy information could not be decoded.", ex, certPath, index); } if (RFC3280CertPathUtilities.ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId())) { try { pq = CertPathValidatorUtilities .getQualifierSet(pinfo.getPolicyQualifiers()); } catch (CertPathValidatorException ex) { throw new ExtCertPathValidatorException( "Policy qualifier info set could not be decoded.", ex, certPath, index); } break; } } boolean ci = false; if (cert.getCriticalExtensionOIDs() != null) { ci = cert.getCriticalExtensionOIDs().contains( RFC3280CertPathUtilities.CERTIFICATE_POLICIES); } PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent(); if (RFC3280CertPathUtilities.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; } } } } } } } } } return _validPolicyTree; } protected static void prepareNextCertA( CertPath certPath, int index) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // // (a) check the policy mappings // ASN1Sequence pm = null; try { pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.POLICY_MAPPINGS)); } catch (AnnotatedException ex) { throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath, index); } if (pm != null) { ASN1Sequence mappings = pm; for (int j = 0; j < mappings.size(); j++) { DERObjectIdentifier issuerDomainPolicy = null; DERObjectIdentifier subjectDomainPolicy = null; try { ASN1Sequence mapping = DERSequence.getInstance(mappings.getObjectAt(j)); issuerDomainPolicy = DERObjectIdentifier.getInstance(mapping.getObjectAt(0)); subjectDomainPolicy = DERObjectIdentifier.getInstance(mapping.getObjectAt(1)); } catch (Exception e) { throw new ExtCertPathValidatorException("Policy mappings extension contents could not be decoded.", e, certPath, index); } if (RFC3280CertPathUtilities.ANY_POLICY.equals(issuerDomainPolicy.getId())) { throw new CertPathValidatorException("IssuerDomainPolicy is anyPolicy", null, certPath, index); } if (RFC3280CertPathUtilities.ANY_POLICY.equals(subjectDomainPolicy.getId())) { throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy,", null, certPath, index); } } } } protected static void processCertF( CertPath certPath, int index, PKIXPolicyNode validPolicyTree, int explicitPolicy) throws CertPathValidatorException { // // (f) // if (explicitPolicy <= 0 && validPolicyTree == null) { throw new ExtCertPathValidatorException("No valid policy tree found when one expected.", null, certPath, index); } } protected static PKIXPolicyNode processCertE( CertPath certPath, int index, PKIXPolicyNode validPolicyTree) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (e) // ASN1Sequence certPolicies = null; try { certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.CERTIFICATE_POLICIES)); } catch (AnnotatedException e) { throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.", e, certPath, index); } if (certPolicies == null) { validPolicyTree = null; } return validPolicyTree; } protected static void processCertBC( CertPath certPath, int index, PKIXNameConstraintValidator nameConstraintValidator) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); int n = certs.size(); // i as defined in the algorithm description int i = n - 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 = DERSequence.getInstance(aIn.readObject()); } catch (Exception e) { throw new CertPathValidatorException("Exception extracting subject name when checking subtrees.", e, certPath, index); } try { nameConstraintValidator.checkPermittedDN(dns); nameConstraintValidator.checkExcludedDN(dns); } catch (PKIXNameConstraintValidatorException e) { throw new CertPathValidatorException("Subtree check for certificate subject failed.", e, certPath, index); } GeneralNames altName = null; try { altName = GeneralNames.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)); } catch (Exception e) { throw new CertPathValidatorException("Subject alternative name extension could not be decoded.", e, certPath, index); } Vector emails = new X509Name(dns).getValues(X509Name.EmailAddress); for (Enumeration e = emails.elements(); e.hasMoreElements();) { String email = (String)e.nextElement(); GeneralName emailAsGeneralName = new GeneralName(GeneralName.rfc822Name, email); try { nameConstraintValidator.checkPermitted(emailAsGeneralName); nameConstraintValidator.checkExcluded(emailAsGeneralName); } catch (PKIXNameConstraintValidatorException ex) { throw new CertPathValidatorException( "Subtree check for certificate subject alternative email failed.", ex, certPath, index); } } if (altName != null) { GeneralName[] genNames = null; try { genNames = altName.getNames(); } catch (Exception e) { throw new CertPathValidatorException("Subject alternative name contents could not be decoded.", e, certPath, index); } for (int j = 0; j < genNames.length; j++) { try { nameConstraintValidator.checkPermitted(genNames[j]); nameConstraintValidator.checkExcluded(genNames[j]); } catch (PKIXNameConstraintValidatorException e) { throw new CertPathValidatorException( "Subtree check for certificate subject alternative name failed.", e, certPath, index); } } } } } protected static PKIXPolicyNode processCertD( CertPath certPath, int index, Set acceptablePolicies, PKIXPolicyNode validPolicyTree, List[] policyNodes, int inhibitAnyPolicy) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); int n = certs.size(); // i as defined in the algorithm description int i = n - index; // // (d) policy Information checking against initial policy and // policy mapping // ASN1Sequence certPolicies = null; try { certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.CERTIFICATE_POLICIES)); } catch (AnnotatedException e) { throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.", e, certPath, index); } 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 (!RFC3280CertPathUtilities.ANY_POLICY.equals(pOid.getId())) { Set pq = null; try { pq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers()); } catch (CertPathValidatorException ex) { throw new ExtCertPathValidatorException("Policy qualifier info set could not be build.", ex, certPath, index); } boolean match = CertPathValidatorUtilities.processCertD1i(i, policyNodes, pOid, pq); if (!match) { CertPathValidatorUtilities.processCertD1ii(i, policyNodes, pOid, pq); } } } if (acceptablePolicies.isEmpty() || acceptablePolicies.contains(RFC3280CertPathUtilities.ANY_POLICY)) { acceptablePolicies.clear(); acceptablePolicies.addAll(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.clear(); acceptablePolicies.addAll(t1); } // // (d) (2) // if ((inhibitAnyPolicy > 0) || ((i < n) && CertPathValidatorUtilities.isSelfIssued(cert))) { e = certPolicies.getObjects(); while (e.hasMoreElements()) { PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement()); if (RFC3280CertPathUtilities.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; } } } PKIXPolicyNode _validPolicyTree = validPolicyTree; // // (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(RFC3280CertPathUtilities.CERTIFICATE_POLICIES); List nodes = policyNodes[i]; for (int j = 0; j < nodes.size(); j++) { PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j); node.setCritical(critical); } } return _validPolicyTree; } return null; } protected static void processCertA( CertPath certPath, ExtendedPKIXParameters paramsPKIX, int index, PublicKey workingPublicKey, boolean verificationAlreadyPerformed, X500Principal workingIssuerName, X509Certificate sign) throws ExtCertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (a) verify // if (!verificationAlreadyPerformed) { try { // (a) (1) // CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey, paramsPKIX.getSigProvider()); } catch (GeneralSecurityException e) { throw new ExtCertPathValidatorException("Could not validate certificate signature.", e, certPath, index); } } try { // (a) (2) // cert.checkValidity(CertPathValidatorUtilities .getValidCertDateFromValidityModel(paramsPKIX, certPath, index)); } catch (CertificateExpiredException e) { throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index); } catch (CertificateNotYetValidException e) { throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index); } catch (AnnotatedException e) { throw new ExtCertPathValidatorException("Could not validate time of certificate.", e, certPath, index); } // // (a) (3) // if (paramsPKIX.isRevocationEnabled()) { try { checkCRLs(paramsPKIX, cert, CertPathValidatorUtilities.getValidCertDateFromValidityModel(paramsPKIX, certPath, index), sign, workingPublicKey, certs); } catch (AnnotatedException e) { Throwable cause = e; if (null != e.getCause()) { cause = e.getCause(); } throw new ExtCertPathValidatorException(e.getMessage(), cause, certPath, index); } } // // (a) (4) name chaining // if (!CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).equals(workingIssuerName)) { throw new ExtCertPathValidatorException("IssuerName(" + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert) + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null, certPath, index); } } protected static int prepareNextCertI1( CertPath certPath, int index, int explicitPolicy) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (i) // ASN1Sequence pc = null; try { pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.POLICY_CONSTRAINTS)); } catch (Exception e) { throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath, index); } int tmpInt; if (pc != null) { Enumeration policyConstraints = pc.getObjects(); while (policyConstraints.hasMoreElements()) { try { ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement()); if (constraint.getTagNo() == 0) { tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue(); if (tmpInt < explicitPolicy) { return tmpInt; } break; } } catch (IllegalArgumentException e) { throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.", e, certPath, index); } } } return explicitPolicy; } protected static int prepareNextCertI2( CertPath certPath, int index, int policyMapping) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (i) // ASN1Sequence pc = null; try { pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.POLICY_CONSTRAINTS)); } catch (Exception e) { throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath, index); } int tmpInt; if (pc != null) { Enumeration policyConstraints = pc.getObjects(); while (policyConstraints.hasMoreElements()) { try { ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement()); if (constraint.getTagNo() == 1) { tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue(); if (tmpInt < policyMapping) { return tmpInt; } break; } } catch (IllegalArgumentException e) { throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.", e, certPath, index); } } } return policyMapping; } protected static void prepareNextCertG( CertPath certPath, int index, PKIXNameConstraintValidator nameConstraintValidator) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (g) handle the name constraints extension // NameConstraints nc = null; try { ASN1Sequence ncSeq = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.NAME_CONSTRAINTS)); if (ncSeq != null) { nc = new NameConstraints(ncSeq); } } catch (Exception e) { throw new ExtCertPathValidatorException("Name constraints extension could not be decoded.", e, certPath, index); } if (nc != null) { // // (g) (1) permitted subtrees // ASN1Sequence permitted = nc.getPermittedSubtrees(); if (permitted != null) { try { nameConstraintValidator.intersectPermittedSubtree(permitted); } catch (Exception ex) { throw new ExtCertPathValidatorException( "Permitted subtrees cannot be build from name constraints extension.", ex, certPath, index); } } // // (g) (2) excluded subtrees // ASN1Sequence excluded = nc.getExcludedSubtrees(); if (excluded != null) { Enumeration e = excluded.getObjects(); try { while (e.hasMoreElements()) { GeneralSubtree subtree = GeneralSubtree.getInstance(e.nextElement()); nameConstraintValidator.addExcludedSubtree(subtree); } } catch (Exception ex) { throw new ExtCertPathValidatorException( "Excluded subtrees cannot be build from name constraints extension.", ex, certPath, index); } } } } /** * Checks a distribution point for revocation information for the * certificate <code>cert</code>. * * @param dp The distribution point to consider. * @param paramsPKIX PKIX parameters. * @param cert Certificate to check if it is revoked. * @param validDate The date when the certificate revocation status should be * checked. * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>. * @param defaultCRLSignKey The public key of the issuer certificate * <code>defaultCRLSignCert</code>. * @param certStatus The current certificate revocation status. * @param reasonMask The reasons mask which is already checked. * @param certPathCerts The certificates of the certification path. * @throws AnnotatedException if the certificate is revoked or the status cannot be checked * or some error occurs. */ private static void checkCRL( DistributionPoint dp, ExtendedPKIXParameters paramsPKIX, X509Certificate cert, Date validDate, X509Certificate defaultCRLSignCert, PublicKey defaultCRLSignKey, CertStatus certStatus, ReasonsMask reasonMask, List certPathCerts) throws AnnotatedException { Date currentDate = new Date(System.currentTimeMillis()); if (validDate.getTime() > currentDate.getTime()) { throw new AnnotatedException("Validation time is in future."); } // (a) /* * We always get timely valid CRLs, so there is no step (a) (1). * "locally cached" CRLs are assumed to be in getStore(), additional * CRLs must be enabled in the ExtendedPKIXParameters and are in * getAdditionalStore() */ Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, cert, currentDate, paramsPKIX); boolean validCrlFound = false; AnnotatedException lastException = null; Iterator crl_iter = crls.iterator(); while (crl_iter.hasNext() && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonMask.isAllReasons()) { try { X509CRL crl = (X509CRL)crl_iter.next(); // (d) ReasonsMask interimReasonsMask = RFC3280CertPathUtilities.processCRLD(crl, dp); // (e) /* * The reasons mask is updated at the end, so only valid CRLs * can update it. If this CRL does not contain new reasons it * must be ignored. */ if (!interimReasonsMask.hasNewReasons(reasonMask)) { continue; } // (f) Set keys = RFC3280CertPathUtilities.processCRLF(crl, cert, defaultCRLSignCert, defaultCRLSignKey, paramsPKIX, certPathCerts); // (g) PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys); X509CRL deltaCRL = null; if (paramsPKIX.isUseDeltasEnabled()) { // get delta CRLs Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl); // we only want one valid delta CRL // (h) deltaCRL = RFC3280CertPathUtilities.processCRLH(deltaCRLs, key); } /* * CRL must be be valid at the current time, not the validation * time. If a certificate is revoked with reason keyCompromise, * cACompromise, it can be used for forgery, also for the past. * This reason may not be contained in older CRLs. */ /* * in the chain model signatures stay valid also after the * certificate has been expired, so they do not have to be in * the CRL validity time */ if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL) { /* * if a certificate has expired, but was revoked, it is not * more in the CRL, so it would be regarded as valid if the * first check is not done */ if (cert.getNotAfter().getTime() < crl.getThisUpdate().getTime()) { throw new AnnotatedException("No valid CRL for current time found."); } } RFC3280CertPathUtilities.processCRLB1(dp, cert, crl); // (b) (2) RFC3280CertPathUtilities.processCRLB2(dp, cert, crl); // (c) RFC3280CertPathUtilities.processCRLC(deltaCRL, crl, paramsPKIX); // (i) RFC3280CertPathUtilities.processCRLI(validDate, deltaCRL, cert, certStatus, paramsPKIX); // (j) RFC3280CertPathUtilities.processCRLJ(validDate, crl, cert, certStatus); // (k) if (certStatus.getCertStatus() == CRLReason.removeFromCRL) { certStatus.setCertStatus(CertStatus.UNREVOKED); } // update reasons mask reasonMask.addReasons(interimReasonsMask); Set criticalExtensions = crl.getCriticalExtensionOIDs(); if (criticalExtensions != null) { criticalExtensions = new HashSet(criticalExtensions); criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId()); criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId()); if (!criticalExtensions.isEmpty()) { throw new AnnotatedException("CRL contains unsupported critical extensions."); } } if (deltaCRL != null) { criticalExtensions = deltaCRL.getCriticalExtensionOIDs(); if (criticalExtensions != null) { criticalExtensions = new HashSet(criticalExtensions); criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId()); criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId()); if (!criticalExtensions.isEmpty()) { throw new AnnotatedException("Delta CRL contains unsupported critical extension."); } } } validCrlFound = true; } catch (AnnotatedException e) { lastException = e; } } if (!validCrlFound) { throw lastException; } } /** * Checks a certificate if it is revoked. * * @param paramsPKIX PKIX parameters. * @param cert Certificate to check if it is revoked. * @param validDate The date when the certificate revocation status should be * checked. * @param sign The issuer certificate of the certificate <code>cert</code>. * @param workingPublicKey The public key of the issuer certificate <code>sign</code>. * @param certPathCerts The certificates of the certification path. * @throws AnnotatedException if the certificate is revoked or the status cannot be checked * or some error occurs. */ protected static void checkCRLs( ExtendedPKIXParameters paramsPKIX, X509Certificate cert, Date validDate, X509Certificate sign, PublicKey workingPublicKey, List certPathCerts) throws AnnotatedException { AnnotatedException lastException = null; CRLDistPoint crldp = null; try { crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)); } catch (Exception e) { throw new AnnotatedException("CRL distribution point extension could not be read.", e); } try { CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX); } catch (AnnotatedException e) { throw new AnnotatedException( "No additional CRL locations could be decoded from CRL distribution point extension.", e); } CertStatus certStatus = new CertStatus(); ReasonsMask reasonsMask = new ReasonsMask(); boolean validCrlFound = false; // for each distribution point if (crldp != null) { DistributionPoint dps[] = null; try { dps = crldp.getDistributionPoints(); } catch (Exception e) { throw new AnnotatedException("Distribution points could not be read.", e); } if (dps != null) { for (int i = 0; i < dps.length && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons(); i++) { ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone(); try { checkCRL(dps[i], paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts); validCrlFound = true; } catch (AnnotatedException e) { lastException = e; } } } } /* * If the revocation status has not been determined, repeat the process * above with any available CRLs not specified in a distribution point * but issued by the certificate issuer. */ if (certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons()) { try { /* * assume a DP with both the reasons and the cRLIssuer fields * omitted and a distribution point name of the certificate * issuer. */ DERObject issuer = null; try { issuer = new ASN1InputStream(CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).getEncoded()) .readObject(); } catch (Exception e) { throw new AnnotatedException("Issuer from certificate for CRL could not be reencoded.", e); } DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames( new GeneralName(GeneralName.directoryName, issuer))), null, null); ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone(); checkCRL(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts); validCrlFound = true; } catch (AnnotatedException e) { lastException = e; } } if (!validCrlFound) { if (lastException instanceof AnnotatedException) { throw lastException; } throw new AnnotatedException("No valid CRL found.", lastException); } if (certStatus.getCertStatus() != CertStatus.UNREVOKED) { String message = "Certificate revocation after " + certStatus.getRevocationDate(); message += ", reason: " + crlReasons[certStatus.getCertStatus()]; throw new AnnotatedException(message); } if (!reasonsMask.isAllReasons() && certStatus.getCertStatus() == CertStatus.UNREVOKED) { certStatus.setCertStatus(CertStatus.UNDETERMINED); } if (certStatus.getCertStatus() == CertStatus.UNDETERMINED) { throw new AnnotatedException("Certificate status could not be determined."); } } protected static int prepareNextCertJ( CertPath certPath, int index, int inhibitAnyPolicy) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (j) // DERInteger iap = null; try { iap = DERInteger.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)); } catch (Exception e) { throw new ExtCertPathValidatorException("Inhibit any-policy extension cannot be decoded.", e, certPath, index); } if (iap != null) { int _inhibitAnyPolicy = iap.getValue().intValue(); if (_inhibitAnyPolicy < inhibitAnyPolicy) { return _inhibitAnyPolicy; } } return inhibitAnyPolicy; } protected static void prepareNextCertK( CertPath certPath, int index) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (k) // BasicConstraints bc = null; try { bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.BASIC_CONSTRAINTS)); } catch (Exception e) { throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath, index); } if (bc != null) { if (!(bc.isCA())) { throw new CertPathValidatorException("Not a CA certificate"); } } else { throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints"); } } protected static int prepareNextCertL( CertPath certPath, int index, int maxPathLength) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (l) // if (!CertPathValidatorUtilities.isSelfIssued(cert)) { if (maxPathLength <= 0) { throw new ExtCertPathValidatorException("Max path length not greater than zero", null, certPath, index); } return maxPathLength - 1; } return maxPathLength; } protected static int prepareNextCertM( CertPath certPath, int index, int maxPathLength) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (m) // BasicConstraints bc = null; try { bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.BASIC_CONSTRAINTS)); } catch (Exception e) { throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath, index); } if (bc != null) { BigInteger _pathLengthConstraint = bc.getPathLenConstraint(); if (_pathLengthConstraint != null) { int _plc = _pathLengthConstraint.intValue(); if (_plc < maxPathLength) { return _plc; } } } return maxPathLength; } protected static void prepareNextCertN( CertPath certPath, int index) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (n) // boolean[] _usage = cert.getKeyUsage(); if ((_usage != null) && !_usage[RFC3280CertPathUtilities.KEY_CERT_SIGN]) { throw new ExtCertPathValidatorException( "Issuer certificate keyusage extension is critical and does not permit key signing.", null, certPath, index); } } protected static void prepareNextCertO( CertPath certPath, int index, Set criticalExtensions, List pathCheckers) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (o) // Iterator tmpIter; 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 ExtCertPathValidatorException("Certificate has unsupported critical extension.", null, certPath, index); } } protected static int prepareNextCertH1( CertPath certPath, int index, int explicitPolicy) { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (h) // if (!CertPathValidatorUtilities.isSelfIssued(cert)) { // // (1) // if (explicitPolicy != 0) { return explicitPolicy - 1; } } return explicitPolicy; } protected static int prepareNextCertH2( CertPath certPath, int index, int policyMapping) { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (h) // if (!CertPathValidatorUtilities.isSelfIssued(cert)) { // // (2) // if (policyMapping != 0) { return policyMapping - 1; } } return policyMapping; } protected static int prepareNextCertH3( CertPath certPath, int index, int inhibitAnyPolicy) { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (h) // if (!CertPathValidatorUtilities.isSelfIssued(cert)) { // // (3) // if (inhibitAnyPolicy != 0) { return inhibitAnyPolicy - 1; } } return inhibitAnyPolicy; } protected static final String[] crlReasons = new String[] { "unspecified", "keyCompromise", "cACompromise", "affiliationChanged", "superseded", "cessationOfOperation", "certificateHold", "unknown", "removeFromCRL", "privilegeWithdrawn", "aACompromise"}; protected static int wrapupCertA( int explicitPolicy, X509Certificate cert) { // // (a) // if (!CertPathValidatorUtilities.isSelfIssued(cert) && (explicitPolicy != 0)) { explicitPolicy--; } return explicitPolicy; } protected static int wrapupCertB( CertPath certPath, int index, int explicitPolicy) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); // // (b) // int tmpInt; ASN1Sequence pc = null; try { pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.POLICY_CONSTRAINTS)); } catch (AnnotatedException e) { throw new ExtCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index); } if (pc != null) { Enumeration policyConstraints = pc.getObjects(); while (policyConstraints.hasMoreElements()) { ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement(); switch (constraint.getTagNo()) { case 0: try { tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue(); } catch (Exception e) { throw new ExtCertPathValidatorException( "Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath, index); } if (tmpInt == 0) { return 0; } break; } } } return explicitPolicy; } protected static void wrapupCertF( CertPath certPath, int index, List pathCheckers, Set criticalExtensions) throws CertPathValidatorException { List certs = certPath.getCertificates(); X509Certificate cert = (X509Certificate)certs.get(index); Iterator tmpIter; tmpIter = pathCheckers.iterator(); while (tmpIter.hasNext()) { try { ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions); } catch (CertPathValidatorException e) { throw new ExtCertPathValidatorException("Additional certificate path checker failed.", e, certPath, index); } } if (!criticalExtensions.isEmpty()) { throw new ExtCertPathValidatorException("Certificate has unsupported critical extension", null, certPath, index); } } protected static PKIXPolicyNode wrapupCertG( CertPath certPath, ExtendedPKIXParameters paramsPKIX, Set userInitialPolicySet, int index, List[] policyNodes, PKIXPolicyNode validPolicyTree, Set acceptablePolicies) throws CertPathValidatorException { int n = certPath.getCertificates().size(); // // (g) // PKIXPolicyNode intersection; // // (g) (i) // if (validPolicyTree == null) { if (paramsPKIX.isExplicitPolicyRequired()) { throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null, certPath, index); } intersection = null; } else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g) // (ii) { if (paramsPKIX.isExplicitPolicyRequired()) { if (acceptablePolicies.isEmpty()) { throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null, certPath, index); } 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 (RFC3280CertPathUtilities.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 (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy())) { Iterator _iter = _node.getChildren(); while (_iter.hasNext()) { PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next(); if (!RFC3280CertPathUtilities.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; } return intersection; } }