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    }