1/*	$NetBSD: cms.c,v 1.1.1.1 2011/04/13 18:15:10 elric 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, i, matched = 0, findflags = 0;
368
369
370    memset(&key, 0, sizeof(key));
371    memset(&ed, 0, sizeof(ed));
372    memset(&ivec, 0, sizeof(ivec));
373    memset(content, 0, sizeof(*content));
374    memset(contentType, 0, sizeof(*contentType));
375
376    if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
377	findflags |= HX509_QUERY_KU_ENCIPHERMENT;
378
379    ret = decode_EnvelopedData(data, length, &ed, &size);
380    if (ret) {
381	hx509_set_error_string(context, 0, ret,
382			       "Failed to decode EnvelopedData");
383	return ret;
384    }
385
386    if (ed.recipientInfos.len == 0) {
387	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
388	hx509_set_error_string(context, 0, ret,
389			       "No recipient info in enveloped data");
390	goto out;
391    }
392
393    enccontent = ed.encryptedContentInfo.encryptedContent;
394    if (enccontent == NULL) {
395	if (encryptedContent == NULL) {
396	    ret = HX509_CMS_NO_DATA_AVAILABLE;
397	    hx509_set_error_string(context, 0, ret,
398				   "Content missing from encrypted data");
399	    goto out;
400	}
401	enccontent = encryptedContent;
402    } else if (encryptedContent != NULL) {
403	ret = HX509_CMS_NO_DATA_AVAILABLE;
404	hx509_set_error_string(context, 0, ret,
405			       "Both internal and external encrypted data");
406	goto out;
407    }
408
409    cert = NULL;
410    for (i = 0; i < ed.recipientInfos.len; i++) {
411	KeyTransRecipientInfo *ri;
412	char *str;
413	int ret2;
414
415	ri = &ed.recipientInfos.val[i];
416
417	ret = find_CMSIdentifier(context, &ri->rid, certs,
418				 time_now, &cert,
419				 HX509_QUERY_PRIVATE_KEY|findflags);
420	if (ret)
421	    continue;
422
423	matched = 1; /* found a matching certificate, let decrypt */
424
425	ret = _hx509_cert_private_decrypt(context,
426					  &ri->encryptedKey,
427					  &ri->keyEncryptionAlgorithm.algorithm,
428					  cert, &key);
429
430	hx509_cert_free(cert);
431	if (ret == 0)
432	    break; /* succuessfully decrypted cert */
433	cert = NULL;
434	ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
435	if (ret2 == 0) {
436	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
437				   "Failed to decrypt with %s", str);
438	    free(str);
439	}
440    }
441
442    if (!matched) {
443	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
444	hx509_set_error_string(context, 0, ret,
445			       "No private key matched any certificate");
446	goto out;
447    }
448
449    if (cert == NULL) {
450	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
451	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
452			       "No private key decrypted the transfer key");
453	goto out;
454    }
455
456    ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
457    if (ret) {
458	hx509_set_error_string(context, 0, ret,
459			       "Failed to copy EnvelopedData content oid");
460	goto out;
461    }
462
463    ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
464    if (ai->parameters) {
465	params_data.data = ai->parameters->data;
466	params_data.length = ai->parameters->length;
467	params = &params_data;
468    } else
469	params = NULL;
470
471    {
472	hx509_crypto crypto;
473
474	ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto);
475	if (ret)
476	    goto out;
477
478	if (flags & HX509_CMS_UE_ALLOW_WEAK)
479	    hx509_crypto_allow_weak(crypto);
480
481	if (params) {
482	    ret = hx509_crypto_set_params(context, crypto, params, &ivec);
483	    if (ret) {
484		hx509_crypto_destroy(crypto);
485		goto out;
486	    }
487	}
488
489	ret = hx509_crypto_set_key_data(crypto, key.data, key.length);
490	if (ret) {
491	    hx509_crypto_destroy(crypto);
492	    hx509_set_error_string(context, 0, ret,
493				   "Failed to set key for decryption "
494				   "of EnvelopedData");
495	    goto out;
496	}
497
498	ret = hx509_crypto_decrypt(crypto,
499				   enccontent->data,
500				   enccontent->length,
501				   ivec.length ? &ivec : NULL,
502				   content);
503	hx509_crypto_destroy(crypto);
504	if (ret) {
505	    hx509_set_error_string(context, 0, ret,
506				   "Failed to decrypt EnvelopedData");
507	    goto out;
508	}
509    }
510
511out:
512
513    free_EnvelopedData(&ed);
514    der_free_octet_string(&key);
515    if (ivec.length)
516	der_free_octet_string(&ivec);
517    if (ret) {
518	der_free_oid(contentType);
519	der_free_octet_string(content);
520    }
521
522    return ret;
523}
524
525/**
526 * Encrypt end encode EnvelopedData.
527 *
528 * Encrypt and encode EnvelopedData. The data is encrypted with a
529 * random key and the the random key is encrypted with the
530 * certificates private key. This limits what private key type can be
531 * used to RSA.
532 *
533 * @param context A hx509 context.
534 * @param flags flags to control the behavior.
535 *    - HX509_CMS_EV_NO_KU_CHECK - Dont check KU on certificate
536 *    - HX509_CMS_EV_ALLOW_WEAK - Allow weak crytpo
537 *    - HX509_CMS_EV_ID_NAME - prefer issuer name and serial number
538 * @param cert Certificate to encrypt the EnvelopedData encryption key
539 * with.
540 * @param data pointer the data to encrypt.
541 * @param length length of the data that data point to.
542 * @param encryption_type Encryption cipher to use for the bulk data,
543 * use NULL to get default.
544 * @param contentType type of the data that is encrypted
545 * @param content the output of the function,
546 * free with der_free_octet_string().
547 *
548 * @ingroup hx509_cms
549 */
550
551int
552hx509_cms_envelope_1(hx509_context context,
553		     int flags,
554		     hx509_cert cert,
555		     const void *data,
556		     size_t length,
557		     const heim_oid *encryption_type,
558		     const heim_oid *contentType,
559		     heim_octet_string *content)
560{
561    KeyTransRecipientInfo *ri;
562    heim_octet_string ivec;
563    heim_octet_string key;
564    hx509_crypto crypto = NULL;
565    int ret, cmsidflag;
566    EnvelopedData ed;
567    size_t size;
568
569    memset(&ivec, 0, sizeof(ivec));
570    memset(&key, 0, sizeof(key));
571    memset(&ed, 0, sizeof(ed));
572    memset(content, 0, sizeof(*content));
573
574    if (encryption_type == NULL)
575	encryption_type = &asn1_oid_id_aes_256_cbc;
576
577    if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) {
578	ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
579	if (ret)
580	    goto out;
581    }
582
583    ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
584    if (ret)
585	goto out;
586
587    if (flags & HX509_CMS_EV_ALLOW_WEAK)
588	hx509_crypto_allow_weak(crypto);
589
590    ret = hx509_crypto_set_random_key(crypto, &key);
591    if (ret) {
592	hx509_set_error_string(context, 0, ret,
593			       "Create random key for EnvelopedData content");
594	goto out;
595    }
596
597    ret = hx509_crypto_random_iv(crypto, &ivec);
598    if (ret) {
599	hx509_set_error_string(context, 0, ret,
600			       "Failed to create a random iv");
601	goto out;
602    }
603
604    ret = hx509_crypto_encrypt(crypto,
605			       data,
606			       length,
607			       &ivec,
608			       &ed.encryptedContentInfo.encryptedContent);
609    if (ret) {
610	hx509_set_error_string(context, 0, ret,
611			       "Failed to encrypt EnvelopedData content");
612	goto out;
613    }
614
615    {
616	AlgorithmIdentifier *enc_alg;
617	enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
618	ret = der_copy_oid(encryption_type, &enc_alg->algorithm);
619	if (ret) {
620	    hx509_set_error_string(context, 0, ret,
621				   "Failed to set crypto oid "
622				   "for EnvelopedData");
623	    goto out;
624	}
625	ALLOC(enc_alg->parameters, 1);
626	if (enc_alg->parameters == NULL) {
627	    ret = ENOMEM;
628	    hx509_set_error_string(context, 0, ret,
629				   "Failed to allocate crypto paramaters "
630				   "for EnvelopedData");
631	    goto out;
632	}
633
634	ret = hx509_crypto_get_params(context,
635				      crypto,
636				      &ivec,
637				      enc_alg->parameters);
638	if (ret) {
639	    goto out;
640	}
641    }
642
643    ALLOC_SEQ(&ed.recipientInfos, 1);
644    if (ed.recipientInfos.val == NULL) {
645	ret = ENOMEM;
646	hx509_set_error_string(context, 0, ret,
647			       "Failed to allocate recipients info "
648			       "for EnvelopedData");
649	goto out;
650    }
651
652    ri = &ed.recipientInfos.val[0];
653
654    if (flags & HX509_CMS_EV_ID_NAME) {
655	ri->version = 0;
656	cmsidflag = CMS_ID_NAME;
657    } else {
658	ri->version = 2;
659	cmsidflag = CMS_ID_SKI;
660    }
661
662    ret = fill_CMSIdentifier(cert, cmsidflag, &ri->rid);
663    if (ret) {
664	hx509_set_error_string(context, 0, ret,
665			       "Failed to set CMS identifier info "
666			       "for EnvelopedData");
667	goto out;
668    }
669
670    ret = hx509_cert_public_encrypt(context,
671				     &key, cert,
672				     &ri->keyEncryptionAlgorithm.algorithm,
673				     &ri->encryptedKey);
674    if (ret) {
675	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
676			       "Failed to encrypt transport key for "
677			       "EnvelopedData");
678	goto out;
679    }
680
681    /*
682     *
683     */
684
685    ed.version = 0;
686    ed.originatorInfo = NULL;
687
688    ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType);
689    if (ret) {
690	hx509_set_error_string(context, 0, ret,
691			       "Failed to copy content oid for "
692			       "EnvelopedData");
693	goto out;
694    }
695
696    ed.unprotectedAttrs = NULL;
697
698    ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length,
699		       &ed, &size, ret);
700    if (ret) {
701	hx509_set_error_string(context, 0, ret,
702			       "Failed to encode EnvelopedData");
703	goto out;
704    }
705    if (size != content->length)
706	_hx509_abort("internal ASN.1 encoder error");
707
708out:
709    if (crypto)
710	hx509_crypto_destroy(crypto);
711    if (ret)
712	der_free_octet_string(content);
713    der_free_octet_string(&key);
714    der_free_octet_string(&ivec);
715    free_EnvelopedData(&ed);
716
717    return ret;
718}
719
720static int
721any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs)
722{
723    int ret, i;
724
725    if (sd->certificates == NULL)
726	return 0;
727
728    for (i = 0; i < sd->certificates->len; i++) {
729	hx509_cert c;
730
731	ret = hx509_cert_init_data(context,
732				   sd->certificates->val[i].data,
733				   sd->certificates->val[i].length,
734				   &c);
735	if (ret)
736	    return ret;
737	ret = hx509_certs_add(context, certs, c);
738	hx509_cert_free(c);
739	if (ret)
740	    return ret;
741    }
742
743    return 0;
744}
745
746static const Attribute *
747find_attribute(const CMSAttributes *attr, const heim_oid *oid)
748{
749    int i;
750    for (i = 0; i < attr->len; i++)
751	if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0)
752	    return &attr->val[i];
753    return NULL;
754}
755
756/**
757 * Decode SignedData and verify that the signature is correct.
758 *
759 * @param context A hx509 context.
760 * @param ctx a hx509 verify context.
761 * @param flags to control the behaivor of the function.
762 *    - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage
763 *    - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch
764 *    - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below.
765 * @param data pointer to CMS SignedData encoded data.
766 * @param length length of the data that data point to.
767 * @param signedContent external data used for signature.
768 * @param pool certificate pool to build certificates paths.
769 * @param contentType free with der_free_oid().
770 * @param content the output of the function, free with
771 * der_free_octet_string().
772 * @param signer_certs list of the cerficates used to sign this
773 * request, free with hx509_certs_free().
774 *
775 * @ingroup hx509_cms
776 */
777
778int
779hx509_cms_verify_signed(hx509_context context,
780			hx509_verify_ctx ctx,
781			unsigned int flags,
782			const void *data,
783			size_t length,
784			const heim_octet_string *signedContent,
785			hx509_certs pool,
786			heim_oid *contentType,
787			heim_octet_string *content,
788			hx509_certs *signer_certs)
789{
790    SignerInfo *signer_info;
791    hx509_cert cert = NULL;
792    hx509_certs certs = NULL;
793    SignedData sd;
794    size_t size;
795    int ret, i, found_valid_sig;
796
797    *signer_certs = NULL;
798    content->data = NULL;
799    content->length = 0;
800    contentType->length = 0;
801    contentType->components = NULL;
802
803    memset(&sd, 0, sizeof(sd));
804
805    ret = decode_SignedData(data, length, &sd, &size);
806    if (ret) {
807	hx509_set_error_string(context, 0, ret,
808			       "Failed to decode SignedData");
809	goto out;
810    }
811
812    if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) {
813	ret = HX509_CMS_NO_DATA_AVAILABLE;
814	hx509_set_error_string(context, 0, ret,
815			       "No content data in SignedData");
816	goto out;
817    }
818    if (sd.encapContentInfo.eContent && signedContent) {
819	ret = HX509_CMS_NO_DATA_AVAILABLE;
820	hx509_set_error_string(context, 0, ret,
821			       "Both external and internal SignedData");
822	goto out;
823    }
824
825    if (sd.encapContentInfo.eContent)
826	ret = der_copy_octet_string(sd.encapContentInfo.eContent, content);
827    else
828	ret = der_copy_octet_string(signedContent, content);
829    if (ret) {
830	hx509_set_error_string(context, 0, ret, "malloc: out of memory");
831	goto out;
832    }
833
834    ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
835			   0, NULL, &certs);
836    if (ret)
837	goto out;
838
839    ret = hx509_certs_init(context, "MEMORY:cms-signer-certs",
840			   0, NULL, signer_certs);
841    if (ret)
842	goto out;
843
844    /* XXX Check CMS version */
845
846    ret = any_to_certs(context, &sd, certs);
847    if (ret)
848	goto out;
849
850    if (pool) {
851	ret = hx509_certs_merge(context, certs, pool);
852	if (ret)
853	    goto out;
854    }
855
856    for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
857	heim_octet_string signed_data;
858	const heim_oid *match_oid;
859	heim_oid decode_oid;
860
861	signer_info = &sd.signerInfos.val[i];
862	match_oid = NULL;
863
864	if (signer_info->signature.length == 0) {
865	    ret = HX509_CMS_MISSING_SIGNER_DATA;
866	    hx509_set_error_string(context, 0, ret,
867				   "SignerInfo %d in SignedData "
868				   "missing sigature", i);
869	    continue;
870	}
871
872	ret = find_CMSIdentifier(context, &signer_info->sid, certs,
873				 _hx509_verify_get_time(ctx), &cert,
874				 HX509_QUERY_KU_DIGITALSIGNATURE);
875	if (ret) {
876	    /**
877	     * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal
878	     * search for matching certificates by not considering
879	     * KeyUsage bits on the certificates.
880	     */
881	    if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0)
882		continue;
883
884	    ret = find_CMSIdentifier(context, &signer_info->sid, certs,
885				     _hx509_verify_get_time(ctx), &cert,
886				     0);
887	    if (ret)
888		continue;
889
890	}
891
892	if (signer_info->signedAttrs) {
893	    const Attribute *attr;
894
895	    CMSAttributes sa;
896	    heim_octet_string os;
897
898	    sa.val = signer_info->signedAttrs->val;
899	    sa.len = signer_info->signedAttrs->len;
900
901	    /* verify that sigature exists */
902	    attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest);
903	    if (attr == NULL) {
904		ret = HX509_CRYPTO_SIGNATURE_MISSING;
905		hx509_set_error_string(context, 0, ret,
906				       "SignerInfo have signed attributes "
907				       "but messageDigest (signature) "
908				       "is missing");
909		goto next_sigature;
910	    }
911	    if (attr->value.len != 1) {
912		ret = HX509_CRYPTO_SIGNATURE_MISSING;
913		hx509_set_error_string(context, 0, ret,
914				       "SignerInfo have more then one "
915				       "messageDigest (signature)");
916		goto next_sigature;
917	    }
918
919	    ret = decode_MessageDigest(attr->value.val[0].data,
920				       attr->value.val[0].length,
921				       &os,
922				       &size);
923	    if (ret) {
924		hx509_set_error_string(context, 0, ret,
925				       "Failed to decode "
926				       "messageDigest (signature)");
927		goto next_sigature;
928	    }
929
930	    ret = _hx509_verify_signature(context,
931					  NULL,
932					  &signer_info->digestAlgorithm,
933					  content,
934					  &os);
935	    der_free_octet_string(&os);
936	    if (ret) {
937		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
938				       "Failed to verify messageDigest");
939		goto next_sigature;
940	    }
941
942	    /*
943	     * Fetch content oid inside signedAttrs or set it to
944	     * id-pkcs7-data.
945	     */
946	    attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType);
947	    if (attr == NULL) {
948		match_oid = &asn1_oid_id_pkcs7_data;
949	    } else {
950		if (attr->value.len != 1) {
951		    ret = HX509_CMS_DATA_OID_MISMATCH;
952		    hx509_set_error_string(context, 0, ret,
953					   "More then one oid in signedAttrs");
954		    goto next_sigature;
955
956		}
957		ret = decode_ContentType(attr->value.val[0].data,
958					 attr->value.val[0].length,
959					 &decode_oid,
960					 &size);
961		if (ret) {
962		    hx509_set_error_string(context, 0, ret,
963					   "Failed to decode "
964					   "oid in signedAttrs");
965		    goto next_sigature;
966		}
967		match_oid = &decode_oid;
968	    }
969
970	    ASN1_MALLOC_ENCODE(CMSAttributes,
971			       signed_data.data,
972			       signed_data.length,
973			       &sa,
974			       &size, ret);
975	    if (ret) {
976		if (match_oid == &decode_oid)
977		    der_free_oid(&decode_oid);
978		hx509_clear_error_string(context);
979		goto next_sigature;
980	    }
981	    if (size != signed_data.length)
982		_hx509_abort("internal ASN.1 encoder error");
983
984	} else {
985	    signed_data.data = content->data;
986	    signed_data.length = content->length;
987	    match_oid = &asn1_oid_id_pkcs7_data;
988	}
989
990	/**
991	 * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow
992	 * encapContentInfo mismatch with the oid in signedAttributes
993	 * (or if no signedAttributes where use, pkcs7-data oid).
994	 * This is only needed to work with broken CMS implementations
995	 * that doesn't follow CMS signedAttributes rules.
996	 */
997
998	if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) &&
999	    (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) {
1000	    ret = HX509_CMS_DATA_OID_MISMATCH;
1001	    hx509_set_error_string(context, 0, ret,
1002				   "Oid in message mismatch from the expected");
1003	}
1004	if (match_oid == &decode_oid)
1005	    der_free_oid(&decode_oid);
1006
1007	if (ret == 0) {
1008	    ret = hx509_verify_signature(context,
1009					 cert,
1010					 &signer_info->signatureAlgorithm,
1011					 &signed_data,
1012					 &signer_info->signature);
1013	    if (ret)
1014		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1015				       "Failed to verify signature in "
1016				       "CMS SignedData");
1017	}
1018        if (signer_info->signedAttrs)
1019	    free(signed_data.data);
1020	if (ret)
1021	    goto next_sigature;
1022
1023	/**
1024	 * If HX509_CMS_VS_NO_VALIDATE flags is set, do not verify the
1025	 * signing certificates and leave that up to the caller.
1026	 */
1027
1028	if ((flags & HX509_CMS_VS_NO_VALIDATE) == 0) {
1029	    ret = hx509_verify_path(context, ctx, cert, certs);
1030	    if (ret)
1031		goto next_sigature;
1032	}
1033
1034	ret = hx509_certs_add(context, *signer_certs, cert);
1035	if (ret)
1036	    goto next_sigature;
1037
1038	found_valid_sig++;
1039
1040    next_sigature:
1041	if (cert)
1042	    hx509_cert_free(cert);
1043	cert = NULL;
1044    }
1045    /**
1046     * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty
1047     * SignerInfo (no signatures). If SignedData have no signatures,
1048     * the function will return 0 with signer_certs set to NULL. Zero
1049     * signers is allowed by the standard, but since its only useful
1050     * in corner cases, it make into a flag that the caller have to
1051     * turn on.
1052     */
1053    if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) {
1054	if (*signer_certs)
1055	    hx509_certs_free(signer_certs);
1056    } else if (found_valid_sig == 0) {
1057	if (ret == 0) {
1058	    ret = HX509_CMS_SIGNER_NOT_FOUND;
1059	    hx509_set_error_string(context, 0, ret,
1060				   "No signers where found");
1061	}
1062	goto out;
1063    }
1064
1065    ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType);
1066    if (ret) {
1067	hx509_clear_error_string(context);
1068	goto out;
1069    }
1070
1071out:
1072    free_SignedData(&sd);
1073    if (certs)
1074	hx509_certs_free(&certs);
1075    if (ret) {
1076	if (content->data)
1077	    der_free_octet_string(content);
1078	if (*signer_certs)
1079	    hx509_certs_free(signer_certs);
1080	der_free_oid(contentType);
1081	der_free_octet_string(content);
1082    }
1083
1084    return ret;
1085}
1086
1087static int
1088add_one_attribute(Attribute **attr,
1089		  unsigned int *len,
1090		  const heim_oid *oid,
1091		  heim_octet_string *data)
1092{
1093    void *d;
1094    int ret;
1095
1096    d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1));
1097    if (d == NULL)
1098	return ENOMEM;
1099    (*attr) = d;
1100
1101    ret = der_copy_oid(oid, &(*attr)[*len].type);
1102    if (ret)
1103	return ret;
1104
1105    ALLOC_SEQ(&(*attr)[*len].value, 1);
1106    if ((*attr)[*len].value.val == NULL) {
1107	der_free_oid(&(*attr)[*len].type);
1108	return ENOMEM;
1109    }
1110
1111    (*attr)[*len].value.val[0].data = data->data;
1112    (*attr)[*len].value.val[0].length = data->length;
1113
1114    *len += 1;
1115
1116    return 0;
1117}
1118
1119/**
1120 * Decode SignedData and verify that the signature is correct.
1121 *
1122 * @param context A hx509 context.
1123 * @param flags
1124 * @param eContentType the type of the data.
1125 * @param data data to sign
1126 * @param length length of the data that data point to.
1127 * @param digest_alg digest algorithm to use, use NULL to get the
1128 * default or the peer determined algorithm.
1129 * @param cert certificate to use for sign the data.
1130 * @param peer info about the peer the message to send the message to,
1131 * like what digest algorithm to use.
1132 * @param anchors trust anchors that the client will use, used to
1133 * polulate the certificates included in the message
1134 * @param pool certificates to use in try to build the path to the
1135 * trust anchors.
1136 * @param signed_data the output of the function, free with
1137 * der_free_octet_string().
1138 *
1139 * @ingroup hx509_cms
1140 */
1141
1142int
1143hx509_cms_create_signed_1(hx509_context context,
1144			  int flags,
1145			  const heim_oid *eContentType,
1146			  const void *data, size_t length,
1147			  const AlgorithmIdentifier *digest_alg,
1148			  hx509_cert cert,
1149			  hx509_peer_info peer,
1150			  hx509_certs anchors,
1151			  hx509_certs pool,
1152			  heim_octet_string *signed_data)
1153{
1154    hx509_certs certs;
1155    int ret = 0;
1156
1157    signed_data->data = NULL;
1158    signed_data->length = 0;
1159
1160    ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs);
1161    if (ret)
1162	return ret;
1163    ret = hx509_certs_add(context, certs, cert);
1164    if (ret)
1165	goto out;
1166
1167    ret = hx509_cms_create_signed(context, flags, eContentType, data, length,
1168				  digest_alg, certs, peer, anchors, pool,
1169				  signed_data);
1170
1171 out:
1172    hx509_certs_free(&certs);
1173    return ret;
1174}
1175
1176struct sigctx {
1177    SignedData sd;
1178    const AlgorithmIdentifier *digest_alg;
1179    const heim_oid *eContentType;
1180    heim_octet_string content;
1181    hx509_peer_info peer;
1182    int cmsidflag;
1183    int leafonly;
1184    hx509_certs certs;
1185    hx509_certs anchors;
1186    hx509_certs pool;
1187};
1188
1189static int
1190sig_process(hx509_context context, void *ctx, hx509_cert cert)
1191{
1192    struct sigctx *sigctx = ctx;
1193    heim_octet_string buf, sigdata = { 0, NULL };
1194    SignerInfo *signer_info = NULL;
1195    AlgorithmIdentifier digest;
1196    size_t size;
1197    void *ptr;
1198    int ret;
1199    SignedData *sd = &sigctx->sd;
1200    hx509_path path;
1201
1202    memset(&digest, 0, sizeof(digest));
1203    memset(&path, 0, sizeof(path));
1204
1205    if (_hx509_cert_private_key(cert) == NULL) {
1206	hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1207			       "Private key missing for signing");
1208	return HX509_PRIVATE_KEY_MISSING;
1209    }
1210
1211    if (sigctx->digest_alg) {
1212	ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest);
1213	if (ret)
1214	    hx509_clear_error_string(context);
1215    } else {
1216	ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
1217				  _hx509_cert_private_key(cert),
1218				  sigctx->peer, &digest);
1219    }
1220    if (ret)
1221	goto out;
1222
1223    /*
1224     * Allocate on more signerInfo and do the signature processing
1225     */
1226
1227    ptr = realloc(sd->signerInfos.val,
1228		  (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0]));
1229    if (ptr == NULL) {
1230	ret = ENOMEM;
1231	goto out;
1232    }
1233    sd->signerInfos.val = ptr;
1234
1235    signer_info = &sd->signerInfos.val[sd->signerInfos.len];
1236
1237    memset(signer_info, 0, sizeof(*signer_info));
1238
1239    signer_info->version = 1;
1240
1241    ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid);
1242    if (ret) {
1243	hx509_clear_error_string(context);
1244	goto out;
1245    }
1246
1247    signer_info->signedAttrs = NULL;
1248    signer_info->unsignedAttrs = NULL;
1249
1250    ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
1251    if (ret) {
1252	hx509_clear_error_string(context);
1253	goto out;
1254    }
1255
1256    /*
1257     * If it isn't pkcs7-data send signedAttributes
1258     */
1259
1260    if (der_heim_oid_cmp(sigctx->eContentType, &asn1_oid_id_pkcs7_data) != 0) {
1261	CMSAttributes sa;
1262	heim_octet_string sig;
1263
1264	ALLOC(signer_info->signedAttrs, 1);
1265	if (signer_info->signedAttrs == NULL) {
1266	    ret = ENOMEM;
1267	    goto out;
1268	}
1269
1270	ret = _hx509_create_signature(context,
1271				      NULL,
1272				      &digest,
1273				      &sigctx->content,
1274				      NULL,
1275				      &sig);
1276	if (ret)
1277	    goto out;
1278
1279	ASN1_MALLOC_ENCODE(MessageDigest,
1280			   buf.data,
1281			   buf.length,
1282			   &sig,
1283			   &size,
1284			   ret);
1285	der_free_octet_string(&sig);
1286	if (ret) {
1287	    hx509_clear_error_string(context);
1288	    goto out;
1289	}
1290	if (size != buf.length)
1291	    _hx509_abort("internal ASN.1 encoder error");
1292
1293	ret = add_one_attribute(&signer_info->signedAttrs->val,
1294				&signer_info->signedAttrs->len,
1295				&asn1_oid_id_pkcs9_messageDigest,
1296				&buf);
1297	if (ret) {
1298	    free(buf.data);
1299	    hx509_clear_error_string(context);
1300	    goto out;
1301	}
1302
1303
1304	ASN1_MALLOC_ENCODE(ContentType,
1305			   buf.data,
1306			   buf.length,
1307			   sigctx->eContentType,
1308			   &size,
1309			   ret);
1310	if (ret)
1311	    goto out;
1312	if (size != buf.length)
1313	    _hx509_abort("internal ASN.1 encoder error");
1314
1315	ret = add_one_attribute(&signer_info->signedAttrs->val,
1316				&signer_info->signedAttrs->len,
1317				&asn1_oid_id_pkcs9_contentType,
1318				&buf);
1319	if (ret) {
1320	    free(buf.data);
1321	    hx509_clear_error_string(context);
1322	    goto out;
1323	}
1324
1325	sa.val = signer_info->signedAttrs->val;
1326	sa.len = signer_info->signedAttrs->len;
1327
1328	ASN1_MALLOC_ENCODE(CMSAttributes,
1329			   sigdata.data,
1330			   sigdata.length,
1331			   &sa,
1332			   &size,
1333			   ret);
1334	if (ret) {
1335	    hx509_clear_error_string(context);
1336	    goto out;
1337	}
1338	if (size != sigdata.length)
1339	    _hx509_abort("internal ASN.1 encoder error");
1340    } else {
1341	sigdata.data = sigctx->content.data;
1342	sigdata.length = sigctx->content.length;
1343    }
1344
1345    {
1346	AlgorithmIdentifier sigalg;
1347
1348	ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
1349				  _hx509_cert_private_key(cert), sigctx->peer,
1350				  &sigalg);
1351	if (ret)
1352	    goto out;
1353
1354	ret = _hx509_create_signature(context,
1355				      _hx509_cert_private_key(cert),
1356				      &sigalg,
1357				      &sigdata,
1358				      &signer_info->signatureAlgorithm,
1359				      &signer_info->signature);
1360	free_AlgorithmIdentifier(&sigalg);
1361	if (ret)
1362	    goto out;
1363    }
1364
1365    sigctx->sd.signerInfos.len++;
1366    signer_info = NULL;
1367
1368    /*
1369     * Provide best effort path
1370     */
1371    if (sigctx->certs) {
1372	unsigned int i;
1373
1374	if (sigctx->pool && sigctx->leafonly == 0) {
1375	    _hx509_calculate_path(context,
1376				  HX509_CALCULATE_PATH_NO_ANCHOR,
1377				  time(NULL),
1378				  sigctx->anchors,
1379				  0,
1380				  cert,
1381				  sigctx->pool,
1382				  &path);
1383	} else
1384	    _hx509_path_append(context, &path, cert);
1385
1386	for (i = 0; i < path.len; i++) {
1387	    /* XXX remove dups */
1388	    ret = hx509_certs_add(context, sigctx->certs, path.val[i]);
1389	    if (ret) {
1390		hx509_clear_error_string(context);
1391		goto out;
1392	    }
1393	}
1394    }
1395
1396 out:
1397    if (signer_info)
1398	free_SignerInfo(signer_info);
1399    if (sigdata.data != sigctx->content.data)
1400	der_free_octet_string(&sigdata);
1401    _hx509_path_free(&path);
1402    free_AlgorithmIdentifier(&digest);
1403
1404    return ret;
1405}
1406
1407static int
1408cert_process(hx509_context context, void *ctx, hx509_cert cert)
1409{
1410    struct sigctx *sigctx = ctx;
1411    const unsigned int i = sigctx->sd.certificates->len;
1412    void *ptr;
1413    int ret;
1414
1415    ptr = realloc(sigctx->sd.certificates->val,
1416		  (i + 1) * sizeof(sigctx->sd.certificates->val[0]));
1417    if (ptr == NULL)
1418	return ENOMEM;
1419    sigctx->sd.certificates->val = ptr;
1420
1421    ret = hx509_cert_binary(context, cert,
1422			    &sigctx->sd.certificates->val[i]);
1423    if (ret == 0)
1424	sigctx->sd.certificates->len++;
1425
1426    return ret;
1427}
1428
1429static int
1430cmp_AlgorithmIdentifier(const AlgorithmIdentifier *p, const AlgorithmIdentifier *q)
1431{
1432    return der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1433}
1434
1435int
1436hx509_cms_create_signed(hx509_context context,
1437			int flags,
1438			const heim_oid *eContentType,
1439			const void *data, size_t length,
1440			const AlgorithmIdentifier *digest_alg,
1441			hx509_certs certs,
1442			hx509_peer_info peer,
1443			hx509_certs anchors,
1444			hx509_certs pool,
1445			heim_octet_string *signed_data)
1446{
1447    unsigned int i, j;
1448    hx509_name name;
1449    int ret;
1450    size_t size;
1451    struct sigctx sigctx;
1452
1453    memset(&sigctx, 0, sizeof(sigctx));
1454    memset(&name, 0, sizeof(name));
1455
1456    if (eContentType == NULL)
1457	eContentType = &asn1_oid_id_pkcs7_data;
1458
1459    sigctx.digest_alg = digest_alg;
1460    sigctx.content.data = rk_UNCONST(data);
1461    sigctx.content.length = length;
1462    sigctx.eContentType = eContentType;
1463    sigctx.peer = peer;
1464    /**
1465     * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name
1466     * and serial number if possible. Otherwise subject key identifier
1467     * will preferred.
1468     */
1469    if (flags & HX509_CMS_SIGNATURE_ID_NAME)
1470	sigctx.cmsidflag = CMS_ID_NAME;
1471    else
1472	sigctx.cmsidflag = CMS_ID_SKI;
1473
1474    /**
1475     * Use HX509_CMS_SIGNATURE_LEAF_ONLY to only request leaf
1476     * certificates to be added to the SignedData.
1477     */
1478    sigctx.leafonly = (flags & HX509_CMS_SIGNATURE_LEAF_ONLY) ? 1 : 0;
1479
1480    /**
1481     * Use HX509_CMS_NO_CERTS to make the SignedData contain no
1482     * certificates, overrides HX509_CMS_SIGNATURE_LEAF_ONLY.
1483     */
1484
1485    if ((flags & HX509_CMS_SIGNATURE_NO_CERTS) == 0) {
1486	ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs);
1487	if (ret)
1488	    return ret;
1489    }
1490
1491    sigctx.anchors = anchors;
1492    sigctx.pool = pool;
1493
1494    sigctx.sd.version = CMSVersion_v3;
1495
1496    der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType);
1497
1498    /**
1499     * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures.
1500     */
1501    if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) {
1502	ALLOC(sigctx.sd.encapContentInfo.eContent, 1);
1503	if (sigctx.sd.encapContentInfo.eContent == NULL) {
1504	    hx509_clear_error_string(context);
1505	    ret = ENOMEM;
1506	    goto out;
1507	}
1508
1509	sigctx.sd.encapContentInfo.eContent->data = malloc(length);
1510	if (sigctx.sd.encapContentInfo.eContent->data == NULL) {
1511	    hx509_clear_error_string(context);
1512	    ret = ENOMEM;
1513	    goto out;
1514	}
1515	memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length);
1516	sigctx.sd.encapContentInfo.eContent->length = length;
1517    }
1518
1519    /**
1520     * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no
1521     * signatures).
1522     */
1523    if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) {
1524	ret = hx509_certs_iter_f(context, certs, sig_process, &sigctx);
1525	if (ret)
1526	    goto out;
1527    }
1528
1529    if (sigctx.sd.signerInfos.len) {
1530	for (i = 0; i < sigctx.sd.signerInfos.len; i++) {
1531	    AlgorithmIdentifier *di =
1532		&sigctx.sd.signerInfos.val[i].digestAlgorithm;
1533
1534	    for (j = 0; j < sigctx.sd.digestAlgorithms.len; j++)
1535		if (cmp_AlgorithmIdentifier(di, &sigctx.sd.digestAlgorithms.val[j]) == 0)
1536		    break;
1537	    if (j < sigctx.sd.digestAlgorithms.len) {
1538		ret = add_DigestAlgorithmIdentifiers(&sigctx.sd.digestAlgorithms, di);
1539		if (ret) {
1540		    hx509_clear_error_string(context);
1541		    goto out;
1542		}
1543	    }
1544	}
1545    }
1546
1547    if (sigctx.certs) {
1548	ALLOC(sigctx.sd.certificates, 1);
1549	if (sigctx.sd.certificates == NULL) {
1550	    hx509_clear_error_string(context);
1551	    ret = ENOMEM;
1552	    goto out;
1553	}
1554
1555	ret = hx509_certs_iter_f(context, sigctx.certs, cert_process, &sigctx);
1556	if (ret)
1557	    goto out;
1558    }
1559
1560    ASN1_MALLOC_ENCODE(SignedData,
1561		       signed_data->data, signed_data->length,
1562		       &sigctx.sd, &size, ret);
1563    if (ret) {
1564	hx509_clear_error_string(context);
1565	goto out;
1566    }
1567    if (signed_data->length != size)
1568	_hx509_abort("internal ASN.1 encoder error");
1569
1570out:
1571    hx509_certs_free(&sigctx.certs);
1572    free_SignedData(&sigctx.sd);
1573
1574    return ret;
1575}
1576
1577int
1578hx509_cms_decrypt_encrypted(hx509_context context,
1579			    hx509_lock lock,
1580			    const void *data,
1581			    size_t length,
1582			    heim_oid *contentType,
1583			    heim_octet_string *content)
1584{
1585    heim_octet_string cont;
1586    CMSEncryptedData ed;
1587    AlgorithmIdentifier *ai;
1588    int ret;
1589
1590    memset(content, 0, sizeof(*content));
1591    memset(&cont, 0, sizeof(cont));
1592
1593    ret = decode_CMSEncryptedData(data, length, &ed, NULL);
1594    if (ret) {
1595	hx509_set_error_string(context, 0, ret,
1596			       "Failed to decode CMSEncryptedData");
1597	return ret;
1598    }
1599
1600    if (ed.encryptedContentInfo.encryptedContent == NULL) {
1601	ret = HX509_CMS_NO_DATA_AVAILABLE;
1602	hx509_set_error_string(context, 0, ret,
1603			       "No content in EncryptedData");
1604	goto out;
1605    }
1606
1607    ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
1608    if (ret) {
1609	hx509_clear_error_string(context);
1610	goto out;
1611    }
1612
1613    ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
1614    if (ai->parameters == NULL) {
1615	ret = HX509_ALG_NOT_SUPP;
1616	hx509_clear_error_string(context);
1617	goto out;
1618    }
1619
1620    ret = _hx509_pbe_decrypt(context,
1621			     lock,
1622			     ai,
1623			     ed.encryptedContentInfo.encryptedContent,
1624			     &cont);
1625    if (ret)
1626	goto out;
1627
1628    *content = cont;
1629
1630out:
1631    if (ret) {
1632	if (cont.data)
1633	    free(cont.data);
1634    }
1635    free_CMSEncryptedData(&ed);
1636    return ret;
1637}
1638