root/source4/heimdal/lib/hx509/ks_file.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. parse_certificate
  2. try_decrypt
  3. parse_rsa_private_key
  4. pem_func
  5. file_init_common
  6. file_init_pem
  7. file_init_der
  8. file_free
  9. store_func
  10. file_store
  11. file_add
  12. file_iter_start
  13. file_iter
  14. file_iter_end
  15. file_getkeys
  16. file_addkey
  17. _hx509_ks_file_register

   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 RCSID("$Id$");
  36 
  37 typedef enum { USE_PEM, USE_DER } outformat;
  38 
  39 struct ks_file {
  40     hx509_certs certs;
  41     char *fn;
  42     outformat format;
  43 };
  44 
  45 /*
  46  *
  47  */
  48 
  49 static int
  50 parse_certificate(hx509_context context, const char *fn,
     /* [<][>][^][v][top][bottom][index][help] */
  51                   struct hx509_collector *c,
  52                   const hx509_pem_header *headers,
  53                   const void *data, size_t len)
  54 {
  55     hx509_cert cert;
  56     int ret;
  57 
  58     ret = hx509_cert_init_data(context, data, len, &cert);
  59     if (ret)
  60         return ret;
  61 
  62     ret = _hx509_collector_certs_add(context, c, cert);
  63     hx509_cert_free(cert);
  64     return ret;
  65 }
  66 
  67 static int
  68 try_decrypt(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
  69             struct hx509_collector *collector,
  70             const AlgorithmIdentifier *alg,
  71             const EVP_CIPHER *c,
  72             const void *ivdata,
  73             const void *password,
  74             size_t passwordlen,
  75             const void *cipher,
  76             size_t len)
  77 {
  78     heim_octet_string clear;
  79     size_t keylen;
  80     void *key;
  81     int ret;
  82 
  83     keylen = EVP_CIPHER_key_length(c);
  84 
  85     key = malloc(keylen);
  86     if (key == NULL) {
  87         hx509_clear_error_string(context);
  88         return ENOMEM;
  89     }
  90 
  91     ret = EVP_BytesToKey(c, EVP_md5(), ivdata,
  92                          password, passwordlen,
  93                          1, key, NULL);
  94     if (ret <= 0) {
  95         hx509_set_error_string(context, 0, HX509_CRYPTO_INTERNAL_ERROR,
  96                                "Failed to do string2key for private key");
  97         return HX509_CRYPTO_INTERNAL_ERROR;
  98     }
  99 
 100     clear.data = malloc(len);
 101     if (clear.data == NULL) {
 102         hx509_set_error_string(context, 0, ENOMEM,
 103                                "Out of memory to decrypt for private key");
 104         ret = ENOMEM;
 105         goto out;
 106     }
 107     clear.length = len;
 108 
 109     {
 110         EVP_CIPHER_CTX ctx;
 111         EVP_CIPHER_CTX_init(&ctx);
 112         EVP_CipherInit_ex(&ctx, c, NULL, key, ivdata, 0);
 113         EVP_Cipher(&ctx, clear.data, cipher, len);
 114         EVP_CIPHER_CTX_cleanup(&ctx);
 115     }   
 116 
 117     ret = _hx509_collector_private_key_add(context,
 118                                            collector,
 119                                            alg,
 120                                            NULL,
 121                                            &clear,
 122                                            NULL);
 123 
 124     memset(clear.data, 0, clear.length);
 125     free(clear.data);
 126 out:
 127     memset(key, 0, keylen);
 128     free(key);
 129     return ret;
 130 }
 131 
 132 static int
 133 parse_rsa_private_key(hx509_context context, const char *fn,
     /* [<][>][^][v][top][bottom][index][help] */
 134                       struct hx509_collector *c,
 135                       const hx509_pem_header *headers,
 136                       const void *data, size_t len)
 137 {
 138     int ret = 0;
 139     const char *enc;
 140 
 141     enc = hx509_pem_find_header(headers, "Proc-Type");
 142     if (enc) {
 143         const char *dek;
 144         char *type, *iv;
 145         ssize_t ssize, size;
 146         void *ivdata;
 147         const EVP_CIPHER *cipher;
 148         const struct _hx509_password *pw;
 149         hx509_lock lock;
 150         int i, decrypted = 0;
 151 
 152         lock = _hx509_collector_get_lock(c);
 153         if (lock == NULL) {
 154             hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
 155                                    "Failed to get password for "
 156                                    "password protected file %s", fn);
 157             return HX509_ALG_NOT_SUPP;
 158         }
 159 
 160         if (strcmp(enc, "4,ENCRYPTED") != 0) {
 161             hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
 162                                    "RSA key encrypted in unknown method %s "
 163                                    "in file",
 164                                    enc, fn);
 165             hx509_clear_error_string(context);
 166             return HX509_PARSING_KEY_FAILED;
 167         }
 168 
 169         dek = hx509_pem_find_header(headers, "DEK-Info");
 170         if (dek == NULL) {
 171             hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
 172                                    "Encrypted RSA missing DEK-Info");
 173             return HX509_PARSING_KEY_FAILED;
 174         }
 175 
 176         type = strdup(dek);
 177         if (type == NULL) {
 178             hx509_clear_error_string(context);
 179             return ENOMEM;
 180         }
 181 
 182         iv = strchr(type, ',');
 183         if (iv == NULL) {
 184             free(type);
 185             hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
 186                                    "IV missing");
 187             return HX509_PARSING_KEY_FAILED;
 188         }
 189 
 190         *iv++ = '\0';
 191 
 192         size = strlen(iv);
 193         ivdata = malloc(size);
 194         if (ivdata == NULL) {
 195             hx509_clear_error_string(context);
 196             free(type);
 197             return ENOMEM;
 198         }
 199 
 200         cipher = EVP_get_cipherbyname(type);
 201         if (cipher == NULL) {
 202             free(ivdata);
 203             hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
 204                                    "RSA key encrypted with "
 205                                    "unsupported cipher: %s",
 206                                    type);
 207             free(type);
 208             return HX509_ALG_NOT_SUPP;
 209         }
 210 
 211 #define PKCS5_SALT_LEN 8
 212 
 213         ssize = hex_decode(iv, ivdata, size);
 214         free(type);
 215         type = NULL;
 216         iv = NULL;
 217 
 218         if (ssize < 0 || ssize < PKCS5_SALT_LEN || ssize < EVP_CIPHER_iv_length(cipher)) {
 219             free(ivdata);
 220             hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
 221                                    "Salt have wrong length in RSA key file");
 222             return HX509_PARSING_KEY_FAILED;
 223         }
 224         
 225         pw = _hx509_lock_get_passwords(lock);
 226         if (pw != NULL) {
 227             const void *password;
 228             size_t passwordlen;
 229 
 230             for (i = 0; i < pw->len; i++) {
 231                 password = pw->val[i];
 232                 passwordlen = strlen(password);
 233                 
 234                 ret = try_decrypt(context, c, hx509_signature_rsa(),
 235                                   cipher, ivdata, password, passwordlen,
 236                                   data, len);
 237                 if (ret == 0) {
 238                     decrypted = 1;
 239                     break;
 240                 }
 241             }
 242         }
 243         if (!decrypted) {
 244             hx509_prompt prompt;
 245             char password[128];
 246 
 247             memset(&prompt, 0, sizeof(prompt));
 248 
 249             prompt.prompt = "Password for keyfile: ";
 250             prompt.type = HX509_PROMPT_TYPE_PASSWORD;
 251             prompt.reply.data = password;
 252             prompt.reply.length = sizeof(password);
 253 
 254             ret = hx509_lock_prompt(lock, &prompt);
 255             if (ret == 0)
 256                 ret = try_decrypt(context, c, hx509_signature_rsa(),
 257                                   cipher, ivdata, password, strlen(password),
 258                                   data, len);
 259             /* XXX add password to lock password collection ? */
 260             memset(password, 0, sizeof(password));
 261         }
 262         free(ivdata);
 263 
 264     } else {
 265         heim_octet_string keydata;
 266 
 267         keydata.data = rk_UNCONST(data);
 268         keydata.length = len;
 269 
 270         ret = _hx509_collector_private_key_add(context,
 271                                                c,
 272                                                hx509_signature_rsa(),
 273                                                NULL,
 274                                                &keydata,
 275                                                NULL);
 276     }
 277 
 278     return ret;
 279 }
 280 
 281 
 282 struct pem_formats {
 283     const char *name;
 284     int (*func)(hx509_context, const char *, struct hx509_collector *,
 285                 const hx509_pem_header *, const void *, size_t);
 286 } formats[] = {
 287     { "CERTIFICATE", parse_certificate },
 288     { "RSA PRIVATE KEY", parse_rsa_private_key }
 289 };
 290 
 291 
 292 struct pem_ctx {
 293     int flags;
 294     struct hx509_collector *c;
 295 };
 296 
 297 static int
 298 pem_func(hx509_context context, const char *type,
     /* [<][>][^][v][top][bottom][index][help] */
 299          const hx509_pem_header *header,
 300          const void *data, size_t len, void *ctx)
 301 {
 302     struct pem_ctx *pem_ctx = (struct pem_ctx*)ctx;
 303     int ret = 0, j;
 304 
 305     for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) {
 306         const char *q = formats[j].name;
 307         if (strcasecmp(type, q) == 0) {
 308             ret = (*formats[j].func)(context, NULL, pem_ctx->c,  header, data, len);
 309             if (ret == 0)
 310                 break;
 311         }
 312     }
 313     if (j == sizeof(formats)/sizeof(formats[0])) {
 314         ret = HX509_UNSUPPORTED_OPERATION;
 315         hx509_set_error_string(context, 0, ret,
 316                                "Found no matching PEM format for %s", type);
 317         return ret;
 318     }
 319     if (ret && (pem_ctx->flags & HX509_CERTS_UNPROTECT_ALL))
 320         return ret;
 321     return 0;
 322 }
 323 
 324 /*
 325  *
 326  */
 327 
 328 static int
 329 file_init_common(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 330                  hx509_certs certs, void **data, int flags,
 331                  const char *residue, hx509_lock lock, outformat format)
 332 {
 333     char *p, *pnext;
 334     struct ks_file *f = NULL;
 335     hx509_private_key *keys = NULL;
 336     int ret;
 337     struct pem_ctx pem_ctx;
 338 
 339     pem_ctx.flags = flags;
 340     pem_ctx.c = NULL;
 341 
 342     *data = NULL;
 343 
 344     if (lock == NULL)
 345         lock = _hx509_empty_lock;
 346 
 347     f = calloc(1, sizeof(*f));
 348     if (f == NULL) {
 349         hx509_clear_error_string(context);
 350         return ENOMEM;
 351     }
 352     f->format = format;
 353 
 354     f->fn = strdup(residue);
 355     if (f->fn == NULL) {
 356         hx509_clear_error_string(context);
 357         ret = ENOMEM;
 358         goto out;
 359     }
 360 
 361     /*
 362      * XXX this is broken, the function should parse the file before
 363      * overwriting it
 364      */
 365 
 366     if (flags & HX509_CERTS_CREATE) {
 367         ret = hx509_certs_init(context, "MEMORY:ks-file-create",
 368                                0, lock, &f->certs);
 369         if (ret)
 370             goto out;
 371         *data = f;
 372         return 0;
 373     }
 374 
 375     ret = _hx509_collector_alloc(context, lock, &pem_ctx.c);
 376     if (ret)
 377         goto out;
 378 
 379     for (p = f->fn; p != NULL; p = pnext) {
 380         FILE *f;
 381 
 382         pnext = strchr(p, ',');
 383         if (pnext)
 384             *pnext++ = '\0';
 385         
 386 
 387         if ((f = fopen(p, "r")) == NULL) {
 388             ret = ENOENT;
 389             hx509_set_error_string(context, 0, ret,
 390                                    "Failed to open PEM file \"%s\": %s",
 391                                    p, strerror(errno));
 392             goto out;
 393         }
 394         rk_cloexec_file(f);
 395 
 396         ret = hx509_pem_read(context, f, pem_func, &pem_ctx);
 397         fclose(f);              
 398         if (ret != 0 && ret != HX509_PARSING_KEY_FAILED)
 399             goto out;
 400         else if (ret == HX509_PARSING_KEY_FAILED) {
 401             size_t length;
 402             void *ptr;
 403             int i;
 404 
 405             ret = rk_undumpdata(p, &ptr, &length);
 406             if (ret) {
 407                 hx509_clear_error_string(context);
 408                 goto out;
 409             }
 410 
 411             for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
 412                 ret = (*formats[i].func)(context, p, pem_ctx.c, NULL, ptr, length);
 413                 if (ret == 0)
 414                     break;
 415             }
 416             rk_xfree(ptr);
 417             if (ret)
 418                 goto out;
 419         }
 420     }
 421 
 422     ret = _hx509_collector_collect_certs(context, pem_ctx.c, &f->certs);
 423     if (ret)
 424         goto out;
 425 
 426     ret = _hx509_collector_collect_private_keys(context, pem_ctx.c, &keys);
 427     if (ret == 0) {
 428         int i;
 429 
 430         for (i = 0; keys[i]; i++)
 431             _hx509_certs_keys_add(context, f->certs, keys[i]);
 432         _hx509_certs_keys_free(context, keys);
 433     }
 434 
 435 out:
 436     if (ret == 0)
 437         *data = f;
 438     else {
 439         if (f->fn)
 440             free(f->fn);
 441         free(f);
 442     }
 443     if (pem_ctx.c)
 444         _hx509_collector_free(pem_ctx.c);
 445 
 446     return ret;
 447 }
 448 
 449 static int
 450 file_init_pem(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 451               hx509_certs certs, void **data, int flags,
 452               const char *residue, hx509_lock lock)
 453 {
 454     return file_init_common(context, certs, data, flags, residue, lock, USE_PEM);
 455 }
 456 
 457 static int
 458 file_init_der(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 459               hx509_certs certs, void **data, int flags,
 460               const char *residue, hx509_lock lock)
 461 {
 462     return file_init_common(context, certs, data, flags, residue, lock, USE_DER);
 463 }
 464 
 465 static int
 466 file_free(hx509_certs certs, void *data)
     /* [<][>][^][v][top][bottom][index][help] */
 467 {
 468     struct ks_file *f = data;
 469     hx509_certs_free(&f->certs);
 470     free(f->fn);
 471     free(f);
 472     return 0;
 473 }
 474 
 475 struct store_ctx {
 476     FILE *f;
 477     outformat format;
 478 };
 479 
 480 static int
 481 store_func(hx509_context context, void *ctx, hx509_cert c)
     /* [<][>][^][v][top][bottom][index][help] */
 482 {
 483     struct store_ctx *sc = ctx;
 484     heim_octet_string data;
 485     int ret;
 486 
 487     ret = hx509_cert_binary(context, c, &data);
 488     if (ret)
 489         return ret;
 490 
 491     switch (sc->format) {
 492     case USE_DER:
 493         fwrite(data.data, data.length, 1, sc->f);
 494         free(data.data);
 495         break;
 496     case USE_PEM:
 497         hx509_pem_write(context, "CERTIFICATE", NULL, sc->f,
 498                         data.data, data.length);
 499         free(data.data);
 500         if (_hx509_cert_private_key_exportable(c)) {
 501             hx509_private_key key = _hx509_cert_private_key(c);
 502             ret = _hx509_private_key_export(context, key, &data);
 503             if (ret)
 504                 break;
 505             hx509_pem_write(context, _hx509_private_pem_name(key), NULL, sc->f,
 506                             data.data, data.length);
 507             free(data.data);
 508         }
 509         break;
 510     }
 511 
 512     return 0;
 513 }
 514 
 515 static int
 516 file_store(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 517            hx509_certs certs, void *data, int flags, hx509_lock lock)
 518 {
 519     struct ks_file *f = data;
 520     struct store_ctx sc;
 521     int ret;
 522 
 523     sc.f = fopen(f->fn, "w");
 524     if (sc.f == NULL) {
 525         hx509_set_error_string(context, 0, ENOENT,
 526                                "Failed to open file %s for writing");
 527         return ENOENT;
 528     }
 529     rk_cloexec_file(sc.f);
 530     sc.format = f->format;
 531 
 532     ret = hx509_certs_iter(context, f->certs, store_func, &sc);
 533     fclose(sc.f);
 534     return ret;
 535 }
 536 
 537 static int
 538 file_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
     /* [<][>][^][v][top][bottom][index][help] */
 539 {
 540     struct ks_file *f = data;
 541     return hx509_certs_add(context, f->certs, c);
 542 }
 543 
 544 static int
 545 file_iter_start(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 546                 hx509_certs certs, void *data, void **cursor)
 547 {
 548     struct ks_file *f = data;
 549     return hx509_certs_start_seq(context, f->certs, cursor);
 550 }
 551 
 552 static int
 553 file_iter(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 554           hx509_certs certs, void *data, void *iter, hx509_cert *cert)
 555 {
 556     struct ks_file *f = data;
 557     return hx509_certs_next_cert(context, f->certs, iter, cert);
 558 }
 559 
 560 static int
 561 file_iter_end(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 562               hx509_certs certs,
 563               void *data,
 564               void *cursor)
 565 {
 566     struct ks_file *f = data;
 567     return hx509_certs_end_seq(context, f->certs, cursor);
 568 }
 569 
 570 static int
 571 file_getkeys(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 572              hx509_certs certs,
 573              void *data,
 574              hx509_private_key **keys)
 575 {
 576     struct ks_file *f = data;
 577     return _hx509_certs_keys_get(context, f->certs, keys);
 578 }
 579 
 580 static int
 581 file_addkey(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 582              hx509_certs certs,
 583              void *data,
 584              hx509_private_key key)
 585 {
 586     struct ks_file *f = data;
 587     return _hx509_certs_keys_add(context, f->certs, key);
 588 }
 589 
 590 static struct hx509_keyset_ops keyset_file = {
 591     "FILE",
 592     0,
 593     file_init_pem,
 594     file_store,
 595     file_free,
 596     file_add,
 597     NULL,
 598     file_iter_start,
 599     file_iter,
 600     file_iter_end,
 601     NULL,
 602     file_getkeys,
 603     file_addkey
 604 };
 605 
 606 static struct hx509_keyset_ops keyset_pemfile = {
 607     "PEM-FILE",
 608     0,
 609     file_init_pem,
 610     file_store,
 611     file_free,
 612     file_add,
 613     NULL,
 614     file_iter_start,
 615     file_iter,
 616     file_iter_end,
 617     NULL,
 618     file_getkeys,
 619     file_addkey
 620 };
 621 
 622 static struct hx509_keyset_ops keyset_derfile = {
 623     "DER-FILE",
 624     0,
 625     file_init_der,
 626     file_store,
 627     file_free,
 628     file_add,
 629     NULL,
 630     file_iter_start,
 631     file_iter,
 632     file_iter_end,
 633     NULL,
 634     file_getkeys,
 635     file_addkey
 636 };
 637 
 638 
 639 void
 640 _hx509_ks_file_register(hx509_context context)
     /* [<][>][^][v][top][bottom][index][help] */
 641 {
 642     _hx509_ks_register(context, &keyset_file);
 643     _hx509_ks_register(context, &keyset_pemfile);
 644     _hx509_ks_register(context, &keyset_derfile);
 645 }

/* [<][>][^][v][top][bottom][index][help] */