xref: /freebsd/crypto/heimdal/lib/hx509/cms.c (revision 39beb93c)
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 }
1427