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

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

DEFINITIONS

This source file includes following definitions.
  1. _hx509_ks_type
  2. _hx509_ks_register
  3. hx509_certs_init
  4. hx509_certs_store
  5. _hx509_certs_ref
  6. hx509_certs_free
  7. hx509_certs_start_seq
  8. hx509_certs_next_cert
  9. hx509_certs_end_seq
  10. hx509_certs_iter
  11. hx509_ci_print_names
  12. hx509_certs_add
  13. hx509_certs_find
  14. certs_merge_func
  15. hx509_certs_merge
  16. hx509_certs_append
  17. hx509_get_one_cert
  18. certs_info_stdio
  19. hx509_certs_info
  20. _hx509_pi_printf
  21. _hx509_certs_keys_get
  22. _hx509_certs_keys_add
  23. _hx509_certs_keys_free

   1 /*
   2  * Copyright (c) 2004 - 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 /**
  38  * @page page_keyset Certificate store operations
  39  *
  40  * Type of certificates store:
  41  * - MEMORY
  42  *   In memory based format. Doesnt support storing.
  43  * - FILE
  44  *   FILE supports raw DER certicates and PEM certicates. When PEM is
  45  *   used the file can contain may certificates and match private
  46  *   keys. Support storing the certificates. DER format only supports
  47  *   on certificate and no private key.
  48  * - PEM-FILE
  49  *   Same as FILE, defaulting to PEM encoded certificates.
  50  * - PEM-FILE
  51  *   Same as FILE, defaulting to DER encoded certificates.
  52  * - PKCS11
  53  * - PKCS12
  54  * - DIR
  55  * - KEYCHAIN
  56  *   Apple Mac OS X KeyChain backed keychain object.
  57  *
  58  * See the library functions here: @ref hx509_keyset
  59  */
  60 
  61 struct hx509_certs_data {
  62     unsigned int ref;
  63     struct hx509_keyset_ops *ops;
  64     void *ops_data;
  65 };
  66 
  67 static struct hx509_keyset_ops *
  68 _hx509_ks_type(hx509_context context, const char *type)
     /* [<][>][^][v][top][bottom][index][help] */
  69 {
  70     int i;
  71 
  72     for (i = 0; i < context->ks_num_ops; i++)
  73         if (strcasecmp(type, context->ks_ops[i]->name) == 0)
  74             return context->ks_ops[i];
  75 
  76     return NULL;
  77 }
  78 
  79 void
  80 _hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops)
     /* [<][>][^][v][top][bottom][index][help] */
  81 {
  82     struct hx509_keyset_ops **val;
  83 
  84     if (_hx509_ks_type(context, ops->name))
  85         return;
  86 
  87     val = realloc(context->ks_ops,
  88                   (context->ks_num_ops + 1) * sizeof(context->ks_ops[0]));
  89     if (val == NULL)
  90         return;
  91     val[context->ks_num_ops] = ops;
  92     context->ks_ops = val;
  93     context->ks_num_ops++;
  94 }
  95 
  96 /**
  97  * Open or creates a new hx509 certificate store.
  98  *
  99  * @param context A hx509 context
 100  * @param name name of the store, format is TYPE:type-specific-string,
 101  * if NULL is used the MEMORY store is used.
 102  * @param flags list of flags:
 103  * - HX509_CERTS_CREATE create a new keystore of the specific TYPE.
 104  * - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted.
 105  * @param lock a lock that unlocks the certificates store, use NULL to
 106  * select no password/certifictes/prompt lock (see @ref page_lock).
 107  * @param certs return pointer, free with hx509_certs_free().
 108  *
 109  * @ingroup hx509_keyset
 110  */
 111 
 112 int
 113 hx509_certs_init(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 114                  const char *name, int flags,
 115                  hx509_lock lock, hx509_certs *certs)
 116 {
 117     struct hx509_keyset_ops *ops;
 118     const char *residue;
 119     hx509_certs c;
 120     char *type;
 121     int ret;
 122 
 123     *certs = NULL;
 124 
 125     residue = strchr(name, ':');
 126     if (residue) {
 127         type = malloc(residue - name + 1);
 128         if (type)
 129             strlcpy(type, name, residue - name + 1);
 130         residue++;
 131         if (residue[0] == '\0')
 132             residue = NULL;
 133     } else {
 134         type = strdup("MEMORY");
 135         residue = name;
 136     }
 137     if (type == NULL) {
 138         hx509_clear_error_string(context);
 139         return ENOMEM;
 140     }
 141 
 142     ops = _hx509_ks_type(context, type);
 143     if (ops == NULL) {
 144         hx509_set_error_string(context, 0, ENOENT,
 145                                "Keyset type %s is not supported", type);
 146         free(type);
 147         return ENOENT;
 148     }
 149     free(type);
 150     c = calloc(1, sizeof(*c));
 151     if (c == NULL) {
 152         hx509_clear_error_string(context);
 153         return ENOMEM;
 154     }
 155     c->ops = ops;
 156     c->ref = 1;
 157 
 158     ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock);
 159     if (ret) {
 160         free(c);
 161         return ret;
 162     }
 163 
 164     *certs = c;
 165     return 0;
 166 }
 167 
 168 /**
 169  * Write the certificate store to stable storage.
 170  *
 171  * @param context A hx509 context.
 172  * @param certs a certificate store to store.
 173  * @param flags currently unused, use 0.
 174  * @param lock a lock that unlocks the certificates store, use NULL to
 175  * select no password/certifictes/prompt lock (see @ref page_lock).
 176  *
 177  * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION if
 178  * the certificate store doesn't support the store operation.
 179  *
 180  * @ingroup hx509_keyset
 181  */
 182 
 183 int
 184 hx509_certs_store(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 185                   hx509_certs certs,
 186                   int flags,
 187                   hx509_lock lock)
 188 {
 189     if (certs->ops->store == NULL) {
 190         hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
 191                                "keystore if type %s doesn't support "
 192                                "store operation",
 193                                certs->ops->name);
 194         return HX509_UNSUPPORTED_OPERATION;
 195     }
 196 
 197     return (*certs->ops->store)(context, certs, certs->ops_data, flags, lock);
 198 }
 199 
 200 
 201 hx509_certs
 202 _hx509_certs_ref(hx509_certs certs)
     /* [<][>][^][v][top][bottom][index][help] */
 203 {
 204     if (certs == NULL)
 205         return NULL;
 206     if (certs->ref == 0)
 207         _hx509_abort("certs refcount == 0 on ref");
 208     if (certs->ref == UINT_MAX)
 209         _hx509_abort("certs refcount == UINT_MAX on ref");
 210     certs->ref++;
 211     return certs;
 212 }
 213 
 214 /**
 215  * Free a certificate store.
 216  *
 217  * @param certs certificate store to free.
 218  *
 219  * @ingroup hx509_keyset
 220  */
 221 
 222 void
 223 hx509_certs_free(hx509_certs *certs)
     /* [<][>][^][v][top][bottom][index][help] */
 224 {
 225     if (*certs) {
 226         if ((*certs)->ref == 0)
 227             _hx509_abort("cert refcount == 0 on free");
 228         if (--(*certs)->ref > 0)
 229             return;
 230 
 231         (*(*certs)->ops->free)(*certs, (*certs)->ops_data);
 232         free(*certs);
 233         *certs = NULL;
 234     }
 235 }
 236 
 237 /**
 238  * Start the integration
 239  *
 240  * @param context a hx509 context.
 241  * @param certs certificate store to iterate over
 242  * @param cursor cursor that will keep track of progress, free with
 243  * hx509_certs_end_seq().
 244  *
 245  * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION is
 246  * returned if the certificate store doesn't support the iteration
 247  * operation.
 248  *
 249  * @ingroup hx509_keyset
 250  */
 251 
 252 int
 253 hx509_certs_start_seq(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 254                       hx509_certs certs,
 255                       hx509_cursor *cursor)
 256 {
 257     int ret;
 258 
 259     if (certs->ops->iter_start == NULL) {
 260         hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
 261                                "Keyset type %s doesn't support iteration",
 262                                certs->ops->name);
 263         return HX509_UNSUPPORTED_OPERATION;
 264     }
 265 
 266     ret = (*certs->ops->iter_start)(context, certs, certs->ops_data, cursor);
 267     if (ret)
 268         return ret;
 269 
 270     return 0;
 271 }
 272 
 273 /**
 274  * Get next ceritificate from the certificate keystore pointed out by
 275  * cursor.
 276  *
 277  * @param context a hx509 context.
 278  * @param certs certificate store to iterate over.
 279  * @param cursor cursor that keeps track of progress.
 280  * @param cert return certificate next in store, NULL if the store
 281  * contains no more certificates. Free with hx509_cert_free().
 282  *
 283  * @return Returns an hx509 error code.
 284  *
 285  * @ingroup hx509_keyset
 286  */
 287 
 288 int
 289 hx509_certs_next_cert(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 290                       hx509_certs certs,
 291                       hx509_cursor cursor,
 292                       hx509_cert *cert)
 293 {
 294     *cert = NULL;
 295     return (*certs->ops->iter)(context, certs, certs->ops_data, cursor, cert);
 296 }
 297 
 298 /**
 299  * End the iteration over certificates.
 300  *
 301  * @param context a hx509 context.
 302  * @param certs certificate store to iterate over.
 303  * @param cursor cursor that will keep track of progress, freed.
 304  *
 305  * @return Returns an hx509 error code.
 306  *
 307  * @ingroup hx509_keyset
 308  */
 309 
 310 int
 311 hx509_certs_end_seq(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 312                     hx509_certs certs,
 313                     hx509_cursor cursor)
 314 {
 315     (*certs->ops->iter_end)(context, certs, certs->ops_data, cursor);
 316     return 0;
 317 }
 318 
 319 /**
 320  * Iterate over all certificates in a keystore and call an function
 321  * for each fo them.
 322  *
 323  * @param context a hx509 context.
 324  * @param certs certificate store to iterate over.
 325  * @param func function to call for each certificate. The function
 326  * should return non-zero to abort the iteration, that value is passed
 327  * back to te caller of hx509_certs_iter().
 328  * @param ctx context variable that will passed to the function.
 329  *
 330  * @return Returns an hx509 error code.
 331  *
 332  * @ingroup hx509_keyset
 333  */
 334 
 335 int
 336 hx509_certs_iter(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 337                  hx509_certs certs,
 338                  int (*func)(hx509_context, void *, hx509_cert),
 339                  void *ctx)
 340 {
 341     hx509_cursor cursor;
 342     hx509_cert c;
 343     int ret;
 344 
 345     ret = hx509_certs_start_seq(context, certs, &cursor);
 346     if (ret)
 347         return ret;
 348 
 349     while (1) {
 350         ret = hx509_certs_next_cert(context, certs, cursor, &c);
 351         if (ret)
 352             break;
 353         if (c == NULL) {
 354             ret = 0;
 355             break;
 356         }
 357         ret = (*func)(context, ctx, c);
 358         hx509_cert_free(c);
 359         if (ret)
 360             break;
 361     }
 362 
 363     hx509_certs_end_seq(context, certs, cursor);
 364 
 365     return ret;
 366 }
 367 
 368 
 369 /**
 370  * Function to use to hx509_certs_iter() as a function argument, the
 371  * ctx variable to hx509_certs_iter() should be a FILE file descriptor.
 372  *
 373  * @param context a hx509 context.
 374  * @param ctx used by hx509_certs_iter().
 375  * @param c a certificate
 376  *
 377  * @return Returns an hx509 error code.
 378  *
 379  * @ingroup hx509_keyset
 380  */
 381 
 382 int
 383 hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c)
     /* [<][>][^][v][top][bottom][index][help] */
 384 {
 385     Certificate *cert;
 386     hx509_name n;
 387     char *s, *i;
 388 
 389     cert = _hx509_get_cert(c);
 390 
 391     _hx509_name_from_Name(&cert->tbsCertificate.subject, &n);
 392     hx509_name_to_string(n, &s);
 393     hx509_name_free(&n);
 394     _hx509_name_from_Name(&cert->tbsCertificate.issuer, &n);
 395     hx509_name_to_string(n, &i);
 396     hx509_name_free(&n);
 397     fprintf(ctx, "subject: %s\nissuer: %s\n", s, i);
 398     free(s);
 399     free(i);
 400     return 0;
 401 }
 402 
 403 /**
 404  * Add a certificate to the certificiate store.
 405  *
 406  * The receiving keyset certs will either increase reference counter
 407  * of the cert or make a deep copy, either way, the caller needs to
 408  * free the cert itself.
 409  *
 410  * @param context a hx509 context.
 411  * @param certs certificate store to add the certificate to.
 412  * @param cert certificate to add.
 413  *
 414  * @return Returns an hx509 error code.
 415  *
 416  * @ingroup hx509_keyset
 417  */
 418 
 419 int
 420 hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
     /* [<][>][^][v][top][bottom][index][help] */
 421 {
 422     if (certs->ops->add == NULL) {
 423         hx509_set_error_string(context, 0, ENOENT,
 424                                "Keyset type %s doesn't support add operation",
 425                                certs->ops->name);
 426         return ENOENT;
 427     }
 428 
 429     return (*certs->ops->add)(context, certs, certs->ops_data, cert);
 430 }
 431 
 432 /**
 433  * Find a certificate matching the query.
 434  *
 435  * @param context a hx509 context.
 436  * @param certs certificate store to search.
 437  * @param q query allocated with @ref hx509_query functions.
 438  * @param r return certificate (or NULL on error), should be freed
 439  * with hx509_cert_free().
 440  *
 441  * @return Returns an hx509 error code.
 442  *
 443  * @ingroup hx509_keyset
 444  */
 445 
 446 int
 447 hx509_certs_find(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 448                  hx509_certs certs,
 449                  const hx509_query *q,
 450                  hx509_cert *r)
 451 {
 452     hx509_cursor cursor;
 453     hx509_cert c;
 454     int ret;
 455 
 456     *r = NULL;
 457 
 458     _hx509_query_statistic(context, 0, q);
 459 
 460     if (certs->ops->query)
 461         return (*certs->ops->query)(context, certs, certs->ops_data, q, r);
 462 
 463     ret = hx509_certs_start_seq(context, certs, &cursor);
 464     if (ret)
 465         return ret;
 466 
 467     c = NULL;
 468     while (1) {
 469         ret = hx509_certs_next_cert(context, certs, cursor, &c);
 470         if (ret)
 471             break;
 472         if (c == NULL)
 473             break;
 474         if (_hx509_query_match_cert(context, q, c)) {
 475             *r = c;
 476             break;
 477         }
 478         hx509_cert_free(c);
 479     }
 480 
 481     hx509_certs_end_seq(context, certs, cursor);
 482     if (ret)
 483         return ret;
 484     if (c == NULL) {
 485         hx509_clear_error_string(context);
 486         return HX509_CERT_NOT_FOUND;
 487     }
 488 
 489     return 0;
 490 }
 491 
 492 static int
 493 certs_merge_func(hx509_context context, void *ctx, hx509_cert c)
     /* [<][>][^][v][top][bottom][index][help] */
 494 {
 495     return hx509_certs_add(context, (hx509_certs)ctx, c);
 496 }
 497 
 498 /**
 499  * Merge a certificate store into another. The from store is keep
 500  * intact.
 501  *
 502  * @param context a hx509 context.
 503  * @param to the store to merge into.
 504  * @param from the store to copy the object from.
 505  *
 506  * @return Returns an hx509 error code.
 507  *
 508  * @ingroup hx509_keyset
 509  */
 510 
 511 int
 512 hx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from)
     /* [<][>][^][v][top][bottom][index][help] */
 513 {
 514     if (from == NULL)
 515         return 0;
 516     return hx509_certs_iter(context, from, certs_merge_func, to);
 517 }
 518 
 519 /**
 520  * Same a hx509_certs_merge() but use a lock and name to describe the
 521  * from source.
 522  *
 523  * @param context a hx509 context.
 524  * @param to the store to merge into.
 525  * @param lock a lock that unlocks the certificates store, use NULL to
 526  * select no password/certifictes/prompt lock (see @ref page_lock).
 527  * @param name name of the source store
 528  *
 529  * @return Returns an hx509 error code.
 530  *
 531  * @ingroup hx509_keyset
 532  */
 533 
 534 int
 535 hx509_certs_append(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 536                    hx509_certs to,
 537                    hx509_lock lock,
 538                    const char *name)
 539 {
 540     hx509_certs s;
 541     int ret;
 542 
 543     ret = hx509_certs_init(context, name, 0, lock, &s);
 544     if (ret)
 545         return ret;
 546     ret = hx509_certs_merge(context, to, s);
 547     hx509_certs_free(&s);
 548     return ret;
 549 }
 550 
 551 /**
 552  * Get one random certificate from the certificate store.
 553  *
 554  * @param context a hx509 context.
 555  * @param certs a certificate store to get the certificate from.
 556  * @param c return certificate, should be freed with hx509_cert_free().
 557  *
 558  * @return Returns an hx509 error code.
 559  *
 560  * @ingroup hx509_keyset
 561  */
 562 
 563 int
 564 hx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c)
     /* [<][>][^][v][top][bottom][index][help] */
 565 {
 566     hx509_cursor cursor;
 567     int ret;
 568 
 569     *c = NULL;
 570 
 571     ret = hx509_certs_start_seq(context, certs, &cursor);
 572     if (ret)
 573         return ret;
 574 
 575     ret = hx509_certs_next_cert(context, certs, cursor, c);
 576     if (ret)
 577         return ret;
 578 
 579     hx509_certs_end_seq(context, certs, cursor);
 580     return 0;
 581 }
 582 
 583 static int
 584 certs_info_stdio(void *ctx, const char *str)
     /* [<][>][^][v][top][bottom][index][help] */
 585 {
 586     FILE *f = ctx;
 587     fprintf(f, "%s\n", str);
 588     return 0;
 589 }
 590 
 591 /**
 592  * Print some info about the certificate store.
 593  *
 594  * @param context a hx509 context.
 595  * @param certs certificate store to print information about.
 596  * @param func function that will get each line of the information, if
 597  * NULL is used the data is printed on a FILE descriptor that should
 598  * be passed in ctx, if ctx also is NULL, stdout is used.
 599  * @param ctx parameter to func.
 600  *
 601  * @return Returns an hx509 error code.
 602  *
 603  * @ingroup hx509_keyset
 604  */
 605 
 606 int
 607 hx509_certs_info(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 608                  hx509_certs certs,
 609                  int (*func)(void *, const char *),
 610                  void *ctx)
 611 {
 612     if (func == NULL) {
 613         func = certs_info_stdio;
 614         if (ctx == NULL)
 615             ctx = stdout;
 616     }
 617     if (certs->ops->printinfo == NULL) {
 618         (*func)(ctx, "No info function for certs");
 619         return 0;
 620     }
 621     return (*certs->ops->printinfo)(context, certs, certs->ops_data,
 622                                     func, ctx);
 623 }
 624 
 625 void
 626 _hx509_pi_printf(int (*func)(void *, const char *), void *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 627                  const char *fmt, ...)
 628 {
 629     va_list ap;
 630     char *str;
 631 
 632     va_start(ap, fmt);
 633     vasprintf(&str, fmt, ap);
 634     va_end(ap);
 635     if (str == NULL)
 636         return;
 637     (*func)(ctx, str);
 638     free(str);
 639 }
 640 
 641 int
 642 _hx509_certs_keys_get(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 643                       hx509_certs certs,
 644                       hx509_private_key **keys)
 645 {
 646     if (certs->ops->getkeys == NULL) {
 647         *keys = NULL;
 648         return 0;
 649     }
 650     return (*certs->ops->getkeys)(context, certs, certs->ops_data, keys);
 651 }
 652 
 653 int
 654 _hx509_certs_keys_add(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 655                       hx509_certs certs,
 656                       hx509_private_key key)
 657 {
 658     if (certs->ops->addkey == NULL) {
 659         hx509_set_error_string(context, 0, EINVAL,
 660                                "keystore if type %s doesn't support "
 661                                "key add operation",
 662                                certs->ops->name);
 663         return EINVAL;
 664     }
 665     return (*certs->ops->addkey)(context, certs, certs->ops_data, key);
 666 }
 667 
 668 
 669 void
 670 _hx509_certs_keys_free(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 671                        hx509_private_key *keys)
 672 {
 673     int i;
 674     for (i = 0; keys[i]; i++)
 675         _hx509_private_key_free(&keys[i]);
 676     free(keys);
 677 }

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