Home | History | Annotate | Line # | Download | only in hx509
      1 /*	$NetBSD: cms.c,v 1.4 2023/06/19 21:41:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2003 - 2007 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include "hx_locl.h"
     37 
     38 /**
     39  * @page page_cms CMS/PKCS7 message functions.
     40  *
     41  * CMS is defined in RFC 3369 and is an continuation of the RSA Labs
     42  * standard PKCS7. The basic messages in CMS is
     43  *
     44  * - SignedData
     45  *   Data signed with private key (RSA, DSA, ECDSA) or secret
     46  *   (symmetric) key
     47  * - EnvelopedData
     48  *   Data encrypted with private key (RSA)
     49  * - EncryptedData
     50  *   Data encrypted with secret (symmetric) key.
     51  * - ContentInfo
     52  *   Wrapper structure including type and data.
     53  *
     54  *
     55  * See the library functions here: @ref hx509_cms
     56  */
     57 
     58 #define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
     59 #define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
     60 
     61 /**
     62  * Wrap data and oid in a ContentInfo and encode it.
     63  *
     64  * @param oid type of the content.
     65  * @param buf data to be wrapped. If a NULL pointer is passed in, the
     66  * optional content field in the ContentInfo is not going be filled
     67  * in.
     68  * @param res the encoded buffer, the result should be freed with
     69  * der_free_octet_string().
     70  *
     71  * @return Returns an hx509 error code.
     72  *
     73  * @ingroup hx509_cms
     74  */
     75 
     76 int
     77 hx509_cms_wrap_ContentInfo(const heim_oid *oid,
     78 			   const heim_octet_string *buf,
     79 			   heim_octet_string *res)
     80 {
     81     ContentInfo ci;
     82     size_t size;
     83     int ret;
     84 
     85     memset(res, 0, sizeof(*res));
     86     memset(&ci, 0, sizeof(ci));
     87 
     88     ret = der_copy_oid(oid, &ci.contentType);
     89     if (ret)
     90 	return ret;
     91     if (buf) {
     92 	ALLOC(ci.content, 1);
     93 	if (ci.content == NULL) {
     94 	    free_ContentInfo(&ci);
     95 	    return ENOMEM;
     96 	}
     97 	ci.content->data = malloc(buf->length);
     98 	if (ci.content->data == NULL) {
     99 	    free_ContentInfo(&ci);
    100 	    return ENOMEM;
    101 	}
    102 	memcpy(ci.content->data, buf->data, buf->length);
    103 	ci.content->length = buf->length;
    104     }
    105 
    106     ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret);
    107     free_ContentInfo(&ci);
    108     if (ret)
    109 	return ret;
    110     if (res->length != size)
    111 	_hx509_abort("internal ASN.1 encoder error");
    112 
    113     return 0;
    114 }
    115 
    116 /**
    117  * Decode an ContentInfo and unwrap data and oid it.
    118  *
    119  * @param in the encoded buffer.
    120  * @param oid type of the content.
    121  * @param out data to be wrapped.
    122  * @param have_data since the data is optional, this flags show dthe
    123  * diffrence between no data and the zero length data.
    124  *
    125  * @return Returns an hx509 error code.
    126  *
    127  * @ingroup hx509_cms
    128  */
    129 
    130 int
    131 hx509_cms_unwrap_ContentInfo(const heim_octet_string *in,
    132 			     heim_oid *oid,
    133 			     heim_octet_string *out,
    134 			     int *have_data)
    135 {
    136     ContentInfo ci;
    137     size_t size;
    138     int ret;
    139 
    140     memset(oid, 0, sizeof(*oid));
    141     memset(out, 0, sizeof(*out));
    142 
    143     ret = decode_ContentInfo(in->data, in->length, &ci, &size);
    144     if (ret)
    145 	return ret;
    146 
    147     ret = der_copy_oid(&ci.contentType, oid);
    148     if (ret) {
    149 	free_ContentInfo(&ci);
    150 	return ret;
    151     }
    152     if (ci.content) {
    153 	ret = der_copy_octet_string(ci.content, out);
    154 	if (ret) {
    155 	    der_free_oid(oid);
    156 	    free_ContentInfo(&ci);
    157 	    return ret;
    158 	}
    159     } else
    160 	memset(out, 0, sizeof(*out));
    161 
    162     if (have_data)
    163 	*have_data = (ci.content != NULL) ? 1 : 0;
    164 
    165     free_ContentInfo(&ci);
    166 
    167     return 0;
    168 }
    169 
    170 #define CMS_ID_SKI	0
    171 #define CMS_ID_NAME	1
    172 
    173 static int
    174 fill_CMSIdentifier(const hx509_cert cert,
    175 		   int type,
    176 		   CMSIdentifier *id)
    177 {
    178     int ret;
    179 
    180     switch (type) {
    181     case CMS_ID_SKI:
    182 	id->element = choice_CMSIdentifier_subjectKeyIdentifier;
    183 	ret = _hx509_find_extension_subject_key_id(_hx509_get_cert(cert),
    184 						   &id->u.subjectKeyIdentifier);
    185 	if (ret == 0)
    186 	    break;
    187 	/* FALLTHROUGH */
    188     case CMS_ID_NAME: {
    189 	hx509_name name;
    190 
    191 	id->element = choice_CMSIdentifier_issuerAndSerialNumber;
    192 	ret = hx509_cert_get_issuer(cert, &name);
    193 	if (ret)
    194 	    return ret;
    195 	ret = hx509_name_to_Name(name, &id->u.issuerAndSerialNumber.issuer);
    196 	hx509_name_free(&name);
    197 	if (ret)
    198 	    return ret;
    199 
    200 	ret = hx509_cert_get_serialnumber(cert, &id->u.issuerAndSerialNumber.serialNumber);
    201 	break;
    202     }
    203     default:
    204 	_hx509_abort("CMS fill identifier with unknown type");
    205     }
    206     return ret;
    207 }
    208 
    209 static int
    210 unparse_CMSIdentifier(hx509_context context,
    211 		      CMSIdentifier *id,
    212 		      char **str)
    213 {
    214     int ret = -1;
    215 
    216     *str = NULL;
    217     switch (id->element) {
    218     case choice_CMSIdentifier_issuerAndSerialNumber: {
    219 	IssuerAndSerialNumber *iasn;
    220 	char *serial, *name;
    221 
    222 	iasn = &id->u.issuerAndSerialNumber;
    223 
    224 	ret = _hx509_Name_to_string(&iasn->issuer, &name);
    225 	if(ret)
    226 	    return ret;
    227 	ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial);
    228 	if (ret) {
    229 	    free(name);
    230 	    return ret;
    231 	}
    232 	ret = asprintf(str, "certificate issued by %s with serial number %s",
    233 		       name, serial);
    234 	free(name);
    235 	free(serial);
    236 	break;
    237     }
    238     case choice_CMSIdentifier_subjectKeyIdentifier: {
    239 	KeyIdentifier *ki  = &id->u.subjectKeyIdentifier;
    240 	char *keyid;
    241 	ssize_t len;
    242 
    243 	len = hex_encode(ki->data, ki->length, &keyid);
    244 	if (len < 0)
    245 	    return ENOMEM;
    246 
    247 	ret = asprintf(str, "certificate with id %s", keyid);
    248 	free(keyid);
    249 	break;
    250     }
    251     default:
    252 	ret = asprintf(str, "certificate have unknown CMSidentifier type");
    253 	break;
    254     }
    255     /*
    256      * In the following if, we check ret and *str which should be returned/set
    257      * by asprintf(3) in every branch of the switch statement.
    258      */
    259     if (ret == -1 || *str == NULL)
    260 	return ENOMEM;
    261     return 0;
    262 }
    263 
    264 static int
    265 find_CMSIdentifier(hx509_context context,
    266 		   CMSIdentifier *client,
    267 		   hx509_certs certs,
    268 		   time_t time_now,
    269 		   hx509_cert *signer_cert,
    270 		   int match)
    271 {
    272     hx509_query q;
    273     hx509_cert cert;
    274     Certificate c;
    275     int ret;
    276 
    277     memset(&c, 0, sizeof(c));
    278     _hx509_query_clear(&q);
    279 
    280     *signer_cert = NULL;
    281 
    282     switch (client->element) {
    283     case choice_CMSIdentifier_issuerAndSerialNumber:
    284 	q.serial = &client->u.issuerAndSerialNumber.serialNumber;
    285 	q.issuer_name = &client->u.issuerAndSerialNumber.issuer;
    286 	q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
    287 	break;
    288     case choice_CMSIdentifier_subjectKeyIdentifier:
    289 	q.subject_id = &client->u.subjectKeyIdentifier;
    290 	q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
    291 	break;
    292     default:
    293 	hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE,
    294 			       "unknown CMS identifier element");
    295 	return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
    296     }
    297 
    298     q.match |= match;
    299 
    300     q.match |= HX509_QUERY_MATCH_TIME;
    301     if (time_now)
    302 	q.timenow = time_now;
    303     else
    304 	q.timenow = time(NULL);
    305 
    306     ret = hx509_certs_find(context, certs, &q, &cert);
    307     if (ret == HX509_CERT_NOT_FOUND) {
    308 	char *str;
    309 
    310 	ret = unparse_CMSIdentifier(context, client, &str);
    311 	if (ret == 0) {
    312 	    hx509_set_error_string(context, 0,
    313 				   HX509_CMS_NO_RECIPIENT_CERTIFICATE,
    314 				   "Failed to find %s", str);
    315 	} else
    316 	    hx509_clear_error_string(context);
    317 	return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
    318     } else if (ret) {
    319 	hx509_set_error_string(context, HX509_ERROR_APPEND,
    320 			       HX509_CMS_NO_RECIPIENT_CERTIFICATE,
    321 			       "Failed to find CMS id in cert store");
    322 	return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
    323     }
    324 
    325     *signer_cert = cert;
    326 
    327     return 0;
    328 }
    329 
    330 /**
    331  * Decode and unencrypt EnvelopedData.
    332  *
    333  * Extract data and parameteres from from the EnvelopedData. Also
    334  * supports using detached EnvelopedData.
    335  *
    336  * @param context A hx509 context.
    337  * @param certs Certificate that can decrypt the EnvelopedData
    338  * encryption key.
    339  * @param flags HX509_CMS_UE flags to control the behavior.
    340  * @param data pointer the structure the contains the DER/BER encoded
    341  * EnvelopedData stucture.
    342  * @param length length of the data that data point to.
    343  * @param encryptedContent in case of detached signature, this
    344  * contains the actual encrypted data, othersize its should be NULL.
    345  * @param time_now set the current time, if zero the library uses now as the date.
    346  * @param contentType output type oid, should be freed with der_free_oid().
    347  * @param content the data, free with der_free_octet_string().
    348  *
    349  * @return an hx509 error code.
    350  *
    351  * @ingroup hx509_cms
    352  */
    353 
    354 int
    355 hx509_cms_unenvelope(hx509_context context,
    356 		     hx509_certs certs,
    357 		     int flags,
    358 		     const void *data,
    359 		     size_t length,
    360 		     const heim_octet_string *encryptedContent,
    361 		     time_t time_now,
    362 		     heim_oid *contentType,
    363 		     heim_octet_string *content)
    364 {
    365     heim_octet_string key;
    366     EnvelopedData ed;
    367     hx509_cert cert;
    368     AlgorithmIdentifier *ai;
    369     const heim_octet_string *enccontent;
    370     heim_octet_string *params, params_data;
    371     heim_octet_string ivec;
    372     size_t size;
    373     int ret, matched = 0, findflags = 0;
    374     size_t i;
    375 
    376 
    377     memset(&key, 0, sizeof(key));
    378     memset(&ed, 0, sizeof(ed));
    379     memset(&ivec, 0, sizeof(ivec));
    380     memset(content, 0, sizeof(*content));
    381     memset(contentType, 0, sizeof(*contentType));
    382 
    383     if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
    384 	findflags |= HX509_QUERY_KU_ENCIPHERMENT;
    385 
    386     ret = decode_EnvelopedData(data, length, &ed, &size);
    387     if (ret) {
    388 	hx509_set_error_string(context, 0, ret,
    389 			       "Failed to decode EnvelopedData");
    390 	return ret;
    391     }
    392 
    393     if (ed.recipientInfos.len == 0) {
    394 	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
    395 	hx509_set_error_string(context, 0, ret,
    396 			       "No recipient info in enveloped data");
    397 	goto out;
    398     }
    399 
    400     enccontent = ed.encryptedContentInfo.encryptedContent;
    401     if (enccontent == NULL) {
    402 	if (encryptedContent == NULL) {
    403 	    ret = HX509_CMS_NO_DATA_AVAILABLE;
    404 	    hx509_set_error_string(context, 0, ret,
    405 				   "Content missing from encrypted data");
    406 	    goto out;
    407 	}
    408 	enccontent = encryptedContent;
    409     } else if (encryptedContent != NULL) {
    410 	ret = HX509_CMS_NO_DATA_AVAILABLE;
    411 	hx509_set_error_string(context, 0, ret,
    412 			       "Both internal and external encrypted data");
    413 	goto out;
    414     }
    415 
    416     cert = NULL;
    417     for (i = 0; i < ed.recipientInfos.len; i++) {
    418 	KeyTransRecipientInfo *ri;
    419 	char *str;
    420 	int ret2;
    421 
    422 	ri = &ed.recipientInfos.val[i];
    423 
    424 	ret = find_CMSIdentifier(context, &ri->rid, certs,
    425 				 time_now, &cert,
    426 				 HX509_QUERY_PRIVATE_KEY|findflags);
    427 	if (ret)
    428 	    continue;
    429 
    430 	matched = 1; /* found a matching certificate, let decrypt */
    431 
    432 	ret = _hx509_cert_private_decrypt(context,
    433 					  &ri->encryptedKey,
    434 					  &ri->keyEncryptionAlgorithm.algorithm,
    435 					  cert, &key);
    436 
    437 	hx509_cert_free(cert);
    438 	if (ret == 0)
    439 	    break; /* succuessfully decrypted cert */
    440 	cert = NULL;
    441 	ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
    442 	if (ret2 == 0) {
    443 	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
    444 				   "Failed to decrypt with %s", str);
    445 	    free(str);
    446 	}
    447     }
    448 
    449     if (!matched) {
    450 	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
    451 	hx509_set_error_string(context, 0, ret,
    452 			       "No private key matched any certificate");
    453 	goto out;
    454     }
    455 
    456     if (cert == NULL) {
    457 	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
    458 	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
    459 			       "No private key decrypted the transfer key");
    460 	goto out;
    461     }
    462 
    463     ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
    464     if (ret) {
    465 	hx509_set_error_string(context, 0, ret,
    466 			       "Failed to copy EnvelopedData content oid");
    467 	goto out;
    468     }
    469 
    470     ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
    471     if (ai->parameters) {
    472 	params_data.data = ai->parameters->data;
    473 	params_data.length = ai->parameters->length;
    474 	params = &params_data;
    475     } else
    476 	params = NULL;
    477 
    478     {
    479 	hx509_crypto crypto;
    480 
    481 	ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto);
    482 	if (ret)
    483 	    goto out;
    484 
    485 	if (flags & HX509_CMS_UE_ALLOW_WEAK)
    486 	    hx509_crypto_allow_weak(crypto);
    487 
    488 	if (params) {
    489 	    ret = hx509_crypto_set_params(context, crypto, params, &ivec);
    490 	    if (ret) {
    491 		hx509_crypto_destroy(crypto);
    492 		goto out;
    493 	    }
    494 	}
    495 
    496 	ret = hx509_crypto_set_key_data(crypto, key.data, key.length);
    497 	if (ret) {
    498 	    hx509_crypto_destroy(crypto);
    499 	    hx509_set_error_string(context, 0, ret,
    500 				   "Failed to set key for decryption "
    501 				   "of EnvelopedData");
    502 	    goto out;
    503 	}
    504 
    505 	ret = hx509_crypto_decrypt(crypto,
    506 				   enccontent->data,
    507 				   enccontent->length,
    508 				   ivec.length ? &ivec : NULL,
    509 				   content);
    510 	hx509_crypto_destroy(crypto);
    511 	if (ret) {
    512 	    hx509_set_error_string(context, 0, ret,
    513 				   "Failed to decrypt EnvelopedData");
    514 	    goto out;
    515 	}
    516     }
    517 
    518 out:
    519 
    520     free_EnvelopedData(&ed);
    521     der_free_octet_string(&key);
    522     if (ivec.length)
    523 	der_free_octet_string(&ivec);
    524     if (ret) {
    525 	der_free_oid(contentType);
    526 	der_free_octet_string(content);
    527     }
    528 
    529     return ret;
    530 }
    531 
    532 /**
    533  * Encrypt end encode EnvelopedData.
    534  *
    535  * Encrypt and encode EnvelopedData. The data is encrypted with a
    536  * random key and the the random key is encrypted with the
    537  * certificates private key. This limits what private key type can be
    538  * used to RSA.
    539  *
    540  * @param context A hx509 context.
    541  * @param flags flags to control the behavior.
    542  *    - HX509_CMS_EV_NO_KU_CHECK - Don't check KU on certificate
    543  *    - HX509_CMS_EV_ALLOW_WEAK - Allow weak crytpo
    544  *    - HX509_CMS_EV_ID_NAME - prefer issuer name and serial number
    545  * @param cert Certificate to encrypt the EnvelopedData encryption key
    546  * with.
    547  * @param data pointer the data to encrypt.
    548  * @param length length of the data that data point to.
    549  * @param encryption_type Encryption cipher to use for the bulk data,
    550  * use NULL to get default.
    551  * @param contentType type of the data that is encrypted
    552  * @param content the output of the function,
    553  * free with der_free_octet_string().
    554  *
    555  * @return an hx509 error code.
    556  *
    557  * @ingroup hx509_cms
    558  */
    559 
    560 int
    561 hx509_cms_envelope_1(hx509_context context,
    562 		     int flags,
    563 		     hx509_cert cert,
    564 		     const void *data,
    565 		     size_t length,
    566 		     const heim_oid *encryption_type,
    567 		     const heim_oid *contentType,
    568 		     heim_octet_string *content)
    569 {
    570     KeyTransRecipientInfo *ri;
    571     heim_octet_string ivec;
    572     heim_octet_string key;
    573     hx509_crypto crypto = NULL;
    574     int ret, cmsidflag;
    575     EnvelopedData ed;
    576     size_t size;
    577 
    578     memset(&ivec, 0, sizeof(ivec));
    579     memset(&key, 0, sizeof(key));
    580     memset(&ed, 0, sizeof(ed));
    581     memset(content, 0, sizeof(*content));
    582 
    583     if (encryption_type == NULL)
    584 	encryption_type = &asn1_oid_id_aes_256_cbc;
    585 
    586     if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) {
    587 	ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
    588 	if (ret)
    589 	    goto out;
    590     }
    591 
    592     ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
    593     if (ret)
    594 	goto out;
    595 
    596     if (flags & HX509_CMS_EV_ALLOW_WEAK)
    597 	hx509_crypto_allow_weak(crypto);
    598 
    599     ret = hx509_crypto_set_random_key(crypto, &key);
    600     if (ret) {
    601 	hx509_set_error_string(context, 0, ret,
    602 			       "Create random key for EnvelopedData content");
    603 	goto out;
    604     }
    605 
    606     ret = hx509_crypto_random_iv(crypto, &ivec);
    607     if (ret) {
    608 	hx509_set_error_string(context, 0, ret,
    609 			       "Failed to create a random iv");
    610 	goto out;
    611     }
    612 
    613     ret = hx509_crypto_encrypt(crypto,
    614 			       data,
    615 			       length,
    616 			       &ivec,
    617 			       &ed.encryptedContentInfo.encryptedContent);
    618     if (ret) {
    619 	hx509_set_error_string(context, 0, ret,
    620 			       "Failed to encrypt EnvelopedData content");
    621 	goto out;
    622     }
    623 
    624     {
    625 	AlgorithmIdentifier *enc_alg;
    626 	enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
    627 	ret = der_copy_oid(encryption_type, &enc_alg->algorithm);
    628 	if (ret) {
    629 	    hx509_set_error_string(context, 0, ret,
    630 				   "Failed to set crypto oid "
    631 				   "for EnvelopedData");
    632 	    goto out;
    633 	}
    634 	ALLOC(enc_alg->parameters, 1);
    635 	if (enc_alg->parameters == NULL) {
    636 	    ret = ENOMEM;
    637 	    hx509_set_error_string(context, 0, ret,
    638 				   "Failed to allocate crypto paramaters "
    639 				   "for EnvelopedData");
    640 	    goto out;
    641 	}
    642 
    643 	ret = hx509_crypto_get_params(context,
    644 				      crypto,
    645 				      &ivec,
    646 				      enc_alg->parameters);
    647 	if (ret) {
    648 	    goto out;
    649 	}
    650     }
    651 
    652     ALLOC_SEQ(&ed.recipientInfos, 1);
    653     if (ed.recipientInfos.val == NULL) {
    654 	ret = ENOMEM;
    655 	hx509_set_error_string(context, 0, ret,
    656 			       "Failed to allocate recipients info "
    657 			       "for EnvelopedData");
    658 	goto out;
    659     }
    660 
    661     ri = &ed.recipientInfos.val[0];
    662 
    663     if (flags & HX509_CMS_EV_ID_NAME) {
    664 	ri->version = 0;
    665 	cmsidflag = CMS_ID_NAME;
    666     } else {
    667 	ri->version = 2;
    668 	cmsidflag = CMS_ID_SKI;
    669     }
    670 
    671     ret = fill_CMSIdentifier(cert, cmsidflag, &ri->rid);
    672     if (ret) {
    673 	hx509_set_error_string(context, 0, ret,
    674 			       "Failed to set CMS identifier info "
    675 			       "for EnvelopedData");
    676 	goto out;
    677     }
    678 
    679     ret = hx509_cert_public_encrypt(context,
    680 				     &key, cert,
    681 				     &ri->keyEncryptionAlgorithm.algorithm,
    682 				     &ri->encryptedKey);
    683     if (ret) {
    684 	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
    685 			       "Failed to encrypt transport key for "
    686 			       "EnvelopedData");
    687 	goto out;
    688     }
    689 
    690     /*
    691      *
    692      */
    693 
    694     ed.version = 0;
    695     ed.originatorInfo = NULL;
    696 
    697     ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType);
    698     if (ret) {
    699 	hx509_set_error_string(context, 0, ret,
    700 			       "Failed to copy content oid for "
    701 			       "EnvelopedData");
    702 	goto out;
    703     }
    704 
    705     ed.unprotectedAttrs = NULL;
    706 
    707     ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length,
    708 		       &ed, &size, ret);
    709     if (ret) {
    710 	hx509_set_error_string(context, 0, ret,
    711 			       "Failed to encode EnvelopedData");
    712 	goto out;
    713     }
    714     if (size != content->length)
    715 	_hx509_abort("internal ASN.1 encoder error");
    716 
    717 out:
    718     if (crypto)
    719 	hx509_crypto_destroy(crypto);
    720     if (ret)
    721 	der_free_octet_string(content);
    722     der_free_octet_string(&key);
    723     der_free_octet_string(&ivec);
    724     free_EnvelopedData(&ed);
    725 
    726     return ret;
    727 }
    728 
    729 static int
    730 any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs)
    731 {
    732     int ret;
    733     size_t i;
    734 
    735     if (sd->certificates == NULL)
    736 	return 0;
    737 
    738     for (i = 0; i < sd->certificates->len; i++) {
    739 	heim_error_t error;
    740 	hx509_cert c;
    741 
    742 	c = hx509_cert_init_data(context,
    743 				 sd->certificates->val[i].data,
    744 				 sd->certificates->val[i].length,
    745 				 &error);
    746 	if (c == NULL) {
    747 	    ret = heim_error_get_code(error);
    748 	    heim_release(error);
    749 	    return ret;
    750 	}
    751 	ret = hx509_certs_add(context, certs, c);
    752 	hx509_cert_free(c);
    753 	if (ret)
    754 	    return ret;
    755     }
    756 
    757     return 0;
    758 }
    759 
    760 static const Attribute *
    761 find_attribute(const CMSAttributes *attr, const heim_oid *oid)
    762 {
    763     size_t i;
    764     for (i = 0; i < attr->len; i++)
    765 	if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0)
    766 	    return &attr->val[i];
    767     return NULL;
    768 }
    769 
    770 /**
    771  * Decode SignedData and verify that the signature is correct.
    772  *
    773  * @param context A hx509 context.
    774  * @param ctx a hx509 verify context.
    775  * @param flags to control the behaivor of the function.
    776  *    - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage
    777  *    - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch
    778  *    - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below.
    779  * @param data pointer to CMS SignedData encoded data.
    780  * @param length length of the data that data point to.
    781  * @param signedContent external data used for signature.
    782  * @param pool certificate pool to build certificates paths.
    783  * @param contentType free with der_free_oid().
    784  * @param content the output of the function, free with
    785  * der_free_octet_string().
    786  * @param signer_certs list of the cerficates used to sign this
    787  * request, free with hx509_certs_free().
    788  *
    789  * @return an hx509 error code.
    790  *
    791  * @ingroup hx509_cms
    792  */
    793 
    794 int
    795 hx509_cms_verify_signed(hx509_context context,
    796 			hx509_verify_ctx ctx,
    797 			unsigned int flags,
    798 			const void *data,
    799 			size_t length,
    800 			const heim_octet_string *signedContent,
    801 			hx509_certs pool,
    802 			heim_oid *contentType,
    803 			heim_octet_string *content,
    804 			hx509_certs *signer_certs)
    805 {
    806     SignerInfo *signer_info;
    807     hx509_cert cert = NULL;
    808     hx509_certs certs = NULL;
    809     SignedData sd;
    810     size_t size;
    811     int ret, found_valid_sig;
    812     size_t i;
    813 
    814     *signer_certs = NULL;
    815     content->data = NULL;
    816     content->length = 0;
    817     contentType->length = 0;
    818     contentType->components = NULL;
    819 
    820     memset(&sd, 0, sizeof(sd));
    821 
    822     ret = decode_SignedData(data, length, &sd, &size);
    823     if (ret) {
    824 	hx509_set_error_string(context, 0, ret,
    825 			       "Failed to decode SignedData");
    826 	goto out;
    827     }
    828 
    829     if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) {
    830 	ret = HX509_CMS_NO_DATA_AVAILABLE;
    831 	hx509_set_error_string(context, 0, ret,
    832 			       "No content data in SignedData");
    833 	goto out;
    834     }
    835     if (sd.encapContentInfo.eContent && signedContent) {
    836 	ret = HX509_CMS_NO_DATA_AVAILABLE;
    837 	hx509_set_error_string(context, 0, ret,
    838 			       "Both external and internal SignedData");
    839 	goto out;
    840     }
    841 
    842     if (sd.encapContentInfo.eContent)
    843 	ret = der_copy_octet_string(sd.encapContentInfo.eContent, content);
    844     else
    845 	ret = der_copy_octet_string(signedContent, content);
    846     if (ret) {
    847 	hx509_set_error_string(context, 0, ret, "malloc: out of memory");
    848 	goto out;
    849     }
    850 
    851     ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
    852 			   0, NULL, &certs);
    853     if (ret)
    854 	goto out;
    855 
    856     ret = hx509_certs_init(context, "MEMORY:cms-signer-certs",
    857 			   0, NULL, signer_certs);
    858     if (ret)
    859 	goto out;
    860 
    861     /* XXX Check CMS version */
    862 
    863     ret = any_to_certs(context, &sd, certs);
    864     if (ret)
    865 	goto out;
    866 
    867     if (pool) {
    868 	ret = hx509_certs_merge(context, certs, pool);
    869 	if (ret)
    870 	    goto out;
    871     }
    872 
    873     for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
    874 	heim_octet_string signed_data = { 0, 0 };
    875 	const heim_oid *match_oid;
    876 	heim_oid decode_oid;
    877 
    878 	signer_info = &sd.signerInfos.val[i];
    879 	match_oid = NULL;
    880 
    881 	if (signer_info->signature.length == 0) {
    882 	    ret = HX509_CMS_MISSING_SIGNER_DATA;
    883 	    hx509_set_error_string(context, 0, ret,
    884 				   "SignerInfo %d in SignedData "
    885 				   "missing sigature", i);
    886 	    continue;
    887 	}
    888 
    889 	ret = find_CMSIdentifier(context, &signer_info->sid, certs,
    890 				 _hx509_verify_get_time(ctx), &cert,
    891 				 HX509_QUERY_KU_DIGITALSIGNATURE);
    892 	if (ret) {
    893 	    /**
    894 	     * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal
    895 	     * search for matching certificates by not considering
    896 	     * KeyUsage bits on the certificates.
    897 	     */
    898 	    if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0)
    899 		continue;
    900 
    901 	    ret = find_CMSIdentifier(context, &signer_info->sid, certs,
    902 				     _hx509_verify_get_time(ctx), &cert,
    903 				     0);
    904 	    if (ret)
    905 		continue;
    906 
    907 	}
    908 
    909 	if (signer_info->signedAttrs) {
    910 	    const Attribute *attr;
    911 
    912 	    CMSAttributes sa;
    913 	    heim_octet_string os;
    914 
    915 	    sa.val = signer_info->signedAttrs->val;
    916 	    sa.len = signer_info->signedAttrs->len;
    917 
    918 	    /* verify that sigature exists */
    919 	    attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest);
    920 	    if (attr == NULL) {
    921 		ret = HX509_CRYPTO_SIGNATURE_MISSING;
    922 		hx509_set_error_string(context, 0, ret,
    923 				       "SignerInfo have signed attributes "
    924 				       "but messageDigest (signature) "
    925 				       "is missing");
    926 		goto next_sigature;
    927 	    }
    928 	    if (attr->value.len != 1) {
    929 		ret = HX509_CRYPTO_SIGNATURE_MISSING;
    930 		hx509_set_error_string(context, 0, ret,
    931 				       "SignerInfo have more then one "
    932 				       "messageDigest (signature)");
    933 		goto next_sigature;
    934 	    }
    935 
    936 	    ret = decode_MessageDigest(attr->value.val[0].data,
    937 				       attr->value.val[0].length,
    938 				       &os,
    939 				       &size);
    940 	    if (ret) {
    941 		hx509_set_error_string(context, 0, ret,
    942 				       "Failed to decode "
    943 				       "messageDigest (signature)");
    944 		goto next_sigature;
    945 	    }
    946 
    947 	    ret = _hx509_verify_signature(context,
    948 					  NULL,
    949 					  &signer_info->digestAlgorithm,
    950 					  content,
    951 					  &os);
    952 	    der_free_octet_string(&os);
    953 	    if (ret) {
    954 		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
    955 				       "Failed to verify messageDigest");
    956 		goto next_sigature;
    957 	    }
    958 
    959 	    /*
    960 	     * Fetch content oid inside signedAttrs or set it to
    961 	     * id-pkcs7-data.
    962 	     */
    963 	    attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType);
    964 	    if (attr == NULL) {
    965 		match_oid = &asn1_oid_id_pkcs7_data;
    966 	    } else {
    967 		if (attr->value.len != 1) {
    968 		    ret = HX509_CMS_DATA_OID_MISMATCH;
    969 		    hx509_set_error_string(context, 0, ret,
    970 					   "More then one oid in signedAttrs");
    971 		    goto next_sigature;
    972 
    973 		}
    974 		ret = decode_ContentType(attr->value.val[0].data,
    975 					 attr->value.val[0].length,
    976 					 &decode_oid,
    977 					 &size);
    978 		if (ret) {
    979 		    hx509_set_error_string(context, 0, ret,
    980 					   "Failed to decode "
    981 					   "oid in signedAttrs");
    982 		    goto next_sigature;
    983 		}
    984 		match_oid = &decode_oid;
    985 	    }
    986 
    987 	    ASN1_MALLOC_ENCODE(CMSAttributes,
    988 			       signed_data.data,
    989 			       signed_data.length,
    990 			       &sa,
    991 			       &size, ret);
    992 	    if (ret) {
    993 		if (match_oid == &decode_oid)
    994 		    der_free_oid(&decode_oid);
    995 		hx509_clear_error_string(context);
    996 		goto next_sigature;
    997 	    }
    998 	    if (size != signed_data.length)
    999 		_hx509_abort("internal ASN.1 encoder error");
   1000 
   1001 	} else {
   1002 	    signed_data.data = content->data;
   1003 	    signed_data.length = content->length;
   1004 	    match_oid = &asn1_oid_id_pkcs7_data;
   1005 	}
   1006 
   1007 	/**
   1008 	 * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow
   1009 	 * encapContentInfo mismatch with the oid in signedAttributes
   1010 	 * (or if no signedAttributes where use, pkcs7-data oid).
   1011 	 * This is only needed to work with broken CMS implementations
   1012 	 * that doesn't follow CMS signedAttributes rules.
   1013 	 */
   1014 
   1015 	if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) &&
   1016 	    (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) {
   1017 	    ret = HX509_CMS_DATA_OID_MISMATCH;
   1018 	    hx509_set_error_string(context, 0, ret,
   1019 				   "Oid in message mismatch from the expected");
   1020 	}
   1021 	if (match_oid == &decode_oid)
   1022 	    der_free_oid(&decode_oid);
   1023 
   1024 	if (ret == 0) {
   1025 	    ret = hx509_verify_signature(context,
   1026 					 cert,
   1027 					 &signer_info->signatureAlgorithm,
   1028 					 &signed_data,
   1029 					 &signer_info->signature);
   1030 	    if (ret)
   1031 		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
   1032 				       "Failed to verify signature in "
   1033 				       "CMS SignedData");
   1034 	}
   1035         if (signed_data.data != NULL && content->data != signed_data.data) {
   1036             free(signed_data.data);
   1037             signed_data.data = NULL;
   1038         }
   1039 	if (ret)
   1040 	    goto next_sigature;
   1041 
   1042 	/**
   1043 	 * If HX509_CMS_VS_NO_VALIDATE flags is set, do not verify the
   1044 	 * signing certificates and leave that up to the caller.
   1045 	 */
   1046 
   1047 	if ((flags & HX509_CMS_VS_NO_VALIDATE) == 0) {
   1048 	    ret = hx509_verify_path(context, ctx, cert, certs);
   1049 	    if (ret)
   1050 		goto next_sigature;
   1051 	}
   1052 
   1053 	ret = hx509_certs_add(context, *signer_certs, cert);
   1054 	if (ret)
   1055 	    goto next_sigature;
   1056 
   1057 	found_valid_sig++;
   1058 
   1059     next_sigature:
   1060 	if (cert)
   1061 	    hx509_cert_free(cert);
   1062 	cert = NULL;
   1063     }
   1064     /**
   1065      * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty
   1066      * SignerInfo (no signatures). If SignedData have no signatures,
   1067      * the function will return 0 with signer_certs set to NULL. Zero
   1068      * signers is allowed by the standard, but since its only useful
   1069      * in corner cases, it make into a flag that the caller have to
   1070      * turn on.
   1071      */
   1072     if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) {
   1073 	if (*signer_certs)
   1074 	    hx509_certs_free(signer_certs);
   1075     } else if (found_valid_sig == 0) {
   1076 	if (ret == 0) {
   1077 	    ret = HX509_CMS_SIGNER_NOT_FOUND;
   1078 	    hx509_set_error_string(context, 0, ret,
   1079 				   "No signers where found");
   1080 	}
   1081 	goto out;
   1082     }
   1083 
   1084     ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType);
   1085     if (ret) {
   1086 	hx509_clear_error_string(context);
   1087 	goto out;
   1088     }
   1089 
   1090 out:
   1091     free_SignedData(&sd);
   1092     if (certs)
   1093 	hx509_certs_free(&certs);
   1094     if (ret) {
   1095 	if (content->data)
   1096 	    der_free_octet_string(content);
   1097 	if (*signer_certs)
   1098 	    hx509_certs_free(signer_certs);
   1099 	der_free_oid(contentType);
   1100 	der_free_octet_string(content);
   1101     }
   1102 
   1103     return ret;
   1104 }
   1105 
   1106 static int
   1107 add_one_attribute(Attribute **attr,
   1108 		  unsigned int *len,
   1109 		  const heim_oid *oid,
   1110 		  heim_octet_string *data)
   1111 {
   1112     void *d;
   1113     int ret;
   1114 
   1115     d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1));
   1116     if (d == NULL)
   1117 	return ENOMEM;
   1118     (*attr) = d;
   1119 
   1120     ret = der_copy_oid(oid, &(*attr)[*len].type);
   1121     if (ret)
   1122 	return ret;
   1123 
   1124     ALLOC_SEQ(&(*attr)[*len].value, 1);
   1125     if ((*attr)[*len].value.val == NULL) {
   1126 	der_free_oid(&(*attr)[*len].type);
   1127 	return ENOMEM;
   1128     }
   1129 
   1130     (*attr)[*len].value.val[0].data = data->data;
   1131     (*attr)[*len].value.val[0].length = data->length;
   1132 
   1133     *len += 1;
   1134 
   1135     return 0;
   1136 }
   1137 
   1138 /**
   1139  * Decode SignedData and verify that the signature is correct.
   1140  *
   1141  * @param context A hx509 context.
   1142  * @param flags
   1143  * @param eContentType the type of the data.
   1144  * @param data data to sign
   1145  * @param length length of the data that data point to.
   1146  * @param digest_alg digest algorithm to use, use NULL to get the
   1147  * default or the peer determined algorithm.
   1148  * @param cert certificate to use for sign the data.
   1149  * @param peer info about the peer the message to send the message to,
   1150  * like what digest algorithm to use.
   1151  * @param anchors trust anchors that the client will use, used to
   1152  * polulate the certificates included in the message
   1153  * @param pool certificates to use in try to build the path to the
   1154  * trust anchors.
   1155  * @param signed_data the output of the function, free with
   1156  * der_free_octet_string().
   1157  *
   1158  * @return Returns an hx509 error code.
   1159  *
   1160  * @ingroup hx509_cms
   1161  */
   1162 
   1163 int
   1164 hx509_cms_create_signed_1(hx509_context context,
   1165 			  int flags,
   1166 			  const heim_oid *eContentType,
   1167 			  const void *data, size_t length,
   1168 			  const AlgorithmIdentifier *digest_alg,
   1169 			  hx509_cert cert,
   1170 			  hx509_peer_info peer,
   1171 			  hx509_certs anchors,
   1172 			  hx509_certs pool,
   1173 			  heim_octet_string *signed_data)
   1174 {
   1175     hx509_certs certs;
   1176     int ret = 0;
   1177 
   1178     signed_data->data = NULL;
   1179     signed_data->length = 0;
   1180 
   1181     ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs);
   1182     if (ret)
   1183 	return ret;
   1184     ret = hx509_certs_add(context, certs, cert);
   1185     if (ret)
   1186 	goto out;
   1187 
   1188     ret = hx509_cms_create_signed(context, flags, eContentType, data, length,
   1189 				  digest_alg, certs, peer, anchors, pool,
   1190 				  signed_data);
   1191 
   1192  out:
   1193     hx509_certs_free(&certs);
   1194     return ret;
   1195 }
   1196 
   1197 struct sigctx {
   1198     SignedData sd;
   1199     const AlgorithmIdentifier *digest_alg;
   1200     const heim_oid *eContentType;
   1201     heim_octet_string content;
   1202     hx509_peer_info peer;
   1203     int cmsidflag;
   1204     int leafonly;
   1205     hx509_certs certs;
   1206     hx509_certs anchors;
   1207     hx509_certs pool;
   1208 };
   1209 
   1210 static int
   1211 sig_process(hx509_context context, void *ctx, hx509_cert cert)
   1212 {
   1213     struct sigctx *sigctx = ctx;
   1214     heim_octet_string buf, sigdata = { 0, NULL };
   1215     SignerInfo *signer_info = NULL;
   1216     AlgorithmIdentifier digest;
   1217     size_t size;
   1218     void *ptr;
   1219     int ret;
   1220     SignedData *sd = &sigctx->sd;
   1221     hx509_path path;
   1222 
   1223     memset(&digest, 0, sizeof(digest));
   1224     memset(&path, 0, sizeof(path));
   1225 
   1226     if (_hx509_cert_private_key(cert) == NULL) {
   1227 	hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
   1228 			       "Private key missing for signing");
   1229 	return HX509_PRIVATE_KEY_MISSING;
   1230     }
   1231 
   1232     if (sigctx->digest_alg) {
   1233 	ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest);
   1234 	if (ret)
   1235 	    hx509_clear_error_string(context);
   1236     } else {
   1237 	ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
   1238 				  _hx509_cert_private_key(cert),
   1239 				  sigctx->peer, &digest);
   1240     }
   1241     if (ret)
   1242 	goto out;
   1243 
   1244     /*
   1245      * Allocate on more signerInfo and do the signature processing
   1246      */
   1247 
   1248     ptr = realloc(sd->signerInfos.val,
   1249 		  (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0]));
   1250     if (ptr == NULL) {
   1251 	ret = ENOMEM;
   1252 	goto out;
   1253     }
   1254     sd->signerInfos.val = ptr;
   1255 
   1256     signer_info = &sd->signerInfos.val[sd->signerInfos.len];
   1257 
   1258     memset(signer_info, 0, sizeof(*signer_info));
   1259 
   1260     signer_info->version = 1;
   1261 
   1262     ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid);
   1263     if (ret) {
   1264 	hx509_clear_error_string(context);
   1265 	goto out;
   1266     }
   1267 
   1268     signer_info->signedAttrs = NULL;
   1269     signer_info->unsignedAttrs = NULL;
   1270 
   1271     ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
   1272     if (ret) {
   1273 	hx509_clear_error_string(context);
   1274 	goto out;
   1275     }
   1276 
   1277     /*
   1278      * If it isn't pkcs7-data send signedAttributes
   1279      */
   1280 
   1281     if (der_heim_oid_cmp(sigctx->eContentType, &asn1_oid_id_pkcs7_data) != 0) {
   1282 	CMSAttributes sa;
   1283 	heim_octet_string sig;
   1284 
   1285 	ALLOC(signer_info->signedAttrs, 1);
   1286 	if (signer_info->signedAttrs == NULL) {
   1287 	    ret = ENOMEM;
   1288 	    goto out;
   1289 	}
   1290 
   1291 	ret = _hx509_create_signature(context,
   1292 				      NULL,
   1293 				      &digest,
   1294 				      &sigctx->content,
   1295 				      NULL,
   1296 				      &sig);
   1297 	if (ret)
   1298 	    goto out;
   1299 
   1300 	ASN1_MALLOC_ENCODE(MessageDigest,
   1301 			   buf.data,
   1302 			   buf.length,
   1303 			   &sig,
   1304 			   &size,
   1305 			   ret);
   1306 	der_free_octet_string(&sig);
   1307 	if (ret) {
   1308 	    hx509_clear_error_string(context);
   1309 	    goto out;
   1310 	}
   1311 	if (size != buf.length)
   1312 	    _hx509_abort("internal ASN.1 encoder error");
   1313 
   1314 	ret = add_one_attribute(&signer_info->signedAttrs->val,
   1315 				&signer_info->signedAttrs->len,
   1316 				&asn1_oid_id_pkcs9_messageDigest,
   1317 				&buf);
   1318 	if (ret) {
   1319 	    free(buf.data);
   1320 	    hx509_clear_error_string(context);
   1321 	    goto out;
   1322 	}
   1323 
   1324 
   1325 	ASN1_MALLOC_ENCODE(ContentType,
   1326 			   buf.data,
   1327 			   buf.length,
   1328 			   sigctx->eContentType,
   1329 			   &size,
   1330 			   ret);
   1331 	if (ret)
   1332 	    goto out;
   1333 	if (size != buf.length)
   1334 	    _hx509_abort("internal ASN.1 encoder error");
   1335 
   1336 	ret = add_one_attribute(&signer_info->signedAttrs->val,
   1337 				&signer_info->signedAttrs->len,
   1338 				&asn1_oid_id_pkcs9_contentType,
   1339 				&buf);
   1340 	if (ret) {
   1341 	    free(buf.data);
   1342 	    hx509_clear_error_string(context);
   1343 	    goto out;
   1344 	}
   1345 
   1346 	sa.val = signer_info->signedAttrs->val;
   1347 	sa.len = signer_info->signedAttrs->len;
   1348 
   1349 	ASN1_MALLOC_ENCODE(CMSAttributes,
   1350 			   sigdata.data,
   1351 			   sigdata.length,
   1352 			   &sa,
   1353 			   &size,
   1354 			   ret);
   1355 	if (ret) {
   1356 	    hx509_clear_error_string(context);
   1357 	    goto out;
   1358 	}
   1359 	if (size != sigdata.length)
   1360 	    _hx509_abort("internal ASN.1 encoder error");
   1361     } else {
   1362 	sigdata.data = sigctx->content.data;
   1363 	sigdata.length = sigctx->content.length;
   1364     }
   1365 
   1366     {
   1367 	AlgorithmIdentifier sigalg;
   1368 
   1369 	ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
   1370 				  _hx509_cert_private_key(cert), sigctx->peer,
   1371 				  &sigalg);
   1372 	if (ret)
   1373 	    goto out;
   1374 
   1375 	ret = _hx509_create_signature(context,
   1376 				      _hx509_cert_private_key(cert),
   1377 				      &sigalg,
   1378 				      &sigdata,
   1379 				      &signer_info->signatureAlgorithm,
   1380 				      &signer_info->signature);
   1381 	free_AlgorithmIdentifier(&sigalg);
   1382 	if (ret)
   1383 	    goto out;
   1384     }
   1385 
   1386     sigctx->sd.signerInfos.len++;
   1387     signer_info = NULL;
   1388 
   1389     /*
   1390      * Provide best effort path
   1391      */
   1392     if (sigctx->certs) {
   1393 	unsigned int i;
   1394 
   1395 	if (sigctx->pool && sigctx->leafonly == 0) {
   1396 	    _hx509_calculate_path(context,
   1397 				  HX509_CALCULATE_PATH_NO_ANCHOR,
   1398 				  time(NULL),
   1399 				  sigctx->anchors,
   1400 				  0,
   1401 				  cert,
   1402 				  sigctx->pool,
   1403 				  &path);
   1404 	} else
   1405 	    _hx509_path_append(context, &path, cert);
   1406 
   1407 	for (i = 0; i < path.len; i++) {
   1408 	    /* XXX remove dups */
   1409 	    ret = hx509_certs_add(context, sigctx->certs, path.val[i]);
   1410 	    if (ret) {
   1411 		hx509_clear_error_string(context);
   1412 		goto out;
   1413 	    }
   1414 	}
   1415     }
   1416 
   1417  out:
   1418     if (signer_info)
   1419 	free_SignerInfo(signer_info);
   1420     if (sigdata.data != sigctx->content.data)
   1421 	der_free_octet_string(&sigdata);
   1422     _hx509_path_free(&path);
   1423     free_AlgorithmIdentifier(&digest);
   1424 
   1425     return ret;
   1426 }
   1427 
   1428 static int
   1429 cert_process(hx509_context context, void *ctx, hx509_cert cert)
   1430 {
   1431     struct sigctx *sigctx = ctx;
   1432     const unsigned int i = sigctx->sd.certificates->len;
   1433     void *ptr;
   1434     int ret;
   1435 
   1436     ptr = realloc(sigctx->sd.certificates->val,
   1437 		  (i + 1) * sizeof(sigctx->sd.certificates->val[0]));
   1438     if (ptr == NULL)
   1439 	return ENOMEM;
   1440     sigctx->sd.certificates->val = ptr;
   1441 
   1442     ret = hx509_cert_binary(context, cert,
   1443 			    &sigctx->sd.certificates->val[i]);
   1444     if (ret == 0)
   1445 	sigctx->sd.certificates->len++;
   1446 
   1447     return ret;
   1448 }
   1449 
   1450 static int
   1451 cmp_AlgorithmIdentifier(const AlgorithmIdentifier *p, const AlgorithmIdentifier *q)
   1452 {
   1453     return der_heim_oid_cmp(&p->algorithm, &q->algorithm);
   1454 }
   1455 
   1456 int
   1457 hx509_cms_create_signed(hx509_context context,
   1458 			int flags,
   1459 			const heim_oid *eContentType,
   1460 			const void *data, size_t length,
   1461 			const AlgorithmIdentifier *digest_alg,
   1462 			hx509_certs certs,
   1463 			hx509_peer_info peer,
   1464 			hx509_certs anchors,
   1465 			hx509_certs pool,
   1466 			heim_octet_string *signed_data)
   1467 {
   1468     unsigned int i, j;
   1469     hx509_name name;
   1470     int ret;
   1471     size_t size;
   1472     struct sigctx sigctx;
   1473 
   1474     memset(&sigctx, 0, sizeof(sigctx));
   1475     memset(&name, 0, sizeof(name));
   1476 
   1477     if (eContentType == NULL)
   1478 	eContentType = &asn1_oid_id_pkcs7_data;
   1479 
   1480     sigctx.digest_alg = digest_alg;
   1481     sigctx.content.data = rk_UNCONST(data);
   1482     sigctx.content.length = length;
   1483     sigctx.eContentType = eContentType;
   1484     sigctx.peer = peer;
   1485     /**
   1486      * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name
   1487      * and serial number if possible. Otherwise subject key identifier
   1488      * will preferred.
   1489      */
   1490     if (flags & HX509_CMS_SIGNATURE_ID_NAME)
   1491 	sigctx.cmsidflag = CMS_ID_NAME;
   1492     else
   1493 	sigctx.cmsidflag = CMS_ID_SKI;
   1494 
   1495     /**
   1496      * Use HX509_CMS_SIGNATURE_LEAF_ONLY to only request leaf
   1497      * certificates to be added to the SignedData.
   1498      */
   1499     sigctx.leafonly = (flags & HX509_CMS_SIGNATURE_LEAF_ONLY) ? 1 : 0;
   1500 
   1501     /**
   1502      * Use HX509_CMS_NO_CERTS to make the SignedData contain no
   1503      * certificates, overrides HX509_CMS_SIGNATURE_LEAF_ONLY.
   1504      */
   1505 
   1506     if ((flags & HX509_CMS_SIGNATURE_NO_CERTS) == 0) {
   1507 	ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs);
   1508 	if (ret)
   1509 	    return ret;
   1510     }
   1511 
   1512     sigctx.anchors = anchors;
   1513     sigctx.pool = pool;
   1514 
   1515     sigctx.sd.version = CMSVersion_v3;
   1516 
   1517     der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType);
   1518 
   1519     /**
   1520      * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures.
   1521      */
   1522     if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) {
   1523 	ALLOC(sigctx.sd.encapContentInfo.eContent, 1);
   1524 	if (sigctx.sd.encapContentInfo.eContent == NULL) {
   1525 	    hx509_clear_error_string(context);
   1526 	    ret = ENOMEM;
   1527 	    goto out;
   1528 	}
   1529 
   1530 	sigctx.sd.encapContentInfo.eContent->data = malloc(length);
   1531 	if (sigctx.sd.encapContentInfo.eContent->data == NULL) {
   1532 	    hx509_clear_error_string(context);
   1533 	    ret = ENOMEM;
   1534 	    goto out;
   1535 	}
   1536 	memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length);
   1537 	sigctx.sd.encapContentInfo.eContent->length = length;
   1538     }
   1539 
   1540     /**
   1541      * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no
   1542      * signatures).
   1543      */
   1544     if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) {
   1545 	ret = hx509_certs_iter_f(context, certs, sig_process, &sigctx);
   1546 	if (ret)
   1547 	    goto out;
   1548     }
   1549 
   1550     if (sigctx.sd.signerInfos.len) {
   1551 
   1552 	/*
   1553 	 * For each signerInfo, collect all different digest types.
   1554 	 */
   1555 	for (i = 0; i < sigctx.sd.signerInfos.len; i++) {
   1556 	    AlgorithmIdentifier *di =
   1557 		&sigctx.sd.signerInfos.val[i].digestAlgorithm;
   1558 
   1559 	    for (j = 0; j < sigctx.sd.digestAlgorithms.len; j++)
   1560 		if (cmp_AlgorithmIdentifier(di, &sigctx.sd.digestAlgorithms.val[j]) == 0)
   1561 		    break;
   1562 	    if (j == sigctx.sd.digestAlgorithms.len) {
   1563 		ret = add_DigestAlgorithmIdentifiers(&sigctx.sd.digestAlgorithms, di);
   1564 		if (ret) {
   1565 		    hx509_clear_error_string(context);
   1566 		    goto out;
   1567 		}
   1568 	    }
   1569 	}
   1570     }
   1571 
   1572     /*
   1573      * Add certs we think are needed, build as part of sig_process
   1574      */
   1575     if (sigctx.certs) {
   1576 	ALLOC(sigctx.sd.certificates, 1);
   1577 	if (sigctx.sd.certificates == NULL) {
   1578 	    hx509_clear_error_string(context);
   1579 	    ret = ENOMEM;
   1580 	    goto out;
   1581 	}
   1582 
   1583 	ret = hx509_certs_iter_f(context, sigctx.certs, cert_process, &sigctx);
   1584 	if (ret)
   1585 	    goto out;
   1586     }
   1587 
   1588     ASN1_MALLOC_ENCODE(SignedData,
   1589 		       signed_data->data, signed_data->length,
   1590 		       &sigctx.sd, &size, ret);
   1591     if (ret) {
   1592 	hx509_clear_error_string(context);
   1593 	goto out;
   1594     }
   1595     if (signed_data->length != size)
   1596 	_hx509_abort("internal ASN.1 encoder error");
   1597 
   1598 out:
   1599     hx509_certs_free(&sigctx.certs);
   1600     free_SignedData(&sigctx.sd);
   1601 
   1602     return ret;
   1603 }
   1604 
   1605 int
   1606 hx509_cms_decrypt_encrypted(hx509_context context,
   1607 			    hx509_lock lock,
   1608 			    const void *data,
   1609 			    size_t length,
   1610 			    heim_oid *contentType,
   1611 			    heim_octet_string *content)
   1612 {
   1613     heim_octet_string cont;
   1614     CMSEncryptedData ed;
   1615     AlgorithmIdentifier *ai;
   1616     int ret;
   1617 
   1618     memset(content, 0, sizeof(*content));
   1619     memset(&cont, 0, sizeof(cont));
   1620 
   1621     ret = decode_CMSEncryptedData(data, length, &ed, NULL);
   1622     if (ret) {
   1623 	hx509_set_error_string(context, 0, ret,
   1624 			       "Failed to decode CMSEncryptedData");
   1625 	return ret;
   1626     }
   1627 
   1628     if (ed.encryptedContentInfo.encryptedContent == NULL) {
   1629 	ret = HX509_CMS_NO_DATA_AVAILABLE;
   1630 	hx509_set_error_string(context, 0, ret,
   1631 			       "No content in EncryptedData");
   1632 	goto out;
   1633     }
   1634 
   1635     ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
   1636     if (ret) {
   1637 	hx509_clear_error_string(context);
   1638 	goto out;
   1639     }
   1640 
   1641     ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
   1642     if (ai->parameters == NULL) {
   1643 	ret = HX509_ALG_NOT_SUPP;
   1644 	hx509_clear_error_string(context);
   1645 	goto out;
   1646     }
   1647 
   1648     ret = _hx509_pbe_decrypt(context,
   1649 			     lock,
   1650 			     ai,
   1651 			     ed.encryptedContentInfo.encryptedContent,
   1652 			     &cont);
   1653     if (ret)
   1654 	goto out;
   1655 
   1656     *content = cont;
   1657 
   1658 out:
   1659     if (ret) {
   1660 	if (cont.data)
   1661 	    free(cont.data);
   1662     }
   1663     free_CMSEncryptedData(&ed);
   1664     return ret;
   1665 }
   1666