| package org.bouncycastle.jcajce; |
| |
| import java.math.BigInteger; |
| import java.security.cert.CRL; |
| import java.security.cert.CRLSelector; |
| import java.security.cert.CertStore; |
| import java.security.cert.CertStoreException; |
| import java.security.cert.X509CRL; |
| import java.security.cert.X509CRLSelector; |
| import java.security.cert.X509Certificate; |
| import java.util.Collection; |
| |
| import org.bouncycastle.asn1.ASN1Integer; |
| import org.bouncycastle.asn1.ASN1OctetString; |
| import org.bouncycastle.asn1.x509.Extension; |
| import org.bouncycastle.util.Arrays; |
| import org.bouncycastle.util.Selector; |
| |
| /** |
| * This class is a Selector implementation for X.509 certificate revocation |
| * lists. |
| * |
| * @see org.bouncycastle.util.Selector |
| */ |
| public class PKIXCRLStoreSelector<T extends CRL> |
| implements Selector<T> |
| { |
| /** |
| * Builder for a PKIXCRLStoreSelector. |
| */ |
| public static class Builder |
| { |
| private final CRLSelector baseSelector; |
| |
| private boolean deltaCRLIndicator = false; |
| private boolean completeCRLEnabled = false; |
| private BigInteger maxBaseCRLNumber = null; |
| private byte[] issuingDistributionPoint = null; |
| private boolean issuingDistributionPointEnabled = false; |
| |
| /** |
| * Constructor initializing a builder with a CertSelector. |
| * |
| * @param crlSelector the CertSelector to copy the match details from. |
| */ |
| public Builder(CRLSelector crlSelector) |
| { |
| this.baseSelector = (CRLSelector)crlSelector.clone(); |
| } |
| |
| |
| /** |
| * If set to <code>true</code> only complete CRLs are returned. |
| * <p> |
| * {@link #setCompleteCRLEnabled(boolean)} and |
| * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other. |
| * |
| * @param completeCRLEnabled <code>true</code> if only complete CRLs |
| * should be returned. |
| */ |
| public Builder setCompleteCRLEnabled(boolean completeCRLEnabled) |
| { |
| this.completeCRLEnabled = completeCRLEnabled; |
| |
| return this; |
| } |
| |
| /** |
| * If this is set to <code>true</code> the CRL reported contains the delta |
| * CRL indicator CRL extension. |
| * <p> |
| * {@link #setCompleteCRLEnabled(boolean)} and |
| * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other. |
| * |
| * @param deltaCRLIndicator <code>true</code> if the delta CRL indicator |
| * extension must be in the CRL. |
| */ |
| public Builder setDeltaCRLIndicatorEnabled(boolean deltaCRLIndicator) |
| { |
| this.deltaCRLIndicator = deltaCRLIndicator; |
| |
| return this; |
| } |
| |
| /** |
| * Sets the maximum base CRL number. Setting to <code>null</code> disables |
| * this cheack. |
| * <p> |
| * This is only meaningful for delta CRLs. Complete CRLs must have a CRL |
| * number which is greater or equal than the base number of the |
| * corresponding CRL. |
| * |
| * @param maxBaseCRLNumber The maximum base CRL number to set. |
| */ |
| public void setMaxBaseCRLNumber(BigInteger maxBaseCRLNumber) |
| { |
| this.maxBaseCRLNumber = maxBaseCRLNumber; |
| } |
| |
| /** |
| * Enables or disables the issuing distribution point check. |
| * |
| * @param issuingDistributionPointEnabled <code>true</code> to enable the |
| * issuing distribution point check. |
| */ |
| public void setIssuingDistributionPointEnabled( |
| boolean issuingDistributionPointEnabled) |
| { |
| this.issuingDistributionPointEnabled = issuingDistributionPointEnabled; |
| } |
| |
| /** |
| * Sets the issuing distribution point. |
| * <p> |
| * The issuing distribution point extension is a CRL extension which |
| * identifies the scope and the distribution point of a CRL. The scope |
| * contains among others information about revocation reasons contained in |
| * the CRL. Delta CRLs and complete CRLs must have matching issuing |
| * distribution points. |
| * <p> |
| * The byte array is cloned to protect against subsequent modifications. |
| * <p> |
| * You must also enable or disable this criteria with |
| * {@link #setIssuingDistributionPointEnabled(boolean)}. |
| * |
| * @param issuingDistributionPoint The issuing distribution point to set. |
| * This is the DER encoded OCTET STRING extension value. |
| * @see #getIssuingDistributionPoint() |
| */ |
| public void setIssuingDistributionPoint(byte[] issuingDistributionPoint) |
| { |
| this.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint); |
| } |
| |
| /** |
| * Build a selector. |
| * |
| * @return a new PKIXCRLStoreSelector |
| */ |
| public PKIXCRLStoreSelector<? extends CRL> build() |
| { |
| return new PKIXCRLStoreSelector(this); |
| } |
| } |
| |
| private final CRLSelector baseSelector; |
| private final boolean deltaCRLIndicator; |
| private final boolean completeCRLEnabled; |
| private final BigInteger maxBaseCRLNumber; |
| private final byte[] issuingDistributionPoint; |
| private final boolean issuingDistributionPointEnabled; |
| |
| private PKIXCRLStoreSelector(Builder baseBuilder) |
| { |
| this.baseSelector = baseBuilder.baseSelector; |
| this.deltaCRLIndicator = baseBuilder.deltaCRLIndicator; |
| this.completeCRLEnabled = baseBuilder.completeCRLEnabled; |
| this.maxBaseCRLNumber = baseBuilder.maxBaseCRLNumber; |
| this.issuingDistributionPoint = baseBuilder.issuingDistributionPoint; |
| this.issuingDistributionPointEnabled = baseBuilder.issuingDistributionPointEnabled; |
| } |
| |
| |
| /** |
| * Returns if the issuing distribution point criteria should be applied. |
| * Defaults to <code>false</code>. |
| * <p> |
| * You may also set the issuing distribution point criteria if not a missing |
| * issuing distribution point should be assumed. |
| * |
| * @return Returns if the issuing distribution point check is enabled. |
| */ |
| public boolean isIssuingDistributionPointEnabled() |
| { |
| return issuingDistributionPointEnabled; |
| } |
| |
| |
| |
| public boolean match(CRL obj) |
| { |
| if (!(obj instanceof X509CRL)) |
| { |
| return baseSelector.match(obj); |
| } |
| |
| X509CRL crl = (X509CRL)obj; |
| ASN1Integer dci = null; |
| try |
| { |
| byte[] bytes = crl |
| .getExtensionValue(Extension.deltaCRLIndicator.getId()); |
| if (bytes != null) |
| { |
| dci = ASN1Integer.getInstance(ASN1OctetString.getInstance(bytes).getOctets()); |
| } |
| } |
| catch (Exception e) |
| { |
| return false; |
| } |
| if (isDeltaCRLIndicatorEnabled()) |
| { |
| if (dci == null) |
| { |
| return false; |
| } |
| } |
| if (isCompleteCRLEnabled()) |
| { |
| if (dci != null) |
| { |
| return false; |
| } |
| } |
| if (dci != null) |
| { |
| |
| if (maxBaseCRLNumber != null) |
| { |
| if (dci.getPositiveValue().compareTo(maxBaseCRLNumber) == 1) |
| { |
| return false; |
| } |
| } |
| } |
| if (issuingDistributionPointEnabled) |
| { |
| byte[] idp = crl |
| .getExtensionValue(Extension.issuingDistributionPoint |
| .getId()); |
| if (issuingDistributionPoint == null) |
| { |
| if (idp != null) |
| { |
| return false; |
| } |
| } |
| else |
| { |
| if (!Arrays.areEqual(idp, issuingDistributionPoint)) |
| { |
| return false; |
| } |
| } |
| |
| } |
| return baseSelector.match(obj); |
| } |
| |
| /** |
| * Returns if this selector must match CRLs with the delta CRL indicator |
| * extension set. Defaults to <code>false</code>. |
| * |
| * @return Returns <code>true</code> if only CRLs with the delta CRL |
| * indicator extension are selected. |
| */ |
| public boolean isDeltaCRLIndicatorEnabled() |
| { |
| return deltaCRLIndicator; |
| } |
| |
| public Object clone() |
| { |
| return this; |
| } |
| |
| /** |
| * If <code>true</code> only complete CRLs are returned. Defaults to |
| * <code>false</code>. |
| * |
| * @return <code>true</code> if only complete CRLs are returned. |
| */ |
| public boolean isCompleteCRLEnabled() |
| { |
| return completeCRLEnabled; |
| } |
| |
| /** |
| * Get the maximum base CRL number. Defaults to <code>null</code>. |
| * |
| * @return Returns the maximum base CRL number. |
| */ |
| public BigInteger getMaxBaseCRLNumber() |
| { |
| return maxBaseCRLNumber; |
| } |
| |
| |
| /** |
| * Returns the issuing distribution point. Defaults to <code>null</code>, |
| * which is a missing issuing distribution point extension. |
| * <p> |
| * The internal byte array is cloned before it is returned. |
| * <p> |
| * The criteria must be enable with Builder.setIssuingDistributionPointEnabled(boolean)}. |
| * |
| * @return Returns the issuing distribution point. |
| */ |
| public byte[] getIssuingDistributionPoint() |
| { |
| return Arrays.clone(issuingDistributionPoint); |
| } |
| |
| public X509Certificate getCertificateChecking() |
| { |
| if (baseSelector instanceof X509CRLSelector) |
| { |
| return ((X509CRLSelector)baseSelector).getCertificateChecking(); |
| } |
| |
| return null; |
| } |
| |
| public static Collection<? extends CRL> getCRLs(final PKIXCRLStoreSelector selector, CertStore certStore) |
| throws CertStoreException |
| { |
| return certStore.getCRLs(new SelectorClone(selector)); |
| } |
| |
| private static class SelectorClone |
| extends X509CRLSelector |
| { |
| private final PKIXCRLStoreSelector selector; |
| |
| SelectorClone(PKIXCRLStoreSelector selector) |
| { |
| this.selector = selector; |
| |
| if (selector.baseSelector instanceof X509CRLSelector) |
| { |
| X509CRLSelector baseSelector = (X509CRLSelector)selector.baseSelector; |
| |
| this.setCertificateChecking(baseSelector.getCertificateChecking()); |
| this.setDateAndTime(baseSelector.getDateAndTime()); |
| this.setIssuers(baseSelector.getIssuers()); |
| this.setMinCRLNumber(baseSelector.getMinCRL()); |
| this.setMaxCRLNumber(baseSelector.getMaxCRL()); |
| } |
| } |
| |
| public boolean match(CRL crl) |
| { |
| return (selector == null) ? (crl != null) : selector.match(crl); |
| } |
| } |
| } |