1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 19 package java.security.cert; 20 21 import java.io.IOException; 22 import java.math.BigInteger; 23 import java.util.ArrayList; 24 import java.util.Collection; 25 import java.util.Collections; 26 import java.util.Date; 27 import javax.security.auth.x500.X500Principal; 28 import org.apache.harmony.security.asn1.ASN1Integer; 29 import org.apache.harmony.security.asn1.ASN1OctetString; 30 import org.apache.harmony.security.x501.Name; 31 32 /** 33 * A CRL selector ({@code CRLSelector} for selecting {@code 34 * X509CRL}s that match the specified criteria. 35 * <p> 36 * When constructed, all criteria are set to default values that will match any 37 * {@code X509CRL}. 38 */ 39 public class X509CRLSelector implements CRLSelector { 40 41 // issuerNames criterion: 42 // contains X.500 distinguished names in CANONICAL format 43 private ArrayList<String> issuerNames; 44 // contains X500Principal objects corresponding to the names 45 // from issuerNames collection (above) 46 private ArrayList<X500Principal> issuerPrincipals; 47 // minCRLNumber criterion 48 private BigInteger minCRL; 49 // maxCRLNumber criterion 50 private BigInteger maxCRL; 51 // dateAndTime criterion 52 private long dateAndTime = -1; 53 // the certificate being checked 54 private X509Certificate certificateChecking; 55 56 /** 57 * Creates a new {@code X509CertSelector}. 58 */ 59 public X509CRLSelector() { } 60 61 /** 62 * Sets the criterion for the issuer distinguished names. 63 * <p> 64 * The CRL issuer must match at least one of the specified distinguished 65 * names. 66 * 67 * @param issuers 68 * the list of issuer distinguished names to match, or {@code 69 * null} if any issuer distinguished name will do. 70 */ 71 public void setIssuers(Collection<X500Principal> issuers) { 72 if (issuers == null) { 73 issuerNames = null; 74 issuerPrincipals = null; 75 return; 76 } 77 issuerNames = new ArrayList<String>(issuers.size()); 78 issuerPrincipals = new ArrayList<X500Principal>(issuers); 79 for (X500Principal issuer: issuers) { 80 issuerNames.add(issuer.getName(X500Principal.CANONICAL)); 81 } 82 } 83 84 /** 85 * <b>Do not use:</b> use {@link #setIssuers(Collection)} or one of 86 * {@link #addIssuerName} instead. Sets the criterion for the issuer 87 * distinguished names. 88 * <p> 89 * The CRL issuer must match at least one of the specified distinguished 90 * names. 91 * <p> 92 * The specified parameter {@code names} is a collection with an entry for 93 * each name to be included in the criterion. The name is specified as a 94 * {@code String} or a byte array specifying the name (in RFC 2253 or ASN.1 95 * DER encoded form) 96 * 97 * @param names 98 * the list of issuer distinguished names to match, or {@code 99 * null} if any issuer distinguished name will do. 100 * @throws IOException 101 * if parsing fails. 102 */ 103 public void setIssuerNames(Collection<?> names) throws IOException { 104 if (names == null) { 105 issuerNames = null; 106 issuerPrincipals = null; 107 return; 108 } 109 if (names.size() == 0) { 110 return; 111 } 112 issuerNames = new ArrayList<String>(names.size()); 113 for (Object name: names) { 114 if (name instanceof String) { 115 issuerNames.add( 116 new Name((String) name).getName( 117 X500Principal.CANONICAL)); 118 } else if (name instanceof byte[]) { 119 issuerNames.add( 120 new Name((byte[]) name).getName( 121 X500Principal.CANONICAL)); 122 } else { 123 throw new IOException("name neither a String nor a byte[]"); 124 } 125 } 126 } 127 128 /** 129 * Adds an issuer to the criterion for the issuer distinguished names. 130 * <p> 131 * The CRL issuer must match at least one of the specified distinguished 132 * names. 133 * 134 * @param issuer 135 * the issuer to add to the criterion 136 */ 137 public void addIssuer(X500Principal issuer) { 138 if (issuer == null) { 139 throw new NullPointerException("issuer == null"); 140 } 141 if (issuerNames == null) { 142 issuerNames = new ArrayList<String>(); 143 } 144 String name = issuer.getName(X500Principal.CANONICAL); 145 if (!issuerNames.contains(name)) { 146 issuerNames.add(name); 147 } 148 if (issuerPrincipals == null) { 149 issuerPrincipals = new ArrayList<X500Principal>(issuerNames.size()); 150 } 151 // extend the list of issuer Principals 152 int size = issuerNames.size() - 1; 153 for (int i=issuerPrincipals.size(); i<size; i++) { 154 issuerPrincipals.add(new X500Principal(issuerNames.get(i))); 155 } 156 issuerPrincipals.add(issuer); 157 } 158 159 /** 160 * <b>Do not use:</b>, use {@link #addIssuer(X500Principal)} or 161 * {@link #addIssuerName(byte[])} instead. It can fail to match some CRLs 162 * because of a loss of encoding information in a RFC 2253 string. 163 * <p> 164 * Adds an issuer to the criterion for the issuer distinguished names. The 165 * CRK issuer must match at least one of the specified distinguished names. 166 * 167 * @param iss_name 168 * the RFC 2253 encoded name. 169 * @throws IOException 170 * if parsing fails. 171 */ 172 public void addIssuerName(String iss_name) throws IOException { 173 if (issuerNames == null) { 174 issuerNames = new ArrayList<String>(); 175 } 176 177 if (iss_name == null) { 178 iss_name = ""; 179 } 180 181 String name = new Name(iss_name).getName(X500Principal.CANONICAL); 182 if (!issuerNames.contains(name)) { 183 issuerNames.add(name); 184 } 185 } 186 187 /** 188 * Adds an issuer to the criterion for the issuer distinguished names. 189 * <p> 190 * The CRL issuer must match at least one of the specified distinguished 191 * names. 192 * 193 * @param iss_name 194 * the issuer to add to the criterion in ASN.1 DER encoded form. 195 * @throws IOException 196 * if parsing fails. 197 */ 198 public void addIssuerName(byte[] iss_name) throws IOException { 199 if (iss_name == null) { 200 throw new NullPointerException("iss_name == null"); 201 } 202 if (issuerNames == null) { 203 issuerNames = new ArrayList<String>(); 204 } 205 String name = new Name(iss_name).getName(X500Principal.CANONICAL); 206 if (!issuerNames.contains(name)) { 207 issuerNames.add(name); 208 } 209 } 210 211 /** 212 * Sets the criterion for the minimum CRL number. 213 * <p> 214 * The CRL must have a number extension with a value greater than or equal 215 * to the specified parameter. 216 * 217 * @param minCRL 218 * the minimum CRL number or null to not check the minimum CRL 219 * number 220 */ 221 public void setMinCRLNumber(BigInteger minCRL) { 222 this.minCRL = minCRL; 223 } 224 225 /** 226 * Sets the criterion for the maximum CRL number. 227 * <p> 228 * The CRL must have a number extension with a value less than or equal to 229 * the specified parameter. 230 * 231 * @param maxCRL 232 * the maximum CRL number or null to not check the maximum CRL 233 * number. 234 */ 235 public void setMaxCRLNumber(BigInteger maxCRL) { 236 this.maxCRL = maxCRL; 237 } 238 239 /** 240 * Sets the criterion for the CRL update period. 241 * <p> 242 * The CRL's {@code thisUpdate} value must be equal or before the specified 243 * date and the {@code nextUpdate} value must be after the specified date. 244 * 245 * @param dateAndTime 246 * the date to search for valid CRL's or {@code null} to not 247 * check the date. 248 */ 249 public void setDateAndTime(Date dateAndTime) { 250 if (dateAndTime == null) { 251 this.dateAndTime = -1; 252 return; 253 } 254 this.dateAndTime = dateAndTime.getTime(); 255 } 256 257 /** 258 * Sets a certificate hint to find CRLs. It's not a criterion but may help 259 * finding relevant CRLs. 260 * 261 * @param cert 262 * the certificate hint or {@code null}. 263 */ 264 public void setCertificateChecking(X509Certificate cert) { 265 this.certificateChecking = cert; 266 } 267 268 /** 269 * Returns the criterion for the issuer distinguished names. 270 * <p> 271 * The CRL issuer must match at least one of the distinguished names. 272 * 273 * @return the unmodifiable list of issuer distinguished names to match, or 274 * {@code null} if any issuer distinguished name will do. 275 */ 276 public Collection<X500Principal> getIssuers() { 277 if (issuerNames == null) { 278 return null; 279 } 280 if (issuerPrincipals == null) { 281 issuerPrincipals = new ArrayList<X500Principal>(issuerNames.size()); 282 } 283 int size = issuerNames.size(); 284 // extend the list of issuer Principals 285 for (int i=issuerPrincipals.size(); i<size; i++) { 286 issuerPrincipals.add(new X500Principal(issuerNames.get(i))); 287 } 288 return Collections.unmodifiableCollection(issuerPrincipals); 289 } 290 291 /** 292 * Returns the criterion for the issuer distinguished names. 293 * <p> 294 * The CRL issuer must match at least one of the distinguished names. 295 * 296 * @return a copy of the list of issuer distinguished names to 297 * match, or {@code null} if any issuer distinguished name 298 * will do. The elements may be strings or ASN.1 DER 299 * encoded byte arrays. 300 */ 301 public Collection<Object> getIssuerNames() { 302 if (issuerNames == null) { 303 return null; 304 } 305 return (Collection<Object>) issuerNames.clone(); 306 } 307 308 /** 309 * Returns the criterion for the minimum CRL number. 310 * <p> 311 * The CRL must have a number extension with a value greater than or equal 312 * to the returned value. 313 * 314 * @return the minimum CRL number or {@code null} if the minimum CRL number 315 * is not to be checked. 316 */ 317 public BigInteger getMinCRL() { 318 return minCRL; 319 } 320 321 /** 322 * Returns the criterion for the maximum CRL number. 323 * <p> 324 * The CRL must have a number extension with a value less than or equal to 325 * the returned value. 326 * 327 * @return the maximum CRL number or null if the maximum CRL number is not 328 * checked. 329 */ 330 public BigInteger getMaxCRL() { 331 return maxCRL; 332 } 333 334 /** 335 * Returns the criterion for the CRL update period. 336 * <p> 337 * The CRL's {@code thisUpdate} value must be equal or before the returned 338 * date and the {@code nextUpdate} value must be after the returned date. 339 * 340 * @return the date to search for valid CRL's or {@code null} if the date is 341 * not checked. 342 */ 343 public Date getDateAndTime() { 344 if (dateAndTime == -1) { 345 return null; 346 } 347 return new Date(dateAndTime); 348 } 349 350 /** 351 * Returns the certificate hint to find CRLs. It's not a criterion but may 352 * help finding relevant CRLs. 353 * 354 * @return the certificate hint or {@code null} if none set. 355 */ 356 public X509Certificate getCertificateChecking() { 357 return certificateChecking; 358 } 359 360 /** 361 * Returns a string representation of this {@code X509CRLSelector} instance. 362 * 363 * @return a string representation of this {@code X509CRLSelector} instance. 364 */ 365 public String toString() { 366 StringBuilder result = new StringBuilder(); 367 result.append("X509CRLSelector:\n["); 368 if (issuerNames != null) { 369 result.append("\n IssuerNames:\n ["); 370 int size = issuerNames.size(); 371 for (int i=0; i<size; i++) { 372 result.append("\n " 373 + issuerNames.get(i)); 374 } 375 result.append("\n ]"); 376 } 377 if (minCRL != null) { 378 result.append("\n minCRL: " + minCRL); 379 } 380 if (maxCRL != null) { 381 result.append("\n maxCRL: " + maxCRL); 382 } 383 if (dateAndTime != -1) { 384 result.append("\n dateAndTime: " + (new Date(dateAndTime))); 385 } 386 if (certificateChecking != null) { 387 result.append("\n certificateChecking: " + certificateChecking); 388 } 389 result.append("\n]"); 390 return result.toString(); 391 } 392 393 /** 394 * Returns whether the specified CRL matches all the criteria collected in 395 * this instance. 396 * 397 * @param crl 398 * the CRL to check. 399 * @return {@code true} if the CRL matches all the criteria, otherwise 400 * {@code false}. 401 */ 402 public boolean match(CRL crl) { 403 if (!(crl instanceof X509CRL)) { 404 return false; 405 } 406 X509CRL crlist = (X509CRL) crl; 407 if ((issuerNames != null) && 408 // the search speed depends on the class of issuerNames 409 !(issuerNames.contains( 410 crlist.getIssuerX500Principal().getName( 411 X500Principal.CANONICAL)))) { 412 return false; 413 } 414 if ((minCRL != null) || (maxCRL != null)) { 415 try { 416 // As specified in rfc 3280 (http://www.ietf.org/rfc/rfc3280.txt) 417 // CRL Number Extension's OID is 2.5.29.20 . 418 byte[] bytes = crlist.getExtensionValue("2.5.29.20"); 419 bytes = (byte[]) ASN1OctetString.getInstance().decode(bytes); 420 BigInteger crlNumber = new BigInteger((byte[]) 421 ASN1Integer.getInstance().decode(bytes)); 422 if ((minCRL != null) && (crlNumber.compareTo(minCRL) < 0)) { 423 return false; 424 } 425 if ((maxCRL != null) && (crlNumber.compareTo(maxCRL) > 0)) { 426 return false; 427 } 428 } catch (IOException e) { 429 return false; 430 } 431 } 432 if (dateAndTime != -1) { 433 Date thisUp = crlist.getThisUpdate(); 434 Date nextUp = crlist.getNextUpdate(); 435 if ((thisUp == null) || (nextUp == null)) { 436 return false; 437 } 438 if ((dateAndTime < thisUp.getTime()) 439 || (dateAndTime > nextUp.getTime())) { 440 return false; 441 } 442 } 443 return true; 444 } 445 446 /** 447 * Clones this {@code X509CRL} instance. 448 * 449 * @return the cloned instance. 450 */ 451 public Object clone() { 452 X509CRLSelector result; 453 454 try { 455 result = (X509CRLSelector) super.clone(); 456 if (issuerNames != null) { 457 result.issuerNames = new ArrayList<String>(issuerNames); 458 } 459 } catch (CloneNotSupportedException e) { 460 result = null; 461 } 462 return result; 463 } 464 } 465