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