1package org.bouncycastle.x509;
2
3import org.bouncycastle.util.Selector;
4import org.bouncycastle.util.Store;
5
6import java.security.InvalidAlgorithmParameterException;
7import java.security.cert.CertSelector;
8import java.security.cert.CertStore;
9import java.security.cert.PKIXParameters;
10import java.security.cert.TrustAnchor;
11import java.security.cert.X509CertSelector;
12import java.util.ArrayList;
13import java.util.Collections;
14import java.util.HashSet;
15import java.util.Iterator;
16import java.util.List;
17import java.util.Set;
18
19/**
20 * This class extends the PKIXParameters with a validity model parameter.
21 */
22public class ExtendedPKIXParameters
23    extends PKIXParameters
24{
25
26    private List stores;
27
28    private Selector selector;
29
30    private boolean additionalLocationsEnabled;
31
32    private List additionalStores;
33
34    private Set trustedACIssuers;
35
36    private Set necessaryACAttributes;
37
38    private Set prohibitedACAttributes;
39
40    private Set attrCertCheckers;
41
42    /**
43     * Creates an instance of <code>PKIXParameters</code> with the specified
44     * <code>Set</code> of most-trusted CAs. Each element of the set is a
45     * {@link TrustAnchor TrustAnchor}. <p/> Note that the <code>Set</code>
46     * is copied to protect against subsequent modifications.
47     *
48     * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
49     * @throws InvalidAlgorithmParameterException if the specified
50     *             <code>Set</code> is empty.
51     * @throws NullPointerException if the specified <code>Set</code> is
52     *             <code>null</code>
53     * @throws ClassCastException if any of the elements in the <code>Set</code>
54     *             is not of type <code>java.security.cert.TrustAnchor</code>
55     */
56    public ExtendedPKIXParameters(Set trustAnchors)
57        throws InvalidAlgorithmParameterException
58    {
59        super(trustAnchors);
60        stores = new ArrayList();
61        additionalStores = new ArrayList();
62        trustedACIssuers = new HashSet();
63        necessaryACAttributes = new HashSet();
64        prohibitedACAttributes = new HashSet();
65        attrCertCheckers = new HashSet();
66    }
67
68    /**
69     * Returns an instance with the parameters of a given
70     * <code>PKIXParameters</code> object.
71     *
72     * @param pkixParams The given <code>PKIXParameters</code>
73     * @return an extended PKIX params object
74     */
75    public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
76    {
77        ExtendedPKIXParameters params;
78        try
79        {
80            params = new ExtendedPKIXParameters(pkixParams.getTrustAnchors());
81        }
82        catch (Exception e)
83        {
84            // cannot happen
85            throw new RuntimeException(e.getMessage());
86        }
87        params.setParams(pkixParams);
88        return params;
89    }
90
91    /**
92     * Method to support <code>clone()</code> under J2ME.
93     * <code>super.clone()</code> does not exist and fields are not copied.
94     *
95     * @param params Parameters to set. If this are
96     *            <code>ExtendedPKIXParameters</code> they are copied to.
97     */
98    protected void setParams(PKIXParameters params)
99    {
100        setDate(params.getDate());
101        setCertPathCheckers(params.getCertPathCheckers());
102        setCertStores(params.getCertStores());
103        setAnyPolicyInhibited(params.isAnyPolicyInhibited());
104        setExplicitPolicyRequired(params.isExplicitPolicyRequired());
105        setPolicyMappingInhibited(params.isPolicyMappingInhibited());
106        setRevocationEnabled(params.isRevocationEnabled());
107        setInitialPolicies(params.getInitialPolicies());
108        setPolicyQualifiersRejected(params.getPolicyQualifiersRejected());
109        setSigProvider(params.getSigProvider());
110        setTargetCertConstraints(params.getTargetCertConstraints());
111        try
112        {
113            setTrustAnchors(params.getTrustAnchors());
114        }
115        catch (Exception e)
116        {
117            // cannot happen
118            throw new RuntimeException(e.getMessage());
119        }
120        if (params instanceof ExtendedPKIXParameters)
121        {
122            ExtendedPKIXParameters _params = (ExtendedPKIXParameters) params;
123            validityModel = _params.validityModel;
124            useDeltas = _params.useDeltas;
125            additionalLocationsEnabled = _params.additionalLocationsEnabled;
126            selector = _params.selector == null ? null
127                : (Selector) _params.selector.clone();
128            stores = new ArrayList(_params.stores);
129            additionalStores = new ArrayList(_params.additionalStores);
130            trustedACIssuers = new HashSet(_params.trustedACIssuers);
131            prohibitedACAttributes = new HashSet(_params.prohibitedACAttributes);
132            necessaryACAttributes = new HashSet(_params.necessaryACAttributes);
133            attrCertCheckers = new HashSet(_params.attrCertCheckers);
134        }
135    }
136
137    /**
138     * This is the default PKIX validity model. Actually there are two variants
139     * of this: The PKIX model and the modified PKIX model. The PKIX model
140     * verifies that all involved certificates must have been valid at the
141     * current time. The modified PKIX model verifies that all involved
142     * certificates were valid at the signing time. Both are indirectly choosen
143     * with the {@link PKIXParameters#setDate(java.util.Date)} method, so this
144     * methods sets the Date when <em>all</em> certificates must have been
145     * valid.
146     */
147    public static final int PKIX_VALIDITY_MODEL = 0;
148
149    /**
150     * This model uses the following validity model. Each certificate must have
151     * been valid at the moment where is was used. That means the end
152     * certificate must have been valid at the time the signature was done. The
153     * CA certificate which signed the end certificate must have been valid,
154     * when the end certificate was signed. The CA (or Root CA) certificate must
155     * have been valid, when the CA certificate was signed and so on. So the
156     * {@link PKIXParameters#setDate(java.util.Date)} method sets the time, when
157     * the <em>end certificate</em> must have been valid. <p/> It is used e.g.
158     * in the German signature law.
159     */
160    public static final int CHAIN_VALIDITY_MODEL = 1;
161
162    private int validityModel = PKIX_VALIDITY_MODEL;
163
164    private boolean useDeltas = false;
165
166    /**
167     * Defaults to <code>false</code>.
168     *
169     * @return Returns if delta CRLs should be used.
170     */
171    public boolean isUseDeltasEnabled()
172    {
173        return useDeltas;
174    }
175
176    /**
177     * Sets if delta CRLs should be used for checking the revocation status.
178     *
179     * @param useDeltas <code>true</code> if delta CRLs should be used.
180     */
181    public void setUseDeltasEnabled(boolean useDeltas)
182    {
183        this.useDeltas = useDeltas;
184    }
185
186    /**
187     * @return Returns the validity model.
188     * @see #CHAIN_VALIDITY_MODEL
189     * @see #PKIX_VALIDITY_MODEL
190     */
191    public int getValidityModel()
192    {
193        return validityModel;
194    }
195
196    /**
197     * Sets the Java CertStore to this extended PKIX parameters.
198     *
199     * @throws ClassCastException if an element of <code>stores</code> is not
200     *             a <code>CertStore</code>.
201     */
202    public void setCertStores(List stores)
203    {
204        if (stores != null)
205        {
206            Iterator it = stores.iterator();
207            while (it.hasNext())
208            {
209                addCertStore((CertStore)it.next());
210            }
211        }
212    }
213
214    /**
215     * Sets the Bouncy Castle Stores for finding CRLs, certificates, attribute
216     * certificates or cross certificates.
217     * <p>
218     * The <code>List</code> is cloned.
219     *
220     * @param stores A list of stores to use.
221     * @see #getStores
222     * @throws ClassCastException if an element of <code>stores</code> is not
223     *             a {@link Store}.
224     */
225    public void setStores(List stores)
226    {
227        if (stores == null)
228        {
229            this.stores = new ArrayList();
230        }
231        else
232        {
233            for (Iterator i = stores.iterator(); i.hasNext();)
234            {
235                if (!(i.next() instanceof Store))
236                {
237                    throw new ClassCastException(
238                        "All elements of list must be "
239                            + "of type org.bouncycastle.util.Store.");
240                }
241            }
242            this.stores = new ArrayList(stores);
243        }
244    }
245
246    /**
247     * Adds a Bouncy Castle {@link Store} to find CRLs, certificates, attribute
248     * certificates or cross certificates.
249     * <p>
250     * This method should be used to add local stores, like collection based
251     * X.509 stores, if available. Local stores should be considered first,
252     * before trying to use additional (remote) locations, because they do not
253     * need possible additional network traffic.
254     * <p>
255     * If <code>store</code> is <code>null</code> it is ignored.
256     *
257     * @param store The store to add.
258     * @see #getStores
259     */
260    public void addStore(Store store)
261    {
262        if (store != null)
263        {
264            stores.add(store);
265        }
266    }
267
268    /**
269     * Adds an additional Bouncy Castle {@link Store} to find CRLs, certificates,
270     * attribute certificates or cross certificates.
271     * <p>
272     * You should not use this method. This method is used for adding additional
273     * X.509 stores, which are used to add (remote) locations, e.g. LDAP, found
274     * during X.509 object processing, e.g. in certificates or CRLs. This method
275     * is used in PKIX certification path processing.
276     * <p>
277     * If <code>store</code> is <code>null</code> it is ignored.
278     *
279     * @param store The store to add.
280     * @see #getStores()
281     */
282    public void addAdditionalStore(Store store)
283    {
284        if (store != null)
285        {
286            additionalStores.add(store);
287        }
288    }
289
290    /**
291     * @deprecated
292     */
293    public void addAddionalStore(Store store)
294    {
295        addAdditionalStore(store);
296    }
297
298    /**
299     * Returns an immutable <code>List</code> of additional Bouncy Castle
300     * <code>Store</code>s used for finding CRLs, certificates, attribute
301     * certificates or cross certificates.
302     *
303     * @return an immutable <code>List</code> of additional Bouncy Castle
304     *         <code>Store</code>s. Never <code>null</code>.
305     *
306     * @see #addAdditionalStore(Store)
307     */
308    public List getAdditionalStores()
309    {
310        return Collections.unmodifiableList(additionalStores);
311    }
312
313    /**
314     * Returns an immutable <code>List</code> of Bouncy Castle
315     * <code>Store</code>s used for finding CRLs, certificates, attribute
316     * certificates or cross certificates.
317     *
318     * @return an immutable <code>List</code> of Bouncy Castle
319     *         <code>Store</code>s. Never <code>null</code>.
320     *
321     * @see #setStores(List)
322     */
323    public List getStores()
324    {
325        return Collections.unmodifiableList(new ArrayList(stores));
326    }
327
328    /**
329     * @param validityModel The validity model to set.
330     * @see #CHAIN_VALIDITY_MODEL
331     * @see #PKIX_VALIDITY_MODEL
332     */
333    public void setValidityModel(int validityModel)
334    {
335        this.validityModel = validityModel;
336    }
337
338    public Object clone()
339    {
340        ExtendedPKIXParameters params;
341        try
342        {
343            params = new ExtendedPKIXParameters(getTrustAnchors());
344        }
345        catch (Exception e)
346        {
347            // cannot happen
348            throw new RuntimeException(e.getMessage());
349        }
350        params.setParams(this);
351        return params;
352    }
353
354    /**
355     * Returns if additional {@link X509Store}s for locations like LDAP found
356     * in certificates or CRLs should be used.
357     *
358     * @return Returns <code>true</code> if additional stores are used.
359     */
360    public boolean isAdditionalLocationsEnabled()
361    {
362        return additionalLocationsEnabled;
363    }
364
365    /**
366     * Sets if additional {@link X509Store}s for locations like LDAP found in
367     * certificates or CRLs should be used.
368     *
369     * @param enabled <code>true</code> if additional stores are used.
370     */
371    public void setAdditionalLocationsEnabled(boolean enabled)
372    {
373        additionalLocationsEnabled = enabled;
374    }
375
376    /**
377     * Returns the required constraints on the target certificate or attribute
378     * certificate. The constraints are returned as an instance of
379     * <code>Selector</code>. If <code>null</code>, no constraints are
380     * defined.
381     *
382     * <p>
383     * The target certificate in a PKIX path may be a certificate or an
384     * attribute certificate.
385     * <p>
386     * Note that the <code>Selector</code> returned is cloned to protect
387     * against subsequent modifications.
388     *
389     * @return a <code>Selector</code> specifying the constraints on the
390     *         target certificate or attribute certificate (or <code>null</code>)
391     * @see #setTargetConstraints
392     * @see X509CertStoreSelector
393     * @see X509AttributeCertStoreSelector
394     */
395    public Selector getTargetConstraints()
396    {
397        if (selector != null)
398        {
399            return (Selector) selector.clone();
400        }
401        else
402        {
403            return null;
404        }
405    }
406
407    /**
408     * Sets the required constraints on the target certificate or attribute
409     * certificate. The constraints are specified as an instance of
410     * <code>Selector</code>. If <code>null</code>, no constraints are
411     * defined.
412     * <p>
413     * The target certificate in a PKIX path may be a certificate or an
414     * attribute certificate.
415     * <p>
416     * Note that the <code>Selector</code> specified is cloned to protect
417     * against subsequent modifications.
418     *
419     * @param selector a <code>Selector</code> specifying the constraints on
420     *            the target certificate or attribute certificate (or
421     *            <code>null</code>)
422     * @see #getTargetConstraints
423     * @see X509CertStoreSelector
424     * @see X509AttributeCertStoreSelector
425     */
426    public void setTargetConstraints(Selector selector)
427    {
428        if (selector != null)
429        {
430            this.selector = (Selector) selector.clone();
431        }
432        else
433        {
434            this.selector = null;
435        }
436    }
437
438    /**
439     * Sets the required constraints on the target certificate. The constraints
440     * are specified as an instance of <code>X509CertSelector</code>. If
441     * <code>null</code>, no constraints are defined.
442     *
443     * <p>
444     * This method wraps the given <code>X509CertSelector</code> into a
445     * <code>X509CertStoreSelector</code>.
446     * <p>
447     * Note that the <code>X509CertSelector</code> specified is cloned to
448     * protect against subsequent modifications.
449     *
450     * @param selector a <code>X509CertSelector</code> specifying the
451     *            constraints on the target certificate (or <code>null</code>)
452     * @see #getTargetCertConstraints
453     * @see X509CertStoreSelector
454     */
455    public void setTargetCertConstraints(CertSelector selector)
456    {
457        super.setTargetCertConstraints(selector);
458        if (selector != null)
459        {
460            this.selector = X509CertStoreSelector
461                .getInstance((X509CertSelector) selector);
462        }
463        else
464        {
465            this.selector = null;
466        }
467    }
468
469    /**
470     * Returns the trusted attribute certificate issuers. If attribute
471     * certificates is verified the trusted AC issuers must be set.
472     * <p>
473     * The returned <code>Set</code> consists of <code>TrustAnchor</code>s.
474     * <p>
475     * The returned <code>Set</code> is immutable. Never <code>null</code>
476     *
477     * @return Returns an immutable set of the trusted AC issuers.
478     */
479    public Set getTrustedACIssuers()
480    {
481        return Collections.unmodifiableSet(trustedACIssuers);
482    }
483
484    /**
485     * Sets the trusted attribute certificate issuers. If attribute certificates
486     * is verified the trusted AC issuers must be set.
487     * <p>
488     * The <code>trustedACIssuers</code> must be a <code>Set</code> of
489     * <code>TrustAnchor</code>
490     * <p>
491     * The given set is cloned.
492     *
493     * @param trustedACIssuers The trusted AC issuers to set. Is never
494     *            <code>null</code>.
495     * @throws ClassCastException if an element of <code>stores</code> is not
496     *             a <code>TrustAnchor</code>.
497     */
498    public void setTrustedACIssuers(Set trustedACIssuers)
499    {
500        if (trustedACIssuers == null)
501        {
502            this.trustedACIssuers.clear();
503            return;
504        }
505        for (Iterator it = trustedACIssuers.iterator(); it.hasNext();)
506        {
507            if (!(it.next() instanceof TrustAnchor))
508            {
509                throw new ClassCastException("All elements of set must be "
510                    + "of type " + TrustAnchor.class.getName() + ".");
511            }
512        }
513        this.trustedACIssuers.clear();
514        this.trustedACIssuers.addAll(trustedACIssuers);
515    }
516
517    /**
518     * Returns the neccessary attributes which must be contained in an attribute
519     * certificate.
520     * <p>
521     * The returned <code>Set</code> is immutable and contains
522     * <code>String</code>s with the OIDs.
523     *
524     * @return Returns the necessary AC attributes.
525     */
526    public Set getNecessaryACAttributes()
527    {
528        return Collections.unmodifiableSet(necessaryACAttributes);
529    }
530
531    /**
532     * Sets the neccessary which must be contained in an attribute certificate.
533     * <p>
534     * The <code>Set</code> must contain <code>String</code>s with the
535     * OIDs.
536     * <p>
537     * The set is cloned.
538     *
539     * @param necessaryACAttributes The necessary AC attributes to set.
540     * @throws ClassCastException if an element of
541     *             <code>necessaryACAttributes</code> is not a
542     *             <code>String</code>.
543     */
544    public void setNecessaryACAttributes(Set necessaryACAttributes)
545    {
546        if (necessaryACAttributes == null)
547        {
548            this.necessaryACAttributes.clear();
549            return;
550        }
551        for (Iterator it = necessaryACAttributes.iterator(); it.hasNext();)
552        {
553            if (!(it.next() instanceof String))
554            {
555                throw new ClassCastException("All elements of set must be "
556                    + "of type String.");
557            }
558        }
559        this.necessaryACAttributes.clear();
560        this.necessaryACAttributes.addAll(necessaryACAttributes);
561    }
562
563    /**
564     * Returns the attribute certificates which are not allowed.
565     * <p>
566     * The returned <code>Set</code> is immutable and contains
567     * <code>String</code>s with the OIDs.
568     *
569     * @return Returns the prohibited AC attributes. Is never <code>null</code>.
570     */
571    public Set getProhibitedACAttributes()
572    {
573        return Collections.unmodifiableSet(prohibitedACAttributes);
574    }
575
576    /**
577     * Sets the attribute certificates which are not allowed.
578     * <p>
579     * The <code>Set</code> must contain <code>String</code>s with the
580     * OIDs.
581     * <p>
582     * The set is cloned.
583     *
584     * @param prohibitedACAttributes The prohibited AC attributes to set.
585     * @throws ClassCastException if an element of
586     *             <code>prohibitedACAttributes</code> is not a
587     *             <code>String</code>.
588     */
589    public void setProhibitedACAttributes(Set prohibitedACAttributes)
590    {
591        if (prohibitedACAttributes == null)
592        {
593            this.prohibitedACAttributes.clear();
594            return;
595        }
596        for (Iterator it = prohibitedACAttributes.iterator(); it.hasNext();)
597        {
598            if (!(it.next() instanceof String))
599            {
600                throw new ClassCastException("All elements of set must be "
601                    + "of type String.");
602            }
603        }
604        this.prohibitedACAttributes.clear();
605        this.prohibitedACAttributes.addAll(prohibitedACAttributes);
606    }
607
608    /**
609     * Returns the attribute certificate checker. The returned set contains
610     * {@link PKIXAttrCertChecker}s and is immutable.
611     *
612     * @return Returns the attribute certificate checker. Is never
613     *         <code>null</code>.
614     */
615    public Set getAttrCertCheckers()
616    {
617        return Collections.unmodifiableSet(attrCertCheckers);
618    }
619
620    /**
621     * Sets the attribute certificate checkers.
622     * <p>
623     * All elements in the <code>Set</code> must a {@link PKIXAttrCertChecker}.
624     * <p>
625     * The given set is cloned.
626     *
627     * @param attrCertCheckers The attribute certificate checkers to set. Is
628     *            never <code>null</code>.
629     * @throws ClassCastException if an element of <code>attrCertCheckers</code>
630     *             is not a <code>PKIXAttrCertChecker</code>.
631     */
632    public void setAttrCertCheckers(Set attrCertCheckers)
633    {
634        if (attrCertCheckers == null)
635        {
636            this.attrCertCheckers.clear();
637            return;
638        }
639        for (Iterator it = attrCertCheckers.iterator(); it.hasNext();)
640        {
641            if (!(it.next() instanceof PKIXAttrCertChecker))
642            {
643                throw new ClassCastException("All elements of set must be "
644                    + "of type " + PKIXAttrCertChecker.class.getName() + ".");
645            }
646        }
647        this.attrCertCheckers.clear();
648        this.attrCertCheckers.addAll(attrCertCheckers);
649    }
650
651}
652