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