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