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.security.der.DERReader; 043 import gnu.java.security.der.DERValue; 044 045 import java.io.IOException; 046 import java.io.InputStream; 047 import java.math.BigInteger; 048 import java.util.ArrayList; 049 import java.util.Collection; 050 import java.util.Collections; 051 import java.util.Date; 052 import java.util.Iterator; 053 import java.util.LinkedList; 054 import java.util.List; 055 056 import javax.security.auth.x500.X500Principal; 057 058 /** 059 * A class for matching X.509 certificate revocation lists by criteria. 060 * 061 * <p>Use of this class requires extensive knowledge of the Internet 062 * Engineering Task Force's Public Key Infrastructure (X.509). The primary 063 * document describing this standard is <a 064 * href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509 065 * Public Key Infrastructure Certificate and Certificate Revocation List 066 * (CRL) Profile</a>. 067 * 068 * <p>Note that this class is not thread-safe. If multiple threads will 069 * use or modify this class then they need to synchronize on the object. 070 * 071 * @author Casey Marshall (csm@gnu.org) 072 * @since 1.4 073 */ 074 public class X509CRLSelector implements CRLSelector, Cloneable 075 { 076 077 // Fields. 078 // ------------------------------------------------------------------------- 079 080 private static final String CRL_NUMBER_ID = "2.5.29.20"; 081 082 private List issuerNames; 083 private BigInteger maxCrlNumber; 084 private BigInteger minCrlNumber; 085 private Date date; 086 private X509Certificate cert; 087 088 // Constructor. 089 // ------------------------------------------------------------------------- 090 091 /** 092 * Creates a new CRL selector with no criteria enabled; i.e., every CRL 093 * will be matched. 094 */ 095 public X509CRLSelector() 096 { 097 } 098 099 // 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 }