1/*
2 * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "hx_locl.h"
35
36/**
37 * @page page_cms CMS/PKCS7 message functions.
38 *
39 * CMS is defined in RFC 3369 and is an continuation of the RSA Labs
40 * standard PKCS7. The basic messages in CMS is
41 *
42 * - SignedData
43 *   Data signed with private key (RSA, DSA, ECDSA) or secret
44 *   (symmetric) key
45 * - EnvelopedData
46 *   Data encrypted with private key (RSA)
47 * - EncryptedData
48 *   Data encrypted with secret (symmetric) key.
49 * - ContentInfo
50 *   Wrapper structure including type and data.
51 *
52 *
53 * See the library functions here: @ref hx509_cms
54 */
55
56#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
57#define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
58
59/**
60 * Wrap data and oid in a ContentInfo and encode it.
61 *
62 * @param oid type of the content.
63 * @param buf data to be wrapped. If a NULL pointer is passed in, the
64 * optional content field in the ContentInfo is not going be filled
65 * in.
66 * @param res the encoded buffer, the result should be freed with
67 * der_free_octet_string().
68 *
69 * @return Returns an hx509 error code.
70 *
71 * @ingroup hx509_cms
72 */
73
74int
75hx509_cms_wrap_ContentInfo(const heim_oid *oid,
76			   const heim_octet_string *buf,
77			   heim_octet_string *res)
78{
79    ContentInfo ci;
80    size_t size = 0;
81    int ret;
82
83    memset(res, 0, sizeof(*res));
84    memset(&ci, 0, sizeof(ci));
85
86    ret = der_copy_oid(oid, &ci.contentType);
87    if (ret)
88	return ret;
89    if (buf) {
90	ALLOC(ci.content, 1);
91	if (ci.content == NULL) {
92	    free_ContentInfo(&ci);
93	    return ENOMEM;
94	}
95	ci.content->data = malloc(buf->length);
96	if (ci.content->data == NULL) {
97	    free_ContentInfo(&ci);
98	    return ENOMEM;
99	}
100	memcpy(ci.content->data, buf->data, buf->length);
101	ci.content->length = buf->length;
102    }
103
104    ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret);
105    free_ContentInfo(&ci);
106    if (ret)
107	return ret;
108    if (res->length != size)
109	_hx509_abort("internal ASN.1 encoder error");
110
111    return 0;
112}
113
114/**
115 * Decode an ContentInfo and unwrap data and oid it.
116 *
117 * @param in the encoded buffer.
118 * @param oid type of the content.
119 * @param out data to be wrapped.
120 * @param have_data since the data is optional, this flags show dthe
121 * diffrence between no data and the zero length data.
122 *
123 * @return Returns an hx509 error code.
124 *
125 * @ingroup hx509_cms
126 */
127
128int
129hx509_cms_unwrap_ContentInfo(const heim_octet_string *in,
130			     heim_oid *oid,
131			     heim_octet_string *out,
132			     int *have_data)
133{
134    ContentInfo ci;
135    size_t size;
136    int ret;
137
138    memset(oid, 0, sizeof(*oid));
139    memset(out, 0, sizeof(*out));
140
141    ret = decode_ContentInfo(in->data, in->length, &ci, &size);
142    if (ret)
143	return ret;
144
145    ret = der_copy_oid(&ci.contentType, oid);
146    if (ret) {
147	free_ContentInfo(&ci);
148	return ret;
149    }
150    if (ci.content) {
151	ret = der_copy_octet_string(ci.content, out);
152	if (ret) {
153	    der_free_oid(oid);
154	    free_ContentInfo(&ci);
155	    return ret;
156	}
157    } else
158	memset(out, 0, sizeof(*out));
159
160    if (have_data)
161	*have_data = (ci.content != NULL) ? 1 : 0;
162
163    free_ContentInfo(&ci);
164
165    return 0;
166}
167
168#define CMS_ID_SKI	0
169#define CMS_ID_NAME	1
170
171static int
172fill_CMSIdentifier(const hx509_cert cert,
173		   int type,
174		   CMSIdentifier *id)
175{
176    int ret;
177
178    switch (type) {
179    case CMS_ID_SKI:
180	id->element = choice_CMSIdentifier_subjectKeyIdentifier;
181	ret = _hx509_find_extension_subject_key_id(_hx509_get_cert(cert),
182						   &id->u.subjectKeyIdentifier);
183	if (ret == 0)
184	    break;
185	/* FALL THOUGH */
186    case CMS_ID_NAME: {
187	hx509_name name;
188
189	id->element = choice_CMSIdentifier_issuerAndSerialNumber;
190	ret = hx509_cert_get_issuer(cert, &name);
191	if (ret)
192	    return ret;
193	ret = hx509_name_to_Name(name, &id->u.issuerAndSerialNumber.issuer);
194	hx509_name_free(&name);
195	if (ret)
196	    return ret;
197
198	ret = hx509_cert_get_serialnumber(cert, &id->u.issuerAndSerialNumber.serialNumber);
199	break;
200    }
201    default:
202	_hx509_abort("CMS fill identifier with unknown type");
203    }
204    return ret;
205}
206
207static int
208unparse_CMSIdentifier(hx509_context context,
209		      CMSIdentifier *id,
210		      char **str)
211{
212    int ret;
213
214    *str = NULL;
215    switch (id->element) {
216    case choice_CMSIdentifier_issuerAndSerialNumber: {
217	IssuerAndSerialNumber *iasn;
218	char *serial, *name;
219
220	iasn = &id->u.issuerAndSerialNumber;
221
222	ret = _hx509_Name_to_string(&iasn->issuer, &name);
223	if(ret)
224	    return ret;
225	ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial);
226	if (ret) {
227	    free(name);
228	    return ret;
229	}
230	asprintf(str, "certificate issued by %s with serial number %s",
231		 name, serial);
232	free(name);
233	free(serial);
234	break;
235    }
236    case choice_CMSIdentifier_subjectKeyIdentifier: {
237	KeyIdentifier *ki  = &id->u.subjectKeyIdentifier;
238	char *keyid;
239	ssize_t len;
240
241	len = hex_encode(ki->data, ki->length, &keyid);
242	if (len < 0)
243	    return ENOMEM;
244
245	asprintf(str, "certificate with id %s", keyid);
246	free(keyid);
247	break;
248    }
249    case invalid_choice_CMSIdentifier:
250	asprintf(str, "certificate have unknown CMSidentifier type");
251	break;
252    }
253    if (*str == NULL)
254	return ENOMEM;
255    return 0;
256}
257
258static int
259find_CMSIdentifier(hx509_context context,
260		   CMSIdentifier *client,
261		   hx509_certs certs,
262		   time_t time_now,
263		   hx509_cert *signer_cert,
264		   int match)
265{
266    hx509_query q;
267    hx509_cert cert;
268    Certificate c;
269    int ret;
270
271    memset(&c, 0, sizeof(c));
272    _hx509_query_clear(&q);
273
274    *signer_cert = NULL;
275
276    switch (client->element) {
277    case choice_CMSIdentifier_issuerAndSerialNumber:
278	q.serial = &client->u.issuerAndSerialNumber.serialNumber;
279	q.issuer_name = &client->u.issuerAndSerialNumber.issuer;
280	q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
281	break;
282    case choice_CMSIdentifier_subjectKeyIdentifier:
283	q.subject_id = &client->u.subjectKeyIdentifier;
284	q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
285	break;
286    case invalid_choice_CMSIdentifier:
287	hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE,
288			       "unknown CMS identifier element");
289	return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
290    }
291
292    q.match |= match;
293
294    q.match |= HX509_QUERY_MATCH_TIME;
295    if (time_now)
296	q.timenow = time_now;
297    else
298	q.timenow = time(NULL);
299
300    ret = hx509_certs_find(context, certs, &q, &cert);
301    if (ret == HX509_CERT_NOT_FOUND) {
302	char *str;
303
304	ret = unparse_CMSIdentifier(context, client, &str);
305	if (ret == 0) {
306	    hx509_set_error_string(context, 0,
307				   HX509_CMS_NO_RECIPIENT_CERTIFICATE,
308				   "Failed to find %s", str);
309	} else
310	    hx509_clear_error_string(context);
311	return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
312    } else if (ret) {
313	hx509_set_error_string(context, HX509_ERROR_APPEND,
314			       HX509_CMS_NO_RECIPIENT_CERTIFICATE,
315			       "Failed to find CMS id in cert store");
316	return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
317    }
318
319    *signer_cert = cert;
320
321    return 0;
322}
323
324/**
325 * Decode and unencrypt EnvelopedData.
326 *
327 * Extract data and parameteres from from the EnvelopedData. Also
328 * supports using detached EnvelopedData.
329 *
330 * @param context A hx509 context.
331 * @param certs Certificate that can decrypt the EnvelopedData
332 * encryption key.
333 * @param flags HX509_CMS_UE flags to control the behavior.
334 * @param data pointer the structure the contains the DER/BER encoded
335 * EnvelopedData stucture.
336 * @param length length of the data that data point to.
337 * @param encryptedContent in case of detached signature, this
338 * contains the actual encrypted data, othersize its should be NULL.
339 * @param time_now set the current time, if zero the library uses now as the date.
340 * @param contentType output type oid, should be freed with der_free_oid().
341 * @param content the data, free with der_free_octet_string().
342 *
343 * @ingroup hx509_cms
344 */
345
346int
347hx509_cms_unenvelope(hx509_context context,
348		     hx509_certs certs,
349		     int flags,
350		     const void *data,
351		     size_t length,
352		     const heim_octet_string *encryptedContent,
353		     time_t time_now,
354		     heim_oid *contentType,
355		     heim_octet_string *content)
356{
357    heim_octet_string key;
358    EnvelopedData ed;
359    hx509_cert cert;
360    AlgorithmIdentifier *ai;
361    const heim_octet_string *enccontent;
362    heim_octet_string *params, params_data;
363    heim_octet_string ivec;
364    size_t size;
365    int ret, matched = 0, findflags = 0;
366    size_t i;
367
368
369    memset(&key, 0, sizeof(key));
370    memset(&ed, 0, sizeof(ed));
371    memset(&ivec, 0, sizeof(ivec));
372    memset(content, 0, sizeof(*content));
373    memset(contentType, 0, sizeof(*contentType));
374
375    if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
376	findflags |= HX509_QUERY_KU_ENCIPHERMENT;
377
378    ret = decode_EnvelopedData(data, length, &ed, &size);
379    if (ret) {
380	hx509_set_error_string(context, 0, ret,
381			       "Failed to decode EnvelopedData");
382	return ret;
383    }
384
385    if (ed.recipientInfos.len == 0) {
386	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
387	hx509_set_error_string(context, 0, ret,
388			       "No recipient info in enveloped data");
389	goto out;
390    }
391
392    enccontent = ed.encryptedContentInfo.encryptedContent;
393    if (enccontent == NULL) {
394	if (encryptedContent == NULL) {
395	    ret = HX509_CMS_NO_DATA_AVAILABLE;
396	    hx509_set_error_string(context, 0, ret,
397				   "Content missing from encrypted data");
398	    goto out;
399	}
400	enccontent = encryptedContent;
401    } else if (encryptedContent != NULL) {
402	ret = HX509_CMS_NO_DATA_AVAILABLE;
403	hx509_set_error_string(context, 0, ret,
404			       "Both internal and external encrypted data");
405	goto out;
406    }
407
408    if (ed.recipientInfos.len == 0) {
409	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
410	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
411			       "No recipientInfos sent in enveloped data");
412	goto out;
413    }
414
415    cert = NULL;
416    for (i = 0; i < ed.recipientInfos.len; i++) {
417	KeyTransRecipientInfo *ri;
418	char *str;
419	int ret2;
420
421	ri = &ed.recipientInfos.val[i];
422
423	ret = find_CMSIdentifier(context, &ri->rid, certs,
424				 time_now, &cert,
425				 HX509_QUERY_PRIVATE_KEY|findflags);
426	if (ret)
427	    continue;
428
429	matched = 1; /* found a matching certificate, let decrypt */
430
431	ret = _hx509_cert_private_decrypt(context,
432					  &ri->encryptedKey,
433					  &ri->keyEncryptionAlgorithm.algorithm,
434					  cert, &key);
435
436	hx509_cert_free(cert);
437	if (ret == 0)
438	    break; /* succuessfully decrypted cert */
439	cert = NULL;
440	ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
441	if (ret2 == 0) {
442	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
443				   "Failed to decrypt with %s", str);
444	    free(str);
445	}
446    }
447
448    if (!matched) {
449	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
450	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
451			       "No matching certificate found in the enveloped data");
452	goto out;
453    }
454
455    if (cert == NULL) {
456	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
457	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
458			       "No private key decrypted the transfer key");
459	goto out;
460    }
461
462    ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
463    if (ret) {
464	hx509_set_error_string(context, 0, ret,
465			       "Failed to copy EnvelopedData content oid");
466	goto out;
467    }
468
469    ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
470    if (ai->parameters) {
471	params_data.data = ai->parameters->data;
472	params_data.length = ai->parameters->length;
473	params = &params_data;
474    } else
475	params = NULL;
476
477    {
478	hx509_crypto crypto;
479
480	ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto);
481	if (ret)
482	    goto out;
483
484	if (flags & HX509_CMS_UE_ALLOW_WEAK)
485	    hx509_crypto_allow_weak(crypto);
486
487	if (params) {
488	    ret = hx509_crypto_set_params(context, crypto, params, &ivec);
489	    if (ret) {
490		hx509_crypto_destroy(crypto);
491		goto out;
492	    }
493	}
494
495	ret = hx509_crypto_set_key_data(crypto, key.data, key.length);
496	if (ret) {
497	    hx509_crypto_destroy(crypto);
498	    hx509_set_error_string(context, 0, ret,
499				   "Failed to set key for decryption "
500				   "of EnvelopedData");
501	    goto out;
502	}
503
504	ret = hx509_crypto_decrypt(crypto,
505				   enccontent->data,
506				   enccontent->length,
507				   ivec.length ? &ivec : NULL,
508				   content);
509	hx509_crypto_destroy(crypto);
510	if (ret) {
511	    hx509_set_error_string(context, 0, ret,
512				   "Failed to decrypt EnvelopedData");
513	    goto out;
514	}
515    }
516
517out:
518    free_EnvelopedData(&ed);
519    der_free_octet_string(&key);
520    if (ivec.length)
521	der_free_octet_string(&ivec);
522    if (ret) {
523	der_free_oid(contentType);
524	der_free_octet_string(content);
525    }
526
527    return ret;
528}
529
530/**
531 * Encrypt end encode EnvelopedData.
532 *
533 * Encrypt and encode EnvelopedData. The data is encrypted with a
534 * random key and the the random key is encrypted with the
535 * certificates private key. This limits what private key type can be
536 * used to RSA.
537 *
538 * @param context A hx509 context.
539 * @param flags flags to control the behavior.
540 *    - HX509_CMS_EV_NO_KU_CHECK - Dont check KU on certificate
541 *    - HX509_CMS_EV_ALLOW_WEAK - Allow weak crytpo
542 *    - HX509_CMS_EV_ID_NAME - prefer issuer name and serial number
543 * @param cert Certificate to encrypt the EnvelopedData encryption key
544 * with.
545 * @param data pointer the data to encrypt.
546 * @param length length of the data that data point to.
547 * @param encryption_type Encryption cipher to use for the bulk data,
548 * use NULL to get default.
549 * @param contentType type of the data that is encrypted
550 * @param content the output of the function,
551 * free with der_free_octet_string().
552 *
553 * @ingroup hx509_cms
554 */
555
556int
557hx509_cms_envelope_1(hx509_context context,
558		     int flags,
559		     hx509_cert cert,
560		     const void *data,
561		     size_t length,
562		     const heim_oid *encryption_type,
563		     const heim_oid *contentType,
564		     heim_octet_string *content)
565{
566    KeyTransRecipientInfo *ri;
567    heim_octet_string ivec;
568    heim_octet_string key;
569    hx509_crypto crypto = NULL;
570    int ret, cmsidflag;
571    EnvelopedData ed;
572    size_t size = 0;
573
574    memset(&ivec, 0, sizeof(ivec));
575    memset(&key, 0, sizeof(key));
576    memset(&ed, 0, sizeof(ed));
577    memset(content, 0, sizeof(*content));
578
579    if (encryption_type == NULL)
580	encryption_type = &asn1_oid_id_aes_256_cbc;
581
582    if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) {
583	ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
584	if (ret)
585	    goto out;
586    }
587
588    ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
589    if (ret)
590	goto out;
591
592    if (flags & HX509_CMS_EV_ALLOW_WEAK)
593	hx509_crypto_allow_weak(crypto);
594
595    ret = hx509_crypto_set_random_key(crypto, &key);
596    if (ret) {
597	hx509_set_error_string(context, 0, ret,
598			       "Create random key for EnvelopedData content");
599	goto out;
600    }
601
602    ret = hx509_crypto_random_iv(crypto, &ivec);
603    if (ret) {
604	hx509_set_error_string(context, 0, ret,
605			       "Failed to create a random iv");
606	goto out;
607    }
608
609    ret = hx509_crypto_encrypt(crypto,
610			       data,
611			       length,
612			       &ivec,
613			       &ed.encryptedContentInfo.encryptedContent);
614    if (ret) {
615	hx509_set_error_string(context, 0, ret,
616			       "Failed to encrypt EnvelopedData content");
617	goto out;
618    }
619
620    {
621	AlgorithmIdentifier *enc_alg;
622	enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
623	ret = der_copy_oid(encryption_type, &enc_alg->algorithm);
624	if (ret) {
625	    hx509_set_error_string(context, 0, ret,
626				   "Failed to set crypto oid "
627				   "for EnvelopedData");
628	    goto out;
629	}
630	ALLOC(enc_alg->parameters, 1);
631	if (enc_alg->parameters == NULL) {
632	    ret = ENOMEM;
633	    hx509_set_error_string(context, 0, ret,
634				   "Failed to allocate crypto paramaters "
635				   "for EnvelopedData");
636	    goto out;
637	}
638
639	ret = hx509_crypto_get_params(context,
640				      crypto,
641				      &ivec,
642				      enc_alg->parameters);
643	if (ret) {
644	    goto out;
645	}
646    }
647
648    ALLOC_SEQ(&ed.recipientInfos, 1);
649    if (ed.recipientInfos.val == NULL) {
650	ret = ENOMEM;
651	hx509_set_error_string(context, 0, ret,
652			       "Failed to allocate recipients info "
653			       "for EnvelopedData");
654	goto out;
655    }
656
657    ri = &ed.recipientInfos.val[0];
658
659    if (flags & HX509_CMS_EV_ID_NAME) {
660	ri->version = 0;
661	cmsidflag = CMS_ID_NAME;
662    } else {
663	ri->version = 2;
664	cmsidflag = CMS_ID_SKI;
665    }
666
667    ret = fill_CMSIdentifier(cert, cmsidflag, &ri->rid);
668    if (ret) {
669	hx509_set_error_string(context, 0, ret,
670			       "Failed to set CMS identifier info "
671			       "for EnvelopedData");
672	goto out;
673    }
674
675    ret = hx509_cert_public_encrypt(context,
676				     &key, cert,
677				     &ri->keyEncryptionAlgorithm.algorithm,
678				     &ri->encryptedKey);
679    if (ret) {
680	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
681			       "Failed to encrypt transport key for "
682			       "EnvelopedData");
683	goto out;
684    }
685
686    /*
687     *
688     */
689
690    ed.version = 0;
691    ed.originatorInfo = NULL;
692
693    ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType);
694    if (ret) {
695	hx509_set_error_string(context, 0, ret,
696			       "Failed to copy content oid for "
697			       "EnvelopedData");
698	goto out;
699    }
700
701    ed.unprotectedAttrs = NULL;
702
703    ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length,
704		       &ed, &size, ret);
705    if (ret) {
706	hx509_set_error_string(context, 0, ret,
707			       "Failed to encode EnvelopedData");
708	goto out;
709    }
710    if (size != content->length)
711	_hx509_abort("internal ASN.1 encoder error");
712
713out:
714    if (crypto)
715	hx509_crypto_destroy(crypto);
716    if (ret)
717	der_free_octet_string(content);
718    der_free_octet_string(&key);
719    der_free_octet_string(&ivec);
720    free_EnvelopedData(&ed);
721
722    return ret;
723}
724
725static int
726any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs)
727{
728    int ret;
729    size_t i;
730
731    if (sd->certificates == NULL)
732	return 0;
733
734    for (i = 0; i < sd->certificates->len; i++) {
735	hx509_cert c;
736
737	ret = hx509_cert_init_data(context,
738				   sd->certificates->val[i].data,
739				   sd->certificates->val[i].length,
740				   &c);
741	if (ret)
742	    return ret;
743	ret = hx509_certs_add(context, certs, c);
744	hx509_cert_free(c);
745	if (ret)
746	    return ret;
747    }
748
749    return 0;
750}
751
752static const Attribute *
753find_attribute(const CMSAttributes *attr, const heim_oid *oid)
754{
755    size_t i;
756    for (i = 0; i < attr->len; i++)
757	if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0)
758	    return &attr->val[i];
759    return NULL;
760}
761
762/**
763 * Decode SignedData and verify that the signature is correct.
764 *
765 * @param context A hx509 context.
766 * @param ctx a hx509 verify context.
767 * @param flags to control the behaivor of the function.
768 *    - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage
769 *    - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch
770 *    - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below.
771 * @param data pointer to CMS SignedData encoded data.
772 * @param length length of the data that data point to.
773 * @param signedContent external data used for signature.
774 * @param pool certificate pool to build certificates paths.
775 * @param contentType free with der_free_oid().
776 * @param content the output of the function, free with
777 * der_free_octet_string().
778 * @param signer_evaluate list of the hx509_evaluate used to sign this
779 * request, free with hx509_certs_free().
780 *
781 * @ingroup hx509_cms
782 */
783
784int
785hx509_cms_verify_signed(hx509_context context,
786			hx509_verify_ctx ctx,
787			unsigned int flags,
788			const void *data,
789			size_t length,
790			const heim_octet_string *signedContent,
791			hx509_certs pool,
792			heim_oid *contentType,
793			heim_octet_string *content,
794			heim_array_t *signer_evaluate)
795{
796    SignerInfo *signer_info;
797    hx509_cert cert = NULL;
798    hx509_certs certs = NULL;
799    SignedData sd;
800    size_t size;
801    int ret, found_valid_sig;
802    size_t i;
803
804    *signer_evaluate = NULL;
805    content->data = NULL;
806    content->length = 0;
807    contentType->length = 0;
808    contentType->components = NULL;
809
810    memset(&sd, 0, sizeof(sd));
811
812    ret = decode_SignedData(data, length, &sd, &size);
813    if (ret) {
814	hx509_set_error_string(context, 0, ret,
815			       "Failed to decode SignedData");
816	goto out;
817    }
818
819    if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) {
820	ret = HX509_CMS_NO_DATA_AVAILABLE;
821	hx509_set_error_string(context, 0, ret,
822			       "No content data in SignedData");
823	goto out;
824    }
825    if (sd.encapContentInfo.eContent && signedContent) {
826	ret = HX509_CMS_NO_DATA_AVAILABLE;
827	hx509_set_error_string(context, 0, ret,
828			       "Both external and internal SignedData");
829	goto out;
830    }
831
832    if (sd.encapContentInfo.eContent)
833	ret = der_copy_octet_string(sd.encapContentInfo.eContent, content);
834    else
835	ret = der_copy_octet_string(signedContent, content);
836    if (ret) {
837	hx509_set_error_string(context, 0, ret, "malloc: out of memory");
838	goto out;
839    }
840
841    ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
842			   0, NULL, &certs);
843    if (ret)
844	goto out;
845
846    *signer_evaluate = heim_array_create();
847    if (*signer_evaluate == NULL) {
848	ret = ENOMEM;
849	goto out;
850    }
851
852    /* XXX Check CMS version */
853
854    ret = any_to_certs(context, &sd, certs);
855    if (ret)
856	goto out;
857
858    if (pool) {
859	ret = hx509_certs_merge(context, certs, pool);
860	if (ret)
861	    goto out;
862    }
863
864    for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
865	heim_octet_string signed_data;
866	const heim_oid *match_oid;
867	heim_oid decode_oid;
868	hx509_evaluate evaluate;
869
870	evaluate = NULL;
871
872	signer_info = &sd.signerInfos.val[i];
873	match_oid = NULL;
874
875	if (signer_info->signature.length == 0) {
876	    ret = HX509_CMS_MISSING_SIGNER_DATA;
877	    hx509_set_error_string(context, 0, ret,
878				   "SignerInfo %d in SignedData "
879				   "missing sigature", (int)i);
880	    continue;
881	}
882
883	ret = find_CMSIdentifier(context, &signer_info->sid, certs,
884				 _hx509_verify_get_time(ctx), &cert,
885				 HX509_QUERY_KU_DIGITALSIGNATURE);
886	if (ret) {
887	    /**
888	     * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal
889	     * search for matching certificates by not considering
890	     * KeyUsage bits on the certificates.
891	     */
892	    if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0)
893		continue;
894
895	    ret = find_CMSIdentifier(context, &signer_info->sid, certs,
896				     _hx509_verify_get_time(ctx), &cert,
897				     0);
898	    if (ret)
899		continue;
900
901	}
902
903	if (signer_info->signedAttrs) {
904	    const Attribute *attr;
905
906	    CMSAttributes sa;
907	    heim_octet_string os;
908
909	    sa.val = signer_info->signedAttrs->val;
910	    sa.len = signer_info->signedAttrs->len;
911
912	    /* verify that sigature exists */
913	    attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest);
914	    if (attr == NULL) {
915		ret = HX509_CRYPTO_SIGNATURE_MISSING;
916		hx509_set_error_string(context, 0, ret,
917				       "SignerInfo have signed attributes "
918				       "but messageDigest (signature) "
919				       "is missing");
920		goto next_sigature;
921	    }
922	    if (attr->value.len != 1) {
923		ret = HX509_CRYPTO_SIGNATURE_MISSING;
924		hx509_set_error_string(context, 0, ret,
925				       "SignerInfo have more then one "
926				       "messageDigest (signature)");
927		goto next_sigature;
928	    }
929
930	    ret = decode_MessageDigest(attr->value.val[0].data,
931				       attr->value.val[0].length,
932				       &os,
933				       &size);
934	    if (ret) {
935		hx509_set_error_string(context, 0, ret,
936				       "Failed to decode "
937				       "messageDigest (signature)");
938		goto next_sigature;
939	    }
940
941	    ret = _hx509_verify_signature(context,
942					  NULL,
943					  &signer_info->digestAlgorithm,
944					  content,
945					  &os);
946	    der_free_octet_string(&os);
947	    if (ret) {
948		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
949				       "Failed to verify messageDigest");
950		goto next_sigature;
951	    }
952
953	    /*
954	     * Fetch content oid inside signedAttrs or set it to
955	     * id-pkcs7-data.
956	     */
957	    attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType);
958	    if (attr == NULL) {
959		match_oid = &asn1_oid_id_pkcs7_data;
960	    } else {
961		if (attr->value.len != 1) {
962		    ret = HX509_CMS_DATA_OID_MISMATCH;
963		    hx509_set_error_string(context, 0, ret,
964					   "More then one oid in signedAttrs");
965		    goto next_sigature;
966
967		}
968		ret = decode_ContentType(attr->value.val[0].data,
969					 attr->value.val[0].length,
970					 &decode_oid,
971					 &size);
972		if (ret) {
973		    hx509_set_error_string(context, 0, ret,
974					   "Failed to decode "
975					   "oid in signedAttrs");
976		    goto next_sigature;
977		}
978		match_oid = &decode_oid;
979	    }
980
981	    ASN1_MALLOC_ENCODE(CMSAttributes,
982			       signed_data.data,
983			       signed_data.length,
984			       &sa,
985			       &size, ret);
986	    if (ret) {
987		if (match_oid == &decode_oid)
988		    der_free_oid(&decode_oid);
989		hx509_clear_error_string(context);
990		goto next_sigature;
991	    }
992	    if (size != signed_data.length)
993		_hx509_abort("internal ASN.1 encoder error");
994
995	} else {
996	    signed_data.data = content->data;
997	    signed_data.length = content->length;
998	    match_oid = &asn1_oid_id_pkcs7_data;
999	}
1000
1001	/**
1002	 * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow
1003	 * encapContentInfo mismatch with the oid in signedAttributes
1004	 * (or if no signedAttributes where use, pkcs7-data oid).
1005	 * This is only needed to work with broken CMS implementations
1006	 * that doesn't follow CMS signedAttributes rules.
1007	 */
1008
1009	if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) &&
1010	    (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) {
1011	    ret = HX509_CMS_DATA_OID_MISMATCH;
1012	    hx509_set_error_string(context, 0, ret,
1013				   "Oid in message mismatch from the expected");
1014	}
1015	if (match_oid == &decode_oid)
1016	    der_free_oid(&decode_oid);
1017
1018	if (ret == 0) {
1019	    ret = hx509_verify_signature(context,
1020					 cert,
1021					 &signer_info->signatureAlgorithm,
1022					 &signed_data,
1023					 &signer_info->signature);
1024	    if (ret)
1025		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1026				       "Failed to verify signature in "
1027				       "CMS SignedData");
1028	}
1029        if (signer_info->signedAttrs) {
1030	    free(signed_data.data);
1031	    signed_data.data = NULL;
1032	}
1033	if (ret)
1034	    goto next_sigature;
1035
1036	/**
1037	 * If HX509_CMS_VS_NO_VALIDATE flags is set, do not verify the
1038	 * signing certificates and leave that up to the caller.
1039	 */
1040
1041	if ((flags & HX509_CMS_VS_NO_VALIDATE) == 0) {
1042	    ret = hx509_evaluate_cert(context, ctx, cert, certs, &evaluate);
1043	    if (ret)
1044		goto next_sigature;
1045
1046	    ret = heim_array_append_value(*signer_evaluate, evaluate);
1047	    heim_release(evaluate);
1048	} else {
1049	    evaluate = _hx509_evaluate_alloc();
1050	    if (evaluate == NULL)
1051		goto next_sigature;
1052	    ret = heim_array_append_value(evaluate->path, cert);
1053	    if (ret == 0)
1054		ret = heim_array_append_value(*signer_evaluate, evaluate);
1055	    heim_release(evaluate);
1056	}
1057	if (ret)
1058	    goto next_sigature;
1059
1060	found_valid_sig++;
1061
1062    next_sigature:
1063	if (cert)
1064	    hx509_cert_free(cert);
1065	cert = NULL;
1066    }
1067    /**
1068     * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty
1069     * SignerInfo (no signatures). If SignedData have no signatures,
1070     * the function will return 0 with signer_certs set to NULL. Zero
1071     * signers is allowed by the standard, but since its only useful
1072     * in corner cases, it make into a flag that the caller have to
1073     * turn on.
1074     */
1075    if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) {
1076	heim_release(*signer_evaluate);
1077	*signer_evaluate = NULL;
1078    } else if (found_valid_sig == 0) {
1079	if (ret == 0) {
1080	    ret = HX509_CMS_SIGNER_NOT_FOUND;
1081	    hx509_set_error_string(context, 0, ret,
1082				   "No signers where found");
1083	}
1084	goto out;
1085    }
1086
1087    ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType);
1088    if (ret) {
1089	hx509_clear_error_string(context);
1090	goto out;
1091    }
1092
1093out:
1094    free_SignedData(&sd);
1095    if (certs)
1096	hx509_certs_free(&certs);
1097    if (ret) {
1098	if (content->data)
1099	    der_free_octet_string(content);
1100
1101	if (*signer_evaluate) {
1102	    heim_release(*signer_evaluate);
1103	    *signer_evaluate = NULL;
1104	}
1105
1106	der_free_oid(contentType);
1107	der_free_octet_string(content);
1108    }
1109
1110    return ret;
1111}
1112
1113static int
1114add_one_attribute(Attribute **attr,
1115		  unsigned int *len,
1116		  const heim_oid *oid,
1117		  heim_octet_string *data)
1118{
1119    void *d;
1120    int ret;
1121
1122    d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1));
1123    if (d == NULL)
1124	return ENOMEM;
1125    (*attr) = d;
1126
1127    ret = der_copy_oid(oid, &(*attr)[*len].type);
1128    if (ret)
1129	return ret;
1130
1131    ALLOC_SEQ(&(*attr)[*len].value, 1);
1132    if ((*attr)[*len].value.val == NULL) {
1133	der_free_oid(&(*attr)[*len].type);
1134	return ENOMEM;
1135    }
1136
1137    (*attr)[*len].value.val[0].data = data->data;
1138    (*attr)[*len].value.val[0].length = data->length;
1139
1140    *len += 1;
1141
1142    return 0;
1143}
1144
1145/**
1146 * Decode SignedData and verify that the signature is correct.
1147 *
1148 * @param context A hx509 context.
1149 * @param flags flags
1150 * @param eContentType the type of the data.
1151 * @param data data to sign
1152 * @param length length of the data that data point to.
1153 * @param digest_alg digest algorithm to use, use NULL to get the
1154 * default or the peer determined algorithm.
1155 * @param cert certificate to use for sign the data.
1156 * @param peer info about the peer the message to send the message to,
1157 * like what digest algorithm to use.
1158 * @param anchors trust anchors that the client will use, used to
1159 * polulate the certificates included in the message
1160 * @param pool certificates to use in try to build the path to the
1161 * trust anchors.
1162 * @param signed_data the output of the function, free with
1163 * der_free_octet_string().
1164 *
1165 * @ingroup hx509_cms
1166 */
1167
1168int
1169hx509_cms_create_signed_1(hx509_context context,
1170			  int flags,
1171			  const heim_oid *eContentType,
1172			  const void *data, size_t length,
1173			  const AlgorithmIdentifier *digest_alg,
1174			  hx509_cert cert,
1175			  hx509_peer_info peer,
1176			  hx509_certs anchors,
1177			  hx509_certs pool,
1178			  heim_octet_string *signed_data)
1179{
1180    hx509_certs certs;
1181    int ret = 0;
1182
1183    signed_data->data = NULL;
1184    signed_data->length = 0;
1185
1186    ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs);
1187    if (ret)
1188	return ret;
1189    ret = hx509_certs_add(context, certs, cert);
1190    if (ret)
1191	goto out;
1192
1193    ret = hx509_cms_create_signed(context, flags, eContentType, data, length,
1194				  digest_alg, certs, peer, anchors, pool,
1195				  signed_data);
1196
1197 out:
1198    hx509_certs_free(&certs);
1199    return ret;
1200}
1201
1202struct sigctx {
1203    SignedData sd;
1204    const AlgorithmIdentifier *digest_alg;
1205    const heim_oid *eContentType;
1206    heim_octet_string content;
1207    hx509_peer_info peer;
1208    int cmsidflag;
1209    int leafonly;
1210    hx509_certs certs;
1211    hx509_certs anchors;
1212    hx509_certs pool;
1213};
1214
1215static int
1216sig_process(hx509_context context, void *ctx, hx509_cert cert)
1217{
1218    struct sigctx *sigctx = ctx;
1219    heim_octet_string buf, sigdata = { 0, NULL };
1220    SignerInfo *signer_info = NULL;
1221    AlgorithmIdentifier digest;
1222    size_t size = 0;
1223    void *ptr;
1224    int ret;
1225    SignedData *sd = &sigctx->sd;
1226    hx509_path path;
1227
1228    memset(&digest, 0, sizeof(digest));
1229    memset(&path, 0, sizeof(path));
1230
1231    if (_hx509_cert_private_key(cert) == NULL) {
1232	hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1233			       "Private key missing for signing");
1234	return HX509_PRIVATE_KEY_MISSING;
1235    }
1236
1237    if (sigctx->digest_alg) {
1238	ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest);
1239	if (ret)
1240	    hx509_clear_error_string(context);
1241    } else {
1242	ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
1243				  _hx509_cert_private_key(cert),
1244				  sigctx->peer, &digest);
1245    }
1246    if (ret)
1247	goto out;
1248
1249    /*
1250     * Allocate on more signerInfo and do the signature processing
1251     */
1252
1253    ptr = realloc(sd->signerInfos.val,
1254		  (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0]));
1255    if (ptr == NULL) {
1256	ret = ENOMEM;
1257	goto out;
1258    }
1259    sd->signerInfos.val = ptr;
1260
1261    signer_info = &sd->signerInfos.val[sd->signerInfos.len];
1262
1263    memset(signer_info, 0, sizeof(*signer_info));
1264
1265    signer_info->version = 1;
1266
1267    ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid);
1268    if (ret) {
1269	hx509_clear_error_string(context);
1270	goto out;
1271    }
1272
1273    signer_info->signedAttrs = NULL;
1274    signer_info->unsignedAttrs = NULL;
1275
1276    ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
1277    if (ret) {
1278	hx509_clear_error_string(context);
1279	goto out;
1280    }
1281
1282    /*
1283     * If it isn't pkcs7-data send signedAttributes
1284     */
1285
1286    if (der_heim_oid_cmp(sigctx->eContentType, &asn1_oid_id_pkcs7_data) != 0) {
1287	CMSAttributes sa;
1288	heim_octet_string sig;
1289
1290	ALLOC(signer_info->signedAttrs, 1);
1291	if (signer_info->signedAttrs == NULL) {
1292	    ret = ENOMEM;
1293	    goto out;
1294	}
1295
1296	ret = _hx509_create_signature(context,
1297				      NULL,
1298				      &digest,
1299				      &sigctx->content,
1300				      NULL,
1301				      &sig);
1302	if (ret)
1303	    goto out;
1304
1305	ASN1_MALLOC_ENCODE(MessageDigest,
1306			   buf.data,
1307			   buf.length,
1308			   &sig,
1309			   &size,
1310			   ret);
1311	der_free_octet_string(&sig);
1312	if (ret) {
1313	    hx509_clear_error_string(context);
1314	    goto out;
1315	}
1316	if (size != buf.length)
1317	    _hx509_abort("internal ASN.1 encoder error");
1318
1319	ret = add_one_attribute(&signer_info->signedAttrs->val,
1320				&signer_info->signedAttrs->len,
1321				&asn1_oid_id_pkcs9_messageDigest,
1322				&buf);
1323	if (ret) {
1324	    free(buf.data);
1325	    hx509_clear_error_string(context);
1326	    goto out;
1327	}
1328
1329
1330	ASN1_MALLOC_ENCODE(ContentType,
1331			   buf.data,
1332			   buf.length,
1333			   sigctx->eContentType,
1334			   &size,
1335			   ret);
1336	if (ret)
1337	    goto out;
1338	if (size != buf.length)
1339	    _hx509_abort("internal ASN.1 encoder error");
1340
1341	ret = add_one_attribute(&signer_info->signedAttrs->val,
1342				&signer_info->signedAttrs->len,
1343				&asn1_oid_id_pkcs9_contentType,
1344				&buf);
1345	if (ret) {
1346	    free(buf.data);
1347	    hx509_clear_error_string(context);
1348	    goto out;
1349	}
1350
1351	sa.val = signer_info->signedAttrs->val;
1352	sa.len = signer_info->signedAttrs->len;
1353
1354	ASN1_MALLOC_ENCODE(CMSAttributes,
1355			   sigdata.data,
1356			   sigdata.length,
1357			   &sa,
1358			   &size,
1359			   ret);
1360	if (ret) {
1361	    hx509_clear_error_string(context);
1362	    goto out;
1363	}
1364	if (size != sigdata.length)
1365	    _hx509_abort("internal ASN.1 encoder error");
1366    } else {
1367	sigdata.data = sigctx->content.data;
1368	sigdata.length = sigctx->content.length;
1369    }
1370
1371    {
1372	AlgorithmIdentifier sigalg;
1373
1374	ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
1375				  _hx509_cert_private_key(cert), sigctx->peer,
1376				  &sigalg);
1377	if (ret)
1378	    goto out;
1379
1380	ret = _hx509_create_signature(context,
1381				      _hx509_cert_private_key(cert),
1382				      &sigalg,
1383				      &sigdata,
1384				      &signer_info->signatureAlgorithm,
1385				      &signer_info->signature);
1386	free_AlgorithmIdentifier(&sigalg);
1387	if (ret)
1388	    goto out;
1389    }
1390
1391    sigctx->sd.signerInfos.len++;
1392    signer_info = NULL;
1393
1394    /*
1395     * Provide best effort path
1396     */
1397    {
1398	unsigned int i;
1399
1400	if (sigctx->pool && sigctx->leafonly == 0) {
1401	    _hx509_calculate_path(context,
1402				  HX509_CALCULATE_PATH_NO_ANCHOR,
1403				  time(NULL),
1404				  sigctx->anchors,
1405				  0,
1406				  cert,
1407				  sigctx->pool,
1408				  &path);
1409	} else
1410	    _hx509_path_append(context, &path, cert);
1411
1412	for (i = 0; i < path.len; i++) {
1413	    /* XXX remove dups */
1414	    ret = hx509_certs_add(context, sigctx->certs, path.val[i]);
1415	    if (ret) {
1416		hx509_clear_error_string(context);
1417		goto out;
1418	    }
1419	}
1420    }
1421
1422 out:
1423    if (signer_info)
1424	free_SignerInfo(signer_info);
1425    if (sigdata.data != sigctx->content.data)
1426	der_free_octet_string(&sigdata);
1427    _hx509_path_free(&path);
1428    free_AlgorithmIdentifier(&digest);
1429
1430    return ret;
1431}
1432
1433static int
1434cert_process(hx509_context context, void *ctx, hx509_cert cert)
1435{
1436    struct sigctx *sigctx = ctx;
1437    const unsigned int i = sigctx->sd.certificates->len;
1438    void *ptr;
1439    int ret;
1440
1441    ptr = realloc(sigctx->sd.certificates->val,
1442		  (i + 1) * sizeof(sigctx->sd.certificates->val[0]));
1443    if (ptr == NULL)
1444	return ENOMEM;
1445    sigctx->sd.certificates->val = ptr;
1446
1447    ret = hx509_cert_binary(context, cert,
1448			    &sigctx->sd.certificates->val[i]);
1449    if (ret == 0)
1450	sigctx->sd.certificates->len++;
1451
1452    return ret;
1453}
1454
1455static int
1456cmp_AlgorithmIdentifier(const AlgorithmIdentifier *p, const AlgorithmIdentifier *q)
1457{
1458    return der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1459}
1460
1461int
1462hx509_cms_create_signed(hx509_context context,
1463			int flags,
1464			const heim_oid *eContentType,
1465			const void *data, size_t length,
1466			const AlgorithmIdentifier *digest_alg,
1467			hx509_certs certs,
1468			hx509_peer_info peer,
1469			hx509_certs anchors,
1470			hx509_certs pool,
1471			heim_octet_string *signed_data)
1472{
1473    unsigned int i, j;
1474    hx509_name name;
1475    int ret;
1476    size_t size = 0;
1477    struct sigctx sigctx;
1478
1479    memset(&sigctx, 0, sizeof(sigctx));
1480    memset(&name, 0, sizeof(name));
1481
1482    if (eContentType == NULL)
1483	eContentType = &asn1_oid_id_pkcs7_data;
1484
1485    sigctx.digest_alg = digest_alg;
1486    sigctx.content.data = rk_UNCONST(data);
1487    sigctx.content.length = length;
1488    sigctx.eContentType = eContentType;
1489    sigctx.peer = peer;
1490    /**
1491     * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name
1492     * and serial number if possible. Otherwise subject key identifier
1493     * will preferred.
1494     */
1495    if (flags & HX509_CMS_SIGNATURE_ID_NAME)
1496	sigctx.cmsidflag = CMS_ID_NAME;
1497    else
1498	sigctx.cmsidflag = CMS_ID_SKI;
1499
1500    /**
1501     * Use HX509_CMS_SIGNATURE_LEAF_ONLY to only request leaf
1502     * certificates to be added to the SignedData.
1503     */
1504    sigctx.leafonly = (flags & HX509_CMS_SIGNATURE_LEAF_ONLY) ? 1 : 0;
1505
1506    /**
1507     * Use HX509_CMS_NO_CERTS to make the SignedData contain no
1508     * certificates, overrides HX509_CMS_SIGNATURE_LEAF_ONLY.
1509     */
1510
1511    if ((flags & HX509_CMS_SIGNATURE_NO_CERTS) == 0) {
1512	ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs);
1513	if (ret)
1514	    return ret;
1515    }
1516
1517    sigctx.anchors = anchors;
1518    sigctx.pool = pool;
1519
1520    sigctx.sd.version = CMSVersion_v3;
1521
1522    der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType);
1523
1524    /**
1525     * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures.
1526     */
1527    if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) {
1528	ALLOC(sigctx.sd.encapContentInfo.eContent, 1);
1529	if (sigctx.sd.encapContentInfo.eContent == NULL) {
1530	    hx509_clear_error_string(context);
1531	    ret = ENOMEM;
1532	    goto out;
1533	}
1534
1535	sigctx.sd.encapContentInfo.eContent->data = malloc(length);
1536	if (sigctx.sd.encapContentInfo.eContent->data == NULL) {
1537	    hx509_clear_error_string(context);
1538	    ret = ENOMEM;
1539	    goto out;
1540	}
1541	memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length);
1542	sigctx.sd.encapContentInfo.eContent->length = length;
1543    }
1544
1545    /**
1546     * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no
1547     * signatures).
1548     */
1549    if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) {
1550	ret = hx509_certs_iter_f(context, certs, sig_process, &sigctx);
1551	if (ret)
1552	    goto out;
1553    }
1554
1555    if (sigctx.sd.signerInfos.len) {
1556
1557	/*
1558	 * For each signerInfo, collect all different digest types.
1559	 */
1560	for (i = 0; i < sigctx.sd.signerInfos.len; i++) {
1561	    AlgorithmIdentifier *di =
1562		&sigctx.sd.signerInfos.val[i].digestAlgorithm;
1563
1564	    for (j = 0; j < sigctx.sd.digestAlgorithms.len; j++)
1565		if (cmp_AlgorithmIdentifier(di, &sigctx.sd.digestAlgorithms.val[j]) == 0)
1566		    break;
1567	    if (j == sigctx.sd.digestAlgorithms.len) {
1568		ret = add_DigestAlgorithmIdentifiers(&sigctx.sd.digestAlgorithms, di);
1569		if (ret) {
1570		    hx509_clear_error_string(context);
1571		    goto out;
1572		}
1573	    }
1574	}
1575    }
1576
1577    /*
1578     * Add certs we think are needed, build as part of sig_process
1579     */
1580    if (sigctx.certs) {
1581	ALLOC(sigctx.sd.certificates, 1);
1582	if (sigctx.sd.certificates == NULL) {
1583	    hx509_clear_error_string(context);
1584	    ret = ENOMEM;
1585	    goto out;
1586	}
1587
1588	ret = hx509_certs_iter_f(context, sigctx.certs, cert_process, &sigctx);
1589	if (ret)
1590	    goto out;
1591    }
1592
1593    ASN1_MALLOC_ENCODE(SignedData,
1594		       signed_data->data, signed_data->length,
1595		       &sigctx.sd, &size, ret);
1596    if (ret) {
1597	hx509_clear_error_string(context);
1598	goto out;
1599    }
1600    if (signed_data->length != size)
1601	_hx509_abort("internal ASN.1 encoder error");
1602
1603out:
1604    hx509_certs_free(&sigctx.certs);
1605    free_SignedData(&sigctx.sd);
1606
1607    return ret;
1608}
1609
1610int
1611hx509_cms_decrypt_encrypted(hx509_context context,
1612			    hx509_lock lock,
1613			    const void *data,
1614			    size_t length,
1615			    heim_oid *contentType,
1616			    heim_octet_string *content)
1617{
1618    heim_octet_string cont;
1619    CMSEncryptedData ed;
1620    AlgorithmIdentifier *ai;
1621    int ret;
1622
1623    memset(content, 0, sizeof(*content));
1624    memset(&cont, 0, sizeof(cont));
1625
1626    ret = decode_CMSEncryptedData(data, length, &ed, NULL);
1627    if (ret) {
1628	hx509_set_error_string(context, 0, ret,
1629			       "Failed to decode CMSEncryptedData");
1630	return ret;
1631    }
1632
1633    if (ed.encryptedContentInfo.encryptedContent == NULL) {
1634	ret = HX509_CMS_NO_DATA_AVAILABLE;
1635	hx509_set_error_string(context, 0, ret,
1636			       "No content in EncryptedData");
1637	goto out;
1638    }
1639
1640    ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
1641    if (ret) {
1642	hx509_clear_error_string(context);
1643	goto out;
1644    }
1645
1646    ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
1647    if (ai->parameters == NULL) {
1648	ret = HX509_ALG_NOT_SUPP;
1649	hx509_clear_error_string(context);
1650	goto out;
1651    }
1652
1653    ret = _hx509_pbe_decrypt(context,
1654			     lock,
1655			     ai,
1656			     ed.encryptedContentInfo.encryptedContent,
1657			     &cont);
1658    if (ret)
1659	goto out;
1660
1661    *content = cont;
1662
1663out:
1664    if (ret) {
1665	if (cont.data)
1666	    free(cont.data);
1667    }
1668    free_CMSEncryptedData(&ed);
1669    return ret;
1670}
1671