1/*
2 * Copyright (c) 2012, 2013, 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 */
25package java.security.cert;
26
27import java.net.URI;
28import java.util.ArrayList;
29import java.util.Collections;
30import java.util.HashMap;
31import java.util.HashSet;
32import java.util.List;
33import java.util.Map;
34import java.util.Map.Entry;
35import java.util.Set;
36
37/**
38 * A {@code PKIXCertPathChecker} for checking the revocation status of
39 * certificates with the PKIX algorithm.
40 *
41 * <p>A {@code PKIXRevocationChecker} checks the revocation status of
42 * certificates with the Online Certificate Status Protocol (OCSP) or
43 * Certificate Revocation Lists (CRLs). OCSP is described in RFC 2560 and
44 * is a network protocol for determining the status of a certificate. A CRL
45 * is a time-stamped list identifying revoked certificates, and RFC 5280
46 * describes an algorithm for determining the revocation status of certificates
47 * using CRLs.
48 *
49 * <p>Each {@code PKIXRevocationChecker} must be able to check the revocation
50 * status of certificates with OCSP and CRLs. By default, OCSP is the
51 * preferred mechanism for checking revocation status, with CRLs as the
52 * fallback mechanism. However, this preference can be switched to CRLs with
53 * the {@link Option#PREFER_CRLS PREFER_CRLS} option. In addition, the fallback
54 * mechanism can be disabled with the {@link Option#NO_FALLBACK NO_FALLBACK}
55 * option.
56 *
57 * <p>A {@code PKIXRevocationChecker} is obtained by calling the
58 * {@link CertPathValidator#getRevocationChecker getRevocationChecker} method
59 * of a PKIX {@code CertPathValidator}. Additional parameters and options
60 * specific to revocation can be set (by calling the
61 * {@link #setOcspResponder setOcspResponder} method for instance). The
62 * {@code PKIXRevocationChecker} is added to a {@code PKIXParameters} object
63 * using the {@link PKIXParameters#addCertPathChecker addCertPathChecker}
64 * or {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} method,
65 * and then the {@code PKIXParameters} is passed along with the {@code CertPath}
66 * to be validated to the {@link CertPathValidator#validate validate} method
67 * of a PKIX {@code CertPathValidator}. When supplying a revocation checker in
68 * this manner, it will be used to check revocation irrespective of the setting
69 * of the {@link PKIXParameters#isRevocationEnabled RevocationEnabled} flag.
70 * Similarly, a {@code PKIXRevocationChecker} may be added to a
71 * {@code PKIXBuilderParameters} object for use with a PKIX
72 * {@code CertPathBuilder}.
73 *
74 * <p>Note that when a {@code PKIXRevocationChecker} is added to
75 * {@code PKIXParameters}, it clones the {@code PKIXRevocationChecker};
76 * thus any subsequent modifications to the {@code PKIXRevocationChecker}
77 * have no effect.
78 *
79 * <p>Any parameter that is not set (or is set to {@code null}) will be set to
80 * the default value for that parameter.
81 *
82 * <p><b>Concurrent Access</b>
83 *
84 * <p>Unless otherwise specified, the methods defined in this class are not
85 * thread-safe. Multiple threads that need to access a single object
86 * concurrently should synchronize amongst themselves and provide the
87 * necessary locking. Multiple threads each manipulating separate objects
88 * need not synchronize.
89 *
90 * <p>See RFC 2560: X.509 Internet Public Key Infrastructure Online Certificate Status Protocol -
91 * OCSP, RFC 5280: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation
92 * List (CRL) Profile (Android note: this paragraph was originally in a malformed "see" tag below,
93 * moved here for correct construction of the docs).
94 *
95 * @since 1.8
96
97 */
98public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
99    private URI ocspResponder;
100    private X509Certificate ocspResponderCert;
101    private List<Extension> ocspExtensions = Collections.<Extension>emptyList();
102    private Map<X509Certificate, byte[]> ocspResponses = Collections.emptyMap();
103    private Set<Option> options = Collections.emptySet();
104
105    /**
106     * Default constructor.
107     */
108    protected PKIXRevocationChecker() {}
109
110    /**
111     * Sets the URI that identifies the location of the OCSP responder. This
112     * overrides the {@code ocsp.responderURL} security property and any
113     * responder specified in a certificate's Authority Information Access
114     * Extension, as defined in RFC 5280.
115     *
116     * @param uri the responder URI
117     */
118    public void setOcspResponder(URI uri) {
119        this.ocspResponder = uri;
120    }
121
122    /**
123     * Gets the URI that identifies the location of the OCSP responder. This
124     * overrides the {@code ocsp.responderURL} security property. If this
125     * parameter or the {@code ocsp.responderURL} property is not set, the
126     * location is determined from the certificate's Authority Information
127     * Access Extension, as defined in RFC 5280.
128     *
129     * @return the responder URI, or {@code null} if not set
130     */
131    public URI getOcspResponder() {
132        return ocspResponder;
133    }
134
135    /**
136     * Sets the OCSP responder's certificate. This overrides the
137     * {@code ocsp.responderCertSubjectName},
138     * {@code ocsp.responderCertIssuerName},
139     * and {@code ocsp.responderCertSerialNumber} security properties.
140     *
141     * @param cert the responder's certificate
142     */
143    public void setOcspResponderCert(X509Certificate cert) {
144        this.ocspResponderCert = cert;
145    }
146
147    /**
148     * Gets the OCSP responder's certificate. This overrides the
149     * {@code ocsp.responderCertSubjectName},
150     * {@code ocsp.responderCertIssuerName},
151     * and {@code ocsp.responderCertSerialNumber} security properties. If this
152     * parameter or the aforementioned properties are not set, then the
153     * responder's certificate is determined as specified in RFC 2560.
154     *
155     * @return the responder's certificate, or {@code null} if not set
156     */
157    public X509Certificate getOcspResponderCert() {
158        return ocspResponderCert;
159    }
160
161    // request extensions; single extensions not supported
162    /**
163     * Sets the optional OCSP request extensions.
164     *
165     * @param extensions a list of extensions. The list is copied to protect
166     *        against subsequent modification.
167     */
168    public void setOcspExtensions(List<Extension> extensions)
169    {
170        this.ocspExtensions = (extensions == null)
171                              ? Collections.<Extension>emptyList()
172                              : new ArrayList<Extension>(extensions);
173    }
174
175    /**
176     * Gets the optional OCSP request extensions.
177     *
178     * @return an unmodifiable list of extensions. The list is empty if no
179     *         extensions have been specified.
180     */
181    public List<Extension> getOcspExtensions() {
182        return Collections.unmodifiableList(ocspExtensions);
183    }
184
185    /**
186     * Sets the OCSP responses. These responses are used to determine
187     * the revocation status of the specified certificates when OCSP is used.
188     *
189     * @param responses a map of OCSP responses. Each key is an
190     *        {@code X509Certificate} that maps to the corresponding
191     *        DER-encoded OCSP response for that certificate. A deep copy of
192     *        the map is performed to protect against subsequent modification.
193     */
194    public void setOcspResponses(Map<X509Certificate, byte[]> responses)
195    {
196        if (responses == null) {
197            this.ocspResponses = Collections.<X509Certificate, byte[]>emptyMap();
198        } else {
199            Map<X509Certificate, byte[]> copy = new HashMap<>(responses.size());
200            for (Map.Entry<X509Certificate, byte[]> e : responses.entrySet()) {
201                copy.put(e.getKey(), e.getValue().clone());
202            }
203            this.ocspResponses = copy;
204        }
205    }
206
207    /**
208     * Gets the OCSP responses. These responses are used to determine
209     * the revocation status of the specified certificates when OCSP is used.
210     *
211     * @return a map of OCSP responses. Each key is an
212     *        {@code X509Certificate} that maps to the corresponding
213     *        DER-encoded OCSP response for that certificate. A deep copy of
214     *        the map is returned to protect against subsequent modification.
215     *        Returns an empty map if no responses have been specified.
216     */
217    public Map<X509Certificate, byte[]> getOcspResponses() {
218        Map<X509Certificate, byte[]> copy = new HashMap<>(ocspResponses.size());
219        for (Map.Entry<X509Certificate, byte[]> e : ocspResponses.entrySet()) {
220            copy.put(e.getKey(), e.getValue().clone());
221        }
222        return copy;
223    }
224
225    /**
226     * Sets the revocation options.
227     *
228     * @param options a set of revocation options. The set is copied to protect
229     *        against subsequent modification.
230     */
231    public void setOptions(Set<Option> options) {
232        this.options = (options == null)
233                       ? Collections.<Option>emptySet()
234                       : new HashSet<Option>(options);
235    }
236
237    /**
238     * Gets the revocation options.
239     *
240     * @return an unmodifiable set of revocation options. The set is empty if
241     *         no options have been specified.
242     */
243    public Set<Option> getOptions() {
244        return Collections.unmodifiableSet(options);
245    }
246
247    /**
248     * Returns a list containing the exceptions that are ignored by the
249     * revocation checker when the {@link Option#SOFT_FAIL SOFT_FAIL} option
250     * is set. The list is cleared each time {@link #init init} is called.
251     * The list is ordered in ascending order according to the certificate
252     * index returned by {@link CertPathValidatorException#getIndex getIndex}
253     * method of each entry.
254     * <p>
255     * An implementation of {@code PKIXRevocationChecker} is responsible for
256     * adding the ignored exceptions to the list.
257     *
258     * @return an unmodifiable list containing the ignored exceptions. The list
259     *         is empty if no exceptions have been ignored.
260     */
261    public abstract List<CertPathValidatorException> getSoftFailExceptions();
262
263    @Override
264    public PKIXRevocationChecker clone() {
265        PKIXRevocationChecker copy = (PKIXRevocationChecker)super.clone();
266        copy.ocspExtensions = new ArrayList<>(ocspExtensions);
267        copy.ocspResponses = new HashMap<>(ocspResponses);
268        // deep-copy the encoded responses, since they are mutable
269        for (Map.Entry<X509Certificate, byte[]> entry :
270                 copy.ocspResponses.entrySet())
271        {
272            byte[] encoded = entry.getValue();
273            entry.setValue(encoded.clone());
274        }
275        copy.options = new HashSet<>(options);
276        return copy;
277    }
278
279    /**
280     * Various revocation options that can be specified for the revocation
281     * checking mechanism.
282     */
283    public enum Option {
284        /**
285         * Only check the revocation status of end-entity certificates.
286         */
287        ONLY_END_ENTITY,
288        /**
289         * Prefer CRLs to OSCP. The default behavior is to prefer OCSP. Each
290         * PKIX implementation should document further details of their
291         * specific preference rules and fallback policies.
292         */
293        PREFER_CRLS,
294        /**
295         * Disable the fallback mechanism.
296         */
297        NO_FALLBACK,
298        /**
299         * Allow revocation check to succeed if the revocation status cannot be
300         * determined for one of the following reasons:
301         * <ul>
302         *  <li>The CRL or OCSP response cannot be obtained because of a
303         *      network error.
304         *  <li>The OCSP responder returns one of the following errors
305         *      specified in section 2.3 of RFC 2560: internalError or tryLater.
306         * </ul><br>
307         * Note that these conditions apply to both OCSP and CRLs, and unless
308         * the {@code NO_FALLBACK} option is set, the revocation check is
309         * allowed to succeed only if both mechanisms fail under one of the
310         * conditions as stated above.
311         * Exceptions that cause the network errors are ignored but can be
312         * later retrieved by calling the
313         * {@link #getSoftFailExceptions getSoftFailExceptions} method.
314         */
315        SOFT_FAIL
316    }
317}
318