1178825Sdfr/* 2233294Sstas * Copyright (c) 2003 - 2007 Kungliga Tekniska H��gskolan 3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden). 4178825Sdfr * All rights reserved. 5178825Sdfr * 6178825Sdfr * Redistribution and use in source and binary forms, with or without 7178825Sdfr * modification, are permitted provided that the following conditions 8178825Sdfr * are met: 9178825Sdfr * 10178825Sdfr * 1. Redistributions of source code must retain the above copyright 11178825Sdfr * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 14178825Sdfr * notice, this list of conditions and the following disclaimer in the 15178825Sdfr * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors 18178825Sdfr * may be used to endorse or promote products derived from this software 19178825Sdfr * without specific prior written permission. 20178825Sdfr * 21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31178825Sdfr * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "hx_locl.h" 35178825Sdfr 36178825Sdfr/** 37178825Sdfr * @page page_cms CMS/PKCS7 message functions. 38178825Sdfr * 39178825Sdfr * CMS is defined in RFC 3369 and is an continuation of the RSA Labs 40233294Sstas * standard PKCS7. The basic messages in CMS is 41178825Sdfr * 42178825Sdfr * - SignedData 43178825Sdfr * Data signed with private key (RSA, DSA, ECDSA) or secret 44178825Sdfr * (symmetric) key 45178825Sdfr * - EnvelopedData 46178825Sdfr * Data encrypted with private key (RSA) 47178825Sdfr * - EncryptedData 48178825Sdfr * Data encrypted with secret (symmetric) key. 49178825Sdfr * - ContentInfo 50178825Sdfr * Wrapper structure including type and data. 51178825Sdfr * 52178825Sdfr * 53178825Sdfr * See the library functions here: @ref hx509_cms 54178825Sdfr */ 55178825Sdfr 56178825Sdfr#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X))) 57178825Sdfr#define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0) 58178825Sdfr 59178825Sdfr/** 60178825Sdfr * Wrap data and oid in a ContentInfo and encode it. 61178825Sdfr * 62178825Sdfr * @param oid type of the content. 63178825Sdfr * @param buf data to be wrapped. If a NULL pointer is passed in, the 64178825Sdfr * optional content field in the ContentInfo is not going be filled 65178825Sdfr * in. 66178825Sdfr * @param res the encoded buffer, the result should be freed with 67178825Sdfr * der_free_octet_string(). 68178825Sdfr * 69178825Sdfr * @return Returns an hx509 error code. 70233294Sstas * 71178825Sdfr * @ingroup hx509_cms 72178825Sdfr */ 73178825Sdfr 74178825Sdfrint 75178825Sdfrhx509_cms_wrap_ContentInfo(const heim_oid *oid, 76178825Sdfr const heim_octet_string *buf, 77178825Sdfr heim_octet_string *res) 78178825Sdfr{ 79178825Sdfr ContentInfo ci; 80178825Sdfr size_t size; 81178825Sdfr int ret; 82178825Sdfr 83178825Sdfr memset(res, 0, sizeof(*res)); 84178825Sdfr memset(&ci, 0, sizeof(ci)); 85178825Sdfr 86178825Sdfr ret = der_copy_oid(oid, &ci.contentType); 87178825Sdfr if (ret) 88178825Sdfr return ret; 89178825Sdfr if (buf) { 90178825Sdfr ALLOC(ci.content, 1); 91178825Sdfr if (ci.content == NULL) { 92178825Sdfr free_ContentInfo(&ci); 93178825Sdfr return ENOMEM; 94178825Sdfr } 95178825Sdfr ci.content->data = malloc(buf->length); 96178825Sdfr if (ci.content->data == NULL) { 97178825Sdfr free_ContentInfo(&ci); 98178825Sdfr return ENOMEM; 99178825Sdfr } 100178825Sdfr memcpy(ci.content->data, buf->data, buf->length); 101178825Sdfr ci.content->length = buf->length; 102178825Sdfr } 103178825Sdfr 104178825Sdfr ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret); 105178825Sdfr free_ContentInfo(&ci); 106178825Sdfr if (ret) 107178825Sdfr return ret; 108178825Sdfr if (res->length != size) 109178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 110178825Sdfr 111178825Sdfr return 0; 112178825Sdfr} 113178825Sdfr 114178825Sdfr/** 115178825Sdfr * Decode an ContentInfo and unwrap data and oid it. 116178825Sdfr * 117178825Sdfr * @param in the encoded buffer. 118178825Sdfr * @param oid type of the content. 119178825Sdfr * @param out data to be wrapped. 120178825Sdfr * @param have_data since the data is optional, this flags show dthe 121178825Sdfr * diffrence between no data and the zero length data. 122178825Sdfr * 123178825Sdfr * @return Returns an hx509 error code. 124233294Sstas * 125178825Sdfr * @ingroup hx509_cms 126178825Sdfr */ 127178825Sdfr 128178825Sdfrint 129178825Sdfrhx509_cms_unwrap_ContentInfo(const heim_octet_string *in, 130178825Sdfr heim_oid *oid, 131178825Sdfr heim_octet_string *out, 132178825Sdfr int *have_data) 133178825Sdfr{ 134178825Sdfr ContentInfo ci; 135178825Sdfr size_t size; 136178825Sdfr int ret; 137178825Sdfr 138178825Sdfr memset(oid, 0, sizeof(*oid)); 139178825Sdfr memset(out, 0, sizeof(*out)); 140178825Sdfr 141178825Sdfr ret = decode_ContentInfo(in->data, in->length, &ci, &size); 142178825Sdfr if (ret) 143178825Sdfr return ret; 144178825Sdfr 145178825Sdfr ret = der_copy_oid(&ci.contentType, oid); 146178825Sdfr if (ret) { 147178825Sdfr free_ContentInfo(&ci); 148178825Sdfr return ret; 149178825Sdfr } 150178825Sdfr if (ci.content) { 151178825Sdfr ret = der_copy_octet_string(ci.content, out); 152178825Sdfr if (ret) { 153178825Sdfr der_free_oid(oid); 154178825Sdfr free_ContentInfo(&ci); 155178825Sdfr return ret; 156178825Sdfr } 157178825Sdfr } else 158178825Sdfr memset(out, 0, sizeof(*out)); 159178825Sdfr 160178825Sdfr if (have_data) 161178825Sdfr *have_data = (ci.content != NULL) ? 1 : 0; 162178825Sdfr 163178825Sdfr free_ContentInfo(&ci); 164178825Sdfr 165178825Sdfr return 0; 166178825Sdfr} 167178825Sdfr 168178825Sdfr#define CMS_ID_SKI 0 169178825Sdfr#define CMS_ID_NAME 1 170178825Sdfr 171178825Sdfrstatic int 172178825Sdfrfill_CMSIdentifier(const hx509_cert cert, 173178825Sdfr int type, 174178825Sdfr CMSIdentifier *id) 175178825Sdfr{ 176178825Sdfr int ret; 177178825Sdfr 178178825Sdfr switch (type) { 179178825Sdfr case CMS_ID_SKI: 180178825Sdfr id->element = choice_CMSIdentifier_subjectKeyIdentifier; 181178825Sdfr ret = _hx509_find_extension_subject_key_id(_hx509_get_cert(cert), 182178825Sdfr &id->u.subjectKeyIdentifier); 183178825Sdfr if (ret == 0) 184178825Sdfr break; 185178825Sdfr /* FALL THOUGH */ 186178825Sdfr case CMS_ID_NAME: { 187178825Sdfr hx509_name name; 188178825Sdfr 189178825Sdfr id->element = choice_CMSIdentifier_issuerAndSerialNumber; 190178825Sdfr ret = hx509_cert_get_issuer(cert, &name); 191178825Sdfr if (ret) 192178825Sdfr return ret; 193178825Sdfr ret = hx509_name_to_Name(name, &id->u.issuerAndSerialNumber.issuer); 194178825Sdfr hx509_name_free(&name); 195178825Sdfr if (ret) 196178825Sdfr return ret; 197178825Sdfr 198178825Sdfr ret = hx509_cert_get_serialnumber(cert, &id->u.issuerAndSerialNumber.serialNumber); 199178825Sdfr break; 200178825Sdfr } 201178825Sdfr default: 202178825Sdfr _hx509_abort("CMS fill identifier with unknown type"); 203178825Sdfr } 204178825Sdfr return ret; 205178825Sdfr} 206178825Sdfr 207178825Sdfrstatic int 208178825Sdfrunparse_CMSIdentifier(hx509_context context, 209178825Sdfr CMSIdentifier *id, 210178825Sdfr char **str) 211178825Sdfr{ 212178825Sdfr int ret; 213178825Sdfr 214178825Sdfr *str = NULL; 215178825Sdfr switch (id->element) { 216178825Sdfr case choice_CMSIdentifier_issuerAndSerialNumber: { 217178825Sdfr IssuerAndSerialNumber *iasn; 218178825Sdfr char *serial, *name; 219178825Sdfr 220178825Sdfr iasn = &id->u.issuerAndSerialNumber; 221178825Sdfr 222178825Sdfr ret = _hx509_Name_to_string(&iasn->issuer, &name); 223178825Sdfr if(ret) 224178825Sdfr return ret; 225178825Sdfr ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial); 226178825Sdfr if (ret) { 227178825Sdfr free(name); 228178825Sdfr return ret; 229178825Sdfr } 230178825Sdfr asprintf(str, "certificate issued by %s with serial number %s", 231178825Sdfr name, serial); 232178825Sdfr free(name); 233178825Sdfr free(serial); 234178825Sdfr break; 235178825Sdfr } 236178825Sdfr case choice_CMSIdentifier_subjectKeyIdentifier: { 237178825Sdfr KeyIdentifier *ki = &id->u.subjectKeyIdentifier; 238178825Sdfr char *keyid; 239178825Sdfr ssize_t len; 240178825Sdfr 241178825Sdfr len = hex_encode(ki->data, ki->length, &keyid); 242178825Sdfr if (len < 0) 243178825Sdfr return ENOMEM; 244178825Sdfr 245178825Sdfr asprintf(str, "certificate with id %s", keyid); 246178825Sdfr free(keyid); 247178825Sdfr break; 248178825Sdfr } 249178825Sdfr default: 250178825Sdfr asprintf(str, "certificate have unknown CMSidentifier type"); 251178825Sdfr break; 252178825Sdfr } 253178825Sdfr if (*str == NULL) 254178825Sdfr return ENOMEM; 255178825Sdfr return 0; 256178825Sdfr} 257178825Sdfr 258178825Sdfrstatic int 259178825Sdfrfind_CMSIdentifier(hx509_context context, 260178825Sdfr CMSIdentifier *client, 261178825Sdfr hx509_certs certs, 262233294Sstas time_t time_now, 263178825Sdfr hx509_cert *signer_cert, 264178825Sdfr int match) 265178825Sdfr{ 266178825Sdfr hx509_query q; 267178825Sdfr hx509_cert cert; 268178825Sdfr Certificate c; 269178825Sdfr int ret; 270178825Sdfr 271178825Sdfr memset(&c, 0, sizeof(c)); 272178825Sdfr _hx509_query_clear(&q); 273178825Sdfr 274178825Sdfr *signer_cert = NULL; 275178825Sdfr 276178825Sdfr switch (client->element) { 277178825Sdfr case choice_CMSIdentifier_issuerAndSerialNumber: 278178825Sdfr q.serial = &client->u.issuerAndSerialNumber.serialNumber; 279178825Sdfr q.issuer_name = &client->u.issuerAndSerialNumber.issuer; 280178825Sdfr q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME; 281178825Sdfr break; 282178825Sdfr case choice_CMSIdentifier_subjectKeyIdentifier: 283178825Sdfr q.subject_id = &client->u.subjectKeyIdentifier; 284178825Sdfr q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID; 285178825Sdfr break; 286178825Sdfr default: 287178825Sdfr hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE, 288178825Sdfr "unknown CMS identifier element"); 289178825Sdfr return HX509_CMS_NO_RECIPIENT_CERTIFICATE; 290178825Sdfr } 291178825Sdfr 292178825Sdfr q.match |= match; 293178825Sdfr 294178825Sdfr q.match |= HX509_QUERY_MATCH_TIME; 295233294Sstas if (time_now) 296233294Sstas q.timenow = time_now; 297233294Sstas else 298233294Sstas q.timenow = time(NULL); 299178825Sdfr 300178825Sdfr ret = hx509_certs_find(context, certs, &q, &cert); 301178825Sdfr if (ret == HX509_CERT_NOT_FOUND) { 302178825Sdfr char *str; 303178825Sdfr 304178825Sdfr ret = unparse_CMSIdentifier(context, client, &str); 305178825Sdfr if (ret == 0) { 306178825Sdfr hx509_set_error_string(context, 0, 307178825Sdfr HX509_CMS_NO_RECIPIENT_CERTIFICATE, 308178825Sdfr "Failed to find %s", str); 309178825Sdfr } else 310178825Sdfr hx509_clear_error_string(context); 311178825Sdfr return HX509_CMS_NO_RECIPIENT_CERTIFICATE; 312178825Sdfr } else if (ret) { 313178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, 314178825Sdfr HX509_CMS_NO_RECIPIENT_CERTIFICATE, 315178825Sdfr "Failed to find CMS id in cert store"); 316178825Sdfr return HX509_CMS_NO_RECIPIENT_CERTIFICATE; 317178825Sdfr } 318178825Sdfr 319178825Sdfr *signer_cert = cert; 320178825Sdfr 321178825Sdfr return 0; 322178825Sdfr} 323178825Sdfr 324178825Sdfr/** 325178825Sdfr * Decode and unencrypt EnvelopedData. 326178825Sdfr * 327178825Sdfr * Extract data and parameteres from from the EnvelopedData. Also 328178825Sdfr * supports using detached EnvelopedData. 329178825Sdfr * 330178825Sdfr * @param context A hx509 context. 331178825Sdfr * @param certs Certificate that can decrypt the EnvelopedData 332178825Sdfr * encryption key. 333178825Sdfr * @param flags HX509_CMS_UE flags to control the behavior. 334178825Sdfr * @param data pointer the structure the contains the DER/BER encoded 335178825Sdfr * EnvelopedData stucture. 336178825Sdfr * @param length length of the data that data point to. 337178825Sdfr * @param encryptedContent in case of detached signature, this 338178825Sdfr * contains the actual encrypted data, othersize its should be NULL. 339233294Sstas * @param time_now set the current time, if zero the library uses now as the date. 340178825Sdfr * @param contentType output type oid, should be freed with der_free_oid(). 341178825Sdfr * @param content the data, free with der_free_octet_string(). 342178825Sdfr * 343178825Sdfr * @ingroup hx509_cms 344178825Sdfr */ 345178825Sdfr 346178825Sdfrint 347178825Sdfrhx509_cms_unenvelope(hx509_context context, 348178825Sdfr hx509_certs certs, 349178825Sdfr int flags, 350178825Sdfr const void *data, 351178825Sdfr size_t length, 352178825Sdfr const heim_octet_string *encryptedContent, 353233294Sstas time_t time_now, 354178825Sdfr heim_oid *contentType, 355178825Sdfr heim_octet_string *content) 356178825Sdfr{ 357178825Sdfr heim_octet_string key; 358178825Sdfr EnvelopedData ed; 359178825Sdfr hx509_cert cert; 360178825Sdfr AlgorithmIdentifier *ai; 361178825Sdfr const heim_octet_string *enccontent; 362178825Sdfr heim_octet_string *params, params_data; 363178825Sdfr heim_octet_string ivec; 364178825Sdfr size_t size; 365233294Sstas int ret, matched = 0, findflags = 0; 366233294Sstas size_t i; 367178825Sdfr 368178825Sdfr 369178825Sdfr memset(&key, 0, sizeof(key)); 370178825Sdfr memset(&ed, 0, sizeof(ed)); 371178825Sdfr memset(&ivec, 0, sizeof(ivec)); 372178825Sdfr memset(content, 0, sizeof(*content)); 373178825Sdfr memset(contentType, 0, sizeof(*contentType)); 374178825Sdfr 375178825Sdfr if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0) 376178825Sdfr findflags |= HX509_QUERY_KU_ENCIPHERMENT; 377178825Sdfr 378178825Sdfr ret = decode_EnvelopedData(data, length, &ed, &size); 379178825Sdfr if (ret) { 380178825Sdfr hx509_set_error_string(context, 0, ret, 381178825Sdfr "Failed to decode EnvelopedData"); 382178825Sdfr return ret; 383178825Sdfr } 384178825Sdfr 385178825Sdfr if (ed.recipientInfos.len == 0) { 386178825Sdfr ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; 387178825Sdfr hx509_set_error_string(context, 0, ret, 388178825Sdfr "No recipient info in enveloped data"); 389178825Sdfr goto out; 390178825Sdfr } 391178825Sdfr 392178825Sdfr enccontent = ed.encryptedContentInfo.encryptedContent; 393178825Sdfr if (enccontent == NULL) { 394178825Sdfr if (encryptedContent == NULL) { 395178825Sdfr ret = HX509_CMS_NO_DATA_AVAILABLE; 396178825Sdfr hx509_set_error_string(context, 0, ret, 397178825Sdfr "Content missing from encrypted data"); 398178825Sdfr goto out; 399178825Sdfr } 400178825Sdfr enccontent = encryptedContent; 401178825Sdfr } else if (encryptedContent != NULL) { 402178825Sdfr ret = HX509_CMS_NO_DATA_AVAILABLE; 403178825Sdfr hx509_set_error_string(context, 0, ret, 404178825Sdfr "Both internal and external encrypted data"); 405178825Sdfr goto out; 406178825Sdfr } 407178825Sdfr 408178825Sdfr cert = NULL; 409178825Sdfr for (i = 0; i < ed.recipientInfos.len; i++) { 410178825Sdfr KeyTransRecipientInfo *ri; 411178825Sdfr char *str; 412178825Sdfr int ret2; 413178825Sdfr 414178825Sdfr ri = &ed.recipientInfos.val[i]; 415178825Sdfr 416233294Sstas ret = find_CMSIdentifier(context, &ri->rid, certs, 417233294Sstas time_now, &cert, 418178825Sdfr HX509_QUERY_PRIVATE_KEY|findflags); 419178825Sdfr if (ret) 420178825Sdfr continue; 421178825Sdfr 422178825Sdfr matched = 1; /* found a matching certificate, let decrypt */ 423178825Sdfr 424178825Sdfr ret = _hx509_cert_private_decrypt(context, 425178825Sdfr &ri->encryptedKey, 426178825Sdfr &ri->keyEncryptionAlgorithm.algorithm, 427178825Sdfr cert, &key); 428178825Sdfr 429178825Sdfr hx509_cert_free(cert); 430178825Sdfr if (ret == 0) 431178825Sdfr break; /* succuessfully decrypted cert */ 432178825Sdfr cert = NULL; 433178825Sdfr ret2 = unparse_CMSIdentifier(context, &ri->rid, &str); 434178825Sdfr if (ret2 == 0) { 435178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 436178825Sdfr "Failed to decrypt with %s", str); 437178825Sdfr free(str); 438178825Sdfr } 439178825Sdfr } 440178825Sdfr 441178825Sdfr if (!matched) { 442178825Sdfr ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; 443178825Sdfr hx509_set_error_string(context, 0, ret, 444178825Sdfr "No private key matched any certificate"); 445178825Sdfr goto out; 446178825Sdfr } 447178825Sdfr 448178825Sdfr if (cert == NULL) { 449178825Sdfr ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; 450178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 451178825Sdfr "No private key decrypted the transfer key"); 452178825Sdfr goto out; 453178825Sdfr } 454178825Sdfr 455178825Sdfr ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType); 456178825Sdfr if (ret) { 457178825Sdfr hx509_set_error_string(context, 0, ret, 458178825Sdfr "Failed to copy EnvelopedData content oid"); 459178825Sdfr goto out; 460178825Sdfr } 461178825Sdfr 462178825Sdfr ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm; 463178825Sdfr if (ai->parameters) { 464178825Sdfr params_data.data = ai->parameters->data; 465178825Sdfr params_data.length = ai->parameters->length; 466178825Sdfr params = ¶ms_data; 467178825Sdfr } else 468178825Sdfr params = NULL; 469178825Sdfr 470178825Sdfr { 471178825Sdfr hx509_crypto crypto; 472178825Sdfr 473178825Sdfr ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto); 474178825Sdfr if (ret) 475178825Sdfr goto out; 476233294Sstas 477233294Sstas if (flags & HX509_CMS_UE_ALLOW_WEAK) 478233294Sstas hx509_crypto_allow_weak(crypto); 479233294Sstas 480178825Sdfr if (params) { 481178825Sdfr ret = hx509_crypto_set_params(context, crypto, params, &ivec); 482178825Sdfr if (ret) { 483178825Sdfr hx509_crypto_destroy(crypto); 484178825Sdfr goto out; 485178825Sdfr } 486178825Sdfr } 487178825Sdfr 488178825Sdfr ret = hx509_crypto_set_key_data(crypto, key.data, key.length); 489178825Sdfr if (ret) { 490178825Sdfr hx509_crypto_destroy(crypto); 491178825Sdfr hx509_set_error_string(context, 0, ret, 492178825Sdfr "Failed to set key for decryption " 493178825Sdfr "of EnvelopedData"); 494178825Sdfr goto out; 495178825Sdfr } 496233294Sstas 497178825Sdfr ret = hx509_crypto_decrypt(crypto, 498178825Sdfr enccontent->data, 499178825Sdfr enccontent->length, 500178825Sdfr ivec.length ? &ivec : NULL, 501178825Sdfr content); 502178825Sdfr hx509_crypto_destroy(crypto); 503178825Sdfr if (ret) { 504178825Sdfr hx509_set_error_string(context, 0, ret, 505178825Sdfr "Failed to decrypt EnvelopedData"); 506178825Sdfr goto out; 507178825Sdfr } 508178825Sdfr } 509178825Sdfr 510178825Sdfrout: 511178825Sdfr 512178825Sdfr free_EnvelopedData(&ed); 513178825Sdfr der_free_octet_string(&key); 514178825Sdfr if (ivec.length) 515178825Sdfr der_free_octet_string(&ivec); 516178825Sdfr if (ret) { 517178825Sdfr der_free_oid(contentType); 518178825Sdfr der_free_octet_string(content); 519178825Sdfr } 520178825Sdfr 521178825Sdfr return ret; 522178825Sdfr} 523178825Sdfr 524178825Sdfr/** 525178825Sdfr * Encrypt end encode EnvelopedData. 526178825Sdfr * 527178825Sdfr * Encrypt and encode EnvelopedData. The data is encrypted with a 528178825Sdfr * random key and the the random key is encrypted with the 529178825Sdfr * certificates private key. This limits what private key type can be 530178825Sdfr * used to RSA. 531178825Sdfr * 532178825Sdfr * @param context A hx509 context. 533233294Sstas * @param flags flags to control the behavior. 534233294Sstas * - HX509_CMS_EV_NO_KU_CHECK - Dont check KU on certificate 535233294Sstas * - HX509_CMS_EV_ALLOW_WEAK - Allow weak crytpo 536233294Sstas * - HX509_CMS_EV_ID_NAME - prefer issuer name and serial number 537178825Sdfr * @param cert Certificate to encrypt the EnvelopedData encryption key 538178825Sdfr * with. 539178825Sdfr * @param data pointer the data to encrypt. 540178825Sdfr * @param length length of the data that data point to. 541178825Sdfr * @param encryption_type Encryption cipher to use for the bulk data, 542178825Sdfr * use NULL to get default. 543178825Sdfr * @param contentType type of the data that is encrypted 544178825Sdfr * @param content the output of the function, 545178825Sdfr * free with der_free_octet_string(). 546178825Sdfr * 547178825Sdfr * @ingroup hx509_cms 548178825Sdfr */ 549178825Sdfr 550178825Sdfrint 551178825Sdfrhx509_cms_envelope_1(hx509_context context, 552178825Sdfr int flags, 553178825Sdfr hx509_cert cert, 554178825Sdfr const void *data, 555178825Sdfr size_t length, 556178825Sdfr const heim_oid *encryption_type, 557178825Sdfr const heim_oid *contentType, 558178825Sdfr heim_octet_string *content) 559178825Sdfr{ 560178825Sdfr KeyTransRecipientInfo *ri; 561178825Sdfr heim_octet_string ivec; 562178825Sdfr heim_octet_string key; 563178825Sdfr hx509_crypto crypto = NULL; 564233294Sstas int ret, cmsidflag; 565178825Sdfr EnvelopedData ed; 566178825Sdfr size_t size; 567178825Sdfr 568178825Sdfr memset(&ivec, 0, sizeof(ivec)); 569178825Sdfr memset(&key, 0, sizeof(key)); 570178825Sdfr memset(&ed, 0, sizeof(ed)); 571178825Sdfr memset(content, 0, sizeof(*content)); 572178825Sdfr 573178825Sdfr if (encryption_type == NULL) 574233294Sstas encryption_type = &asn1_oid_id_aes_256_cbc; 575178825Sdfr 576233294Sstas if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) { 577233294Sstas ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE); 578233294Sstas if (ret) 579233294Sstas goto out; 580233294Sstas } 581178825Sdfr 582178825Sdfr ret = hx509_crypto_init(context, NULL, encryption_type, &crypto); 583178825Sdfr if (ret) 584178825Sdfr goto out; 585178825Sdfr 586233294Sstas if (flags & HX509_CMS_EV_ALLOW_WEAK) 587233294Sstas hx509_crypto_allow_weak(crypto); 588233294Sstas 589178825Sdfr ret = hx509_crypto_set_random_key(crypto, &key); 590178825Sdfr if (ret) { 591178825Sdfr hx509_set_error_string(context, 0, ret, 592178825Sdfr "Create random key for EnvelopedData content"); 593178825Sdfr goto out; 594178825Sdfr } 595178825Sdfr 596178825Sdfr ret = hx509_crypto_random_iv(crypto, &ivec); 597178825Sdfr if (ret) { 598178825Sdfr hx509_set_error_string(context, 0, ret, 599178825Sdfr "Failed to create a random iv"); 600178825Sdfr goto out; 601178825Sdfr } 602178825Sdfr 603178825Sdfr ret = hx509_crypto_encrypt(crypto, 604178825Sdfr data, 605178825Sdfr length, 606178825Sdfr &ivec, 607178825Sdfr &ed.encryptedContentInfo.encryptedContent); 608178825Sdfr if (ret) { 609178825Sdfr hx509_set_error_string(context, 0, ret, 610178825Sdfr "Failed to encrypt EnvelopedData content"); 611178825Sdfr goto out; 612178825Sdfr } 613178825Sdfr 614178825Sdfr { 615178825Sdfr AlgorithmIdentifier *enc_alg; 616178825Sdfr enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm; 617178825Sdfr ret = der_copy_oid(encryption_type, &enc_alg->algorithm); 618178825Sdfr if (ret) { 619178825Sdfr hx509_set_error_string(context, 0, ret, 620178825Sdfr "Failed to set crypto oid " 621178825Sdfr "for EnvelopedData"); 622178825Sdfr goto out; 623233294Sstas } 624178825Sdfr ALLOC(enc_alg->parameters, 1); 625178825Sdfr if (enc_alg->parameters == NULL) { 626178825Sdfr ret = ENOMEM; 627178825Sdfr hx509_set_error_string(context, 0, ret, 628178825Sdfr "Failed to allocate crypto paramaters " 629178825Sdfr "for EnvelopedData"); 630178825Sdfr goto out; 631178825Sdfr } 632178825Sdfr 633178825Sdfr ret = hx509_crypto_get_params(context, 634178825Sdfr crypto, 635178825Sdfr &ivec, 636178825Sdfr enc_alg->parameters); 637178825Sdfr if (ret) { 638178825Sdfr goto out; 639178825Sdfr } 640178825Sdfr } 641178825Sdfr 642178825Sdfr ALLOC_SEQ(&ed.recipientInfos, 1); 643178825Sdfr if (ed.recipientInfos.val == NULL) { 644178825Sdfr ret = ENOMEM; 645178825Sdfr hx509_set_error_string(context, 0, ret, 646178825Sdfr "Failed to allocate recipients info " 647178825Sdfr "for EnvelopedData"); 648178825Sdfr goto out; 649178825Sdfr } 650178825Sdfr 651178825Sdfr ri = &ed.recipientInfos.val[0]; 652178825Sdfr 653233294Sstas if (flags & HX509_CMS_EV_ID_NAME) { 654233294Sstas ri->version = 0; 655233294Sstas cmsidflag = CMS_ID_NAME; 656233294Sstas } else { 657233294Sstas ri->version = 2; 658233294Sstas cmsidflag = CMS_ID_SKI; 659233294Sstas } 660233294Sstas 661233294Sstas ret = fill_CMSIdentifier(cert, cmsidflag, &ri->rid); 662178825Sdfr if (ret) { 663178825Sdfr hx509_set_error_string(context, 0, ret, 664178825Sdfr "Failed to set CMS identifier info " 665178825Sdfr "for EnvelopedData"); 666178825Sdfr goto out; 667178825Sdfr } 668178825Sdfr 669233294Sstas ret = hx509_cert_public_encrypt(context, 670178825Sdfr &key, cert, 671178825Sdfr &ri->keyEncryptionAlgorithm.algorithm, 672178825Sdfr &ri->encryptedKey); 673178825Sdfr if (ret) { 674178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 675178825Sdfr "Failed to encrypt transport key for " 676178825Sdfr "EnvelopedData"); 677178825Sdfr goto out; 678178825Sdfr } 679178825Sdfr 680178825Sdfr /* 681178825Sdfr * 682178825Sdfr */ 683178825Sdfr 684178825Sdfr ed.version = 0; 685178825Sdfr ed.originatorInfo = NULL; 686178825Sdfr 687178825Sdfr ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType); 688178825Sdfr if (ret) { 689178825Sdfr hx509_set_error_string(context, 0, ret, 690178825Sdfr "Failed to copy content oid for " 691178825Sdfr "EnvelopedData"); 692178825Sdfr goto out; 693178825Sdfr } 694178825Sdfr 695178825Sdfr ed.unprotectedAttrs = NULL; 696178825Sdfr 697178825Sdfr ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length, 698178825Sdfr &ed, &size, ret); 699178825Sdfr if (ret) { 700178825Sdfr hx509_set_error_string(context, 0, ret, 701178825Sdfr "Failed to encode EnvelopedData"); 702178825Sdfr goto out; 703178825Sdfr } 704178825Sdfr if (size != content->length) 705178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 706178825Sdfr 707178825Sdfrout: 708178825Sdfr if (crypto) 709178825Sdfr hx509_crypto_destroy(crypto); 710178825Sdfr if (ret) 711178825Sdfr der_free_octet_string(content); 712178825Sdfr der_free_octet_string(&key); 713178825Sdfr der_free_octet_string(&ivec); 714178825Sdfr free_EnvelopedData(&ed); 715178825Sdfr 716178825Sdfr return ret; 717178825Sdfr} 718178825Sdfr 719178825Sdfrstatic int 720178825Sdfrany_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs) 721178825Sdfr{ 722233294Sstas int ret; 723233294Sstas size_t i; 724178825Sdfr 725178825Sdfr if (sd->certificates == NULL) 726178825Sdfr return 0; 727178825Sdfr 728178825Sdfr for (i = 0; i < sd->certificates->len; i++) { 729178825Sdfr hx509_cert c; 730178825Sdfr 731233294Sstas ret = hx509_cert_init_data(context, 732233294Sstas sd->certificates->val[i].data, 733178825Sdfr sd->certificates->val[i].length, 734178825Sdfr &c); 735178825Sdfr if (ret) 736178825Sdfr return ret; 737178825Sdfr ret = hx509_certs_add(context, certs, c); 738178825Sdfr hx509_cert_free(c); 739178825Sdfr if (ret) 740178825Sdfr return ret; 741178825Sdfr } 742178825Sdfr 743178825Sdfr return 0; 744178825Sdfr} 745178825Sdfr 746178825Sdfrstatic const Attribute * 747178825Sdfrfind_attribute(const CMSAttributes *attr, const heim_oid *oid) 748178825Sdfr{ 749233294Sstas size_t i; 750178825Sdfr for (i = 0; i < attr->len; i++) 751178825Sdfr if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0) 752178825Sdfr return &attr->val[i]; 753178825Sdfr return NULL; 754178825Sdfr} 755178825Sdfr 756178825Sdfr/** 757178825Sdfr * Decode SignedData and verify that the signature is correct. 758178825Sdfr * 759178825Sdfr * @param context A hx509 context. 760233294Sstas * @param ctx a hx509 verify context. 761233294Sstas * @param flags to control the behaivor of the function. 762233294Sstas * - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage 763233294Sstas * - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch 764233294Sstas * - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below. 765233294Sstas * @param data pointer to CMS SignedData encoded data. 766178825Sdfr * @param length length of the data that data point to. 767233294Sstas * @param signedContent external data used for signature. 768178825Sdfr * @param pool certificate pool to build certificates paths. 769233294Sstas * @param contentType free with der_free_oid(). 770178825Sdfr * @param content the output of the function, free with 771178825Sdfr * der_free_octet_string(). 772178825Sdfr * @param signer_certs list of the cerficates used to sign this 773178825Sdfr * request, free with hx509_certs_free(). 774178825Sdfr * 775178825Sdfr * @ingroup hx509_cms 776178825Sdfr */ 777178825Sdfr 778178825Sdfrint 779178825Sdfrhx509_cms_verify_signed(hx509_context context, 780178825Sdfr hx509_verify_ctx ctx, 781233294Sstas unsigned int flags, 782178825Sdfr const void *data, 783178825Sdfr size_t length, 784178825Sdfr const heim_octet_string *signedContent, 785178825Sdfr hx509_certs pool, 786178825Sdfr heim_oid *contentType, 787178825Sdfr heim_octet_string *content, 788178825Sdfr hx509_certs *signer_certs) 789178825Sdfr{ 790178825Sdfr SignerInfo *signer_info; 791178825Sdfr hx509_cert cert = NULL; 792178825Sdfr hx509_certs certs = NULL; 793178825Sdfr SignedData sd; 794178825Sdfr size_t size; 795233294Sstas int ret, found_valid_sig; 796233294Sstas size_t i; 797178825Sdfr 798178825Sdfr *signer_certs = NULL; 799178825Sdfr content->data = NULL; 800178825Sdfr content->length = 0; 801178825Sdfr contentType->length = 0; 802178825Sdfr contentType->components = NULL; 803178825Sdfr 804178825Sdfr memset(&sd, 0, sizeof(sd)); 805178825Sdfr 806178825Sdfr ret = decode_SignedData(data, length, &sd, &size); 807178825Sdfr if (ret) { 808178825Sdfr hx509_set_error_string(context, 0, ret, 809178825Sdfr "Failed to decode SignedData"); 810178825Sdfr goto out; 811178825Sdfr } 812178825Sdfr 813178825Sdfr if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) { 814178825Sdfr ret = HX509_CMS_NO_DATA_AVAILABLE; 815178825Sdfr hx509_set_error_string(context, 0, ret, 816178825Sdfr "No content data in SignedData"); 817178825Sdfr goto out; 818178825Sdfr } 819178825Sdfr if (sd.encapContentInfo.eContent && signedContent) { 820178825Sdfr ret = HX509_CMS_NO_DATA_AVAILABLE; 821178825Sdfr hx509_set_error_string(context, 0, ret, 822178825Sdfr "Both external and internal SignedData"); 823178825Sdfr goto out; 824178825Sdfr } 825233294Sstas 826178825Sdfr if (sd.encapContentInfo.eContent) 827233294Sstas ret = der_copy_octet_string(sd.encapContentInfo.eContent, content); 828233294Sstas else 829233294Sstas ret = der_copy_octet_string(signedContent, content); 830233294Sstas if (ret) { 831233294Sstas hx509_set_error_string(context, 0, ret, "malloc: out of memory"); 832233294Sstas goto out; 833233294Sstas } 834178825Sdfr 835178825Sdfr ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer", 836178825Sdfr 0, NULL, &certs); 837178825Sdfr if (ret) 838178825Sdfr goto out; 839178825Sdfr 840178825Sdfr ret = hx509_certs_init(context, "MEMORY:cms-signer-certs", 841178825Sdfr 0, NULL, signer_certs); 842178825Sdfr if (ret) 843178825Sdfr goto out; 844178825Sdfr 845178825Sdfr /* XXX Check CMS version */ 846178825Sdfr 847178825Sdfr ret = any_to_certs(context, &sd, certs); 848178825Sdfr if (ret) 849178825Sdfr goto out; 850178825Sdfr 851178825Sdfr if (pool) { 852178825Sdfr ret = hx509_certs_merge(context, certs, pool); 853178825Sdfr if (ret) 854178825Sdfr goto out; 855178825Sdfr } 856178825Sdfr 857178825Sdfr for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) { 858233294Sstas heim_octet_string signed_data; 859178825Sdfr const heim_oid *match_oid; 860178825Sdfr heim_oid decode_oid; 861178825Sdfr 862178825Sdfr signer_info = &sd.signerInfos.val[i]; 863178825Sdfr match_oid = NULL; 864178825Sdfr 865178825Sdfr if (signer_info->signature.length == 0) { 866178825Sdfr ret = HX509_CMS_MISSING_SIGNER_DATA; 867178825Sdfr hx509_set_error_string(context, 0, ret, 868178825Sdfr "SignerInfo %d in SignedData " 869178825Sdfr "missing sigature", i); 870178825Sdfr continue; 871178825Sdfr } 872178825Sdfr 873233294Sstas ret = find_CMSIdentifier(context, &signer_info->sid, certs, 874233294Sstas _hx509_verify_get_time(ctx), &cert, 875178825Sdfr HX509_QUERY_KU_DIGITALSIGNATURE); 876233294Sstas if (ret) { 877233294Sstas /** 878233294Sstas * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal 879233294Sstas * search for matching certificates by not considering 880233294Sstas * KeyUsage bits on the certificates. 881233294Sstas */ 882233294Sstas if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0) 883233294Sstas continue; 884178825Sdfr 885233294Sstas ret = find_CMSIdentifier(context, &signer_info->sid, certs, 886233294Sstas _hx509_verify_get_time(ctx), &cert, 887233294Sstas 0); 888233294Sstas if (ret) 889233294Sstas continue; 890233294Sstas 891233294Sstas } 892233294Sstas 893178825Sdfr if (signer_info->signedAttrs) { 894178825Sdfr const Attribute *attr; 895233294Sstas 896178825Sdfr CMSAttributes sa; 897178825Sdfr heim_octet_string os; 898178825Sdfr 899178825Sdfr sa.val = signer_info->signedAttrs->val; 900178825Sdfr sa.len = signer_info->signedAttrs->len; 901178825Sdfr 902178825Sdfr /* verify that sigature exists */ 903233294Sstas attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest); 904178825Sdfr if (attr == NULL) { 905178825Sdfr ret = HX509_CRYPTO_SIGNATURE_MISSING; 906178825Sdfr hx509_set_error_string(context, 0, ret, 907178825Sdfr "SignerInfo have signed attributes " 908178825Sdfr "but messageDigest (signature) " 909178825Sdfr "is missing"); 910178825Sdfr goto next_sigature; 911178825Sdfr } 912178825Sdfr if (attr->value.len != 1) { 913178825Sdfr ret = HX509_CRYPTO_SIGNATURE_MISSING; 914178825Sdfr hx509_set_error_string(context, 0, ret, 915178825Sdfr "SignerInfo have more then one " 916178825Sdfr "messageDigest (signature)"); 917178825Sdfr goto next_sigature; 918178825Sdfr } 919233294Sstas 920178825Sdfr ret = decode_MessageDigest(attr->value.val[0].data, 921178825Sdfr attr->value.val[0].length, 922178825Sdfr &os, 923178825Sdfr &size); 924178825Sdfr if (ret) { 925178825Sdfr hx509_set_error_string(context, 0, ret, 926178825Sdfr "Failed to decode " 927178825Sdfr "messageDigest (signature)"); 928178825Sdfr goto next_sigature; 929178825Sdfr } 930178825Sdfr 931178825Sdfr ret = _hx509_verify_signature(context, 932178825Sdfr NULL, 933178825Sdfr &signer_info->digestAlgorithm, 934233294Sstas content, 935178825Sdfr &os); 936178825Sdfr der_free_octet_string(&os); 937178825Sdfr if (ret) { 938178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 939178825Sdfr "Failed to verify messageDigest"); 940178825Sdfr goto next_sigature; 941178825Sdfr } 942178825Sdfr 943178825Sdfr /* 944178825Sdfr * Fetch content oid inside signedAttrs or set it to 945178825Sdfr * id-pkcs7-data. 946178825Sdfr */ 947233294Sstas attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType); 948178825Sdfr if (attr == NULL) { 949233294Sstas match_oid = &asn1_oid_id_pkcs7_data; 950178825Sdfr } else { 951178825Sdfr if (attr->value.len != 1) { 952178825Sdfr ret = HX509_CMS_DATA_OID_MISMATCH; 953178825Sdfr hx509_set_error_string(context, 0, ret, 954178825Sdfr "More then one oid in signedAttrs"); 955178825Sdfr goto next_sigature; 956178825Sdfr 957178825Sdfr } 958178825Sdfr ret = decode_ContentType(attr->value.val[0].data, 959178825Sdfr attr->value.val[0].length, 960178825Sdfr &decode_oid, 961178825Sdfr &size); 962178825Sdfr if (ret) { 963178825Sdfr hx509_set_error_string(context, 0, ret, 964178825Sdfr "Failed to decode " 965178825Sdfr "oid in signedAttrs"); 966178825Sdfr goto next_sigature; 967178825Sdfr } 968178825Sdfr match_oid = &decode_oid; 969178825Sdfr } 970178825Sdfr 971178825Sdfr ASN1_MALLOC_ENCODE(CMSAttributes, 972233294Sstas signed_data.data, 973233294Sstas signed_data.length, 974178825Sdfr &sa, 975178825Sdfr &size, ret); 976178825Sdfr if (ret) { 977178825Sdfr if (match_oid == &decode_oid) 978178825Sdfr der_free_oid(&decode_oid); 979178825Sdfr hx509_clear_error_string(context); 980178825Sdfr goto next_sigature; 981178825Sdfr } 982233294Sstas if (size != signed_data.length) 983178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 984178825Sdfr 985178825Sdfr } else { 986233294Sstas signed_data.data = content->data; 987233294Sstas signed_data.length = content->length; 988233294Sstas match_oid = &asn1_oid_id_pkcs7_data; 989178825Sdfr } 990178825Sdfr 991233294Sstas /** 992233294Sstas * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow 993233294Sstas * encapContentInfo mismatch with the oid in signedAttributes 994233294Sstas * (or if no signedAttributes where use, pkcs7-data oid). 995233294Sstas * This is only needed to work with broken CMS implementations 996233294Sstas * that doesn't follow CMS signedAttributes rules. 997233294Sstas */ 998233294Sstas 999233294Sstas if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) && 1000233294Sstas (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) { 1001178825Sdfr ret = HX509_CMS_DATA_OID_MISMATCH; 1002178825Sdfr hx509_set_error_string(context, 0, ret, 1003178825Sdfr "Oid in message mismatch from the expected"); 1004178825Sdfr } 1005178825Sdfr if (match_oid == &decode_oid) 1006178825Sdfr der_free_oid(&decode_oid); 1007178825Sdfr 1008178825Sdfr if (ret == 0) { 1009178825Sdfr ret = hx509_verify_signature(context, 1010178825Sdfr cert, 1011178825Sdfr &signer_info->signatureAlgorithm, 1012233294Sstas &signed_data, 1013178825Sdfr &signer_info->signature); 1014178825Sdfr if (ret) 1015178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 1016233294Sstas "Failed to verify signature in " 1017178825Sdfr "CMS SignedData"); 1018178825Sdfr } 1019233294Sstas if (signer_info->signedAttrs) 1020233294Sstas free(signed_data.data); 1021178825Sdfr if (ret) 1022178825Sdfr goto next_sigature; 1023178825Sdfr 1024233294Sstas /** 1025233294Sstas * If HX509_CMS_VS_NO_VALIDATE flags is set, do not verify the 1026233294Sstas * signing certificates and leave that up to the caller. 1027233294Sstas */ 1028178825Sdfr 1029233294Sstas if ((flags & HX509_CMS_VS_NO_VALIDATE) == 0) { 1030233294Sstas ret = hx509_verify_path(context, ctx, cert, certs); 1031233294Sstas if (ret) 1032233294Sstas goto next_sigature; 1033233294Sstas } 1034233294Sstas 1035178825Sdfr ret = hx509_certs_add(context, *signer_certs, cert); 1036178825Sdfr if (ret) 1037178825Sdfr goto next_sigature; 1038178825Sdfr 1039178825Sdfr found_valid_sig++; 1040178825Sdfr 1041178825Sdfr next_sigature: 1042178825Sdfr if (cert) 1043178825Sdfr hx509_cert_free(cert); 1044178825Sdfr cert = NULL; 1045178825Sdfr } 1046233294Sstas /** 1047233294Sstas * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty 1048233294Sstas * SignerInfo (no signatures). If SignedData have no signatures, 1049233294Sstas * the function will return 0 with signer_certs set to NULL. Zero 1050233294Sstas * signers is allowed by the standard, but since its only useful 1051233294Sstas * in corner cases, it make into a flag that the caller have to 1052233294Sstas * turn on. 1053233294Sstas */ 1054233294Sstas if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) { 1055233294Sstas if (*signer_certs) 1056233294Sstas hx509_certs_free(signer_certs); 1057233294Sstas } else if (found_valid_sig == 0) { 1058178825Sdfr if (ret == 0) { 1059178825Sdfr ret = HX509_CMS_SIGNER_NOT_FOUND; 1060178825Sdfr hx509_set_error_string(context, 0, ret, 1061178825Sdfr "No signers where found"); 1062178825Sdfr } 1063178825Sdfr goto out; 1064178825Sdfr } 1065178825Sdfr 1066178825Sdfr ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType); 1067178825Sdfr if (ret) { 1068178825Sdfr hx509_clear_error_string(context); 1069178825Sdfr goto out; 1070178825Sdfr } 1071178825Sdfr 1072178825Sdfrout: 1073178825Sdfr free_SignedData(&sd); 1074178825Sdfr if (certs) 1075178825Sdfr hx509_certs_free(&certs); 1076178825Sdfr if (ret) { 1077233294Sstas if (content->data) 1078233294Sstas der_free_octet_string(content); 1079178825Sdfr if (*signer_certs) 1080178825Sdfr hx509_certs_free(signer_certs); 1081178825Sdfr der_free_oid(contentType); 1082178825Sdfr der_free_octet_string(content); 1083178825Sdfr } 1084178825Sdfr 1085178825Sdfr return ret; 1086178825Sdfr} 1087178825Sdfr 1088178825Sdfrstatic int 1089178825Sdfradd_one_attribute(Attribute **attr, 1090178825Sdfr unsigned int *len, 1091178825Sdfr const heim_oid *oid, 1092178825Sdfr heim_octet_string *data) 1093178825Sdfr{ 1094178825Sdfr void *d; 1095178825Sdfr int ret; 1096178825Sdfr 1097178825Sdfr d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1)); 1098178825Sdfr if (d == NULL) 1099178825Sdfr return ENOMEM; 1100178825Sdfr (*attr) = d; 1101178825Sdfr 1102178825Sdfr ret = der_copy_oid(oid, &(*attr)[*len].type); 1103178825Sdfr if (ret) 1104178825Sdfr return ret; 1105178825Sdfr 1106178825Sdfr ALLOC_SEQ(&(*attr)[*len].value, 1); 1107178825Sdfr if ((*attr)[*len].value.val == NULL) { 1108178825Sdfr der_free_oid(&(*attr)[*len].type); 1109178825Sdfr return ENOMEM; 1110178825Sdfr } 1111178825Sdfr 1112178825Sdfr (*attr)[*len].value.val[0].data = data->data; 1113178825Sdfr (*attr)[*len].value.val[0].length = data->length; 1114178825Sdfr 1115178825Sdfr *len += 1; 1116178825Sdfr 1117178825Sdfr return 0; 1118178825Sdfr} 1119233294Sstas 1120178825Sdfr/** 1121178825Sdfr * Decode SignedData and verify that the signature is correct. 1122178825Sdfr * 1123178825Sdfr * @param context A hx509 context. 1124178825Sdfr * @param flags 1125178825Sdfr * @param eContentType the type of the data. 1126178825Sdfr * @param data data to sign 1127178825Sdfr * @param length length of the data that data point to. 1128178825Sdfr * @param digest_alg digest algorithm to use, use NULL to get the 1129178825Sdfr * default or the peer determined algorithm. 1130178825Sdfr * @param cert certificate to use for sign the data. 1131178825Sdfr * @param peer info about the peer the message to send the message to, 1132178825Sdfr * like what digest algorithm to use. 1133178825Sdfr * @param anchors trust anchors that the client will use, used to 1134178825Sdfr * polulate the certificates included in the message 1135178825Sdfr * @param pool certificates to use in try to build the path to the 1136178825Sdfr * trust anchors. 1137178825Sdfr * @param signed_data the output of the function, free with 1138178825Sdfr * der_free_octet_string(). 1139178825Sdfr * 1140178825Sdfr * @ingroup hx509_cms 1141178825Sdfr */ 1142178825Sdfr 1143178825Sdfrint 1144178825Sdfrhx509_cms_create_signed_1(hx509_context context, 1145178825Sdfr int flags, 1146178825Sdfr const heim_oid *eContentType, 1147178825Sdfr const void *data, size_t length, 1148178825Sdfr const AlgorithmIdentifier *digest_alg, 1149178825Sdfr hx509_cert cert, 1150178825Sdfr hx509_peer_info peer, 1151178825Sdfr hx509_certs anchors, 1152178825Sdfr hx509_certs pool, 1153178825Sdfr heim_octet_string *signed_data) 1154178825Sdfr{ 1155233294Sstas hx509_certs certs; 1156233294Sstas int ret = 0; 1157233294Sstas 1158233294Sstas signed_data->data = NULL; 1159233294Sstas signed_data->length = 0; 1160233294Sstas 1161233294Sstas ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs); 1162233294Sstas if (ret) 1163233294Sstas return ret; 1164233294Sstas ret = hx509_certs_add(context, certs, cert); 1165233294Sstas if (ret) 1166233294Sstas goto out; 1167233294Sstas 1168233294Sstas ret = hx509_cms_create_signed(context, flags, eContentType, data, length, 1169233294Sstas digest_alg, certs, peer, anchors, pool, 1170233294Sstas signed_data); 1171233294Sstas 1172233294Sstas out: 1173233294Sstas hx509_certs_free(&certs); 1174233294Sstas return ret; 1175233294Sstas} 1176233294Sstas 1177233294Sstasstruct sigctx { 1178233294Sstas SignedData sd; 1179233294Sstas const AlgorithmIdentifier *digest_alg; 1180233294Sstas const heim_oid *eContentType; 1181233294Sstas heim_octet_string content; 1182233294Sstas hx509_peer_info peer; 1183233294Sstas int cmsidflag; 1184233294Sstas int leafonly; 1185233294Sstas hx509_certs certs; 1186233294Sstas hx509_certs anchors; 1187233294Sstas hx509_certs pool; 1188233294Sstas}; 1189233294Sstas 1190233294Sstasstatic int 1191233294Sstassig_process(hx509_context context, void *ctx, hx509_cert cert) 1192233294Sstas{ 1193233294Sstas struct sigctx *sigctx = ctx; 1194233294Sstas heim_octet_string buf, sigdata = { 0, NULL }; 1195233294Sstas SignerInfo *signer_info = NULL; 1196178825Sdfr AlgorithmIdentifier digest; 1197233294Sstas size_t size; 1198233294Sstas void *ptr; 1199178825Sdfr int ret; 1200233294Sstas SignedData *sd = &sigctx->sd; 1201178825Sdfr hx509_path path; 1202178825Sdfr 1203233294Sstas memset(&digest, 0, sizeof(digest)); 1204178825Sdfr memset(&path, 0, sizeof(path)); 1205178825Sdfr 1206178825Sdfr if (_hx509_cert_private_key(cert) == NULL) { 1207178825Sdfr hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, 1208178825Sdfr "Private key missing for signing"); 1209178825Sdfr return HX509_PRIVATE_KEY_MISSING; 1210178825Sdfr } 1211178825Sdfr 1212233294Sstas if (sigctx->digest_alg) { 1213233294Sstas ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest); 1214178825Sdfr if (ret) 1215178825Sdfr hx509_clear_error_string(context); 1216233294Sstas } else { 1217233294Sstas ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, 1218233294Sstas _hx509_cert_private_key(cert), 1219233294Sstas sigctx->peer, &digest); 1220178825Sdfr } 1221178825Sdfr if (ret) 1222178825Sdfr goto out; 1223178825Sdfr 1224233294Sstas /* 1225233294Sstas * Allocate on more signerInfo and do the signature processing 1226233294Sstas */ 1227178825Sdfr 1228233294Sstas ptr = realloc(sd->signerInfos.val, 1229233294Sstas (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0])); 1230233294Sstas if (ptr == NULL) { 1231178825Sdfr ret = ENOMEM; 1232178825Sdfr goto out; 1233178825Sdfr } 1234233294Sstas sd->signerInfos.val = ptr; 1235178825Sdfr 1236233294Sstas signer_info = &sd->signerInfos.val[sd->signerInfos.len]; 1237178825Sdfr 1238233294Sstas memset(signer_info, 0, sizeof(*signer_info)); 1239233294Sstas 1240178825Sdfr signer_info->version = 1; 1241178825Sdfr 1242233294Sstas ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid); 1243178825Sdfr if (ret) { 1244178825Sdfr hx509_clear_error_string(context); 1245178825Sdfr goto out; 1246233294Sstas } 1247178825Sdfr 1248178825Sdfr signer_info->signedAttrs = NULL; 1249178825Sdfr signer_info->unsignedAttrs = NULL; 1250178825Sdfr 1251178825Sdfr ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm); 1252178825Sdfr if (ret) { 1253178825Sdfr hx509_clear_error_string(context); 1254178825Sdfr goto out; 1255178825Sdfr } 1256178825Sdfr 1257178825Sdfr /* 1258178825Sdfr * If it isn't pkcs7-data send signedAttributes 1259178825Sdfr */ 1260178825Sdfr 1261233294Sstas if (der_heim_oid_cmp(sigctx->eContentType, &asn1_oid_id_pkcs7_data) != 0) { 1262233294Sstas CMSAttributes sa; 1263178825Sdfr heim_octet_string sig; 1264178825Sdfr 1265178825Sdfr ALLOC(signer_info->signedAttrs, 1); 1266178825Sdfr if (signer_info->signedAttrs == NULL) { 1267178825Sdfr ret = ENOMEM; 1268178825Sdfr goto out; 1269178825Sdfr } 1270178825Sdfr 1271178825Sdfr ret = _hx509_create_signature(context, 1272178825Sdfr NULL, 1273178825Sdfr &digest, 1274233294Sstas &sigctx->content, 1275178825Sdfr NULL, 1276178825Sdfr &sig); 1277178825Sdfr if (ret) 1278178825Sdfr goto out; 1279178825Sdfr 1280178825Sdfr ASN1_MALLOC_ENCODE(MessageDigest, 1281178825Sdfr buf.data, 1282178825Sdfr buf.length, 1283178825Sdfr &sig, 1284178825Sdfr &size, 1285178825Sdfr ret); 1286178825Sdfr der_free_octet_string(&sig); 1287178825Sdfr if (ret) { 1288178825Sdfr hx509_clear_error_string(context); 1289178825Sdfr goto out; 1290178825Sdfr } 1291178825Sdfr if (size != buf.length) 1292178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 1293178825Sdfr 1294178825Sdfr ret = add_one_attribute(&signer_info->signedAttrs->val, 1295178825Sdfr &signer_info->signedAttrs->len, 1296233294Sstas &asn1_oid_id_pkcs9_messageDigest, 1297178825Sdfr &buf); 1298178825Sdfr if (ret) { 1299233294Sstas free(buf.data); 1300178825Sdfr hx509_clear_error_string(context); 1301178825Sdfr goto out; 1302178825Sdfr } 1303178825Sdfr 1304178825Sdfr 1305178825Sdfr ASN1_MALLOC_ENCODE(ContentType, 1306178825Sdfr buf.data, 1307178825Sdfr buf.length, 1308233294Sstas sigctx->eContentType, 1309178825Sdfr &size, 1310178825Sdfr ret); 1311178825Sdfr if (ret) 1312178825Sdfr goto out; 1313178825Sdfr if (size != buf.length) 1314178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 1315178825Sdfr 1316178825Sdfr ret = add_one_attribute(&signer_info->signedAttrs->val, 1317178825Sdfr &signer_info->signedAttrs->len, 1318233294Sstas &asn1_oid_id_pkcs9_contentType, 1319178825Sdfr &buf); 1320178825Sdfr if (ret) { 1321233294Sstas free(buf.data); 1322178825Sdfr hx509_clear_error_string(context); 1323178825Sdfr goto out; 1324178825Sdfr } 1325178825Sdfr 1326178825Sdfr sa.val = signer_info->signedAttrs->val; 1327178825Sdfr sa.len = signer_info->signedAttrs->len; 1328233294Sstas 1329178825Sdfr ASN1_MALLOC_ENCODE(CMSAttributes, 1330178825Sdfr sigdata.data, 1331178825Sdfr sigdata.length, 1332178825Sdfr &sa, 1333178825Sdfr &size, 1334178825Sdfr ret); 1335178825Sdfr if (ret) { 1336178825Sdfr hx509_clear_error_string(context); 1337178825Sdfr goto out; 1338178825Sdfr } 1339178825Sdfr if (size != sigdata.length) 1340178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 1341178825Sdfr } else { 1342233294Sstas sigdata.data = sigctx->content.data; 1343233294Sstas sigdata.length = sigctx->content.length; 1344178825Sdfr } 1345178825Sdfr 1346178825Sdfr { 1347178825Sdfr AlgorithmIdentifier sigalg; 1348178825Sdfr 1349178825Sdfr ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG, 1350233294Sstas _hx509_cert_private_key(cert), sigctx->peer, 1351178825Sdfr &sigalg); 1352178825Sdfr if (ret) 1353178825Sdfr goto out; 1354178825Sdfr 1355178825Sdfr ret = _hx509_create_signature(context, 1356178825Sdfr _hx509_cert_private_key(cert), 1357178825Sdfr &sigalg, 1358178825Sdfr &sigdata, 1359178825Sdfr &signer_info->signatureAlgorithm, 1360178825Sdfr &signer_info->signature); 1361178825Sdfr free_AlgorithmIdentifier(&sigalg); 1362178825Sdfr if (ret) 1363178825Sdfr goto out; 1364178825Sdfr } 1365178825Sdfr 1366233294Sstas sigctx->sd.signerInfos.len++; 1367233294Sstas signer_info = NULL; 1368178825Sdfr 1369178825Sdfr /* 1370178825Sdfr * Provide best effort path 1371178825Sdfr */ 1372233294Sstas if (sigctx->certs) { 1373233294Sstas unsigned int i; 1374178825Sdfr 1375233294Sstas if (sigctx->pool && sigctx->leafonly == 0) { 1376233294Sstas _hx509_calculate_path(context, 1377233294Sstas HX509_CALCULATE_PATH_NO_ANCHOR, 1378233294Sstas time(NULL), 1379233294Sstas sigctx->anchors, 1380233294Sstas 0, 1381233294Sstas cert, 1382233294Sstas sigctx->pool, 1383233294Sstas &path); 1384233294Sstas } else 1385233294Sstas _hx509_path_append(context, &path, cert); 1386178825Sdfr 1387233294Sstas for (i = 0; i < path.len; i++) { 1388233294Sstas /* XXX remove dups */ 1389233294Sstas ret = hx509_certs_add(context, sigctx->certs, path.val[i]); 1390233294Sstas if (ret) { 1391233294Sstas hx509_clear_error_string(context); 1392233294Sstas goto out; 1393233294Sstas } 1394233294Sstas } 1395233294Sstas } 1396178825Sdfr 1397233294Sstas out: 1398233294Sstas if (signer_info) 1399233294Sstas free_SignerInfo(signer_info); 1400233294Sstas if (sigdata.data != sigctx->content.data) 1401233294Sstas der_free_octet_string(&sigdata); 1402233294Sstas _hx509_path_free(&path); 1403233294Sstas free_AlgorithmIdentifier(&digest); 1404233294Sstas 1405233294Sstas return ret; 1406233294Sstas} 1407233294Sstas 1408233294Sstasstatic int 1409233294Sstascert_process(hx509_context context, void *ctx, hx509_cert cert) 1410233294Sstas{ 1411233294Sstas struct sigctx *sigctx = ctx; 1412233294Sstas const unsigned int i = sigctx->sd.certificates->len; 1413233294Sstas void *ptr; 1414233294Sstas int ret; 1415233294Sstas 1416233294Sstas ptr = realloc(sigctx->sd.certificates->val, 1417233294Sstas (i + 1) * sizeof(sigctx->sd.certificates->val[0])); 1418233294Sstas if (ptr == NULL) 1419233294Sstas return ENOMEM; 1420233294Sstas sigctx->sd.certificates->val = ptr; 1421233294Sstas 1422233294Sstas ret = hx509_cert_binary(context, cert, 1423233294Sstas &sigctx->sd.certificates->val[i]); 1424233294Sstas if (ret == 0) 1425233294Sstas sigctx->sd.certificates->len++; 1426233294Sstas 1427233294Sstas return ret; 1428233294Sstas} 1429233294Sstas 1430233294Sstasstatic int 1431233294Sstascmp_AlgorithmIdentifier(const AlgorithmIdentifier *p, const AlgorithmIdentifier *q) 1432233294Sstas{ 1433233294Sstas return der_heim_oid_cmp(&p->algorithm, &q->algorithm); 1434233294Sstas} 1435233294Sstas 1436233294Sstasint 1437233294Sstashx509_cms_create_signed(hx509_context context, 1438233294Sstas int flags, 1439233294Sstas const heim_oid *eContentType, 1440233294Sstas const void *data, size_t length, 1441233294Sstas const AlgorithmIdentifier *digest_alg, 1442233294Sstas hx509_certs certs, 1443233294Sstas hx509_peer_info peer, 1444233294Sstas hx509_certs anchors, 1445233294Sstas hx509_certs pool, 1446233294Sstas heim_octet_string *signed_data) 1447233294Sstas{ 1448233294Sstas unsigned int i, j; 1449233294Sstas hx509_name name; 1450233294Sstas int ret; 1451233294Sstas size_t size; 1452233294Sstas struct sigctx sigctx; 1453233294Sstas 1454233294Sstas memset(&sigctx, 0, sizeof(sigctx)); 1455233294Sstas memset(&name, 0, sizeof(name)); 1456233294Sstas 1457233294Sstas if (eContentType == NULL) 1458233294Sstas eContentType = &asn1_oid_id_pkcs7_data; 1459233294Sstas 1460233294Sstas sigctx.digest_alg = digest_alg; 1461233294Sstas sigctx.content.data = rk_UNCONST(data); 1462233294Sstas sigctx.content.length = length; 1463233294Sstas sigctx.eContentType = eContentType; 1464233294Sstas sigctx.peer = peer; 1465233294Sstas /** 1466233294Sstas * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name 1467233294Sstas * and serial number if possible. Otherwise subject key identifier 1468233294Sstas * will preferred. 1469233294Sstas */ 1470233294Sstas if (flags & HX509_CMS_SIGNATURE_ID_NAME) 1471233294Sstas sigctx.cmsidflag = CMS_ID_NAME; 1472233294Sstas else 1473233294Sstas sigctx.cmsidflag = CMS_ID_SKI; 1474233294Sstas 1475233294Sstas /** 1476233294Sstas * Use HX509_CMS_SIGNATURE_LEAF_ONLY to only request leaf 1477233294Sstas * certificates to be added to the SignedData. 1478233294Sstas */ 1479233294Sstas sigctx.leafonly = (flags & HX509_CMS_SIGNATURE_LEAF_ONLY) ? 1 : 0; 1480233294Sstas 1481233294Sstas /** 1482233294Sstas * Use HX509_CMS_NO_CERTS to make the SignedData contain no 1483233294Sstas * certificates, overrides HX509_CMS_SIGNATURE_LEAF_ONLY. 1484233294Sstas */ 1485233294Sstas 1486233294Sstas if ((flags & HX509_CMS_SIGNATURE_NO_CERTS) == 0) { 1487233294Sstas ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs); 1488233294Sstas if (ret) 1489233294Sstas return ret; 1490233294Sstas } 1491233294Sstas 1492233294Sstas sigctx.anchors = anchors; 1493233294Sstas sigctx.pool = pool; 1494233294Sstas 1495233294Sstas sigctx.sd.version = CMSVersion_v3; 1496233294Sstas 1497233294Sstas der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType); 1498233294Sstas 1499233294Sstas /** 1500233294Sstas * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures. 1501233294Sstas */ 1502233294Sstas if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) { 1503233294Sstas ALLOC(sigctx.sd.encapContentInfo.eContent, 1); 1504233294Sstas if (sigctx.sd.encapContentInfo.eContent == NULL) { 1505178825Sdfr hx509_clear_error_string(context); 1506178825Sdfr ret = ENOMEM; 1507178825Sdfr goto out; 1508178825Sdfr } 1509233294Sstas 1510233294Sstas sigctx.sd.encapContentInfo.eContent->data = malloc(length); 1511233294Sstas if (sigctx.sd.encapContentInfo.eContent->data == NULL) { 1512178825Sdfr hx509_clear_error_string(context); 1513178825Sdfr ret = ENOMEM; 1514178825Sdfr goto out; 1515178825Sdfr } 1516233294Sstas memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length); 1517233294Sstas sigctx.sd.encapContentInfo.eContent->length = length; 1518233294Sstas } 1519178825Sdfr 1520233294Sstas /** 1521233294Sstas * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no 1522233294Sstas * signatures). 1523233294Sstas */ 1524233294Sstas if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) { 1525233294Sstas ret = hx509_certs_iter_f(context, certs, sig_process, &sigctx); 1526233294Sstas if (ret) 1527233294Sstas goto out; 1528233294Sstas } 1529233294Sstas 1530233294Sstas if (sigctx.sd.signerInfos.len) { 1531233294Sstas 1532233294Sstas /* 1533233294Sstas * For each signerInfo, collect all different digest types. 1534233294Sstas */ 1535233294Sstas for (i = 0; i < sigctx.sd.signerInfos.len; i++) { 1536233294Sstas AlgorithmIdentifier *di = 1537233294Sstas &sigctx.sd.signerInfos.val[i].digestAlgorithm; 1538233294Sstas 1539233294Sstas for (j = 0; j < sigctx.sd.digestAlgorithms.len; j++) 1540233294Sstas if (cmp_AlgorithmIdentifier(di, &sigctx.sd.digestAlgorithms.val[j]) == 0) 1541233294Sstas break; 1542233294Sstas if (j == sigctx.sd.digestAlgorithms.len) { 1543233294Sstas ret = add_DigestAlgorithmIdentifiers(&sigctx.sd.digestAlgorithms, di); 1544233294Sstas if (ret) { 1545233294Sstas hx509_clear_error_string(context); 1546233294Sstas goto out; 1547233294Sstas } 1548178825Sdfr } 1549178825Sdfr } 1550178825Sdfr } 1551178825Sdfr 1552233294Sstas /* 1553233294Sstas * Add certs we think are needed, build as part of sig_process 1554233294Sstas */ 1555233294Sstas if (sigctx.certs) { 1556233294Sstas ALLOC(sigctx.sd.certificates, 1); 1557233294Sstas if (sigctx.sd.certificates == NULL) { 1558233294Sstas hx509_clear_error_string(context); 1559233294Sstas ret = ENOMEM; 1560233294Sstas goto out; 1561233294Sstas } 1562233294Sstas 1563233294Sstas ret = hx509_certs_iter_f(context, sigctx.certs, cert_process, &sigctx); 1564233294Sstas if (ret) 1565233294Sstas goto out; 1566233294Sstas } 1567233294Sstas 1568178825Sdfr ASN1_MALLOC_ENCODE(SignedData, 1569178825Sdfr signed_data->data, signed_data->length, 1570233294Sstas &sigctx.sd, &size, ret); 1571178825Sdfr if (ret) { 1572178825Sdfr hx509_clear_error_string(context); 1573178825Sdfr goto out; 1574178825Sdfr } 1575178825Sdfr if (signed_data->length != size) 1576178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 1577178825Sdfr 1578178825Sdfrout: 1579233294Sstas hx509_certs_free(&sigctx.certs); 1580233294Sstas free_SignedData(&sigctx.sd); 1581178825Sdfr 1582178825Sdfr return ret; 1583178825Sdfr} 1584178825Sdfr 1585178825Sdfrint 1586178825Sdfrhx509_cms_decrypt_encrypted(hx509_context context, 1587178825Sdfr hx509_lock lock, 1588178825Sdfr const void *data, 1589178825Sdfr size_t length, 1590178825Sdfr heim_oid *contentType, 1591178825Sdfr heim_octet_string *content) 1592178825Sdfr{ 1593178825Sdfr heim_octet_string cont; 1594178825Sdfr CMSEncryptedData ed; 1595178825Sdfr AlgorithmIdentifier *ai; 1596178825Sdfr int ret; 1597178825Sdfr 1598178825Sdfr memset(content, 0, sizeof(*content)); 1599178825Sdfr memset(&cont, 0, sizeof(cont)); 1600178825Sdfr 1601178825Sdfr ret = decode_CMSEncryptedData(data, length, &ed, NULL); 1602178825Sdfr if (ret) { 1603178825Sdfr hx509_set_error_string(context, 0, ret, 1604178825Sdfr "Failed to decode CMSEncryptedData"); 1605178825Sdfr return ret; 1606178825Sdfr } 1607178825Sdfr 1608178825Sdfr if (ed.encryptedContentInfo.encryptedContent == NULL) { 1609178825Sdfr ret = HX509_CMS_NO_DATA_AVAILABLE; 1610178825Sdfr hx509_set_error_string(context, 0, ret, 1611178825Sdfr "No content in EncryptedData"); 1612178825Sdfr goto out; 1613178825Sdfr } 1614178825Sdfr 1615178825Sdfr ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType); 1616178825Sdfr if (ret) { 1617178825Sdfr hx509_clear_error_string(context); 1618178825Sdfr goto out; 1619178825Sdfr } 1620178825Sdfr 1621178825Sdfr ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm; 1622178825Sdfr if (ai->parameters == NULL) { 1623178825Sdfr ret = HX509_ALG_NOT_SUPP; 1624178825Sdfr hx509_clear_error_string(context); 1625178825Sdfr goto out; 1626178825Sdfr } 1627178825Sdfr 1628178825Sdfr ret = _hx509_pbe_decrypt(context, 1629178825Sdfr lock, 1630178825Sdfr ai, 1631178825Sdfr ed.encryptedContentInfo.encryptedContent, 1632178825Sdfr &cont); 1633178825Sdfr if (ret) 1634178825Sdfr goto out; 1635178825Sdfr 1636178825Sdfr *content = cont; 1637178825Sdfr 1638178825Sdfrout: 1639178825Sdfr if (ret) { 1640178825Sdfr if (cont.data) 1641178825Sdfr free(cont.data); 1642178825Sdfr } 1643178825Sdfr free_CMSEncryptedData(&ed); 1644178825Sdfr return ret; 1645178825Sdfr} 1646