1/*
2 * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.security.cert;
27
28import java.io.IOException;
29import java.math.BigInteger;
30import java.util.*;
31
32import javax.security.auth.x500.X500Principal;
33
34import sun.security.util.Debug;
35import sun.security.util.DerInputStream;
36import sun.security.x509.CRLNumberExtension;
37import sun.security.x509.X500Name;
38
39/**
40 * A {@code CRLSelector} that selects {@code X509CRLs} that
41 * match all specified criteria. This class is particularly useful when
42 * selecting CRLs from a {@code CertStore} to check revocation status
43 * of a particular certificate.
44 * <p>
45 * When first constructed, an {@code X509CRLSelector} has no criteria
46 * enabled and each of the {@code get} methods return a default
47 * value ({@code null}). Therefore, the {@link #match match} method
48 * would return {@code true} for any {@code X509CRL}. Typically,
49 * several criteria are enabled (by calling {@link #setIssuers setIssuers}
50 * or {@link #setDateAndTime setDateAndTime}, for instance) and then the
51 * {@code X509CRLSelector} is passed to
52 * {@link CertStore#getCRLs CertStore.getCRLs} or some similar
53 * method.
54 * <p>
55 * Please refer to <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280:
56 * Internet X.509 Public Key Infrastructure Certificate and CRL Profile</a>
57 * for definitions of the X.509 CRL fields and extensions mentioned below.
58 * <p>
59 * <b>Concurrent Access</b>
60 * <p>
61 * Unless otherwise specified, the methods defined in this class are not
62 * thread-safe. Multiple threads that need to access a single
63 * object concurrently should synchronize amongst themselves and
64 * provide the necessary locking. Multiple threads each manipulating
65 * separate objects need not synchronize.
66 *
67 * @see CRLSelector
68 * @see X509CRL
69 *
70 * @since       1.4
71 * @author      Steve Hanna
72 */
73public class X509CRLSelector implements CRLSelector {
74
75    static {
76        CertPathHelperImpl.initialize();
77    }
78
79    private static final Debug debug = Debug.getInstance("certpath");
80    private HashSet<Object> issuerNames;
81    private HashSet<X500Principal> issuerX500Principals;
82    private BigInteger minCRL;
83    private BigInteger maxCRL;
84    private Date dateAndTime;
85    private X509Certificate certChecking;
86    private long skew = 0;
87
88    /**
89     * Creates an {@code X509CRLSelector}. Initially, no criteria are set
90     * so any {@code X509CRL} will match.
91     */
92    public X509CRLSelector() {}
93
94    /**
95     * Sets the issuerNames criterion. The issuer distinguished name in the
96     * {@code X509CRL} must match at least one of the specified
97     * distinguished names. If {@code null}, any issuer distinguished name
98     * will do.
99     * <p>
100     * This method allows the caller to specify, with a single method call,
101     * the complete set of issuer names which {@code X509CRLs} may contain.
102     * The specified value replaces the previous value for the issuerNames
103     * criterion.
104     * <p>
105     * The {@code names} parameter (if not {@code null}) is a
106     * {@code Collection} of {@code X500Principal}s.
107     * <p>
108     * Note that the {@code names} parameter can contain duplicate
109     * distinguished names, but they may be removed from the
110     * {@code Collection} of names returned by the
111     * {@link #getIssuers getIssuers} method.
112     * <p>
113     * Note that a copy is performed on the {@code Collection} to
114     * protect against subsequent modifications.
115     *
116     * @param issuers a {@code Collection} of X500Principals
117     *   (or {@code null})
118     * @see #getIssuers
119     * @since 1.5
120     */
121    public void setIssuers(Collection<X500Principal> issuers) {
122        if ((issuers == null) || issuers.isEmpty()) {
123            issuerNames = null;
124            issuerX500Principals = null;
125        } else {
126            // clone
127            issuerX500Principals = new HashSet<X500Principal>(issuers);
128            issuerNames = new HashSet<Object>();
129            for (X500Principal p : issuerX500Principals) {
130                issuerNames.add(p.getEncoded());
131            }
132        }
133    }
134
135    /**
136     * <strong>Note:</strong> use {@linkplain #setIssuers(Collection)} instead
137     * or only specify the byte array form of distinguished names when using
138     * this method. See {@link #addIssuerName(String)} for more information.
139     * <p>
140     * Sets the issuerNames criterion. The issuer distinguished name in the
141     * {@code X509CRL} must match at least one of the specified
142     * distinguished names. If {@code null}, any issuer distinguished name
143     * will do.
144     * <p>
145     * This method allows the caller to specify, with a single method call,
146     * the complete set of issuer names which {@code X509CRLs} may contain.
147     * The specified value replaces the previous value for the issuerNames
148     * criterion.
149     * <p>
150     * The {@code names} parameter (if not {@code null}) is a
151     * {@code Collection} of names. Each name is a {@code String}
152     * or a byte array representing a distinguished name (in
153     * <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a> or
154     * ASN.1 DER encoded form, respectively). If {@code null} is supplied
155     * as the value for this argument, no issuerNames check will be performed.
156     * <p>
157     * Note that the {@code names} parameter can contain duplicate
158     * distinguished names, but they may be removed from the
159     * {@code Collection} of names returned by the
160     * {@link #getIssuerNames getIssuerNames} method.
161     * <p>
162     * If a name is specified as a byte array, it should contain a single DER
163     * encoded distinguished name, as defined in X.501. The ASN.1 notation for
164     * this structure is as follows.
165     * <pre>{@code
166     * Name ::= CHOICE {
167     *   RDNSequence }
168     *
169     * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
170     *
171     * RelativeDistinguishedName ::=
172     *   SET SIZE (1 .. MAX) OF AttributeTypeAndValue
173     *
174     * AttributeTypeAndValue ::= SEQUENCE {
175     *   type     AttributeType,
176     *   value    AttributeValue }
177     *
178     * AttributeType ::= OBJECT IDENTIFIER
179     *
180     * AttributeValue ::= ANY DEFINED BY AttributeType
181     * ....
182     * DirectoryString ::= CHOICE {
183     *       teletexString           TeletexString (SIZE (1..MAX)),
184     *       printableString         PrintableString (SIZE (1..MAX)),
185     *       universalString         UniversalString (SIZE (1..MAX)),
186     *       utf8String              UTF8String (SIZE (1.. MAX)),
187     *       bmpString               BMPString (SIZE (1..MAX)) }
188     * }</pre>
189     * <p>
190     * Note that a deep copy is performed on the {@code Collection} to
191     * protect against subsequent modifications.
192     *
193     * @param names a {@code Collection} of names (or {@code null})
194     * @throws IOException if a parsing error occurs
195     * @see #getIssuerNames
196     */
197    public void setIssuerNames(Collection<?> names) throws IOException {
198        if (names == null || names.size() == 0) {
199            issuerNames = null;
200            issuerX500Principals = null;
201        } else {
202            HashSet<Object> tempNames = cloneAndCheckIssuerNames(names);
203            // Ensure that we either set both of these or neither
204            issuerX500Principals = parseIssuerNames(tempNames);
205            issuerNames = tempNames;
206        }
207    }
208
209    /**
210     * Adds a name to the issuerNames criterion. The issuer distinguished
211     * name in the {@code X509CRL} must match at least one of the specified
212     * distinguished names.
213     * <p>
214     * This method allows the caller to add a name to the set of issuer names
215     * which {@code X509CRLs} may contain. The specified name is added to
216     * any previous value for the issuerNames criterion.
217     * If the specified name is a duplicate, it may be ignored.
218     *
219     * @param issuer the issuer as X500Principal
220     * @since 1.5
221     */
222    public void addIssuer(X500Principal issuer) {
223        addIssuerNameInternal(issuer.getEncoded(), issuer);
224    }
225
226    /**
227     * <strong>Denigrated</strong>, use
228     * {@linkplain #addIssuer(X500Principal)} or
229     * {@linkplain #addIssuerName(byte[])} instead. This method should not be
230     * relied on as it can fail to match some CRLs because of a loss of
231     * encoding information in the RFC 2253 String form of some distinguished
232     * names.
233     * <p>
234     * Adds a name to the issuerNames criterion. The issuer distinguished
235     * name in the {@code X509CRL} must match at least one of the specified
236     * distinguished names.
237     * <p>
238     * This method allows the caller to add a name to the set of issuer names
239     * which {@code X509CRLs} may contain. The specified name is added to
240     * any previous value for the issuerNames criterion.
241     * If the specified name is a duplicate, it may be ignored.
242     *
243     * @param name the name in RFC 2253 form
244     * @throws IOException if a parsing error occurs
245     */
246    public void addIssuerName(String name) throws IOException {
247        addIssuerNameInternal(name, new X500Name(name).asX500Principal());
248    }
249
250    /**
251     * Adds a name to the issuerNames criterion. The issuer distinguished
252     * name in the {@code X509CRL} must match at least one of the specified
253     * distinguished names.
254     * <p>
255     * This method allows the caller to add a name to the set of issuer names
256     * which {@code X509CRLs} may contain. The specified name is added to
257     * any previous value for the issuerNames criterion. If the specified name
258     * is a duplicate, it may be ignored.
259     * If a name is specified as a byte array, it should contain a single DER
260     * encoded distinguished name, as defined in X.501. The ASN.1 notation for
261     * this structure is as follows.
262     * <p>
263     * The name is provided as a byte array. This byte array should contain
264     * a single DER encoded distinguished name, as defined in X.501. The ASN.1
265     * notation for this structure appears in the documentation for
266     * {@link #setIssuerNames setIssuerNames(Collection names)}.
267     * <p>
268     * Note that the byte array supplied here is cloned to protect against
269     * subsequent modifications.
270     *
271     * @param name a byte array containing the name in ASN.1 DER encoded form
272     * @throws IOException if a parsing error occurs
273     */
274    public void addIssuerName(byte[] name) throws IOException {
275        // clone because byte arrays are modifiable
276        addIssuerNameInternal(name.clone(), new X500Name(name).asX500Principal());
277    }
278
279    /**
280     * A private method that adds a name (String or byte array) to the
281     * issuerNames criterion. The issuer distinguished
282     * name in the {@code X509CRL} must match at least one of the specified
283     * distinguished names.
284     *
285     * @param name the name in string or byte array form
286     * @param principal the name in X500Principal form
287     * @throws IOException if a parsing error occurs
288     */
289    private void addIssuerNameInternal(Object name, X500Principal principal) {
290        if (issuerNames == null) {
291            issuerNames = new HashSet<Object>();
292        }
293        if (issuerX500Principals == null) {
294            issuerX500Principals = new HashSet<X500Principal>();
295        }
296        issuerNames.add(name);
297        issuerX500Principals.add(principal);
298    }
299
300    /**
301     * Clone and check an argument of the form passed to
302     * setIssuerNames. Throw an IOException if the argument is malformed.
303     *
304     * @param names a {@code Collection} of names. Each entry is a
305     *              String or a byte array (the name, in string or ASN.1
306     *              DER encoded form, respectively). {@code null} is
307     *              not an acceptable value.
308     * @return a deep copy of the specified {@code Collection}
309     * @throws IOException if a parsing error occurs
310     */
311    private static HashSet<Object> cloneAndCheckIssuerNames(Collection<?> names)
312        throws IOException
313    {
314        HashSet<Object> namesCopy = new HashSet<Object>();
315        Iterator<?> i = names.iterator();
316        while (i.hasNext()) {
317            Object nameObject = i.next();
318            if (!(nameObject instanceof byte []) &&
319                !(nameObject instanceof String))
320                throw new IOException("name not byte array or String");
321            if (nameObject instanceof byte [])
322                namesCopy.add(((byte []) nameObject).clone());
323            else
324                namesCopy.add(nameObject);
325        }
326        return(namesCopy);
327    }
328
329    /**
330     * Clone an argument of the form passed to setIssuerNames.
331     * Throw a RuntimeException if the argument is malformed.
332     * <p>
333     * This method wraps cloneAndCheckIssuerNames, changing any IOException
334     * into a RuntimeException. This method should be used when the object being
335     * cloned has already been checked, so there should never be any exceptions.
336     *
337     * @param names a {@code Collection} of names. Each entry is a
338     *              String or a byte array (the name, in string or ASN.1
339     *              DER encoded form, respectively). {@code null} is
340     *              not an acceptable value.
341     * @return a deep copy of the specified {@code Collection}
342     * @throws RuntimeException if a parsing error occurs
343     */
344    private static HashSet<Object> cloneIssuerNames(Collection<Object> names) {
345        try {
346            return cloneAndCheckIssuerNames(names);
347        } catch (IOException ioe) {
348            throw new RuntimeException(ioe);
349        }
350    }
351
352    /**
353     * Parse an argument of the form passed to setIssuerNames,
354     * returning a Collection of issuerX500Principals.
355     * Throw an IOException if the argument is malformed.
356     *
357     * @param names a {@code Collection} of names. Each entry is a
358     *              String or a byte array (the name, in string or ASN.1
359     *              DER encoded form, respectively). <Code>Null</Code> is
360     *              not an acceptable value.
361     * @return a HashSet of issuerX500Principals
362     * @throws IOException if a parsing error occurs
363     */
364    private static HashSet<X500Principal> parseIssuerNames(Collection<Object> names)
365    throws IOException {
366        HashSet<X500Principal> x500Principals = new HashSet<X500Principal>();
367        for (Iterator<Object> t = names.iterator(); t.hasNext(); ) {
368            Object nameObject = t.next();
369            if (nameObject instanceof String) {
370                x500Principals.add(new X500Name((String)nameObject).asX500Principal());
371            } else {
372                try {
373                    x500Principals.add(new X500Principal((byte[])nameObject));
374                } catch (IllegalArgumentException e) {
375                    throw (IOException)new IOException("Invalid name").initCause(e);
376                }
377            }
378        }
379        return x500Principals;
380    }
381
382    /**
383     * Sets the minCRLNumber criterion. The {@code X509CRL} must have a
384     * CRL number extension whose value is greater than or equal to the
385     * specified value. If {@code null}, no minCRLNumber check will be
386     * done.
387     *
388     * @param minCRL the minimum CRL number accepted (or {@code null})
389     */
390    public void setMinCRLNumber(BigInteger minCRL) {
391        this.minCRL = minCRL;
392    }
393
394    /**
395     * Sets the maxCRLNumber criterion. The {@code X509CRL} must have a
396     * CRL number extension whose value is less than or equal to the
397     * specified value. If {@code null}, no maxCRLNumber check will be
398     * done.
399     *
400     * @param maxCRL the maximum CRL number accepted (or {@code null})
401     */
402    public void setMaxCRLNumber(BigInteger maxCRL) {
403        this.maxCRL = maxCRL;
404    }
405
406    /**
407     * Sets the dateAndTime criterion. The specified date must be
408     * equal to or later than the value of the thisUpdate component
409     * of the {@code X509CRL} and earlier than the value of the
410     * nextUpdate component. There is no match if the {@code X509CRL}
411     * does not contain a nextUpdate component.
412     * If {@code null}, no dateAndTime check will be done.
413     * <p>
414     * Note that the {@code Date} supplied here is cloned to protect
415     * against subsequent modifications.
416     *
417     * @param dateAndTime the {@code Date} to match against
418     *                    (or {@code null})
419     * @see #getDateAndTime
420     */
421    public void setDateAndTime(Date dateAndTime) {
422        if (dateAndTime == null)
423            this.dateAndTime = null;
424        else
425            this.dateAndTime = new Date(dateAndTime.getTime());
426        this.skew = 0;
427    }
428
429    /**
430     * Sets the dateAndTime criterion and allows for the specified clock skew
431     * (in milliseconds) when checking against the validity period of the CRL.
432     */
433    void setDateAndTime(Date dateAndTime, long skew) {
434        this.dateAndTime =
435            (dateAndTime == null ? null : new Date(dateAndTime.getTime()));
436        this.skew = skew;
437    }
438
439    /**
440     * Sets the certificate being checked. This is not a criterion. Rather,
441     * it is optional information that may help a {@code CertStore}
442     * find CRLs that would be relevant when checking revocation for the
443     * specified certificate. If {@code null} is specified, then no
444     * such optional information is provided.
445     *
446     * @param cert the {@code X509Certificate} being checked
447     *             (or {@code null})
448     * @see #getCertificateChecking
449     */
450    public void setCertificateChecking(X509Certificate cert) {
451        certChecking = cert;
452    }
453
454    /**
455     * Returns the issuerNames criterion. The issuer distinguished
456     * name in the {@code X509CRL} must match at least one of the specified
457     * distinguished names. If the value returned is {@code null}, any
458     * issuer distinguished name will do.
459     * <p>
460     * If the value returned is not {@code null}, it is a
461     * unmodifiable {@code Collection} of {@code X500Principal}s.
462     *
463     * @return an unmodifiable {@code Collection} of names
464     *   (or {@code null})
465     * @see #setIssuers
466     * @since 1.5
467     */
468    public Collection<X500Principal> getIssuers() {
469        if (issuerX500Principals == null) {
470            return null;
471        }
472        return Collections.unmodifiableCollection(issuerX500Principals);
473    }
474
475    /**
476     * Returns a copy of the issuerNames criterion. The issuer distinguished
477     * name in the {@code X509CRL} must match at least one of the specified
478     * distinguished names. If the value returned is {@code null}, any
479     * issuer distinguished name will do.
480     * <p>
481     * If the value returned is not {@code null}, it is a
482     * {@code Collection} of names. Each name is a {@code String}
483     * or a byte array representing a distinguished name (in RFC 2253 or
484     * ASN.1 DER encoded form, respectively).  Note that the
485     * {@code Collection} returned may contain duplicate names.
486     * <p>
487     * If a name is specified as a byte array, it should contain a single DER
488     * encoded distinguished name, as defined in X.501. The ASN.1 notation for
489     * this structure is given in the documentation for
490     * {@link #setIssuerNames setIssuerNames(Collection names)}.
491     * <p>
492     * Note that a deep copy is performed on the {@code Collection} to
493     * protect against subsequent modifications.
494     *
495     * @return a {@code Collection} of names (or {@code null})
496     * @see #setIssuerNames
497     */
498    public Collection<Object> getIssuerNames() {
499        if (issuerNames == null) {
500            return null;
501        }
502        return cloneIssuerNames(issuerNames);
503    }
504
505    /**
506     * Returns the minCRLNumber criterion. The {@code X509CRL} must have a
507     * CRL number extension whose value is greater than or equal to the
508     * specified value. If {@code null}, no minCRLNumber check will be done.
509     *
510     * @return the minimum CRL number accepted (or {@code null})
511     */
512    public BigInteger getMinCRL() {
513        return minCRL;
514    }
515
516    /**
517     * Returns the maxCRLNumber criterion. The {@code X509CRL} must have a
518     * CRL number extension whose value is less than or equal to the
519     * specified value. If {@code null}, no maxCRLNumber check will be
520     * done.
521     *
522     * @return the maximum CRL number accepted (or {@code null})
523     */
524    public BigInteger getMaxCRL() {
525        return maxCRL;
526    }
527
528    /**
529     * Returns the dateAndTime criterion. The specified date must be
530     * equal to or later than the value of the thisUpdate component
531     * of the {@code X509CRL} and earlier than the value of the
532     * nextUpdate component. There is no match if the
533     * {@code X509CRL} does not contain a nextUpdate component.
534     * If {@code null}, no dateAndTime check will be done.
535     * <p>
536     * Note that the {@code Date} returned is cloned to protect against
537     * subsequent modifications.
538     *
539     * @return the {@code Date} to match against (or {@code null})
540     * @see #setDateAndTime
541     */
542    public Date getDateAndTime() {
543        if (dateAndTime == null)
544            return null;
545        return (Date) dateAndTime.clone();
546    }
547
548    /**
549     * Returns the certificate being checked. This is not a criterion. Rather,
550     * it is optional information that may help a {@code CertStore}
551     * find CRLs that would be relevant when checking revocation for the
552     * specified certificate. If the value returned is {@code null}, then
553     * no such optional information is provided.
554     *
555     * @return the certificate being checked (or {@code null})
556     * @see #setCertificateChecking
557     */
558    public X509Certificate getCertificateChecking() {
559        return certChecking;
560    }
561
562    /**
563     * Returns a printable representation of the {@code X509CRLSelector}.
564     *
565     * @return a {@code String} describing the contents of the
566     *         {@code X509CRLSelector}.
567     */
568    public String toString() {
569        StringBuffer sb = new StringBuffer();
570        sb.append("X509CRLSelector: [\n");
571        if (issuerNames != null) {
572            sb.append("  IssuerNames:\n");
573            Iterator<Object> i = issuerNames.iterator();
574            while (i.hasNext())
575                sb.append("    " + i.next() + "\n");
576        }
577        if (minCRL != null)
578            sb.append("  minCRLNumber: " + minCRL + "\n");
579        if (maxCRL != null)
580            sb.append("  maxCRLNumber: " + maxCRL + "\n");
581        if (dateAndTime != null)
582            sb.append("  dateAndTime: " + dateAndTime + "\n");
583        if (certChecking != null)
584            sb.append("  Certificate being checked: " + certChecking + "\n");
585        sb.append("]");
586        return sb.toString();
587    }
588
589    /**
590     * Decides whether a {@code CRL} should be selected.
591     *
592     * @param crl the {@code CRL} to be checked
593     * @return {@code true} if the {@code CRL} should be selected,
594     *         {@code false} otherwise
595     */
596    public boolean match(CRL crl) {
597        if (!(crl instanceof X509CRL)) {
598            return false;
599        }
600        X509CRL xcrl = (X509CRL)crl;
601
602        /* match on issuer name */
603        if (issuerNames != null) {
604            X500Principal issuer = xcrl.getIssuerX500Principal();
605            Iterator<X500Principal> i = issuerX500Principals.iterator();
606            boolean found = false;
607            while (!found && i.hasNext()) {
608                if (i.next().equals(issuer)) {
609                    found = true;
610                }
611            }
612            if (!found) {
613                if (debug != null) {
614                    debug.println("X509CRLSelector.match: issuer DNs "
615                        + "don't match");
616                }
617                return false;
618            }
619        }
620
621        if ((minCRL != null) || (maxCRL != null)) {
622            /* Get CRL number extension from CRL */
623            byte[] crlNumExtVal = xcrl.getExtensionValue("2.5.29.20");
624            if (crlNumExtVal == null) {
625                if (debug != null) {
626                    debug.println("X509CRLSelector.match: no CRLNumber");
627                }
628            }
629            BigInteger crlNum;
630            try {
631                DerInputStream in = new DerInputStream(crlNumExtVal);
632                byte[] encoded = in.getOctetString();
633                CRLNumberExtension crlNumExt =
634                    new CRLNumberExtension(Boolean.FALSE, encoded);
635                crlNum = crlNumExt.get(CRLNumberExtension.NUMBER);
636            } catch (IOException ex) {
637                if (debug != null) {
638                    debug.println("X509CRLSelector.match: exception in "
639                        + "decoding CRL number");
640                }
641                return false;
642            }
643
644            /* match on minCRLNumber */
645            if (minCRL != null) {
646                if (crlNum.compareTo(minCRL) < 0) {
647                    if (debug != null) {
648                        debug.println("X509CRLSelector.match: CRLNumber too small");
649                    }
650                    return false;
651                }
652            }
653
654            /* match on maxCRLNumber */
655            if (maxCRL != null) {
656                if (crlNum.compareTo(maxCRL) > 0) {
657                    if (debug != null) {
658                        debug.println("X509CRLSelector.match: CRLNumber too large");
659                    }
660                    return false;
661                }
662            }
663        }
664
665
666        /* match on dateAndTime */
667        if (dateAndTime != null) {
668            Date crlThisUpdate = xcrl.getThisUpdate();
669            Date nextUpdate = xcrl.getNextUpdate();
670            if (nextUpdate == null) {
671                if (debug != null) {
672                    debug.println("X509CRLSelector.match: nextUpdate null");
673                }
674                return false;
675            }
676            Date nowPlusSkew = dateAndTime;
677            Date nowMinusSkew = dateAndTime;
678            if (skew > 0) {
679                nowPlusSkew = new Date(dateAndTime.getTime() + skew);
680                nowMinusSkew = new Date(dateAndTime.getTime() - skew);
681            }
682
683            // Check that the test date is within the validity interval:
684            //   [ thisUpdate - MAX_CLOCK_SKEW,
685            //     nextUpdate + MAX_CLOCK_SKEW ]
686            if (nowMinusSkew.after(nextUpdate)
687                || nowPlusSkew.before(crlThisUpdate)) {
688                if (debug != null) {
689                    debug.println("X509CRLSelector.match: update out-of-range");
690                }
691                return false;
692            }
693        }
694
695        return true;
696    }
697
698    /**
699     * Returns a copy of this object.
700     *
701     * @return the copy
702     */
703    public Object clone() {
704        try {
705            X509CRLSelector copy = (X509CRLSelector)super.clone();
706            if (issuerNames != null) {
707                copy.issuerNames =
708                        new HashSet<Object>(issuerNames);
709                copy.issuerX500Principals =
710                        new HashSet<X500Principal>(issuerX500Principals);
711            }
712            return copy;
713        } catch (CloneNotSupportedException e) {
714            /* Cannot happen */
715            throw new InternalError(e.toString(), e);
716        }
717    }
718}
719