001/* X509CRLSelector.java -- selects X.509 CRLs by criteria. 002 Copyright (C) 2004 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package java.security.cert; 040 041import gnu.classpath.SystemProperties; 042import gnu.java.lang.CPStringBuilder; 043import gnu.java.security.der.DERReader; 044import gnu.java.security.der.DERValue; 045 046import java.io.IOException; 047import java.io.InputStream; 048import java.math.BigInteger; 049import java.util.ArrayList; 050import java.util.Collection; 051import java.util.Collections; 052import java.util.Date; 053import java.util.Iterator; 054import java.util.LinkedList; 055import java.util.List; 056 057import 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 */ 075public 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}