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     * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the
113     * extensions contained in this holder's certificate.
114     *
115     * @return a list of extension OIDs.
116     */
117    public List getExtensionOIDs()
118    {
119        return CertUtils.getExtensionOIDs(extensions);
120    }
121
122    /**
123     * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
124     * critical extensions contained in this holder's certificate.
125     *
126     * @return a set of critical extension OIDs.
127     */
128    public Set getCriticalExtensionOIDs()
129    {
130        return CertUtils.getCriticalExtensionOIDs(extensions);
131    }
132
133    /**
134     * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
135     * non-critical extensions contained in this holder's certificate.
136     *
137     * @return a set of non-critical extension OIDs.
138     */
139    public Set getNonCriticalExtensionOIDs()
140    {
141        return CertUtils.getNonCriticalExtensionOIDs(extensions);
142    }
143
144    /**
145     * Return the serial number of this attribute certificate.
146     *
147     * @return the serial number.
148     */
149    public BigInteger getSerialNumber()
150    {
151        return x509Certificate.getSerialNumber().getValue();
152    }
153
154    /**
155     * Return the issuer of this certificate.
156     *
157     * @return the certificate issuer.
158     */
159    public X500Name getIssuer()
160    {
161        return X500Name.getInstance(x509Certificate.getIssuer());
162    }
163
164    /**
165     * Return the subject this certificate is for.
166     *
167     * @return the subject for the certificate.
168     */
169    public X500Name getSubject()
170    {
171        return X500Name.getInstance(x509Certificate.getSubject());
172    }
173
174    /**
175     * Return the date before which this certificate is not valid.
176     *
177     * @return the start time for the certificate's validity period.
178     */
179    public Date getNotBefore()
180    {
181        return x509Certificate.getStartDate().getDate();
182    }
183
184    /**
185     * Return the date after which this certificate is not valid.
186     *
187     * @return the final time for the certificate's validity period.
188     */
189    public Date getNotAfter()
190    {
191        return x509Certificate.getEndDate().getDate();
192    }
193
194    /**
195     * Return the SubjectPublicKeyInfo describing the public key this certificate is carrying.
196     *
197     * @return the public key ASN.1 structure contained in the certificate.
198     */
199    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
200    {
201        return x509Certificate.getSubjectPublicKeyInfo();
202    }
203
204    /**
205     * Return the underlying ASN.1 structure for the certificate in this holder.
206     *
207     * @return a X509CertificateStructure object.
208     */
209    public Certificate toASN1Structure()
210    {
211        return x509Certificate;
212    }
213
214    /**
215     * Return the details of the signature algorithm used to create this attribute certificate.
216     *
217     * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate.
218     */
219    public AlgorithmIdentifier getSignatureAlgorithm()
220    {
221        return x509Certificate.getSignatureAlgorithm();
222    }
223
224    /**
225     * Return the bytes making up the signature associated with this attribute certificate.
226     *
227     * @return the attribute certificate signature bytes.
228     */
229    public byte[] getSignature()
230    {
231        return x509Certificate.getSignature().getBytes();
232    }
233
234    /**
235     * Return whether or not this certificate is valid on a particular date.
236     *
237     * @param date the date of interest.
238     * @return true if the certificate is valid, false otherwise.
239     */
240    public boolean isValidOn(Date date)
241    {
242        return !date.before(x509Certificate.getStartDate().getDate()) && !date.after(x509Certificate.getEndDate().getDate());
243    }
244
245    /**
246     * Validate the signature on the certificate in this holder.
247     *
248     * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.
249     * @return true if the signature is valid, false otherwise.
250     * @throws CertException if the signature cannot be processed or is inappropriate.
251     */
252    public boolean isSignatureValid(ContentVerifierProvider verifierProvider)
253        throws CertException
254    {
255        TBSCertificate tbsCert = x509Certificate.getTBSCertificate();
256
257        if (!tbsCert.getSignature().equals(x509Certificate.getSignatureAlgorithm()))
258        {
259            throw new CertException("signature invalid - algorithm identifier mismatch");
260        }
261
262        ContentVerifier verifier;
263
264        try
265        {
266            verifier = verifierProvider.get((tbsCert.getSignature()));
267
268            OutputStream sOut = verifier.getOutputStream();
269            DEROutputStream dOut = new DEROutputStream(sOut);
270
271            dOut.writeObject(tbsCert);
272
273            sOut.close();
274        }
275        catch (Exception e)
276        {
277            throw new CertException("unable to process signature: " + e.getMessage(), e);
278        }
279
280        return verifier.verify(x509Certificate.getSignature().getBytes());
281    }
282
283    public boolean equals(
284        Object o)
285    {
286        if (o == this)
287        {
288            return true;
289        }
290
291        if (!(o instanceof X509CertificateHolder))
292        {
293            return false;
294        }
295
296        X509CertificateHolder other = (X509CertificateHolder)o;
297
298        return this.x509Certificate.equals(other.x509Certificate);
299    }
300
301    public int hashCode()
302    {
303        return this.x509Certificate.hashCode();
304    }
305
306    /**
307     * Return the ASN.1 encoding of this holder's certificate.
308     *
309     * @return a DER encoded byte array.
310     * @throws IOException if an encoding cannot be generated.
311     */
312    public byte[] getEncoded()
313        throws IOException
314    {
315        return x509Certificate.getEncoded();
316    }
317}
318