LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hx509 - ks_file.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 107 363 29.5 %
Date: 2024-04-21 15:09:00 Functions: 10 20 50.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2005 - 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             : #ifndef WIN32
      36             : #include <libgen.h>
      37             : #endif
      38             : 
      39             : typedef enum { USE_PEM, USE_DER } outformat;
      40             : 
      41             : struct ks_file {
      42             :     hx509_certs certs;
      43             :     char *fn;
      44             :     outformat format;
      45             : };
      46             : 
      47             : /*
      48             :  *
      49             :  */
      50             : 
      51             : static int
      52         249 : parse_certificate(hx509_context context, const char *fn, int flags,
      53             :                   struct hx509_collector *c,
      54             :                   const hx509_pem_header *headers,
      55             :                   const void *data, size_t len,
      56             :                   const AlgorithmIdentifier *ai)
      57             : {
      58         249 :     heim_error_t error = NULL;
      59          16 :     hx509_cert cert;
      60          16 :     int ret;
      61             : 
      62         249 :     cert = hx509_cert_init_data(context, data, len, &error);
      63         249 :     if (cert == NULL) {
      64           0 :         ret = heim_error_get_code(error);
      65           0 :         heim_release(error);
      66           0 :         return ret;
      67             :     }
      68             : 
      69         249 :     ret = _hx509_collector_certs_add(context, c, cert);
      70         249 :     hx509_cert_free(cert);
      71         249 :     return ret;
      72             : }
      73             : 
      74             : static int
      75           0 : try_decrypt(hx509_context context,
      76             :             struct hx509_collector *collector,
      77             :             int flags,
      78             :             const AlgorithmIdentifier *alg,
      79             :             const EVP_CIPHER *c,
      80             :             const void *ivdata,
      81             :             const void *password,
      82             :             size_t passwordlen,
      83             :             const void *cipher,
      84             :             size_t len)
      85             : {
      86           0 :     heim_octet_string clear;
      87           0 :     size_t keylen;
      88           0 :     void *key;
      89           0 :     int ret;
      90             : 
      91           0 :     keylen = EVP_CIPHER_key_length(c);
      92             : 
      93           0 :     key = malloc(keylen);
      94           0 :     if (key == NULL) {
      95           0 :         hx509_clear_error_string(context);
      96           0 :         return ENOMEM;
      97             :     }
      98             : 
      99           0 :     ret = EVP_BytesToKey(c, EVP_md5(), ivdata,
     100             :                          password, passwordlen,
     101             :                          1, key, NULL);
     102           0 :     if (ret <= 0) {
     103           0 :         ret = HX509_CRYPTO_INTERNAL_ERROR;
     104           0 :         hx509_set_error_string(context, 0, ret,
     105             :                                "Failed to do string2key for private key");
     106           0 :         goto out;
     107             :     }
     108             : 
     109           0 :     clear.data = malloc(len);
     110           0 :     if (clear.data == NULL) {
     111           0 :         hx509_set_error_string(context, 0, ENOMEM,
     112             :                                "Out of memory to decrypt for private key");
     113           0 :         ret = ENOMEM;
     114           0 :         goto out;
     115             :     }
     116           0 :     clear.length = len;
     117             : 
     118             :     {
     119           0 :         EVP_CIPHER_CTX ctx;
     120           0 :         EVP_CIPHER_CTX_init(&ctx);
     121           0 :         EVP_CipherInit_ex(&ctx, c, NULL, key, ivdata, 0);
     122           0 :         EVP_Cipher(&ctx, clear.data, cipher, len);
     123           0 :         EVP_CIPHER_CTX_cleanup(&ctx);
     124             :     }
     125             : 
     126           0 :     if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS))
     127           0 :         ret = _hx509_collector_private_key_add(context, collector, alg, NULL,
     128             :                                                &clear, NULL);
     129             : 
     130           0 :     memset_s(clear.data, clear.length, 0, clear.length);
     131           0 :     free(clear.data);
     132           0 : out:
     133           0 :     memset_s(key, keylen, 0, keylen);
     134           0 :     free(key);
     135           0 :     return ret;
     136             : }
     137             : 
     138             : static int
     139           0 : parse_pkcs8_private_key(hx509_context context, const char *fn, int flags,
     140             :                         struct hx509_collector *c,
     141             :                         const hx509_pem_header *headers,
     142             :                         const void *data, size_t length,
     143             :                         const AlgorithmIdentifier *ai)
     144             : {
     145           0 :     PKCS8PrivateKeyInfo ki;
     146           0 :     heim_octet_string keydata;
     147           0 :     int ret;
     148             : 
     149           0 :     ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
     150           0 :     if (ret)
     151           0 :         return ret;
     152             : 
     153           0 :     if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) {
     154           0 :         keydata.data = rk_UNCONST(data);
     155           0 :         keydata.length = length;
     156           0 :         ret = _hx509_collector_private_key_add(context,
     157             :                                                c,
     158             :                                                &ki.privateKeyAlgorithm,
     159             :                                                NULL,
     160             :                                                &ki.privateKey,
     161             :                                                &keydata);
     162             :     }
     163           0 :     free_PKCS8PrivateKeyInfo(&ki);
     164           0 :     return ret;
     165             : }
     166             : 
     167             : static int
     168          74 : parse_pem_private_key(hx509_context context, const char *fn, int flags,
     169             :                       struct hx509_collector *c,
     170             :                       const hx509_pem_header *headers,
     171             :                       const void *data, size_t len,
     172             :                       const AlgorithmIdentifier *ai)
     173             : {
     174          74 :     int ret = 0;
     175           8 :     const char *enc;
     176             : 
     177          74 :     enc = hx509_pem_find_header(headers, "Proc-Type");
     178          74 :     if (enc) {
     179           0 :         const char *dek;
     180           0 :         char *type, *iv;
     181           0 :         ssize_t ssize, size;
     182           0 :         void *ivdata;
     183           0 :         const EVP_CIPHER *cipher;
     184           0 :         const struct _hx509_password *pw;
     185           0 :         hx509_lock lock;
     186           0 :         int decrypted = 0;
     187           0 :         size_t i;
     188             : 
     189           0 :         lock = _hx509_collector_get_lock(c);
     190           0 :         if (lock == NULL) {
     191           0 :             hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
     192             :                                    "Failed to get password for "
     193             :                                    "password protected file %s", fn);
     194           0 :             return HX509_ALG_NOT_SUPP;
     195             :         }
     196             : 
     197           0 :         if (strcmp(enc, "4,ENCRYPTED") != 0) {
     198           0 :             hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
     199             :                                    "Private key encrypted in unknown method %s "
     200             :                                    "in file %s",
     201             :                                    enc, fn);
     202           0 :             hx509_clear_error_string(context);
     203           0 :             return HX509_PARSING_KEY_FAILED;
     204             :         }
     205             : 
     206           0 :         dek = hx509_pem_find_header(headers, "DEK-Info");
     207           0 :         if (dek == NULL) {
     208           0 :             hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
     209             :                                    "Encrypted private key missing DEK-Info");
     210           0 :             return HX509_PARSING_KEY_FAILED;
     211             :         }
     212             : 
     213           0 :         type = strdup(dek);
     214           0 :         if (type == NULL) {
     215           0 :             hx509_clear_error_string(context);
     216           0 :             return ENOMEM;
     217             :         }
     218             : 
     219           0 :         iv = strchr(type, ',');
     220           0 :         if (iv == NULL) {
     221           0 :             free(type);
     222           0 :             hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
     223             :                                    "IV missing");
     224           0 :             return HX509_PARSING_KEY_FAILED;
     225             :         }
     226             : 
     227           0 :         *iv++ = '\0';
     228             : 
     229           0 :         size = strlen(iv);
     230           0 :         ivdata = malloc(size);
     231           0 :         if (ivdata == NULL) {
     232           0 :             hx509_clear_error_string(context);
     233           0 :             free(type);
     234           0 :             return ENOMEM;
     235             :         }
     236             : 
     237           0 :         cipher = EVP_get_cipherbyname(type);
     238           0 :         if (cipher == NULL) {
     239           0 :             free(ivdata);
     240           0 :             hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
     241             :                                    "Private key encrypted with "
     242             :                                    "unsupported cipher: %s",
     243             :                                    type);
     244           0 :             free(type);
     245           0 :             return HX509_ALG_NOT_SUPP;
     246             :         }
     247             : 
     248             : #define PKCS5_SALT_LEN 8
     249             : 
     250           0 :         ssize = hex_decode(iv, ivdata, size);
     251           0 :         free(type);
     252           0 :         type = NULL;
     253           0 :         iv = NULL;
     254             : 
     255           0 :         if (ssize < 0 || ssize < PKCS5_SALT_LEN || ssize < EVP_CIPHER_iv_length(cipher)) {
     256           0 :             free(ivdata);
     257           0 :             hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
     258             :                                    "Salt have wrong length in "
     259             :                                    "private key file");
     260           0 :             return HX509_PARSING_KEY_FAILED;
     261             :         }
     262             : 
     263           0 :         pw = _hx509_lock_get_passwords(lock);
     264           0 :         if (pw != NULL) {
     265             :             const void *password;
     266             :             size_t passwordlen;
     267             : 
     268           0 :             for (i = 0; i < pw->len; i++) {
     269           0 :                 password = pw->val[i];
     270           0 :                 passwordlen = strlen(password);
     271             : 
     272           0 :                 ret = try_decrypt(context, c, flags, ai, cipher, ivdata,
     273             :                                   password, passwordlen, data, len);
     274           0 :                 if (ret == 0) {
     275           0 :                     decrypted = 1;
     276           0 :                     break;
     277             :                 }
     278             :             }
     279             :         }
     280           0 :         if (!decrypted) {
     281           0 :             hx509_prompt prompt;
     282           0 :             char password[128];
     283             : 
     284           0 :             memset(&prompt, 0, sizeof(prompt));
     285             : 
     286           0 :             prompt.prompt = "Password for keyfile: ";
     287           0 :             prompt.type = HX509_PROMPT_TYPE_PASSWORD;
     288           0 :             prompt.reply.data = password;
     289           0 :             prompt.reply.length = sizeof(password);
     290             : 
     291           0 :             ret = hx509_lock_prompt(lock, &prompt);
     292           0 :             if (ret == 0)
     293           0 :                 ret = try_decrypt(context, c, flags, ai, cipher, ivdata,
     294             :                                   password, strlen(password), data, len);
     295             :             /* XXX add password to lock password collection ? */
     296           0 :             memset_s(password, sizeof(password), 0, sizeof(password));
     297             :         }
     298           0 :         free(ivdata);
     299             : 
     300          74 :     } else if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) {
     301           8 :         heim_octet_string keydata;
     302             : 
     303          74 :         keydata.data = rk_UNCONST(data);
     304          74 :         keydata.length = len;
     305             : 
     306          74 :         ret = _hx509_collector_private_key_add(context, c, ai, NULL,
     307             :                                                &keydata, NULL);
     308             :     }
     309             : 
     310          66 :     return ret;
     311             : }
     312             : 
     313             : 
     314             : struct pem_formats {
     315             :     const char *name;
     316             :     int (*func)(hx509_context, const char *, int, struct hx509_collector *,
     317             :                 const hx509_pem_header *, const void *, size_t,
     318             :                 const AlgorithmIdentifier *);
     319             :     const AlgorithmIdentifier *(*ai)(void);
     320             : } formats[] = {
     321             :     { "CERTIFICATE", parse_certificate, NULL },
     322             :     { "PRIVATE KEY", parse_pkcs8_private_key, NULL },
     323             :     { "RSA PRIVATE KEY", parse_pem_private_key, hx509_signature_rsa },
     324             : #ifdef HAVE_HCRYPTO_W_OPENSSL
     325             :     { "EC PRIVATE KEY", parse_pem_private_key, hx509_signature_ecPublicKey }
     326             : #endif
     327             : };
     328             : 
     329             : 
     330             : struct pem_ctx {
     331             :     int flags;
     332             :     struct hx509_collector *c;
     333             : };
     334             : 
     335             : static int
     336         323 : pem_func(hx509_context context, const char *type,
     337             :          const hx509_pem_header *header,
     338             :          const void *data, size_t len, void *ctx)
     339             : {
     340         323 :     struct pem_ctx *pem_ctx = (struct pem_ctx*)ctx;
     341         323 :     int ret = 0;
     342          24 :     size_t j;
     343             : 
     344         471 :     for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) {
     345         471 :         const char *q = formats[j].name;
     346         471 :         if (strcasecmp(type, q) == 0) {
     347         323 :             const AlgorithmIdentifier *ai = NULL;
     348             : 
     349         323 :             if (formats[j].ai != NULL)
     350          74 :                 ai = (*formats[j].ai)();
     351             : 
     352         323 :             ret = (*formats[j].func)(context, NULL, pem_ctx->flags, pem_ctx->c,
     353             :                                      header, data, len, ai);
     354         323 :             if (ret && (pem_ctx->flags & HX509_CERTS_UNPROTECT_ALL)) {
     355           0 :                 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     356             :                                        "Failed parseing PEM format %s", type);
     357           0 :                 return ret;
     358             :             }
     359         299 :             break;
     360             :         }
     361             :     }
     362         323 :     if (j == sizeof(formats)/sizeof(formats[0])) {
     363           0 :         ret = HX509_UNSUPPORTED_OPERATION;
     364           0 :         hx509_set_error_string(context, 0, ret,
     365             :                                "Found no matching PEM format for %s", type);
     366           0 :         return ret;
     367             :     }
     368         299 :     return 0;
     369             : }
     370             : 
     371             : /*
     372             :  *
     373             :  */
     374             : 
     375             : static int
     376         288 : file_init_common(hx509_context context,
     377             :                  hx509_certs certs, void **data, int flags,
     378             :                  const char *residue, hx509_lock lock, outformat format)
     379             : {
     380          16 :     char *p, *pnext;
     381         288 :     struct ks_file *ksf = NULL;
     382         288 :     hx509_private_key *keys = NULL;
     383          16 :     int ret;
     384          16 :     struct pem_ctx pem_ctx;
     385             : 
     386         288 :     pem_ctx.flags = flags;
     387         288 :     pem_ctx.c = NULL;
     388             : 
     389         288 :     if (residue == NULL || residue[0] == '\0') {
     390           0 :         hx509_set_error_string(context, 0, EINVAL,
     391             :                                "PEM file name not specified");
     392           0 :         return EINVAL;
     393             :     }
     394             : 
     395         288 :     *data = NULL;
     396             : 
     397         288 :     if (lock == NULL)
     398         175 :         lock = _hx509_empty_lock;
     399             : 
     400         288 :     ksf = calloc(1, sizeof(*ksf));
     401         288 :     if (ksf == NULL) {
     402           0 :         hx509_clear_error_string(context);
     403           0 :         return ENOMEM;
     404             :     }
     405         288 :     ksf->format = format;
     406             : 
     407         288 :     ksf->fn = strdup(residue);
     408         288 :     if (ksf->fn == NULL) {
     409           0 :         hx509_clear_error_string(context);
     410           0 :         ret = ENOMEM;
     411           0 :         goto out;
     412             :     }
     413             : 
     414             :     /*
     415             :      * XXX this is broken, the function should parse the file before
     416             :      * overwriting it
     417             :      */
     418             : 
     419         288 :     if (flags & HX509_CERTS_CREATE) {
     420             :         /*
     421             :          * Note that the file creation is deferred until file_store() is
     422             :          * called.
     423             :          */
     424           0 :         ret = hx509_certs_init(context, "MEMORY:ks-file-create",
     425             :                                0, lock, &ksf->certs);
     426           0 :         if (ret)
     427           0 :             goto out;
     428           0 :         *data = ksf;
     429           0 :         return 0;
     430             :     }
     431             : 
     432         288 :     ret = _hx509_collector_alloc(context, lock, &pem_ctx.c);
     433         288 :     if (ret)
     434           0 :         goto out;
     435             : 
     436         611 :     for (p = ksf->fn; p != NULL; p = pnext) {
     437          24 :         FILE *f;
     438             : 
     439         362 :         pnext = strchr(p, ',');
     440         362 :         if (pnext)
     441         113 :             *pnext++ = '\0';
     442             : 
     443             : 
     444         362 :         if ((f = fopen(p, "r")) == NULL) {
     445          39 :             ret = ENOENT;
     446          39 :             hx509_set_error_string(context, 0, ret,
     447             :                                    "Failed to open PEM file \"%s\": %s",
     448          39 :                                    p, strerror(errno));
     449          39 :             goto out;
     450             :         }
     451         323 :         rk_cloexec_file(f);
     452             : 
     453         323 :         ret = hx509_pem_read(context, f, pem_func, &pem_ctx);
     454         323 :         fclose(f);
     455         323 :         if (ret != 0 && ret != HX509_PARSING_KEY_FAILED)
     456           0 :             goto out;
     457         323 :         else if (ret == HX509_PARSING_KEY_FAILED) {
     458           0 :             size_t length;
     459           0 :             void *ptr;
     460           0 :             size_t i;
     461             : 
     462           0 :             ret = rk_undumpdata(p, &ptr, &length);
     463           0 :             if (ret) {
     464           0 :                 hx509_clear_error_string(context);
     465           0 :                 goto out;
     466             :             }
     467             : 
     468           0 :             for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
     469           0 :                 const AlgorithmIdentifier *ai = NULL;
     470             : 
     471           0 :                 if (formats[i].ai != NULL)
     472           0 :                     ai = (*formats[i].ai)();
     473             : 
     474           0 :                 ret = (*formats[i].func)(context, p, pem_ctx.flags, pem_ctx.c,
     475             :                                          NULL, ptr, length, ai);
     476           0 :                 if (ret == 0)
     477           0 :                     break;
     478             :             }
     479           0 :             rk_xfree(ptr);
     480           0 :             if (ret) {
     481           0 :                 hx509_clear_error_string(context);
     482           0 :                 goto out;
     483             :             }
     484             :         }
     485             :     }
     486             : 
     487         249 :     ret = _hx509_collector_collect_certs(context, pem_ctx.c, &ksf->certs);
     488         249 :     if (ret)
     489           0 :         goto out;
     490             : 
     491         249 :     ret = _hx509_collector_collect_private_keys(context, pem_ctx.c, &keys);
     492         249 :     if (ret == 0) {
     493             :         int i;
     494             : 
     495         323 :         for (i = 0; keys[i]; i++)
     496          74 :             _hx509_certs_keys_add(context, ksf->certs, keys[i]);
     497         249 :         _hx509_certs_keys_free(context, keys);
     498             :     }
     499             : 
     500           0 : out:
     501         288 :     if (ret == 0)
     502         249 :         *data = ksf;
     503             :     else {
     504          39 :         if (ksf->fn)
     505          39 :             free(ksf->fn);
     506          39 :         free(ksf);
     507             :     }
     508         288 :     if (pem_ctx.c)
     509         288 :         _hx509_collector_free(pem_ctx.c);
     510             : 
     511         272 :     return ret;
     512             : }
     513             : 
     514             : static int
     515         288 : file_init_pem(hx509_context context,
     516             :               hx509_certs certs, void **data, int flags,
     517             :               const char *residue, hx509_lock lock)
     518             : {
     519         288 :     return file_init_common(context, certs, data, flags, residue, lock, USE_PEM);
     520             : }
     521             : 
     522             : static int
     523           0 : file_init_der(hx509_context context,
     524             :               hx509_certs certs, void **data, int flags,
     525             :               const char *residue, hx509_lock lock)
     526             : {
     527           0 :     return file_init_common(context, certs, data, flags, residue, lock, USE_DER);
     528             : }
     529             : 
     530             : static int
     531         141 : file_free(hx509_certs certs, void *data)
     532             : {
     533         141 :     struct ks_file *ksf = data;
     534         141 :     hx509_certs_free(&ksf->certs);
     535         141 :     free(ksf->fn);
     536         141 :     free(ksf);
     537         141 :     return 0;
     538             : }
     539             : 
     540             : struct store_ctx {
     541             :     FILE *f;
     542             :     outformat format;
     543             :     int store_flags;
     544             : };
     545             : 
     546             : static int HX509_LIB_CALL
     547           0 : store_func(hx509_context context, void *ctx, hx509_cert c)
     548             : {
     549           0 :     struct store_ctx *sc = ctx;
     550           0 :     heim_octet_string data;
     551           0 :     int ret = 0;
     552             : 
     553           0 :     if ((sc->store_flags & HX509_CERTS_STORE_NO_ROOTS)) {
     554           0 :         int self_signed = 0;
     555             : 
     556           0 :         ret = hx509_cert_is_self_signed(context, c, &self_signed);
     557           0 :         if (ret || self_signed)
     558           0 :             return ret;
     559             :     }
     560             : 
     561           0 :     if (hx509_cert_have_private_key_only(c)) {
     562           0 :         data.length = 0;
     563           0 :         data.data = NULL;
     564             :     } else {
     565           0 :         ret = hx509_cert_binary(context, c, &data);
     566           0 :         if (ret)
     567           0 :             return ret;
     568             :     }
     569             : 
     570           0 :     switch (sc->format) {
     571           0 :     case USE_DER:
     572             :         /* Can't store both.  Well, we could, but nothing will support it */
     573           0 :         if (data.data) {
     574           0 :             fwrite(data.data, data.length, 1, sc->f);
     575           0 :         } else if (_hx509_cert_private_key_exportable(c) &&
     576           0 :                    !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) {
     577           0 :             hx509_private_key key = _hx509_cert_private_key(c);
     578             : 
     579           0 :             free(data.data);
     580           0 :             data.length = 0;
     581           0 :             data.data = NULL;
     582           0 :             ret = _hx509_private_key_export(context, key,
     583             :                                             HX509_KEY_FORMAT_DER, &data);
     584           0 :             if (ret == 0 && data.length)
     585           0 :                 fwrite(data.data, data.length, 1, sc->f);
     586             :         }
     587           0 :         break;
     588           0 :     case USE_PEM:
     589           0 :         if (_hx509_cert_private_key_exportable(c) &&
     590           0 :             !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) {
     591           0 :             heim_octet_string priv_key;
     592           0 :             hx509_private_key key = _hx509_cert_private_key(c);
     593             : 
     594           0 :             ret = _hx509_private_key_export(context, key,
     595             :                                             HX509_KEY_FORMAT_DER, &priv_key);
     596           0 :             if (ret == 0)
     597           0 :                 ret = hx509_pem_write(context, _hx509_private_pem_name(key), NULL,
     598           0 :                                       sc->f, priv_key.data, priv_key.length);
     599           0 :             free(priv_key.data);
     600             :         }
     601           0 :         if (ret == 0 && data.data) {
     602           0 :             ret = hx509_pem_write(context, "CERTIFICATE", NULL, sc->f,
     603           0 :                                   data.data, data.length);
     604             :         }
     605           0 :         break;
     606             :     }
     607             : 
     608           0 :     free(data.data);
     609           0 :     return ret;
     610             : }
     611             : 
     612             : static int
     613           0 : mk_temp(const char *fn, char **tfn)
     614             : {
     615           0 :     char *ds;
     616           0 :     int ret = -1;
     617             : 
     618             : #ifdef WIN32
     619             :     char buf[PATH_MAX];
     620             :     char *p;
     621             : 
     622             :     *tfn = NULL;
     623             : 
     624             :     if ((ds = _fullpath(buf, fn, sizeof(buf))) == NULL) {
     625             :         errno = errno ? errno : ENAMETOOLONG;
     626             :         return -1;
     627             :     }
     628             : 
     629             :     if ((p = strrchr(ds, '\\')) == NULL) {
     630             :         ret = asprintf(tfn, ".%s-XXXXXX", ds); /* XXX can't happen */
     631             :     } else {
     632             :         *(p++) = '\0';
     633             :         ret = asprintf(tfn, "%s/.%s-XXXXXX", ds, p);
     634             :     }
     635             : #else
     636           0 :     *tfn = NULL;
     637           0 :     if ((ds = strdup(fn)))
     638           0 :         ret = asprintf(tfn, "%s/.%s-XXXXXX", dirname(ds), basename(ds));
     639           0 :     free(ds);
     640             : #endif
     641             : 
     642             :     /*
     643             :      * Using mkostemp() risks leaving garbage files lying around.  To do better
     644             :      * without resorting to file locks (which have their own problems) we need
     645             :      * O_TMPFILE and linkat(2), which only Linux has.
     646             :      */
     647           0 :     return  (ret == -1 || *tfn == NULL) ? -1 : mkostemp(*tfn, O_CLOEXEC);
     648             : }
     649             : 
     650             : static int
     651           0 : file_store(hx509_context context,
     652             :            hx509_certs certs, void *data, int flags, hx509_lock lock)
     653             : {
     654           0 :     struct ks_file *ksf = data;
     655           0 :     struct store_ctx sc;
     656           0 :     char *tfn;
     657           0 :     int ret;
     658           0 :     int fd;
     659             : 
     660           0 :     sc.f = NULL;
     661           0 :     fd = mk_temp(ksf->fn, &tfn);
     662           0 :     if (fd > -1)
     663           0 :         sc.f = fdopen(fd, "w");
     664           0 :     if (sc.f == NULL) {
     665           0 :         hx509_set_error_string(context, 0, ret = errno,
     666             :                                "Failed to open file %s for writing", ksf->fn);
     667           0 :         if (fd > -1)
     668           0 :             (void) close(fd);
     669           0 :         return ret;
     670             :     }
     671           0 :     rk_cloexec_file(sc.f);
     672           0 :     sc.store_flags = flags;
     673           0 :     sc.format = ksf->format;
     674             : 
     675           0 :     ret = hx509_certs_iter_f(context, ksf->certs, store_func, &sc);
     676           0 :     if (ret == 0)
     677           0 :         ret = fclose(sc.f);
     678             :     else
     679           0 :         (void) fclose(sc.f);
     680           0 :     if (ret)
     681           0 :         (void) unlink(tfn);
     682             :     else
     683           0 :         (void) rename(tfn, ksf->fn);
     684           0 :     free(tfn);
     685           0 :     return ret;
     686             : }
     687             : 
     688             : static int
     689           0 : file_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
     690             : {
     691           0 :     struct ks_file *ksf = data;
     692           0 :     return hx509_certs_add(context, ksf->certs, c);
     693             : }
     694             : 
     695             : static int
     696         395 : file_iter_start(hx509_context context,
     697             :                 hx509_certs certs, void *data, void **cursor)
     698             : {
     699         395 :     struct ks_file *ksf = data;
     700         395 :     return hx509_certs_start_seq(context, ksf->certs, cursor);
     701             : }
     702             : 
     703             : static int
     704         645 : file_iter(hx509_context context,
     705             :           hx509_certs certs, void *data, void *iter, hx509_cert *cert)
     706             : {
     707         645 :     struct ks_file *ksf = data;
     708         645 :     return hx509_certs_next_cert(context, ksf->certs, iter, cert);
     709             : }
     710             : 
     711             : static int
     712         395 : file_iter_end(hx509_context context,
     713             :               hx509_certs certs,
     714             :               void *data,
     715             :               void *cursor)
     716             : {
     717         395 :     struct ks_file *ksf = data;
     718         395 :     return hx509_certs_end_seq(context, ksf->certs, cursor);
     719             : }
     720             : 
     721             : static int
     722           0 : file_getkeys(hx509_context context,
     723             :              hx509_certs certs,
     724             :              void *data,
     725             :              hx509_private_key **keys)
     726             : {
     727           0 :     struct ks_file *ksf = data;
     728           0 :     return _hx509_certs_keys_get(context, ksf->certs, keys);
     729             : }
     730             : 
     731             : static int
     732           0 : file_addkey(hx509_context context,
     733             :              hx509_certs certs,
     734             :              void *data,
     735             :              hx509_private_key key)
     736             : {
     737           0 :     struct ks_file *ksf = data;
     738           0 :     return _hx509_certs_keys_add(context, ksf->certs, key);
     739             : }
     740             : 
     741             : static int
     742           0 : file_destroy(hx509_context context,
     743             :              hx509_certs certs,
     744             :              void *data)
     745             : {
     746           0 :     struct ks_file *ksf = data;
     747           0 :     return _hx509_erase_file(context, ksf->fn);
     748             : }
     749             : 
     750             : static struct hx509_keyset_ops keyset_file = {
     751             :     "FILE",
     752             :     0,
     753             :     file_init_pem,
     754             :     file_store,
     755             :     file_free,
     756             :     file_add,
     757             :     NULL,
     758             :     file_iter_start,
     759             :     file_iter,
     760             :     file_iter_end,
     761             :     NULL,
     762             :     file_getkeys,
     763             :     file_addkey,
     764             :     file_destroy
     765             : };
     766             : 
     767             : static struct hx509_keyset_ops keyset_pemfile = {
     768             :     "PEM-FILE",
     769             :     0,
     770             :     file_init_pem,
     771             :     file_store,
     772             :     file_free,
     773             :     file_add,
     774             :     NULL,
     775             :     file_iter_start,
     776             :     file_iter,
     777             :     file_iter_end,
     778             :     NULL,
     779             :     file_getkeys,
     780             :     file_addkey,
     781             :     file_destroy
     782             : };
     783             : 
     784             : static struct hx509_keyset_ops keyset_derfile = {
     785             :     "DER-FILE",
     786             :     0,
     787             :     file_init_der,
     788             :     file_store,
     789             :     file_free,
     790             :     file_add,
     791             :     NULL,
     792             :     file_iter_start,
     793             :     file_iter,
     794             :     file_iter_end,
     795             :     NULL,
     796             :     file_getkeys,
     797             :     file_addkey,
     798             :     file_destroy
     799             : };
     800             : 
     801             : 
     802             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     803      792004 : _hx509_ks_file_register(hx509_context context)
     804             : {
     805      792004 :     _hx509_ks_register(context, &keyset_file);
     806      792004 :     _hx509_ks_register(context, &keyset_pemfile);
     807      792004 :     _hx509_ks_register(context, &keyset_derfile);
     808      792004 : }

Generated by: LCOV version 1.14