LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hx509 - cms.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 70 743 9.4 %
Date: 2024-06-13 04:01:37 Functions: 3 18 16.7 %

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

Generated by: LCOV version 1.13