Source for java.security.cert.X509CRLSelector

   1: /* X509CRLSelector.java -- selects X.509 CRLs by criteria.
   2:    Copyright (C) 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package java.security.cert;
  40: 
  41: import gnu.classpath.SystemProperties;
  42: import gnu.java.lang.CPStringBuilder;
  43: import gnu.java.security.der.DERReader;
  44: import gnu.java.security.der.DERValue;
  45: 
  46: import java.io.IOException;
  47: import java.io.InputStream;
  48: import java.math.BigInteger;
  49: import java.util.ArrayList;
  50: import java.util.Collection;
  51: import java.util.Collections;
  52: import java.util.Date;
  53: import java.util.Iterator;
  54: import java.util.LinkedList;
  55: import java.util.List;
  56: 
  57: import javax.security.auth.x500.X500Principal;
  58: 
  59: /**
  60:  * A class for matching X.509 certificate revocation lists by criteria.
  61:  *
  62:  * <p>Use of this class requires extensive knowledge of the Internet
  63:  * Engineering Task Force's Public Key Infrastructure (X.509). The primary
  64:  * document describing this standard is <a
  65:  * href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
  66:  * Public Key Infrastructure Certificate and Certificate Revocation List
  67:  * (CRL) Profile</a>.
  68:  *
  69:  * <p>Note that this class is not thread-safe. If multiple threads will
  70:  * use or modify this class then they need to synchronize on the object.
  71:  *
  72:  * @author Casey Marshall (csm@gnu.org)
  73:  * @since 1.4
  74:  */
  75: public class X509CRLSelector implements CRLSelector, Cloneable
  76: {
  77: 
  78:   // Fields.
  79:   // -------------------------------------------------------------------------
  80: 
  81:   private static final String CRL_NUMBER_ID = "2.5.29.20";
  82: 
  83:   private List issuerNames;
  84:   private BigInteger maxCrlNumber;
  85:   private BigInteger minCrlNumber;
  86:   private Date date;
  87:   private X509Certificate cert;
  88: 
  89:   // Constructor.
  90:   // -------------------------------------------------------------------------
  91: 
  92:   /**
  93:    * Creates a new CRL selector with no criteria enabled; i.e., every CRL
  94:    * will be matched.
  95:    */
  96:   public X509CRLSelector()
  97:   {
  98:   }
  99: 
 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: }