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