001 /* X509CRLSelector.java -- selects X.509 CRLs by criteria.
002 Copyright (C) 2004 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package java.security.cert;
040
041 import gnu.classpath.SystemProperties;
042 import gnu.java.security.der.DERReader;
043 import gnu.java.security.der.DERValue;
044
045 import java.io.IOException;
046 import java.io.InputStream;
047 import java.math.BigInteger;
048 import java.util.ArrayList;
049 import java.util.Collection;
050 import java.util.Collections;
051 import java.util.Date;
052 import java.util.Iterator;
053 import java.util.LinkedList;
054 import java.util.List;
055
056 import javax.security.auth.x500.X500Principal;
057
058 /**
059 * A class for matching X.509 certificate revocation lists by criteria.
060 *
061 * <p>Use of this class requires extensive knowledge of the Internet
062 * Engineering Task Force's Public Key Infrastructure (X.509). The primary
063 * document describing this standard is <a
064 * href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
065 * Public Key Infrastructure Certificate and Certificate Revocation List
066 * (CRL) Profile</a>.
067 *
068 * <p>Note that this class is not thread-safe. If multiple threads will
069 * use or modify this class then they need to synchronize on the object.
070 *
071 * @author Casey Marshall (csm@gnu.org)
072 * @since 1.4
073 */
074 public class X509CRLSelector implements CRLSelector, Cloneable
075 {
076
077 // Fields.
078 // -------------------------------------------------------------------------
079
080 private static final String CRL_NUMBER_ID = "2.5.29.20";
081
082 private List issuerNames;
083 private BigInteger maxCrlNumber;
084 private BigInteger minCrlNumber;
085 private Date date;
086 private X509Certificate cert;
087
088 // Constructor.
089 // -------------------------------------------------------------------------
090
091 /**
092 * Creates a new CRL selector with no criteria enabled; i.e., every CRL
093 * will be matched.
094 */
095 public X509CRLSelector()
096 {
097 }
098
099 // Instance methods.
100 // -------------------------------------------------------------------------
101
102 /**
103 * Add an issuer name to the set of issuer names criteria, as the DER
104 * encoded form.
105 *
106 * @param name The name to add, as DER bytes.
107 * @throws IOException If the argument is not a valid DER-encoding.
108 */
109 public void addIssuerName(byte[] name) throws IOException
110 {
111 X500Principal p = null;
112 try
113 {
114 p = new X500Principal(name);
115 }
116 catch (IllegalArgumentException iae)
117 {
118 IOException ioe = new IOException("malformed name");
119 ioe.initCause(iae);
120 throw ioe;
121 }
122 if (issuerNames == null)
123 issuerNames = new LinkedList();
124 issuerNames.add(p);
125 }
126
127 /**
128 * Add an issuer name to the set of issuer names criteria, as a
129 * String representation.
130 *
131 * @param name The name to add.
132 * @throws IOException If the argument is not a valid name.
133 */
134 public void addIssuerName(String name) throws IOException
135 {
136 X500Principal p = null;
137 try
138 {
139 p = new X500Principal(name);
140 }
141 catch (IllegalArgumentException iae)
142 {
143 IOException ioe = new IOException("malformed name: " + name);
144 ioe.initCause(iae);
145 throw ioe;
146 }
147 if (issuerNames == null)
148 issuerNames = new LinkedList();
149 issuerNames.add(p);
150 }
151
152 /**
153 * Sets the issuer names criterion. Pass <code>null</code> to clear this
154 * value. CRLs matched by this selector must have an issuer name in this
155 * set.
156 *
157 * @param names The issuer names.
158 * @throws IOException If any of the elements in the collection is not
159 * a valid name.
160 */
161 public void setIssuerNames(Collection<?> names) throws IOException
162 {
163 if (names == null)
164 {
165 issuerNames = null;
166 return;
167 }
168 List l = new ArrayList(names.size());
169 for (Iterator it = names.iterator(); it.hasNext(); )
170 {
171 Object o = it.next();
172 if (o instanceof X500Principal)
173 l.add(o);
174 else if (o instanceof String)
175 {
176 try
177 {
178 l.add(new X500Principal((String) o));
179 }
180 catch (IllegalArgumentException iae)
181 {
182 IOException ioe = new IOException("malformed name: " + o);
183 ioe.initCause(iae);
184 throw ioe;
185 }
186 }
187 else if (o instanceof byte[])
188 {
189 try
190 {
191 l.add(new X500Principal((byte[]) o));
192 }
193 catch (IllegalArgumentException iae)
194 {
195 IOException ioe = new IOException("malformed name");
196 ioe.initCause(iae);
197 throw ioe;
198 }
199 }
200 else if (o instanceof InputStream)
201 {
202 try
203 {
204 l.add(new X500Principal((InputStream) o));
205 }
206 catch (IllegalArgumentException iae)
207 {
208 IOException ioe = new IOException("malformed name");
209 ioe.initCause(iae);
210 throw ioe;
211 }
212 }
213 else
214 throw new IOException("not a valid name: " +
215 (o != null ? o.getClass().getName() : "null"));
216
217 }
218 issuerNames = l;
219 }
220
221 /**
222 * Returns the set of issuer names that are matched by this selector,
223 * or <code>null</code> if this criteria is not set. The returned
224 * collection is not modifiable.
225 *
226 * @return The set of issuer names.
227 */
228 public Collection<Object> getIssuerNames()
229 {
230 if (issuerNames != null)
231 return Collections.unmodifiableList(issuerNames);
232 else
233 return null;
234 }
235
236 /**
237 * Returns the maximum value of the CRLNumber extension present in
238 * CRLs matched by this selector, or <code>null</code> if this
239 * criteria is not set.
240 *
241 * @return The maximum CRL number.
242 */
243 public BigInteger getMaxCRL()
244 {
245 return maxCrlNumber;
246 }
247
248 /**
249 * Returns the minimum value of the CRLNumber extension present in
250 * CRLs matched by this selector, or <code>null</code> if this
251 * criteria is not set.
252 *
253 * @return The minimum CRL number.
254 */
255 public BigInteger getMinCRL()
256 {
257 return minCrlNumber;
258 }
259
260 /**
261 * Sets the maximum value of the CRLNumber extension present in CRLs
262 * matched by this selector. Specify <code>null</code> to clear this
263 * criterion.
264 *
265 * @param maxCrlNumber The maximum CRL number.
266 */
267 public void setMaxCRLNumber(BigInteger maxCrlNumber)
268 {
269 this.maxCrlNumber = maxCrlNumber;
270 }
271
272 /**
273 * Sets the minimum value of the CRLNumber extension present in CRLs
274 * matched by this selector. Specify <code>null</code> to clear this
275 * criterion.
276 *
277 * @param minCrlNumber The minimum CRL number.
278 */
279 public void setMinCRLNumber(BigInteger minCrlNumber)
280 {
281 this.minCrlNumber = minCrlNumber;
282 }
283
284 /**
285 * Returns the date when this CRL must be valid; that is, the date
286 * must be after the thisUpdate date, but before the nextUpdate date.
287 * Returns <code>null</code> if this criterion is not set.
288 *
289 * @return The date.
290 */
291 public Date getDateAndTime()
292 {
293 return date != null ? (Date) date.clone() : null;
294 }
295
296 /**
297 * Sets the date at which this CRL must be valid. Specify
298 * <code>null</code> to clear this criterion.
299 *
300 * @param date The date.
301 */
302 public void setDateAndTime(Date date)
303 {
304 this.date = date != null ? (Date) date.clone() : null;
305 }
306
307 /**
308 * Returns the certificate being checked, or <code>null</code> if this
309 * value is not set.
310 *
311 * @return The certificate.
312 */
313 public X509Certificate getCertificateChecking()
314 {
315 return cert;
316 }
317
318 /**
319 * Sets the certificate being checked. This is not a criterion, but
320 * info used by certificate store implementations to aid in searching.
321 *
322 * @param cert The certificate.
323 */
324 public void setCertificateChecking(X509Certificate cert)
325 {
326 this.cert = cert;
327 }
328
329 /**
330 * Returns a string representation of this selector. The string will
331 * only describe the enabled criteria, so if none are enabled this will
332 * return a string that contains little else besides the class name.
333 *
334 * @return The string.
335 */
336 public String toString()
337 {
338 StringBuffer str = new StringBuffer(X509CRLSelector.class.getName());
339 String nl = SystemProperties.getProperty("line.separator");
340 String eol = ";" + nl;
341
342 str.append(" {").append(nl);
343 if (issuerNames != null)
344 str.append(" issuer names = ").append(issuerNames).append(eol);
345 if (maxCrlNumber != null)
346 str.append(" max CRL = ").append(maxCrlNumber).append(eol);
347 if (minCrlNumber != null)
348 str.append(" min CRL = ").append(minCrlNumber).append(eol);
349 if (date != null)
350 str.append(" date = ").append(date).append(eol);
351 if (cert != null)
352 str.append(" certificate = ").append(cert).append(eol);
353 str.append("}").append(nl);
354 return str.toString();
355 }
356
357 /**
358 * Checks a CRL against the criteria of this selector, returning
359 * <code>true</code> if the given CRL matches all the criteria.
360 *
361 * @param _crl The CRL being checked.
362 * @return True if the CRL matches, false otherwise.
363 */
364 public boolean match(CRL _crl)
365 {
366 if (!(_crl instanceof X509CRL))
367 return false;
368 X509CRL crl = (X509CRL) _crl;
369 if (issuerNames != null)
370 {
371 if (!issuerNames.contains(crl.getIssuerX500Principal()))
372 return false;
373 }
374 BigInteger crlNumber = null;
375 if (maxCrlNumber != null)
376 {
377 byte[] b = crl.getExtensionValue(CRL_NUMBER_ID);
378 if (b == null)
379 return false;
380 try
381 {
382 DERValue val = DERReader.read(b);
383 if (!(val.getValue() instanceof BigInteger))
384 return false;
385 crlNumber = (BigInteger) val.getValue();
386 }
387 catch (IOException ioe)
388 {
389 return false;
390 }
391 if (maxCrlNumber.compareTo(crlNumber) < 0)
392 return false;
393 }
394 if (minCrlNumber != null)
395 {
396 if (crlNumber == null)
397 {
398 byte[] b = crl.getExtensionValue(CRL_NUMBER_ID);
399 if (b == null)
400 return false;
401 try
402 {
403 DERValue val = DERReader.read(b);
404 if (!(val.getValue() instanceof BigInteger))
405 return false;
406 crlNumber = (BigInteger) val.getValue();
407 }
408 catch (IOException ioe)
409 {
410 return false;
411 }
412 }
413 if (minCrlNumber.compareTo(crlNumber) > 0)
414 return false;
415 }
416 if (date != null)
417 {
418 if (date.compareTo(crl.getThisUpdate()) < 0 ||
419 date.compareTo(crl.getNextUpdate()) > 0)
420 return false;
421 }
422 return true;
423 }
424
425 /**
426 * Returns a copy of this object.
427 *
428 * @return The copy.
429 */
430 public Object clone()
431 {
432 try
433 {
434 return super.clone();
435 }
436 catch (CloneNotSupportedException shouldNotHappen)
437 {
438 throw new Error(shouldNotHappen);
439 }
440 }
441 }