1 2 /* 3 * Copyright (C) Valentin V. Bartenev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 #include <nxt_conf.h> 9 #include <nxt_cert.h> 10 11 #include <dirent.h> 12 13 #include <openssl/bio.h> 14 #include <openssl/pem.h> 15 #include <openssl/evp.h> 16 #include <openssl/x509.h> 17 #include <openssl/x509v3.h> 18 #include <openssl/rsa.h> 19 #include <openssl/err.h> 20 21 22 struct nxt_cert_s { 23 EVP_PKEY *key; 24 nxt_uint_t count; 25 X509 *chain[]; 26 }; 27 28 29 typedef struct { 30 nxt_str_t name; 31 nxt_conf_value_t *value; 32 nxt_mp_t *mp; 33 } nxt_cert_info_t; 34 35 36 typedef struct { 37 nxt_str_t name; 38 nxt_fd_t fd; 39 } nxt_cert_item_t; 40 41 42 static nxt_cert_t *nxt_cert_fd(nxt_task_t *task, nxt_fd_t fd); 43 static nxt_cert_t *nxt_cert_bio(nxt_task_t *task, BIO *bio); 44 static int nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix); 45 46 static nxt_conf_value_t *nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert); 47 static nxt_conf_value_t *nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, 48 nxt_bool_t issuer); 49 static nxt_conf_value_t *nxt_cert_alt_names_details(nxt_mp_t *mp, 50 STACK_OF(GENERAL_NAME) *alt_names); 51 52 53 static nxt_lvlhsh_t nxt_cert_info; 54 55 56 nxt_cert_t * 57 nxt_cert_mem(nxt_task_t *task, nxt_buf_mem_t *mbuf) 58 { 59 BIO *bio; 60 nxt_cert_t *cert; 61 62 bio = BIO_new_mem_buf(mbuf->pos, nxt_buf_mem_used_size(mbuf)); 63 if (nxt_slow_path(bio == NULL)) { 64 nxt_openssl_log_error(task, NXT_LOG_ALERT, "BIO_new_mem_buf() failed"); 65 return NULL; 66 } 67 68 cert = nxt_cert_bio(task, bio); 69 70 BIO_free(bio); 71 72 return cert; 73 } 74 75 76 static nxt_cert_t * 77 nxt_cert_fd(nxt_task_t *task, nxt_fd_t fd) 78 { 79 BIO *bio; 80 nxt_cert_t *cert; 81 82 bio = BIO_new_fd(fd, 0); 83 if (nxt_slow_path(bio == NULL)) { 84 nxt_openssl_log_error(task, NXT_LOG_ALERT, "BIO_new_fd() failed"); 85 return NULL; 86 } 87 88 cert = nxt_cert_bio(task, bio); 89 90 BIO_free(bio); 91 92 return cert; 93 } 94 95 96 static nxt_cert_t * 97 nxt_cert_bio(nxt_task_t *task, BIO *bio) 98 { 99 int ret, suffix, key_id; 100 long length, reason; 101 char *type, *header; 102 X509 *x509; 103 EVP_PKEY *key; 104 nxt_uint_t nalloc; 105 nxt_cert_t *cert, *new_cert; 106 u_char *data; 107 const u_char *data_copy; 108 PKCS8_PRIV_KEY_INFO *p8inf; 109 const EVP_PKEY_ASN1_METHOD *ameth; 110 111 nalloc = 4; 112 113 cert = nxt_zalloc(sizeof(nxt_cert_t) + nalloc * sizeof(X509 *)); 114 if (cert == NULL) { 115 return NULL; 116 } 117 118 for ( ;; ) { 119 ret = PEM_read_bio(bio, &type, &header, &data, &length); 120 121 if (ret == 0) { 122 reason = ERR_GET_REASON(ERR_peek_last_error()); 123 if (reason != PEM_R_NO_START_LINE) { 124 nxt_openssl_log_error(task, NXT_LOG_ALERT, 125 "PEM_read_bio() failed"); 126 goto fail; 127 } 128 129 ERR_clear_error(); 130 break; 131 } 132 133 nxt_debug(task, "PEM type: \"%s\"", type); 134 135 key = NULL; 136 x509 = NULL; 137 /* 138 EVP_CIPHER_INFO cipher; 139 140 if (PEM_get_EVP_CIPHER_INFO(header, &cipher) != 0) { 141 nxt_alert(task, "encrypted PEM isn't supported"); 142 goto done; 143 } 144 */ 145 if (nxt_strcmp(type, PEM_STRING_PKCS8) == 0) { 146 nxt_alert(task, "PEM PKCS8 isn't supported"); 147 goto done; 148 } 149 150 if (nxt_strcmp(type, PEM_STRING_PKCS8INF) == 0) { 151 data_copy = data; 152 153 p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &data_copy, length); 154 155 if (p8inf == NULL) { 156 nxt_openssl_log_error(task, NXT_LOG_ALERT, 157 "d2i_PKCS8_PRIV_KEY_INFO() failed"); 158 goto done; 159 } 160 161 key = EVP_PKCS82PKEY(p8inf); 162 163 PKCS8_PRIV_KEY_INFO_free(p8inf); 164 goto done; 165 } 166 167 suffix = nxt_nxt_cert_pem_suffix(type, PEM_STRING_PKCS8INF); 168 169 if (suffix != 0) { 170 171 ameth = EVP_PKEY_asn1_find_str(NULL, type, suffix); 172 if (ameth == NULL) { 173 nxt_openssl_log_error(task, NXT_LOG_ALERT, 174 "EVP_PKEY_asn1_find_str() failed"); 175 goto done; 176 } 177 178 EVP_PKEY_asn1_get0_info(&key_id, NULL, NULL, NULL, NULL, ameth); 179 180 data_copy = data; 181 182 key = d2i_PrivateKey(key_id, NULL, &data_copy, length); 183 goto done; 184 } 185 186 if (nxt_strcmp(type, PEM_STRING_X509) == 0 187 || nxt_strcmp(type, PEM_STRING_X509_OLD) == 0) 188 { 189 data_copy = data; 190 191 x509 = d2i_X509(NULL, &data_copy, length); 192 if (x509 == NULL) { 193 nxt_openssl_log_error(task, NXT_LOG_ALERT, 194 "d2i_X509() failed"); 195 } 196 197 goto done; 198 } 199 200 if (nxt_strcmp(type, PEM_STRING_X509_TRUSTED) == 0) { 201 data_copy = data; 202 203 x509 = d2i_X509_AUX(NULL, &data_copy, length); 204 if (x509 == NULL) { 205 nxt_openssl_log_error(task, NXT_LOG_ALERT, 206 "d2i_X509_AUX() failed"); 207 } 208 209 goto done; 210 } 211 212 nxt_alert(task, "unsupported PEM type: \"%s\"", type); 213 214 done: 215 216 OPENSSL_free(data); 217 OPENSSL_free(header); 218 OPENSSL_free(type); 219 220 if (key != NULL) { 221 if (cert->key != NULL) { 222 EVP_PKEY_free(key); 223 nxt_alert(task, "multiple private keys in PEM"); 224 goto fail; 225 } 226 227 cert->key = key; 228 continue; 229 } 230 231 if (x509 != NULL) { 232 233 if (cert->count == nalloc) { 234 nalloc += 4; 235 236 new_cert = nxt_realloc(cert, sizeof(nxt_cert_t) 237 + nalloc * sizeof(X509 *)); 238 if (new_cert == NULL) { 239 X509_free(x509); 240 goto fail; 241 } 242 243 nxt_free(cert); 244 cert = new_cert; 245 } 246 247 cert->chain[cert->count++] = x509; 248 continue; 249 } 250 251 goto fail; 252 } 253 254 if (cert->key == NULL) { 255 nxt_alert(task, "no key found"); 256 goto fail; 257 } 258 259 if (cert->count == 0) { 260 nxt_alert(task, "no certificates found"); 261 goto fail; 262 } 263 264 return cert; 265 266 fail: 267 268 nxt_cert_destroy(cert); 269 270 return NULL; 271 } 272 273 274 static int 275 nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix) 276 { 277 char *p; 278 nxt_uint_t pem_len, suffix_len; 279 280 pem_len = strlen(pem_str); 281 suffix_len = strlen(suffix); 282 283 if (suffix_len + 1 >= pem_len) { 284 return 0; 285 } 286 287 p = pem_str + pem_len - suffix_len; 288 289 if (nxt_strcmp(p, suffix) != 0) { 290 return 0; 291 } 292 293 p--; 294 295 if (*p != ' ') { 296 return 0; 297 } 298 299 return p - pem_str; 300 } 301 302 303 void 304 nxt_cert_destroy(nxt_cert_t *cert) 305 { 306 nxt_uint_t i; 307 308 EVP_PKEY_free(cert->key); 309 310 for (i = 0; i != cert->count; i++) { 311 X509_free(cert->chain[i]); 312 } 313 314 nxt_free(cert); 315 } 316 317 318 319 static nxt_int_t 320 nxt_cert_info_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 321 { 322 nxt_cert_info_t *info; 323 324 info = data; 325 326 if (nxt_strcasestr_eq(&lhq->key, &info->name)) { 327 return NXT_OK; 328 } 329 330 return NXT_DECLINED; 331 } 332 333 334 static const nxt_lvlhsh_proto_t nxt_cert_info_hash_proto 335 nxt_aligned(64) = 336 { 337 NXT_LVLHSH_DEFAULT, 338 nxt_cert_info_hash_test, 339 nxt_lvlhsh_alloc, 340 nxt_lvlhsh_free, 341 }; 342 343 344 void 345 nxt_cert_info_init(nxt_task_t *task, nxt_array_t *certs) 346 { 347 uint32_t i; 348 nxt_cert_t *cert; 349 nxt_cert_item_t *items; 350 351 for (items = certs->elts, i = 0; i < certs->nelts; i++) { 352 cert = nxt_cert_fd(task, items[i].fd); 353 354 if (nxt_slow_path(cert == NULL)) { 355 continue; 356 } 357 358 (void) nxt_cert_info_save(&items[i].name, cert); 359 360 nxt_cert_destroy(cert); 361 } 362 } 363 364 365 nxt_int_t 366 nxt_cert_info_save(nxt_str_t *name, nxt_cert_t *cert) 367 { 368 nxt_mp_t *mp; 369 nxt_int_t ret; 370 nxt_cert_info_t *info; 371 nxt_conf_value_t *value; 372 nxt_lvlhsh_query_t lhq; 373 374 mp = nxt_mp_create(1024, 128, 256, 32); 375 if (nxt_slow_path(mp == NULL)) { 376 return NXT_ERROR; 377 } 378 379 info = nxt_mp_get(mp, sizeof(nxt_cert_info_t)); 380 if (nxt_slow_path(info == NULL)) { 381 goto fail; 382 } 383 384 name = nxt_str_dup(mp, &info->name, name); 385 if (nxt_slow_path(name == NULL)) { 386 goto fail; 387 } 388 389 value = nxt_cert_details(mp, cert); 390 if (nxt_slow_path(value == NULL)) { 391 goto fail; 392 } 393 394 info->mp = mp; 395 info->value = value; 396 397 lhq.key_hash = nxt_djb_hash(name->start, name->length); 398 lhq.replace = 1; 399 lhq.key = *name; 400 lhq.value = info; 401 lhq.proto = &nxt_cert_info_hash_proto; 402 403 ret = nxt_lvlhsh_insert(&nxt_cert_info, &lhq); 404 if (nxt_slow_path(ret != NXT_OK)) { 405 goto fail; 406 } 407 408 if (lhq.value != info) { 409 info = lhq.value; 410 nxt_mp_destroy(info->mp); 411 } 412 413 return NXT_OK; 414 415 fail: 416 417 nxt_mp_destroy(mp); 418 return NXT_ERROR; 419 } 420 421 422 nxt_conf_value_t * 423 nxt_cert_info_get(nxt_str_t *name) 424 { 425 nxt_int_t ret; 426 nxt_cert_info_t *info; 427 nxt_lvlhsh_query_t lhq; 428 429 lhq.key_hash = nxt_djb_hash(name->start, name->length); 430 lhq.key = *name; 431 lhq.proto = &nxt_cert_info_hash_proto; 432 433 ret = nxt_lvlhsh_find(&nxt_cert_info, &lhq); 434 if (ret != NXT_OK) { 435 return NULL; 436 } 437 438 info = lhq.value; 439 440 return info->value; 441 } 442 443 444 nxt_conf_value_t * 445 nxt_cert_info_get_all(nxt_mp_t *mp) 446 { 447 uint32_t i; 448 nxt_cert_info_t *info; 449 nxt_conf_value_t *all; 450 nxt_lvlhsh_each_t lhe; 451 452 nxt_lvlhsh_each_init(&lhe, &nxt_cert_info_hash_proto); 453 454 i = 0; 455 456 for ( ;; ) { 457 info = nxt_lvlhsh_each(&nxt_cert_info, &lhe); 458 459 if (info == NULL) { 460 break; 461 } 462 463 i++; 464 } 465 466 all = nxt_conf_create_object(mp, i); 467 if (nxt_slow_path(all == NULL)) { 468 return NULL; 469 } 470 471 nxt_lvlhsh_each_init(&lhe, &nxt_cert_info_hash_proto); 472 473 i = 0; 474 475 for ( ;; ) { 476 info = nxt_lvlhsh_each(&nxt_cert_info, &lhe); 477 478 if (info == NULL) { 479 break; 480 } 481 482 nxt_conf_set_member(all, &info->name, info->value, i); 483 484 i++; 485 } 486 487 return all; 488 } 489 490 491 static nxt_conf_value_t * 492 nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert) 493 { 494 BIO *bio; 495 X509 *x509; 496 u_char *end; 497 EVP_PKEY *key; 498 ASN1_TIME *asn1_time; 499 nxt_str_t str; 500 nxt_int_t ret; 501 nxt_uint_t i; 502 nxt_conf_value_t *object, *chain, *element, *value; 503 u_char buf[256]; 504 505 static nxt_str_t key_str = nxt_string("key"); 506 static nxt_str_t chain_str = nxt_string("chain"); 507 static nxt_str_t since_str = nxt_string("since"); 508 static nxt_str_t until_str = nxt_string("until"); 509 static nxt_str_t issuer_str = nxt_string("issuer"); 510 static nxt_str_t subject_str = nxt_string("subject"); 511 static nxt_str_t validity_str = nxt_string("validity"); 512 513 object = nxt_conf_create_object(mp, 2); 514 if (nxt_slow_path(object == NULL)) { 515 return NULL; 516 } 517 518 if (cert->key != NULL) { 519 key = cert->key; 520 521 switch (EVP_PKEY_base_id(key)) { 522 case EVP_PKEY_RSA: 523 end = nxt_sprintf(buf, buf + sizeof(buf), "RSA (%d bits)", 524 EVP_PKEY_bits(key)); 525 526 str.length = end - buf; 527 str.start = buf; 528 break; 529 530 case EVP_PKEY_DH: 531 end = nxt_sprintf(buf, buf + sizeof(buf), "DH (%d bits)", 532 EVP_PKEY_bits(key)); 533 534 str.length = end - buf; 535 str.start = buf; 536 break; 537 538 case EVP_PKEY_EC: 539 nxt_str_set(&str, "ECDH"); 540 break; 541 542 default: 543 nxt_str_set(&str, "unknown"); 544 } 545 546 ret = nxt_conf_set_member_string_dup(object, mp, &key_str, &str, 0); 547 548 if (nxt_slow_path(ret != NXT_OK)) { 549 return NULL; 550 } 551 552 } else { 553 nxt_conf_set_member_null(object, &key_str, 0); 554 } 555 556 chain = nxt_conf_create_array(mp, cert->count); 557 if (nxt_slow_path(chain == NULL)) { 558 return NULL; 559 } 560 561 for (i = 0; i < cert->count; i++) { 562 element = nxt_conf_create_object(mp, 3); 563 if (nxt_slow_path(element == NULL)) { 564 return NULL; 565 } 566 567 x509 = cert->chain[i]; 568 569 value = nxt_cert_name_details(mp, x509, 0); 570 if (value == NULL) { 571 return NULL; 572 } 573 574 nxt_conf_set_member(element, &subject_str, value, 0); 575 576 value = nxt_cert_name_details(mp, x509, 1); 577 if (value == NULL) { 578 return NULL; 579 } 580 581 nxt_conf_set_member(element, &issuer_str, value, 1); 582 583 value = nxt_conf_create_object(mp, 2); 584 if (nxt_slow_path(value == NULL)) { 585 return NULL; 586 } 587 588 bio = BIO_new(BIO_s_mem()); 589 if (nxt_slow_path(bio == NULL)) { 590 return NULL; 591 } 592 593 asn1_time = X509_get_notBefore(x509); 594 595 ret = ASN1_TIME_print(bio, asn1_time); 596 597 if (nxt_fast_path(ret == 1)) { 598 str.length = BIO_get_mem_data(bio, &str.start); 599 ret = nxt_conf_set_member_string_dup(value, mp, &since_str, &str, 600 0); 601 } else { 602 ret = NXT_ERROR; 603 } 604 605 BIO_free(bio); 606 607 if (nxt_slow_path(ret != NXT_OK)) { 608 return NULL; 609 } 610 611 bio = BIO_new(BIO_s_mem()); 612 if (nxt_slow_path(bio == NULL)) { 613 return NULL; 614 } 615 616 asn1_time = X509_get_notAfter(x509); 617 618 ret = ASN1_TIME_print(bio, asn1_time); 619 620 if (nxt_fast_path(ret == 1)) { 621 str.length = BIO_get_mem_data(bio, &str.start); 622 ret = nxt_conf_set_member_string_dup(value, mp, &until_str, &str, 623 1); 624 } else { 625 ret = NXT_ERROR; 626 } 627 628 BIO_free(bio); 629 630 if (nxt_slow_path(ret != NXT_OK)) { 631 return NULL; 632 } 633 634 nxt_conf_set_member(element, &validity_str, value, 2); 635 636 nxt_conf_set_element(chain, i, element); 637 } 638 639 nxt_conf_set_member(object, &chain_str, chain, 1); 640 641 return object; 642 } 643 644 645 typedef struct { 646 int nid; 647 nxt_str_t name; 648 } nxt_cert_nid_t; 649 650 651 static nxt_conf_value_t * 652 nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer) 653 { 654 int len; 655 X509_NAME *x509_name; 656 nxt_str_t str; 657 nxt_int_t ret; 658 nxt_uint_t i, n, count; 659 nxt_conf_value_t *object, *names; 660 STACK_OF(GENERAL_NAME) *alt_names; 661 u_char buf[256]; 662 663 static nxt_cert_nid_t nids[] = { 664 { NID_commonName, nxt_string("common_name") }, 665 { NID_countryName, nxt_string("country") }, 666 { NID_stateOrProvinceName, nxt_string("state_or_province") }, 667 { NID_localityName, nxt_string("locality") }, 668 { NID_organizationName, nxt_string("organization") }, 669 { NID_organizationalUnitName, nxt_string("department") }, 670 }; 671 672 static nxt_str_t alt_names_str = nxt_string("alt_names"); 673 674 count = 0; 675 676 x509_name = issuer ? X509_get_issuer_name(x509) 677 : X509_get_subject_name(x509); 678 679 for (n = 0; n != nxt_nitems(nids); n++) { 680 681 if (X509_NAME_get_index_by_NID(x509_name, nids[n].nid, -1) < 0) { 682 continue; 683 } 684 685 count++; 686 } 687 688 alt_names = X509_get_ext_d2i(x509, issuer ? NID_issuer_alt_name 689 : NID_subject_alt_name, 690 NULL, NULL); 691 692 if (alt_names != NULL) { 693 count++; 694 } 695 696 object = nxt_conf_create_object(mp, count); 697 if (nxt_slow_path(object == NULL)) { 698 goto fail; 699 } 700 701 for (n = 0, i = 0; n != nxt_nitems(nids) && i != count; n++) { 702 703 len = X509_NAME_get_text_by_NID(x509_name, nids[n].nid, 704 (char *) buf, sizeof(buf)); 705 706 if (len < 0) { 707 continue; 708 } 709 710 if (i == 1 && alt_names != NULL) { 711 i++; 712 } 713 714 str.length = len; 715 str.start = buf; 716 717 ret = nxt_conf_set_member_string_dup(object, mp, &nids[n].name, 718 &str, i++); 719 if (nxt_slow_path(ret != NXT_OK)) { 720 goto fail; 721 } 722 } 723 724 if (alt_names != NULL) { 725 names = nxt_cert_alt_names_details(mp, alt_names); 726 727 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 728 729 if (nxt_slow_path(names == NULL)) { 730 return NULL; 731 } 732 733 nxt_conf_set_member(object, &alt_names_str, names, 1); 734 } 735 736 return object; 737 738 fail: 739 740 if (alt_names != NULL) { 741 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 742 } 743 744 return NULL; 745 } 746 747 748 static nxt_conf_value_t * 749 nxt_cert_alt_names_details(nxt_mp_t *mp, STACK_OF(GENERAL_NAME) *alt_names) 750 { 751 nxt_str_t str; 752 nxt_int_t ret; 753 nxt_uint_t i, n, count; 754 GENERAL_NAME *name; 755 nxt_conf_value_t *array; 756 757 count = sk_GENERAL_NAME_num(alt_names); 758 n = 0; 759 760 for (i = 0; i != count; i++) { 761 name = sk_GENERAL_NAME_value(alt_names, i); 762 763 if (name->type != GEN_DNS) { 764 continue; 765 } 766 767 n++; 768 } 769 770 array = nxt_conf_create_array(mp, n); 771 if (nxt_slow_path(array == NULL)) { 772 return NULL; 773 } 774 775 for (n = 0, i = 0; n != count; n++) { 776 name = sk_GENERAL_NAME_value(alt_names, n); 777 778 if (name->type != GEN_DNS) { 779 continue; 780 } 781 782 str.length = ASN1_STRING_length(name->d.dNSName); 783 #if OPENSSL_VERSION_NUMBER > 0x10100000L 784 str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); 785 #else 786 str.start = ASN1_STRING_data(name->d.dNSName); 787 #endif 788 789 ret = nxt_conf_set_element_string_dup(array, mp, i++, &str); 790 if (nxt_slow_path(ret != NXT_OK)) { 791 return NULL; 792 } 793 } 794 795 return array; 796 } 797 798 799 nxt_int_t 800 nxt_cert_info_delete(nxt_str_t *name) 801 { 802 nxt_int_t ret; 803 nxt_cert_info_t *info; 804 nxt_lvlhsh_query_t lhq; 805 806 lhq.key_hash = nxt_djb_hash(name->start, name->length); 807 lhq.key = *name; 808 lhq.proto = &nxt_cert_info_hash_proto; 809 810 ret = nxt_lvlhsh_delete(&nxt_cert_info, &lhq); 811 812 if (ret == NXT_OK) { 813 info = lhq.value; 814 nxt_mp_destroy(info->mp); 815 } 816 817 return ret; 818 } 819 820 821 822 nxt_array_t * 823 nxt_cert_store_load(nxt_task_t *task, nxt_mp_t *mp) 824 { 825 DIR *dir; 826 size_t size, alloc; 827 u_char *buf, *p; 828 nxt_str_t name; 829 nxt_int_t ret; 830 nxt_file_t file; 831 nxt_array_t *certs; 832 nxt_runtime_t *rt; 833 struct dirent *de; 834 nxt_cert_item_t *item; 835 836 rt = task->thread->runtime; 837 838 if (nxt_slow_path(rt->certs.start == NULL)) { 839 nxt_alert(task, "no certificates storage directory"); 840 return NULL; 841 } 842 843 certs = nxt_array_create(mp, 16, sizeof(nxt_cert_item_t)); 844 if (nxt_slow_path(certs == NULL)) { 845 return NULL; 846 } 847 848 buf = NULL; 849 alloc = 0; 850 851 dir = opendir((char *) rt->certs.start); 852 if (nxt_slow_path(dir == NULL)) { 853 nxt_alert(task, "opendir(\"%s\") failed %E", 854 rt->certs.start, nxt_errno); 855 goto fail; 856 } 857 858 for ( ;; ) { 859 de = readdir(dir); 860 if (de == NULL) { 861 break; 862 } 863 864 nxt_debug(task, "readdir(\"%s\"): \"%s\"", rt->certs.start, de->d_name); 865 866 name.length = nxt_strlen(de->d_name); 867 name.start = (u_char *) de->d_name; 868 869 if (nxt_str_eq(&name, ".", 1) || nxt_str_eq(&name, "..", 2)) { 870 continue; 871 } 872 873 item = nxt_array_add(certs); 874 if (nxt_slow_path(item == NULL)) { 875 goto fail; 876 } 877 878 item->fd = -1; 879 880 size = rt->certs.length + name.length + 1; 881 882 if (size > alloc) { 883 size += 32; 884 885 p = nxt_realloc(buf, size); 886 if (p == NULL) { 887 goto fail; 888 } 889 890 alloc = size; 891 buf = p; 892 } 893 894 p = nxt_cpymem(buf, rt->certs.start, rt->certs.length); 895 p = nxt_cpymem(p, name.start, name.length + 1); 896 897 nxt_memzero(&file, sizeof(nxt_file_t)); 898 899 file.name = buf; 900 901 ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 902 NXT_FILE_OWNER_ACCESS); 903 904 905 if (nxt_slow_path(ret != NXT_OK)) { 906 nxt_array_remove_last(certs); 907 continue; 908 } 909 910 item->fd = file.fd; 911 912 if (nxt_slow_path(nxt_str_dup(mp, &item->name, &name) == NULL)) { 913 goto fail; 914 } 915 } 916 917 if (buf != NULL) { 918 nxt_free(buf); 919 } 920 921 (void) closedir(dir); 922 923 return certs; 924 925 fail: 926 927 if (buf != NULL) { 928 nxt_free(buf); 929 } 930 931 if (dir != NULL) { 932 (void) closedir(dir); 933 } 934 935 nxt_cert_store_release(certs); 936 937 return NULL; 938 } 939 940 941 void 942 nxt_cert_store_release(nxt_array_t *certs) 943 { 944 uint32_t i; 945 nxt_cert_item_t *items; 946 947 for (items = certs->elts, i = 0; 948 i < certs->nelts; 949 i++) 950 { 951 nxt_fd_close(items[i].fd); 952 } 953 954 nxt_array_destroy(certs); 955 } 956 957 958 #if 0 959 960 void 961 nxt_cert_store_discovery_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 962 { 963 DIR *dir; 964 size_t size; 965 nxt_buf_t *b; 966 nxt_int_t ret; 967 nxt_port_t *port; 968 nxt_runtime_t *rt; 969 struct dirent *de; 970 971 port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 972 msg->port_msg.reply_port); 973 974 if (nxt_slow_path(port == NULL)) { 975 return; 976 } 977 978 b = NULL; 979 dir = NULL; 980 981 rt = task->thread->runtime; 982 983 if (nxt_slow_path(rt->certs.start == NULL)) { 984 nxt_alert(task, "no certificates storage directory"); 985 goto fail; 986 } 987 988 dir = opendir((char *) rt->certs.start); 989 if (nxt_slow_path(dir == NULL)) { 990 nxt_alert(task, "opendir(\"%s\") failed %E", 991 rt->certs.start, nxt_errno); 992 goto fail; 993 } 994 995 size = 0; 996 997 for ( ;; ) { 998 de = readdir(dir); 999 if (de == NULL) { 1000 break; 1001 } 1002 1003 if (de->d_type != DT_REG) { 1004 continue; 1005 } 1006 1007 size += nxt_strlen(de->d_name) + 1; 1008 } 1009 1010 b = nxt_port_mmap_get_buf(task, port, size); 1011 if (nxt_slow_path(b == NULL)) { 1012 goto fail; 1013 } 1014 1015 rewinddir(dir); 1016 1017 for ( ;; ) { 1018 de = readdir(dir); 1019 if (de == NULL) { 1020 break; 1021 } 1022 1023 if (de->d_type != DT_REG) { 1024 continue; 1025 } 1026 1027 size = nxt_strlen(de->d_name) + 1; 1028 1029 if (nxt_slow_path(size > (size_t) nxt_buf_mem_free_size(&b->mem))) { 1030 b->mem.free = b->mem.start; 1031 break; 1032 } 1033 1034 b->mem.free = nxt_cpymem(b->mem.free, de->d_name, size); 1035 } 1036 1037 (void) closedir(dir); 1038 dir = NULL; 1039 1040 if (nxt_slow_path(nxt_buf_mem_free_size(&b->mem) != 0)) { 1041 nxt_alert(task, "certificates storage directory " 1042 "has changed while reading it"); 1043 goto fail; 1044 } 1045 1046 ret = nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST, -1, 1047 msg->port_msg.stream, 0, b); 1048 1049 if (nxt_fast_path(ret == NXT_OK)) { 1050 return; 1051 } 1052 1053 fail: 1054 1055 if (dir != NULL) { 1056 (void) closedir(dir); 1057 } 1058 1059 if (b != NULL) { 1060 b->completion_handler(task, b, b->parent); 1061 } 1062 1063 (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1, 1064 msg->port_msg.stream, 0, NULL); 1065 } 1066 1067 #endif 1068 1069 1070 void 1071 nxt_cert_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp, 1072 nxt_port_rpc_handler_t handler, void *ctx) 1073 { 1074 uint32_t stream; 1075 nxt_int_t ret; 1076 nxt_buf_t *b; 1077 nxt_port_t *main_port, *recv_port; 1078 nxt_runtime_t *rt; 1079 1080 b = nxt_buf_mem_alloc(mp, name->length + 1, 0); 1081 if (nxt_slow_path(b == NULL)) { 1082 goto fail; 1083 } 1084 1085 nxt_buf_cpystr(b, name); 1086 *b->mem.free++ = '\0'; 1087 1088 rt = task->thread->runtime; 1089 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1090 recv_port = rt->port_by_type[rt->type]; 1091 1092 stream = nxt_port_rpc_register_handler(task, recv_port, handler, handler, 1093 -1, ctx); 1094 if (nxt_slow_path(stream == 0)) { 1095 goto fail; 1096 } 1097 1098 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_GET, -1, 1099 stream, recv_port->id, b); 1100 1101 if (nxt_slow_path(ret != NXT_OK)) { 1102 nxt_port_rpc_cancel(task, recv_port, stream); 1103 goto fail; 1104 } 1105 1106 return; 1107 1108 fail: 1109 1110 handler(task, NULL, ctx); 1111 } 1112 1113 1114 void 1115 nxt_cert_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1116 { 1117 u_char *p; 1118 nxt_int_t ret; 1119 nxt_str_t name; 1120 nxt_file_t file; 1121 nxt_port_t *port; 1122 nxt_runtime_t *rt; 1123 nxt_port_msg_type_t type; 1124 1125 port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 1126 msg->port_msg.reply_port); 1127 1128 if (port == NULL) { 1129 return; 1130 } 1131 1132 nxt_memzero(&file, sizeof(nxt_file_t)); 1133 1134 file.fd = -1; 1135 type = NXT_PORT_MSG_RPC_ERROR; 1136 1137 rt = task->thread->runtime; 1138 1139 if (nxt_slow_path(rt->certs.start == NULL)) { 1140 nxt_alert(task, "no certificates storage directory"); 1141 goto error; 1142 } 1143 1144 name.start = msg->buf->mem.pos; 1145 name.length = nxt_strlen(name.start); 1146 1147 file.name = nxt_malloc(rt->certs.length + name.length + 1); 1148 1149 if (nxt_slow_path(file.name == NULL)) { 1150 goto error; 1151 } 1152 1153 p = nxt_cpymem(file.name, rt->certs.start, rt->certs.length); 1154 p = nxt_cpymem(p, name.start, name.length + 1); 1155 1156 ret = nxt_file_open(task, &file, NXT_FILE_RDWR, NXT_FILE_CREATE_OR_OPEN, 1157 NXT_FILE_OWNER_ACCESS); 1158 1159 nxt_free(file.name); 1160 1161 if (nxt_fast_path(ret == NXT_OK)) { 1162 type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD; 1163 } 1164 1165 error: 1166 1167 (void) nxt_port_socket_write(task, port, type, file.fd, 1168 msg->port_msg.stream, 0, NULL); 1169 } 1170 1171 1172 void 1173 nxt_cert_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp) 1174 { 1175 nxt_buf_t *b; 1176 nxt_port_t *main_port; 1177 nxt_runtime_t *rt; 1178 1179 b = nxt_buf_mem_alloc(mp, name->length + 1, 0); 1180 1181 if (nxt_fast_path(b != NULL)) { 1182 nxt_buf_cpystr(b, name); 1183 *b->mem.free++ = '\0'; 1184 1185 rt = task->thread->runtime; 1186 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1187 1188 (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_DELETE, 1189 -1, 0, 0, b); 1190 } 1191 } 1192 1193 1194 void 1195 nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1196 { 1197 u_char *p; 1198 nxt_str_t name; 1199 nxt_runtime_t *rt; 1200 nxt_file_name_t *path; 1201 1202 rt = task->thread->runtime; 1203 1204 if (nxt_slow_path(rt->certs.start == NULL)) { 1205 nxt_alert(task, "no certificates storage directory"); 1206 return; 1207 } 1208 1209 name.start = msg->buf->mem.pos; 1210 name.length = nxt_strlen(name.start); 1211 1212 path = nxt_malloc(rt->certs.length + name.length + 1); 1213 1214 if (nxt_fast_path(path != NULL)) { 1215 p = nxt_cpymem(path, rt->certs.start, rt->certs.length); 1216 p = nxt_cpymem(p, name.start, name.length + 1); 1217 1218 (void) nxt_file_delete(path); 1219 1220 nxt_free(path); 1221 } 1222 } 1223