CMSSignedGenerator.java revision 87490acd76f544251011cf49753d4d0a61f86a66
1package org.bouncycastle.cms;
2
3import java.io.IOException;
4import java.security.PrivateKey;
5import java.security.SecureRandom;
6import java.security.cert.CertStore;
7import java.security.cert.CertStoreException;
8import java.security.interfaces.DSAPrivateKey;
9import java.security.interfaces.RSAPrivateKey;
10import java.util.ArrayList;
11import java.util.HashMap;
12import java.util.HashSet;
13import java.util.Iterator;
14import java.util.List;
15import java.util.Map;
16import java.util.Set;
17
18import org.bouncycastle.asn1.ASN1Encodable;
19import org.bouncycastle.asn1.ASN1ObjectIdentifier;
20import org.bouncycastle.asn1.ASN1Primitive;
21import org.bouncycastle.asn1.ASN1Set;
22import org.bouncycastle.asn1.DERSet;
23import org.bouncycastle.asn1.DERTaggedObject;
24import org.bouncycastle.asn1.cms.AttributeTable;
25import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
26// BEGIN android-removed
27// import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat;
28// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
29// END android-removed
30import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
31import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
32import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
33import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
34import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
35import org.bouncycastle.asn1.x509.AttributeCertificate;
36import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
37import org.bouncycastle.cert.X509AttributeCertificateHolder;
38import org.bouncycastle.cert.X509CRLHolder;
39import org.bouncycastle.cert.X509CertificateHolder;
40// BEGIN android-removed
41// import org.bouncycastle.jce.interfaces.GOST3410PrivateKey;
42// END android-removed
43import org.bouncycastle.util.Arrays;
44import org.bouncycastle.util.Store;
45import org.bouncycastle.x509.X509AttributeCertificate;
46import org.bouncycastle.x509.X509Store;
47
48public class CMSSignedGenerator
49{
50    /**
51     * Default type for the signed data.
52     */
53    public static final String  DATA = CMSObjectIdentifiers.data.getId();
54
55    public static final String  DIGEST_SHA1 = OIWObjectIdentifiers.idSHA1.getId();
56    public static final String  DIGEST_SHA224 = NISTObjectIdentifiers.id_sha224.getId();
57    public static final String  DIGEST_SHA256 = NISTObjectIdentifiers.id_sha256.getId();
58    public static final String  DIGEST_SHA384 = NISTObjectIdentifiers.id_sha384.getId();
59    public static final String  DIGEST_SHA512 = NISTObjectIdentifiers.id_sha512.getId();
60    public static final String  DIGEST_MD5 = PKCSObjectIdentifiers.md5.getId();
61    // BEGIN android-removed
62    // public static final String  DIGEST_GOST3411 = CryptoProObjectIdentifiers.gostR3411.getId();
63    // public static final String  DIGEST_RIPEMD128 = TeleTrusTObjectIdentifiers.ripemd128.getId();
64    // public static final String  DIGEST_RIPEMD160 = TeleTrusTObjectIdentifiers.ripemd160.getId();
65    // public static final String  DIGEST_RIPEMD256 = TeleTrusTObjectIdentifiers.ripemd256.getId();
66    // END android-removed
67
68    public static final String  ENCRYPTION_RSA = PKCSObjectIdentifiers.rsaEncryption.getId();
69    public static final String  ENCRYPTION_DSA = X9ObjectIdentifiers.id_dsa_with_sha1.getId();
70    public static final String  ENCRYPTION_ECDSA = X9ObjectIdentifiers.ecdsa_with_SHA1.getId();
71    public static final String  ENCRYPTION_RSA_PSS = PKCSObjectIdentifiers.id_RSASSA_PSS.getId();
72    // BEGIN android-removed
73    // public static final String  ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94.getId();
74    // public static final String  ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001.getId();
75    // END android-removed
76
77    private static final String  ENCRYPTION_ECDSA_WITH_SHA1 = X9ObjectIdentifiers.ecdsa_with_SHA1.getId();
78    private static final String  ENCRYPTION_ECDSA_WITH_SHA224 = X9ObjectIdentifiers.ecdsa_with_SHA224.getId();
79    private static final String  ENCRYPTION_ECDSA_WITH_SHA256 = X9ObjectIdentifiers.ecdsa_with_SHA256.getId();
80    private static final String  ENCRYPTION_ECDSA_WITH_SHA384 = X9ObjectIdentifiers.ecdsa_with_SHA384.getId();
81    private static final String  ENCRYPTION_ECDSA_WITH_SHA512 = X9ObjectIdentifiers.ecdsa_with_SHA512.getId();
82
83    private static final Set NO_PARAMS = new HashSet();
84    private static final Map EC_ALGORITHMS = new HashMap();
85
86    static
87    {
88        NO_PARAMS.add(ENCRYPTION_DSA);
89        NO_PARAMS.add(ENCRYPTION_ECDSA);
90        NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA1);
91        NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA224);
92        NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA256);
93        NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA384);
94        NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA512);
95
96        EC_ALGORITHMS.put(DIGEST_SHA1, ENCRYPTION_ECDSA_WITH_SHA1);
97        EC_ALGORITHMS.put(DIGEST_SHA224, ENCRYPTION_ECDSA_WITH_SHA224);
98        EC_ALGORITHMS.put(DIGEST_SHA256, ENCRYPTION_ECDSA_WITH_SHA256);
99        EC_ALGORITHMS.put(DIGEST_SHA384, ENCRYPTION_ECDSA_WITH_SHA384);
100        EC_ALGORITHMS.put(DIGEST_SHA512, ENCRYPTION_ECDSA_WITH_SHA512);
101    }
102
103    protected List certs = new ArrayList();
104    protected List crls = new ArrayList();
105    protected List _signers = new ArrayList();
106    protected List signerGens = new ArrayList();
107    protected Map digests = new HashMap();
108
109    protected final SecureRandom rand;
110
111    /**
112     * base constructor
113     */
114    protected CMSSignedGenerator()
115    {
116        this(new SecureRandom());
117    }
118
119    /**
120     * constructor allowing specific source of randomness
121     * @param rand instance of SecureRandom to use
122     */
123    protected CMSSignedGenerator(
124        SecureRandom rand)
125    {
126        this.rand = rand;
127    }
128
129    protected String getEncOID(
130        PrivateKey key,
131        String     digestOID)
132    {
133        String encOID = null;
134
135        if (key instanceof RSAPrivateKey || "RSA".equalsIgnoreCase(key.getAlgorithm()))
136        {
137            encOID = ENCRYPTION_RSA;
138        }
139        else if (key instanceof DSAPrivateKey || "DSA".equalsIgnoreCase(key.getAlgorithm()))
140        {
141            encOID = ENCRYPTION_DSA;
142            if (!digestOID.equals(DIGEST_SHA1))
143            {
144                throw new IllegalArgumentException("can't mix DSA with anything but SHA1");
145            }
146        }
147        else if ("ECDSA".equalsIgnoreCase(key.getAlgorithm()) || "EC".equalsIgnoreCase(key.getAlgorithm()))
148        {
149            encOID = (String)EC_ALGORITHMS.get(digestOID);
150            if (encOID == null)
151            {
152                throw new IllegalArgumentException("can't mix ECDSA with anything but SHA family digests");
153            }
154        }
155        // BEGIN android-removed
156        // else if (key instanceof GOST3410PrivateKey || "GOST3410".equalsIgnoreCase(key.getAlgorithm()))
157        // {
158        //     encOID = ENCRYPTION_GOST3410;
159        // }
160        // else if ("ECGOST3410".equalsIgnoreCase(key.getAlgorithm()))
161        // {
162        //     encOID = ENCRYPTION_ECGOST3410;
163        // }
164        // END android-removed
165
166        return encOID;
167    }
168
169    protected Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, byte[] hash)
170    {
171        Map param = new HashMap();
172        param.put(CMSAttributeTableGenerator.CONTENT_TYPE, contentType);
173        param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId);
174        param.put(CMSAttributeTableGenerator.DIGEST, Arrays.clone(hash));
175        return param;
176    }
177
178    protected ASN1Set getAttributeSet(
179        AttributeTable attr)
180    {
181        if (attr != null)
182        {
183            return new DERSet(attr.toASN1EncodableVector());
184        }
185
186        return null;
187    }
188
189    /**
190     * add the certificates and CRLs contained in the given CertStore
191     * to the pool that will be included in the encoded signature block.
192     * <p>
193     * Note: this assumes the CertStore will support null in the get
194     * methods.
195     * @param certStore CertStore containing the public key certificates and CRLs
196     * @throws java.security.cert.CertStoreException  if an issue occurs processing the CertStore
197     * @throws CMSException  if an issue occurse transforming data from the CertStore into the message
198     * @deprecated use addCertificates and addCRLs
199     */
200    public void addCertificatesAndCRLs(
201        CertStore certStore)
202        throws CertStoreException, CMSException
203    {
204        certs.addAll(CMSUtils.getCertificatesFromStore(certStore));
205        crls.addAll(CMSUtils.getCRLsFromStore(certStore));
206    }
207
208    /**
209     * Add a certificate to the certificate set to be included with the generated SignedData message.
210     *
211     * @param certificate the certificate to be included.
212     * @throws CMSException if the certificate cannot be encoded for adding.
213     */
214    public void addCertificate(
215        X509CertificateHolder certificate)
216        throws CMSException
217    {
218        certs.add(certificate.toASN1Structure());
219    }
220
221    /**
222     * Add the certificates in certStore to the certificate set to be included with the generated SignedData message.
223     *
224     * @param certStore the store containing the certificates to be included.
225     * @throws CMSException if the certificates cannot be encoded for adding.
226     */
227    public void addCertificates(
228        Store certStore)
229        throws CMSException
230    {
231        certs.addAll(CMSUtils.getCertificatesFromStore(certStore));
232    }
233
234    /**
235     * Add a CRL to the CRL set to be included with the generated SignedData message.
236     *
237     * @param crl the CRL to be included.
238     */
239    public void addCRL(X509CRLHolder crl)
240    {
241        crls.add(crl.toASN1Structure());
242    }
243
244    /**
245     * Add the CRLs in crlStore to the CRL set to be included with the generated SignedData message.
246     *
247     * @param crlStore the store containing the CRLs to be included.
248     * @throws CMSException if the CRLs cannot be encoded for adding.
249     */
250    public void addCRLs(
251        Store crlStore)
252        throws CMSException
253    {
254        crls.addAll(CMSUtils.getCRLsFromStore(crlStore));
255    }
256
257    /**
258     * Add the attribute certificates in attrStore to the certificate set to be included with the generated SignedData message.
259     *
260     * @param attrCert the store containing the certificates to be included.
261     * @throws CMSException if the attribute certificate cannot be encoded for adding.
262     */
263    public void addAttributeCertificate(
264        X509AttributeCertificateHolder attrCert)
265        throws CMSException
266    {
267        certs.add(new DERTaggedObject(false, 2, attrCert.toASN1Structure()));
268    }
269
270    /**
271     * Add the attribute certificates in attrStore to the certificate set to be included with the generated SignedData message.
272     *
273     * @param attrStore the store containing the certificates to be included.
274     * @throws CMSException if the attribute certificate cannot be encoded for adding.
275     */
276    public void addAttributeCertificates(
277        Store attrStore)
278        throws CMSException
279    {
280        certs.addAll(CMSUtils.getAttributeCertificatesFromStore(attrStore));
281    }
282
283    // BEGIN android-removed
284    // /**
285    //  * Add a single instance of otherRevocationData to the CRL set to be included with the generated SignedData message.
286    //  *
287    //  * @param otherRevocationInfoFormat the OID specifying the format of the otherRevocationInfo data.
288    //  * @param otherRevocationInfo the otherRevocationInfo ASN.1 structure.
289    //  */
290    // public void addOtherRevocationInfo(
291    //     ASN1ObjectIdentifier   otherRevocationInfoFormat,
292    //     ASN1Encodable          otherRevocationInfo)
293    // {
294    //     crls.add(new DERTaggedObject(false, 1, new OtherRevocationInfoFormat(otherRevocationInfoFormat, otherRevocationInfo)));
295    // }
296    //
297    // /**
298    //  * Add a Store of otherRevocationData to the CRL set to be included with the generated SignedData message.
299    //  *
300    //  * @param otherRevocationInfoFormat the OID specifying the format of the otherRevocationInfo data.
301    //  * @param otherRevocationInfos a Store of otherRevocationInfo data to add.
302    //  */
303    // public void addOtherRevocationInfo(
304    //     ASN1ObjectIdentifier   otherRevocationInfoFormat,
305    //     Store                  otherRevocationInfos)
306    // {
307    //     crls.addAll(CMSUtils.getOthersFromStore(otherRevocationInfoFormat, otherRevocationInfos));
308    // }
309    // END android-removed
310
311    /**
312     * Add the attribute certificates contained in the passed in store to the
313     * generator.
314     *
315     * @param store a store of Version 2 attribute certificates
316     * @throws CMSException if an error occurse processing the store.
317     * @deprecated use basic Store method
318     */
319    public void addAttributeCertificates(
320        X509Store store)
321        throws CMSException
322    {
323        try
324        {
325            for (Iterator it = store.getMatches(null).iterator(); it.hasNext();)
326            {
327                X509AttributeCertificate attrCert = (X509AttributeCertificate)it.next();
328
329                certs.add(new DERTaggedObject(false, 2,
330                             AttributeCertificate.getInstance(ASN1Primitive.fromByteArray(attrCert.getEncoded()))));
331            }
332        }
333        catch (IllegalArgumentException e)
334        {
335            throw new CMSException("error processing attribute certs", e);
336        }
337        catch (IOException e)
338        {
339            throw new CMSException("error processing attribute certs", e);
340        }
341    }
342
343
344    /**
345     * Add a store of precalculated signers to the generator.
346     *
347     * @param signerStore store of signers
348     */
349    public void addSigners(
350        SignerInformationStore    signerStore)
351    {
352        Iterator    it = signerStore.getSigners().iterator();
353
354        while (it.hasNext())
355        {
356            _signers.add(it.next());
357        }
358    }
359
360    public void addSignerInfoGenerator(SignerInfoGenerator infoGen)
361    {
362         signerGens.add(infoGen);
363    }
364
365    /**
366     * Return a map of oids and byte arrays representing the digests calculated on the content during
367     * the last generate.
368     *
369     * @return a map of oids (as String objects) and byte[] representing digests.
370     */
371    public Map getGeneratedDigests()
372    {
373        return new HashMap(digests);
374    }
375}
376