1183234Ssimon/* crypto/cms/cms_sd.c */
2183234Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3183234Ssimon * project.
4183234Ssimon */
5183234Ssimon/* ====================================================================
6183234Ssimon * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
7183234Ssimon *
8183234Ssimon * Redistribution and use in source and binary forms, with or without
9183234Ssimon * modification, are permitted provided that the following conditions
10183234Ssimon * are met:
11183234Ssimon *
12183234Ssimon * 1. Redistributions of source code must retain the above copyright
13183234Ssimon *    notice, this list of conditions and the following disclaimer.
14183234Ssimon *
15183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright
16183234Ssimon *    notice, this list of conditions and the following disclaimer in
17183234Ssimon *    the documentation and/or other materials provided with the
18183234Ssimon *    distribution.
19183234Ssimon *
20183234Ssimon * 3. All advertising materials mentioning features or use of this
21183234Ssimon *    software must display the following acknowledgment:
22183234Ssimon *    "This product includes software developed by the OpenSSL Project
23183234Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24183234Ssimon *
25183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26183234Ssimon *    endorse or promote products derived from this software without
27183234Ssimon *    prior written permission. For written permission, please contact
28183234Ssimon *    licensing@OpenSSL.org.
29183234Ssimon *
30183234Ssimon * 5. Products derived from this software may not be called "OpenSSL"
31183234Ssimon *    nor may "OpenSSL" appear in their names without prior written
32183234Ssimon *    permission of the OpenSSL Project.
33183234Ssimon *
34183234Ssimon * 6. Redistributions of any form whatsoever must retain the following
35183234Ssimon *    acknowledgment:
36183234Ssimon *    "This product includes software developed by the OpenSSL Project
37183234Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38183234Ssimon *
39183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42183234Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
51183234Ssimon * ====================================================================
52183234Ssimon */
53183234Ssimon
54183234Ssimon#include "cryptlib.h"
55183234Ssimon#include <openssl/asn1t.h>
56183234Ssimon#include <openssl/pem.h>
57183234Ssimon#include <openssl/x509v3.h>
58183234Ssimon#include <openssl/err.h>
59183234Ssimon#include <openssl/cms.h>
60183234Ssimon#include "cms_lcl.h"
61238405Sjkim#include "asn1_locl.h"
62183234Ssimon
63183234Ssimon/* CMS SignedData Utilities */
64183234Ssimon
65183234SsimonDECLARE_ASN1_ITEM(CMS_SignedData)
66183234Ssimon
67183234Ssimonstatic CMS_SignedData *cms_get0_signed(CMS_ContentInfo *cms)
68183234Ssimon	{
69183234Ssimon	if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_signed)
70183234Ssimon		{
71183234Ssimon		CMSerr(CMS_F_CMS_GET0_SIGNED, CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA);
72183234Ssimon		return NULL;
73183234Ssimon		}
74183234Ssimon	return cms->d.signedData;
75183234Ssimon	}
76183234Ssimon
77183234Ssimonstatic CMS_SignedData *cms_signed_data_init(CMS_ContentInfo *cms)
78183234Ssimon	{
79183234Ssimon	if (cms->d.other == NULL)
80183234Ssimon		{
81183234Ssimon		cms->d.signedData = M_ASN1_new_of(CMS_SignedData);
82183234Ssimon		if (!cms->d.signedData)
83183234Ssimon			{
84183234Ssimon			CMSerr(CMS_F_CMS_SIGNED_DATA_INIT, ERR_R_MALLOC_FAILURE);
85183234Ssimon			return NULL;
86183234Ssimon			}
87183234Ssimon		cms->d.signedData->version = 1;
88183234Ssimon		cms->d.signedData->encapContentInfo->eContentType =
89183234Ssimon						OBJ_nid2obj(NID_pkcs7_data);
90183234Ssimon		cms->d.signedData->encapContentInfo->partial = 1;
91183234Ssimon		ASN1_OBJECT_free(cms->contentType);
92183234Ssimon		cms->contentType = OBJ_nid2obj(NID_pkcs7_signed);
93183234Ssimon		return cms->d.signedData;
94183234Ssimon		}
95183234Ssimon	return cms_get0_signed(cms);
96183234Ssimon	}
97183234Ssimon
98183234Ssimon/* Just initialize SignedData e.g. for certs only structure */
99183234Ssimon
100183234Ssimonint CMS_SignedData_init(CMS_ContentInfo *cms)
101183234Ssimon	{
102183234Ssimon	if (cms_signed_data_init(cms))
103183234Ssimon		return 1;
104183234Ssimon	else
105183234Ssimon		return 0;
106183234Ssimon	}
107183234Ssimon
108183234Ssimon/* Check structures and fixup version numbers (if necessary) */
109183234Ssimon
110183234Ssimonstatic void cms_sd_set_version(CMS_SignedData *sd)
111183234Ssimon	{
112183234Ssimon	int i;
113183234Ssimon	CMS_CertificateChoices *cch;
114183234Ssimon	CMS_RevocationInfoChoice *rch;
115183234Ssimon	CMS_SignerInfo *si;
116183234Ssimon
117183234Ssimon	for (i = 0; i < sk_CMS_CertificateChoices_num(sd->certificates); i++)
118183234Ssimon		{
119183234Ssimon		cch = sk_CMS_CertificateChoices_value(sd->certificates, i);
120183234Ssimon		if (cch->type == CMS_CERTCHOICE_OTHER)
121183234Ssimon			{
122183234Ssimon			if (sd->version < 5)
123183234Ssimon				sd->version = 5;
124183234Ssimon			}
125183234Ssimon		else if (cch->type == CMS_CERTCHOICE_V2ACERT)
126183234Ssimon			{
127183234Ssimon			if (sd->version < 4)
128183234Ssimon				sd->version = 4;
129183234Ssimon			}
130183234Ssimon		else if (cch->type == CMS_CERTCHOICE_V1ACERT)
131183234Ssimon			{
132183234Ssimon			if (sd->version < 3)
133183234Ssimon				sd->version = 3;
134183234Ssimon			}
135183234Ssimon		}
136183234Ssimon
137183234Ssimon	for (i = 0; i < sk_CMS_RevocationInfoChoice_num(sd->crls); i++)
138183234Ssimon		{
139183234Ssimon		rch = sk_CMS_RevocationInfoChoice_value(sd->crls, i);
140183234Ssimon		if (rch->type == CMS_REVCHOICE_OTHER)
141183234Ssimon			{
142183234Ssimon			if (sd->version < 5)
143183234Ssimon				sd->version = 5;
144183234Ssimon			}
145183234Ssimon		}
146183234Ssimon
147183234Ssimon	if ((OBJ_obj2nid(sd->encapContentInfo->eContentType) != NID_pkcs7_data)
148183234Ssimon			&& (sd->version < 3))
149183234Ssimon		sd->version = 3;
150183234Ssimon
151183234Ssimon	for (i = 0; i < sk_CMS_SignerInfo_num(sd->signerInfos); i++)
152183234Ssimon		{
153183234Ssimon		si = sk_CMS_SignerInfo_value(sd->signerInfos, i);
154183234Ssimon		if (si->sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
155183234Ssimon			{
156183234Ssimon			if (si->version < 3)
157183234Ssimon				si->version = 3;
158183234Ssimon			if (sd->version < 3)
159183234Ssimon				sd->version = 3;
160183234Ssimon			}
161279264Sdelphij		else if (si->version < 1)
162279264Sdelphij			si->version = 1;
163183234Ssimon		}
164183234Ssimon
165183234Ssimon	if (sd->version < 1)
166183234Ssimon		sd->version = 1;
167183234Ssimon
168183234Ssimon	}
169183234Ssimon
170183234Ssimon/* Copy an existing messageDigest value */
171183234Ssimon
172183234Ssimonstatic int cms_copy_messageDigest(CMS_ContentInfo *cms, CMS_SignerInfo *si)
173183234Ssimon	{
174183234Ssimon	STACK_OF(CMS_SignerInfo) *sinfos;
175183234Ssimon	CMS_SignerInfo *sitmp;
176183234Ssimon	int i;
177183234Ssimon	sinfos = CMS_get0_SignerInfos(cms);
178183234Ssimon	for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
179183234Ssimon		{
180183234Ssimon		ASN1_OCTET_STRING *messageDigest;
181183234Ssimon		sitmp = sk_CMS_SignerInfo_value(sinfos, i);
182183234Ssimon		if (sitmp == si)
183183234Ssimon			continue;
184183234Ssimon		if (CMS_signed_get_attr_count(sitmp) < 0)
185183234Ssimon			continue;
186183234Ssimon		if (OBJ_cmp(si->digestAlgorithm->algorithm,
187183234Ssimon				sitmp->digestAlgorithm->algorithm))
188183234Ssimon			continue;
189183234Ssimon		messageDigest = CMS_signed_get0_data_by_OBJ(sitmp,
190183234Ssimon					OBJ_nid2obj(NID_pkcs9_messageDigest),
191183234Ssimon					-3, V_ASN1_OCTET_STRING);
192183234Ssimon		if (!messageDigest)
193183234Ssimon			{
194183234Ssimon			CMSerr(CMS_F_CMS_COPY_MESSAGEDIGEST,
195183234Ssimon				CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE);
196183234Ssimon			return 0;
197183234Ssimon			}
198183234Ssimon
199183234Ssimon		if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest,
200183234Ssimon						V_ASN1_OCTET_STRING,
201183234Ssimon						messageDigest, -1))
202183234Ssimon			return 1;
203183234Ssimon		else
204183234Ssimon			return 0;
205183234Ssimon		}
206183234Ssimon		CMSerr(CMS_F_CMS_COPY_MESSAGEDIGEST, CMS_R_NO_MATCHING_DIGEST);
207183234Ssimon		return 0;
208183234Ssimon	}
209183234Ssimon
210183234Ssimonint cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type)
211183234Ssimon	{
212183234Ssimon	switch(type)
213183234Ssimon		{
214183234Ssimon		case CMS_SIGNERINFO_ISSUER_SERIAL:
215183234Ssimon		sid->d.issuerAndSerialNumber =
216183234Ssimon			M_ASN1_new_of(CMS_IssuerAndSerialNumber);
217183234Ssimon		if (!sid->d.issuerAndSerialNumber)
218183234Ssimon			goto merr;
219183234Ssimon		if (!X509_NAME_set(&sid->d.issuerAndSerialNumber->issuer,
220183234Ssimon					X509_get_issuer_name(cert)))
221183234Ssimon			goto merr;
222238405Sjkim		if (!ASN1_STRING_copy(
223238405Sjkim			sid->d.issuerAndSerialNumber->serialNumber,
224238405Sjkim				X509_get_serialNumber(cert)))
225183234Ssimon			goto merr;
226183234Ssimon		break;
227183234Ssimon
228183234Ssimon		case CMS_SIGNERINFO_KEYIDENTIFIER:
229183234Ssimon		if (!cert->skid)
230183234Ssimon			{
231183234Ssimon			CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER,
232183234Ssimon					CMS_R_CERTIFICATE_HAS_NO_KEYID);
233183234Ssimon			return 0;
234183234Ssimon			}
235183234Ssimon		sid->d.subjectKeyIdentifier = ASN1_STRING_dup(cert->skid);
236183234Ssimon		if (!sid->d.subjectKeyIdentifier)
237183234Ssimon			goto merr;
238183234Ssimon		break;
239183234Ssimon
240183234Ssimon		default:
241183234Ssimon		CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, CMS_R_UNKNOWN_ID);
242183234Ssimon		return 0;
243183234Ssimon		}
244183234Ssimon
245183234Ssimon	sid->type = type;
246183234Ssimon
247183234Ssimon	return 1;
248183234Ssimon
249183234Ssimon	merr:
250183234Ssimon	CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, ERR_R_MALLOC_FAILURE);
251183234Ssimon	return 0;
252183234Ssimon
253183234Ssimon	}
254183234Ssimon
255183234Ssimonint cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid,
256183234Ssimon					ASN1_OCTET_STRING **keyid,
257183234Ssimon					X509_NAME **issuer, ASN1_INTEGER **sno)
258183234Ssimon	{
259183234Ssimon	if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL)
260183234Ssimon		{
261183234Ssimon		if (issuer)
262183234Ssimon			*issuer = sid->d.issuerAndSerialNumber->issuer;
263183234Ssimon		if (sno)
264183234Ssimon			*sno = sid->d.issuerAndSerialNumber->serialNumber;
265183234Ssimon		}
266183234Ssimon	else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
267183234Ssimon		{
268183234Ssimon		if (keyid)
269183234Ssimon			*keyid = sid->d.subjectKeyIdentifier;
270183234Ssimon		}
271183234Ssimon	else
272183234Ssimon		return 0;
273183234Ssimon	return 1;
274183234Ssimon	}
275183234Ssimon
276183234Ssimonint cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert)
277183234Ssimon	{
278183234Ssimon	int ret;
279183234Ssimon	if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL)
280183234Ssimon		{
281183234Ssimon		ret = X509_NAME_cmp(sid->d.issuerAndSerialNumber->issuer,
282183234Ssimon					X509_get_issuer_name(cert));
283183234Ssimon		if (ret)
284183234Ssimon			return ret;
285183234Ssimon		return ASN1_INTEGER_cmp(sid->d.issuerAndSerialNumber->serialNumber,
286183234Ssimon					X509_get_serialNumber(cert));
287183234Ssimon		}
288183234Ssimon	else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
289183234Ssimon		{
290183234Ssimon		X509_check_purpose(cert, -1, -1);
291183234Ssimon		if (!cert->skid)
292183234Ssimon			return -1;
293183234Ssimon		return ASN1_OCTET_STRING_cmp(sid->d.subjectKeyIdentifier,
294183234Ssimon							cert->skid);
295183234Ssimon		}
296183234Ssimon	else
297183234Ssimon		return -1;
298183234Ssimon	}
299183234Ssimon
300183234SsimonCMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
301183234Ssimon			X509 *signer, EVP_PKEY *pk, const EVP_MD *md,
302183234Ssimon			unsigned int flags)
303183234Ssimon	{
304183234Ssimon	CMS_SignedData *sd;
305183234Ssimon	CMS_SignerInfo *si = NULL;
306183234Ssimon	X509_ALGOR *alg;
307183234Ssimon	int i, type;
308183234Ssimon	if(!X509_check_private_key(signer, pk))
309183234Ssimon		{
310183234Ssimon		CMSerr(CMS_F_CMS_ADD1_SIGNER,
311183234Ssimon			CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
312183234Ssimon                return NULL;
313183234Ssimon		}
314183234Ssimon	sd = cms_signed_data_init(cms);
315183234Ssimon	if (!sd)
316183234Ssimon		goto err;
317183234Ssimon	si = M_ASN1_new_of(CMS_SignerInfo);
318183234Ssimon	if (!si)
319183234Ssimon		goto merr;
320183234Ssimon	X509_check_purpose(signer, -1, -1);
321183234Ssimon
322183234Ssimon	CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY);
323183234Ssimon	CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509);
324183234Ssimon
325183234Ssimon	si->pkey = pk;
326183234Ssimon	si->signer = signer;
327183234Ssimon
328183234Ssimon	if (flags & CMS_USE_KEYID)
329183234Ssimon		{
330183234Ssimon		si->version = 3;
331183234Ssimon		if (sd->version < 3)
332183234Ssimon			sd->version = 3;
333183234Ssimon		type = CMS_SIGNERINFO_KEYIDENTIFIER;
334183234Ssimon		}
335183234Ssimon	else
336183234Ssimon		{
337183234Ssimon		type = CMS_SIGNERINFO_ISSUER_SERIAL;
338183234Ssimon		si->version = 1;
339183234Ssimon		}
340183234Ssimon
341183234Ssimon	if (!cms_set1_SignerIdentifier(si->sid, signer, type))
342183234Ssimon		goto err;
343183234Ssimon
344183234Ssimon	if (md == NULL)
345238405Sjkim		{
346238405Sjkim		int def_nid;
347238405Sjkim		if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0)
348238405Sjkim			goto err;
349238405Sjkim		md = EVP_get_digestbynid(def_nid);
350238405Sjkim		if (md == NULL)
351238405Sjkim			{
352238405Sjkim			CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DEFAULT_DIGEST);
353238405Sjkim			goto err;
354238405Sjkim			}
355238405Sjkim		}
356183234Ssimon
357238405Sjkim	if (!md)
358183234Ssimon		{
359238405Sjkim		CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DIGEST_SET);
360183234Ssimon		goto err;
361183234Ssimon		}
362183234Ssimon
363183234Ssimon	cms_DigestAlgorithm_set(si->digestAlgorithm, md);
364183234Ssimon
365183234Ssimon	/* See if digest is present in digestAlgorithms */
366183234Ssimon	for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++)
367183234Ssimon		{
368183234Ssimon		ASN1_OBJECT *aoid;
369183234Ssimon		alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i);
370183234Ssimon		X509_ALGOR_get0(&aoid, NULL, NULL, alg);
371183234Ssimon		if (OBJ_obj2nid(aoid) == EVP_MD_type(md))
372183234Ssimon			break;
373183234Ssimon		}
374183234Ssimon
375183234Ssimon	if (i == sk_X509_ALGOR_num(sd->digestAlgorithms))
376183234Ssimon		{
377183234Ssimon		alg = X509_ALGOR_new();
378183234Ssimon		if (!alg)
379183234Ssimon			goto merr;
380183234Ssimon		cms_DigestAlgorithm_set(alg, md);
381183234Ssimon		if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg))
382183234Ssimon			{
383183234Ssimon			X509_ALGOR_free(alg);
384183234Ssimon			goto merr;
385183234Ssimon			}
386183234Ssimon		}
387183234Ssimon
388238405Sjkim	if (pk->ameth && pk->ameth->pkey_ctrl)
389183234Ssimon		{
390238405Sjkim		i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_SIGN,
391238405Sjkim						0, si);
392238405Sjkim		if (i == -2)
393238405Sjkim			{
394238405Sjkim			CMSerr(CMS_F_CMS_ADD1_SIGNER,
395183234Ssimon				CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
396238405Sjkim			goto err;
397238405Sjkim			}
398238405Sjkim		if (i <= 0)
399238405Sjkim			{
400238405Sjkim			CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_CTRL_FAILURE);
401238405Sjkim			goto err;
402238405Sjkim			}
403183234Ssimon		}
404183234Ssimon
405183234Ssimon	if (!(flags & CMS_NOATTR))
406183234Ssimon		{
407183234Ssimon		/* Initialialize signed attributes strutucture so other
408183234Ssimon		 * attributes such as signing time etc are added later
409183234Ssimon		 * even if we add none here.
410183234Ssimon		 */
411183234Ssimon		if (!si->signedAttrs)
412183234Ssimon			{
413183234Ssimon			si->signedAttrs = sk_X509_ATTRIBUTE_new_null();
414183234Ssimon			if (!si->signedAttrs)
415183234Ssimon				goto merr;
416183234Ssimon			}
417183234Ssimon
418183234Ssimon		if (!(flags & CMS_NOSMIMECAP))
419183234Ssimon			{
420183234Ssimon			STACK_OF(X509_ALGOR) *smcap = NULL;
421183234Ssimon			i = CMS_add_standard_smimecap(&smcap);
422183234Ssimon			if (i)
423183234Ssimon				i = CMS_add_smimecap(si, smcap);
424183234Ssimon			sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
425183234Ssimon			if (!i)
426183234Ssimon				goto merr;
427183234Ssimon			}
428183234Ssimon		if (flags & CMS_REUSE_DIGEST)
429183234Ssimon			{
430183234Ssimon			if (!cms_copy_messageDigest(cms, si))
431183234Ssimon				goto err;
432183234Ssimon			if (!(flags & CMS_PARTIAL) &&
433183234Ssimon					!CMS_SignerInfo_sign(si))
434183234Ssimon				goto err;
435183234Ssimon			}
436183234Ssimon		}
437183234Ssimon
438183234Ssimon	if (!(flags & CMS_NOCERTS))
439183234Ssimon		{
440183234Ssimon		/* NB ignore -1 return for duplicate cert */
441183234Ssimon		if (!CMS_add1_cert(cms, signer))
442183234Ssimon			goto merr;
443183234Ssimon		}
444183234Ssimon
445183234Ssimon	if (!sd->signerInfos)
446183234Ssimon		sd->signerInfos = sk_CMS_SignerInfo_new_null();
447183234Ssimon	if (!sd->signerInfos ||
448183234Ssimon		!sk_CMS_SignerInfo_push(sd->signerInfos, si))
449183234Ssimon		goto merr;
450183234Ssimon
451183234Ssimon	return si;
452183234Ssimon
453183234Ssimon	merr:
454183234Ssimon	CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE);
455183234Ssimon	err:
456183234Ssimon	if (si)
457183234Ssimon		M_ASN1_free_of(si, CMS_SignerInfo);
458183234Ssimon	return NULL;
459183234Ssimon
460183234Ssimon	}
461183234Ssimon
462183234Ssimonstatic int cms_add1_signingTime(CMS_SignerInfo *si, ASN1_TIME *t)
463183234Ssimon	{
464183234Ssimon	ASN1_TIME *tt;
465183234Ssimon	int r = 0;
466183234Ssimon	if (t)
467183234Ssimon		tt = t;
468183234Ssimon	else
469183234Ssimon		tt = X509_gmtime_adj(NULL, 0);
470183234Ssimon
471183234Ssimon	if (!tt)
472183234Ssimon		goto merr;
473183234Ssimon
474183234Ssimon	if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_signingTime,
475183234Ssimon						tt->type, tt, -1) <= 0)
476183234Ssimon		goto merr;
477183234Ssimon
478183234Ssimon	r = 1;
479183234Ssimon
480183234Ssimon	merr:
481183234Ssimon
482183234Ssimon	if (!t)
483183234Ssimon		ASN1_TIME_free(tt);
484183234Ssimon
485183234Ssimon	if (!r)
486183234Ssimon		CMSerr(CMS_F_CMS_ADD1_SIGNINGTIME, ERR_R_MALLOC_FAILURE);
487183234Ssimon
488183234Ssimon	return r;
489183234Ssimon
490183234Ssimon	}
491183234Ssimon
492183234SsimonSTACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms)
493183234Ssimon	{
494183234Ssimon	CMS_SignedData *sd;
495183234Ssimon	sd = cms_get0_signed(cms);
496183234Ssimon	if (!sd)
497183234Ssimon		return NULL;
498183234Ssimon	return sd->signerInfos;
499183234Ssimon	}
500183234Ssimon
501183234SsimonSTACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms)
502183234Ssimon	{
503183234Ssimon	STACK_OF(X509) *signers = NULL;
504183234Ssimon	STACK_OF(CMS_SignerInfo) *sinfos;
505183234Ssimon	CMS_SignerInfo *si;
506183234Ssimon	int i;
507183234Ssimon	sinfos = CMS_get0_SignerInfos(cms);
508183234Ssimon	for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
509183234Ssimon		{
510183234Ssimon		si = sk_CMS_SignerInfo_value(sinfos, i);
511183234Ssimon		if (si->signer)
512183234Ssimon			{
513183234Ssimon			if (!signers)
514183234Ssimon				{
515183234Ssimon				signers = sk_X509_new_null();
516183234Ssimon				if (!signers)
517183234Ssimon					return NULL;
518183234Ssimon				}
519183234Ssimon			if (!sk_X509_push(signers, si->signer))
520183234Ssimon				{
521183234Ssimon				sk_X509_free(signers);
522183234Ssimon				return NULL;
523183234Ssimon				}
524183234Ssimon			}
525183234Ssimon		}
526183234Ssimon	return signers;
527183234Ssimon	}
528183234Ssimon
529183234Ssimonvoid CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer)
530183234Ssimon	{
531183234Ssimon	if (signer)
532183234Ssimon		{
533183234Ssimon		CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509);
534183234Ssimon		if (si->pkey)
535183234Ssimon			EVP_PKEY_free(si->pkey);
536183234Ssimon		si->pkey = X509_get_pubkey(signer);
537183234Ssimon		}
538183234Ssimon	if (si->signer)
539183234Ssimon		X509_free(si->signer);
540183234Ssimon	si->signer = signer;
541183234Ssimon	}
542183234Ssimon
543183234Ssimonint CMS_SignerInfo_get0_signer_id(CMS_SignerInfo *si,
544183234Ssimon					ASN1_OCTET_STRING **keyid,
545183234Ssimon					X509_NAME **issuer, ASN1_INTEGER **sno)
546183234Ssimon	{
547183234Ssimon	return cms_SignerIdentifier_get0_signer_id(si->sid, keyid, issuer, sno);
548183234Ssimon	}
549183234Ssimon
550183234Ssimonint CMS_SignerInfo_cert_cmp(CMS_SignerInfo *si, X509 *cert)
551183234Ssimon	{
552183234Ssimon	return cms_SignerIdentifier_cert_cmp(si->sid, cert);
553183234Ssimon	}
554183234Ssimon
555183234Ssimonint CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *scerts,
556183234Ssimon				unsigned int flags)
557183234Ssimon	{
558183234Ssimon	CMS_SignedData *sd;
559183234Ssimon	CMS_SignerInfo *si;
560183234Ssimon	CMS_CertificateChoices *cch;
561183234Ssimon	STACK_OF(CMS_CertificateChoices) *certs;
562183234Ssimon	X509 *x;
563183234Ssimon	int i, j;
564183234Ssimon	int ret = 0;
565183234Ssimon	sd = cms_get0_signed(cms);
566183234Ssimon	if (!sd)
567183234Ssimon		return -1;
568183234Ssimon	certs = sd->certificates;
569183234Ssimon	for (i = 0; i < sk_CMS_SignerInfo_num(sd->signerInfos); i++)
570183234Ssimon		{
571183234Ssimon		si = sk_CMS_SignerInfo_value(sd->signerInfos, i);
572183234Ssimon		if (si->signer)
573183234Ssimon			continue;
574183234Ssimon
575183234Ssimon		for (j = 0; j < sk_X509_num(scerts); j++)
576183234Ssimon			{
577183234Ssimon			x = sk_X509_value(scerts, j);
578183234Ssimon			if (CMS_SignerInfo_cert_cmp(si, x) == 0)
579183234Ssimon				{
580183234Ssimon				CMS_SignerInfo_set1_signer_cert(si, x);
581183234Ssimon				ret++;
582183234Ssimon				break;
583183234Ssimon				}
584183234Ssimon			}
585183234Ssimon
586183234Ssimon		if (si->signer || (flags & CMS_NOINTERN))
587183234Ssimon			continue;
588183234Ssimon
589183234Ssimon		for (j = 0; j < sk_CMS_CertificateChoices_num(certs); j++)
590183234Ssimon			{
591183234Ssimon			cch = sk_CMS_CertificateChoices_value(certs, j);
592183234Ssimon			if (cch->type != 0)
593183234Ssimon				continue;
594183234Ssimon			x = cch->d.certificate;
595183234Ssimon			if (CMS_SignerInfo_cert_cmp(si, x) == 0)
596183234Ssimon				{
597183234Ssimon				CMS_SignerInfo_set1_signer_cert(si, x);
598183234Ssimon				ret++;
599183234Ssimon				break;
600183234Ssimon				}
601183234Ssimon			}
602183234Ssimon		}
603183234Ssimon	return ret;
604183234Ssimon	}
605183234Ssimon
606183234Ssimonvoid CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk, X509 **signer,
607183234Ssimon					X509_ALGOR **pdig, X509_ALGOR **psig)
608183234Ssimon	{
609183234Ssimon	if (pk)
610183234Ssimon		*pk = si->pkey;
611183234Ssimon	if (signer)
612183234Ssimon		*signer = si->signer;
613183234Ssimon	if (pdig)
614183234Ssimon		*pdig = si->digestAlgorithm;
615183234Ssimon	if (psig)
616183234Ssimon		*psig = si->signatureAlgorithm;
617183234Ssimon	}
618183234Ssimon
619183234Ssimonstatic int cms_SignerInfo_content_sign(CMS_ContentInfo *cms,
620183234Ssimon					CMS_SignerInfo *si, BIO *chain)
621183234Ssimon	{
622183234Ssimon	EVP_MD_CTX mctx;
623183234Ssimon	int r = 0;
624183234Ssimon	EVP_MD_CTX_init(&mctx);
625183234Ssimon
626183234Ssimon
627183234Ssimon	if (!si->pkey)
628183234Ssimon		{
629183234Ssimon		CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, CMS_R_NO_PRIVATE_KEY);
630183234Ssimon		return 0;
631183234Ssimon		}
632183234Ssimon
633183234Ssimon	if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm))
634183234Ssimon		goto err;
635183234Ssimon
636183234Ssimon	/* If any signed attributes calculate and add messageDigest attribute */
637183234Ssimon
638183234Ssimon	if (CMS_signed_get_attr_count(si) >= 0)
639183234Ssimon		{
640183234Ssimon		ASN1_OBJECT *ctype =
641183234Ssimon			cms->d.signedData->encapContentInfo->eContentType;
642183234Ssimon		unsigned char md[EVP_MAX_MD_SIZE];
643183234Ssimon		unsigned int mdlen;
644238405Sjkim		if (!EVP_DigestFinal_ex(&mctx, md, &mdlen))
645238405Sjkim			goto err;
646183234Ssimon		if (!CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest,
647183234Ssimon						V_ASN1_OCTET_STRING,
648183234Ssimon						md, mdlen))
649183234Ssimon			goto err;
650183234Ssimon		/* Copy content type across */
651183234Ssimon		if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_contentType,
652183234Ssimon					V_ASN1_OBJECT, ctype, -1) <= 0)
653183234Ssimon			goto err;
654183234Ssimon		if (!CMS_SignerInfo_sign(si))
655183234Ssimon			goto err;
656183234Ssimon		}
657183234Ssimon	else
658183234Ssimon		{
659183234Ssimon		unsigned char *sig;
660183234Ssimon		unsigned int siglen;
661183234Ssimon		sig = OPENSSL_malloc(EVP_PKEY_size(si->pkey));
662183234Ssimon		if (!sig)
663183234Ssimon			{
664183234Ssimon			CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN,
665183234Ssimon					ERR_R_MALLOC_FAILURE);
666183234Ssimon			goto err;
667183234Ssimon			}
668183234Ssimon		if (!EVP_SignFinal(&mctx, sig, &siglen, si->pkey))
669183234Ssimon			{
670183234Ssimon			CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN,
671183234Ssimon					CMS_R_SIGNFINAL_ERROR);
672183234Ssimon			OPENSSL_free(sig);
673183234Ssimon			goto err;
674183234Ssimon			}
675183234Ssimon		ASN1_STRING_set0(si->signature, sig, siglen);
676183234Ssimon		}
677183234Ssimon
678183234Ssimon	r = 1;
679183234Ssimon
680183234Ssimon	err:
681183234Ssimon	EVP_MD_CTX_cleanup(&mctx);
682183234Ssimon	return r;
683183234Ssimon
684183234Ssimon	}
685183234Ssimon
686183234Ssimonint cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain)
687183234Ssimon	{
688183234Ssimon	STACK_OF(CMS_SignerInfo) *sinfos;
689183234Ssimon	CMS_SignerInfo *si;
690183234Ssimon	int i;
691183234Ssimon	sinfos = CMS_get0_SignerInfos(cms);
692183234Ssimon	for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
693183234Ssimon		{
694183234Ssimon		si = sk_CMS_SignerInfo_value(sinfos, i);
695183234Ssimon		if (!cms_SignerInfo_content_sign(cms, si, chain))
696183234Ssimon			return 0;
697183234Ssimon		}
698183234Ssimon	cms->d.signedData->encapContentInfo->partial = 0;
699183234Ssimon	return 1;
700183234Ssimon	}
701183234Ssimon
702183234Ssimonint CMS_SignerInfo_sign(CMS_SignerInfo *si)
703183234Ssimon	{
704183234Ssimon	EVP_MD_CTX mctx;
705238405Sjkim	EVP_PKEY_CTX *pctx;
706183234Ssimon	unsigned char *abuf = NULL;
707183234Ssimon	int alen;
708238405Sjkim	size_t siglen;
709183234Ssimon	const EVP_MD *md = NULL;
710183234Ssimon
711183234Ssimon	md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
712183234Ssimon	if (md == NULL)
713183234Ssimon		return 0;
714183234Ssimon
715183234Ssimon	EVP_MD_CTX_init(&mctx);
716183234Ssimon
717183234Ssimon	if (CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1) < 0)
718183234Ssimon		{
719183234Ssimon		if (!cms_add1_signingTime(si, NULL))
720183234Ssimon			goto err;
721183234Ssimon		}
722183234Ssimon
723238405Sjkim	if (EVP_DigestSignInit(&mctx, &pctx, md, NULL, si->pkey) <= 0)
724183234Ssimon		goto err;
725183234Ssimon
726183234Ssimon	if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
727183234Ssimon				EVP_PKEY_CTRL_CMS_SIGN, 0, si) <= 0)
728183234Ssimon		{
729183234Ssimon		CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR);
730183234Ssimon		goto err;
731183234Ssimon		}
732183234Ssimon
733183234Ssimon	alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs,&abuf,
734183234Ssimon				ASN1_ITEM_rptr(CMS_Attributes_Sign));
735183234Ssimon	if(!abuf)
736183234Ssimon		goto err;
737238405Sjkim	if (EVP_DigestSignUpdate(&mctx, abuf, alen) <= 0)
738183234Ssimon		goto err;
739238405Sjkim	if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0)
740238405Sjkim		goto err;
741183234Ssimon	OPENSSL_free(abuf);
742183234Ssimon	abuf = OPENSSL_malloc(siglen);
743183234Ssimon	if(!abuf)
744183234Ssimon		goto err;
745238405Sjkim	if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0)
746183234Ssimon		goto err;
747238405Sjkim
748183234Ssimon	if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
749183234Ssimon				EVP_PKEY_CTRL_CMS_SIGN, 1, si) <= 0)
750183234Ssimon		{
751183234Ssimon		CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR);
752183234Ssimon		goto err;
753183234Ssimon		}
754238405Sjkim
755183234Ssimon	EVP_MD_CTX_cleanup(&mctx);
756183234Ssimon
757183234Ssimon	ASN1_STRING_set0(si->signature, abuf, siglen);
758183234Ssimon
759183234Ssimon	return 1;
760183234Ssimon
761183234Ssimon	err:
762183234Ssimon	if (abuf)
763183234Ssimon		OPENSSL_free(abuf);
764183234Ssimon	EVP_MD_CTX_cleanup(&mctx);
765183234Ssimon	return 0;
766183234Ssimon
767183234Ssimon	}
768183234Ssimon
769183234Ssimonint CMS_SignerInfo_verify(CMS_SignerInfo *si)
770183234Ssimon	{
771183234Ssimon	EVP_MD_CTX mctx;
772238405Sjkim	EVP_PKEY_CTX *pctx;
773183234Ssimon	unsigned char *abuf = NULL;
774183234Ssimon	int alen, r = -1;
775183234Ssimon	const EVP_MD *md = NULL;
776183234Ssimon
777183234Ssimon	if (!si->pkey)
778183234Ssimon		{
779183234Ssimon		CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_NO_PUBLIC_KEY);
780183234Ssimon		return -1;
781183234Ssimon		}
782183234Ssimon
783183234Ssimon	md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
784183234Ssimon	if (md == NULL)
785183234Ssimon		return -1;
786183234Ssimon	EVP_MD_CTX_init(&mctx);
787238405Sjkim	if (EVP_DigestVerifyInit(&mctx, &pctx, md, NULL, si->pkey) <= 0)
788183234Ssimon		goto err;
789183234Ssimon
790183234Ssimon	alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs,&abuf,
791183234Ssimon				ASN1_ITEM_rptr(CMS_Attributes_Verify));
792183234Ssimon	if(!abuf)
793183234Ssimon		goto err;
794238405Sjkim	r = EVP_DigestVerifyUpdate(&mctx, abuf, alen);
795183234Ssimon	OPENSSL_free(abuf);
796183234Ssimon	if (r <= 0)
797183234Ssimon		{
798183234Ssimon		r = -1;
799183234Ssimon		goto err;
800183234Ssimon		}
801238405Sjkim	r = EVP_DigestVerifyFinal(&mctx,
802238405Sjkim			si->signature->data, si->signature->length);
803193645Ssimon	if (r <= 0)
804183234Ssimon		CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_VERIFICATION_FAILURE);
805183234Ssimon	err:
806183234Ssimon	EVP_MD_CTX_cleanup(&mctx);
807183234Ssimon	return r;
808183234Ssimon	}
809183234Ssimon
810183234Ssimon/* Create a chain of digest BIOs from a CMS ContentInfo */
811183234Ssimon
812183234SsimonBIO *cms_SignedData_init_bio(CMS_ContentInfo *cms)
813183234Ssimon	{
814183234Ssimon	int i;
815183234Ssimon	CMS_SignedData *sd;
816183234Ssimon	BIO *chain = NULL;
817183234Ssimon	sd = cms_get0_signed(cms);
818183234Ssimon	if (!sd)
819183234Ssimon		return NULL;
820183234Ssimon	if (cms->d.signedData->encapContentInfo->partial)
821183234Ssimon		cms_sd_set_version(sd);
822183234Ssimon	for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++)
823183234Ssimon		{
824183234Ssimon		X509_ALGOR *digestAlgorithm;
825183234Ssimon		BIO *mdbio;
826183234Ssimon		digestAlgorithm = sk_X509_ALGOR_value(sd->digestAlgorithms, i);
827183234Ssimon		mdbio = cms_DigestAlgorithm_init_bio(digestAlgorithm);
828183234Ssimon		if (!mdbio)
829183234Ssimon			goto err;
830183234Ssimon		if (chain)
831183234Ssimon			 BIO_push(chain, mdbio);
832183234Ssimon		else
833183234Ssimon			chain = mdbio;
834183234Ssimon		}
835183234Ssimon	return chain;
836183234Ssimon	err:
837183234Ssimon	if (chain)
838183234Ssimon		BIO_free_all(chain);
839183234Ssimon	return NULL;
840183234Ssimon	}
841183234Ssimon
842183234Ssimonint CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain)
843183234Ssimon	{
844183234Ssimon	ASN1_OCTET_STRING *os = NULL;
845183234Ssimon	EVP_MD_CTX mctx;
846183234Ssimon	int r = -1;
847183234Ssimon	EVP_MD_CTX_init(&mctx);
848183234Ssimon	/* If we have any signed attributes look for messageDigest value */
849183234Ssimon	if (CMS_signed_get_attr_count(si) >= 0)
850183234Ssimon		{
851183234Ssimon		os = CMS_signed_get0_data_by_OBJ(si,
852183234Ssimon					OBJ_nid2obj(NID_pkcs9_messageDigest),
853183234Ssimon					-3, V_ASN1_OCTET_STRING);
854183234Ssimon		if (!os)
855183234Ssimon			{
856183234Ssimon			CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
857183234Ssimon				CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE);
858183234Ssimon			goto err;
859183234Ssimon			}
860183234Ssimon		}
861183234Ssimon
862183234Ssimon	if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm))
863183234Ssimon		goto err;
864183234Ssimon
865183234Ssimon	/* If messageDigest found compare it */
866183234Ssimon
867183234Ssimon	if (os)
868183234Ssimon		{
869183234Ssimon		unsigned char mval[EVP_MAX_MD_SIZE];
870183234Ssimon		unsigned int mlen;
871183234Ssimon		if (EVP_DigestFinal_ex(&mctx, mval, &mlen) <= 0)
872183234Ssimon			{
873183234Ssimon			CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
874183234Ssimon				CMS_R_UNABLE_TO_FINALIZE_CONTEXT);
875183234Ssimon			goto err;
876183234Ssimon			}
877183234Ssimon		if (mlen != (unsigned int)os->length)
878183234Ssimon			{
879183234Ssimon			CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
880183234Ssimon				CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH);
881183234Ssimon			goto err;
882183234Ssimon			}
883183234Ssimon
884183234Ssimon		if (memcmp(mval, os->data, mlen))
885183234Ssimon			{
886183234Ssimon			CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
887183234Ssimon				CMS_R_VERIFICATION_FAILURE);
888183234Ssimon			r = 0;
889183234Ssimon			}
890183234Ssimon		else
891183234Ssimon			r = 1;
892183234Ssimon		}
893183234Ssimon	else
894183234Ssimon		{
895183234Ssimon		r = EVP_VerifyFinal(&mctx, si->signature->data,
896183234Ssimon					si->signature->length, si->pkey);
897183234Ssimon		if (r <= 0)
898183234Ssimon			{
899183234Ssimon			CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
900183234Ssimon				CMS_R_VERIFICATION_FAILURE);
901183234Ssimon			r = 0;
902183234Ssimon			}
903183234Ssimon		}
904183234Ssimon
905183234Ssimon	err:
906183234Ssimon	EVP_MD_CTX_cleanup(&mctx);
907183234Ssimon	return r;
908183234Ssimon
909183234Ssimon	}
910183234Ssimon
911183234Ssimonint CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs)
912183234Ssimon	{
913183234Ssimon	unsigned char *smder = NULL;
914183234Ssimon	int smderlen, r;
915183234Ssimon	smderlen = i2d_X509_ALGORS(algs, &smder);
916183234Ssimon	if (smderlen <= 0)
917183234Ssimon		return 0;
918183234Ssimon	r = CMS_signed_add1_attr_by_NID(si, NID_SMIMECapabilities,
919183234Ssimon					V_ASN1_SEQUENCE, smder, smderlen);
920183234Ssimon	OPENSSL_free(smder);
921183234Ssimon	return r;
922183234Ssimon	}
923183234Ssimon
924183234Ssimonint CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs,
925183234Ssimon				int algnid, int keysize)
926183234Ssimon	{
927183234Ssimon	X509_ALGOR *alg;
928183234Ssimon	ASN1_INTEGER *key = NULL;
929183234Ssimon	if (keysize > 0)
930183234Ssimon		{
931183234Ssimon		key = ASN1_INTEGER_new();
932183234Ssimon		if (!key || !ASN1_INTEGER_set(key, keysize))
933183234Ssimon			return 0;
934183234Ssimon		}
935183234Ssimon	alg = X509_ALGOR_new();
936183234Ssimon	if (!alg)
937183234Ssimon		{
938183234Ssimon		if (key)
939183234Ssimon			ASN1_INTEGER_free(key);
940183234Ssimon		return 0;
941183234Ssimon		}
942183234Ssimon
943183234Ssimon	X509_ALGOR_set0(alg, OBJ_nid2obj(algnid),
944183234Ssimon				key ? V_ASN1_INTEGER : V_ASN1_UNDEF, key);
945183234Ssimon	if (!*algs)
946183234Ssimon		*algs = sk_X509_ALGOR_new_null();
947183234Ssimon	if (!*algs || !sk_X509_ALGOR_push(*algs, alg))
948183234Ssimon		{
949183234Ssimon		X509_ALGOR_free(alg);
950183234Ssimon		return 0;
951183234Ssimon		}
952183234Ssimon	return 1;
953183234Ssimon	}
954183234Ssimon
955183234Ssimon/* Check to see if a cipher exists and if so add S/MIME capabilities */
956183234Ssimon
957183234Ssimonstatic int cms_add_cipher_smcap(STACK_OF(X509_ALGOR) **sk, int nid, int arg)
958183234Ssimon	{
959183234Ssimon	if (EVP_get_cipherbynid(nid))
960183234Ssimon		return CMS_add_simple_smimecap(sk, nid, arg);
961183234Ssimon	return 1;
962183234Ssimon	}
963238405Sjkim
964183234Ssimonstatic int cms_add_digest_smcap(STACK_OF(X509_ALGOR) **sk, int nid, int arg)
965183234Ssimon	{
966183234Ssimon	if (EVP_get_digestbynid(nid))
967183234Ssimon		return CMS_add_simple_smimecap(sk, nid, arg);
968183234Ssimon	return 1;
969183234Ssimon	}
970238405Sjkim
971183234Ssimonint CMS_add_standard_smimecap(STACK_OF(X509_ALGOR) **smcap)
972183234Ssimon	{
973183234Ssimon	if (!cms_add_cipher_smcap(smcap, NID_aes_256_cbc, -1)
974238405Sjkim		|| !cms_add_digest_smcap(smcap, NID_id_GostR3411_94, -1)
975238405Sjkim		|| !cms_add_cipher_smcap(smcap, NID_id_Gost28147_89, -1)
976183234Ssimon		|| !cms_add_cipher_smcap(smcap, NID_aes_192_cbc, -1)
977183234Ssimon		|| !cms_add_cipher_smcap(smcap, NID_aes_128_cbc, -1)
978183234Ssimon		|| !cms_add_cipher_smcap(smcap, NID_des_ede3_cbc, -1)
979183234Ssimon		|| !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 128)
980183234Ssimon		|| !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 64)
981183234Ssimon		|| !cms_add_cipher_smcap(smcap, NID_des_cbc, -1)
982183234Ssimon		|| !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 40))
983183234Ssimon		return 0;
984183234Ssimon	return 1;
985183234Ssimon	}
986