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.security.der.DERReader;
  43: import gnu.java.security.der.DERValue;
  44: 
  45: import java.io.IOException;
  46: import java.io.InputStream;
  47: import java.math.BigInteger;
  48: import java.util.ArrayList;
  49: import java.util.Collection;
  50: import java.util.Collections;
  51: import java.util.Date;
  52: import java.util.Iterator;
  53: import java.util.LinkedList;
  54: import java.util.List;
  55: 
  56: import javax.security.auth.x500.X500Principal;
  57: 
  58: /**
  59:  * A class for matching X.509 certificate revocation lists by criteria.
  60:  *
  61:  * <p>Use of this class requires extensive knowledge of the Internet
  62:  * Engineering Task Force's Public Key Infrastructure (X.509). The primary
  63:  * document describing this standard is <a
  64:  * href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
  65:  * Public Key Infrastructure Certificate and Certificate Revocation List
  66:  * (CRL) Profile</a>.
  67:  *
  68:  * <p>Note that this class is not thread-safe. If multiple threads will
  69:  * use or modify this class then they need to synchronize on the object.
  70:  *
  71:  * @author Casey Marshall (csm@gnu.org)
  72:  * @since 1.4
  73:  */
  74: public class X509CRLSelector implements CRLSelector, Cloneable
  75: {
  76: 
  77:   // Fields.
  78:   // -------------------------------------------------------------------------
  79: 
  80:   private static final String CRL_NUMBER_ID = "2.5.29.20";
  81: 
  82:   private List issuerNames;
  83:   private BigInteger maxCrlNumber;
  84:   private BigInteger minCrlNumber;
  85:   private Date date;
  86:   private X509Certificate cert;
  87: 
  88:   // Constructor.
  89:   // -------------------------------------------------------------------------
  90: 
  91:   /**
  92:    * Creates a new CRL selector with no criteria enabled; i.e., every CRL
  93:    * will be matched.
  94:    */
  95:   public X509CRLSelector()
  96:   {
  97:   }
  98: 
  99:   // 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: }