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:  */
  73: public class X509CRLSelector implements CRLSelector, Cloneable
  74: {
  75: 
  76:   // Fields.
  77:   // -------------------------------------------------------------------------
  78: 
  79:   private static final String CRL_NUMBER_ID = "2.5.29.20";
  80: 
  81:   private List issuerNames;
  82:   private BigInteger maxCrlNumber;
  83:   private BigInteger minCrlNumber;
  84:   private Date date;
  85:   private X509Certificate cert;
  86: 
  87:   // Constructor.
  88:   // -------------------------------------------------------------------------
  89: 
  90:   /**
  91:    * Creates a new CRL selector with no criteria enabled; i.e., every CRL
  92:    * will be matched.
  93:    */
  94:   public X509CRLSelector()
  95:   {
  96:   }
  97: 
  98:   // Instance methods.
  99:   // -------------------------------------------------------------------------
 100: 
 101:   /**
 102:    * Add an issuer name to the set of issuer names criteria, as the DER
 103:    * encoded form.
 104:    *
 105:    * @param name The name to add, as DER bytes.
 106:    * @throws IOException If the argument is not a valid DER-encoding.
 107:    */
 108:   public void addIssuerName(byte[] name) throws IOException
 109:   {
 110:     X500Principal p = null;
 111:     try
 112:       {
 113:         p = new X500Principal(name);
 114:       }
 115:     catch (IllegalArgumentException iae)
 116:       {
 117:         IOException ioe = new IOException("malformed name");
 118:         ioe.initCause(iae);
 119:         throw ioe;
 120:       }
 121:     if (issuerNames == null)
 122:       issuerNames = new LinkedList();
 123:     issuerNames.add(p);
 124:   }
 125: 
 126:   /**
 127:    * Add an issuer name to the set of issuer names criteria, as a
 128:    * String representation.
 129:    *
 130:    * @param name The name to add.
 131:    * @throws IOException If the argument is not a valid name.
 132:    */
 133:   public void addIssuerName(String name) throws IOException
 134:   {
 135:     X500Principal p = null;
 136:     try
 137:       {
 138:         p = new X500Principal(name);
 139:       }
 140:     catch (IllegalArgumentException iae)
 141:       {
 142:         IOException ioe = new IOException("malformed name: " + name);
 143:         ioe.initCause(iae);
 144:         throw ioe;
 145:       }
 146:     if (issuerNames == null)
 147:       issuerNames = new LinkedList();
 148:     issuerNames.add(p);
 149:   }
 150: 
 151:   /**
 152:    * Sets the issuer names criterion. Pass <code>null</code> to clear this
 153:    * value. CRLs matched by this selector must have an issuer name in this
 154:    * set.
 155:    *
 156:    * @param names The issuer names.
 157:    * @throws IOException If any of the elements in the collection is not
 158:    *         a valid name.
 159:    */
 160:   public void setIssuerNames(Collection names) throws IOException
 161:   {
 162:     if (names == null)
 163:       {
 164:         issuerNames = null;
 165:         return;
 166:       }
 167:     List l = new ArrayList(names.size());
 168:     for (Iterator it = names.iterator(); it.hasNext(); )
 169:       {
 170:         Object o = it.next();
 171:         if (o instanceof X500Principal)
 172:           l.add(o);
 173:         else if (o instanceof String)
 174:           {
 175:             try
 176:               {
 177:                 l.add(new X500Principal((String) o));
 178:               }
 179:             catch (IllegalArgumentException iae)
 180:               {
 181:                 IOException ioe = new IOException("malformed name: " + o);
 182:                 ioe.initCause(iae);
 183:                 throw ioe;
 184:               }
 185:           }
 186:         else if (o instanceof byte[])
 187:           {
 188:             try
 189:               {
 190:                 l.add(new X500Principal((byte[]) o));
 191:               }
 192:             catch (IllegalArgumentException iae)
 193:               {
 194:                 IOException ioe = new IOException("malformed name");
 195:                 ioe.initCause(iae);
 196:                 throw ioe;
 197:               }
 198:           }
 199:         else if (o instanceof InputStream)
 200:           {
 201:             try
 202:               {
 203:                 l.add(new X500Principal((InputStream) o));
 204:               }
 205:             catch (IllegalArgumentException iae)
 206:               {
 207:                 IOException ioe = new IOException("malformed name");
 208:                 ioe.initCause(iae);
 209:                 throw ioe;
 210:               }
 211:           }
 212:         else
 213:           throw new IOException("not a valid name: " +
 214:                                 (o != null ? o.getClass().getName() : "null"));
 215: 
 216:       }
 217:     issuerNames = l;
 218:   }
 219: 
 220:   /**
 221:    * Returns the set of issuer names that are matched by this selector,
 222:    * or <code>null</code> if this criteria is not set. The returned
 223:    * collection is not modifiable.
 224:    *
 225:    * @return The set of issuer names.
 226:    */
 227:   public Collection getIssuerNames()
 228:   {
 229:     if (issuerNames != null)
 230:       return Collections.unmodifiableList(issuerNames);
 231:     else
 232:       return null;
 233:   }
 234: 
 235:   /**
 236:    * Returns the maximum value of the CRLNumber extension present in
 237:    * CRLs matched by this selector, or <code>null</code> if this
 238:    * criteria is not set.
 239:    *
 240:    * @return The maximum CRL number.
 241:    */
 242:   public BigInteger getMaxCRL()
 243:   {
 244:     return maxCrlNumber;
 245:   }
 246: 
 247:   /**
 248:    * Returns the minimum value of the CRLNumber extension present in
 249:    * CRLs matched by this selector, or <code>null</code> if this
 250:    * criteria is not set.
 251:    *
 252:    * @return The minimum CRL number.
 253:    */
 254:   public BigInteger getMinCRL()
 255:   {
 256:     return minCrlNumber;
 257:   }
 258: 
 259:   /**
 260:    * Sets the maximum value of the CRLNumber extension present in CRLs
 261:    * matched by this selector. Specify <code>null</code> to clear this
 262:    * criterion.
 263:    *
 264:    * @param maxCrlNumber The maximum CRL number.
 265:    */
 266:   public void setMaxCRLNumber(BigInteger maxCrlNumber)
 267:   {
 268:     this.maxCrlNumber = maxCrlNumber;
 269:   }
 270: 
 271:   /**
 272:    * Sets the minimum value of the CRLNumber extension present in CRLs
 273:    * matched by this selector. Specify <code>null</code> to clear this
 274:    * criterion.
 275:    *
 276:    * @param minCrlNumber The minimum CRL number.
 277:    */
 278:   public void setMinCRLNumber(BigInteger minCrlNumber)
 279:   {
 280:     this.minCrlNumber = minCrlNumber;
 281:   }
 282: 
 283:   /**
 284:    * Returns the date when this CRL must be valid; that is, the date
 285:    * must be after the thisUpdate date, but before the nextUpdate date.
 286:    * Returns <code>null</code> if this criterion is not set.
 287:    *
 288:    * @return The date.
 289:    */
 290:   public Date getDateAndTime()
 291:   {
 292:     return date != null ? (Date) date.clone() : null;
 293:   }
 294: 
 295:   /**
 296:    * Sets the date at which this CRL must be valid. Specify
 297:    * <code>null</code> to clear this criterion.
 298:    *
 299:    * @param date The date.
 300:    */
 301:   public void setDateAndTime(Date date)
 302:   {
 303:     this.date = date != null ? (Date) date.clone() : null;
 304:   }
 305: 
 306:   /**
 307:    * Returns the certificate being checked, or <code>null</code> if this
 308:    * value is not set.
 309:    *
 310:    * @return The certificate.
 311:    */
 312:   public X509Certificate getCertificateChecking()
 313:   {
 314:     return cert;
 315:   }
 316: 
 317:   /**
 318:    * Sets the certificate being checked. This is not a criterion, but
 319:    * info used by certificate store implementations to aid in searching.
 320:    *
 321:    * @param cert The certificate.
 322:    */
 323:   public void setCertificateChecking(X509Certificate cert)
 324:   {
 325:     this.cert = cert;
 326:   }
 327: 
 328:   /**
 329:    * Returns a string representation of this selector. The string will
 330:    * only describe the enabled criteria, so if none are enabled this will
 331:    * return a string that contains little else besides the class name.
 332:    *
 333:    * @return The string.
 334:    */
 335:   public String toString()
 336:   {
 337:     StringBuffer str = new StringBuffer(X509CRLSelector.class.getName());
 338:     String nl = SystemProperties.getProperty("line.separator");
 339:     String eol = ";" + nl;
 340: 
 341:     str.append(" {").append(nl);
 342:     if (issuerNames != null)
 343:       str.append("  issuer names = ").append(issuerNames).append(eol);
 344:     if (maxCrlNumber != null)
 345:       str.append("  max CRL = ").append(maxCrlNumber).append(eol);
 346:     if (minCrlNumber != null)
 347:       str.append("  min CRL = ").append(minCrlNumber).append(eol);
 348:     if (date != null)
 349:       str.append("  date = ").append(date).append(eol);
 350:     if (cert != null)
 351:       str.append("  certificate = ").append(cert).append(eol);
 352:     str.append("}").append(nl);
 353:     return str.toString();
 354:   }
 355: 
 356:   /**
 357:    * Checks a CRL against the criteria of this selector, returning
 358:    * <code>true</code> if the given CRL matches all the criteria.
 359:    *
 360:    * @param _crl The CRL being checked.
 361:    * @return True if the CRL matches, false otherwise.
 362:    */
 363:   public boolean match(CRL _crl)
 364:   {
 365:     if (!(_crl instanceof X509CRL))
 366:       return false;
 367:     X509CRL crl = (X509CRL) _crl;
 368:     if (issuerNames != null)
 369:       {
 370:         if (!issuerNames.contains(crl.getIssuerX500Principal()))
 371:           return false;
 372:       }
 373:     BigInteger crlNumber = null;
 374:     if (maxCrlNumber != null)
 375:       {
 376:         byte[] b = crl.getExtensionValue(CRL_NUMBER_ID);
 377:         if (b == null)
 378:           return false;
 379:         try
 380:           {
 381:             DERValue val = DERReader.read(b);
 382:             if (!(val.getValue() instanceof BigInteger))
 383:               return false;
 384:             crlNumber = (BigInteger) val.getValue();
 385:           }
 386:         catch (IOException ioe)
 387:           {
 388:             return false;
 389:           }
 390:         if (maxCrlNumber.compareTo(crlNumber) < 0)
 391:           return false;
 392:       }
 393:     if (minCrlNumber != null)
 394:       {
 395:         if (crlNumber == null)
 396:           {
 397:             byte[] b = crl.getExtensionValue(CRL_NUMBER_ID);
 398:             if (b == null)
 399:               return false;
 400:             try
 401:               {
 402:                 DERValue val = DERReader.read(b);
 403:                 if (!(val.getValue() instanceof BigInteger))
 404:                   return false;
 405:                 crlNumber = (BigInteger) val.getValue();
 406:               }
 407:             catch (IOException ioe)
 408:               {
 409:                 return false;
 410:               }
 411:           }
 412:         if (minCrlNumber.compareTo(crlNumber) > 0)
 413:           return false;
 414:       }
 415:     if (date != null)
 416:       {
 417:         if (date.compareTo(crl.getThisUpdate()) < 0 ||
 418:             date.compareTo(crl.getNextUpdate()) > 0)
 419:           return false;
 420:       }
 421:     return true;
 422:   }
 423: 
 424:   /**
 425:    * Returns a copy of this object.
 426:    *
 427:    * @return The copy.
 428:    */
 429:   public Object clone()
 430:   {
 431:     try
 432:       {
 433:         return super.clone();
 434:       }
 435:     catch (CloneNotSupportedException shouldNotHappen)
 436:       {
 437:         throw new Error(shouldNotHappen);
 438:       }
 439:   }
 440: }