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, nxt_mp_t *mp) 801 { 802 DIR *dir; 803 size_t size, alloc; 804 u_char *buf, *p; 805 nxt_str_t name; 806 nxt_int_t ret; 807 nxt_file_t file; 808 nxt_array_t *certs; 809 nxt_runtime_t *rt; 810 struct dirent *de; 811 nxt_cert_item_t *item; 812 813 rt = task->thread->runtime; 814 815 if (nxt_slow_path(rt->certs.start == NULL)) { 816 nxt_alert(task, "no certificates storage directory"); 817 return NULL; 818 } 819 820 certs = nxt_array_create(mp, 16, sizeof(nxt_cert_item_t)); 821 if (nxt_slow_path(certs == NULL)) { 822 return NULL; 823 } 824 825 buf = NULL; 826 alloc = 0; 827 828 dir = opendir((char *) rt->certs.start); 829 if (nxt_slow_path(dir == NULL)) { 830 nxt_alert(task, "opendir(\"%s\") failed %E", 831 rt->certs.start, nxt_errno); 832 goto fail; 833 } 834 835 for ( ;; ) { 836 de = readdir(dir); 837 if (de == NULL) { 838 break; 839 } 840 841 nxt_debug(task, "readdir(\"%s\"): \"%s\"", rt->certs.start, de->d_name); 842 843 name.length = nxt_strlen(de->d_name); 844 name.start = (u_char *) de->d_name; 845 846 if (nxt_str_eq(&name, ".", 1) || nxt_str_eq(&name, "..", 2)) { 847 continue; 848 } 849 850 item = nxt_array_add(certs); 851 if (nxt_slow_path(item == NULL)) { 852 goto fail; 853 } 854 855 item->fd = -1; 856 857 size = rt->certs.length + name.length + 1; 858 859 if (size > alloc) { 860 size += 32; 861 862 p = nxt_realloc(buf, size); 863 if (p == NULL) { 864 goto fail; 865 } 866 867 alloc = size; 868 buf = p; 869 } 870 871 p = nxt_cpymem(buf, rt->certs.start, rt->certs.length); 872 p = nxt_cpymem(p, name.start, name.length + 1); 873 874 nxt_memzero(&file, sizeof(nxt_file_t)); 875 876 file.name = buf; 877 878 ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 879 NXT_FILE_OWNER_ACCESS); 880 881 882 if (nxt_slow_path(ret != NXT_OK)) { 883 nxt_array_remove_last(certs); 884 continue; 885 } 886 887 item->fd = file.fd; 888 889 if (nxt_slow_path(nxt_str_dup(mp, &item->name, &name) == NULL)) { 890 goto fail; 891 } 892 } 893 894 if (buf != NULL) { 895 nxt_free(buf); 896 } 897 898 (void) closedir(dir); 899 900 return certs; 901 902 fail: 903 904 if (buf != NULL) { 905 nxt_free(buf); 906 } 907 908 if (dir != NULL) { 909 (void) closedir(dir); 910 } 911 912 nxt_cert_store_release(certs); 913 914 return NULL; 915 } 916 917 918 void 919 nxt_cert_store_release(nxt_array_t *certs) 920 { 921 uint32_t i; 922 nxt_cert_item_t *items; 923 924 for (items = certs->elts, i = 0; 925 i < certs->nelts; 926 i++) 927 { 928 nxt_fd_close(items[i].fd); 929 } 930 931 nxt_array_destroy(certs); 932 } 933 934 935 #if 0 936 937 void 938 nxt_cert_store_discovery_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 939 { 940 DIR *dir; 941 size_t size; 942 nxt_buf_t *b; 943 nxt_int_t ret; 944 nxt_port_t *port; 945 nxt_runtime_t *rt; 946 struct dirent *de; 947 948 port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 949 msg->port_msg.reply_port); 950 951 if (nxt_slow_path(port == NULL)) { 952 return; 953 } 954 955 b = NULL; 956 dir = NULL; 957 958 rt = task->thread->runtime; 959 960 if (nxt_slow_path(rt->certs.start == NULL)) { 961 nxt_alert(task, "no certificates storage directory"); 962 goto fail; 963 } 964 965 dir = opendir((char *) rt->certs.start); 966 if (nxt_slow_path(dir == NULL)) { 967 nxt_alert(task, "opendir(\"%s\") failed %E", 968 rt->certs.start, nxt_errno); 969 goto fail; 970 } 971 972 size = 0; 973 974 for ( ;; ) { 975 de = readdir(dir); 976 if (de == NULL) { 977 break; 978 } 979 980 if (de->d_type != DT_REG) { 981 continue; 982 } 983 984 size += nxt_strlen(de->d_name) + 1; 985 } 986 987 b = nxt_port_mmap_get_buf(task, port, size); 988 if (nxt_slow_path(b == NULL)) { 989 goto fail; 990 } 991 992 rewinddir(dir); 993 994 for ( ;; ) { 995 de = readdir(dir); 996 if (de == NULL) { 997 break; 998 } 999 1000 if (de->d_type != DT_REG) { 1001 continue; 1002 } 1003 1004 size = nxt_strlen(de->d_name) + 1; 1005 1006 if (nxt_slow_path(size > (size_t) nxt_buf_mem_free_size(&b->mem))) { 1007 b->mem.free = b->mem.start; 1008 break; 1009 } 1010 1011 b->mem.free = nxt_cpymem(b->mem.free, de->d_name, size); 1012 } 1013 1014 (void) closedir(dir); 1015 dir = NULL; 1016 1017 if (nxt_slow_path(nxt_buf_mem_free_size(&b->mem) != 0)) { 1018 nxt_alert(task, "certificates storage directory " 1019 "has changed while reading it"); 1020 goto fail; 1021 } 1022 1023 ret = nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST, -1, 1024 msg->port_msg.stream, 0, b); 1025 1026 if (nxt_fast_path(ret == NXT_OK)) { 1027 return; 1028 } 1029 1030 fail: 1031 1032 if (dir != NULL) { 1033 (void) closedir(dir); 1034 } 1035 1036 if (b != NULL) { 1037 b->completion_handler(task, b, b->parent); 1038 } 1039 1040 (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1, 1041 msg->port_msg.stream, 0, NULL); 1042 } 1043 1044 #endif 1045 1046 1047 void 1048 nxt_cert_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp, 1049 nxt_port_rpc_handler_t handler, void *ctx) 1050 { 1051 uint32_t stream; 1052 nxt_int_t ret; 1053 nxt_buf_t *b; 1054 nxt_port_t *main_port, *recv_port; 1055 nxt_runtime_t *rt; 1056 1057 b = nxt_buf_mem_alloc(mp, name->length + 1, 0); 1058 if (nxt_slow_path(b == NULL)) { 1059 goto fail; 1060 } 1061 1062 nxt_buf_cpystr(b, name); 1063 *b->mem.free++ = '\0'; 1064 1065 rt = task->thread->runtime; 1066 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1067 recv_port = rt->port_by_type[rt->type]; 1068 1069 stream = nxt_port_rpc_register_handler(task, recv_port, handler, handler, 1070 -1, ctx); 1071 if (nxt_slow_path(stream == 0)) { 1072 goto fail; 1073 } 1074 1075 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_GET, -1, 1076 stream, recv_port->id, b); 1077 1078 if (nxt_slow_path(ret != NXT_OK)) { 1079 nxt_port_rpc_cancel(task, recv_port, stream); 1080 goto fail; 1081 } 1082 1083 return; 1084 1085 fail: 1086 1087 handler(task, NULL, ctx); 1088 } 1089 1090 1091 void 1092 nxt_cert_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1093 { 1094 u_char *p; 1095 nxt_int_t ret; 1096 nxt_str_t name; 1097 nxt_file_t file; 1098 nxt_port_t *port; 1099 nxt_runtime_t *rt; 1100 nxt_port_msg_type_t type; 1101 1102 port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 1103 msg->port_msg.reply_port); 1104 1105 if (port == NULL) { 1106 return; 1107 } 1108 1109 nxt_memzero(&file, sizeof(nxt_file_t)); 1110 1111 file.fd = -1; 1112 type = NXT_PORT_MSG_RPC_ERROR; 1113 1114 rt = task->thread->runtime; 1115 1116 if (nxt_slow_path(rt->certs.start == NULL)) { 1117 nxt_alert(task, "no certificates storage directory"); 1118 goto error; 1119 } 1120 1121 name.start = msg->buf->mem.pos; 1122 name.length = nxt_strlen(name.start); 1123 1124 file.name = nxt_malloc(rt->certs.length + name.length + 1); 1125 1126 if (nxt_slow_path(file.name == NULL)) { 1127 goto error; 1128 } 1129 1130 p = nxt_cpymem(file.name, rt->certs.start, rt->certs.length); 1131 p = nxt_cpymem(p, name.start, name.length + 1); 1132 1133 ret = nxt_file_open(task, &file, NXT_FILE_RDWR, NXT_FILE_CREATE_OR_OPEN, 1134 NXT_FILE_OWNER_ACCESS); 1135 1136 nxt_free(file.name); 1137 1138 if (nxt_fast_path(ret == NXT_OK)) { 1139 type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD; 1140 } 1141 1142 error: 1143 1144 (void) nxt_port_socket_write(task, port, type, file.fd, 1145 msg->port_msg.stream, 0, NULL); 1146 } 1147 1148 1149 void 1150 nxt_cert_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp) 1151 { 1152 nxt_buf_t *b; 1153 nxt_port_t *main_port; 1154 nxt_runtime_t *rt; 1155 1156 b = nxt_buf_mem_alloc(mp, name->length + 1, 0); 1157 1158 if (nxt_fast_path(b != NULL)) { 1159 nxt_buf_cpystr(b, name); 1160 *b->mem.free++ = '\0'; 1161 1162 rt = task->thread->runtime; 1163 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1164 1165 (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_DELETE, 1166 -1, 0, 0, b); 1167 } 1168 } 1169 1170 1171 void 1172 nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1173 { 1174 u_char *p; 1175 nxt_str_t name; 1176 nxt_runtime_t *rt; 1177 nxt_file_name_t *path; 1178 1179 rt = task->thread->runtime; 1180 1181 if (nxt_slow_path(rt->certs.start == NULL)) { 1182 nxt_alert(task, "no certificates storage directory"); 1183 return; 1184 } 1185 1186 name.start = msg->buf->mem.pos; 1187 name.length = nxt_strlen(name.start); 1188 1189 path = nxt_malloc(rt->certs.length + name.length + 1); 1190 1191 if (nxt_fast_path(path != NULL)) { 1192 p = nxt_cpymem(path, rt->certs.start, rt->certs.length); 1193 p = nxt_cpymem(p, name.start, name.length + 1); 1194 1195 (void) nxt_file_delete(path); 1196 1197 nxt_free(path); 1198 } 1199 } 1200