1package org.bouncycastle.x509;
2
3import java.io.ByteArrayInputStream;
4import java.io.IOException;
5import java.io.InputStream;
6import java.math.BigInteger;
7import java.security.InvalidKeyException;
8import java.security.NoSuchAlgorithmException;
9import java.security.NoSuchProviderException;
10import java.security.PublicKey;
11import java.security.Signature;
12import java.security.SignatureException;
13import java.security.cert.CertificateException;
14import java.security.cert.CertificateExpiredException;
15import java.security.cert.CertificateNotYetValidException;
16import java.text.ParseException;
17import java.util.ArrayList;
18import java.util.Date;
19import java.util.Enumeration;
20import java.util.HashSet;
21import java.util.List;
22import java.util.Set;
23
24import org.bouncycastle.asn1.ASN1Encodable;
25import org.bouncycastle.asn1.ASN1Encoding;
26import org.bouncycastle.asn1.ASN1InputStream;
27import org.bouncycastle.asn1.ASN1ObjectIdentifier;
28import org.bouncycastle.asn1.ASN1Sequence;
29import org.bouncycastle.asn1.DERBitString;
30import org.bouncycastle.asn1.x509.AttributeCertificate;
31import org.bouncycastle.asn1.x509.Extension;
32import org.bouncycastle.asn1.x509.Extensions;
33import org.bouncycastle.util.Arrays;
34
35/**
36 * An implementation of a version 2 X.509 Attribute Certificate.
37 * @deprecated use org.bouncycastle.cert.X509AttributeCertificateHolder
38 */
39public class X509V2AttributeCertificate
40    implements X509AttributeCertificate
41{
42    private AttributeCertificate    cert;
43    private Date                    notBefore;
44    private Date                    notAfter;
45
46    private static AttributeCertificate getObject(InputStream in)
47        throws IOException
48    {
49        try
50        {
51            return AttributeCertificate.getInstance(new ASN1InputStream(in).readObject());
52        }
53        catch (IOException e)
54        {
55            throw e;
56        }
57        catch (Exception e)
58        {
59            throw new IOException("exception decoding certificate structure: " + e.toString());
60        }
61    }
62
63    public X509V2AttributeCertificate(
64        InputStream encIn)
65        throws IOException
66    {
67        this(getObject(encIn));
68    }
69
70    public X509V2AttributeCertificate(
71        byte[]  encoded)
72        throws IOException
73    {
74        this(new ByteArrayInputStream(encoded));
75    }
76
77    X509V2AttributeCertificate(
78        AttributeCertificate    cert)
79        throws IOException
80    {
81        this.cert = cert;
82
83        try
84        {
85            this.notAfter = cert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime().getDate();
86            this.notBefore = cert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime().getDate();
87        }
88        catch (ParseException e)
89        {
90            throw new IOException("invalid data structure in certificate!");
91        }
92    }
93
94    public int getVersion()
95    {
96        return cert.getAcinfo().getVersion().getValue().intValue() + 1;
97    }
98
99    public BigInteger getSerialNumber()
100    {
101        return cert.getAcinfo().getSerialNumber().getValue();
102    }
103
104    public AttributeCertificateHolder getHolder()
105    {
106        return new AttributeCertificateHolder((ASN1Sequence)cert.getAcinfo().getHolder().toASN1Object());
107    }
108
109    public AttributeCertificateIssuer getIssuer()
110    {
111        return new AttributeCertificateIssuer(cert.getAcinfo().getIssuer());
112    }
113
114    public Date getNotBefore()
115    {
116        return notBefore;
117    }
118
119    public Date getNotAfter()
120    {
121        return notAfter;
122    }
123
124    public boolean[] getIssuerUniqueID()
125    {
126        DERBitString    id = cert.getAcinfo().getIssuerUniqueID();
127
128        if (id != null)
129        {
130            byte[]          bytes = id.getBytes();
131            boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
132
133            for (int i = 0; i != boolId.length; i++)
134            {
135                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
136            }
137
138            return boolId;
139        }
140
141        return null;
142    }
143
144    public void checkValidity()
145        throws CertificateExpiredException, CertificateNotYetValidException
146    {
147        this.checkValidity(new Date());
148    }
149
150    public void checkValidity(
151        Date    date)
152        throws CertificateExpiredException, CertificateNotYetValidException
153    {
154        if (date.after(this.getNotAfter()))
155        {
156            throw new CertificateExpiredException("certificate expired on " + this.getNotAfter());
157        }
158
159        if (date.before(this.getNotBefore()))
160        {
161            throw new CertificateNotYetValidException("certificate not valid till " + this.getNotBefore());
162        }
163    }
164
165    public byte[] getSignature()
166    {
167        return cert.getSignatureValue().getBytes();
168    }
169
170    public final void verify(
171            PublicKey   key,
172            String      provider)
173            throws CertificateException, NoSuchAlgorithmException,
174            InvalidKeyException, NoSuchProviderException, SignatureException
175    {
176        Signature   signature = null;
177
178        if (!cert.getSignatureAlgorithm().equals(cert.getAcinfo().getSignature()))
179        {
180            throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
181        }
182
183        signature = Signature.getInstance(cert.getSignatureAlgorithm().getObjectId().getId(), provider);
184
185        signature.initVerify(key);
186
187        try
188        {
189            signature.update(cert.getAcinfo().getEncoded());
190        }
191        catch (IOException e)
192        {
193            throw new SignatureException("Exception encoding certificate info object");
194        }
195
196        if (!signature.verify(this.getSignature()))
197        {
198            throw new InvalidKeyException("Public key presented not for certificate signature");
199        }
200    }
201
202    public byte[] getEncoded()
203        throws IOException
204    {
205        return cert.getEncoded();
206    }
207
208    public byte[] getExtensionValue(String oid)
209    {
210        Extensions extensions = cert.getAcinfo().getExtensions();
211
212        if (extensions != null)
213        {
214            Extension ext = extensions.getExtension(new ASN1ObjectIdentifier(oid));
215
216            if (ext != null)
217            {
218                try
219                {
220                    return ext.getExtnValue().getEncoded(ASN1Encoding.DER);
221                }
222                catch (Exception e)
223                {
224                    throw new RuntimeException("error encoding " + e.toString());
225                }
226            }
227        }
228
229        return null;
230    }
231
232    private Set getExtensionOIDs(
233        boolean critical)
234    {
235        Extensions  extensions = cert.getAcinfo().getExtensions();
236
237        if (extensions != null)
238        {
239            Set             set = new HashSet();
240            Enumeration     e = extensions.oids();
241
242            while (e.hasMoreElements())
243            {
244                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
245                Extension            ext = extensions.getExtension(oid);
246
247                if (ext.isCritical() == critical)
248                {
249                    set.add(oid.getId());
250                }
251            }
252
253            return set;
254        }
255
256        return null;
257    }
258
259    public Set getNonCriticalExtensionOIDs()
260    {
261        return getExtensionOIDs(false);
262    }
263
264    public Set getCriticalExtensionOIDs()
265    {
266        return getExtensionOIDs(true);
267    }
268
269    public boolean hasUnsupportedCriticalExtension()
270    {
271        Set  extensions = getCriticalExtensionOIDs();
272
273        return extensions != null && !extensions.isEmpty();
274    }
275
276    public X509Attribute[] getAttributes()
277    {
278        ASN1Sequence    seq = cert.getAcinfo().getAttributes();
279        X509Attribute[] attrs = new X509Attribute[seq.size()];
280
281        for (int i = 0; i != seq.size(); i++)
282        {
283            attrs[i] = new X509Attribute((ASN1Encodable)seq.getObjectAt(i));
284        }
285
286        return attrs;
287    }
288
289    public X509Attribute[] getAttributes(String oid)
290    {
291        ASN1Sequence    seq = cert.getAcinfo().getAttributes();
292        List            list = new ArrayList();
293
294        for (int i = 0; i != seq.size(); i++)
295        {
296            X509Attribute attr = new X509Attribute((ASN1Encodable)seq.getObjectAt(i));
297            if (attr.getOID().equals(oid))
298            {
299                list.add(attr);
300            }
301        }
302
303        if (list.size() == 0)
304        {
305            return null;
306        }
307
308        return (X509Attribute[])list.toArray(new X509Attribute[list.size()]);
309    }
310
311    public boolean equals(
312        Object o)
313    {
314        if (o == this)
315        {
316            return true;
317        }
318
319        if (!(o instanceof X509AttributeCertificate))
320        {
321            return false;
322        }
323
324        X509AttributeCertificate other = (X509AttributeCertificate)o;
325
326        try
327        {
328            byte[] b1 = this.getEncoded();
329            byte[] b2 = other.getEncoded();
330
331            return Arrays.areEqual(b1, b2);
332        }
333        catch (IOException e)
334        {
335            return false;
336        }
337    }
338
339    public int hashCode()
340    {
341        try
342        {
343            return Arrays.hashCode(this.getEncoded());
344        }
345        catch (IOException e)
346        {
347            return 0;
348        }
349    }
350}
351