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