1178825Sdfr/*
2233294Sstas * Copyright (c) 2003 - 2007 Kungliga Tekniska H��gskolan
3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr * All rights reserved.
5178825Sdfr *
6178825Sdfr * Redistribution and use in source and binary forms, with or without
7178825Sdfr * modification, are permitted provided that the following conditions
8178825Sdfr * are met:
9178825Sdfr *
10178825Sdfr * 1. Redistributions of source code must retain the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14178825Sdfr *    notice, this list of conditions and the following disclaimer in the
15178825Sdfr *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors
18178825Sdfr *    may be used to endorse or promote products derived from this software
19178825Sdfr *    without specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31178825Sdfr * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825Sdfr
36178825Sdfr/**
37178825Sdfr * @page page_cms CMS/PKCS7 message functions.
38178825Sdfr *
39178825Sdfr * CMS is defined in RFC 3369 and is an continuation of the RSA Labs
40233294Sstas * standard PKCS7. The basic messages in CMS is
41178825Sdfr *
42178825Sdfr * - SignedData
43178825Sdfr *   Data signed with private key (RSA, DSA, ECDSA) or secret
44178825Sdfr *   (symmetric) key
45178825Sdfr * - EnvelopedData
46178825Sdfr *   Data encrypted with private key (RSA)
47178825Sdfr * - EncryptedData
48178825Sdfr *   Data encrypted with secret (symmetric) key.
49178825Sdfr * - ContentInfo
50178825Sdfr *   Wrapper structure including type and data.
51178825Sdfr *
52178825Sdfr *
53178825Sdfr * See the library functions here: @ref hx509_cms
54178825Sdfr */
55178825Sdfr
56178825Sdfr#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
57178825Sdfr#define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
58178825Sdfr
59178825Sdfr/**
60178825Sdfr * Wrap data and oid in a ContentInfo and encode it.
61178825Sdfr *
62178825Sdfr * @param oid type of the content.
63178825Sdfr * @param buf data to be wrapped. If a NULL pointer is passed in, the
64178825Sdfr * optional content field in the ContentInfo is not going be filled
65178825Sdfr * in.
66178825Sdfr * @param res the encoded buffer, the result should be freed with
67178825Sdfr * der_free_octet_string().
68178825Sdfr *
69178825Sdfr * @return Returns an hx509 error code.
70233294Sstas *
71178825Sdfr * @ingroup hx509_cms
72178825Sdfr */
73178825Sdfr
74178825Sdfrint
75178825Sdfrhx509_cms_wrap_ContentInfo(const heim_oid *oid,
76178825Sdfr			   const heim_octet_string *buf,
77178825Sdfr			   heim_octet_string *res)
78178825Sdfr{
79178825Sdfr    ContentInfo ci;
80178825Sdfr    size_t size;
81178825Sdfr    int ret;
82178825Sdfr
83178825Sdfr    memset(res, 0, sizeof(*res));
84178825Sdfr    memset(&ci, 0, sizeof(ci));
85178825Sdfr
86178825Sdfr    ret = der_copy_oid(oid, &ci.contentType);
87178825Sdfr    if (ret)
88178825Sdfr	return ret;
89178825Sdfr    if (buf) {
90178825Sdfr	ALLOC(ci.content, 1);
91178825Sdfr	if (ci.content == NULL) {
92178825Sdfr	    free_ContentInfo(&ci);
93178825Sdfr	    return ENOMEM;
94178825Sdfr	}
95178825Sdfr	ci.content->data = malloc(buf->length);
96178825Sdfr	if (ci.content->data == NULL) {
97178825Sdfr	    free_ContentInfo(&ci);
98178825Sdfr	    return ENOMEM;
99178825Sdfr	}
100178825Sdfr	memcpy(ci.content->data, buf->data, buf->length);
101178825Sdfr	ci.content->length = buf->length;
102178825Sdfr    }
103178825Sdfr
104178825Sdfr    ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret);
105178825Sdfr    free_ContentInfo(&ci);
106178825Sdfr    if (ret)
107178825Sdfr	return ret;
108178825Sdfr    if (res->length != size)
109178825Sdfr	_hx509_abort("internal ASN.1 encoder error");
110178825Sdfr
111178825Sdfr    return 0;
112178825Sdfr}
113178825Sdfr
114178825Sdfr/**
115178825Sdfr * Decode an ContentInfo and unwrap data and oid it.
116178825Sdfr *
117178825Sdfr * @param in the encoded buffer.
118178825Sdfr * @param oid type of the content.
119178825Sdfr * @param out data to be wrapped.
120178825Sdfr * @param have_data since the data is optional, this flags show dthe
121178825Sdfr * diffrence between no data and the zero length data.
122178825Sdfr *
123178825Sdfr * @return Returns an hx509 error code.
124233294Sstas *
125178825Sdfr * @ingroup hx509_cms
126178825Sdfr */
127178825Sdfr
128178825Sdfrint
129178825Sdfrhx509_cms_unwrap_ContentInfo(const heim_octet_string *in,
130178825Sdfr			     heim_oid *oid,
131178825Sdfr			     heim_octet_string *out,
132178825Sdfr			     int *have_data)
133178825Sdfr{
134178825Sdfr    ContentInfo ci;
135178825Sdfr    size_t size;
136178825Sdfr    int ret;
137178825Sdfr
138178825Sdfr    memset(oid, 0, sizeof(*oid));
139178825Sdfr    memset(out, 0, sizeof(*out));
140178825Sdfr
141178825Sdfr    ret = decode_ContentInfo(in->data, in->length, &ci, &size);
142178825Sdfr    if (ret)
143178825Sdfr	return ret;
144178825Sdfr
145178825Sdfr    ret = der_copy_oid(&ci.contentType, oid);
146178825Sdfr    if (ret) {
147178825Sdfr	free_ContentInfo(&ci);
148178825Sdfr	return ret;
149178825Sdfr    }
150178825Sdfr    if (ci.content) {
151178825Sdfr	ret = der_copy_octet_string(ci.content, out);
152178825Sdfr	if (ret) {
153178825Sdfr	    der_free_oid(oid);
154178825Sdfr	    free_ContentInfo(&ci);
155178825Sdfr	    return ret;
156178825Sdfr	}
157178825Sdfr    } else
158178825Sdfr	memset(out, 0, sizeof(*out));
159178825Sdfr
160178825Sdfr    if (have_data)
161178825Sdfr	*have_data = (ci.content != NULL) ? 1 : 0;
162178825Sdfr
163178825Sdfr    free_ContentInfo(&ci);
164178825Sdfr
165178825Sdfr    return 0;
166178825Sdfr}
167178825Sdfr
168178825Sdfr#define CMS_ID_SKI	0
169178825Sdfr#define CMS_ID_NAME	1
170178825Sdfr
171178825Sdfrstatic int
172178825Sdfrfill_CMSIdentifier(const hx509_cert cert,
173178825Sdfr		   int type,
174178825Sdfr		   CMSIdentifier *id)
175178825Sdfr{
176178825Sdfr    int ret;
177178825Sdfr
178178825Sdfr    switch (type) {
179178825Sdfr    case CMS_ID_SKI:
180178825Sdfr	id->element = choice_CMSIdentifier_subjectKeyIdentifier;
181178825Sdfr	ret = _hx509_find_extension_subject_key_id(_hx509_get_cert(cert),
182178825Sdfr						   &id->u.subjectKeyIdentifier);
183178825Sdfr	if (ret == 0)
184178825Sdfr	    break;
185178825Sdfr	/* FALL THOUGH */
186178825Sdfr    case CMS_ID_NAME: {
187178825Sdfr	hx509_name name;
188178825Sdfr
189178825Sdfr	id->element = choice_CMSIdentifier_issuerAndSerialNumber;
190178825Sdfr	ret = hx509_cert_get_issuer(cert, &name);
191178825Sdfr	if (ret)
192178825Sdfr	    return ret;
193178825Sdfr	ret = hx509_name_to_Name(name, &id->u.issuerAndSerialNumber.issuer);
194178825Sdfr	hx509_name_free(&name);
195178825Sdfr	if (ret)
196178825Sdfr	    return ret;
197178825Sdfr
198178825Sdfr	ret = hx509_cert_get_serialnumber(cert, &id->u.issuerAndSerialNumber.serialNumber);
199178825Sdfr	break;
200178825Sdfr    }
201178825Sdfr    default:
202178825Sdfr	_hx509_abort("CMS fill identifier with unknown type");
203178825Sdfr    }
204178825Sdfr    return ret;
205178825Sdfr}
206178825Sdfr
207178825Sdfrstatic int
208178825Sdfrunparse_CMSIdentifier(hx509_context context,
209178825Sdfr		      CMSIdentifier *id,
210178825Sdfr		      char **str)
211178825Sdfr{
212178825Sdfr    int ret;
213178825Sdfr
214178825Sdfr    *str = NULL;
215178825Sdfr    switch (id->element) {
216178825Sdfr    case choice_CMSIdentifier_issuerAndSerialNumber: {
217178825Sdfr	IssuerAndSerialNumber *iasn;
218178825Sdfr	char *serial, *name;
219178825Sdfr
220178825Sdfr	iasn = &id->u.issuerAndSerialNumber;
221178825Sdfr
222178825Sdfr	ret = _hx509_Name_to_string(&iasn->issuer, &name);
223178825Sdfr	if(ret)
224178825Sdfr	    return ret;
225178825Sdfr	ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial);
226178825Sdfr	if (ret) {
227178825Sdfr	    free(name);
228178825Sdfr	    return ret;
229178825Sdfr	}
230178825Sdfr	asprintf(str, "certificate issued by %s with serial number %s",
231178825Sdfr		 name, serial);
232178825Sdfr	free(name);
233178825Sdfr	free(serial);
234178825Sdfr	break;
235178825Sdfr    }
236178825Sdfr    case choice_CMSIdentifier_subjectKeyIdentifier: {
237178825Sdfr	KeyIdentifier *ki  = &id->u.subjectKeyIdentifier;
238178825Sdfr	char *keyid;
239178825Sdfr	ssize_t len;
240178825Sdfr
241178825Sdfr	len = hex_encode(ki->data, ki->length, &keyid);
242178825Sdfr	if (len < 0)
243178825Sdfr	    return ENOMEM;
244178825Sdfr
245178825Sdfr	asprintf(str, "certificate with id %s", keyid);
246178825Sdfr	free(keyid);
247178825Sdfr	break;
248178825Sdfr    }
249178825Sdfr    default:
250178825Sdfr	asprintf(str, "certificate have unknown CMSidentifier type");
251178825Sdfr	break;
252178825Sdfr    }
253178825Sdfr    if (*str == NULL)
254178825Sdfr	return ENOMEM;
255178825Sdfr    return 0;
256178825Sdfr}
257178825Sdfr
258178825Sdfrstatic int
259178825Sdfrfind_CMSIdentifier(hx509_context context,
260178825Sdfr		   CMSIdentifier *client,
261178825Sdfr		   hx509_certs certs,
262233294Sstas		   time_t time_now,
263178825Sdfr		   hx509_cert *signer_cert,
264178825Sdfr		   int match)
265178825Sdfr{
266178825Sdfr    hx509_query q;
267178825Sdfr    hx509_cert cert;
268178825Sdfr    Certificate c;
269178825Sdfr    int ret;
270178825Sdfr
271178825Sdfr    memset(&c, 0, sizeof(c));
272178825Sdfr    _hx509_query_clear(&q);
273178825Sdfr
274178825Sdfr    *signer_cert = NULL;
275178825Sdfr
276178825Sdfr    switch (client->element) {
277178825Sdfr    case choice_CMSIdentifier_issuerAndSerialNumber:
278178825Sdfr	q.serial = &client->u.issuerAndSerialNumber.serialNumber;
279178825Sdfr	q.issuer_name = &client->u.issuerAndSerialNumber.issuer;
280178825Sdfr	q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
281178825Sdfr	break;
282178825Sdfr    case choice_CMSIdentifier_subjectKeyIdentifier:
283178825Sdfr	q.subject_id = &client->u.subjectKeyIdentifier;
284178825Sdfr	q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
285178825Sdfr	break;
286178825Sdfr    default:
287178825Sdfr	hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE,
288178825Sdfr			       "unknown CMS identifier element");
289178825Sdfr	return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
290178825Sdfr    }
291178825Sdfr
292178825Sdfr    q.match |= match;
293178825Sdfr
294178825Sdfr    q.match |= HX509_QUERY_MATCH_TIME;
295233294Sstas    if (time_now)
296233294Sstas	q.timenow = time_now;
297233294Sstas    else
298233294Sstas	q.timenow = time(NULL);
299178825Sdfr
300178825Sdfr    ret = hx509_certs_find(context, certs, &q, &cert);
301178825Sdfr    if (ret == HX509_CERT_NOT_FOUND) {
302178825Sdfr	char *str;
303178825Sdfr
304178825Sdfr	ret = unparse_CMSIdentifier(context, client, &str);
305178825Sdfr	if (ret == 0) {
306178825Sdfr	    hx509_set_error_string(context, 0,
307178825Sdfr				   HX509_CMS_NO_RECIPIENT_CERTIFICATE,
308178825Sdfr				   "Failed to find %s", str);
309178825Sdfr	} else
310178825Sdfr	    hx509_clear_error_string(context);
311178825Sdfr	return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
312178825Sdfr    } else if (ret) {
313178825Sdfr	hx509_set_error_string(context, HX509_ERROR_APPEND,
314178825Sdfr			       HX509_CMS_NO_RECIPIENT_CERTIFICATE,
315178825Sdfr			       "Failed to find CMS id in cert store");
316178825Sdfr	return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
317178825Sdfr    }
318178825Sdfr
319178825Sdfr    *signer_cert = cert;
320178825Sdfr
321178825Sdfr    return 0;
322178825Sdfr}
323178825Sdfr
324178825Sdfr/**
325178825Sdfr * Decode and unencrypt EnvelopedData.
326178825Sdfr *
327178825Sdfr * Extract data and parameteres from from the EnvelopedData. Also
328178825Sdfr * supports using detached EnvelopedData.
329178825Sdfr *
330178825Sdfr * @param context A hx509 context.
331178825Sdfr * @param certs Certificate that can decrypt the EnvelopedData
332178825Sdfr * encryption key.
333178825Sdfr * @param flags HX509_CMS_UE flags to control the behavior.
334178825Sdfr * @param data pointer the structure the contains the DER/BER encoded
335178825Sdfr * EnvelopedData stucture.
336178825Sdfr * @param length length of the data that data point to.
337178825Sdfr * @param encryptedContent in case of detached signature, this
338178825Sdfr * contains the actual encrypted data, othersize its should be NULL.
339233294Sstas * @param time_now set the current time, if zero the library uses now as the date.
340178825Sdfr * @param contentType output type oid, should be freed with der_free_oid().
341178825Sdfr * @param content the data, free with der_free_octet_string().
342178825Sdfr *
343178825Sdfr * @ingroup hx509_cms
344178825Sdfr */
345178825Sdfr
346178825Sdfrint
347178825Sdfrhx509_cms_unenvelope(hx509_context context,
348178825Sdfr		     hx509_certs certs,
349178825Sdfr		     int flags,
350178825Sdfr		     const void *data,
351178825Sdfr		     size_t length,
352178825Sdfr		     const heim_octet_string *encryptedContent,
353233294Sstas		     time_t time_now,
354178825Sdfr		     heim_oid *contentType,
355178825Sdfr		     heim_octet_string *content)
356178825Sdfr{
357178825Sdfr    heim_octet_string key;
358178825Sdfr    EnvelopedData ed;
359178825Sdfr    hx509_cert cert;
360178825Sdfr    AlgorithmIdentifier *ai;
361178825Sdfr    const heim_octet_string *enccontent;
362178825Sdfr    heim_octet_string *params, params_data;
363178825Sdfr    heim_octet_string ivec;
364178825Sdfr    size_t size;
365233294Sstas    int ret, matched = 0, findflags = 0;
366233294Sstas    size_t i;
367178825Sdfr
368178825Sdfr
369178825Sdfr    memset(&key, 0, sizeof(key));
370178825Sdfr    memset(&ed, 0, sizeof(ed));
371178825Sdfr    memset(&ivec, 0, sizeof(ivec));
372178825Sdfr    memset(content, 0, sizeof(*content));
373178825Sdfr    memset(contentType, 0, sizeof(*contentType));
374178825Sdfr
375178825Sdfr    if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
376178825Sdfr	findflags |= HX509_QUERY_KU_ENCIPHERMENT;
377178825Sdfr
378178825Sdfr    ret = decode_EnvelopedData(data, length, &ed, &size);
379178825Sdfr    if (ret) {
380178825Sdfr	hx509_set_error_string(context, 0, ret,
381178825Sdfr			       "Failed to decode EnvelopedData");
382178825Sdfr	return ret;
383178825Sdfr    }
384178825Sdfr
385178825Sdfr    if (ed.recipientInfos.len == 0) {
386178825Sdfr	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
387178825Sdfr	hx509_set_error_string(context, 0, ret,
388178825Sdfr			       "No recipient info in enveloped data");
389178825Sdfr	goto out;
390178825Sdfr    }
391178825Sdfr
392178825Sdfr    enccontent = ed.encryptedContentInfo.encryptedContent;
393178825Sdfr    if (enccontent == NULL) {
394178825Sdfr	if (encryptedContent == NULL) {
395178825Sdfr	    ret = HX509_CMS_NO_DATA_AVAILABLE;
396178825Sdfr	    hx509_set_error_string(context, 0, ret,
397178825Sdfr				   "Content missing from encrypted data");
398178825Sdfr	    goto out;
399178825Sdfr	}
400178825Sdfr	enccontent = encryptedContent;
401178825Sdfr    } else if (encryptedContent != NULL) {
402178825Sdfr	ret = HX509_CMS_NO_DATA_AVAILABLE;
403178825Sdfr	hx509_set_error_string(context, 0, ret,
404178825Sdfr			       "Both internal and external encrypted data");
405178825Sdfr	goto out;
406178825Sdfr    }
407178825Sdfr
408178825Sdfr    cert = NULL;
409178825Sdfr    for (i = 0; i < ed.recipientInfos.len; i++) {
410178825Sdfr	KeyTransRecipientInfo *ri;
411178825Sdfr	char *str;
412178825Sdfr	int ret2;
413178825Sdfr
414178825Sdfr	ri = &ed.recipientInfos.val[i];
415178825Sdfr
416233294Sstas	ret = find_CMSIdentifier(context, &ri->rid, certs,
417233294Sstas				 time_now, &cert,
418178825Sdfr				 HX509_QUERY_PRIVATE_KEY|findflags);
419178825Sdfr	if (ret)
420178825Sdfr	    continue;
421178825Sdfr
422178825Sdfr	matched = 1; /* found a matching certificate, let decrypt */
423178825Sdfr
424178825Sdfr	ret = _hx509_cert_private_decrypt(context,
425178825Sdfr					  &ri->encryptedKey,
426178825Sdfr					  &ri->keyEncryptionAlgorithm.algorithm,
427178825Sdfr					  cert, &key);
428178825Sdfr
429178825Sdfr	hx509_cert_free(cert);
430178825Sdfr	if (ret == 0)
431178825Sdfr	    break; /* succuessfully decrypted cert */
432178825Sdfr	cert = NULL;
433178825Sdfr	ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
434178825Sdfr	if (ret2 == 0) {
435178825Sdfr	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
436178825Sdfr				   "Failed to decrypt with %s", str);
437178825Sdfr	    free(str);
438178825Sdfr	}
439178825Sdfr    }
440178825Sdfr
441178825Sdfr    if (!matched) {
442178825Sdfr	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
443178825Sdfr	hx509_set_error_string(context, 0, ret,
444178825Sdfr			       "No private key matched any certificate");
445178825Sdfr	goto out;
446178825Sdfr    }
447178825Sdfr
448178825Sdfr    if (cert == NULL) {
449178825Sdfr	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
450178825Sdfr	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
451178825Sdfr			       "No private key decrypted the transfer key");
452178825Sdfr	goto out;
453178825Sdfr    }
454178825Sdfr
455178825Sdfr    ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
456178825Sdfr    if (ret) {
457178825Sdfr	hx509_set_error_string(context, 0, ret,
458178825Sdfr			       "Failed to copy EnvelopedData content oid");
459178825Sdfr	goto out;
460178825Sdfr    }
461178825Sdfr
462178825Sdfr    ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
463178825Sdfr    if (ai->parameters) {
464178825Sdfr	params_data.data = ai->parameters->data;
465178825Sdfr	params_data.length = ai->parameters->length;
466178825Sdfr	params = &params_data;
467178825Sdfr    } else
468178825Sdfr	params = NULL;
469178825Sdfr
470178825Sdfr    {
471178825Sdfr	hx509_crypto crypto;
472178825Sdfr
473178825Sdfr	ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto);
474178825Sdfr	if (ret)
475178825Sdfr	    goto out;
476233294Sstas
477233294Sstas	if (flags & HX509_CMS_UE_ALLOW_WEAK)
478233294Sstas	    hx509_crypto_allow_weak(crypto);
479233294Sstas
480178825Sdfr	if (params) {
481178825Sdfr	    ret = hx509_crypto_set_params(context, crypto, params, &ivec);
482178825Sdfr	    if (ret) {
483178825Sdfr		hx509_crypto_destroy(crypto);
484178825Sdfr		goto out;
485178825Sdfr	    }
486178825Sdfr	}
487178825Sdfr
488178825Sdfr	ret = hx509_crypto_set_key_data(crypto, key.data, key.length);
489178825Sdfr	if (ret) {
490178825Sdfr	    hx509_crypto_destroy(crypto);
491178825Sdfr	    hx509_set_error_string(context, 0, ret,
492178825Sdfr				   "Failed to set key for decryption "
493178825Sdfr				   "of EnvelopedData");
494178825Sdfr	    goto out;
495178825Sdfr	}
496233294Sstas
497178825Sdfr	ret = hx509_crypto_decrypt(crypto,
498178825Sdfr				   enccontent->data,
499178825Sdfr				   enccontent->length,
500178825Sdfr				   ivec.length ? &ivec : NULL,
501178825Sdfr				   content);
502178825Sdfr	hx509_crypto_destroy(crypto);
503178825Sdfr	if (ret) {
504178825Sdfr	    hx509_set_error_string(context, 0, ret,
505178825Sdfr				   "Failed to decrypt EnvelopedData");
506178825Sdfr	    goto out;
507178825Sdfr	}
508178825Sdfr    }
509178825Sdfr
510178825Sdfrout:
511178825Sdfr
512178825Sdfr    free_EnvelopedData(&ed);
513178825Sdfr    der_free_octet_string(&key);
514178825Sdfr    if (ivec.length)
515178825Sdfr	der_free_octet_string(&ivec);
516178825Sdfr    if (ret) {
517178825Sdfr	der_free_oid(contentType);
518178825Sdfr	der_free_octet_string(content);
519178825Sdfr    }
520178825Sdfr
521178825Sdfr    return ret;
522178825Sdfr}
523178825Sdfr
524178825Sdfr/**
525178825Sdfr * Encrypt end encode EnvelopedData.
526178825Sdfr *
527178825Sdfr * Encrypt and encode EnvelopedData. The data is encrypted with a
528178825Sdfr * random key and the the random key is encrypted with the
529178825Sdfr * certificates private key. This limits what private key type can be
530178825Sdfr * used to RSA.
531178825Sdfr *
532178825Sdfr * @param context A hx509 context.
533233294Sstas * @param flags flags to control the behavior.
534233294Sstas *    - HX509_CMS_EV_NO_KU_CHECK - Dont check KU on certificate
535233294Sstas *    - HX509_CMS_EV_ALLOW_WEAK - Allow weak crytpo
536233294Sstas *    - HX509_CMS_EV_ID_NAME - prefer issuer name and serial number
537178825Sdfr * @param cert Certificate to encrypt the EnvelopedData encryption key
538178825Sdfr * with.
539178825Sdfr * @param data pointer the data to encrypt.
540178825Sdfr * @param length length of the data that data point to.
541178825Sdfr * @param encryption_type Encryption cipher to use for the bulk data,
542178825Sdfr * use NULL to get default.
543178825Sdfr * @param contentType type of the data that is encrypted
544178825Sdfr * @param content the output of the function,
545178825Sdfr * free with der_free_octet_string().
546178825Sdfr *
547178825Sdfr * @ingroup hx509_cms
548178825Sdfr */
549178825Sdfr
550178825Sdfrint
551178825Sdfrhx509_cms_envelope_1(hx509_context context,
552178825Sdfr		     int flags,
553178825Sdfr		     hx509_cert cert,
554178825Sdfr		     const void *data,
555178825Sdfr		     size_t length,
556178825Sdfr		     const heim_oid *encryption_type,
557178825Sdfr		     const heim_oid *contentType,
558178825Sdfr		     heim_octet_string *content)
559178825Sdfr{
560178825Sdfr    KeyTransRecipientInfo *ri;
561178825Sdfr    heim_octet_string ivec;
562178825Sdfr    heim_octet_string key;
563178825Sdfr    hx509_crypto crypto = NULL;
564233294Sstas    int ret, cmsidflag;
565178825Sdfr    EnvelopedData ed;
566178825Sdfr    size_t size;
567178825Sdfr
568178825Sdfr    memset(&ivec, 0, sizeof(ivec));
569178825Sdfr    memset(&key, 0, sizeof(key));
570178825Sdfr    memset(&ed, 0, sizeof(ed));
571178825Sdfr    memset(content, 0, sizeof(*content));
572178825Sdfr
573178825Sdfr    if (encryption_type == NULL)
574233294Sstas	encryption_type = &asn1_oid_id_aes_256_cbc;
575178825Sdfr
576233294Sstas    if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) {
577233294Sstas	ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
578233294Sstas	if (ret)
579233294Sstas	    goto out;
580233294Sstas    }
581178825Sdfr
582178825Sdfr    ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
583178825Sdfr    if (ret)
584178825Sdfr	goto out;
585178825Sdfr
586233294Sstas    if (flags & HX509_CMS_EV_ALLOW_WEAK)
587233294Sstas	hx509_crypto_allow_weak(crypto);
588233294Sstas
589178825Sdfr    ret = hx509_crypto_set_random_key(crypto, &key);
590178825Sdfr    if (ret) {
591178825Sdfr	hx509_set_error_string(context, 0, ret,
592178825Sdfr			       "Create random key for EnvelopedData content");
593178825Sdfr	goto out;
594178825Sdfr    }
595178825Sdfr
596178825Sdfr    ret = hx509_crypto_random_iv(crypto, &ivec);
597178825Sdfr    if (ret) {
598178825Sdfr	hx509_set_error_string(context, 0, ret,
599178825Sdfr			       "Failed to create a random iv");
600178825Sdfr	goto out;
601178825Sdfr    }
602178825Sdfr
603178825Sdfr    ret = hx509_crypto_encrypt(crypto,
604178825Sdfr			       data,
605178825Sdfr			       length,
606178825Sdfr			       &ivec,
607178825Sdfr			       &ed.encryptedContentInfo.encryptedContent);
608178825Sdfr    if (ret) {
609178825Sdfr	hx509_set_error_string(context, 0, ret,
610178825Sdfr			       "Failed to encrypt EnvelopedData content");
611178825Sdfr	goto out;
612178825Sdfr    }
613178825Sdfr
614178825Sdfr    {
615178825Sdfr	AlgorithmIdentifier *enc_alg;
616178825Sdfr	enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
617178825Sdfr	ret = der_copy_oid(encryption_type, &enc_alg->algorithm);
618178825Sdfr	if (ret) {
619178825Sdfr	    hx509_set_error_string(context, 0, ret,
620178825Sdfr				   "Failed to set crypto oid "
621178825Sdfr				   "for EnvelopedData");
622178825Sdfr	    goto out;
623233294Sstas	}
624178825Sdfr	ALLOC(enc_alg->parameters, 1);
625178825Sdfr	if (enc_alg->parameters == NULL) {
626178825Sdfr	    ret = ENOMEM;
627178825Sdfr	    hx509_set_error_string(context, 0, ret,
628178825Sdfr				   "Failed to allocate crypto paramaters "
629178825Sdfr				   "for EnvelopedData");
630178825Sdfr	    goto out;
631178825Sdfr	}
632178825Sdfr
633178825Sdfr	ret = hx509_crypto_get_params(context,
634178825Sdfr				      crypto,
635178825Sdfr				      &ivec,
636178825Sdfr				      enc_alg->parameters);
637178825Sdfr	if (ret) {
638178825Sdfr	    goto out;
639178825Sdfr	}
640178825Sdfr    }
641178825Sdfr
642178825Sdfr    ALLOC_SEQ(&ed.recipientInfos, 1);
643178825Sdfr    if (ed.recipientInfos.val == NULL) {
644178825Sdfr	ret = ENOMEM;
645178825Sdfr	hx509_set_error_string(context, 0, ret,
646178825Sdfr			       "Failed to allocate recipients info "
647178825Sdfr			       "for EnvelopedData");
648178825Sdfr	goto out;
649178825Sdfr    }
650178825Sdfr
651178825Sdfr    ri = &ed.recipientInfos.val[0];
652178825Sdfr
653233294Sstas    if (flags & HX509_CMS_EV_ID_NAME) {
654233294Sstas	ri->version = 0;
655233294Sstas	cmsidflag = CMS_ID_NAME;
656233294Sstas    } else {
657233294Sstas	ri->version = 2;
658233294Sstas	cmsidflag = CMS_ID_SKI;
659233294Sstas    }
660233294Sstas
661233294Sstas    ret = fill_CMSIdentifier(cert, cmsidflag, &ri->rid);
662178825Sdfr    if (ret) {
663178825Sdfr	hx509_set_error_string(context, 0, ret,
664178825Sdfr			       "Failed to set CMS identifier info "
665178825Sdfr			       "for EnvelopedData");
666178825Sdfr	goto out;
667178825Sdfr    }
668178825Sdfr
669233294Sstas    ret = hx509_cert_public_encrypt(context,
670178825Sdfr				     &key, cert,
671178825Sdfr				     &ri->keyEncryptionAlgorithm.algorithm,
672178825Sdfr				     &ri->encryptedKey);
673178825Sdfr    if (ret) {
674178825Sdfr	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
675178825Sdfr			       "Failed to encrypt transport key for "
676178825Sdfr			       "EnvelopedData");
677178825Sdfr	goto out;
678178825Sdfr    }
679178825Sdfr
680178825Sdfr    /*
681178825Sdfr     *
682178825Sdfr     */
683178825Sdfr
684178825Sdfr    ed.version = 0;
685178825Sdfr    ed.originatorInfo = NULL;
686178825Sdfr
687178825Sdfr    ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType);
688178825Sdfr    if (ret) {
689178825Sdfr	hx509_set_error_string(context, 0, ret,
690178825Sdfr			       "Failed to copy content oid for "
691178825Sdfr			       "EnvelopedData");
692178825Sdfr	goto out;
693178825Sdfr    }
694178825Sdfr
695178825Sdfr    ed.unprotectedAttrs = NULL;
696178825Sdfr
697178825Sdfr    ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length,
698178825Sdfr		       &ed, &size, ret);
699178825Sdfr    if (ret) {
700178825Sdfr	hx509_set_error_string(context, 0, ret,
701178825Sdfr			       "Failed to encode EnvelopedData");
702178825Sdfr	goto out;
703178825Sdfr    }
704178825Sdfr    if (size != content->length)
705178825Sdfr	_hx509_abort("internal ASN.1 encoder error");
706178825Sdfr
707178825Sdfrout:
708178825Sdfr    if (crypto)
709178825Sdfr	hx509_crypto_destroy(crypto);
710178825Sdfr    if (ret)
711178825Sdfr	der_free_octet_string(content);
712178825Sdfr    der_free_octet_string(&key);
713178825Sdfr    der_free_octet_string(&ivec);
714178825Sdfr    free_EnvelopedData(&ed);
715178825Sdfr
716178825Sdfr    return ret;
717178825Sdfr}
718178825Sdfr
719178825Sdfrstatic int
720178825Sdfrany_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs)
721178825Sdfr{
722233294Sstas    int ret;
723233294Sstas    size_t i;
724178825Sdfr
725178825Sdfr    if (sd->certificates == NULL)
726178825Sdfr	return 0;
727178825Sdfr
728178825Sdfr    for (i = 0; i < sd->certificates->len; i++) {
729178825Sdfr	hx509_cert c;
730178825Sdfr
731233294Sstas	ret = hx509_cert_init_data(context,
732233294Sstas				   sd->certificates->val[i].data,
733178825Sdfr				   sd->certificates->val[i].length,
734178825Sdfr				   &c);
735178825Sdfr	if (ret)
736178825Sdfr	    return ret;
737178825Sdfr	ret = hx509_certs_add(context, certs, c);
738178825Sdfr	hx509_cert_free(c);
739178825Sdfr	if (ret)
740178825Sdfr	    return ret;
741178825Sdfr    }
742178825Sdfr
743178825Sdfr    return 0;
744178825Sdfr}
745178825Sdfr
746178825Sdfrstatic const Attribute *
747178825Sdfrfind_attribute(const CMSAttributes *attr, const heim_oid *oid)
748178825Sdfr{
749233294Sstas    size_t i;
750178825Sdfr    for (i = 0; i < attr->len; i++)
751178825Sdfr	if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0)
752178825Sdfr	    return &attr->val[i];
753178825Sdfr    return NULL;
754178825Sdfr}
755178825Sdfr
756178825Sdfr/**
757178825Sdfr * Decode SignedData and verify that the signature is correct.
758178825Sdfr *
759178825Sdfr * @param context A hx509 context.
760233294Sstas * @param ctx a hx509 verify context.
761233294Sstas * @param flags to control the behaivor of the function.
762233294Sstas *    - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage
763233294Sstas *    - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch
764233294Sstas *    - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below.
765233294Sstas * @param data pointer to CMS SignedData encoded data.
766178825Sdfr * @param length length of the data that data point to.
767233294Sstas * @param signedContent external data used for signature.
768178825Sdfr * @param pool certificate pool to build certificates paths.
769233294Sstas * @param contentType free with der_free_oid().
770178825Sdfr * @param content the output of the function, free with
771178825Sdfr * der_free_octet_string().
772178825Sdfr * @param signer_certs list of the cerficates used to sign this
773178825Sdfr * request, free with hx509_certs_free().
774178825Sdfr *
775178825Sdfr * @ingroup hx509_cms
776178825Sdfr */
777178825Sdfr
778178825Sdfrint
779178825Sdfrhx509_cms_verify_signed(hx509_context context,
780178825Sdfr			hx509_verify_ctx ctx,
781233294Sstas			unsigned int flags,
782178825Sdfr			const void *data,
783178825Sdfr			size_t length,
784178825Sdfr			const heim_octet_string *signedContent,
785178825Sdfr			hx509_certs pool,
786178825Sdfr			heim_oid *contentType,
787178825Sdfr			heim_octet_string *content,
788178825Sdfr			hx509_certs *signer_certs)
789178825Sdfr{
790178825Sdfr    SignerInfo *signer_info;
791178825Sdfr    hx509_cert cert = NULL;
792178825Sdfr    hx509_certs certs = NULL;
793178825Sdfr    SignedData sd;
794178825Sdfr    size_t size;
795233294Sstas    int ret, found_valid_sig;
796233294Sstas    size_t i;
797178825Sdfr
798178825Sdfr    *signer_certs = NULL;
799178825Sdfr    content->data = NULL;
800178825Sdfr    content->length = 0;
801178825Sdfr    contentType->length = 0;
802178825Sdfr    contentType->components = NULL;
803178825Sdfr
804178825Sdfr    memset(&sd, 0, sizeof(sd));
805178825Sdfr
806178825Sdfr    ret = decode_SignedData(data, length, &sd, &size);
807178825Sdfr    if (ret) {
808178825Sdfr	hx509_set_error_string(context, 0, ret,
809178825Sdfr			       "Failed to decode SignedData");
810178825Sdfr	goto out;
811178825Sdfr    }
812178825Sdfr
813178825Sdfr    if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) {
814178825Sdfr	ret = HX509_CMS_NO_DATA_AVAILABLE;
815178825Sdfr	hx509_set_error_string(context, 0, ret,
816178825Sdfr			       "No content data in SignedData");
817178825Sdfr	goto out;
818178825Sdfr    }
819178825Sdfr    if (sd.encapContentInfo.eContent && signedContent) {
820178825Sdfr	ret = HX509_CMS_NO_DATA_AVAILABLE;
821178825Sdfr	hx509_set_error_string(context, 0, ret,
822178825Sdfr			       "Both external and internal SignedData");
823178825Sdfr	goto out;
824178825Sdfr    }
825233294Sstas
826178825Sdfr    if (sd.encapContentInfo.eContent)
827233294Sstas	ret = der_copy_octet_string(sd.encapContentInfo.eContent, content);
828233294Sstas    else
829233294Sstas	ret = der_copy_octet_string(signedContent, content);
830233294Sstas    if (ret) {
831233294Sstas	hx509_set_error_string(context, 0, ret, "malloc: out of memory");
832233294Sstas	goto out;
833233294Sstas    }
834178825Sdfr
835178825Sdfr    ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
836178825Sdfr			   0, NULL, &certs);
837178825Sdfr    if (ret)
838178825Sdfr	goto out;
839178825Sdfr
840178825Sdfr    ret = hx509_certs_init(context, "MEMORY:cms-signer-certs",
841178825Sdfr			   0, NULL, signer_certs);
842178825Sdfr    if (ret)
843178825Sdfr	goto out;
844178825Sdfr
845178825Sdfr    /* XXX Check CMS version */
846178825Sdfr
847178825Sdfr    ret = any_to_certs(context, &sd, certs);
848178825Sdfr    if (ret)
849178825Sdfr	goto out;
850178825Sdfr
851178825Sdfr    if (pool) {
852178825Sdfr	ret = hx509_certs_merge(context, certs, pool);
853178825Sdfr	if (ret)
854178825Sdfr	    goto out;
855178825Sdfr    }
856178825Sdfr
857178825Sdfr    for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
858233294Sstas	heim_octet_string signed_data;
859178825Sdfr	const heim_oid *match_oid;
860178825Sdfr	heim_oid decode_oid;
861178825Sdfr
862178825Sdfr	signer_info = &sd.signerInfos.val[i];
863178825Sdfr	match_oid = NULL;
864178825Sdfr
865178825Sdfr	if (signer_info->signature.length == 0) {
866178825Sdfr	    ret = HX509_CMS_MISSING_SIGNER_DATA;
867178825Sdfr	    hx509_set_error_string(context, 0, ret,
868178825Sdfr				   "SignerInfo %d in SignedData "
869178825Sdfr				   "missing sigature", i);
870178825Sdfr	    continue;
871178825Sdfr	}
872178825Sdfr
873233294Sstas	ret = find_CMSIdentifier(context, &signer_info->sid, certs,
874233294Sstas				 _hx509_verify_get_time(ctx), &cert,
875178825Sdfr				 HX509_QUERY_KU_DIGITALSIGNATURE);
876233294Sstas	if (ret) {
877233294Sstas	    /**
878233294Sstas	     * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal
879233294Sstas	     * search for matching certificates by not considering
880233294Sstas	     * KeyUsage bits on the certificates.
881233294Sstas	     */
882233294Sstas	    if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0)
883233294Sstas		continue;
884178825Sdfr
885233294Sstas	    ret = find_CMSIdentifier(context, &signer_info->sid, certs,
886233294Sstas				     _hx509_verify_get_time(ctx), &cert,
887233294Sstas				     0);
888233294Sstas	    if (ret)
889233294Sstas		continue;
890233294Sstas
891233294Sstas	}
892233294Sstas
893178825Sdfr	if (signer_info->signedAttrs) {
894178825Sdfr	    const Attribute *attr;
895233294Sstas
896178825Sdfr	    CMSAttributes sa;
897178825Sdfr	    heim_octet_string os;
898178825Sdfr
899178825Sdfr	    sa.val = signer_info->signedAttrs->val;
900178825Sdfr	    sa.len = signer_info->signedAttrs->len;
901178825Sdfr
902178825Sdfr	    /* verify that sigature exists */
903233294Sstas	    attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest);
904178825Sdfr	    if (attr == NULL) {
905178825Sdfr		ret = HX509_CRYPTO_SIGNATURE_MISSING;
906178825Sdfr		hx509_set_error_string(context, 0, ret,
907178825Sdfr				       "SignerInfo have signed attributes "
908178825Sdfr				       "but messageDigest (signature) "
909178825Sdfr				       "is missing");
910178825Sdfr		goto next_sigature;
911178825Sdfr	    }
912178825Sdfr	    if (attr->value.len != 1) {
913178825Sdfr		ret = HX509_CRYPTO_SIGNATURE_MISSING;
914178825Sdfr		hx509_set_error_string(context, 0, ret,
915178825Sdfr				       "SignerInfo have more then one "
916178825Sdfr				       "messageDigest (signature)");
917178825Sdfr		goto next_sigature;
918178825Sdfr	    }
919233294Sstas
920178825Sdfr	    ret = decode_MessageDigest(attr->value.val[0].data,
921178825Sdfr				       attr->value.val[0].length,
922178825Sdfr				       &os,
923178825Sdfr				       &size);
924178825Sdfr	    if (ret) {
925178825Sdfr		hx509_set_error_string(context, 0, ret,
926178825Sdfr				       "Failed to decode "
927178825Sdfr				       "messageDigest (signature)");
928178825Sdfr		goto next_sigature;
929178825Sdfr	    }
930178825Sdfr
931178825Sdfr	    ret = _hx509_verify_signature(context,
932178825Sdfr					  NULL,
933178825Sdfr					  &signer_info->digestAlgorithm,
934233294Sstas					  content,
935178825Sdfr					  &os);
936178825Sdfr	    der_free_octet_string(&os);
937178825Sdfr	    if (ret) {
938178825Sdfr		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
939178825Sdfr				       "Failed to verify messageDigest");
940178825Sdfr		goto next_sigature;
941178825Sdfr	    }
942178825Sdfr
943178825Sdfr	    /*
944178825Sdfr	     * Fetch content oid inside signedAttrs or set it to
945178825Sdfr	     * id-pkcs7-data.
946178825Sdfr	     */
947233294Sstas	    attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType);
948178825Sdfr	    if (attr == NULL) {
949233294Sstas		match_oid = &asn1_oid_id_pkcs7_data;
950178825Sdfr	    } else {
951178825Sdfr		if (attr->value.len != 1) {
952178825Sdfr		    ret = HX509_CMS_DATA_OID_MISMATCH;
953178825Sdfr		    hx509_set_error_string(context, 0, ret,
954178825Sdfr					   "More then one oid in signedAttrs");
955178825Sdfr		    goto next_sigature;
956178825Sdfr
957178825Sdfr		}
958178825Sdfr		ret = decode_ContentType(attr->value.val[0].data,
959178825Sdfr					 attr->value.val[0].length,
960178825Sdfr					 &decode_oid,
961178825Sdfr					 &size);
962178825Sdfr		if (ret) {
963178825Sdfr		    hx509_set_error_string(context, 0, ret,
964178825Sdfr					   "Failed to decode "
965178825Sdfr					   "oid in signedAttrs");
966178825Sdfr		    goto next_sigature;
967178825Sdfr		}
968178825Sdfr		match_oid = &decode_oid;
969178825Sdfr	    }
970178825Sdfr
971178825Sdfr	    ASN1_MALLOC_ENCODE(CMSAttributes,
972233294Sstas			       signed_data.data,
973233294Sstas			       signed_data.length,
974178825Sdfr			       &sa,
975178825Sdfr			       &size, ret);
976178825Sdfr	    if (ret) {
977178825Sdfr		if (match_oid == &decode_oid)
978178825Sdfr		    der_free_oid(&decode_oid);
979178825Sdfr		hx509_clear_error_string(context);
980178825Sdfr		goto next_sigature;
981178825Sdfr	    }
982233294Sstas	    if (size != signed_data.length)
983178825Sdfr		_hx509_abort("internal ASN.1 encoder error");
984178825Sdfr
985178825Sdfr	} else {
986233294Sstas	    signed_data.data = content->data;
987233294Sstas	    signed_data.length = content->length;
988233294Sstas	    match_oid = &asn1_oid_id_pkcs7_data;
989178825Sdfr	}
990178825Sdfr
991233294Sstas	/**
992233294Sstas	 * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow
993233294Sstas	 * encapContentInfo mismatch with the oid in signedAttributes
994233294Sstas	 * (or if no signedAttributes where use, pkcs7-data oid).
995233294Sstas	 * This is only needed to work with broken CMS implementations
996233294Sstas	 * that doesn't follow CMS signedAttributes rules.
997233294Sstas	 */
998233294Sstas
999233294Sstas	if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) &&
1000233294Sstas	    (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) {
1001178825Sdfr	    ret = HX509_CMS_DATA_OID_MISMATCH;
1002178825Sdfr	    hx509_set_error_string(context, 0, ret,
1003178825Sdfr				   "Oid in message mismatch from the expected");
1004178825Sdfr	}
1005178825Sdfr	if (match_oid == &decode_oid)
1006178825Sdfr	    der_free_oid(&decode_oid);
1007178825Sdfr
1008178825Sdfr	if (ret == 0) {
1009178825Sdfr	    ret = hx509_verify_signature(context,
1010178825Sdfr					 cert,
1011178825Sdfr					 &signer_info->signatureAlgorithm,
1012233294Sstas					 &signed_data,
1013178825Sdfr					 &signer_info->signature);
1014178825Sdfr	    if (ret)
1015178825Sdfr		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1016233294Sstas				       "Failed to verify signature in "
1017178825Sdfr				       "CMS SignedData");
1018178825Sdfr	}
1019233294Sstas        if (signer_info->signedAttrs)
1020233294Sstas	    free(signed_data.data);
1021178825Sdfr	if (ret)
1022178825Sdfr	    goto next_sigature;
1023178825Sdfr
1024233294Sstas	/**
1025233294Sstas	 * If HX509_CMS_VS_NO_VALIDATE flags is set, do not verify the
1026233294Sstas	 * signing certificates and leave that up to the caller.
1027233294Sstas	 */
1028178825Sdfr
1029233294Sstas	if ((flags & HX509_CMS_VS_NO_VALIDATE) == 0) {
1030233294Sstas	    ret = hx509_verify_path(context, ctx, cert, certs);
1031233294Sstas	    if (ret)
1032233294Sstas		goto next_sigature;
1033233294Sstas	}
1034233294Sstas
1035178825Sdfr	ret = hx509_certs_add(context, *signer_certs, cert);
1036178825Sdfr	if (ret)
1037178825Sdfr	    goto next_sigature;
1038178825Sdfr
1039178825Sdfr	found_valid_sig++;
1040178825Sdfr
1041178825Sdfr    next_sigature:
1042178825Sdfr	if (cert)
1043178825Sdfr	    hx509_cert_free(cert);
1044178825Sdfr	cert = NULL;
1045178825Sdfr    }
1046233294Sstas    /**
1047233294Sstas     * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty
1048233294Sstas     * SignerInfo (no signatures). If SignedData have no signatures,
1049233294Sstas     * the function will return 0 with signer_certs set to NULL. Zero
1050233294Sstas     * signers is allowed by the standard, but since its only useful
1051233294Sstas     * in corner cases, it make into a flag that the caller have to
1052233294Sstas     * turn on.
1053233294Sstas     */
1054233294Sstas    if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) {
1055233294Sstas	if (*signer_certs)
1056233294Sstas	    hx509_certs_free(signer_certs);
1057233294Sstas    } else if (found_valid_sig == 0) {
1058178825Sdfr	if (ret == 0) {
1059178825Sdfr	    ret = HX509_CMS_SIGNER_NOT_FOUND;
1060178825Sdfr	    hx509_set_error_string(context, 0, ret,
1061178825Sdfr				   "No signers where found");
1062178825Sdfr	}
1063178825Sdfr	goto out;
1064178825Sdfr    }
1065178825Sdfr
1066178825Sdfr    ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType);
1067178825Sdfr    if (ret) {
1068178825Sdfr	hx509_clear_error_string(context);
1069178825Sdfr	goto out;
1070178825Sdfr    }
1071178825Sdfr
1072178825Sdfrout:
1073178825Sdfr    free_SignedData(&sd);
1074178825Sdfr    if (certs)
1075178825Sdfr	hx509_certs_free(&certs);
1076178825Sdfr    if (ret) {
1077233294Sstas	if (content->data)
1078233294Sstas	    der_free_octet_string(content);
1079178825Sdfr	if (*signer_certs)
1080178825Sdfr	    hx509_certs_free(signer_certs);
1081178825Sdfr	der_free_oid(contentType);
1082178825Sdfr	der_free_octet_string(content);
1083178825Sdfr    }
1084178825Sdfr
1085178825Sdfr    return ret;
1086178825Sdfr}
1087178825Sdfr
1088178825Sdfrstatic int
1089178825Sdfradd_one_attribute(Attribute **attr,
1090178825Sdfr		  unsigned int *len,
1091178825Sdfr		  const heim_oid *oid,
1092178825Sdfr		  heim_octet_string *data)
1093178825Sdfr{
1094178825Sdfr    void *d;
1095178825Sdfr    int ret;
1096178825Sdfr
1097178825Sdfr    d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1));
1098178825Sdfr    if (d == NULL)
1099178825Sdfr	return ENOMEM;
1100178825Sdfr    (*attr) = d;
1101178825Sdfr
1102178825Sdfr    ret = der_copy_oid(oid, &(*attr)[*len].type);
1103178825Sdfr    if (ret)
1104178825Sdfr	return ret;
1105178825Sdfr
1106178825Sdfr    ALLOC_SEQ(&(*attr)[*len].value, 1);
1107178825Sdfr    if ((*attr)[*len].value.val == NULL) {
1108178825Sdfr	der_free_oid(&(*attr)[*len].type);
1109178825Sdfr	return ENOMEM;
1110178825Sdfr    }
1111178825Sdfr
1112178825Sdfr    (*attr)[*len].value.val[0].data = data->data;
1113178825Sdfr    (*attr)[*len].value.val[0].length = data->length;
1114178825Sdfr
1115178825Sdfr    *len += 1;
1116178825Sdfr
1117178825Sdfr    return 0;
1118178825Sdfr}
1119233294Sstas
1120178825Sdfr/**
1121178825Sdfr * Decode SignedData and verify that the signature is correct.
1122178825Sdfr *
1123178825Sdfr * @param context A hx509 context.
1124178825Sdfr * @param flags
1125178825Sdfr * @param eContentType the type of the data.
1126178825Sdfr * @param data data to sign
1127178825Sdfr * @param length length of the data that data point to.
1128178825Sdfr * @param digest_alg digest algorithm to use, use NULL to get the
1129178825Sdfr * default or the peer determined algorithm.
1130178825Sdfr * @param cert certificate to use for sign the data.
1131178825Sdfr * @param peer info about the peer the message to send the message to,
1132178825Sdfr * like what digest algorithm to use.
1133178825Sdfr * @param anchors trust anchors that the client will use, used to
1134178825Sdfr * polulate the certificates included in the message
1135178825Sdfr * @param pool certificates to use in try to build the path to the
1136178825Sdfr * trust anchors.
1137178825Sdfr * @param signed_data the output of the function, free with
1138178825Sdfr * der_free_octet_string().
1139178825Sdfr *
1140178825Sdfr * @ingroup hx509_cms
1141178825Sdfr */
1142178825Sdfr
1143178825Sdfrint
1144178825Sdfrhx509_cms_create_signed_1(hx509_context context,
1145178825Sdfr			  int flags,
1146178825Sdfr			  const heim_oid *eContentType,
1147178825Sdfr			  const void *data, size_t length,
1148178825Sdfr			  const AlgorithmIdentifier *digest_alg,
1149178825Sdfr			  hx509_cert cert,
1150178825Sdfr			  hx509_peer_info peer,
1151178825Sdfr			  hx509_certs anchors,
1152178825Sdfr			  hx509_certs pool,
1153178825Sdfr			  heim_octet_string *signed_data)
1154178825Sdfr{
1155233294Sstas    hx509_certs certs;
1156233294Sstas    int ret = 0;
1157233294Sstas
1158233294Sstas    signed_data->data = NULL;
1159233294Sstas    signed_data->length = 0;
1160233294Sstas
1161233294Sstas    ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs);
1162233294Sstas    if (ret)
1163233294Sstas	return ret;
1164233294Sstas    ret = hx509_certs_add(context, certs, cert);
1165233294Sstas    if (ret)
1166233294Sstas	goto out;
1167233294Sstas
1168233294Sstas    ret = hx509_cms_create_signed(context, flags, eContentType, data, length,
1169233294Sstas				  digest_alg, certs, peer, anchors, pool,
1170233294Sstas				  signed_data);
1171233294Sstas
1172233294Sstas out:
1173233294Sstas    hx509_certs_free(&certs);
1174233294Sstas    return ret;
1175233294Sstas}
1176233294Sstas
1177233294Sstasstruct sigctx {
1178233294Sstas    SignedData sd;
1179233294Sstas    const AlgorithmIdentifier *digest_alg;
1180233294Sstas    const heim_oid *eContentType;
1181233294Sstas    heim_octet_string content;
1182233294Sstas    hx509_peer_info peer;
1183233294Sstas    int cmsidflag;
1184233294Sstas    int leafonly;
1185233294Sstas    hx509_certs certs;
1186233294Sstas    hx509_certs anchors;
1187233294Sstas    hx509_certs pool;
1188233294Sstas};
1189233294Sstas
1190233294Sstasstatic int
1191233294Sstassig_process(hx509_context context, void *ctx, hx509_cert cert)
1192233294Sstas{
1193233294Sstas    struct sigctx *sigctx = ctx;
1194233294Sstas    heim_octet_string buf, sigdata = { 0, NULL };
1195233294Sstas    SignerInfo *signer_info = NULL;
1196178825Sdfr    AlgorithmIdentifier digest;
1197233294Sstas    size_t size;
1198233294Sstas    void *ptr;
1199178825Sdfr    int ret;
1200233294Sstas    SignedData *sd = &sigctx->sd;
1201178825Sdfr    hx509_path path;
1202178825Sdfr
1203233294Sstas    memset(&digest, 0, sizeof(digest));
1204178825Sdfr    memset(&path, 0, sizeof(path));
1205178825Sdfr
1206178825Sdfr    if (_hx509_cert_private_key(cert) == NULL) {
1207178825Sdfr	hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1208178825Sdfr			       "Private key missing for signing");
1209178825Sdfr	return HX509_PRIVATE_KEY_MISSING;
1210178825Sdfr    }
1211178825Sdfr
1212233294Sstas    if (sigctx->digest_alg) {
1213233294Sstas	ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest);
1214178825Sdfr	if (ret)
1215178825Sdfr	    hx509_clear_error_string(context);
1216233294Sstas    } else {
1217233294Sstas	ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
1218233294Sstas				  _hx509_cert_private_key(cert),
1219233294Sstas				  sigctx->peer, &digest);
1220178825Sdfr    }
1221178825Sdfr    if (ret)
1222178825Sdfr	goto out;
1223178825Sdfr
1224233294Sstas    /*
1225233294Sstas     * Allocate on more signerInfo and do the signature processing
1226233294Sstas     */
1227178825Sdfr
1228233294Sstas    ptr = realloc(sd->signerInfos.val,
1229233294Sstas		  (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0]));
1230233294Sstas    if (ptr == NULL) {
1231178825Sdfr	ret = ENOMEM;
1232178825Sdfr	goto out;
1233178825Sdfr    }
1234233294Sstas    sd->signerInfos.val = ptr;
1235178825Sdfr
1236233294Sstas    signer_info = &sd->signerInfos.val[sd->signerInfos.len];
1237178825Sdfr
1238233294Sstas    memset(signer_info, 0, sizeof(*signer_info));
1239233294Sstas
1240178825Sdfr    signer_info->version = 1;
1241178825Sdfr
1242233294Sstas    ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid);
1243178825Sdfr    if (ret) {
1244178825Sdfr	hx509_clear_error_string(context);
1245178825Sdfr	goto out;
1246233294Sstas    }
1247178825Sdfr
1248178825Sdfr    signer_info->signedAttrs = NULL;
1249178825Sdfr    signer_info->unsignedAttrs = NULL;
1250178825Sdfr
1251178825Sdfr    ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
1252178825Sdfr    if (ret) {
1253178825Sdfr	hx509_clear_error_string(context);
1254178825Sdfr	goto out;
1255178825Sdfr    }
1256178825Sdfr
1257178825Sdfr    /*
1258178825Sdfr     * If it isn't pkcs7-data send signedAttributes
1259178825Sdfr     */
1260178825Sdfr
1261233294Sstas    if (der_heim_oid_cmp(sigctx->eContentType, &asn1_oid_id_pkcs7_data) != 0) {
1262233294Sstas	CMSAttributes sa;
1263178825Sdfr	heim_octet_string sig;
1264178825Sdfr
1265178825Sdfr	ALLOC(signer_info->signedAttrs, 1);
1266178825Sdfr	if (signer_info->signedAttrs == NULL) {
1267178825Sdfr	    ret = ENOMEM;
1268178825Sdfr	    goto out;
1269178825Sdfr	}
1270178825Sdfr
1271178825Sdfr	ret = _hx509_create_signature(context,
1272178825Sdfr				      NULL,
1273178825Sdfr				      &digest,
1274233294Sstas				      &sigctx->content,
1275178825Sdfr				      NULL,
1276178825Sdfr				      &sig);
1277178825Sdfr	if (ret)
1278178825Sdfr	    goto out;
1279178825Sdfr
1280178825Sdfr	ASN1_MALLOC_ENCODE(MessageDigest,
1281178825Sdfr			   buf.data,
1282178825Sdfr			   buf.length,
1283178825Sdfr			   &sig,
1284178825Sdfr			   &size,
1285178825Sdfr			   ret);
1286178825Sdfr	der_free_octet_string(&sig);
1287178825Sdfr	if (ret) {
1288178825Sdfr	    hx509_clear_error_string(context);
1289178825Sdfr	    goto out;
1290178825Sdfr	}
1291178825Sdfr	if (size != buf.length)
1292178825Sdfr	    _hx509_abort("internal ASN.1 encoder error");
1293178825Sdfr
1294178825Sdfr	ret = add_one_attribute(&signer_info->signedAttrs->val,
1295178825Sdfr				&signer_info->signedAttrs->len,
1296233294Sstas				&asn1_oid_id_pkcs9_messageDigest,
1297178825Sdfr				&buf);
1298178825Sdfr	if (ret) {
1299233294Sstas	    free(buf.data);
1300178825Sdfr	    hx509_clear_error_string(context);
1301178825Sdfr	    goto out;
1302178825Sdfr	}
1303178825Sdfr
1304178825Sdfr
1305178825Sdfr	ASN1_MALLOC_ENCODE(ContentType,
1306178825Sdfr			   buf.data,
1307178825Sdfr			   buf.length,
1308233294Sstas			   sigctx->eContentType,
1309178825Sdfr			   &size,
1310178825Sdfr			   ret);
1311178825Sdfr	if (ret)
1312178825Sdfr	    goto out;
1313178825Sdfr	if (size != buf.length)
1314178825Sdfr	    _hx509_abort("internal ASN.1 encoder error");
1315178825Sdfr
1316178825Sdfr	ret = add_one_attribute(&signer_info->signedAttrs->val,
1317178825Sdfr				&signer_info->signedAttrs->len,
1318233294Sstas				&asn1_oid_id_pkcs9_contentType,
1319178825Sdfr				&buf);
1320178825Sdfr	if (ret) {
1321233294Sstas	    free(buf.data);
1322178825Sdfr	    hx509_clear_error_string(context);
1323178825Sdfr	    goto out;
1324178825Sdfr	}
1325178825Sdfr
1326178825Sdfr	sa.val = signer_info->signedAttrs->val;
1327178825Sdfr	sa.len = signer_info->signedAttrs->len;
1328233294Sstas
1329178825Sdfr	ASN1_MALLOC_ENCODE(CMSAttributes,
1330178825Sdfr			   sigdata.data,
1331178825Sdfr			   sigdata.length,
1332178825Sdfr			   &sa,
1333178825Sdfr			   &size,
1334178825Sdfr			   ret);
1335178825Sdfr	if (ret) {
1336178825Sdfr	    hx509_clear_error_string(context);
1337178825Sdfr	    goto out;
1338178825Sdfr	}
1339178825Sdfr	if (size != sigdata.length)
1340178825Sdfr	    _hx509_abort("internal ASN.1 encoder error");
1341178825Sdfr    } else {
1342233294Sstas	sigdata.data = sigctx->content.data;
1343233294Sstas	sigdata.length = sigctx->content.length;
1344178825Sdfr    }
1345178825Sdfr
1346178825Sdfr    {
1347178825Sdfr	AlgorithmIdentifier sigalg;
1348178825Sdfr
1349178825Sdfr	ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
1350233294Sstas				  _hx509_cert_private_key(cert), sigctx->peer,
1351178825Sdfr				  &sigalg);
1352178825Sdfr	if (ret)
1353178825Sdfr	    goto out;
1354178825Sdfr
1355178825Sdfr	ret = _hx509_create_signature(context,
1356178825Sdfr				      _hx509_cert_private_key(cert),
1357178825Sdfr				      &sigalg,
1358178825Sdfr				      &sigdata,
1359178825Sdfr				      &signer_info->signatureAlgorithm,
1360178825Sdfr				      &signer_info->signature);
1361178825Sdfr	free_AlgorithmIdentifier(&sigalg);
1362178825Sdfr	if (ret)
1363178825Sdfr	    goto out;
1364178825Sdfr    }
1365178825Sdfr
1366233294Sstas    sigctx->sd.signerInfos.len++;
1367233294Sstas    signer_info = NULL;
1368178825Sdfr
1369178825Sdfr    /*
1370178825Sdfr     * Provide best effort path
1371178825Sdfr     */
1372233294Sstas    if (sigctx->certs) {
1373233294Sstas	unsigned int i;
1374178825Sdfr
1375233294Sstas	if (sigctx->pool && sigctx->leafonly == 0) {
1376233294Sstas	    _hx509_calculate_path(context,
1377233294Sstas				  HX509_CALCULATE_PATH_NO_ANCHOR,
1378233294Sstas				  time(NULL),
1379233294Sstas				  sigctx->anchors,
1380233294Sstas				  0,
1381233294Sstas				  cert,
1382233294Sstas				  sigctx->pool,
1383233294Sstas				  &path);
1384233294Sstas	} else
1385233294Sstas	    _hx509_path_append(context, &path, cert);
1386178825Sdfr
1387233294Sstas	for (i = 0; i < path.len; i++) {
1388233294Sstas	    /* XXX remove dups */
1389233294Sstas	    ret = hx509_certs_add(context, sigctx->certs, path.val[i]);
1390233294Sstas	    if (ret) {
1391233294Sstas		hx509_clear_error_string(context);
1392233294Sstas		goto out;
1393233294Sstas	    }
1394233294Sstas	}
1395233294Sstas    }
1396178825Sdfr
1397233294Sstas out:
1398233294Sstas    if (signer_info)
1399233294Sstas	free_SignerInfo(signer_info);
1400233294Sstas    if (sigdata.data != sigctx->content.data)
1401233294Sstas	der_free_octet_string(&sigdata);
1402233294Sstas    _hx509_path_free(&path);
1403233294Sstas    free_AlgorithmIdentifier(&digest);
1404233294Sstas
1405233294Sstas    return ret;
1406233294Sstas}
1407233294Sstas
1408233294Sstasstatic int
1409233294Sstascert_process(hx509_context context, void *ctx, hx509_cert cert)
1410233294Sstas{
1411233294Sstas    struct sigctx *sigctx = ctx;
1412233294Sstas    const unsigned int i = sigctx->sd.certificates->len;
1413233294Sstas    void *ptr;
1414233294Sstas    int ret;
1415233294Sstas
1416233294Sstas    ptr = realloc(sigctx->sd.certificates->val,
1417233294Sstas		  (i + 1) * sizeof(sigctx->sd.certificates->val[0]));
1418233294Sstas    if (ptr == NULL)
1419233294Sstas	return ENOMEM;
1420233294Sstas    sigctx->sd.certificates->val = ptr;
1421233294Sstas
1422233294Sstas    ret = hx509_cert_binary(context, cert,
1423233294Sstas			    &sigctx->sd.certificates->val[i]);
1424233294Sstas    if (ret == 0)
1425233294Sstas	sigctx->sd.certificates->len++;
1426233294Sstas
1427233294Sstas    return ret;
1428233294Sstas}
1429233294Sstas
1430233294Sstasstatic int
1431233294Sstascmp_AlgorithmIdentifier(const AlgorithmIdentifier *p, const AlgorithmIdentifier *q)
1432233294Sstas{
1433233294Sstas    return der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1434233294Sstas}
1435233294Sstas
1436233294Sstasint
1437233294Sstashx509_cms_create_signed(hx509_context context,
1438233294Sstas			int flags,
1439233294Sstas			const heim_oid *eContentType,
1440233294Sstas			const void *data, size_t length,
1441233294Sstas			const AlgorithmIdentifier *digest_alg,
1442233294Sstas			hx509_certs certs,
1443233294Sstas			hx509_peer_info peer,
1444233294Sstas			hx509_certs anchors,
1445233294Sstas			hx509_certs pool,
1446233294Sstas			heim_octet_string *signed_data)
1447233294Sstas{
1448233294Sstas    unsigned int i, j;
1449233294Sstas    hx509_name name;
1450233294Sstas    int ret;
1451233294Sstas    size_t size;
1452233294Sstas    struct sigctx sigctx;
1453233294Sstas
1454233294Sstas    memset(&sigctx, 0, sizeof(sigctx));
1455233294Sstas    memset(&name, 0, sizeof(name));
1456233294Sstas
1457233294Sstas    if (eContentType == NULL)
1458233294Sstas	eContentType = &asn1_oid_id_pkcs7_data;
1459233294Sstas
1460233294Sstas    sigctx.digest_alg = digest_alg;
1461233294Sstas    sigctx.content.data = rk_UNCONST(data);
1462233294Sstas    sigctx.content.length = length;
1463233294Sstas    sigctx.eContentType = eContentType;
1464233294Sstas    sigctx.peer = peer;
1465233294Sstas    /**
1466233294Sstas     * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name
1467233294Sstas     * and serial number if possible. Otherwise subject key identifier
1468233294Sstas     * will preferred.
1469233294Sstas     */
1470233294Sstas    if (flags & HX509_CMS_SIGNATURE_ID_NAME)
1471233294Sstas	sigctx.cmsidflag = CMS_ID_NAME;
1472233294Sstas    else
1473233294Sstas	sigctx.cmsidflag = CMS_ID_SKI;
1474233294Sstas
1475233294Sstas    /**
1476233294Sstas     * Use HX509_CMS_SIGNATURE_LEAF_ONLY to only request leaf
1477233294Sstas     * certificates to be added to the SignedData.
1478233294Sstas     */
1479233294Sstas    sigctx.leafonly = (flags & HX509_CMS_SIGNATURE_LEAF_ONLY) ? 1 : 0;
1480233294Sstas
1481233294Sstas    /**
1482233294Sstas     * Use HX509_CMS_NO_CERTS to make the SignedData contain no
1483233294Sstas     * certificates, overrides HX509_CMS_SIGNATURE_LEAF_ONLY.
1484233294Sstas     */
1485233294Sstas
1486233294Sstas    if ((flags & HX509_CMS_SIGNATURE_NO_CERTS) == 0) {
1487233294Sstas	ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs);
1488233294Sstas	if (ret)
1489233294Sstas	    return ret;
1490233294Sstas    }
1491233294Sstas
1492233294Sstas    sigctx.anchors = anchors;
1493233294Sstas    sigctx.pool = pool;
1494233294Sstas
1495233294Sstas    sigctx.sd.version = CMSVersion_v3;
1496233294Sstas
1497233294Sstas    der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType);
1498233294Sstas
1499233294Sstas    /**
1500233294Sstas     * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures.
1501233294Sstas     */
1502233294Sstas    if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) {
1503233294Sstas	ALLOC(sigctx.sd.encapContentInfo.eContent, 1);
1504233294Sstas	if (sigctx.sd.encapContentInfo.eContent == NULL) {
1505178825Sdfr	    hx509_clear_error_string(context);
1506178825Sdfr	    ret = ENOMEM;
1507178825Sdfr	    goto out;
1508178825Sdfr	}
1509233294Sstas
1510233294Sstas	sigctx.sd.encapContentInfo.eContent->data = malloc(length);
1511233294Sstas	if (sigctx.sd.encapContentInfo.eContent->data == NULL) {
1512178825Sdfr	    hx509_clear_error_string(context);
1513178825Sdfr	    ret = ENOMEM;
1514178825Sdfr	    goto out;
1515178825Sdfr	}
1516233294Sstas	memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length);
1517233294Sstas	sigctx.sd.encapContentInfo.eContent->length = length;
1518233294Sstas    }
1519178825Sdfr
1520233294Sstas    /**
1521233294Sstas     * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no
1522233294Sstas     * signatures).
1523233294Sstas     */
1524233294Sstas    if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) {
1525233294Sstas	ret = hx509_certs_iter_f(context, certs, sig_process, &sigctx);
1526233294Sstas	if (ret)
1527233294Sstas	    goto out;
1528233294Sstas    }
1529233294Sstas
1530233294Sstas    if (sigctx.sd.signerInfos.len) {
1531233294Sstas
1532233294Sstas	/*
1533233294Sstas	 * For each signerInfo, collect all different digest types.
1534233294Sstas	 */
1535233294Sstas	for (i = 0; i < sigctx.sd.signerInfos.len; i++) {
1536233294Sstas	    AlgorithmIdentifier *di =
1537233294Sstas		&sigctx.sd.signerInfos.val[i].digestAlgorithm;
1538233294Sstas
1539233294Sstas	    for (j = 0; j < sigctx.sd.digestAlgorithms.len; j++)
1540233294Sstas		if (cmp_AlgorithmIdentifier(di, &sigctx.sd.digestAlgorithms.val[j]) == 0)
1541233294Sstas		    break;
1542233294Sstas	    if (j == sigctx.sd.digestAlgorithms.len) {
1543233294Sstas		ret = add_DigestAlgorithmIdentifiers(&sigctx.sd.digestAlgorithms, di);
1544233294Sstas		if (ret) {
1545233294Sstas		    hx509_clear_error_string(context);
1546233294Sstas		    goto out;
1547233294Sstas		}
1548178825Sdfr	    }
1549178825Sdfr	}
1550178825Sdfr    }
1551178825Sdfr
1552233294Sstas    /*
1553233294Sstas     * Add certs we think are needed, build as part of sig_process
1554233294Sstas     */
1555233294Sstas    if (sigctx.certs) {
1556233294Sstas	ALLOC(sigctx.sd.certificates, 1);
1557233294Sstas	if (sigctx.sd.certificates == NULL) {
1558233294Sstas	    hx509_clear_error_string(context);
1559233294Sstas	    ret = ENOMEM;
1560233294Sstas	    goto out;
1561233294Sstas	}
1562233294Sstas
1563233294Sstas	ret = hx509_certs_iter_f(context, sigctx.certs, cert_process, &sigctx);
1564233294Sstas	if (ret)
1565233294Sstas	    goto out;
1566233294Sstas    }
1567233294Sstas
1568178825Sdfr    ASN1_MALLOC_ENCODE(SignedData,
1569178825Sdfr		       signed_data->data, signed_data->length,
1570233294Sstas		       &sigctx.sd, &size, ret);
1571178825Sdfr    if (ret) {
1572178825Sdfr	hx509_clear_error_string(context);
1573178825Sdfr	goto out;
1574178825Sdfr    }
1575178825Sdfr    if (signed_data->length != size)
1576178825Sdfr	_hx509_abort("internal ASN.1 encoder error");
1577178825Sdfr
1578178825Sdfrout:
1579233294Sstas    hx509_certs_free(&sigctx.certs);
1580233294Sstas    free_SignedData(&sigctx.sd);
1581178825Sdfr
1582178825Sdfr    return ret;
1583178825Sdfr}
1584178825Sdfr
1585178825Sdfrint
1586178825Sdfrhx509_cms_decrypt_encrypted(hx509_context context,
1587178825Sdfr			    hx509_lock lock,
1588178825Sdfr			    const void *data,
1589178825Sdfr			    size_t length,
1590178825Sdfr			    heim_oid *contentType,
1591178825Sdfr			    heim_octet_string *content)
1592178825Sdfr{
1593178825Sdfr    heim_octet_string cont;
1594178825Sdfr    CMSEncryptedData ed;
1595178825Sdfr    AlgorithmIdentifier *ai;
1596178825Sdfr    int ret;
1597178825Sdfr
1598178825Sdfr    memset(content, 0, sizeof(*content));
1599178825Sdfr    memset(&cont, 0, sizeof(cont));
1600178825Sdfr
1601178825Sdfr    ret = decode_CMSEncryptedData(data, length, &ed, NULL);
1602178825Sdfr    if (ret) {
1603178825Sdfr	hx509_set_error_string(context, 0, ret,
1604178825Sdfr			       "Failed to decode CMSEncryptedData");
1605178825Sdfr	return ret;
1606178825Sdfr    }
1607178825Sdfr
1608178825Sdfr    if (ed.encryptedContentInfo.encryptedContent == NULL) {
1609178825Sdfr	ret = HX509_CMS_NO_DATA_AVAILABLE;
1610178825Sdfr	hx509_set_error_string(context, 0, ret,
1611178825Sdfr			       "No content in EncryptedData");
1612178825Sdfr	goto out;
1613178825Sdfr    }
1614178825Sdfr
1615178825Sdfr    ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
1616178825Sdfr    if (ret) {
1617178825Sdfr	hx509_clear_error_string(context);
1618178825Sdfr	goto out;
1619178825Sdfr    }
1620178825Sdfr
1621178825Sdfr    ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
1622178825Sdfr    if (ai->parameters == NULL) {
1623178825Sdfr	ret = HX509_ALG_NOT_SUPP;
1624178825Sdfr	hx509_clear_error_string(context);
1625178825Sdfr	goto out;
1626178825Sdfr    }
1627178825Sdfr
1628178825Sdfr    ret = _hx509_pbe_decrypt(context,
1629178825Sdfr			     lock,
1630178825Sdfr			     ai,
1631178825Sdfr			     ed.encryptedContentInfo.encryptedContent,
1632178825Sdfr			     &cont);
1633178825Sdfr    if (ret)
1634178825Sdfr	goto out;
1635178825Sdfr
1636178825Sdfr    *content = cont;
1637178825Sdfr
1638178825Sdfrout:
1639178825Sdfr    if (ret) {
1640178825Sdfr	if (cont.data)
1641178825Sdfr	    free(cont.data);
1642178825Sdfr    }
1643178825Sdfr    free_CMSEncryptedData(&ed);
1644178825Sdfr    return ret;
1645178825Sdfr}
1646