1package org.bouncycastle.cms;
2
3import java.io.IOException;
4import java.io.InputStream;
5import java.io.OutputStream;
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.Iterator;
9import java.util.List;
10
11import org.bouncycastle.asn1.ASN1Encodable;
12import org.bouncycastle.asn1.ASN1EncodableVector;
13import org.bouncycastle.asn1.ASN1InputStream;
14import org.bouncycastle.asn1.ASN1ObjectIdentifier;
15import org.bouncycastle.asn1.ASN1Set;
16import org.bouncycastle.asn1.ASN1TaggedObject;
17import org.bouncycastle.asn1.BEROctetStringGenerator;
18import org.bouncycastle.asn1.BERSet;
19import org.bouncycastle.asn1.DERSet;
20import org.bouncycastle.asn1.DERTaggedObject;
21import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
22import org.bouncycastle.asn1.cms.ContentInfo;
23// BEGIN android-removed
24// import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat;
25// import org.bouncycastle.asn1.ocsp.OCSPResponse;
26// import org.bouncycastle.asn1.ocsp.OCSPResponseStatus;
27// END android-removed
28import org.bouncycastle.cert.X509AttributeCertificateHolder;
29import org.bouncycastle.cert.X509CRLHolder;
30import org.bouncycastle.cert.X509CertificateHolder;
31import org.bouncycastle.operator.DigestCalculator;
32import org.bouncycastle.util.Store;
33import org.bouncycastle.util.Strings;
34import org.bouncycastle.util.io.Streams;
35import org.bouncycastle.util.io.TeeInputStream;
36import org.bouncycastle.util.io.TeeOutputStream;
37
38class CMSUtils
39{
40    static ContentInfo readContentInfo(
41        byte[] input)
42        throws CMSException
43    {
44        // enforce limit checking as from a byte array
45        return readContentInfo(new ASN1InputStream(input));
46    }
47
48    static ContentInfo readContentInfo(
49        InputStream input)
50        throws CMSException
51    {
52        // enforce some limit checking
53        return readContentInfo(new ASN1InputStream(input));
54    }
55
56    static List getCertificatesFromStore(Store certStore)
57        throws CMSException
58    {
59        List certs = new ArrayList();
60
61        try
62        {
63            for (Iterator it = certStore.getMatches(null).iterator(); it.hasNext();)
64            {
65                X509CertificateHolder c = (X509CertificateHolder)it.next();
66
67                certs.add(c.toASN1Structure());
68            }
69
70            return certs;
71        }
72        catch (ClassCastException e)
73        {
74            throw new CMSException("error processing certs", e);
75        }
76    }
77
78    static List getAttributeCertificatesFromStore(Store attrStore)
79        throws CMSException
80    {
81        List certs = new ArrayList();
82
83        try
84        {
85            for (Iterator it = attrStore.getMatches(null).iterator(); it.hasNext();)
86            {
87                X509AttributeCertificateHolder attrCert = (X509AttributeCertificateHolder)it.next();
88
89                certs.add(new DERTaggedObject(false, 2, attrCert.toASN1Structure()));
90            }
91
92            return certs;
93        }
94        catch (ClassCastException e)
95        {
96            throw new CMSException("error processing certs", e);
97        }
98    }
99
100
101    static List getCRLsFromStore(Store crlStore)
102        throws CMSException
103    {
104        List crls = new ArrayList();
105
106        try
107        {
108            for (Iterator it = crlStore.getMatches(null).iterator(); it.hasNext();)
109            {
110                Object rev = it.next();
111
112                if (rev instanceof X509CRLHolder)
113                {
114                    X509CRLHolder c = (X509CRLHolder)rev;
115
116                    crls.add(c.toASN1Structure());
117                }
118                // BEGIN android-removed
119                // else if (rev instanceof OtherRevocationInfoFormat)
120                // {
121                //     OtherRevocationInfoFormat infoFormat = OtherRevocationInfoFormat.getInstance(rev);
122                //
123                //     validateInfoFormat(infoFormat);
124                //
125                //     crls.add(new DERTaggedObject(false, 1, infoFormat));
126                // }
127                // END android-removed
128                else if (rev instanceof ASN1TaggedObject)
129                {
130                    crls.add(rev);
131                }
132            }
133
134            return crls;
135        }
136        catch (ClassCastException e)
137        {
138            throw new CMSException("error processing certs", e);
139        }
140    }
141
142    // BEGIN android-removed
143    // private static void validateInfoFormat(OtherRevocationInfoFormat infoFormat)
144    // {
145    //     if (CMSObjectIdentifiers.id_ri_ocsp_response.equals(infoFormat.getInfoFormat()))
146    //     {
147    //         OCSPResponse resp = OCSPResponse.getInstance(infoFormat.getInfo());
148    //
149    //         if (resp.getResponseStatus().getValue().intValue() != OCSPResponseStatus.SUCCESSFUL)
150    //         {
151    //             throw new IllegalArgumentException("cannot add unsuccessful OCSP response to CMS SignedData");
152    //         }
153    //     }
154    // }
155    //
156    // static Collection getOthersFromStore(ASN1ObjectIdentifier otherRevocationInfoFormat, Store otherRevocationInfos)
157    // {
158    //     List others = new ArrayList();
159    //
160    //     for (Iterator it = otherRevocationInfos.getMatches(null).iterator(); it.hasNext();)
161    //     {
162    //         ASN1Encodable info = (ASN1Encodable)it.next();
163    //         OtherRevocationInfoFormat infoFormat = new OtherRevocationInfoFormat(otherRevocationInfoFormat, info);
164    //         validateInfoFormat(infoFormat);
165    //
166    //         others.add(new DERTaggedObject(false, 1, infoFormat));
167    //     }
168    //
169    //     return others;
170    // }
171    // END android-removed
172
173    static ASN1Set createBerSetFromList(List derObjects)
174    {
175        ASN1EncodableVector v = new ASN1EncodableVector();
176
177        for (Iterator it = derObjects.iterator(); it.hasNext();)
178        {
179            v.add((ASN1Encodable)it.next());
180        }
181
182        return new BERSet(v);
183    }
184
185    static ASN1Set createDerSetFromList(List derObjects)
186    {
187        ASN1EncodableVector v = new ASN1EncodableVector();
188
189        for (Iterator it = derObjects.iterator(); it.hasNext();)
190        {
191            v.add((ASN1Encodable)it.next());
192        }
193
194        return new DERSet(v);
195    }
196
197    static OutputStream createBEROctetOutputStream(OutputStream s,
198            int tagNo, boolean isExplicit, int bufferSize) throws IOException
199    {
200        BEROctetStringGenerator octGen = new BEROctetStringGenerator(s, tagNo, isExplicit);
201
202        if (bufferSize != 0)
203        {
204            return octGen.getOctetOutputStream(new byte[bufferSize]);
205        }
206
207        return octGen.getOctetOutputStream();
208    }
209
210    private static ContentInfo readContentInfo(
211        ASN1InputStream in)
212        throws CMSException
213    {
214        try
215        {
216            return ContentInfo.getInstance(in.readObject());
217        }
218        catch (IOException e)
219        {
220            throw new CMSException("IOException reading content.", e);
221        }
222        catch (ClassCastException e)
223        {
224            throw new CMSException("Malformed content.", e);
225        }
226        catch (IllegalArgumentException e)
227        {
228            throw new CMSException("Malformed content.", e);
229        }
230    }
231
232    static byte[] getPasswordBytes(int scheme, char[] password)
233    {
234        if (scheme == PasswordRecipient.PKCS5_SCHEME2)
235        {
236            return PKCS5PasswordToBytes(password);
237        }
238
239        return PKCS5PasswordToUTF8Bytes(password);
240    }
241
242    /**
243     * converts a password to a byte array according to the scheme in
244     * PKCS5 (ascii, no padding)
245     *
246     * @param password a character array representing the password.
247     * @return a byte array representing the password.
248     */
249    private static byte[] PKCS5PasswordToBytes(
250        char[]  password)
251    {
252        if (password != null)
253        {
254            byte[]  bytes = new byte[password.length];
255
256            for (int i = 0; i != bytes.length; i++)
257            {
258                bytes[i] = (byte)password[i];
259            }
260
261            return bytes;
262        }
263        else
264        {
265            return new byte[0];
266        }
267    }
268
269    /**
270     * converts a password to a byte array according to the scheme in
271     * PKCS5 (UTF-8, no padding)
272     *
273     * @param password a character array representing the password.
274     * @return a byte array representing the password.
275     */
276    private static byte[] PKCS5PasswordToUTF8Bytes(
277        char[]  password)
278    {
279        if (password != null)
280        {
281            return Strings.toUTF8ByteArray(password);
282        }
283        else
284        {
285            return new byte[0];
286        }
287    }
288
289    public static byte[] streamToByteArray(
290        InputStream in)
291        throws IOException
292    {
293        return Streams.readAll(in);
294    }
295
296    public static byte[] streamToByteArray(
297        InputStream in,
298        int         limit)
299        throws IOException
300    {
301        return Streams.readAllLimited(in, limit);
302    }
303
304    static InputStream attachDigestsToInputStream(Collection digests, InputStream s)
305    {
306        InputStream result = s;
307        Iterator it = digests.iterator();
308        while (it.hasNext())
309        {
310            DigestCalculator digest = (DigestCalculator)it.next();
311            result = new TeeInputStream(result, digest.getOutputStream());
312        }
313        return result;
314    }
315
316    static OutputStream attachSignersToOutputStream(Collection signers, OutputStream s)
317    {
318        OutputStream result = s;
319        Iterator it = signers.iterator();
320        while (it.hasNext())
321        {
322            SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next();
323            result = getSafeTeeOutputStream(result, signerGen.getCalculatingOutputStream());
324        }
325        return result;
326    }
327
328    static OutputStream getSafeOutputStream(OutputStream s)
329    {
330        return s == null ? new NullOutputStream() : s;
331    }
332
333    static OutputStream getSafeTeeOutputStream(OutputStream s1,
334            OutputStream s2)
335    {
336        return s1 == null ? getSafeOutputStream(s2)
337                : s2 == null ? getSafeOutputStream(s1) : new TeeOutputStream(
338                        s1, s2);
339    }
340}
341