1 package org.bouncycastle.x509;
2 
3 import java.io.IOException;
4 import java.math.BigInteger;
5 import java.security.cert.CertificateExpiredException;
6 import java.security.cert.CertificateNotYetValidException;
7 import java.util.Collection;
8 import java.util.Collections;
9 import java.util.Date;
10 import java.util.HashSet;
11 import java.util.Iterator;
12 import java.util.Set;
13 
14 import org.bouncycastle.asn1.ASN1InputStream;
15 import org.bouncycastle.asn1.ASN1Primitive;
16 import org.bouncycastle.asn1.DEROctetString;
17 import org.bouncycastle.asn1.x509.GeneralName;
18 import org.bouncycastle.asn1.x509.Target;
19 import org.bouncycastle.asn1.x509.TargetInformation;
20 import org.bouncycastle.asn1.x509.Targets;
21 import org.bouncycastle.asn1.x509.X509Extensions;
22 import org.bouncycastle.util.Selector;
23 
24 /**
25  * This class is an <code>Selector</code> like implementation to select
26  * attribute certificates from a given set of criteria.
27  *
28  * @see org.bouncycastle.x509.X509AttributeCertificate
29  * @see org.bouncycastle.x509.X509Store
30  */
31 public class X509AttributeCertStoreSelector
32     implements Selector
33 {
34 
35     // TODO: name constraints???
36 
37     private AttributeCertificateHolder holder;
38 
39     private AttributeCertificateIssuer issuer;
40 
41     private BigInteger serialNumber;
42 
43     private Date attributeCertificateValid;
44 
45     private X509AttributeCertificate attributeCert;
46 
47     private Collection targetNames = new HashSet();
48 
49     private Collection targetGroups = new HashSet();
50 
X509AttributeCertStoreSelector()51     public X509AttributeCertStoreSelector()
52     {
53         super();
54     }
55 
56     /**
57      * Decides if the given attribute certificate should be selected.
58      *
59      * @param obj The attribute certificate which should be checked.
60      * @return <code>true</code> if the attribute certificate can be selected,
61      *         <code>false</code> otherwise.
62      */
match(Object obj)63     public boolean match(Object obj)
64     {
65         if (!(obj instanceof X509AttributeCertificate))
66         {
67             return false;
68         }
69 
70         X509AttributeCertificate attrCert = (X509AttributeCertificate) obj;
71 
72         if (this.attributeCert != null)
73         {
74             if (!this.attributeCert.equals(attrCert))
75             {
76                 return false;
77             }
78         }
79         if (serialNumber != null)
80         {
81             if (!attrCert.getSerialNumber().equals(serialNumber))
82             {
83                 return false;
84             }
85         }
86         if (holder != null)
87         {
88             if (!attrCert.getHolder().equals(holder))
89             {
90                 return false;
91             }
92         }
93         if (issuer != null)
94         {
95             if (!attrCert.getIssuer().equals(issuer))
96             {
97                 return false;
98             }
99         }
100 
101         if (attributeCertificateValid != null)
102         {
103             try
104             {
105                 attrCert.checkValidity(attributeCertificateValid);
106             }
107             catch (CertificateExpiredException e)
108             {
109                 return false;
110             }
111             catch (CertificateNotYetValidException e)
112             {
113                 return false;
114             }
115         }
116         if (!targetNames.isEmpty() || !targetGroups.isEmpty())
117         {
118 
119             byte[] targetInfoExt = attrCert
120                 .getExtensionValue(X509Extensions.TargetInformation.getId());
121             if (targetInfoExt != null)
122             {
123                 TargetInformation targetinfo;
124                 try
125                 {
126                     targetinfo = TargetInformation
127                         .getInstance(new ASN1InputStream(
128                             ((DEROctetString) DEROctetString
129                                 .fromByteArray(targetInfoExt)).getOctets())
130                             .readObject());
131                 }
132                 catch (IOException e)
133                 {
134                     return false;
135                 }
136                 catch (IllegalArgumentException e)
137                 {
138                     return false;
139                 }
140                 Targets[] targetss = targetinfo.getTargetsObjects();
141                 if (!targetNames.isEmpty())
142                 {
143                     boolean found = false;
144 
145                     for (int i=0; i<targetss.length; i++)
146                     {
147                         Targets t = targetss[i];
148                         Target[] targets = t.getTargets();
149                         for (int j=0; j<targets.length; j++)
150                         {
151                             if (targetNames.contains(targets[j]
152                                                        .getTargetName()))
153                             {
154                                 found = true;
155                                 break;
156                             }
157                         }
158                     }
159                     if (!found)
160                     {
161                         return false;
162                     }
163                 }
164                 if (!targetGroups.isEmpty())
165                 {
166                     boolean found = false;
167 
168                     for (int i=0; i<targetss.length; i++)
169                     {
170                         Targets t = targetss[i];
171                         Target[] targets = t.getTargets();
172                         for (int j=0; j<targets.length; j++)
173                         {
174                             if (targetGroups.contains(targets[j]
175                                                         .getTargetGroup()))
176                             {
177                                 found = true;
178                                 break;
179                             }
180                         }
181                     }
182                     if (!found)
183                     {
184                         return false;
185                     }
186                 }
187             }
188         }
189         return true;
190     }
191 
192     /**
193      * Returns a clone of this object.
194      *
195      * @return the clone.
196      */
clone()197     public Object clone()
198     {
199         X509AttributeCertStoreSelector sel = new X509AttributeCertStoreSelector();
200         sel.attributeCert = attributeCert;
201         sel.attributeCertificateValid = getAttributeCertificateValid();
202         sel.holder = holder;
203         sel.issuer = issuer;
204         sel.serialNumber = serialNumber;
205         sel.targetGroups = getTargetGroups();
206         sel.targetNames = getTargetNames();
207         return sel;
208     }
209 
210     /**
211      * Returns the attribute certificate which must be matched.
212      *
213      * @return Returns the attribute certificate.
214      */
getAttributeCert()215     public X509AttributeCertificate getAttributeCert()
216     {
217         return attributeCert;
218     }
219 
220     /**
221      * Set the attribute certificate to be matched. If <code>null</code> is
222      * given any will do.
223      *
224      * @param attributeCert The attribute certificate to set.
225      */
setAttributeCert(X509AttributeCertificate attributeCert)226     public void setAttributeCert(X509AttributeCertificate attributeCert)
227     {
228         this.attributeCert = attributeCert;
229     }
230 
231     /**
232      * Get the criteria for the validity.
233      *
234      * @return Returns the attributeCertificateValid.
235      */
getAttributeCertificateValid()236     public Date getAttributeCertificateValid()
237     {
238         if (attributeCertificateValid != null)
239         {
240             return new Date(attributeCertificateValid.getTime());
241         }
242 
243         return null;
244     }
245 
246     /**
247      * Set the time, when the certificate must be valid. If <code>null</code>
248      * is given any will do.
249      *
250      * @param attributeCertificateValid The attribute certificate validation
251      *            time to set.
252      */
setAttributeCertificateValid(Date attributeCertificateValid)253     public void setAttributeCertificateValid(Date attributeCertificateValid)
254     {
255         if (attributeCertificateValid != null)
256         {
257             this.attributeCertificateValid = new Date(attributeCertificateValid
258                 .getTime());
259         }
260         else
261         {
262             this.attributeCertificateValid = null;
263         }
264     }
265 
266     /**
267      * Gets the holder.
268      *
269      * @return Returns the holder.
270      */
getHolder()271     public AttributeCertificateHolder getHolder()
272     {
273         return holder;
274     }
275 
276     /**
277      * Sets the holder. If <code>null</code> is given any will do.
278      *
279      * @param holder The holder to set.
280      */
setHolder(AttributeCertificateHolder holder)281     public void setHolder(AttributeCertificateHolder holder)
282     {
283         this.holder = holder;
284     }
285 
286     /**
287      * Returns the issuer criterion.
288      *
289      * @return Returns the issuer.
290      */
getIssuer()291     public AttributeCertificateIssuer getIssuer()
292     {
293         return issuer;
294     }
295 
296     /**
297      * Sets the issuer the attribute certificate must have. If <code>null</code>
298      * is given any will do.
299      *
300      * @param issuer The issuer to set.
301      */
setIssuer(AttributeCertificateIssuer issuer)302     public void setIssuer(AttributeCertificateIssuer issuer)
303     {
304         this.issuer = issuer;
305     }
306 
307     /**
308      * Gets the serial number the attribute certificate must have.
309      *
310      * @return Returns the serialNumber.
311      */
getSerialNumber()312     public BigInteger getSerialNumber()
313     {
314         return serialNumber;
315     }
316 
317     /**
318      * Sets the serial number the attribute certificate must have. If
319      * <code>null</code> is given any will do.
320      *
321      * @param serialNumber The serialNumber to set.
322      */
setSerialNumber(BigInteger serialNumber)323     public void setSerialNumber(BigInteger serialNumber)
324     {
325         this.serialNumber = serialNumber;
326     }
327 
328     /**
329      * Adds a target name criterion for the attribute certificate to the target
330      * information extension criteria. The <code>X509AttributeCertificate</code>
331      * must contain at least one of the specified target names.
332      * <p>
333      * Each attribute certificate may contain a target information extension
334      * limiting the servers where this attribute certificate can be used. If
335      * this extension is not present, the attribute certificate is not targeted
336      * and may be accepted by any server.
337      *
338      * @param name The name as a GeneralName (not <code>null</code>)
339      */
addTargetName(GeneralName name)340     public void addTargetName(GeneralName name)
341     {
342         targetNames.add(name);
343     }
344 
345     /**
346      * Adds a target name criterion for the attribute certificate to the target
347      * information extension criteria. The <code>X509AttributeCertificate</code>
348      * must contain at least one of the specified target names.
349      * <p>
350      * Each attribute certificate may contain a target information extension
351      * limiting the servers where this attribute certificate can be used. If
352      * this extension is not present, the attribute certificate is not targeted
353      * and may be accepted by any server.
354      *
355      * @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName
356      * @throws IOException if a parsing error occurs.
357      */
addTargetName(byte[] name)358     public void addTargetName(byte[] name) throws IOException
359     {
360         addTargetName(GeneralName.getInstance(ASN1Primitive.fromByteArray(name)));
361     }
362 
363     /**
364      * Adds a collection with target names criteria. If <code>null</code> is
365      * given any will do.
366      * <p>
367      * The collection consists of either GeneralName objects or byte[] arrays representing
368      * DER encoded GeneralName structures.
369      *
370      * @param names A collection of target names.
371      * @throws IOException if a parsing error occurs.
372      * @see #addTargetName(byte[])
373      * @see #addTargetName(GeneralName)
374      */
setTargetNames(Collection names)375     public void setTargetNames(Collection names) throws IOException
376     {
377         targetNames = extractGeneralNames(names);
378     }
379 
380     /**
381      * Gets the target names. The collection consists of <code>List</code>s
382      * made up of an <code>Integer</code> in the first entry and a DER encoded
383      * byte array or a <code>String</code> in the second entry.
384      * <p>
385      * The returned collection is immutable.
386      *
387      * @return The collection of target names
388      * @see #setTargetNames(Collection)
389      */
getTargetNames()390     public Collection getTargetNames()
391     {
392         return Collections.unmodifiableCollection(targetNames);
393     }
394 
395     /**
396      * Adds a target group criterion for the attribute certificate to the target
397      * information extension criteria. The <code>X509AttributeCertificate</code>
398      * must contain at least one of the specified target groups.
399      * <p>
400      * Each attribute certificate may contain a target information extension
401      * limiting the servers where this attribute certificate can be used. If
402      * this extension is not present, the attribute certificate is not targeted
403      * and may be accepted by any server.
404      *
405      * @param group The group as GeneralName form (not <code>null</code>)
406      */
addTargetGroup(GeneralName group)407     public void addTargetGroup(GeneralName group)
408     {
409         targetGroups.add(group);
410     }
411 
412     /**
413      * Adds a target group criterion for the attribute certificate to the target
414      * information extension criteria. The <code>X509AttributeCertificate</code>
415      * must contain at least one of the specified target groups.
416      * <p>
417      * Each attribute certificate may contain a target information extension
418      * limiting the servers where this attribute certificate can be used. If
419      * this extension is not present, the attribute certificate is not targeted
420      * and may be accepted by any server.
421      *
422      * @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName
423      * @throws IOException if a parsing error occurs.
424      */
addTargetGroup(byte[] name)425     public void addTargetGroup(byte[] name) throws IOException
426     {
427         addTargetGroup(GeneralName.getInstance(ASN1Primitive.fromByteArray(name)));
428     }
429 
430     /**
431      * Adds a collection with target groups criteria. If <code>null</code> is
432      * given any will do.
433      * <p>
434      * The collection consists of <code>GeneralName</code> objects or <code>byte[]</code representing DER
435      * encoded GeneralNames.
436      *
437      * @param names A collection of target groups.
438      * @throws IOException if a parsing error occurs.
439      * @see #addTargetGroup(byte[])
440      * @see #addTargetGroup(GeneralName)
441      */
setTargetGroups(Collection names)442     public void setTargetGroups(Collection names) throws IOException
443     {
444         targetGroups = extractGeneralNames(names);
445     }
446 
447 
448 
449     /**
450      * Gets the target groups. The collection consists of <code>List</code>s
451      * made up of an <code>Integer</code> in the first entry and a DER encoded
452      * byte array or a <code>String</code> in the second entry.
453      * <p>
454      * The returned collection is immutable.
455      *
456      * @return The collection of target groups.
457      * @see #setTargetGroups(Collection)
458      */
getTargetGroups()459     public Collection getTargetGroups()
460     {
461         return Collections.unmodifiableCollection(targetGroups);
462     }
463 
extractGeneralNames(Collection names)464     private Set extractGeneralNames(Collection names)
465         throws IOException
466     {
467         if (names == null || names.isEmpty())
468         {
469             return new HashSet();
470         }
471         Set temp = new HashSet();
472         for (Iterator it = names.iterator(); it.hasNext();)
473         {
474             Object o = it.next();
475             if (o instanceof GeneralName)
476             {
477                 temp.add(o);
478             }
479             else
480             {
481                 temp.add(GeneralName.getInstance(ASN1Primitive.fromByteArray((byte[])o)));
482             }
483         }
484         return temp;
485     }
486 }
487