blob: 728528aca267d74cd96fa090c0671135a587aca1 [file] [log] [blame]
package org.bouncycastle.pkix.jcajce;
import java.io.IOException;
import java.security.PublicKey;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderException;
import java.security.cert.CertPathValidatorException;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLSelector;
import java.security.cert.X509CertSelector;
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.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x500.X500Name;
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.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
import org.bouncycastle.jcajce.PKIXCRLStoreSelector;
import org.bouncycastle.jcajce.PKIXCertStoreSelector;
import org.bouncycastle.jcajce.PKIXExtendedBuilderParameters;
import org.bouncycastle.jcajce.PKIXExtendedParameters;
import org.bouncycastle.util.Arrays;
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(RevocationUtilities.getExtensionValue(crl,
Extension.issuingDistributionPoint));
}
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(crl.getIssuerX500Principal().getEncoded()).getObjects();
while (e.hasMoreElements())
{
vec.add((ASN1Encodable)e.nextElement());
}
}
catch (Exception e)
{
throw new AnnotatedException("Could not read CRL issuer.", e);
}
vec.add(dpName.getName());
names.add(new GeneralName(X500Name.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(X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded()));
}
catch (Exception 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().toASN1Primitive()).getObjects();
ASN1EncodableVector vec = new ASN1EncodableVector();
while (e.hasMoreElements())
{
vec.add((ASN1Encodable)e.nextElement());
}
vec.add(dpName.getName());
genNames[j] = new GeneralName(X500Name.getInstance(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(RevocationUtilities.getExtensionValue((X509Extension)cert,
Extension.basicConstraints));
}
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
{
ASN1Primitive idp = RevocationUtilities.getExtensionValue(crl, Extension.issuingDistributionPoint);
boolean isIndirect = false;
if (idp != null)
{
if (IssuingDistributionPoint.getInstance(idp).isIndirectCRL())
{
isIndirect = true;
}
}
byte[] issuerBytes;
issuerBytes = crl.getIssuerX500Principal().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().toASN1Primitive().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 (crl.getIssuerX500Principal().equals(((X509Certificate)cert).getIssuerX500Principal()))
{
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(RevocationUtilities.getExtensionValue(crl,
Extension.issuingDistributionPoint));
}
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()).intersect(new ReasonsMask(idp.getOnlySomeReasons()));
}
// (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())).intersect(idp == null
? ReasonsMask.allReasons
: new ReasonsMask(idp.getOnlySomeReasons()));
}
public static final String ISSUING_DISTRIBUTION_POINT = Extension.issuingDistributionPoint.getId();
public static final String FRESHEST_CRL = Extension.freshestCRL.getId();
public static final String DELTA_CRL_INDICATOR = Extension.deltaCRLIndicator.getId();
public static final String BASIC_CONSTRAINTS = Extension.basicConstraints.getId();
public static final String AUTHORITY_KEY_IDENTIFIER = Extension.authorityKeyIdentifier.getId();
/*
* 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,
PKIXExtendedParameters paramsPKIX,
List certPathCerts,
PKIXJcaJceHelper helper)
throws AnnotatedException
{
// (f)
// get issuer from CRL
X509CertSelector certSelector = new X509CertSelector();
try
{
byte[] issuerPrincipal = crl.getIssuerX500Principal().getEncoded();
certSelector.setSubject(issuerPrincipal);
}
catch (IOException e)
{
throw new AnnotatedException(
"subject criteria for certificate selector to find issuer certificate for CRL could not be set", e);
}
PKIXCertStoreSelector selector = new PKIXCertStoreSelector.Builder(certSelector).build();
// get CRL signing certs
Collection coll;
try
{
coll = RevocationUtilities.findCertificates(selector, paramsPKIX.getCertificateStores());
coll.addAll(RevocationUtilities.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 = helper.createCertPathBuilder("PKIX");
X509CertSelector tmpCertSelector = new X509CertSelector();
tmpCertSelector.setCertificate(signingCert);
PKIXExtendedParameters.Builder paramsBuilder = new PKIXExtendedParameters.Builder(paramsPKIX)
.setTargetConstraints(new PKIXCertStoreSelector.Builder(tmpCertSelector).build());
/*
* 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))
{
paramsBuilder.setRevocationEnabled(false);
}
else
{
paramsBuilder.setRevocationEnabled(true);
}
PKIXExtendedBuilderParameters extParams = new PKIXExtendedBuilderParameters.Builder(paramsBuilder.build()).build();
List certs = builder.build(extParams).getCertPath().getCertificates();
validCerts.add(signingCert);
validKeys.add(RevocationUtilities.getNextWorkingKey(certs, 0, helper));
}
catch (CertPathBuilderException e)
{
throw new AnnotatedException("CertPath for CRL signer failed to validate.", e);
}
catch (CertPathValidatorException e)
{
throw new AnnotatedException("Public key of issuer certificate of CRL could not be retrieved.", e);
}
catch (Exception e)
{
throw new AnnotatedException(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,
PKIXExtendedParameters paramsPKIX,
X509Certificate cert,
X509CRL crl)
throws AnnotatedException
{
Set set = new HashSet();
if (paramsPKIX.isUseDeltasEnabled())
{
CRLDistPoint freshestCRL = null;
try
{
freshestCRL = CRLDistPoint
.getInstance(RevocationUtilities.getExtensionValue(cert, Extension.freshestCRL));
}
catch (AnnotatedException e)
{
throw new AnnotatedException("Freshest CRL extension could not be decoded from certificate.", e);
}
if (freshestCRL == null)
{
try
{
freshestCRL = CRLDistPoint.getInstance(RevocationUtilities.getExtensionValue(crl,
Extension.freshestCRL));
}
catch (AnnotatedException e)
{
throw new AnnotatedException("Freshest CRL extension could not be decoded from CRL.", e);
}
}
if (freshestCRL != null)
{
List crlStores = new ArrayList();
crlStores.addAll(paramsPKIX.getCRLStores());
try
{
crlStores.addAll(RevocationUtilities.getAdditionalStoresFromCRLDistributionPoint(freshestCRL, paramsPKIX.getNamedCRLStoreMap()));
}
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(RevocationUtilities.getDeltaCRLs(currentDate, crl, paramsPKIX.getCertStores(), crlStores));
}
catch (AnnotatedException e)
{
throw new AnnotatedException("Exception obtaining delta CRLs.", e);
}
}
}
return set;
}
protected static Set[] processCRLA1ii(
Date currentDate,
PKIXExtendedParameters paramsPKIX,
X509Certificate cert,
X509CRL crl)
throws AnnotatedException
{
Set deltaSet = new HashSet();
X509CRLSelector crlselect = new X509CRLSelector();
crlselect.setCertificateChecking(cert);
try
{
crlselect.addIssuerName(crl.getIssuerX500Principal().getEncoded());
}
catch (IOException e)
{
throw new AnnotatedException("Cannot extract issuer from CRL." + e, e);
}
PKIXCRLStoreSelector extSelect = new PKIXCRLStoreSelector.Builder(crlselect).setCompleteCRLEnabled(true).build();
Date validityDate = currentDate;
if (paramsPKIX.getDate() != null)
{
validityDate = paramsPKIX.getDate();
}
Set completeSet = CRL_UTIL.findCRLs(extSelect, validityDate, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores());
if (paramsPKIX.isUseDeltasEnabled())
{
// get delta CRL(s)
try
{
deltaSet.addAll(RevocationUtilities.getDeltaCRLs(validityDate, crl, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores()));
}
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,
PKIXExtendedParameters pkixParams)
throws AnnotatedException
{
if (deltaCRL == null)
{
return;
}
IssuingDistributionPoint completeidp = null;
try
{
completeidp = IssuingDistributionPoint.getInstance(RevocationUtilities.getExtensionValue(
completeCRL, Extension.issuingDistributionPoint));
}
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(RevocationUtilities.getExtensionValue(
deltaCRL, Extension.issuingDistributionPoint));
}
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)
ASN1Primitive completeKeyIdentifier = null;
try
{
completeKeyIdentifier = RevocationUtilities.getExtensionValue(
completeCRL, Extension.authorityKeyIdentifier);
}
catch (AnnotatedException e)
{
throw new AnnotatedException(
"Authority key identifier extension could not be extracted from complete CRL.", e);
}
ASN1Primitive deltaKeyIdentifier = null;
try
{
deltaKeyIdentifier = RevocationUtilities.getExtensionValue(
deltaCRL, Extension.authorityKeyIdentifier);
}
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,
PKIXExtendedParameters pkixParams)
throws AnnotatedException
{
if (pkixParams.isUseDeltasEnabled() && deltacrl != null)
{
RevocationUtilities.getCertStatus(validDate, deltacrl, cert, certStatus);
}
}
protected static void processCRLJ(
Date validDate,
X509CRL completecrl,
Object cert,
CertStatus certStatus)
throws AnnotatedException
{
if (certStatus.getCertStatus() == CertStatus.UNREVOKED)
{
RevocationUtilities.getCertStatus(validDate, completecrl, cert, certStatus);
}
}
/**
* 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.
*/
static void checkCRL(
DistributionPoint dp,
PKIXExtendedParameters paramsPKIX,
X509Certificate cert,
Date validDate,
X509Certificate defaultCRLSignCert,
PublicKey defaultCRLSignKey,
CertStatus certStatus,
ReasonsMask reasonMask,
List certPathCerts,
PKIXJcaJceHelper helper)
throws AnnotatedException, CRLNotFoundException
{
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()
*/
Date validityDate = currentDate;
if (paramsPKIX.getDate() != null)
{
validityDate = paramsPKIX.getDate();
}
Set crls = RevocationUtilities.getCompleteCRLs(dp, cert, validityDate, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores());
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, helper);
// (g)
PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys);
X509CRL deltaCRL = null;
if (paramsPKIX.isUseDeltasEnabled())
{
// get delta CRLs
Set deltaCRLs = RevocationUtilities.getDeltaCRLs(validityDate, crl, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores());
// 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() != PKIXExtendedParameters.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(Extension.issuingDistributionPoint.getId());
criticalExtensions.remove(Extension.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(Extension.issuingDistributionPoint.getId());
criticalExtensions.remove(Extension.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;
}
}
}