1package org.bouncycastle.jce.provider;
2
3import java.io.ByteArrayOutputStream;
4import java.io.IOException;
5import java.math.BigInteger;
6import java.security.cert.CRLException;
7import java.security.cert.X509CRLEntry;
8import java.util.Date;
9import java.util.Enumeration;
10import java.util.HashSet;
11import java.util.Set;
12
13import javax.security.auth.x500.X500Principal;
14
15import org.bouncycastle.asn1.DERObjectIdentifier;
16import org.bouncycastle.asn1.DEROutputStream;
17import org.bouncycastle.asn1.x509.GeneralName;
18import org.bouncycastle.asn1.x509.GeneralNames;
19import org.bouncycastle.asn1.x509.TBSCertList;
20import org.bouncycastle.asn1.x509.X509Extension;
21import org.bouncycastle.asn1.x509.X509Extensions;
22import org.bouncycastle.x509.extension.X509ExtensionUtil;
23
24/**
25 * The following extensions are listed in RFC 2459 as relevant to CRL Entries
26 *
27 * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
28 * (critical)
29 */
30public class X509CRLEntryObject extends X509CRLEntry
31{
32    private TBSCertList.CRLEntry c;
33
34    private boolean isIndirect = false;
35
36    private X500Principal previousCertificateIssuer = null;
37
38    public X509CRLEntryObject(TBSCertList.CRLEntry c)
39    {
40        this.c = c;
41    }
42
43    /**
44     * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
45     * is <code>false</code> {@link #getCertificateIssuer()} will always
46     * return <code>null</code>, <code>previousCertificateIssuer</code> is
47     * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
48     * has no certificate issuer CRL entry extension
49     * <code>previousCertificateIssuer</code> is returned by
50     * {@link #getCertificateIssuer()}.
51     *
52     * @param c
53     *            TBSCertList.CRLEntry object.
54     * @param isIndirect
55     *            <code>true</code> if the corresponding CRL is a indirect
56     *            CRL.
57     * @param previousCertificateIssuer
58     *            Certificate issuer of the previous CRLEntry.
59     */
60    public X509CRLEntryObject(
61        TBSCertList.CRLEntry c,
62        boolean isIndirect,
63        X500Principal previousCertificateIssuer)
64    {
65        this.c = c;
66        this.isIndirect = isIndirect;
67        this.previousCertificateIssuer = previousCertificateIssuer;
68    }
69
70    /**
71     * Will return true if any extensions are present and marked as critical as
72     * we currently dont handle any extensions!
73     */
74    public boolean hasUnsupportedCriticalExtension()
75    {
76        Set extns = getCriticalExtensionOIDs();
77        if (extns != null && !extns.isEmpty())
78        {
79            return true;
80        }
81
82        return false;
83    }
84
85    public X500Principal getCertificateIssuer()
86    {
87        if (!isIndirect)
88        {
89            return null;
90        }
91
92        byte[] ext = getExtensionValue(X509Extensions.CertificateIssuer.getId());
93        if (ext == null)
94        {
95            return previousCertificateIssuer;
96        }
97
98        try
99        {
100            GeneralName[] names = GeneralNames.getInstance(
101                    X509ExtensionUtil.fromExtensionValue(ext)).getNames();
102            for (int i = 0; i < names.length; i++)
103            {
104                if (names[i].getTagNo() == GeneralName.directoryName)
105                {
106                    return new X500Principal(names[i].getName().getDERObject().getDEREncoded());
107                }
108            }
109            throw new RuntimeException(
110                    "Cannot extract directory name from certificate issuer CRL entry extension");
111        }
112        catch (IOException e)
113        {
114            throw new RuntimeException(
115                    "Cannot extract certificate issuer CRL entry extension "
116                            + e);
117        }
118    }
119
120    private Set getExtensionOIDs(boolean critical)
121    {
122        X509Extensions extensions = c.getExtensions();
123
124        if (extensions != null)
125        {
126            Set set = new HashSet();
127            Enumeration e = extensions.oids();
128
129            while (e.hasMoreElements())
130            {
131                DERObjectIdentifier oid = (DERObjectIdentifier) e.nextElement();
132                X509Extension ext = extensions.getExtension(oid);
133
134                if (critical == ext.isCritical())
135                {
136                    set.add(oid.getId());
137                }
138            }
139
140            return set;
141        }
142
143        return null;
144    }
145
146    public Set getCriticalExtensionOIDs()
147    {
148        return getExtensionOIDs(true);
149    }
150
151    public Set getNonCriticalExtensionOIDs()
152    {
153        return getExtensionOIDs(false);
154    }
155
156    public byte[] getExtensionValue(String oid)
157    {
158        X509Extensions exts = c.getExtensions();
159
160        if (exts != null)
161        {
162            X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
163
164            if (ext != null)
165            {
166                try
167                {
168                    return ext.getValue().getEncoded();
169                }
170                catch (Exception e)
171                {
172                    throw new RuntimeException("error encoding " + e.toString());
173                }
174            }
175        }
176
177        return null;
178    }
179
180    public byte[] getEncoded()
181        throws CRLException
182    {
183        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
184        DEROutputStream dOut = new DEROutputStream(bOut);
185
186        try
187        {
188            dOut.writeObject(c);
189
190            return bOut.toByteArray();
191        }
192        catch (IOException e)
193        {
194            throw new CRLException(e.toString());
195        }
196    }
197
198    public BigInteger getSerialNumber()
199    {
200        return c.getUserCertificate().getValue();
201    }
202
203    public Date getRevocationDate()
204    {
205        return c.getRevocationDate().getDate();
206    }
207
208    public boolean hasExtensions()
209    {
210        return c.getExtensions() != null;
211    }
212
213    public String toString()
214    {
215        StringBuffer buf = new StringBuffer();
216        String nl = System.getProperty("line.separator");
217
218        buf.append("      userCertificate: ").append(this.getSerialNumber()).append(nl);
219        buf.append("       revocationDate: ").append(this.getRevocationDate()).append(nl);
220
221        X509Extensions extensions = c.getExtensions();
222
223        if (extensions != null)
224        {
225            Enumeration e = extensions.oids();
226            if (e.hasMoreElements())
227            {
228                buf.append("   crlEntryExtensions:").append(nl);
229
230                while (e.hasMoreElements())
231                {
232                    DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
233                    X509Extension ext = extensions.getExtension(oid);
234                    buf.append(ext);
235                }
236            }
237        }
238
239        return buf.toString();
240    }
241}
242