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