r23456: Update Samba4 to current lorikeet-heimdal.
[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 RCSID("$Id: cms.c 20937 2007-06-06 20:50:55Z lha $");
36
37 #define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
38 #define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
39
40 int
41 hx509_cms_wrap_ContentInfo(const heim_oid *oid,
42                            const heim_octet_string *buf,
43                            heim_octet_string *res)
44 {
45     ContentInfo ci;
46     size_t size;
47     int ret;
48
49     memset(res, 0, sizeof(*res));
50     memset(&ci, 0, sizeof(ci));
51
52     ret = der_copy_oid(oid, &ci.contentType);
53     if (ret)
54         return ret;
55     ALLOC(ci.content, 1);
56     if (ci.content == NULL) {
57         free_ContentInfo(&ci);
58         return ENOMEM;
59     }
60     ci.content->data = malloc(buf->length);
61     if (ci.content->data == NULL) {
62         free_ContentInfo(&ci);
63         return ENOMEM;
64     }
65     memcpy(ci.content->data, buf->data, buf->length);
66     ci.content->length = buf->length;
67
68     ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret);
69     free_ContentInfo(&ci);
70     if (ret)
71         return ret;
72     if (res->length != size)
73         _hx509_abort("internal ASN.1 encoder error");
74
75     return 0;
76 }
77
78 int
79 hx509_cms_unwrap_ContentInfo(const heim_octet_string *in,
80                              heim_oid *oid,
81                              heim_octet_string *out,
82                              int *have_data)
83 {
84     ContentInfo ci;
85     size_t size;
86     int ret;
87
88     memset(oid, 0, sizeof(*oid));
89     memset(out, 0, sizeof(*out));
90
91     ret = decode_ContentInfo(in->data, in->length, &ci, &size);
92     if (ret)
93         return ret;
94
95     ret = der_copy_oid(&ci.contentType, oid);
96     if (ret) {
97         free_ContentInfo(&ci);
98         return ret;
99     }
100     if (ci.content) {
101         ret = der_copy_octet_string(ci.content, out);
102         if (ret) {
103             der_free_oid(oid);
104             free_ContentInfo(&ci);
105             return ret;
106         }
107     } else
108         memset(out, 0, sizeof(*out));
109
110     if (have_data)
111         *have_data = (ci.content != NULL) ? 1 : 0;
112
113     free_ContentInfo(&ci);
114
115     return 0;
116 }
117
118 static int
119 fill_CMSIdentifier(const hx509_cert cert, CMSIdentifier *id)
120 {
121     hx509_name name;
122     int ret;
123
124     id->element = choice_CMSIdentifier_issuerAndSerialNumber;
125     ret = hx509_cert_get_issuer(cert, &name);
126     if (ret)
127         return ret;
128     ret = copy_Name(&name->der_name,
129                     &id->u.issuerAndSerialNumber.issuer);
130     hx509_name_free(&name);
131     if (ret)
132         return ret;
133
134     ret = hx509_cert_get_serialnumber(cert,
135                                       &id->u.issuerAndSerialNumber.serialNumber);
136     return ret;
137 }
138
139 static int
140 unparse_CMSIdentifier(hx509_context context,
141                       CMSIdentifier *id,
142                       char **str)
143 {
144     int ret;
145
146     *str = NULL;
147     switch (id->element) {
148     case choice_CMSIdentifier_issuerAndSerialNumber: {
149         IssuerAndSerialNumber *iasn;
150         char *serial, *name;
151
152         iasn = &id->u.issuerAndSerialNumber;
153
154         ret = _hx509_Name_to_string(&iasn->issuer, &name);
155         if(ret)
156             return ret;
157         ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial);
158         if (ret) {
159             free(name);
160             return ret;
161         }
162         asprintf(str, "certificate issued by %s with serial number %s",
163                  name, serial);
164         free(name);
165         free(serial);
166         break;
167     }
168     case choice_CMSIdentifier_subjectKeyIdentifier: {
169         KeyIdentifier *ki  = &id->u.subjectKeyIdentifier;
170         char *keyid;
171         ssize_t len;
172
173         len = hex_encode(ki->data, ki->length, &keyid);
174         if (len < 0)
175             return ENOMEM;
176
177         asprintf(str, "certificate with id %s", keyid);
178         free(keyid);
179         break;
180     }
181     default:
182         asprintf(str, "certificate have unknown CMSidentifier type");
183         break;
184     }
185     if (*str == NULL)
186         return ENOMEM;
187     return 0;
188 }
189
190 static int
191 find_CMSIdentifier(hx509_context context,
192                    CMSIdentifier *client,
193                    hx509_certs certs,
194                    hx509_cert *signer_cert,
195                    int match)
196 {
197     hx509_query q;
198     hx509_cert cert;
199     Certificate c;
200     int ret;
201
202     memset(&c, 0, sizeof(c));
203     _hx509_query_clear(&q);
204
205     *signer_cert = NULL;
206
207     switch (client->element) {
208     case choice_CMSIdentifier_issuerAndSerialNumber:
209         q.serial = &client->u.issuerAndSerialNumber.serialNumber;
210         q.issuer_name = &client->u.issuerAndSerialNumber.issuer;
211         q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
212         break;
213     case choice_CMSIdentifier_subjectKeyIdentifier:
214         q.subject_id = &client->u.subjectKeyIdentifier;
215         q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
216         break;
217     default:
218         hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE,
219                                "unknown CMS identifier element");
220         return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
221     }
222
223     q.match |= match;
224
225     q.match |= HX509_QUERY_MATCH_TIME;
226     q.timenow = time(NULL);
227
228     ret = hx509_certs_find(context, certs, &q, &cert);
229     if (ret == HX509_CERT_NOT_FOUND) {
230         char *str;
231
232         ret = unparse_CMSIdentifier(context, client, &str);
233         if (ret == 0) {
234             hx509_set_error_string(context, 0,
235                                    HX509_CMS_NO_RECIPIENT_CERTIFICATE,
236                                    "Failed to find %s", str);
237         } else
238             hx509_clear_error_string(context);
239         return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
240     } else if (ret) {
241         hx509_set_error_string(context, HX509_ERROR_APPEND,
242                                HX509_CMS_NO_RECIPIENT_CERTIFICATE,
243                                "Failed to find CMS id in cert store");
244         return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
245     }
246
247     *signer_cert = cert;
248
249     return 0;
250 }
251
252 int
253 hx509_cms_unenvelope(hx509_context context,
254                      hx509_certs certs,
255                      int flags,
256                      const void *data,
257                      size_t length,
258                      const heim_octet_string *encryptedContent,
259                      heim_oid *contentType,
260                      heim_octet_string *content)
261 {
262     heim_octet_string key;
263     EnvelopedData ed;
264     hx509_cert cert;
265     AlgorithmIdentifier *ai;
266     const heim_octet_string *enccontent;
267     heim_octet_string *params, params_data;
268     heim_octet_string ivec;
269     size_t size;
270     int ret, i, matched = 0, findflags = 0;
271
272
273     memset(&key, 0, sizeof(key));
274     memset(&ed, 0, sizeof(ed));
275     memset(&ivec, 0, sizeof(ivec));
276     memset(content, 0, sizeof(*content));
277     memset(contentType, 0, sizeof(*contentType));
278
279     if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
280         findflags |= HX509_QUERY_KU_ENCIPHERMENT;
281
282     ret = decode_EnvelopedData(data, length, &ed, &size);
283     if (ret) {
284         hx509_set_error_string(context, 0, ret,
285                                "Failed to decode EnvelopedData");
286         return ret;
287     }
288
289     if (ed.recipientInfos.len == 0) {
290         ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
291         hx509_set_error_string(context, 0, ret,
292                                "No recipient info in enveloped data");
293         goto out;
294     }
295
296     enccontent = ed.encryptedContentInfo.encryptedContent;
297     if (enccontent == NULL) {
298         if (encryptedContent == NULL) {
299             ret = HX509_CMS_NO_DATA_AVAILABLE;
300             hx509_set_error_string(context, 0, ret,
301                                    "Content missing from encrypted data");
302             goto out;
303         }
304         enccontent = encryptedContent;
305     } else if (encryptedContent != NULL) {
306         ret = HX509_CMS_NO_DATA_AVAILABLE;
307         hx509_set_error_string(context, 0, ret,
308                                "Both internal and external encrypted data");
309         goto out;
310     }
311
312     cert = NULL;
313     for (i = 0; i < ed.recipientInfos.len; i++) {
314         KeyTransRecipientInfo *ri;
315         char *str;
316         int ret2;
317
318         ri = &ed.recipientInfos.val[i];
319
320         /* ret = search_keyset(ri,
321          *      PRIVATE_KEY,
322          *      ki->keyEncryptionAlgorithm.algorithm);
323          */
324
325         ret = find_CMSIdentifier(context, &ri->rid, certs, &cert,
326                                  HX509_QUERY_PRIVATE_KEY|findflags);
327         if (ret)
328             continue;
329
330         matched = 1; /* found a matching certificate, let decrypt */
331
332         ret = _hx509_cert_private_decrypt(context,
333                                           &ri->encryptedKey,
334                                           &ri->keyEncryptionAlgorithm.algorithm,
335                                           cert, &key);
336
337         hx509_cert_free(cert);
338         if (ret == 0)
339             break; /* succuessfully decrypted cert */
340         cert = NULL;
341         ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
342         if (ret2 == 0) {
343             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
344                                    "Failed to decrypt with %s", str);
345             free(str);
346         }
347     }
348
349     if (!matched) {
350         ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
351         hx509_set_error_string(context, 0, ret,
352                                "No private key matched any certificate");
353         goto out;
354     }
355
356     if (cert == NULL) {
357         ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
358         hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
359                                "No private key decrypted the transfer key");
360         goto out;
361     }
362
363     ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
364     if (ret) {
365         hx509_set_error_string(context, 0, ret,
366                                "Failed to copy EnvelopedData content oid");
367         goto out;
368     }
369
370     ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
371     if (ai->parameters) {
372         params_data.data = ai->parameters->data;
373         params_data.length = ai->parameters->length;
374         params = &params_data;
375     } else
376         params = NULL;
377
378     {
379         hx509_crypto crypto;
380
381         ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto);
382         if (ret)
383             goto out;
384         
385         if (params) {
386             ret = hx509_crypto_set_params(context, crypto, params, &ivec);
387             if (ret) {
388                 hx509_crypto_destroy(crypto);
389                 goto out;
390             }
391         }
392
393         ret = hx509_crypto_set_key_data(crypto, key.data, key.length);
394         if (ret) {
395             hx509_crypto_destroy(crypto);
396             hx509_set_error_string(context, 0, ret,
397                                    "Failed to set key for decryption "
398                                    "of EnvelopedData");
399             goto out;
400         }
401         
402         ret = hx509_crypto_decrypt(crypto,
403                                    enccontent->data,
404                                    enccontent->length,
405                                    ivec.length ? &ivec : NULL,
406                                    content);
407         hx509_crypto_destroy(crypto);
408         if (ret) {
409             hx509_set_error_string(context, 0, ret,
410                                    "Failed to decrypt EnvelopedData");
411             goto out;
412         }
413     }
414
415 out:
416
417     free_EnvelopedData(&ed);
418     der_free_octet_string(&key);
419     if (ivec.length)
420         der_free_octet_string(&ivec);
421     if (ret) {
422         der_free_oid(contentType);
423         der_free_octet_string(content);
424     }
425
426     return ret;
427 }
428
429 int
430 hx509_cms_envelope_1(hx509_context context,
431                      int flags,
432                      hx509_cert cert,
433                      const void *data,
434                      size_t length,
435                      const heim_oid *encryption_type,
436                      const heim_oid *contentType,
437                      heim_octet_string *content)
438 {
439     KeyTransRecipientInfo *ri;
440     heim_octet_string ivec;
441     heim_octet_string key;
442     hx509_crypto crypto = NULL;
443     EnvelopedData ed;
444     size_t size;
445     int ret;
446
447     memset(&ivec, 0, sizeof(ivec));
448     memset(&key, 0, sizeof(key));
449     memset(&ed, 0, sizeof(ed));
450     memset(content, 0, sizeof(*content));
451
452     if (encryption_type == NULL)
453         encryption_type = oid_id_aes_256_cbc();
454
455     ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
456     if (ret)
457         goto out;
458
459     ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
460     if (ret)
461         goto out;
462
463     ret = hx509_crypto_set_random_key(crypto, &key);
464     if (ret) {
465         hx509_set_error_string(context, 0, ret,
466                                "Create random key for EnvelopedData content");
467         goto out;
468     }
469
470     ret = hx509_crypto_encrypt(crypto,
471                                data,
472                                length,
473                                &ivec,
474                                &ed.encryptedContentInfo.encryptedContent);
475     if (ret) {
476         hx509_set_error_string(context, 0, ret,
477                                "Failed to encrypt EnvelopedData content");
478         goto out;
479     }
480
481     {
482         AlgorithmIdentifier *enc_alg;
483         enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
484         ret = der_copy_oid(encryption_type, &enc_alg->algorithm);
485         if (ret) {
486             hx509_set_error_string(context, 0, ret,
487                                    "Failed to set crypto oid "
488                                    "for EnvelopedData");
489             goto out;
490         }       
491         ALLOC(enc_alg->parameters, 1);
492         if (enc_alg->parameters == NULL) {
493             ret = ENOMEM;
494             hx509_set_error_string(context, 0, ret,
495                                    "Failed to allocate crypto paramaters "
496                                    "for EnvelopedData");
497             goto out;
498         }
499
500         ret = hx509_crypto_get_params(context,
501                                       crypto,
502                                       &ivec,
503                                       enc_alg->parameters);
504         if (ret) {
505             goto out;
506         }
507     }
508
509     ALLOC_SEQ(&ed.recipientInfos, 1);
510     if (ed.recipientInfos.val == NULL) {
511         ret = ENOMEM;
512         hx509_set_error_string(context, 0, ret,
513                                "Failed to allocate recipients info "
514                                "for EnvelopedData");
515         goto out;
516     }
517
518     ri = &ed.recipientInfos.val[0];
519
520     ri->version = 0;
521     ret = fill_CMSIdentifier(cert, &ri->rid);
522     if (ret) {
523         hx509_set_error_string(context, 0, ret,
524                                "Failed to set CMS identifier info "
525                                "for EnvelopedData");
526         goto out;
527     }
528
529     ret = _hx509_cert_public_encrypt(context,
530                                      &key, cert,
531                                      &ri->keyEncryptionAlgorithm.algorithm,
532                                      &ri->encryptedKey);
533     if (ret) {
534         hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
535                                "Failed to encrypt transport key for "
536                                "EnvelopedData");
537         goto out;
538     }
539
540     /*
541      *
542      */
543
544     ed.version = 0;
545     ed.originatorInfo = NULL;
546
547     ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType);
548     if (ret) {
549         hx509_set_error_string(context, 0, ret,
550                                "Failed to copy content oid for "
551                                "EnvelopedData");
552         goto out;
553     }
554
555     ed.unprotectedAttrs = NULL;
556
557     ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length,
558                        &ed, &size, ret);
559     if (ret) {
560         hx509_set_error_string(context, 0, ret,
561                                "Failed to encode EnvelopedData");
562         goto out;
563     }
564     if (size != content->length)
565         _hx509_abort("internal ASN.1 encoder error");
566
567 out:
568     if (crypto)
569         hx509_crypto_destroy(crypto);
570     if (ret)
571         der_free_octet_string(content);
572     der_free_octet_string(&key);
573     der_free_octet_string(&ivec);
574     free_EnvelopedData(&ed);
575
576     return ret;
577 }
578
579 static int
580 any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs)
581 {
582     int ret, i;
583
584     if (sd->certificates == NULL)
585         return 0;
586
587     for (i = 0; i < sd->certificates->len; i++) {
588         Certificate cert;
589         hx509_cert c;
590
591         const void *p = sd->certificates->val[i].data;
592         size_t size, length = sd->certificates->val[i].length;
593
594         ret = decode_Certificate(p, length, &cert, &size);
595         if (ret) {
596             hx509_set_error_string(context, 0, ret,
597                                    "Failed to decode certificate %d "
598                                    "in SignedData.certificates", i);
599             return ret;
600         }
601
602         ret = hx509_cert_init(context, &cert, &c);
603         free_Certificate(&cert);
604         if (ret)
605             return ret;
606         ret = hx509_certs_add(context, certs, c);
607         hx509_cert_free(c);
608         if (ret)
609             return ret;
610     }
611
612     return 0;
613 }
614
615 static const Attribute *
616 find_attribute(const CMSAttributes *attr, const heim_oid *oid)
617 {
618     int i;
619     for (i = 0; i < attr->len; i++)
620         if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0)
621             return &attr->val[i];
622     return NULL;
623 }
624
625 int
626 hx509_cms_verify_signed(hx509_context context,
627                         hx509_verify_ctx ctx,
628                         const void *data,
629                         size_t length,
630                         const heim_octet_string *signedContent,
631                         hx509_certs store,
632                         heim_oid *contentType,
633                         heim_octet_string *content,
634                         hx509_certs *signer_certs)
635 {
636     SignerInfo *signer_info;
637     hx509_cert cert = NULL;
638     hx509_certs certs = NULL;
639     SignedData sd;
640     size_t size;
641     int ret, i, found_valid_sig;
642
643     *signer_certs = NULL;
644     content->data = NULL;
645     content->length = 0;
646     contentType->length = 0;
647     contentType->components = NULL;
648
649     memset(&sd, 0, sizeof(sd));
650
651     ret = decode_SignedData(data, length, &sd, &size);
652     if (ret) {
653         hx509_set_error_string(context, 0, ret,
654                                "Failed to decode SignedData");
655         goto out;
656     }
657
658     if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) {
659         ret = HX509_CMS_NO_DATA_AVAILABLE;
660         hx509_set_error_string(context, 0, ret,
661                                "No content data in SignedData");
662         goto out;
663     }
664     if (sd.encapContentInfo.eContent && signedContent) {
665         ret = HX509_CMS_NO_DATA_AVAILABLE;
666         hx509_set_error_string(context, 0, ret,
667                                "Both external and internal SignedData");
668         goto out;
669     }
670     if (sd.encapContentInfo.eContent)
671         signedContent = sd.encapContentInfo.eContent;
672
673     ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
674                            0, NULL, &certs);
675     if (ret)
676         goto out;
677
678     ret = hx509_certs_init(context, "MEMORY:cms-signer-certs",
679                            0, NULL, signer_certs);
680     if (ret)
681         goto out;
682
683     /* XXX Check CMS version */
684
685     ret = any_to_certs(context, &sd, certs);
686     if (ret)
687         goto out;
688
689     if (store) {
690         ret = hx509_certs_merge(context, certs, store);
691         if (ret)
692             goto out;
693     }
694
695     for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
696         heim_octet_string *signed_data;
697         const heim_oid *match_oid;
698         heim_oid decode_oid;
699
700         signer_info = &sd.signerInfos.val[i];
701         match_oid = NULL;
702
703         if (signer_info->signature.length == 0) {
704             ret = HX509_CMS_MISSING_SIGNER_DATA;
705             hx509_set_error_string(context, 0, ret,
706                                    "SignerInfo %d in SignedData "
707                                    "missing sigature", i);
708             continue;
709         }
710
711         ret = find_CMSIdentifier(context, &signer_info->sid, certs, &cert,
712                                  HX509_QUERY_KU_DIGITALSIGNATURE);
713         if (ret)
714             continue;
715
716         if (signer_info->signedAttrs) {
717             const Attribute *attr;
718         
719             CMSAttributes sa;
720             heim_octet_string os;
721
722             sa.val = signer_info->signedAttrs->val;
723             sa.len = signer_info->signedAttrs->len;
724
725             /* verify that sigature exists */
726             attr = find_attribute(&sa, oid_id_pkcs9_messageDigest());
727             if (attr == NULL) {
728                 ret = HX509_CRYPTO_SIGNATURE_MISSING;
729                 hx509_set_error_string(context, 0, ret,
730                                        "SignerInfo have signed attributes "
731                                        "but messageDigest (signature) "
732                                        "is missing");
733                 goto next_sigature;
734             }
735             if (attr->value.len != 1) {
736                 ret = HX509_CRYPTO_SIGNATURE_MISSING;
737                 hx509_set_error_string(context, 0, ret,
738                                        "SignerInfo have more then one "
739                                        "messageDigest (signature)");
740                 goto next_sigature;
741             }
742         
743             ret = decode_MessageDigest(attr->value.val[0].data,
744                                        attr->value.val[0].length,
745                                        &os,
746                                        &size);
747             if (ret) {
748                 hx509_set_error_string(context, 0, ret,
749                                        "Failed to decode "
750                                        "messageDigest (signature)");
751                 goto next_sigature;
752             }
753
754             ret = _hx509_verify_signature(context,
755                                           NULL,
756                                           &signer_info->digestAlgorithm,
757                                           signedContent,
758                                           &os);
759             der_free_octet_string(&os);
760             if (ret) {
761                 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
762                                        "Failed to verify messageDigest");
763                 goto next_sigature;
764             }
765
766             /*
767              * Fetch content oid inside signedAttrs or set it to
768              * id-pkcs7-data.
769              */
770             attr = find_attribute(&sa, oid_id_pkcs9_contentType());
771             if (attr == NULL) {
772                 match_oid = oid_id_pkcs7_data();
773             } else {
774                 if (attr->value.len != 1) {
775                     ret = HX509_CMS_DATA_OID_MISMATCH;
776                     hx509_set_error_string(context, 0, ret,
777                                            "More then one oid in signedAttrs");
778                     goto next_sigature;
779
780                 }
781                 ret = decode_ContentType(attr->value.val[0].data,
782                                          attr->value.val[0].length,
783                                          &decode_oid,
784                                          &size);
785                 if (ret) {
786                     hx509_set_error_string(context, 0, ret,
787                                            "Failed to decode "
788                                            "oid in signedAttrs");
789                     goto next_sigature;
790                 }
791                 match_oid = &decode_oid;
792             }
793
794             ALLOC(signed_data, 1);
795             if (signed_data == NULL) {
796                 if (match_oid == &decode_oid)
797                     der_free_oid(&decode_oid);
798                 ret = ENOMEM;
799                 hx509_clear_error_string(context);
800                 goto next_sigature;
801             }
802         
803             ASN1_MALLOC_ENCODE(CMSAttributes,
804                                signed_data->data,
805                                signed_data->length,
806                                &sa,
807                                &size, ret);
808             if (ret) {
809                 if (match_oid == &decode_oid)
810                     der_free_oid(&decode_oid);
811                 free(signed_data);
812                 hx509_clear_error_string(context);
813                 goto next_sigature;
814             }
815             if (size != signed_data->length)
816                 _hx509_abort("internal ASN.1 encoder error");
817
818         } else {
819             signed_data = rk_UNCONST(signedContent);
820             match_oid = oid_id_pkcs7_data();
821         }
822
823         if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType)) {
824             ret = HX509_CMS_DATA_OID_MISMATCH;
825             hx509_set_error_string(context, 0, ret,
826                                    "Oid in message mismatch from the expected");
827         }
828         if (match_oid == &decode_oid)
829             der_free_oid(&decode_oid);
830
831         if (ret == 0) {
832             ret = hx509_verify_signature(context,
833                                          cert,
834                                          &signer_info->signatureAlgorithm,
835                                          signed_data,
836                                          &signer_info->signature);
837             if (ret)
838                 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
839                                        "Failed to verify sigature in "
840                                        "CMS SignedData");
841         }
842         if (signed_data != signedContent) {
843             der_free_octet_string(signed_data);
844             free(signed_data);
845         }
846         if (ret)
847             goto next_sigature;
848
849         ret = hx509_verify_path(context, ctx, cert, certs);
850         if (ret)
851             goto next_sigature;
852
853         ret = hx509_certs_add(context, *signer_certs, cert);
854         if (ret)
855             goto next_sigature;
856
857         found_valid_sig++;
858
859     next_sigature:
860         if (cert)
861             hx509_cert_free(cert);
862         cert = NULL;
863     }
864     if (found_valid_sig == 0) {
865         if (ret == 0) {
866             ret = HX509_CMS_SIGNER_NOT_FOUND;
867             hx509_set_error_string(context, 0, ret,
868                                    "No signers where found");
869         }
870         goto out;
871     }
872
873     ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType);
874     if (ret) {
875         hx509_clear_error_string(context);
876         goto out;
877     }
878
879     content->data = malloc(signedContent->length);
880     if (content->data == NULL) {
881         hx509_clear_error_string(context);
882         ret = ENOMEM;
883         goto out;
884     }
885     content->length = signedContent->length;
886     memcpy(content->data, signedContent->data, content->length);
887
888 out:
889     free_SignedData(&sd);
890     if (certs)
891         hx509_certs_free(&certs);
892     if (ret) {
893         if (*signer_certs)
894             hx509_certs_free(signer_certs);
895         der_free_oid(contentType);
896         der_free_octet_string(content);
897     }
898
899     return ret;
900 }
901
902 static int
903 add_one_attribute(Attribute **attr,
904                   unsigned int *len,
905                   const heim_oid *oid,
906                   heim_octet_string *data)
907 {
908     void *d;
909     int ret;
910
911     d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1));
912     if (d == NULL)
913         return ENOMEM;
914     (*attr) = d;
915
916     ret = der_copy_oid(oid, &(*attr)[*len].type);
917     if (ret)
918         return ret;
919
920     ALLOC_SEQ(&(*attr)[*len].value, 1);
921     if ((*attr)[*len].value.val == NULL) {
922         der_free_oid(&(*attr)[*len].type);
923         return ENOMEM;
924     }
925
926     (*attr)[*len].value.val[0].data = data->data;
927     (*attr)[*len].value.val[0].length = data->length;
928
929     *len += 1;
930
931     return 0;
932 }
933         
934 int
935 hx509_cms_create_signed_1(hx509_context context,
936                           int flags,
937                           const heim_oid *eContentType,
938                           const void *data, size_t length,
939                           const AlgorithmIdentifier *digest_alg,
940                           hx509_cert cert,
941                           hx509_peer_info peer,
942                           hx509_certs anchors,
943                           hx509_certs pool,
944                           heim_octet_string *signed_data)
945 {
946     AlgorithmIdentifier digest;
947     hx509_name name;
948     SignerInfo *signer_info;
949     heim_octet_string buf, content, sigdata = { 0, NULL };
950     SignedData sd;
951     int ret;
952     size_t size;
953     hx509_path path;
954
955     memset(&sd, 0, sizeof(sd));
956     memset(&name, 0, sizeof(name));
957     memset(&path, 0, sizeof(path));
958     memset(&digest, 0, sizeof(digest));
959
960     content.data = rk_UNCONST(data);
961     content.length = length;
962
963     if (_hx509_cert_private_key(cert) == NULL) {
964         hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
965                                "Private key missing for signing");
966         return HX509_PRIVATE_KEY_MISSING;
967     }
968
969     if (digest_alg == NULL) {
970         ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
971                                   _hx509_cert_private_key(cert), peer, &digest);
972     } else {
973         ret = copy_AlgorithmIdentifier(digest_alg, &digest);
974         if (ret)
975             hx509_clear_error_string(context);
976     }
977     if (ret)
978         goto out;
979
980     sd.version = CMSVersion_v3;
981
982     if (eContentType == NULL)
983         eContentType = oid_id_pkcs7_data();
984
985     der_copy_oid(eContentType, &sd.encapContentInfo.eContentType);
986
987     /* */
988     if ((flags & HX509_CMS_SIGATURE_DETACHED) == 0) {
989         ALLOC(sd.encapContentInfo.eContent, 1);
990         if (sd.encapContentInfo.eContent == NULL) {
991             hx509_clear_error_string(context);
992             ret = ENOMEM;
993             goto out;
994         }
995         
996         sd.encapContentInfo.eContent->data = malloc(length);
997         if (sd.encapContentInfo.eContent->data == NULL) {
998             hx509_clear_error_string(context);
999             ret = ENOMEM;
1000             goto out;
1001         }
1002         memcpy(sd.encapContentInfo.eContent->data, data, length);
1003         sd.encapContentInfo.eContent->length = length;
1004     }
1005
1006     ALLOC_SEQ(&sd.signerInfos, 1);
1007     if (sd.signerInfos.val == NULL) {
1008         hx509_clear_error_string(context);
1009         ret = ENOMEM;
1010         goto out;
1011     }
1012
1013     signer_info = &sd.signerInfos.val[0];
1014
1015     signer_info->version = 1;
1016
1017     ret = fill_CMSIdentifier(cert, &signer_info->sid);
1018     if (ret) {
1019         hx509_clear_error_string(context);
1020         goto out;
1021     }                   
1022
1023     signer_info->signedAttrs = NULL;
1024     signer_info->unsignedAttrs = NULL;
1025
1026
1027     ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
1028     if (ret) {
1029         hx509_clear_error_string(context);
1030         goto out;
1031     }
1032
1033     /*
1034      * If its not pkcs7-data send signedAttributes
1035      */
1036
1037     if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) {
1038         CMSAttributes sa;       
1039         heim_octet_string sig;
1040
1041         ALLOC(signer_info->signedAttrs, 1);
1042         if (signer_info->signedAttrs == NULL) {
1043             ret = ENOMEM;
1044             goto out;
1045         }
1046
1047         ret = _hx509_create_signature(context,
1048                                       NULL,
1049                                       &digest,
1050                                       &content,
1051                                       NULL,
1052                                       &sig);
1053         if (ret)
1054             goto out;
1055
1056         ASN1_MALLOC_ENCODE(MessageDigest,
1057                            buf.data,
1058                            buf.length,
1059                            &sig,
1060                            &size,
1061                            ret);
1062         der_free_octet_string(&sig);
1063         if (ret) {
1064             hx509_clear_error_string(context);
1065             goto out;
1066         }
1067         if (size != buf.length)
1068             _hx509_abort("internal ASN.1 encoder error");
1069
1070         ret = add_one_attribute(&signer_info->signedAttrs->val,
1071                                 &signer_info->signedAttrs->len,
1072                                 oid_id_pkcs9_messageDigest(),
1073                                 &buf);
1074         if (ret) {
1075             hx509_clear_error_string(context);
1076             goto out;
1077         }
1078
1079
1080         ASN1_MALLOC_ENCODE(ContentType,
1081                            buf.data,
1082                            buf.length,
1083                            eContentType,
1084                            &size,
1085                            ret);
1086         if (ret)
1087             goto out;
1088         if (size != buf.length)
1089             _hx509_abort("internal ASN.1 encoder error");
1090
1091         ret = add_one_attribute(&signer_info->signedAttrs->val,
1092                                 &signer_info->signedAttrs->len,
1093                                 oid_id_pkcs9_contentType(),
1094                                 &buf);
1095         if (ret) {
1096             hx509_clear_error_string(context);
1097             goto out;
1098         }
1099
1100         sa.val = signer_info->signedAttrs->val;
1101         sa.len = signer_info->signedAttrs->len;
1102         
1103         ASN1_MALLOC_ENCODE(CMSAttributes,
1104                            sigdata.data,
1105                            sigdata.length,
1106                            &sa,
1107                            &size,
1108                            ret);
1109         if (ret) {
1110             hx509_clear_error_string(context);
1111             goto out;
1112         }
1113         if (size != sigdata.length)
1114             _hx509_abort("internal ASN.1 encoder error");
1115     } else {
1116         sigdata.data = content.data;
1117         sigdata.length = content.length;
1118     }
1119
1120
1121     {
1122         AlgorithmIdentifier sigalg;
1123
1124         ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
1125                                   _hx509_cert_private_key(cert), peer,
1126                                   &sigalg);
1127         if (ret)
1128             goto out;
1129
1130         ret = _hx509_create_signature(context,
1131                                       _hx509_cert_private_key(cert),
1132                                       &sigalg,
1133                                       &sigdata,
1134                                       &signer_info->signatureAlgorithm,
1135                                       &signer_info->signature);
1136         free_AlgorithmIdentifier(&sigalg);
1137         if (ret)
1138             goto out;
1139     }
1140
1141     ALLOC_SEQ(&sd.digestAlgorithms, 1);
1142     if (sd.digestAlgorithms.val == NULL) {
1143         ret = ENOMEM;
1144         hx509_clear_error_string(context);
1145         goto out;
1146     }
1147
1148     ret = copy_AlgorithmIdentifier(&digest, &sd.digestAlgorithms.val[0]);
1149     if (ret) {
1150         hx509_clear_error_string(context);
1151         goto out;
1152     }
1153
1154     /*
1155      * Provide best effort path
1156      */
1157     if (pool) {
1158         _hx509_calculate_path(context,
1159                               HX509_CALCULATE_PATH_NO_ANCHOR,                         
1160                               time(NULL),
1161                               anchors,
1162                               0,
1163                               cert,
1164                               pool,
1165                               &path);
1166     } else
1167         _hx509_path_append(context, &path, cert);
1168
1169
1170     if (path.len) {
1171         int i;
1172
1173         ALLOC(sd.certificates, 1);
1174         if (sd.certificates == NULL) {
1175             hx509_clear_error_string(context);
1176             ret = ENOMEM;
1177             goto out;
1178         }
1179         ALLOC_SEQ(sd.certificates, path.len);
1180         if (sd.certificates->val == NULL) {
1181             hx509_clear_error_string(context);
1182             ret = ENOMEM;
1183             goto out;
1184         }
1185
1186         for (i = 0; i < path.len; i++) {
1187             ret = hx509_cert_binary(context, path.val[i],
1188                                     &sd.certificates->val[i]);
1189             if (ret) {
1190                 hx509_clear_error_string(context);
1191                 goto out;
1192             }
1193         }
1194     }
1195
1196     ASN1_MALLOC_ENCODE(SignedData,
1197                        signed_data->data, signed_data->length,
1198                        &sd, &size, ret);
1199     if (ret) {
1200         hx509_clear_error_string(context);
1201         goto out;
1202     }
1203     if (signed_data->length != size)
1204         _hx509_abort("internal ASN.1 encoder error");
1205
1206 out:
1207     if (sigdata.data != content.data)
1208         der_free_octet_string(&sigdata);
1209     free_AlgorithmIdentifier(&digest);
1210     _hx509_path_free(&path);
1211     free_SignedData(&sd);
1212
1213     return ret;
1214 }
1215
1216 int
1217 hx509_cms_decrypt_encrypted(hx509_context context,
1218                             hx509_lock lock,
1219                             const void *data,
1220                             size_t length,
1221                             heim_oid *contentType,
1222                             heim_octet_string *content)
1223 {
1224     heim_octet_string cont;
1225     CMSEncryptedData ed;
1226     AlgorithmIdentifier *ai;
1227     int ret;
1228
1229     memset(content, 0, sizeof(*content));
1230     memset(&cont, 0, sizeof(cont));
1231
1232     ret = decode_CMSEncryptedData(data, length, &ed, NULL);
1233     if (ret) {
1234         hx509_set_error_string(context, 0, ret,
1235                                "Failed to decode CMSEncryptedData");
1236         return ret;
1237     }
1238
1239     if (ed.encryptedContentInfo.encryptedContent == NULL) {
1240         ret = HX509_CMS_NO_DATA_AVAILABLE;
1241         hx509_set_error_string(context, 0, ret,
1242                                "No content in EncryptedData");
1243         goto out;
1244     }
1245
1246     ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
1247     if (ret) {
1248         hx509_clear_error_string(context);
1249         goto out;
1250     }
1251
1252     ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
1253     if (ai->parameters == NULL) {
1254         ret = HX509_ALG_NOT_SUPP;
1255         hx509_clear_error_string(context);
1256         goto out;
1257     }
1258
1259     ret = _hx509_pbe_decrypt(context,
1260                              lock,
1261                              ai,
1262                              ed.encryptedContentInfo.encryptedContent,
1263                              &cont);
1264     if (ret)
1265         goto out;
1266
1267     *content = cont;
1268
1269 out:
1270     if (ret) {
1271         if (cont.data)
1272             free(cont.data);
1273     }
1274     free_CMSEncryptedData(&ed);
1275     return ret;
1276 }