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