LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hx509 - cms.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 386 821 47.0 %
Date: 2024-05-31 13:13:24 Functions: 14 18 77.8 %

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

Generated by: LCOV version 1.14