001/* X509CRLSelector.java -- selects X.509 CRLs by criteria.
002   Copyright (C) 2004 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.security.cert;
040
041import gnu.classpath.SystemProperties;
042import gnu.java.lang.CPStringBuilder;
043import gnu.java.security.der.DERReader;
044import gnu.java.security.der.DERValue;
045
046import java.io.IOException;
047import java.io.InputStream;
048import java.math.BigInteger;
049import java.util.ArrayList;
050import java.util.Collection;
051import java.util.Collections;
052import java.util.Date;
053import java.util.Iterator;
054import java.util.LinkedList;
055import java.util.List;
056
057import 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 */
075public 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}