1
package java.security.cert;
3
import java.io.ByteArrayInputStream;
4
import java.io.IOException;
5
import java.math.BigInteger;
6
import java.util.Collection;
8
import java.util.HashSet;
9
import java.util.Iterator;
12
import org.bouncycastle.asn1.ASN1InputStream;
13
import org.bouncycastle.asn1.ASN1OctetString;
14
import org.bouncycastle.asn1.ASN1Sequence;
15
import org.bouncycastle.asn1.DERInteger;
16
import org.bouncycastle.asn1.DERObject;
17
import org.bouncycastle.asn1.x509.X509Extensions;
18
import org.bouncycastle.asn1.x509.X509Name;
19
import org.bouncycastle.jce.PrincipalUtil;
22
* A <code>CRLSelector</code> that selects <code>X509CRLs</code> that
23
* match all specified criteria. This class is particularly useful when
24
* selecting CRLs from a <code>CertStore</code> to check revocation status
25
* of a particular certificate.<br />
27
* When first constructed, an <code>X509CRLSelector</code> has no criteria
28
* enabled and each of the <code>get</code> methods return a default
29
* value (<code>null</code>). Therefore, the {@link #match match} method
30
* would return <code>true</code> for any <code>X509CRL</code>. Typically,
31
* several criteria are enabled (by calling {@link #setIssuerNames setIssuerNames}
32
* or {@link #setDateAndTime setDateAndTime}, for instance) and then the
33
* <code>X509CRLSelector</code> is passed to
34
* {@link CertStore#getCRLs CertStore.getCRLs} or some similar
37
* Please refer to RFC 2459 for definitions of the X.509 CRL fields and
38
* extensions mentioned below.<br />
40
* <b>Concurrent Access</b><br />
42
* Unless otherwise specified, the methods defined in this class are not
43
* thread-safe. Multiple threads that need to access a single
44
* object concurrently should synchronize amongst themselves and
45
* provide the necessary locking. Multiple threads each manipulating
46
* separate objects need not synchronize.<br />
48
* Uses {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream},
49
* {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence},
50
* {@link org.bouncycastle.asn1.DERObjectIdentifier DERObjectIdentifier},
51
* {@link org.bouncycastle.asn1.DEROutputStream DEROutputStream},
52
* {@link org.bouncycastle.asn1.DERObject DERObject},
53
* {@link org.bouncycastle.asn1.x509.X509Name X509Name} and
54
* {@link org.bouncycastle.asn1.util.ASN1Dump#_dumpAsString _dumpAsString}
59
public class X509CRLSelector implements CRLSelector
61
private Set issuerNames = null;
62
private Set issuerNamesX509 = null;
63
private BigInteger minCRL = null;
64
private BigInteger maxCRL = null;
65
private Date dateAndTime = null;
66
private X509Certificate certChecking = null;
69
* Creates an <code>X509CRLSelector</code>. Initially, no criteria are set
70
* so any <code>X509CRL</code> will match.
72
public X509CRLSelector() {}
75
* Sets the issuerNames criterion. The issuer distinguished name in the
76
* <code>X509CRL</code> must match at least one of the specified
77
* distinguished names. If <code>null</code>, any issuer distinguished name
80
* This method allows the caller to specify, with a single method call,
81
* the complete set of issuer names which <code>X509CRLs</code> may contain.
82
* The specified value replaces the previous value for the issuerNames
85
* The <code>names</code> parameter (if not <code>null</code>) is a
86
* <code>Collection</code> of names. Each name is a <code>String</code>
87
* or a byte array representing a distinguished name (in RFC 2253 or
88
* ASN.1 DER encoded form, respectively). If <code>null</code> is supplied
89
* as the value for this argument, no issuerNames check will be performed.<br />
91
* Note that the <code>names</code> parameter can contain duplicate
92
* distinguished names, but they may be removed from the
93
* <code>Collection</code> of names returned by the
94
* {@link #getIssuerNames getIssuerNames} method.<br />
96
* If a name is specified as a byte array, it should contain a single DER
97
* encoded distinguished name, as defined in X.501. The ASN.1 notation for
98
* this structure is as follows.
103
* RDNSequence ::= SEQUENCE OF RDN
106
* SET SIZE (1 .. MAX) OF AttributeTypeAndValue
108
* AttributeTypeAndValue ::= SEQUENCE {
109
* type AttributeType,
110
* value AttributeValue }
112
* AttributeType ::= OBJECT IDENTIFIER
114
* AttributeValue ::= ANY DEFINED BY AttributeType
116
* DirectoryString ::= CHOICE {
117
* teletexString TeletexString (SIZE (1..MAX)),
118
* printableString PrintableString (SIZE (1..MAX)),
119
* universalString UniversalString (SIZE (1..MAX)),
120
* utf8String UTF8String (SIZE (1.. MAX)),
121
* bmpString BMPString (SIZE (1..MAX)) }
122
* </code></pre><br />
124
* Note that a deep copy is performed on the <code>Collection</code> to
125
* protect against subsequent modifications.
127
* @param names a <code>Collection</code> of names (or <code>null</code>)
129
* @exception IOException if a parsing error occurs
131
* @see #getIssuerNames
133
public void setIssuerNames(Collection names)
136
if ( names == null || names.isEmpty() )
139
issuerNamesX509 = null;
144
Iterator iter = names.iterator();
145
while ( iter.hasNext() )
148
if ( item instanceof String )
149
addIssuerName( (String)item );
150
else if ( item instanceof byte[] )
151
addIssuerName( (byte[])item );
153
throw new IOException( "name not byte[]or String: " + item.toString() );
159
* Adds a name to the issuerNames criterion. The issuer distinguished
160
* name in the <code>X509CRL</code> must match at least one of the specified
161
* distinguished names.<br />
163
* This method allows the caller to add a name to the set of issuer names
164
* which <code>X509CRLs</code> may contain. The specified name is added to
165
* any previous value for the issuerNames criterion.
166
* If the specified name is a duplicate, it may be ignored.<br />
168
* Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name} for parsing the name
170
* @param name the name in RFC 2253 form
172
* @exception IOException if a parsing error occurs
174
public void addIssuerName(String name)
177
if ( issuerNames == null )
179
issuerNames = new HashSet();
180
issuerNamesX509 = new HashSet();
184
nameX509 = new X509Name(name);
185
} catch ( IllegalArgumentException ex ) {
186
throw new IOException(ex.getMessage());
188
issuerNamesX509.add(nameX509);
189
issuerNames.add(name);
193
* Adds a name to the issuerNames criterion. The issuer distinguished
194
* name in the <code>X509CRL</code> must match at least one of the specified
195
* distinguished names.<br />
197
* This method allows the caller to add a name to the set of issuer names
198
* which <code>X509CRLs</code> may contain. The specified name is added to
199
* any previous value for the issuerNames criterion. If the specified name
200
* is a duplicate, it may be ignored.
201
* If a name is specified as a byte array, it should contain a single DER
202
* encoded distinguished name, as defined in X.501. The ASN.1 notation for
203
* this structure is as follows.<br />
205
* The name is provided as a byte array. This byte array should contain
206
* a single DER encoded distinguished name, as defined in X.501. The ASN.1
207
* notation for this structure appears in the documentation for
208
* {@link #setIssuerNames setIssuerNames(Collection names)}.<br />
210
* Note that the byte array supplied here is cloned to protect against
211
* subsequent modifications.<br />
213
* Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name} for parsing the name,
214
* {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream},
215
* {@link org.bouncycastle.asn1.DERObject DERObject} and
216
* {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence}
218
* @param name a byte array containing the name in ASN.1 DER encoded form
220
* @exception IOException if a parsing error occurs
222
public void addIssuerName(byte[] name)
225
if ( issuerNames == null ) {
226
issuerNames = new HashSet();
227
issuerNamesX509 = new HashSet();
230
ByteArrayInputStream inStream = new ByteArrayInputStream(name);
231
ASN1InputStream derInStream = new ASN1InputStream(inStream);
232
DERObject obj = derInStream.readObject();
233
if ( obj instanceof ASN1Sequence )
235
issuerNamesX509.add(new X509Name((ASN1Sequence)obj));
239
throw new IOException("parsing error");
241
issuerNames.add(name.clone());
245
* Sets the minCRLNumber criterion. The <code>X509CRL</code> must have a
246
* CRL number extension whose value is greater than or equal to the
247
* specified value. If <code>null</code>, no minCRLNumber check will be
250
* @param minCRL the minimum CRL number accepted (or <code>null</code>)
252
public void setMinCRLNumber(BigInteger minCRL)
254
this.minCRL = minCRL;
258
* Sets the maxCRLNumber criterion. The <code>X509CRL</code> must have a
259
* CRL number extension whose value is less than or equal to the
260
* specified value. If <code>null</code>, no maxCRLNumber check will be
263
* @param maxCRL the maximum CRL number accepted (or <code>null</code>)
265
public void setMaxCRLNumber(BigInteger maxCRL)
267
this.maxCRL = maxCRL;
271
* Sets the dateAndTime criterion. The specified date must be
272
* equal to or later than the value of the thisUpdate component
273
* of the <code>X509CRL</code> and earlier than the value of the
274
* nextUpdate component. There is no match if the <code>X509CRL</code>
275
* does not contain a nextUpdate component.
276
* If <code>null</code>, no dateAndTime check will be done.<br />
278
* Note that the <code>Date</code> supplied here is cloned to protect
279
* against subsequent modifications.
281
* @param dateAndTime the <code>Date</code> to match against
282
* (or <code>null</code>)
284
* @see #getDateAndTime
286
public void setDateAndTime(Date dateAndTime)
288
if ( dateAndTime == null )
289
this.dateAndTime = null;
291
this.dateAndTime = new Date( dateAndTime.getTime() );
295
* Sets the certificate being checked. This is not a criterion. Rather,
296
* it is optional information that may help a <code>CertStore</code>
297
* find CRLs that would be relevant when checking revocation for the
298
* specified certificate. If <code>null</code> is specified, then no
299
* such optional information is provided.
301
* @param cert the <code>X509Certificate</code> being checked
302
* (or <code>null</code>)
304
* @see #getCertificateChecking
306
public void setCertificateChecking(X509Certificate cert)
312
* Returns a copy of the issuerNames criterion. The issuer distinguished
313
* name in the <code>X509CRL</code> must match at least one of the specified
314
* distinguished names. If the value returned is <code>null</code>, any
315
* issuer distinguished name will do.<br />
317
* If the value returned is not <code>null</code>, it is a
318
* <code>Collection</code> of names. Each name is a <code>String</code>
319
* or a byte array representing a distinguished name (in RFC 2253 or
320
* ASN.1 DER encoded form, respectively). Note that the
321
* <code>Collection</code> returned may contain duplicate names.<br />
323
* If a name is specified as a byte array, it should contain a single DER
324
* encoded distinguished name, as defined in X.501. The ASN.1 notation for
325
* this structure is given in the documentation for
326
* {@link #setIssuerNames setIssuerNames(Collection names)}.<br />
328
* Note that a deep copy is performed on the <code>Collection</code> to
329
* protect against subsequent modifications.
331
* @return a <code>Collection</code> of names (or <code>null</code>)
332
* @see #setIssuerNames
334
public Collection getIssuerNames()
336
if ( issuerNames == null )
339
Collection set = new HashSet();
340
Iterator iter = issuerNames.iterator();
342
while ( iter.hasNext() )
345
if ( item instanceof String )
346
set.add(new String((String)item));
347
else if ( item instanceof byte[] )
348
set.add(((byte[])item).clone());
354
* Returns the minCRLNumber criterion. The <code>X509CRL</code> must have a
355
* CRL number extension whose value is greater than or equal to the
356
* specified value. If <code>null</code>, no minCRLNumber check will be done.
358
* @return the minimum CRL number accepted (or <code>null</code>)
360
public BigInteger getMinCRL()
366
* Returns the maxCRLNumber criterion. The <code>X509CRL</code> must have a
367
* CRL number extension whose value is less than or equal to the
368
* specified value. If <code>null</code>, no maxCRLNumber check will be
371
* @return the maximum CRL number accepted (or <code>null</code>)
373
public BigInteger getMaxCRL()
379
* Returns the dateAndTime criterion. The specified date must be
380
* equal to or later than the value of the thisUpdate component
381
* of the <code>X509CRL</code> and earlier than the value of the
382
* nextUpdate component. There is no match if the
383
* <code>X509CRL</code> does not contain a nextUpdate component.
384
* If <code>null</code>, no dateAndTime check will be done.<br />
386
* Note that the <code>Date</code> returned is cloned to protect against
387
* subsequent modifications.
389
* @return the <code>Date</code> to match against (or <code>null</code>)
391
* @see #setDateAndTime
393
public Date getDateAndTime()
395
if ( dateAndTime == null )
398
return new Date(dateAndTime.getTime());
402
* Returns the certificate being checked. This is not a criterion. Rather,
403
* it is optional information that may help a <code>CertStore</code>
404
* find CRLs that would be relevant when checking revocation for the
405
* specified certificate. If the value returned is <code>null</code>, then
406
* no such optional information is provided.
408
* @return the certificate being checked (or <code>null</code>)
410
* @see #setCertificateChecking
412
public X509Certificate getCertificateChecking()
418
* Returns a printable representation of the <code>X509CRLSelector</code>.<br />
420
* Uses {@link org.bouncycastle.asn1.x509.X509Name#toString X509Name.toString} to format the output
422
* @return a <code>String</code> describing the contents of the
423
* <code>X509CRLSelector</code>.
425
public String toString()
427
StringBuffer s = new StringBuffer();
428
s.append( "X509CRLSelector: [\n" );
429
if ( issuerNamesX509 != null ) {
430
s.append(" IssuerNames:\n");
431
Iterator iter = issuerNamesX509.iterator();
432
while ( iter.hasNext() ) {
433
s.append( " ").append(iter.next()).append('\n' );
437
s.append(" minCRLNumber: ").append(minCRL).append('\n');
439
s.append(" maxCRLNumber: ").append(maxCRL).append('\n');
440
if (dateAndTime != null)
441
s.append(" dateAndTime: ").append(dateAndTime).append('\n');
442
if (certChecking != null)
443
s.append(" Certificate being checked: ").append(certChecking).append('\n');
449
* Decides whether a <code>CRL</code> should be selected.<br />
451
* Uses {@link org.bouncycastle.asn1.x509.X509Name#toString X509Name.toString}
452
* to parse and to compare the crl parameter issuer and
453
* {@link org.bouncycastle.asn1.x509.X509Extensions#CRLNumber CRLNumber} to access
454
* the CRL number extension.
456
* @param crl the <code>CRL</code> to be checked
458
* @return <code>true</code> if the <code>CRL</code> should be selected,
459
* <code>false</code> otherwise
461
public boolean match(CRL crl)
463
if ( ! ( crl instanceof X509CRL ) )
466
X509CRL crlX509 = (X509CRL)crl;
469
if ( issuerNamesX509 != null )
471
Iterator iter = issuerNamesX509.iterator();
473
X509Name crlIssuer = null;
475
crlIssuer = PrincipalUtil.getIssuerX509Principal(crlX509);
476
} catch ( Exception ex ) {
480
while ( iter.hasNext() )
482
if ( crlIssuer.equals(iter.next(), true) )
494
byte[] data = crlX509.getExtensionValue( X509Extensions.CRLNumber.getId() );
498
ByteArrayInputStream inStream = new ByteArrayInputStream(data);
499
ASN1InputStream derInputStream = new ASN1InputStream(inStream);
500
inStream = new ByteArrayInputStream(((ASN1OctetString)derInputStream.readObject()).getOctets());
501
derInputStream = new ASN1InputStream(inStream);
502
BigInteger crlNumber = ((DERInteger)derInputStream.readObject()).getPositiveValue();
503
if ( minCRL != null && minCRL.compareTo( crlNumber ) > 0 )
505
if ( maxCRL != null && maxCRL.compareTo( crlNumber ) < 0 )
507
} catch ( IOException ex ) {
510
} else if ( minCRL != null || maxCRL != null )
515
if ( dateAndTime != null )
517
Date check = crlX509.getThisUpdate();
522
else if ( dateAndTime.before( check ) )
527
check = crlX509.getNextUpdate();
532
else if ( ! dateAndTime.before( check ) )
542
* Returns a copy of this object.
546
public Object clone()
549
X509CRLSelector copy = (X509CRLSelector)super.clone();
550
if ( issuerNames != null )
552
copy.issuerNames = new HashSet();
553
Iterator iter = issuerNames.iterator();
555
while ( iter.hasNext() )
558
if ( obj instanceof byte[] )
559
copy.issuerNames.add( ((byte[])obj).clone() );
561
copy.issuerNames.add( obj );
563
copy.issuerNamesX509 = new HashSet( issuerNamesX509 );
566
} catch (CloneNotSupportedException e) {
568
throw new InternalError(e.toString());
573
* Decides whether a <code>CRL</code> should be selected.
575
* @param crl the <code>CRL</code> to be checked
577
* @return <code>true</code> if the <code>CRL</code> should be selected,
578
* <code>false</code> otherwise
580
public boolean equals( Object obj )
582
if ( ! ( obj instanceof X509CRLSelector ) )
585
X509CRLSelector equalsCRL = (X509CRLSelector)obj;
587
if ( ! equals(dateAndTime, equalsCRL.dateAndTime) )
590
if ( ! equals(minCRL, equalsCRL.minCRL) )
593
if ( ! equals(maxCRL, equalsCRL.maxCRL) )
596
if ( ! equals(issuerNamesX509, equalsCRL.issuerNamesX509) )
599
if ( ! equals( certChecking, equalsCRL.certChecking) )
606
* Return <code>true</code> if two Objects are unequal.
607
* This means that one is <code>null</code> and the other is
608
* not or <code>obj1.equals(obj2)</code> returns
609
* <code>false</code>.
611
private boolean equals( Object obj1, Object obj2 )
613
if ( obj1 == null ) {
617
else if ( ! obj1.equals( obj2 ) )