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