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.ASN1Primitive;
19import org.bouncycastle.asn1.ASN1Set;
20import org.bouncycastle.asn1.DERObjectIdentifier;
21import org.bouncycastle.asn1.DERSet;
22import org.bouncycastle.asn1.DERTaggedObject;
23import org.bouncycastle.asn1.cms.AttributeTable;
24import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
25// BEGIN android-removed
26// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
27// END android-removed
28import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
29import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
30import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
31import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
32import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
33import org.bouncycastle.asn1.x509.AttributeCertificate;
34import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
35// BEGIN android-removed
36// import org.bouncycastle.jce.interfaces.GOST3410PrivateKey;
37// END android-removed
38import org.bouncycastle.util.Store;
39import org.bouncycastle.x509.X509AttributeCertificate;
40import org.bouncycastle.x509.X509Store;
41
42public class CMSSignedGenerator
43{
44    /**
45     * Default type for the signed data.
46     */
47    public static final String  DATA = CMSObjectIdentifiers.data.getId();
48
49    public static final String  DIGEST_SHA1 = OIWObjectIdentifiers.idSHA1.getId();
50    // BEGIN android-removed
51    // public static final String  DIGEST_SHA224 = NISTObjectIdentifiers.id_sha224.getId();
52    // END android-removed
53    public static final String  DIGEST_SHA256 = NISTObjectIdentifiers.id_sha256.getId();
54    public static final String  DIGEST_SHA384 = NISTObjectIdentifiers.id_sha384.getId();
55    public static final String  DIGEST_SHA512 = NISTObjectIdentifiers.id_sha512.getId();
56    public static final String  DIGEST_MD5 = PKCSObjectIdentifiers.md5.getId();
57    // BEGIN android-removed
58    // public static final String  DIGEST_GOST3411 = CryptoProObjectIdentifiers.gostR3411.getId();
59    // public static final String  DIGEST_RIPEMD128 = TeleTrusTObjectIdentifiers.ripemd128.getId();
60    // public static final String  DIGEST_RIPEMD160 = TeleTrusTObjectIdentifiers.ripemd160.getId();
61    // public static final String  DIGEST_RIPEMD256 = TeleTrusTObjectIdentifiers.ripemd256.getId();
62    // END android-removed
63
64    public static final String  ENCRYPTION_RSA = PKCSObjectIdentifiers.rsaEncryption.getId();
65    public static final String  ENCRYPTION_DSA = X9ObjectIdentifiers.id_dsa_with_sha1.getId();
66    public static final String  ENCRYPTION_ECDSA = X9ObjectIdentifiers.ecdsa_with_SHA1.getId();
67    public static final String  ENCRYPTION_RSA_PSS = PKCSObjectIdentifiers.id_RSASSA_PSS.getId();
68    // BEGIN android-removed
69    // public static final String  ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94.getId();
70    // public static final String  ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001.getId();
71    // END android-removed
72
73    private static final String  ENCRYPTION_ECDSA_WITH_SHA1 = X9ObjectIdentifiers.ecdsa_with_SHA1.getId();
74    // BEGIN android-removed
75    // private static final String  ENCRYPTION_ECDSA_WITH_SHA224 = X9ObjectIdentifiers.ecdsa_with_SHA224.getId();
76    // END android-removed
77    private static final String  ENCRYPTION_ECDSA_WITH_SHA256 = X9ObjectIdentifiers.ecdsa_with_SHA256.getId();
78    private static final String  ENCRYPTION_ECDSA_WITH_SHA384 = X9ObjectIdentifiers.ecdsa_with_SHA384.getId();
79    private static final String  ENCRYPTION_ECDSA_WITH_SHA512 = X9ObjectIdentifiers.ecdsa_with_SHA512.getId();
80
81    private static final Set NO_PARAMS = new HashSet();
82    private static final Map EC_ALGORITHMS = new HashMap();
83
84    static
85    {
86        NO_PARAMS.add(ENCRYPTION_DSA);
87        NO_PARAMS.add(ENCRYPTION_ECDSA);
88        NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA1);
89        // BEGIN android-removed
90        // NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA224);
91        // END android-removed
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        // BEGIN android-removed
98        // EC_ALGORITHMS.put(DIGEST_SHA224, ENCRYPTION_ECDSA_WITH_SHA224);
99        // END android-removed
100        EC_ALGORITHMS.put(DIGEST_SHA256, ENCRYPTION_ECDSA_WITH_SHA256);
101        EC_ALGORITHMS.put(DIGEST_SHA384, ENCRYPTION_ECDSA_WITH_SHA384);
102        EC_ALGORITHMS.put(DIGEST_SHA512, ENCRYPTION_ECDSA_WITH_SHA512);
103    }
104
105    protected List certs = new ArrayList();
106    protected List crls = new ArrayList();
107    protected List _signers = new ArrayList();
108    protected List signerGens = new ArrayList();
109    protected Map digests = new HashMap();
110
111    protected final SecureRandom rand;
112
113    /**
114     * base constructor
115     */
116    protected CMSSignedGenerator()
117    {
118        this(new SecureRandom());
119    }
120
121    /**
122     * constructor allowing specific source of randomness
123     * @param rand instance of SecureRandom to use
124     */
125    protected CMSSignedGenerator(
126        SecureRandom rand)
127    {
128        this.rand = rand;
129    }
130
131    protected String getEncOID(
132        PrivateKey key,
133        String     digestOID)
134    {
135        String encOID = null;
136
137        if (key instanceof RSAPrivateKey || "RSA".equalsIgnoreCase(key.getAlgorithm()))
138        {
139            encOID = ENCRYPTION_RSA;
140        }
141        else if (key instanceof DSAPrivateKey || "DSA".equalsIgnoreCase(key.getAlgorithm()))
142        {
143            encOID = ENCRYPTION_DSA;
144            if (!digestOID.equals(DIGEST_SHA1))
145            {
146                throw new IllegalArgumentException("can't mix DSA with anything but SHA1");
147            }
148        }
149        else if ("ECDSA".equalsIgnoreCase(key.getAlgorithm()) || "EC".equalsIgnoreCase(key.getAlgorithm()))
150        {
151            encOID = (String)EC_ALGORITHMS.get(digestOID);
152            if (encOID == null)
153            {
154                throw new IllegalArgumentException("can't mix ECDSA with anything but SHA family digests");
155            }
156        }
157        // BEGIN android-removed
158        // else if (key instanceof GOST3410PrivateKey || "GOST3410".equalsIgnoreCase(key.getAlgorithm()))
159        // {
160        //     encOID = ENCRYPTION_GOST3410;
161        // }
162        // else if ("ECGOST3410".equalsIgnoreCase(key.getAlgorithm()))
163        // {
164        //     encOID = ENCRYPTION_ECGOST3410;
165        // }
166        // END android-removed
167
168        return encOID;
169    }
170
171    protected Map getBaseParameters(DERObjectIdentifier contentType, AlgorithmIdentifier digAlgId, byte[] hash)
172    {
173        Map param = new HashMap();
174        param.put(CMSAttributeTableGenerator.CONTENT_TYPE, contentType);
175        param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId);
176        param.put(CMSAttributeTableGenerator.DIGEST,  hash.clone());
177        return param;
178    }
179
180    protected ASN1Set getAttributeSet(
181        AttributeTable attr)
182    {
183        if (attr != null)
184        {
185            return new DERSet(attr.toASN1EncodableVector());
186        }
187
188        return null;
189    }
190
191    /**
192     * add the certificates and CRLs contained in the given CertStore
193     * to the pool that will be included in the encoded signature block.
194     * <p>
195     * Note: this assumes the CertStore will support null in the get
196     * methods.
197     * @param certStore CertStore containing the public key certificates and CRLs
198     * @throws java.security.cert.CertStoreException  if an issue occurs processing the CertStore
199     * @throws CMSException  if an issue occurse transforming data from the CertStore into the message
200     * @deprecated use addCertificates and addCRLs
201     */
202    public void addCertificatesAndCRLs(
203        CertStore certStore)
204        throws CertStoreException, CMSException
205    {
206        certs.addAll(CMSUtils.getCertificatesFromStore(certStore));
207        crls.addAll(CMSUtils.getCRLsFromStore(certStore));
208    }
209
210    public void addCertificates(
211        Store certStore)
212        throws CMSException
213    {
214        certs.addAll(CMSUtils.getCertificatesFromStore(certStore));
215    }
216
217    public void addCRLs(
218        Store crlStore)
219        throws CMSException
220    {
221        crls.addAll(CMSUtils.getCRLsFromStore(crlStore));
222    }
223
224    public void addAttributeCertificates(
225        Store attrStore)
226        throws CMSException
227    {
228        certs.addAll(CMSUtils.getAttributeCertificatesFromStore(attrStore));
229    }
230
231    /**
232     * Add the attribute certificates contained in the passed in store to the
233     * generator.
234     *
235     * @param store a store of Version 2 attribute certificates
236     * @throws CMSException if an error occurse processing the store.
237     * @deprecated use basic Store method
238     */
239    public void addAttributeCertificates(
240        X509Store store)
241        throws CMSException
242    {
243        try
244        {
245            for (Iterator it = store.getMatches(null).iterator(); it.hasNext();)
246            {
247                X509AttributeCertificate attrCert = (X509AttributeCertificate)it.next();
248
249                certs.add(new DERTaggedObject(false, 2,
250                             AttributeCertificate.getInstance(ASN1Primitive.fromByteArray(attrCert.getEncoded()))));
251            }
252        }
253        catch (IllegalArgumentException e)
254        {
255            throw new CMSException("error processing attribute certs", e);
256        }
257        catch (IOException e)
258        {
259            throw new CMSException("error processing attribute certs", e);
260        }
261    }
262
263
264    /**
265     * Add a store of precalculated signers to the generator.
266     *
267     * @param signerStore store of signers
268     */
269    public void addSigners(
270        SignerInformationStore    signerStore)
271    {
272        Iterator    it = signerStore.getSigners().iterator();
273
274        while (it.hasNext())
275        {
276            _signers.add(it.next());
277        }
278    }
279
280    public void addSignerInfoGenerator(SignerInfoGenerator infoGen)
281    {
282         signerGens.add(infoGen);
283    }
284
285    /**
286     * Return a map of oids and byte arrays representing the digests calculated on the content during
287     * the last generate.
288     *
289     * @return a map of oids (as String objects) and byte[] representing digests.
290     */
291    public Map getGeneratedDigests()
292    {
293        return new HashMap(digests);
294    }
295}
296