1package org.bouncycastle.cert;
2
3import java.io.IOException;
4import java.io.OutputStream;
5import java.text.ParseException;
6import java.util.ArrayList;
7import java.util.Arrays;
8import java.util.Collections;
9import java.util.Date;
10import java.util.HashSet;
11import java.util.List;
12import java.util.Set;
13
14import org.bouncycastle.asn1.ASN1Encodable;
15import org.bouncycastle.asn1.ASN1EncodableVector;
16import org.bouncycastle.asn1.ASN1GeneralizedTime;
17import org.bouncycastle.asn1.ASN1ObjectIdentifier;
18import org.bouncycastle.asn1.ASN1Primitive;
19import org.bouncycastle.asn1.DERBitString;
20import org.bouncycastle.asn1.DERNull;
21import org.bouncycastle.asn1.DEROutputStream;
22import org.bouncycastle.asn1.DERSequence;
23import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
24import org.bouncycastle.asn1.x509.AttributeCertificate;
25import org.bouncycastle.asn1.x509.AttributeCertificateInfo;
26import org.bouncycastle.asn1.x509.Certificate;
27import org.bouncycastle.asn1.x509.CertificateList;
28import org.bouncycastle.asn1.x509.Extensions;
29import org.bouncycastle.asn1.x509.ExtensionsGenerator;
30import org.bouncycastle.asn1.x509.TBSCertList;
31import org.bouncycastle.asn1.x509.TBSCertificate;
32import org.bouncycastle.operator.ContentSigner;
33
34class CertUtils
35{
36    private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet());
37    private static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
38
39    static ASN1Primitive parseNonEmptyASN1(byte[] encoding)
40        throws IOException
41    {
42        ASN1Primitive p = ASN1Primitive.fromByteArray(encoding);
43
44        if (p == null)
45        {
46            throw new IOException("no content found");
47        }
48        return p;
49    }
50
51    static X509CertificateHolder generateFullCert(ContentSigner signer, TBSCertificate tbsCert)
52    {
53        try
54        {
55            return new X509CertificateHolder(generateStructure(tbsCert, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCert)));
56        }
57        catch (IOException e)
58        {
59            throw new IllegalStateException("cannot produce certificate signature");
60        }
61    }
62
63    static X509AttributeCertificateHolder generateFullAttrCert(ContentSigner signer, AttributeCertificateInfo attrInfo)
64    {
65        try
66        {
67            return new X509AttributeCertificateHolder(generateAttrStructure(attrInfo, signer.getAlgorithmIdentifier(), generateSig(signer, attrInfo)));
68        }
69        catch (IOException e)
70        {
71            throw new IllegalStateException("cannot produce attribute certificate signature");
72        }
73    }
74
75    static X509CRLHolder generateFullCRL(ContentSigner signer, TBSCertList tbsCertList)
76    {
77        try
78        {
79            return new X509CRLHolder(generateCRLStructure(tbsCertList, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCertList)));
80        }
81        catch (IOException e)
82        {
83            throw new IllegalStateException("cannot produce certificate signature");
84        }
85    }
86
87    private static byte[] generateSig(ContentSigner signer, ASN1Encodable tbsObj)
88        throws IOException
89    {
90        OutputStream sOut = signer.getOutputStream();
91        DEROutputStream dOut = new DEROutputStream(sOut);
92
93        dOut.writeObject(tbsObj);
94
95        sOut.close();
96
97        return signer.getSignature();
98    }
99
100    private static Certificate generateStructure(TBSCertificate tbsCert, AlgorithmIdentifier sigAlgId, byte[] signature)
101    {
102        ASN1EncodableVector v = new ASN1EncodableVector();
103
104        v.add(tbsCert);
105        v.add(sigAlgId);
106        v.add(new DERBitString(signature));
107
108        return Certificate.getInstance(new DERSequence(v));
109    }
110
111    private static AttributeCertificate generateAttrStructure(AttributeCertificateInfo attrInfo, AlgorithmIdentifier sigAlgId, byte[] signature)
112    {
113        ASN1EncodableVector v = new ASN1EncodableVector();
114
115        v.add(attrInfo);
116        v.add(sigAlgId);
117        v.add(new DERBitString(signature));
118
119        return AttributeCertificate.getInstance(new DERSequence(v));
120    }
121
122    private static CertificateList generateCRLStructure(TBSCertList tbsCertList, AlgorithmIdentifier sigAlgId, byte[] signature)
123    {
124        ASN1EncodableVector v = new ASN1EncodableVector();
125
126        v.add(tbsCertList);
127        v.add(sigAlgId);
128        v.add(new DERBitString(signature));
129
130        return CertificateList.getInstance(new DERSequence(v));
131    }
132
133    static Set getCriticalExtensionOIDs(Extensions extensions)
134    {
135        if (extensions == null)
136        {
137            return EMPTY_SET;
138        }
139
140        return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs())));
141    }
142
143    static Set getNonCriticalExtensionOIDs(Extensions extensions)
144    {
145        if (extensions == null)
146        {
147            return EMPTY_SET;
148        }
149
150        // TODO: should probably produce a set that imposes correct ordering
151        return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs())));
152    }
153
154    static List getExtensionOIDs(Extensions extensions)
155    {
156        if (extensions == null)
157        {
158            return EMPTY_LIST;
159        }
160
161        return Collections.unmodifiableList(Arrays.asList(extensions.getExtensionOIDs()));
162    }
163
164    static void addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value)
165        throws CertIOException
166    {
167        try
168        {
169            extGenerator.addExtension(oid, isCritical, value);
170        }
171        catch (IOException e)
172        {
173            throw new CertIOException("cannot encode extension: " + e.getMessage(), e);
174        }
175    }
176
177    static DERBitString booleanToBitString(boolean[] id)
178    {
179        byte[] bytes = new byte[(id.length + 7) / 8];
180
181        for (int i = 0; i != id.length; i++)
182        {
183            bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0;
184        }
185
186        int pad = id.length % 8;
187
188        if (pad == 0)
189        {
190            return new DERBitString(bytes);
191        }
192        else
193        {
194            return new DERBitString(bytes, 8 - pad);
195        }
196    }
197
198    static boolean[] bitStringToBoolean(DERBitString bitString)
199    {
200        if (bitString != null)
201        {
202            byte[]          bytes = bitString.getBytes();
203            boolean[]       boolId = new boolean[bytes.length * 8 - bitString.getPadBits()];
204
205            for (int i = 0; i != boolId.length; i++)
206            {
207                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
208            }
209
210            return boolId;
211        }
212
213        return null;
214    }
215
216    static Date recoverDate(ASN1GeneralizedTime time)
217    {
218        try
219        {
220            return time.getDate();
221        }
222        catch (ParseException e)
223        {
224            throw new IllegalStateException("unable to recover date: " + e.getMessage());
225        }
226    }
227
228    static boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
229    {
230        if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
231        {
232            return false;
233        }
234
235        if (id1.getParameters() == null)
236        {
237            if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
238            {
239                return false;
240            }
241
242            return true;
243        }
244
245        if (id2.getParameters() == null)
246        {
247            if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
248            {
249                return false;
250            }
251
252            return true;
253        }
254
255        return id1.getParameters().equals(id2.getParameters());
256    }
257}
258