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 v4-17-test 1498b464 Lines: 99 320 30.9 %
Date: 2024-06-13 04:01:37 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         151 : 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         151 :     heim_error_t error = NULL;
      59             :     hx509_cert cert;
      60             :     int ret;
      61             : 
      62         151 :     cert = hx509_cert_init_data(context, data, len, &error);
      63         151 :     if (cert == NULL) {
      64           0 :         ret = heim_error_get_code(error);
      65           0 :         heim_release(error);
      66           0 :         return ret;
      67             :     }
      68             : 
      69         151 :     ret = _hx509_collector_certs_add(context, c, cert);
      70         151 :     hx509_cert_free(cert);
      71         151 :     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             :     heim_octet_string clear;
      87             :     size_t keylen;
      88             :     void *key;
      89             :     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             :         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             :     PKCS8PrivateKeyInfo ki;
     146             :     heim_octet_string keydata;
     147             :     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          38 : 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          38 :     int ret = 0;
     175             :     const char *enc;
     176             : 
     177          38 :     enc = hx509_pem_find_header(headers, "Proc-Type");
     178          38 :     if (enc) {
     179             :         const char *dek;
     180             :         char *type, *iv;
     181             :         ssize_t ssize, size;
     182             :         void *ivdata;
     183             :         const EVP_CIPHER *cipher;
     184             :         const struct _hx509_password *pw;
     185             :         hx509_lock lock;
     186           0 :         int decrypted = 0;
     187             :         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",
     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             :             hx509_prompt prompt;
     282             :             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          38 :     } else if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) {
     301             :         heim_octet_string keydata;
     302             : 
     303          38 :         keydata.data = rk_UNCONST(data);
     304          38 :         keydata.length = len;
     305             : 
     306          38 :         ret = _hx509_collector_private_key_add(context, c, ai, NULL,
     307             :                                                &keydata, NULL);
     308             :     }
     309             : 
     310          38 :     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         189 : 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         189 :     struct pem_ctx *pem_ctx = (struct pem_ctx*)ctx;
     341         189 :     int ret = 0;
     342             :     size_t j;
     343             : 
     344         265 :     for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) {
     345         265 :         const char *q = formats[j].name;
     346         265 :         if (strcasecmp(type, q) == 0) {
     347         189 :             const AlgorithmIdentifier *ai = NULL;
     348             : 
     349         189 :             if (formats[j].ai != NULL)
     350          38 :                 ai = (*formats[j].ai)();
     351             : 
     352         189 :             ret = (*formats[j].func)(context, NULL, pem_ctx->flags, pem_ctx->c,
     353             :                                      header, data, len, ai);
     354         189 :             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         189 :             break;
     360             :         }
     361             :     }
     362         189 :     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         189 :     return 0;
     369             : }
     370             : 
     371             : /*
     372             :  *
     373             :  */
     374             : 
     375             : static int
     376         184 : 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             :     char *p, *pnext;
     381         184 :     struct ks_file *ksf = NULL;
     382         184 :     hx509_private_key *keys = NULL;
     383             :     int ret;
     384             :     struct pem_ctx pem_ctx;
     385             : 
     386         184 :     pem_ctx.flags = flags;
     387         184 :     pem_ctx.c = NULL;
     388             : 
     389         184 :     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         184 :     *data = NULL;
     396             : 
     397         184 :     if (lock == NULL)
     398         113 :         lock = _hx509_empty_lock;
     399             : 
     400         184 :     ksf = calloc(1, sizeof(*ksf));
     401         184 :     if (ksf == NULL) {
     402           0 :         hx509_clear_error_string(context);
     403           0 :         return ENOMEM;
     404             :     }
     405         184 :     ksf->format = format;
     406             : 
     407         184 :     ksf->fn = strdup(residue);
     408         184 :     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         184 :     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         184 :     ret = _hx509_collector_alloc(context, lock, &pem_ctx.c);
     433         184 :     if (ret)
     434           0 :         goto out;
     435             : 
     436         373 :     for (p = ksf->fn; p != NULL; p = pnext) {
     437             :         FILE *f;
     438             : 
     439         222 :         pnext = strchr(p, ',');
     440         222 :         if (pnext)
     441          71 :             *pnext++ = '\0';
     442             : 
     443             : 
     444         222 :         if ((f = fopen(p, "r")) == NULL) {
     445          33 :             ret = ENOENT;
     446          33 :             hx509_set_error_string(context, 0, ret,
     447             :                                    "Failed to open PEM file \"%s\": %s",
     448          33 :                                    p, strerror(errno));
     449          33 :             goto out;
     450             :         }
     451         189 :         rk_cloexec_file(f);
     452             : 
     453         189 :         ret = hx509_pem_read(context, f, pem_func, &pem_ctx);
     454         189 :         fclose(f);
     455         189 :         if (ret != 0 && ret != HX509_PARSING_KEY_FAILED)
     456             :             goto out;
     457         189 :         else if (ret == HX509_PARSING_KEY_FAILED) {
     458             :             size_t length;
     459             :             void *ptr;
     460             :             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         151 :     ret = _hx509_collector_collect_certs(context, pem_ctx.c, &ksf->certs);
     488         151 :     if (ret)
     489           0 :         goto out;
     490             : 
     491         151 :     ret = _hx509_collector_collect_private_keys(context, pem_ctx.c, &keys);
     492         151 :     if (ret == 0) {
     493             :         int i;
     494             : 
     495         189 :         for (i = 0; keys[i]; i++)
     496          38 :             _hx509_certs_keys_add(context, ksf->certs, keys[i]);
     497         151 :         _hx509_certs_keys_free(context, keys);
     498             :     }
     499             : 
     500         184 : out:
     501         184 :     if (ret == 0)
     502         151 :         *data = ksf;
     503             :     else {
     504          33 :         if (ksf->fn)
     505          33 :             free(ksf->fn);
     506          33 :         free(ksf);
     507             :     }
     508         184 :     if (pem_ctx.c)
     509         184 :         _hx509_collector_free(pem_ctx.c);
     510             : 
     511         184 :     return ret;
     512             : }
     513             : 
     514             : static int
     515         184 : file_init_pem(hx509_context context,
     516             :               hx509_certs certs, void **data, int flags,
     517             :               const char *residue, hx509_lock lock)
     518             : {
     519         184 :     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          75 : file_free(hx509_certs certs, void *data)
     532             : {
     533          75 :     struct ks_file *ksf = data;
     534          75 :     hx509_certs_free(&ksf->certs);
     535          75 :     free(ksf->fn);
     536          75 :     free(ksf);
     537          75 :     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             :     heim_octet_string data;
     551           0 :     int ret = 0;
     552             : 
     553           0 :     if (hx509_cert_have_private_key_only(c)) {
     554           0 :         data.length = 0;
     555           0 :         data.data = NULL;
     556             :     } else {
     557           0 :         ret = hx509_cert_binary(context, c, &data);
     558           0 :         if (ret)
     559           0 :             return ret;
     560             :     }
     561             : 
     562           0 :     switch (sc->format) {
     563           0 :     case USE_DER:
     564             :         /* Can't store both.  Well, we could, but nothing will support it */
     565           0 :         if (data.data) {
     566           0 :             fwrite(data.data, data.length, 1, sc->f);
     567           0 :         } else if (_hx509_cert_private_key_exportable(c) &&
     568           0 :                    !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) {
     569           0 :             hx509_private_key key = _hx509_cert_private_key(c);
     570             : 
     571           0 :             free(data.data);
     572           0 :             data.length = 0;
     573           0 :             data.data = NULL;
     574           0 :             ret = _hx509_private_key_export(context, key,
     575             :                                             HX509_KEY_FORMAT_DER, &data);
     576           0 :             if (ret == 0 && data.length)
     577           0 :                 fwrite(data.data, data.length, 1, sc->f);
     578             :         }
     579           0 :         break;
     580           0 :     case USE_PEM:
     581           0 :         if (_hx509_cert_private_key_exportable(c) &&
     582           0 :             !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) {
     583             :             heim_octet_string priv_key;
     584           0 :             hx509_private_key key = _hx509_cert_private_key(c);
     585             : 
     586           0 :             ret = _hx509_private_key_export(context, key,
     587             :                                             HX509_KEY_FORMAT_DER, &priv_key);
     588           0 :             if (ret == 0)
     589           0 :                 ret = hx509_pem_write(context, _hx509_private_pem_name(key), NULL,
     590           0 :                                       sc->f, priv_key.data, priv_key.length);
     591           0 :             free(priv_key.data);
     592             :         }
     593           0 :         if (ret == 0 && data.data) {
     594           0 :             ret = hx509_pem_write(context, "CERTIFICATE", NULL, sc->f,
     595           0 :                                   data.data, data.length);
     596             :         }
     597           0 :         break;
     598             :     }
     599             : 
     600           0 :     free(data.data);
     601           0 :     return ret;
     602             : }
     603             : 
     604             : static int
     605           0 : mk_temp(const char *fn, char **tfn)
     606             : {
     607             :     char *ds;
     608           0 :     int ret = -1;
     609             : 
     610             : #ifdef WIN32
     611             :     char buf[PATH_MAX];
     612             :     char *p;
     613             : 
     614             :     *tfn = NULL;
     615             : 
     616             :     if ((ds = _fullpath(buf, fn, sizeof(buf))) == NULL) {
     617             :         errno = errno ? errno : ENAMETOOLONG;
     618             :         return -1;
     619             :     }
     620             : 
     621             :     if ((p = strrchr(ds, '\\')) == NULL) {
     622             :         ret = asprintf(tfn, ".%s-XXXXXX", ds); /* XXX can't happen */
     623             :     } else {
     624             :         *(p++) = '\0';
     625             :         ret = asprintf(tfn, "%s/.%s-XXXXXX", ds, p);
     626             :     }
     627             : #else
     628           0 :     *tfn = NULL;
     629           0 :     if ((ds = strdup(fn)))
     630           0 :         ret = asprintf(tfn, "%s/.%s-XXXXXX", dirname(ds), basename(ds));
     631           0 :     free(ds);
     632             : #endif
     633             : 
     634             :     /*
     635             :      * Using mkostemp() risks leaving garbage files lying around.  To do better
     636             :      * without resorting to file locks (which have their own problems) we need
     637             :      * O_TMPFILE and linkat(2), which only Linux has.
     638             :      */
     639           0 :     return  (ret == -1 || *tfn == NULL) ? -1 : mkostemp(*tfn, O_CLOEXEC);
     640             : }
     641             : 
     642             : static int
     643           0 : file_store(hx509_context context,
     644             :            hx509_certs certs, void *data, int flags, hx509_lock lock)
     645             : {
     646           0 :     struct ks_file *ksf = data;
     647             :     struct store_ctx sc;
     648             :     char *tfn;
     649             :     int ret;
     650             :     int fd;
     651             : 
     652           0 :     sc.f = NULL;
     653           0 :     fd = mk_temp(ksf->fn, &tfn);
     654           0 :     if (fd > -1)
     655           0 :         sc.f = fdopen(fd, "w");
     656           0 :     if (sc.f == NULL) {
     657           0 :         hx509_set_error_string(context, 0, ret = errno,
     658             :                                "Failed to open file %s for writing", ksf->fn);
     659           0 :         if (fd > -1)
     660           0 :             (void) close(fd);
     661           0 :         return ret;
     662             :     }
     663           0 :     rk_cloexec_file(sc.f);
     664           0 :     sc.store_flags = flags;
     665           0 :     sc.format = ksf->format;
     666             : 
     667           0 :     ret = hx509_certs_iter_f(context, ksf->certs, store_func, &sc);
     668           0 :     if (ret == 0)
     669           0 :         ret = fclose(sc.f);
     670             :     else
     671           0 :         (void) fclose(sc.f);
     672           0 :     if (ret)
     673           0 :         (void) unlink(tfn);
     674             :     else
     675           0 :         (void) rename(tfn, ksf->fn);
     676           0 :     free(tfn);
     677           0 :     return ret;
     678             : }
     679             : 
     680             : static int
     681           0 : file_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
     682             : {
     683           0 :     struct ks_file *ksf = data;
     684           0 :     return hx509_certs_add(context, ksf->certs, c);
     685             : }
     686             : 
     687             : static int
     688         113 : file_iter_start(hx509_context context,
     689             :                 hx509_certs certs, void *data, void **cursor)
     690             : {
     691         113 :     struct ks_file *ksf = data;
     692         113 :     return hx509_certs_start_seq(context, ksf->certs, cursor);
     693             : }
     694             : 
     695             : static int
     696         188 : file_iter(hx509_context context,
     697             :           hx509_certs certs, void *data, void *iter, hx509_cert *cert)
     698             : {
     699         188 :     struct ks_file *ksf = data;
     700         188 :     return hx509_certs_next_cert(context, ksf->certs, iter, cert);
     701             : }
     702             : 
     703             : static int
     704         113 : file_iter_end(hx509_context context,
     705             :               hx509_certs certs,
     706             :               void *data,
     707             :               void *cursor)
     708             : {
     709         113 :     struct ks_file *ksf = data;
     710         113 :     return hx509_certs_end_seq(context, ksf->certs, cursor);
     711             : }
     712             : 
     713             : static int
     714           0 : file_getkeys(hx509_context context,
     715             :              hx509_certs certs,
     716             :              void *data,
     717             :              hx509_private_key **keys)
     718             : {
     719           0 :     struct ks_file *ksf = data;
     720           0 :     return _hx509_certs_keys_get(context, ksf->certs, keys);
     721             : }
     722             : 
     723             : static int
     724           0 : file_addkey(hx509_context context,
     725             :              hx509_certs certs,
     726             :              void *data,
     727             :              hx509_private_key key)
     728             : {
     729           0 :     struct ks_file *ksf = data;
     730           0 :     return _hx509_certs_keys_add(context, ksf->certs, key);
     731             : }
     732             : 
     733             : static int
     734           0 : file_destroy(hx509_context context,
     735             :              hx509_certs certs,
     736             :              void *data)
     737             : {
     738           0 :     struct ks_file *ksf = data;
     739           0 :     return _hx509_erase_file(context, ksf->fn);
     740             : }
     741             : 
     742             : static struct hx509_keyset_ops keyset_file = {
     743             :     "FILE",
     744             :     0,
     745             :     file_init_pem,
     746             :     file_store,
     747             :     file_free,
     748             :     file_add,
     749             :     NULL,
     750             :     file_iter_start,
     751             :     file_iter,
     752             :     file_iter_end,
     753             :     NULL,
     754             :     file_getkeys,
     755             :     file_addkey,
     756             :     file_destroy
     757             : };
     758             : 
     759             : static struct hx509_keyset_ops keyset_pemfile = {
     760             :     "PEM-FILE",
     761             :     0,
     762             :     file_init_pem,
     763             :     file_store,
     764             :     file_free,
     765             :     file_add,
     766             :     NULL,
     767             :     file_iter_start,
     768             :     file_iter,
     769             :     file_iter_end,
     770             :     NULL,
     771             :     file_getkeys,
     772             :     file_addkey,
     773             :     file_destroy
     774             : };
     775             : 
     776             : static struct hx509_keyset_ops keyset_derfile = {
     777             :     "DER-FILE",
     778             :     0,
     779             :     file_init_der,
     780             :     file_store,
     781             :     file_free,
     782             :     file_add,
     783             :     NULL,
     784             :     file_iter_start,
     785             :     file_iter,
     786             :     file_iter_end,
     787             :     NULL,
     788             :     file_getkeys,
     789             :     file_addkey,
     790             :     file_destroy
     791             : };
     792             : 
     793             : 
     794             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     795      555816 : _hx509_ks_file_register(hx509_context context)
     796             : {
     797      555816 :     _hx509_ks_register(context, &keyset_file);
     798      555816 :     _hx509_ks_register(context, &keyset_pemfile);
     799      555816 :     _hx509_ks_register(context, &keyset_derfile);
     800      555816 : }

Generated by: LCOV version 1.13