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