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"
35RCSID("$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
75int
76hx509_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
129int
130hx509_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
172static int
173fill_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
208static int
209unparse_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
259static int
260find_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
342int
343hx509_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
500out:
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
537int
538hx509_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
682out:
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
694static int
695any_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
720static const Attribute *
721find_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
748int
749hx509_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
1011out:
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
1025static int
1026add_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
1080int
1081hx509_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
1356out:
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
1366int
1367hx509_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
1419out:
1420    if (ret) {
1421	if (cont.data)
1422	    free(cont.data);
1423    }
1424    free_CMSEncryptedData(&ed);
1425    return ret;
1426}
1427