001package org.apache.commons.ssl.org.bouncycastle.asn1.x509;
002
003import java.util.Enumeration;
004
005import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector;
006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1GeneralizedTime;
007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Integer;
008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
011import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject;
012import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1UTCTime;
013import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence;
014import org.apache.commons.ssl.org.bouncycastle.asn1.DERTaggedObject;
015import org.apache.commons.ssl.org.bouncycastle.asn1.x500.X500Name;
016
017/**
018 * PKIX RFC-2459 - TBSCertList object.
019 * <pre>
020 * TBSCertList  ::=  SEQUENCE  {
021 *      version                 Version OPTIONAL,
022 *                                   -- if present, shall be v2
023 *      signature               AlgorithmIdentifier,
024 *      issuer                  Name,
025 *      thisUpdate              Time,
026 *      nextUpdate              Time OPTIONAL,
027 *      revokedCertificates     SEQUENCE OF SEQUENCE  {
028 *           userCertificate         CertificateSerialNumber,
029 *           revocationDate          Time,
030 *           crlEntryExtensions      Extensions OPTIONAL
031 *                                         -- if present, shall be v2
032 *                                }  OPTIONAL,
033 *      crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
034 *                                         -- if present, shall be v2
035 *                                }
036 * </pre>
037 */
038public class TBSCertList
039    extends ASN1Object
040{
041    public static class CRLEntry
042        extends ASN1Object
043    {
044        ASN1Sequence  seq;
045
046        Extensions    crlEntryExtensions;
047
048        private CRLEntry(
049            ASN1Sequence  seq)
050        {
051            if (seq.size() < 2 || seq.size() > 3)
052            {
053                throw new IllegalArgumentException("Bad sequence size: " + seq.size());
054            }
055            
056            this.seq = seq;
057        }
058
059        public static CRLEntry getInstance(Object o)
060        {
061            if (o instanceof CRLEntry)
062            {
063                return ((CRLEntry)o);
064            }
065            else if (o != null)
066            {
067                return new CRLEntry(ASN1Sequence.getInstance(o));
068            }
069
070            return null;
071        }
072
073        public ASN1Integer getUserCertificate()
074        {
075            return ASN1Integer.getInstance(seq.getObjectAt(0));
076        }
077
078        public Time getRevocationDate()
079        {
080            return Time.getInstance(seq.getObjectAt(1));
081        }
082
083        public Extensions getExtensions()
084        {
085            if (crlEntryExtensions == null && seq.size() == 3)
086            {
087                crlEntryExtensions = Extensions.getInstance(seq.getObjectAt(2));
088            }
089            
090            return crlEntryExtensions;
091        }
092
093        public ASN1Primitive toASN1Primitive()
094        {
095            return seq;
096        }
097
098        public boolean hasExtensions()
099        {
100            return seq.size() == 3;
101        }
102    }
103
104    private class RevokedCertificatesEnumeration
105        implements Enumeration
106    {
107        private final Enumeration en;
108
109        RevokedCertificatesEnumeration(Enumeration en)
110        {
111            this.en = en;
112        }
113
114        public boolean hasMoreElements()
115        {
116            return en.hasMoreElements();
117        }
118
119        public Object nextElement()
120        {
121            return CRLEntry.getInstance(en.nextElement());
122        }
123    }
124
125    private class EmptyEnumeration
126        implements Enumeration
127    {
128        public boolean hasMoreElements()
129        {
130            return false;
131        }
132
133        public Object nextElement()
134        {
135            return null;   // TODO: check exception handling
136        }
137    }
138
139    ASN1Integer             version;
140    AlgorithmIdentifier     signature;
141    X500Name                issuer;
142    Time                    thisUpdate;
143    Time                    nextUpdate;
144    ASN1Sequence            revokedCertificates;
145    Extensions              crlExtensions;
146
147    public static TBSCertList getInstance(
148        ASN1TaggedObject obj,
149        boolean          explicit)
150    {
151        return getInstance(ASN1Sequence.getInstance(obj, explicit));
152    }
153
154    public static TBSCertList getInstance(
155        Object  obj)
156    {
157        if (obj instanceof TBSCertList)
158        {
159            return (TBSCertList)obj;
160        }
161        else if (obj != null)
162        {
163            return new TBSCertList(ASN1Sequence.getInstance(obj));
164        }
165
166        return null;
167    }
168
169    public TBSCertList(
170        ASN1Sequence  seq)
171    {
172        if (seq.size() < 3 || seq.size() > 7)
173        {
174            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
175        }
176
177        int seqPos = 0;
178
179        if (seq.getObjectAt(seqPos) instanceof ASN1Integer)
180        {
181            version = ASN1Integer.getInstance(seq.getObjectAt(seqPos++));
182        }
183        else
184        {
185            version = null;  // version is optional
186        }
187
188        signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqPos++));
189        issuer = X500Name.getInstance(seq.getObjectAt(seqPos++));
190        thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
191
192        if (seqPos < seq.size()
193            && (seq.getObjectAt(seqPos) instanceof ASN1UTCTime
194               || seq.getObjectAt(seqPos) instanceof ASN1GeneralizedTime
195               || seq.getObjectAt(seqPos) instanceof Time))
196        {
197            nextUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
198        }
199
200        if (seqPos < seq.size()
201            && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject))
202        {
203            revokedCertificates = ASN1Sequence.getInstance(seq.getObjectAt(seqPos++));
204        }
205
206        if (seqPos < seq.size()
207            && seq.getObjectAt(seqPos) instanceof DERTaggedObject)
208        {
209            crlExtensions = Extensions.getInstance(ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(seqPos), true));
210        }
211    }
212
213    public int getVersionNumber()
214    {
215        if (version == null)
216        {
217            return 1;
218        }
219        return version.getValue().intValue() + 1;
220    }
221
222    public ASN1Integer getVersion()
223    {
224        return version;
225    }
226
227    public AlgorithmIdentifier getSignature()
228    {
229        return signature;
230    }
231
232    public X500Name getIssuer()
233    {
234        return issuer;
235    }
236
237    public Time getThisUpdate()
238    {
239        return thisUpdate;
240    }
241
242    public Time getNextUpdate()
243    {
244        return nextUpdate;
245    }
246
247    public CRLEntry[] getRevokedCertificates()
248    {
249        if (revokedCertificates == null)
250        {
251            return new CRLEntry[0];
252        }
253
254        CRLEntry[] entries = new CRLEntry[revokedCertificates.size()];
255
256        for (int i = 0; i < entries.length; i++)
257        {
258            entries[i] = CRLEntry.getInstance(revokedCertificates.getObjectAt(i));
259        }
260        
261        return entries;
262    }
263
264    public Enumeration getRevokedCertificateEnumeration()
265    {
266        if (revokedCertificates == null)
267        {
268            return new EmptyEnumeration();
269        }
270
271        return new RevokedCertificatesEnumeration(revokedCertificates.getObjects());
272    }
273
274    public Extensions getExtensions()
275    {
276        return crlExtensions;
277    }
278
279    public ASN1Primitive toASN1Primitive()
280    {
281        ASN1EncodableVector v = new ASN1EncodableVector();
282
283        if (version != null)
284        {
285            v.add(version);
286        }
287        v.add(signature);
288        v.add(issuer);
289
290        v.add(thisUpdate);
291        if (nextUpdate != null)
292        {
293            v.add(nextUpdate);
294        }
295
296        // Add CRLEntries if they exist
297        if (revokedCertificates != null)
298        {
299            v.add(revokedCertificates);
300        }
301
302        if (crlExtensions != null)
303        {
304            v.add(new DERTaggedObject(0, crlExtensions));
305        }
306
307        return new DERSequence(v);
308    }
309}