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 *
nxt_cert_mem(nxt_task_t * task,nxt_buf_mem_t * mbuf)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 *
nxt_cert_fd(nxt_task_t * task,nxt_fd_t fd)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 *
nxt_cert_bio(nxt_task_t * task,BIO * bio)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 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
nxt_nxt_cert_pem_suffix(char * pem_str,const char * suffix)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
nxt_cert_destroy(nxt_cert_t * cert)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
nxt_cert_info_hash_test(nxt_lvlhsh_query_t * lhq,void * data)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
nxt_cert_info_init(nxt_task_t * task,nxt_array_t * certs)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
nxt_cert_info_save(nxt_str_t * name,nxt_cert_t * cert)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 *
nxt_cert_info_get(nxt_str_t * name)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 *
nxt_cert_info_get_all(nxt_mp_t * mp)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 *
nxt_cert_details(nxt_mp_t * mp,nxt_cert_t * cert)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 *
nxt_cert_name_details(nxt_mp_t * mp,X509 * x509,nxt_bool_t issuer)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 names = nxt_cert_alt_names_details(mp, alt_names);
694
695 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
696
697 if (nxt_slow_path(names == NULL)) {
698 return NULL;
699 }
700
701 count++;
702
703 } else {
704 names = NULL;
705 }
706
707 object = nxt_conf_create_object(mp, count);
708 if (nxt_slow_path(object == NULL)) {
709 return NULL;
710 }
711
712 for (n = 0, i = 0; n != nxt_nitems(nids) && i != count; n++) {
713
714 len = X509_NAME_get_text_by_NID(x509_name, nids[n].nid,
715 (char *) buf, sizeof(buf));
716
717 if (n == 1 && names != NULL) {
718 nxt_conf_set_member(object, &alt_names_str, names, i++);
719 }
720
721 if (len < 0) {
722 continue;
723 }
724
725 str.length = len;
726 str.start = buf;
727
728 ret = nxt_conf_set_member_string_dup(object, mp, &nids[n].name,
729 &str, i++);
730 if (nxt_slow_path(ret != NXT_OK)) {
731 return NULL;
732 }
733 }
734
735 return object;
736 }
737
738
739 static nxt_conf_value_t *
nxt_cert_alt_names_details(nxt_mp_t * mp,STACK_OF (GENERAL_NAME)* alt_names)740 nxt_cert_alt_names_details(nxt_mp_t *mp, STACK_OF(GENERAL_NAME) *alt_names)
741 {
742 nxt_str_t str;
743 nxt_int_t ret;
744 nxt_uint_t i, n, count;
745 GENERAL_NAME *name;
746 nxt_conf_value_t *array;
747
748 count = sk_GENERAL_NAME_num(alt_names);
749 n = 0;
750
751 for (i = 0; i != count; i++) {
752 name = sk_GENERAL_NAME_value(alt_names, i);
753
754 if (name->type != GEN_DNS) {
755 continue;
756 }
757
758 n++;
759 }
760
761 array = nxt_conf_create_array(mp, n);
762 if (nxt_slow_path(array == NULL)) {
763 return NULL;
764 }
765
766 for (n = 0, i = 0; n != count; n++) {
767 name = sk_GENERAL_NAME_value(alt_names, n);
768
769 if (name->type != GEN_DNS) {
770 continue;
771 }
772
773 str.length = ASN1_STRING_length(name->d.dNSName);
774 #if OPENSSL_VERSION_NUMBER > 0x10100000L
775 str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName);
776 #else
777 str.start = ASN1_STRING_data(name->d.dNSName);
778 #endif
779
780 ret = nxt_conf_set_element_string_dup(array, mp, i++, &str);
781 if (nxt_slow_path(ret != NXT_OK)) {
782 return NULL;
783 }
784 }
785
786 return array;
787 }
788
789
790 nxt_int_t
nxt_cert_info_delete(nxt_str_t * name)791 nxt_cert_info_delete(nxt_str_t *name)
792 {
793 nxt_int_t ret;
794 nxt_cert_info_t *info;
795 nxt_lvlhsh_query_t lhq;
796
797 lhq.key_hash = nxt_djb_hash(name->start, name->length);
798 lhq.key = *name;
799 lhq.proto = &nxt_cert_info_hash_proto;
800
801 ret = nxt_lvlhsh_delete(&nxt_cert_info, &lhq);
802
803 if (ret == NXT_OK) {
804 info = lhq.value;
805 nxt_mp_destroy(info->mp);
806 }
807
808 return ret;
809 }
810
811
812
813 nxt_array_t *
nxt_cert_store_load(nxt_task_t * task,nxt_mp_t * mp)814 nxt_cert_store_load(nxt_task_t *task, nxt_mp_t *mp)
815 {
816 DIR *dir;
817 size_t size, alloc;
818 u_char *buf, *p;
819 nxt_str_t name;
820 nxt_int_t ret;
821 nxt_file_t file;
822 nxt_array_t *certs;
823 nxt_runtime_t *rt;
824 struct dirent *de;
825 nxt_cert_item_t *item;
826
827 rt = task->thread->runtime;
828
829 if (nxt_slow_path(rt->certs.start == NULL)) {
830 nxt_alert(task, "no certificates storage directory");
831 return NULL;
832 }
833
834 certs = nxt_array_create(mp, 16, sizeof(nxt_cert_item_t));
835 if (nxt_slow_path(certs == NULL)) {
836 return NULL;
837 }
838
839 buf = NULL;
840 alloc = 0;
841
842 dir = opendir((char *) rt->certs.start);
843 if (nxt_slow_path(dir == NULL)) {
844 nxt_alert(task, "opendir(\"%s\") failed %E",
845 rt->certs.start, nxt_errno);
846 goto fail;
847 }
848
849 for ( ;; ) {
850 de = readdir(dir);
851 if (de == NULL) {
852 break;
853 }
854
855 nxt_debug(task, "readdir(\"%s\"): \"%s\"", rt->certs.start, de->d_name);
856
857 name.length = nxt_strlen(de->d_name);
858 name.start = (u_char *) de->d_name;
859
860 if (nxt_str_eq(&name, ".", 1) || nxt_str_eq(&name, "..", 2)) {
861 continue;
862 }
863
864 item = nxt_array_add(certs);
865 if (nxt_slow_path(item == NULL)) {
866 goto fail;
867 }
868
869 item->fd = -1;
870
871 size = rt->certs.length + name.length + 1;
872
873 if (size > alloc) {
874 size += 32;
875
876 p = nxt_realloc(buf, size);
877 if (p == NULL) {
878 goto fail;
879 }
880
881 alloc = size;
882 buf = p;
883 }
884
885 p = nxt_cpymem(buf, rt->certs.start, rt->certs.length);
886 p = nxt_cpymem(p, name.start, name.length + 1);
887
888 nxt_memzero(&file, sizeof(nxt_file_t));
889
890 file.name = buf;
891
892 ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN,
893 NXT_FILE_OWNER_ACCESS);
894
895
896 if (nxt_slow_path(ret != NXT_OK)) {
897 nxt_array_remove_last(certs);
898 continue;
899 }
900
901 item->fd = file.fd;
902
903 if (nxt_slow_path(nxt_str_dup(mp, &item->name, &name) == NULL)) {
904 goto fail;
905 }
906 }
907
908 if (buf != NULL) {
909 nxt_free(buf);
910 }
911
912 (void) closedir(dir);
913
914 return certs;
915
916 fail:
917
918 if (buf != NULL) {
919 nxt_free(buf);
920 }
921
922 if (dir != NULL) {
923 (void) closedir(dir);
924 }
925
926 nxt_cert_store_release(certs);
927
928 return NULL;
929 }
930
931
932 void
nxt_cert_store_release(nxt_array_t * certs)933 nxt_cert_store_release(nxt_array_t *certs)
934 {
935 uint32_t i;
936 nxt_cert_item_t *items;
937
938 for (items = certs->elts, i = 0;
939 i < certs->nelts;
940 i++)
941 {
942 nxt_fd_close(items[i].fd);
943 }
944
945 nxt_array_destroy(certs);
946 }
947
948
949 #if 0
950
951 void
952 nxt_cert_store_discovery_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
953 {
954 DIR *dir;
955 size_t size;
956 nxt_buf_t *b;
957 nxt_int_t ret;
958 nxt_port_t *port;
959 nxt_runtime_t *rt;
960 struct dirent *de;
961
962 port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
963 msg->port_msg.reply_port);
964
965 if (nxt_slow_path(port == NULL)) {
966 return;
967 }
968
969 b = NULL;
970 dir = NULL;
971
972 rt = task->thread->runtime;
973
974 if (nxt_slow_path(rt->certs.start == NULL)) {
975 nxt_alert(task, "no certificates storage directory");
976 goto fail;
977 }
978
979 dir = opendir((char *) rt->certs.start);
980 if (nxt_slow_path(dir == NULL)) {
981 nxt_alert(task, "opendir(\"%s\") failed %E",
982 rt->certs.start, nxt_errno);
983 goto fail;
984 }
985
986 size = 0;
987
988 for ( ;; ) {
989 de = readdir(dir);
990 if (de == NULL) {
991 break;
992 }
993
994 if (de->d_type != DT_REG) {
995 continue;
996 }
997
998 size += nxt_strlen(de->d_name) + 1;
999 }
1000
1001 b = nxt_port_mmap_get_buf(task, port, size);
1002 if (nxt_slow_path(b == NULL)) {
1003 goto fail;
1004 }
1005
1006 rewinddir(dir);
1007
1008 for ( ;; ) {
1009 de = readdir(dir);
1010 if (de == NULL) {
1011 break;
1012 }
1013
1014 if (de->d_type != DT_REG) {
1015 continue;
1016 }
1017
1018 size = nxt_strlen(de->d_name) + 1;
1019
1020 if (nxt_slow_path(size > (size_t) nxt_buf_mem_free_size(&b->mem))) {
1021 b->mem.free = b->mem.start;
1022 break;
1023 }
1024
1025 b->mem.free = nxt_cpymem(b->mem.free, de->d_name, size);
1026 }
1027
1028 (void) closedir(dir);
1029 dir = NULL;
1030
1031 if (nxt_slow_path(nxt_buf_mem_free_size(&b->mem) != 0)) {
1032 nxt_alert(task, "certificates storage directory "
1033 "has changed while reading it");
1034 goto fail;
1035 }
1036
1037 ret = nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST, -1,
1038 msg->port_msg.stream, 0, b);
1039
1040 if (nxt_fast_path(ret == NXT_OK)) {
1041 return;
1042 }
1043
1044 fail:
1045
1046 if (dir != NULL) {
1047 (void) closedir(dir);
1048 }
1049
1050 if (b != NULL) {
1051 b->completion_handler(task, b, b->parent);
1052 }
1053
1054 (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1,
1055 msg->port_msg.stream, 0, NULL);
1056 }
1057
1058 #endif
1059
1060
1061 void
nxt_cert_store_get(nxt_task_t * task,nxt_str_t * name,nxt_mp_t * mp,nxt_port_rpc_handler_t handler,void * ctx)1062 nxt_cert_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp,
1063 nxt_port_rpc_handler_t handler, void *ctx)
1064 {
1065 uint32_t stream;
1066 nxt_int_t ret;
1067 nxt_buf_t *b;
1068 nxt_port_t *main_port, *recv_port;
1069 nxt_runtime_t *rt;
1070
1071 b = nxt_buf_mem_alloc(mp, name->length + 1, 0);
1072 if (nxt_slow_path(b == NULL)) {
1073 goto fail;
1074 }
1075
1076 nxt_mp_retain(mp);
1077 b->completion_handler = nxt_cert_buf_completion;
1078
1079 nxt_buf_cpystr(b, name);
1080 *b->mem.free++ = '\0';
1081
1082 rt = task->thread->runtime;
1083 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1084 recv_port = rt->port_by_type[rt->type];
1085
1086 stream = nxt_port_rpc_register_handler(task, recv_port, handler, handler,
1087 -1, ctx);
1088 if (nxt_slow_path(stream == 0)) {
1089 goto fail;
1090 }
1091
1092 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_GET, -1,
1093 stream, recv_port->id, b);
1094
1095 if (nxt_slow_path(ret != NXT_OK)) {
1096 nxt_port_rpc_cancel(task, recv_port, stream);
1097 goto fail;
1098 }
1099
1100 return;
1101
1102 fail:
1103
1104 handler(task, NULL, ctx);
1105 }
1106
1107
1108 static void
nxt_cert_buf_completion(nxt_task_t * task,void * obj,void * data)1109 nxt_cert_buf_completion(nxt_task_t *task, void *obj, void *data)
1110 {
1111 nxt_mp_t *mp;
1112 nxt_buf_t *b;
1113
1114 b = obj;
1115 mp = b->data;
1116 nxt_assert(b->next == NULL);
1117
1118 nxt_mp_free(mp, b);
1119 nxt_mp_release(mp);
1120 }
1121
1122
1123 void
nxt_cert_store_get_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)1124 nxt_cert_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1125 {
1126 u_char *p;
1127 nxt_int_t ret;
1128 nxt_str_t name;
1129 nxt_file_t file;
1130 nxt_port_t *port;
1131 nxt_runtime_t *rt;
1132 nxt_port_msg_type_t type;
1133
1134 port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
1135 msg->port_msg.reply_port);
1136
1137 if (nxt_slow_path(port == NULL)) {
1138 nxt_alert(task, "process port not found (pid %PI, reply_port %d)",
1139 msg->port_msg.pid, msg->port_msg.reply_port);
1140 return;
1141 }
1142
1143 if (nxt_slow_path(port->type != NXT_PROCESS_CONTROLLER
1144 && port->type != NXT_PROCESS_ROUTER))
1145 {
1146 nxt_alert(task, "process %PI cannot store certificates",
1147 msg->port_msg.pid);
1148 return;
1149 }
1150
1151 nxt_memzero(&file, sizeof(nxt_file_t));
1152
1153 file.fd = -1;
1154 type = NXT_PORT_MSG_RPC_ERROR;
1155
1156 rt = task->thread->runtime;
1157
1158 if (nxt_slow_path(rt->certs.start == NULL)) {
1159 nxt_alert(task, "no certificates storage directory");
1160 goto error;
1161 }
1162
1163 name.start = msg->buf->mem.pos;
1164 name.length = nxt_strlen(name.start);
1165
1166 file.name = nxt_malloc(rt->certs.length + name.length + 1);
1167
1168 if (nxt_slow_path(file.name == NULL)) {
1169 goto error;
1170 }
1171
1172 p = nxt_cpymem(file.name, rt->certs.start, rt->certs.length);
1173 p = nxt_cpymem(p, name.start, name.length + 1);
1174
1175 ret = nxt_file_open(task, &file, NXT_FILE_RDWR, NXT_FILE_CREATE_OR_OPEN,
1176 NXT_FILE_OWNER_ACCESS);
1177
1178 nxt_free(file.name);
1179
1180 if (nxt_fast_path(ret == NXT_OK)) {
1181 type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD;
1182 }
1183
1184 error:
1185
1186 (void) nxt_port_socket_write(task, port, type, file.fd,
1187 msg->port_msg.stream, 0, NULL);
1188 }
1189
1190
1191 void
nxt_cert_store_delete(nxt_task_t * task,nxt_str_t * name,nxt_mp_t * mp)1192 nxt_cert_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp)
1193 {
1194 nxt_buf_t *b;
1195 nxt_port_t *main_port;
1196 nxt_runtime_t *rt;
1197
1198 b = nxt_buf_mem_alloc(mp, name->length + 1, 0);
1199
1200 if (nxt_fast_path(b != NULL)) {
1201 nxt_buf_cpystr(b, name);
1202 *b->mem.free++ = '\0';
1203
1204 rt = task->thread->runtime;
1205 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1206
1207 (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_DELETE,
1208 -1, 0, 0, b);
1209 }
1210 }
1211
1212
1213 void
nxt_cert_store_delete_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)1214 nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1215 {
1216 u_char *p;
1217 nxt_str_t name;
1218 nxt_port_t *ctl_port;
1219 nxt_runtime_t *rt;
1220 nxt_file_name_t *path;
1221
1222 rt = task->thread->runtime;
1223 ctl_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
1224
1225 if (nxt_slow_path(ctl_port == NULL)) {
1226 nxt_alert(task, "controller port not found");
1227 return;
1228 }
1229
1230 if (nxt_slow_path(nxt_recv_msg_cmsg_pid(msg) != ctl_port->pid)) {
1231 nxt_alert(task, "process %PI cannot delete certificates",
1232 nxt_recv_msg_cmsg_pid(msg));
1233 return;
1234 }
1235
1236 if (nxt_slow_path(rt->certs.start == NULL)) {
1237 nxt_alert(task, "no certificates storage directory");
1238 return;
1239 }
1240
1241 name.start = msg->buf->mem.pos;
1242 name.length = nxt_strlen(name.start);
1243
1244 path = nxt_malloc(rt->certs.length + name.length + 1);
1245
1246 if (nxt_fast_path(path != NULL)) {
1247 p = nxt_cpymem(path, rt->certs.start, rt->certs.length);
1248 p = nxt_cpymem(p, name.start, name.length + 1);
1249
1250 (void) nxt_file_delete(path);
1251
1252 nxt_free(path);
1253 }
1254 }
1255