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