1 package org.bouncycastle.cert;
2 
3 import java.io.IOException;
4 import java.io.OutputStream;
5 import java.math.BigInteger;
6 import java.util.ArrayList;
7 import java.util.Date;
8 import java.util.List;
9 import java.util.Set;
10 
11 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
12 import org.bouncycastle.asn1.ASN1Primitive;
13 import org.bouncycastle.asn1.ASN1Sequence;
14 import org.bouncycastle.asn1.DEROutputStream;
15 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
16 import org.bouncycastle.asn1.x509.AttCertValidityPeriod;
17 import org.bouncycastle.asn1.x509.Attribute;
18 import org.bouncycastle.asn1.x509.AttributeCertificate;
19 import org.bouncycastle.asn1.x509.AttributeCertificateInfo;
20 import org.bouncycastle.asn1.x509.Extension;
21 import org.bouncycastle.asn1.x509.Extensions;
22 import org.bouncycastle.operator.ContentVerifier;
23 import org.bouncycastle.operator.ContentVerifierProvider;
24 import org.bouncycastle.util.Encodable;
25 
26 /**
27  * Holding class for an X.509 AttributeCertificate structure.
28  */
29 public class X509AttributeCertificateHolder
30     implements Encodable
31 {
32     private static Attribute[] EMPTY_ARRAY = new Attribute[0];
33 
34     private AttributeCertificate attrCert;
35     private Extensions extensions;
36 
parseBytes(byte[] certEncoding)37     private static AttributeCertificate parseBytes(byte[] certEncoding)
38         throws IOException
39     {
40         try
41         {
42             return AttributeCertificate.getInstance(ASN1Primitive.fromByteArray(certEncoding));
43         }
44         catch (ClassCastException e)
45         {
46             throw new CertIOException("malformed data: " + e.getMessage(), e);
47         }
48         catch (IllegalArgumentException e)
49         {
50             throw new CertIOException("malformed data: " + e.getMessage(), e);
51         }
52     }
53 
54     /**
55      * Create a X509AttributeCertificateHolder from the passed in bytes.
56      *
57      * @param certEncoding BER/DER encoding of the certificate.
58      * @throws IOException in the event of corrupted data, or an incorrect structure.
59      */
X509AttributeCertificateHolder(byte[] certEncoding)60     public X509AttributeCertificateHolder(byte[] certEncoding)
61         throws IOException
62     {
63         this(parseBytes(certEncoding));
64     }
65 
66     /**
67      * Create a X509AttributeCertificateHolder from the passed in ASN.1 structure.
68      *
69      * @param attrCert an ASN.1 AttributeCertificate structure.
70      */
X509AttributeCertificateHolder(AttributeCertificate attrCert)71     public X509AttributeCertificateHolder(AttributeCertificate attrCert)
72     {
73         this.attrCert = attrCert;
74         this.extensions = attrCert.getAcinfo().getExtensions();
75     }
76 
77     /**
78      * Return the ASN.1 encoding of this holder's attribute certificate.
79      *
80      * @return a DER encoded byte array.
81      * @throws IOException if an encoding cannot be generated.
82      */
getEncoded()83     public byte[] getEncoded()
84         throws IOException
85     {
86         return attrCert.getEncoded();
87     }
88 
getVersion()89     public int getVersion()
90     {
91         return attrCert.getAcinfo().getVersion().getValue().intValue() + 1;
92     }
93 
94     /**
95      * Return the serial number of this attribute certificate.
96      *
97      * @return the serial number.
98      */
getSerialNumber()99     public BigInteger getSerialNumber()
100     {
101         return attrCert.getAcinfo().getSerialNumber().getValue();
102     }
103 
104     /**
105      * Return the holder details for this attribute certificate.
106      *
107      * @return this attribute certificate's holder structure.
108      */
getHolder()109     public AttributeCertificateHolder getHolder()
110     {
111         return new AttributeCertificateHolder((ASN1Sequence)attrCert.getAcinfo().getHolder().toASN1Primitive());
112     }
113 
114     /**
115      * Return the issuer details for this attribute certificate.
116      *
117      * @return this attribute certificate's issuer structure,
118      */
getIssuer()119     public AttributeCertificateIssuer getIssuer()
120     {
121         return new AttributeCertificateIssuer(attrCert.getAcinfo().getIssuer());
122     }
123 
124     /**
125      * Return the date before which this attribute certificate is not valid.
126      *
127      * @return the start date for the attribute certificate's validity period.
128      */
getNotBefore()129     public Date getNotBefore()
130     {
131         return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime());
132     }
133 
134     /**
135      * Return the date after which this attribute certificate is not valid.
136      *
137      * @return the final date for the attribute certificate's validity period.
138      */
getNotAfter()139     public Date getNotAfter()
140     {
141         return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime());
142     }
143 
144     /**
145      * Return the attributes, if any associated with this request.
146      *
147      * @return an array of Attribute, zero length if none present.
148      */
getAttributes()149     public Attribute[] getAttributes()
150     {
151         ASN1Sequence seq = attrCert.getAcinfo().getAttributes();
152         Attribute[] attrs = new Attribute[seq.size()];
153 
154         for (int i = 0; i != seq.size(); i++)
155         {
156             attrs[i] = Attribute.getInstance(seq.getObjectAt(i));
157         }
158 
159         return attrs;
160     }
161 
162     /**
163      * Return an  array of attributes matching the passed in type OID.
164      *
165      * @param type the type of the attribute being looked for.
166      * @return an array of Attribute of the requested type, zero length if none present.
167      */
getAttributes(ASN1ObjectIdentifier type)168     public Attribute[] getAttributes(ASN1ObjectIdentifier type)
169     {
170         ASN1Sequence    seq = attrCert.getAcinfo().getAttributes();
171         List            list = new ArrayList();
172 
173         for (int i = 0; i != seq.size(); i++)
174         {
175             Attribute attr = Attribute.getInstance(seq.getObjectAt(i));
176             if (attr.getAttrType().equals(type))
177             {
178                 list.add(attr);
179             }
180         }
181 
182         if (list.size() == 0)
183         {
184             return EMPTY_ARRAY;
185         }
186 
187         return (Attribute[])list.toArray(new Attribute[list.size()]);
188     }
189 
190     /**
191      * Return whether or not the holder's attribute certificate contains extensions.
192      *
193      * @return true if extension are present, false otherwise.
194      */
hasExtensions()195     public boolean hasExtensions()
196     {
197         return extensions != null;
198     }
199 
200     /**
201      * Look up the extension associated with the passed in OID.
202      *
203      * @param oid the OID of the extension of interest.
204      *
205      * @return the extension if present, null otherwise.
206      */
getExtension(ASN1ObjectIdentifier oid)207     public Extension getExtension(ASN1ObjectIdentifier oid)
208     {
209         if (extensions != null)
210         {
211             return extensions.getExtension(oid);
212         }
213 
214         return null;
215     }
216 
217     /**
218      * Return the extensions block associated with this certificate if there is one.
219      *
220      * @return the extensions block, null otherwise.
221      */
getExtensions()222     public Extensions getExtensions()
223     {
224         return extensions;
225     }
226 
227     /**
228      * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the
229      * extensions contained in this holder's attribute certificate.
230      *
231      * @return a list of extension OIDs.
232      */
getExtensionOIDs()233     public List getExtensionOIDs()
234     {
235         return CertUtils.getExtensionOIDs(extensions);
236     }
237 
238     /**
239      * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
240      * critical extensions contained in this holder's attribute certificate.
241      *
242      * @return a set of critical extension OIDs.
243      */
getCriticalExtensionOIDs()244     public Set getCriticalExtensionOIDs()
245     {
246         return CertUtils.getCriticalExtensionOIDs(extensions);
247     }
248 
249     /**
250      * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
251      * non-critical extensions contained in this holder's attribute certificate.
252      *
253      * @return a set of non-critical extension OIDs.
254      */
getNonCriticalExtensionOIDs()255     public Set getNonCriticalExtensionOIDs()
256     {
257         return CertUtils.getNonCriticalExtensionOIDs(extensions);
258     }
259 
getIssuerUniqueID()260     public boolean[] getIssuerUniqueID()
261     {
262         return CertUtils.bitStringToBoolean(attrCert.getAcinfo().getIssuerUniqueID());
263     }
264 
265     /**
266      * Return the details of the signature algorithm used to create this attribute certificate.
267      *
268      * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate.
269      */
getSignatureAlgorithm()270     public AlgorithmIdentifier getSignatureAlgorithm()
271     {
272         return attrCert.getSignatureAlgorithm();
273     }
274 
275     /**
276      * Return the bytes making up the signature associated with this attribute certificate.
277      *
278      * @return the attribute certificate signature bytes.
279      */
getSignature()280     public byte[] getSignature()
281     {
282         return attrCert.getSignatureValue().getBytes();
283     }
284 
285     /**
286      * Return the underlying ASN.1 structure for the attribute certificate in this holder.
287      *
288      * @return a AttributeCertificate object.
289      */
toASN1Structure()290     public AttributeCertificate toASN1Structure()
291     {
292         return attrCert;
293     }
294 
295     /**
296      * Return whether or not this attribute certificate is valid on a particular date.
297      *
298      * @param date the date of interest.
299      * @return true if the attribute certificate is valid, false otherwise.
300      */
isValidOn(Date date)301     public boolean isValidOn(Date date)
302     {
303         AttCertValidityPeriod certValidityPeriod = attrCert.getAcinfo().getAttrCertValidityPeriod();
304 
305         return !date.before(CertUtils.recoverDate(certValidityPeriod.getNotBeforeTime())) && !date.after(CertUtils.recoverDate(certValidityPeriod.getNotAfterTime()));
306     }
307 
308     /**
309      * Validate the signature on the attribute certificate in this holder.
310      *
311      * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.
312      * @return true if the signature is valid, false otherwise.
313      * @throws CertException if the signature cannot be processed or is inappropriate.
314      */
isSignatureValid(ContentVerifierProvider verifierProvider)315     public boolean isSignatureValid(ContentVerifierProvider verifierProvider)
316         throws CertException
317     {
318         AttributeCertificateInfo acinfo = attrCert.getAcinfo();
319 
320         if (!CertUtils.isAlgIdEqual(acinfo.getSignature(), attrCert.getSignatureAlgorithm()))
321         {
322             throw new CertException("signature invalid - algorithm identifier mismatch");
323         }
324 
325         ContentVerifier verifier;
326 
327         try
328         {
329             verifier = verifierProvider.get((acinfo.getSignature()));
330 
331             OutputStream sOut = verifier.getOutputStream();
332             DEROutputStream dOut = new DEROutputStream(sOut);
333 
334             dOut.writeObject(acinfo);
335 
336             sOut.close();
337         }
338         catch (Exception e)
339         {
340             throw new CertException("unable to process signature: " + e.getMessage(), e);
341         }
342 
343         return verifier.verify(attrCert.getSignatureValue().getBytes());
344     }
345 
equals( Object o)346     public boolean equals(
347         Object o)
348     {
349         if (o == this)
350         {
351             return true;
352         }
353 
354         if (!(o instanceof X509AttributeCertificateHolder))
355         {
356             return false;
357         }
358 
359         X509AttributeCertificateHolder other = (X509AttributeCertificateHolder)o;
360 
361         return this.attrCert.equals(other.attrCert);
362     }
363 
hashCode()364     public int hashCode()
365     {
366         return this.attrCert.hashCode();
367     }
368 }
369