1 package org.bouncycastle.jcajce; 2 3 import java.math.BigInteger; 4 import java.security.cert.CRL; 5 import java.security.cert.CRLSelector; 6 import java.security.cert.CertStore; 7 import java.security.cert.CertStoreException; 8 import java.security.cert.X509CRL; 9 import java.security.cert.X509CRLSelector; 10 import java.security.cert.X509Certificate; 11 import java.util.Collection; 12 13 import org.bouncycastle.asn1.ASN1Integer; 14 import org.bouncycastle.asn1.ASN1OctetString; 15 import org.bouncycastle.asn1.x509.Extension; 16 import org.bouncycastle.util.Arrays; 17 import org.bouncycastle.util.Selector; 18 19 /** 20 * This class is a Selector implementation for X.509 certificate revocation 21 * lists. 22 * 23 * @see org.bouncycastle.util.Selector 24 */ 25 public class PKIXCRLStoreSelector<T extends CRL> 26 implements Selector<T> 27 { 28 /** 29 * Builder for a PKIXCRLStoreSelector. 30 */ 31 public static class Builder 32 { 33 private final CRLSelector baseSelector; 34 35 private boolean deltaCRLIndicator = false; 36 private boolean completeCRLEnabled = false; 37 private BigInteger maxBaseCRLNumber = null; 38 private byte[] issuingDistributionPoint = null; 39 private boolean issuingDistributionPointEnabled = false; 40 41 /** 42 * Constructor initializing a builder with a CertSelector. 43 * 44 * @param crlSelector the CertSelector to copy the match details from. 45 */ 46 public Builder(CRLSelector crlSelector) 47 { 48 this.baseSelector = (CRLSelector)crlSelector.clone(); 49 } 50 51 52 /** 53 * If set to <code>true</code> only complete CRLs are returned. 54 * <p> 55 * {@link #setCompleteCRLEnabled(boolean)} and 56 * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other. 57 * 58 * @param completeCRLEnabled <code>true</code> if only complete CRLs 59 * should be returned. 60 */ 61 public Builder setCompleteCRLEnabled(boolean completeCRLEnabled) 62 { 63 this.completeCRLEnabled = completeCRLEnabled; 64 65 return this; 66 } 67 68 /** 69 * If this is set to <code>true</code> the CRL reported contains the delta 70 * CRL indicator CRL extension. 71 * <p> 72 * {@link #setCompleteCRLEnabled(boolean)} and 73 * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other. 74 * 75 * @param deltaCRLIndicator <code>true</code> if the delta CRL indicator 76 * extension must be in the CRL. 77 */ 78 public Builder setDeltaCRLIndicatorEnabled(boolean deltaCRLIndicator) 79 { 80 this.deltaCRLIndicator = deltaCRLIndicator; 81 82 return this; 83 } 84 85 /** 86 * Sets the maximum base CRL number. Setting to <code>null</code> disables 87 * this cheack. 88 * <p> 89 * This is only meaningful for delta CRLs. Complete CRLs must have a CRL 90 * number which is greater or equal than the base number of the 91 * corresponding CRL. 92 * 93 * @param maxBaseCRLNumber The maximum base CRL number to set. 94 */ 95 public void setMaxBaseCRLNumber(BigInteger maxBaseCRLNumber) 96 { 97 this.maxBaseCRLNumber = maxBaseCRLNumber; 98 } 99 100 /** 101 * Enables or disables the issuing distribution point check. 102 * 103 * @param issuingDistributionPointEnabled <code>true</code> to enable the 104 * issuing distribution point check. 105 */ 106 public void setIssuingDistributionPointEnabled( 107 boolean issuingDistributionPointEnabled) 108 { 109 this.issuingDistributionPointEnabled = issuingDistributionPointEnabled; 110 } 111 112 /** 113 * Sets the issuing distribution point. 114 * <p> 115 * The issuing distribution point extension is a CRL extension which 116 * identifies the scope and the distribution point of a CRL. The scope 117 * contains among others information about revocation reasons contained in 118 * the CRL. Delta CRLs and complete CRLs must have matching issuing 119 * distribution points. 120 * <p> 121 * The byte array is cloned to protect against subsequent modifications. 122 * <p> 123 * You must also enable or disable this criteria with 124 * {@link #setIssuingDistributionPointEnabled(boolean)}. 125 * 126 * @param issuingDistributionPoint The issuing distribution point to set. 127 * This is the DER encoded OCTET STRING extension value. 128 * @see #getIssuingDistributionPoint() 129 */ 130 public void setIssuingDistributionPoint(byte[] issuingDistributionPoint) 131 { 132 this.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint); 133 } 134 135 /** 136 * Build a selector. 137 * 138 * @return a new PKIXCRLStoreSelector 139 */ 140 public PKIXCRLStoreSelector<? extends CRL> build() 141 { 142 return new PKIXCRLStoreSelector(this); 143 } 144 } 145 146 private final CRLSelector baseSelector; 147 private final boolean deltaCRLIndicator; 148 private final boolean completeCRLEnabled; 149 private final BigInteger maxBaseCRLNumber; 150 private final byte[] issuingDistributionPoint; 151 private final boolean issuingDistributionPointEnabled; 152 153 private PKIXCRLStoreSelector(Builder baseBuilder) 154 { 155 this.baseSelector = baseBuilder.baseSelector; 156 this.deltaCRLIndicator = baseBuilder.deltaCRLIndicator; 157 this.completeCRLEnabled = baseBuilder.completeCRLEnabled; 158 this.maxBaseCRLNumber = baseBuilder.maxBaseCRLNumber; 159 this.issuingDistributionPoint = baseBuilder.issuingDistributionPoint; 160 this.issuingDistributionPointEnabled = baseBuilder.issuingDistributionPointEnabled; 161 } 162 163 164 /** 165 * Returns if the issuing distribution point criteria should be applied. 166 * Defaults to <code>false</code>. 167 * <p> 168 * You may also set the issuing distribution point criteria if not a missing 169 * issuing distribution point should be assumed. 170 * 171 * @return Returns if the issuing distribution point check is enabled. 172 */ 173 public boolean isIssuingDistributionPointEnabled() 174 { 175 return issuingDistributionPointEnabled; 176 } 177 178 179 180 public boolean match(CRL obj) 181 { 182 if (!(obj instanceof X509CRL)) 183 { 184 return baseSelector.match(obj); 185 } 186 187 X509CRL crl = (X509CRL)obj; 188 ASN1Integer dci = null; 189 try 190 { 191 byte[] bytes = crl 192 .getExtensionValue(Extension.deltaCRLIndicator.getId()); 193 if (bytes != null) 194 { 195 dci = ASN1Integer.getInstance(ASN1OctetString.getInstance(bytes).getOctets()); 196 } 197 } 198 catch (Exception e) 199 { 200 return false; 201 } 202 if (isDeltaCRLIndicatorEnabled()) 203 { 204 if (dci == null) 205 { 206 return false; 207 } 208 } 209 if (isCompleteCRLEnabled()) 210 { 211 if (dci != null) 212 { 213 return false; 214 } 215 } 216 if (dci != null) 217 { 218 219 if (maxBaseCRLNumber != null) 220 { 221 if (dci.getPositiveValue().compareTo(maxBaseCRLNumber) == 1) 222 { 223 return false; 224 } 225 } 226 } 227 if (issuingDistributionPointEnabled) 228 { 229 byte[] idp = crl 230 .getExtensionValue(Extension.issuingDistributionPoint 231 .getId()); 232 if (issuingDistributionPoint == null) 233 { 234 if (idp != null) 235 { 236 return false; 237 } 238 } 239 else 240 { 241 if (!Arrays.areEqual(idp, issuingDistributionPoint)) 242 { 243 return false; 244 } 245 } 246 247 } 248 return baseSelector.match(obj); 249 } 250 251 /** 252 * Returns if this selector must match CRLs with the delta CRL indicator 253 * extension set. Defaults to <code>false</code>. 254 * 255 * @return Returns <code>true</code> if only CRLs with the delta CRL 256 * indicator extension are selected. 257 */ 258 public boolean isDeltaCRLIndicatorEnabled() 259 { 260 return deltaCRLIndicator; 261 } 262 263 public Object clone() 264 { 265 return this; 266 } 267 268 /** 269 * If <code>true</code> only complete CRLs are returned. Defaults to 270 * <code>false</code>. 271 * 272 * @return <code>true</code> if only complete CRLs are returned. 273 */ 274 public boolean isCompleteCRLEnabled() 275 { 276 return completeCRLEnabled; 277 } 278 279 /** 280 * Get the maximum base CRL number. Defaults to <code>null</code>. 281 * 282 * @return Returns the maximum base CRL number. 283 */ 284 public BigInteger getMaxBaseCRLNumber() 285 { 286 return maxBaseCRLNumber; 287 } 288 289 290 /** 291 * Returns the issuing distribution point. Defaults to <code>null</code>, 292 * which is a missing issuing distribution point extension. 293 * <p> 294 * The internal byte array is cloned before it is returned. 295 * <p> 296 * The criteria must be enable with Builder.setIssuingDistributionPointEnabled(boolean)}. 297 * 298 * @return Returns the issuing distribution point. 299 */ 300 public byte[] getIssuingDistributionPoint() 301 { 302 return Arrays.clone(issuingDistributionPoint); 303 } 304 305 public X509Certificate getCertificateChecking() 306 { 307 if (baseSelector instanceof X509CRLSelector) 308 { 309 return ((X509CRLSelector)baseSelector).getCertificateChecking(); 310 } 311 312 return null; 313 } 314 315 public static Collection<? extends CRL> getCRLs(final PKIXCRLStoreSelector selector, CertStore certStore) 316 throws CertStoreException 317 { 318 return certStore.getCRLs(new SelectorClone(selector)); 319 } 320 321 private static class SelectorClone 322 extends X509CRLSelector 323 { 324 private final PKIXCRLStoreSelector selector; 325 326 SelectorClone(PKIXCRLStoreSelector selector) 327 { 328 this.selector = selector; 329 330 if (selector.baseSelector instanceof X509CRLSelector) 331 { 332 X509CRLSelector baseSelector = (X509CRLSelector)selector.baseSelector; 333 334 this.setCertificateChecking(baseSelector.getCertificateChecking()); 335 this.setDateAndTime(baseSelector.getDateAndTime()); 336 this.setIssuers(baseSelector.getIssuers()); 337 this.setMinCRLNumber(baseSelector.getMinCRL()); 338 this.setMaxCRLNumber(baseSelector.getMaxCRL()); 339 } 340 } 341 342 public boolean match(CRL crl) 343 { 344 return (selector == null) ? (crl != null) : selector.match(crl); 345 } 346 } 347 } 348