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