Home | History | Annotate | Download | only in cert
      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