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
18package java.security.cert;
19
20import java.security.InvalidAlgorithmParameterException;
21import java.security.KeyStore;
22import java.security.KeyStoreException;
23import java.util.ArrayList;
24import java.util.Collections;
25import java.util.Date;
26import java.util.Enumeration;
27import java.util.HashSet;
28import java.util.Iterator;
29import java.util.List;
30import java.util.Set;
31
32/**
33 * This class implements the parameters for the {@code PKIX CertPathValidator}.
34 * <p>
35 * The parameters must be created with <i>trusted</i> certificate authorities
36 * (trust anchors).
37 *
38 * @see CertPathValidator
39 * @see CertPathParameters
40 */
41public class PKIXParameters implements CertPathParameters {
42    // Set of trust anchors - most trusted CAs
43    private Set<TrustAnchor> trustAnchors;
44    // Set of acceptable initial policy identifiers (OID strings)
45    private Set<String> initialPolicies;
46    // List of cert stores that used to find certificates and CRLs
47    private List<CertStore> certStores;
48    // Time for which the validity of the certification
49    // patch should be determined
50    private Date date;
51    // List of certification patch checkers (PKIXCertPathChecker)
52    private List<PKIXCertPathChecker> certPathCheckers;
53    // Preferred signature provider name
54    private String sigProvider;
55    // Required constraints on the target certificate
56    private CertSelector targetCertConstraints;
57    // Indicates whether cert revocation is enabled or not
58    private boolean revocationEnabled = true;
59    // Indicates whether explicit policy required or not
60    private boolean explicitPolicyRequired = false;
61    // Indicates whether policy mapping inhibited or not
62    private boolean policyMappingInhibited = false;
63    // Indicates whether any policy inhibited or not
64    private boolean anyPolicyInhibited = false;
65    // Indicates whether certificates that include policy
66    // qualifiers in a certificate policies extension that
67    // is marked critical must be rejected or not
68    private boolean policyQualifiersRejected = true;
69
70    /**
71     * Creates a new {@code PKIXParameters} instance with the specified set of
72     * <i>trusted</i> certificate authorities.
73     *
74     * @param trustAnchors
75     *            the trusted CAs.
76     * @throws InvalidAlgorithmParameterException
77     *             if {@code trustAnchors} is empty.
78     */
79    public PKIXParameters(Set<TrustAnchor> trustAnchors)
80        throws InvalidAlgorithmParameterException {
81        if (trustAnchors == null) {
82            throw new NullPointerException("trustAnchors == null");
83        }
84        checkTrustAnchors(trustAnchors);
85        this.trustAnchors = new HashSet<TrustAnchor>(trustAnchors);
86    }
87
88    /**
89     * Creates a new {@code PKIXParameters} instance with the trusted {@code
90     * X509Certificate} entries from the specified {@code KeyStore}.
91     *
92     * @param keyStore
93     *            the key store containing trusted certificates.
94     * @throws KeyStoreException
95     *             if the {@code keyStore} is not initialized.
96     * @throws InvalidAlgorithmParameterException
97     *             if {@code keyStore} does not contained any trusted
98     *             certificate entry.
99     */
100    public PKIXParameters(KeyStore keyStore)
101        throws KeyStoreException,
102               InvalidAlgorithmParameterException {
103        if (keyStore == null) {
104            throw new NullPointerException("keyStore == null");
105        }
106        // Will throw KeyStoreException if
107        // keyStore has not been initialized (loaded)
108        if (keyStore.size() == 0) {
109            throw new InvalidAlgorithmParameterException("keyStore.size() == 0");
110        }
111        // keyStore is not null and loaded
112        trustAnchors = new HashSet<TrustAnchor>();
113        for (Enumeration i = keyStore.aliases(); i.hasMoreElements();) {
114            String alias = (String) i.nextElement();
115            if (keyStore.isCertificateEntry(alias)) {
116                // this is trusted certificate entry
117                // check if it is X509Certificate
118                Certificate c = keyStore.getCertificate(alias);
119                // add only X509Certificate
120                // ignore all other types
121                if (c instanceof X509Certificate) {
122                    trustAnchors.add(new TrustAnchor((X509Certificate)c, null));
123                }
124            }
125        }
126        checkTrustAnchors(trustAnchors);
127    }
128
129    /**
130     * Returns a unmodifiable set of the <i>trusted</i> certificate authorities.
131     *
132     * @return a unmodifiable set of the <i>trusted</i> certificate authorities.
133     */
134    public Set<TrustAnchor> getTrustAnchors() {
135        return Collections.unmodifiableSet(trustAnchors);
136    }
137
138    /**
139     * Sets the set of <i>trusted</i> certificate authorities.
140     *
141     * @param trustAnchors
142     *            the set of <i>trusted</i> certificate authorities.
143     * @throws InvalidAlgorithmParameterException
144     *             if {@code trustAnchors} is empty.
145     */
146    public void setTrustAnchors(Set<TrustAnchor> trustAnchors)
147        throws InvalidAlgorithmParameterException {
148        if (trustAnchors == null) {
149            throw new NullPointerException("trustAnchors == null");
150        }
151        checkTrustAnchors(trustAnchors);
152        // make shallow copy
153        this.trustAnchors = new HashSet<TrustAnchor>(trustAnchors);
154    }
155
156    /**
157     * Returns whether the <i>any policy OID</i> will be inhibited if it's
158     * included in a certificate.
159     *
160     * @return {@code true} if the <i>any policy OID</i> will be inhibited,
161     *         otherwise {@code false}.
162     */
163    public boolean isAnyPolicyInhibited() {
164        return anyPolicyInhibited;
165    }
166
167    /**
168     * Sets whether the <i>any policy OID</i> should be inhibited if it's
169     * included in a certificate.
170     *
171     * @param anyPolicyInhibited
172     *            {@code true} if the <i>any policy OID</i> should be inhibited,
173     *            otherwise {@code false}.
174     */
175    public void setAnyPolicyInhibited(boolean anyPolicyInhibited) {
176        this.anyPolicyInhibited = anyPolicyInhibited;
177    }
178
179    /**
180     * Returns the list of checkers for the certification path.
181     * <p>
182     * The list is unmodifiable and the entries in the list are cloned.
183     *
184     * @return the list of checkers for the certification path.
185     */
186    public List<PKIXCertPathChecker> getCertPathCheckers() {
187        if (certPathCheckers == null) {
188            // set to empty List if has not been set yet
189            certPathCheckers = new ArrayList<PKIXCertPathChecker>();
190        }
191        if (certPathCheckers.isEmpty()) {
192            // no content - no need to copy,
193            // just return immutable view of the same
194            // empty List each time
195            return Collections.unmodifiableList(certPathCheckers);
196        }
197        // List is not empty - do deep copy
198        ArrayList<PKIXCertPathChecker> modifiableList = new ArrayList<PKIXCertPathChecker>();
199        for (PKIXCertPathChecker certPathChecker : certPathCheckers) {
200            modifiableList.add((PKIXCertPathChecker) certPathChecker.clone());
201        }
202        return Collections.unmodifiableList(modifiableList);
203    }
204
205    /**
206     * Sets the list of checkers for the certification path.
207     * <p>
208     * The list is copied and the entries are cloned.
209     *
210     * @param certPathCheckers
211     *            the list of checkers for the certification path, or {@code
212     *            null} to clear the checkers.
213     */
214    public void setCertPathCheckers(List<PKIXCertPathChecker> certPathCheckers) {
215        if (certPathCheckers == null || certPathCheckers.isEmpty()) {
216            // empty list or null provided
217            if (this.certPathCheckers != null &&
218               !this.certPathCheckers.isEmpty()) {
219                // discard non-empty list
220                this.certPathCheckers = null;
221            }
222            return;
223        }
224        // non-empty list provided - do deep copy
225        this.certPathCheckers = new ArrayList<PKIXCertPathChecker>();
226        for (PKIXCertPathChecker certPathChecker : certPathCheckers) {
227            this.certPathCheckers.add((PKIXCertPathChecker) certPathChecker.clone());
228        }
229    }
230
231    /**
232     * Adds the specified {@code PKIXCertPathChecker} to the list of
233     * certification path checkers.
234     *
235     * @param checker
236     *            the {@code PKIXCertPathChecker} to add, if {@code null}, it
237     *            will be ignored.
238     */
239    public void addCertPathChecker(PKIXCertPathChecker checker) {
240        if (checker == null) {
241            // do nothing if null provided
242            return;
243        }
244        if (certPathCheckers == null) {
245            // set to empty List if has not been set yet
246            certPathCheckers = new ArrayList<PKIXCertPathChecker>();
247        }
248        // add a copy to avoid possible modifications
249        certPathCheckers.add((PKIXCertPathChecker) checker.clone());
250    }
251
252    /**
253     * Returns the list of certificate stores that are used to find certificates
254     * and CRLs.
255     *
256     * @return an immutable list of certificate stores.
257     */
258    public List<CertStore> getCertStores() {
259        if (certStores == null) {
260            // set to empty List if has not been set yet
261            certStores = new ArrayList<CertStore>();
262        }
263        if (certStores.isEmpty()) {
264            // no content - no need to copy,
265            // just return immutable view of the same
266            // empty List each time
267            return Collections.unmodifiableList(certStores);
268        }
269        // List is not empty - do shallow copy
270        ArrayList<CertStore> modifiableList
271            = new ArrayList<CertStore>(certStores);
272        return Collections.unmodifiableList(modifiableList);
273    }
274
275    /**
276     * Set the list of certificate stores that are used to find certificates and
277     * CRLs.
278     *
279     * @param certStores the list of certificate stores.
280     */
281    public void setCertStores(List<CertStore> certStores) {
282        if (certStores == null || certStores.isEmpty()) {
283            // empty list or null provided
284            if (this.certStores != null && !this.certStores.isEmpty()) {
285                // discard non-empty list
286                this.certStores = null;
287            }
288            return;
289        }
290        // non-empty list provided - do shallow copy
291        this.certStores = new ArrayList<CertStore>(certStores);
292    }
293
294    /**
295     * Adds a certificate store to the list of certificate stores that are used
296     * to find certificates and CRLs.
297     *
298     * @param store
299     *            the store to add, if {@code null}, it will be ignored.
300     */
301    public void addCertStore(CertStore store) {
302        if (store == null) {
303            // do nothing if null provided
304            return;
305        }
306        if (certStores == null) {
307            // set to empty List if has not been set yet
308            certStores = new ArrayList<CertStore>();
309        }
310        // add store
311        certStores.add(store);
312    }
313
314    /**
315     * Returns the time for which the validation of the certification path
316     * should be evaluated.
317     *
318     * @return the time for the validation, or {@code null} for the current
319     *         time.
320     */
321    public Date getDate() {
322        return date == null ? null : (Date)date.clone();
323    }
324
325    /**
326     * Sets the time for which the validation of the certification path should be
327     * evaluated.
328     *
329     * @param date
330     *            the time for the validation, or {@code null} for the current
331     *            time.
332     */
333    public void setDate(Date date) {
334        this.date = (date == null ? null : new Date(date.getTime()));
335    }
336
337    /**
338     * Returns whether an acceptable policy needs to be explicit identified in
339     * every certificate.
340     *
341     * @return {@code true} if an explicit policy is required, otherwise {@code
342     *         false}.
343     */
344    public boolean isExplicitPolicyRequired() {
345        return explicitPolicyRequired;
346    }
347
348    /**
349     * Sets whether an an acceptable policy needs to be explicit identified in
350     * every certificate.
351     *
352     * @param explicitPolicyRequired
353     *            {@code true} if an explicit policy is required, otherwise
354     *            {@code false}.
355     */
356    public void setExplicitPolicyRequired(boolean explicitPolicyRequired) {
357        this.explicitPolicyRequired = explicitPolicyRequired;
358    }
359
360    /**
361     * Returns the list of policies (as OID strings) that would be acceptable
362     * for the purpose of certification path processing.
363     *
364     * @return the unmodifiable list of policies, or an empty set if any policy
365     *         is acceptable.
366     */
367    public Set<String> getInitialPolicies() {
368        if (initialPolicies == null) {
369            // set to empty Set if has not been set yet
370            initialPolicies = new HashSet<String>();
371        }
372        if (initialPolicies.isEmpty()) {
373            // no content - no need to copy,
374            // just return immutable view of the same
375            // empty Set each time
376            return Collections.unmodifiableSet(initialPolicies);
377        }
378        // List is not empty - do shallow copy
379        HashSet<String> modifiableSet = new HashSet<String>(initialPolicies);
380        return Collections.unmodifiableSet(modifiableSet);
381    }
382
383    /**
384     * Sets the list of policies (as OID strings) that would be acceptable for
385     * the purpose of certification path processing.
386     *
387     * @param initialPolicies
388     *            the list of policies, or an empty set or {@code null} if any
389     *            policy is acceptable.
390     */
391    public void setInitialPolicies(Set<String> initialPolicies) {
392        if (initialPolicies == null || initialPolicies.isEmpty()) {
393            // empty list or null provided
394            if (this.initialPolicies != null && !this.initialPolicies.isEmpty()) {
395                // discard non-empty list
396                this.initialPolicies = null;
397            }
398            return;
399        }
400        // non-empty list provided - do shallow copy
401        this.initialPolicies = new HashSet<String>(initialPolicies);
402    }
403
404    /**
405     * Returns whether policy mapping is inhibited.
406     *
407     * @return {@code true} if policy mapping is inhibited, otherwise {@code
408     *         false}.
409     */
410    public boolean isPolicyMappingInhibited() {
411        return policyMappingInhibited;
412    }
413
414    /**
415     * Sets whether policy mapping is to be inhibited.
416     *
417     * @param policyMappingInhibited
418     *            {@code true} if policy mapping is to be inhibited, otherwise
419     *            {@code false}.
420     */
421    public void setPolicyMappingInhibited(boolean policyMappingInhibited) {
422        this.policyMappingInhibited = policyMappingInhibited;
423    }
424
425    /**
426     * Returns whether certificates are rejected that include policy
427     * qualifiers in a certificate policy extension that is marked as critical.
428     *
429     * @return {@code true} if the certificates should be rejected, otherwise
430     *         {@code false}.
431     */
432    public boolean getPolicyQualifiersRejected() {
433        return policyQualifiersRejected;
434    }
435
436    /**
437     * Sets whether certificates should be rejected that include policy
438     * qualifiers in a certificate policy extension that is marked as critical.
439     *
440     * @param policyQualifiersRejected
441     *            {@code true} if the certificates should be rejected, otherwise
442     *            {@code false}.
443     */
444    public void setPolicyQualifiersRejected(boolean policyQualifiersRejected) {
445        this.policyQualifiersRejected = policyQualifiersRejected;
446    }
447
448    /**
449     * Returns whether the default revocation checking mechanism of the
450     * underlying service provider is used.
451     *
452     * @return {@code true} if the default revocation checking mechanism is
453     *         used, otherwise {@code false}.
454     */
455    public boolean isRevocationEnabled() {
456        return revocationEnabled;
457    }
458
459    /**
460     * Sets whether the default revocation checking mechanism of the underlying
461     * service provider should be used.
462     *
463     * @param revocationEnabled
464     *            {@code true} id the default revocation checking mechanism
465     *            should be used, otherwise {@code false}.
466     */
467    public void setRevocationEnabled(boolean revocationEnabled) {
468        this.revocationEnabled = revocationEnabled;
469    }
470
471    /**
472     * Returns the name of the signature provider.
473     *
474     * @return the name of the signature provider, or {@code null} if none is
475     *         set.
476     */
477    public String getSigProvider() {
478        return sigProvider;
479    }
480
481    /**
482     * Sets the name of the preferred signature provider.
483     * <p>
484     * If set, the specified provider will be preferred for creating signatures.
485     * If not set, the first provider found supporting creation of signatures
486     * will be used.
487     *
488     * @param sigProvider
489     *            the name of the preferred signature provider, or {@code null}
490     *            if none is preferred.
491     */
492    public void setSigProvider(String sigProvider) {
493        this.sigProvider = sigProvider;
494    }
495
496    /**
497     * Returns the constraints that are required for the target certificate.
498     *
499     * @return the constraints for the target certificate, or {@code null} if
500     *         none are set.
501     */
502    public CertSelector getTargetCertConstraints() {
503        return (targetCertConstraints == null ? null
504                :(CertSelector)targetCertConstraints.clone());
505    }
506
507    /**
508     * Sets the constraints that are required for the target certificate.
509     *
510     * @param targetCertConstraints
511     *            the constraints for the target certificate, or {@code null} if
512     *            none should be used.
513     */
514    public void setTargetCertConstraints(CertSelector targetCertConstraints) {
515        this.targetCertConstraints = (targetCertConstraints == null ? null
516                : (CertSelector)targetCertConstraints.clone());
517    }
518
519    /**
520     * Clones this {@code PKIXParameters} instance.
521     *
522     * @return the cloned instance.
523     */
524    public Object clone() {
525        try {
526            // do shallow copy first
527            PKIXParameters ret = (PKIXParameters)super.clone();
528            // copy fields containing references to mutable objects
529            if (this.certStores != null) {
530                ret.certStores = new ArrayList<CertStore>(this.certStores);
531            }
532            if (this.certPathCheckers != null) {
533                ret.certPathCheckers = new ArrayList<PKIXCertPathChecker>(this.certPathCheckers);
534            }
535            return ret;
536        } catch (CloneNotSupportedException e) {
537            throw new AssertionError(e);
538        }
539    }
540
541    /**
542     * Returns a string representation of this {@code PKIXParameters} instance.
543     *
544     * @return a string representation of this {@code PKIXParameters} instance.
545     */
546    public String toString() {
547        StringBuilder sb =
548            new StringBuilder("[\n Trust Anchors: ");
549        sb.append(trustAnchors);
550        sb.append("\n Revocation Enabled: ");
551        sb.append(revocationEnabled);
552        sb.append("\n Explicit Policy Required: ");
553        sb.append(explicitPolicyRequired);
554        sb.append("\n Policy Mapping Inhibited: ");
555        sb.append(policyMappingInhibited);
556        sb.append("\n Any Policy Inhibited: ");
557        sb.append(anyPolicyInhibited);
558        sb.append("\n Policy Qualifiers Rejected: ");
559        sb.append(policyQualifiersRejected);
560        sb.append("\n Initial Policy OIDs: ");
561        sb.append((initialPolicies == null || initialPolicies.isEmpty())
562                ? "any" : initialPolicies.toString());
563        sb.append("\n Cert Stores: ");
564        sb.append((certStores==null||certStores.isEmpty())?
565                "no":certStores.toString());
566        sb.append("\n Validity Date: ");
567        sb.append(date);
568        sb.append("\n Cert Path Checkers: ");
569        sb.append((certPathCheckers==null||certPathCheckers.isEmpty())?
570                "no":certPathCheckers.toString());
571        sb.append("\n Signature Provider: ");
572        sb.append(sigProvider);
573        sb.append("\n Target Certificate Constraints: ");
574        sb.append(targetCertConstraints);
575        sb.append("\n]");
576        return sb.toString();
577    }
578
579    /**
580     * Checks that {@code trustAnchors} contains only {@code
581     * TrustAnchor} instances.
582     *
583     * @throws InvalidAlgorithmParameterException if trustAnchors set is empty.
584     */
585    private void checkTrustAnchors(Set<TrustAnchor> trustAnchors)
586            throws InvalidAlgorithmParameterException {
587        if (trustAnchors.isEmpty()) {
588            throw new InvalidAlgorithmParameterException("trustAnchors.isEmpty()");
589        }
590    }
591}
592