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