1package org.bouncycastle.asn1.x509;
2
3import java.util.Enumeration;
4
5import org.bouncycastle.asn1.ASN1Encodable;
6import org.bouncycastle.asn1.ASN1Sequence;
7import org.bouncycastle.asn1.ASN1TaggedObject;
8import org.bouncycastle.asn1.DERGeneralizedTime;
9import org.bouncycastle.asn1.DERInteger;
10import org.bouncycastle.asn1.DERObject;
11import org.bouncycastle.asn1.DERTaggedObject;
12import org.bouncycastle.asn1.DERUTCTime;
13
14/**
15 * PKIX RFC-2459 - TBSCertList object.
16 * <pre>
17 * TBSCertList  ::=  SEQUENCE  {
18 *      version                 Version OPTIONAL,
19 *                                   -- if present, shall be v2
20 *      signature               AlgorithmIdentifier,
21 *      issuer                  Name,
22 *      thisUpdate              Time,
23 *      nextUpdate              Time OPTIONAL,
24 *      revokedCertificates     SEQUENCE OF SEQUENCE  {
25 *           userCertificate         CertificateSerialNumber,
26 *           revocationDate          Time,
27 *           crlEntryExtensions      Extensions OPTIONAL
28 *                                         -- if present, shall be v2
29 *                                }  OPTIONAL,
30 *      crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
31 *                                         -- if present, shall be v2
32 *                                }
33 * </pre>
34 */
35public class TBSCertList
36    extends ASN1Encodable
37{
38    public static class CRLEntry
39        extends ASN1Encodable
40    {
41        ASN1Sequence  seq;
42
43        DERInteger          userCertificate;
44        Time                revocationDate;
45        X509Extensions      crlEntryExtensions;
46
47        public CRLEntry(
48            ASN1Sequence  seq)
49        {
50            if (seq.size() < 2 || seq.size() > 3)
51            {
52                throw new IllegalArgumentException("Bad sequence size: " + seq.size());
53            }
54
55            this.seq = seq;
56
57            userCertificate = DERInteger.getInstance(seq.getObjectAt(0));
58            revocationDate = Time.getInstance(seq.getObjectAt(1));
59        }
60
61        public DERInteger getUserCertificate()
62        {
63            return userCertificate;
64        }
65
66        public Time getRevocationDate()
67        {
68            return revocationDate;
69        }
70
71        public X509Extensions getExtensions()
72        {
73            if (crlEntryExtensions == null && seq.size() == 3)
74            {
75                crlEntryExtensions = X509Extensions.getInstance(seq.getObjectAt(2));
76            }
77
78            return crlEntryExtensions;
79        }
80
81        public DERObject toASN1Object()
82        {
83            return seq;
84        }
85    }
86
87    private class RevokedCertificatesEnumeration
88        implements Enumeration
89    {
90        private final Enumeration en;
91
92        RevokedCertificatesEnumeration(Enumeration en)
93        {
94            this.en = en;
95        }
96
97        public boolean hasMoreElements()
98        {
99            return en.hasMoreElements();
100        }
101
102        public Object nextElement()
103        {
104            return new CRLEntry(ASN1Sequence.getInstance(en.nextElement()));
105        }
106    }
107
108    private class EmptyEnumeration
109        implements Enumeration
110    {
111        public boolean hasMoreElements()
112        {
113            return false;
114        }
115
116        public Object nextElement()
117        {
118            return null;   // TODO: check exception handling
119        }
120    }
121
122    ASN1Sequence     seq;
123
124    DERInteger              version;
125    AlgorithmIdentifier     signature;
126    X509Name                issuer;
127    Time                    thisUpdate;
128    Time                    nextUpdate;
129    ASN1Sequence            revokedCertificates;
130    X509Extensions          crlExtensions;
131
132    public static TBSCertList getInstance(
133        ASN1TaggedObject obj,
134        boolean          explicit)
135    {
136        return getInstance(ASN1Sequence.getInstance(obj, explicit));
137    }
138
139    public static TBSCertList getInstance(
140        Object  obj)
141    {
142        if (obj instanceof TBSCertList)
143        {
144            return (TBSCertList)obj;
145        }
146        else if (obj instanceof ASN1Sequence)
147        {
148            return new TBSCertList((ASN1Sequence)obj);
149        }
150
151        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
152    }
153
154    public TBSCertList(
155        ASN1Sequence  seq)
156    {
157        if (seq.size() < 3 || seq.size() > 7)
158        {
159            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
160        }
161
162        int seqPos = 0;
163
164        this.seq = seq;
165
166        if (seq.getObjectAt(seqPos) instanceof DERInteger)
167        {
168            version = DERInteger.getInstance(seq.getObjectAt(seqPos++));
169        }
170        else
171        {
172            version = new DERInteger(0);
173        }
174
175        signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqPos++));
176        issuer = X509Name.getInstance(seq.getObjectAt(seqPos++));
177        thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
178
179        if (seqPos < seq.size()
180            && (seq.getObjectAt(seqPos) instanceof DERUTCTime
181               || seq.getObjectAt(seqPos) instanceof DERGeneralizedTime
182               || seq.getObjectAt(seqPos) instanceof Time))
183        {
184            nextUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
185        }
186
187        if (seqPos < seq.size()
188            && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject))
189        {
190            revokedCertificates = ASN1Sequence.getInstance(seq.getObjectAt(seqPos++));
191        }
192
193        if (seqPos < seq.size()
194            && seq.getObjectAt(seqPos) instanceof DERTaggedObject)
195        {
196            crlExtensions = X509Extensions.getInstance(seq.getObjectAt(seqPos));
197        }
198    }
199
200    public int getVersion()
201    {
202        return version.getValue().intValue() + 1;
203    }
204
205    public DERInteger getVersionNumber()
206    {
207        return version;
208    }
209
210    public AlgorithmIdentifier getSignature()
211    {
212        return signature;
213    }
214
215    public X509Name getIssuer()
216    {
217        return issuer;
218    }
219
220    public Time getThisUpdate()
221    {
222        return thisUpdate;
223    }
224
225    public Time getNextUpdate()
226    {
227        return nextUpdate;
228    }
229
230    public CRLEntry[] getRevokedCertificates()
231    {
232        if (revokedCertificates == null)
233        {
234            return new CRLEntry[0];
235        }
236
237        CRLEntry[] entries = new CRLEntry[revokedCertificates.size()];
238
239        for (int i = 0; i < entries.length; i++)
240        {
241            entries[i] = new CRLEntry(ASN1Sequence.getInstance(revokedCertificates.getObjectAt(i)));
242        }
243
244        return entries;
245    }
246
247    public Enumeration getRevokedCertificateEnumeration()
248    {
249        if (revokedCertificates == null)
250        {
251            return new EmptyEnumeration();
252        }
253
254        return new RevokedCertificatesEnumeration(revokedCertificates.getObjects());
255    }
256
257    public X509Extensions getExtensions()
258    {
259        return crlExtensions;
260    }
261
262    public DERObject toASN1Object()
263    {
264        return seq;
265    }
266}
267