| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| |
| package java.security.cert; |
| |
| import java.io.IOException; |
| import java.math.BigInteger; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Date; |
| import javax.security.auth.x500.X500Principal; |
| import org.apache.harmony.security.asn1.ASN1Integer; |
| import org.apache.harmony.security.asn1.ASN1OctetString; |
| import org.apache.harmony.security.x501.Name; |
| |
| /** |
| * A CRL selector ({@code CRLSelector} for selecting {@code |
| * X509CRL}s that match the specified criteria. |
| * <p> |
| * When constructed, all criteria are set to default values that will match any |
| * {@code X509CRL}. |
| */ |
| public class X509CRLSelector implements CRLSelector { |
| |
| // issuerNames criterion: |
| // contains X.500 distinguished names in CANONICAL format |
| private ArrayList<String> issuerNames; |
| // contains X500Principal objects corresponding to the names |
| // from issuerNames collection (above) |
| private ArrayList<X500Principal> issuerPrincipals; |
| // minCRLNumber criterion |
| private BigInteger minCRL; |
| // maxCRLNumber criterion |
| private BigInteger maxCRL; |
| // dateAndTime criterion |
| private long dateAndTime = -1; |
| // the certificate being checked |
| private X509Certificate certificateChecking; |
| |
| /** |
| * Creates a new {@code X509CertSelector}. |
| */ |
| public X509CRLSelector() { } |
| |
| /** |
| * Sets the criterion for the issuer distinguished names. |
| * <p> |
| * The CRL issuer must match at least one of the specified distinguished |
| * names. |
| * |
| * @param issuers |
| * the list of issuer distinguished names to match, or {@code |
| * null} if any issuer distinguished name will do. |
| */ |
| public void setIssuers(Collection<X500Principal> issuers) { |
| if (issuers == null) { |
| issuerNames = null; |
| issuerPrincipals = null; |
| return; |
| } |
| issuerNames = new ArrayList<String>(issuers.size()); |
| issuerPrincipals = new ArrayList<X500Principal>(issuers); |
| for (X500Principal issuer: issuers) { |
| issuerNames.add(issuer.getName(X500Principal.CANONICAL)); |
| } |
| } |
| |
| /** |
| * <b>Do not use:</b> use {@link #setIssuers(Collection)} or one of |
| * {@link #addIssuerName} instead. Sets the criterion for the issuer |
| * distinguished names. |
| * <p> |
| * The CRL issuer must match at least one of the specified distinguished |
| * names. |
| * <p> |
| * The specified parameter {@code names} is a collection with an entry for |
| * each name to be included in the criterion. The name is specified as a |
| * {@code String} or a byte array specifying the name (in RFC 2253 or ASN.1 |
| * DER encoded form) |
| * |
| * @param names |
| * the list of issuer distinguished names to match, or {@code |
| * null} if any issuer distinguished name will do. |
| * @throws IOException |
| * if parsing fails. |
| */ |
| public void setIssuerNames(Collection<?> names) throws IOException { |
| if (names == null) { |
| issuerNames = null; |
| issuerPrincipals = null; |
| return; |
| } |
| if (names.size() == 0) { |
| return; |
| } |
| issuerNames = new ArrayList<String>(names.size()); |
| for (Object name: names) { |
| if (name instanceof String) { |
| issuerNames.add( |
| new Name((String) name).getName( |
| X500Principal.CANONICAL)); |
| } else if (name instanceof byte[]) { |
| issuerNames.add( |
| new Name((byte[]) name).getName( |
| X500Principal.CANONICAL)); |
| } else { |
| throw new IOException("name neither a String nor a byte[]"); |
| } |
| } |
| } |
| |
| /** |
| * Adds an issuer to the criterion for the issuer distinguished names. |
| * <p> |
| * The CRL issuer must match at least one of the specified distinguished |
| * names. |
| * |
| * @param issuer |
| * the issuer to add to the criterion |
| */ |
| public void addIssuer(X500Principal issuer) { |
| if (issuer == null) { |
| throw new NullPointerException("issuer == null"); |
| } |
| if (issuerNames == null) { |
| issuerNames = new ArrayList<String>(); |
| } |
| String name = issuer.getName(X500Principal.CANONICAL); |
| if (!issuerNames.contains(name)) { |
| issuerNames.add(name); |
| } |
| if (issuerPrincipals == null) { |
| issuerPrincipals = new ArrayList<X500Principal>(issuerNames.size()); |
| } |
| // extend the list of issuer Principals |
| int size = issuerNames.size() - 1; |
| for (int i=issuerPrincipals.size(); i<size; i++) { |
| issuerPrincipals.add(new X500Principal(issuerNames.get(i))); |
| } |
| issuerPrincipals.add(issuer); |
| } |
| |
| /** |
| * <b>Do not use:</b>, use {@link #addIssuer(X500Principal)} or |
| * {@link #addIssuerName(byte[])} instead. It can fail to match some CRLs |
| * because of a loss of encoding information in a RFC 2253 string. |
| * <p> |
| * Adds an issuer to the criterion for the issuer distinguished names. The |
| * CRK issuer must match at least one of the specified distinguished names. |
| * |
| * @param iss_name |
| * the RFC 2253 encoded name. |
| * @throws IOException |
| * if parsing fails. |
| */ |
| public void addIssuerName(String iss_name) throws IOException { |
| if (issuerNames == null) { |
| issuerNames = new ArrayList<String>(); |
| } |
| |
| if (iss_name == null) { |
| iss_name = ""; |
| } |
| |
| String name = new Name(iss_name).getName(X500Principal.CANONICAL); |
| if (!issuerNames.contains(name)) { |
| issuerNames.add(name); |
| } |
| } |
| |
| /** |
| * Adds an issuer to the criterion for the issuer distinguished names. |
| * <p> |
| * The CRL issuer must match at least one of the specified distinguished |
| * names. |
| * |
| * @param iss_name |
| * the issuer to add to the criterion in ASN.1 DER encoded form. |
| * @throws IOException |
| * if parsing fails. |
| */ |
| public void addIssuerName(byte[] iss_name) throws IOException { |
| if (iss_name == null) { |
| throw new NullPointerException("iss_name == null"); |
| } |
| if (issuerNames == null) { |
| issuerNames = new ArrayList<String>(); |
| } |
| String name = new Name(iss_name).getName(X500Principal.CANONICAL); |
| if (!issuerNames.contains(name)) { |
| issuerNames.add(name); |
| } |
| } |
| |
| /** |
| * Sets the criterion for the minimum CRL number. |
| * <p> |
| * The CRL must have a number extension with a value greater than or equal |
| * to the specified parameter. |
| * |
| * @param minCRL |
| * the minimum CRL number or null to not check the minimum CRL |
| * number |
| */ |
| public void setMinCRLNumber(BigInteger minCRL) { |
| this.minCRL = minCRL; |
| } |
| |
| /** |
| * Sets the criterion for the maximum CRL number. |
| * <p> |
| * The CRL must have a number extension with a value less than or equal to |
| * the specified parameter. |
| * |
| * @param maxCRL |
| * the maximum CRL number or null to not check the maximum CRL |
| * number. |
| */ |
| public void setMaxCRLNumber(BigInteger maxCRL) { |
| this.maxCRL = maxCRL; |
| } |
| |
| /** |
| * Sets the criterion for the CRL update period. |
| * <p> |
| * The CRL's {@code thisUpdate} value must be equal or before the specified |
| * date and the {@code nextUpdate} value must be after the specified date. |
| * |
| * @param dateAndTime |
| * the date to search for valid CRL's or {@code null} to not |
| * check the date. |
| */ |
| public void setDateAndTime(Date dateAndTime) { |
| if (dateAndTime == null) { |
| this.dateAndTime = -1; |
| return; |
| } |
| this.dateAndTime = dateAndTime.getTime(); |
| } |
| |
| /** |
| * Sets a certificate hint to find CRLs. It's not a criterion but may help |
| * finding relevant CRLs. |
| * |
| * @param cert |
| * the certificate hint or {@code null}. |
| */ |
| public void setCertificateChecking(X509Certificate cert) { |
| this.certificateChecking = cert; |
| } |
| |
| /** |
| * Returns the criterion for the issuer distinguished names. |
| * <p> |
| * The CRL issuer must match at least one of the distinguished names. |
| * |
| * @return the unmodifiable list of issuer distinguished names to match, or |
| * {@code null} if any issuer distinguished name will do. |
| */ |
| public Collection<X500Principal> getIssuers() { |
| if (issuerNames == null) { |
| return null; |
| } |
| if (issuerPrincipals == null) { |
| issuerPrincipals = new ArrayList<X500Principal>(issuerNames.size()); |
| } |
| int size = issuerNames.size(); |
| // extend the list of issuer Principals |
| for (int i=issuerPrincipals.size(); i<size; i++) { |
| issuerPrincipals.add(new X500Principal(issuerNames.get(i))); |
| } |
| return Collections.unmodifiableCollection(issuerPrincipals); |
| } |
| |
| /** |
| * Returns the criterion for the issuer distinguished names. |
| * <p> |
| * The CRL issuer must match at least one of the distinguished names. |
| * |
| * @return a copy of the list of issuer distinguished names to match, or |
| * {@code null} if any issuer distinguished name will do. |
| */ |
| public Collection<Object> getIssuerNames() { |
| if (issuerNames == null) { |
| return null; |
| } |
| return Collections.unmodifiableCollection((ArrayList<?>) issuerNames); |
| } |
| |
| /** |
| * Returns the criterion for the minimum CRL number. |
| * <p> |
| * The CRL must have a number extension with a value greater than or equal |
| * to the returned value. |
| * |
| * @return the minimum CRL number or {@code null} if the minimum CRL number |
| * is not to be checked. |
| */ |
| public BigInteger getMinCRL() { |
| return minCRL; |
| } |
| |
| /** |
| * Returns the criterion for the maximum CRL number. |
| * <p> |
| * The CRL must have a number extension with a value less than or equal to |
| * the returned value. |
| * |
| * @return the maximum CRL number or null if the maximum CRL number is not |
| * checked. |
| */ |
| public BigInteger getMaxCRL() { |
| return maxCRL; |
| } |
| |
| /** |
| * Returns the criterion for the CRL update period. |
| * <p> |
| * The CRL's {@code thisUpdate} value must be equal or before the returned |
| * date and the {@code nextUpdate} value must be after the returned date. |
| * |
| * @return the date to search for valid CRL's or {@code null} if the date is |
| * not checked. |
| */ |
| public Date getDateAndTime() { |
| if (dateAndTime == -1) { |
| return null; |
| } |
| return new Date(dateAndTime); |
| } |
| |
| /** |
| * Returns the certificate hint to find CRLs. It's not a criterion but may |
| * help finding relevant CRLs. |
| * |
| * @return the certificate hint or {@code null} if none set. |
| */ |
| public X509Certificate getCertificateChecking() { |
| return certificateChecking; |
| } |
| |
| /** |
| * Returns a string representation of this {@code X509CRLSelector} instance. |
| * |
| * @return a string representation of this {@code X509CRLSelector} instance. |
| */ |
| public String toString() { |
| StringBuilder result = new StringBuilder(); |
| result.append("X509CRLSelector:\n["); |
| if (issuerNames != null) { |
| result.append("\n IssuerNames:\n ["); |
| int size = issuerNames.size(); |
| for (int i=0; i<size; i++) { |
| result.append("\n " |
| + issuerNames.get(i)); |
| } |
| result.append("\n ]"); |
| } |
| if (minCRL != null) { |
| result.append("\n minCRL: " + minCRL); |
| } |
| if (maxCRL != null) { |
| result.append("\n maxCRL: " + maxCRL); |
| } |
| if (dateAndTime != -1) { |
| result.append("\n dateAndTime: " + (new Date(dateAndTime))); |
| } |
| if (certificateChecking != null) { |
| result.append("\n certificateChecking: " + certificateChecking); |
| } |
| result.append("\n]"); |
| return result.toString(); |
| } |
| |
| /** |
| * Returns whether the specified CRL matches all the criteria collected in |
| * this instance. |
| * |
| * @param crl |
| * the CRL to check. |
| * @return {@code true} if the CRL matches all the criteria, otherwise |
| * {@code false}. |
| */ |
| public boolean match(CRL crl) { |
| if (!(crl instanceof X509CRL)) { |
| return false; |
| } |
| X509CRL crlist = (X509CRL) crl; |
| if ((issuerNames != null) && |
| // the search speed depends on the class of issuerNames |
| !(issuerNames.contains( |
| crlist.getIssuerX500Principal().getName( |
| X500Principal.CANONICAL)))) { |
| return false; |
| } |
| if ((minCRL != null) || (maxCRL != null)) { |
| try { |
| // As specified in rfc 3280 (http://www.ietf.org/rfc/rfc3280.txt) |
| // CRL Number Extension's OID is 2.5.29.20 . |
| byte[] bytes = crlist.getExtensionValue("2.5.29.20"); |
| bytes = (byte[]) ASN1OctetString.getInstance().decode(bytes); |
| BigInteger crlNumber = new BigInteger((byte[]) |
| ASN1Integer.getInstance().decode(bytes)); |
| if ((minCRL != null) && (crlNumber.compareTo(minCRL) < 0)) { |
| return false; |
| } |
| if ((maxCRL != null) && (crlNumber.compareTo(maxCRL) > 0)) { |
| return false; |
| } |
| } catch (IOException e) { |
| return false; |
| } |
| } |
| if (dateAndTime != -1) { |
| Date thisUp = crlist.getThisUpdate(); |
| Date nextUp = crlist.getNextUpdate(); |
| if ((thisUp == null) || (nextUp == null)) { |
| return false; |
| } |
| if ((dateAndTime < thisUp.getTime()) |
| || (dateAndTime > nextUp.getTime())) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Clones this {@code X509CRL} instance. |
| * |
| * @return the cloned instance. |
| */ |
| public Object clone() { |
| X509CRLSelector result; |
| |
| try { |
| result = (X509CRLSelector) super.clone(); |
| if (issuerNames != null) { |
| result.issuerNames = new ArrayList<String>(issuerNames); |
| } |
| } catch (CloneNotSupportedException e) { |
| result = null; |
| } |
| return result; |
| } |
| } |