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