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 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
nxt_nxt_cert_pem_suffix(char * pem_str,const char * suffix)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
nxt_cert_destroy(nxt_cert_t * cert)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
nxt_cert_info_hash_test(nxt_lvlhsh_query_t * lhq,void * data)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
nxt_cert_info_init(nxt_task_t * task,nxt_array_t * certs)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
nxt_cert_info_save(nxt_str_t * name,nxt_cert_t * cert)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 *
nxt_cert_info_get(nxt_str_t * name)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 *
nxt_cert_info_get_all(nxt_mp_t * mp)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 *
nxt_cert_details(nxt_mp_t * mp,nxt_cert_t * cert)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 *
nxt_cert_name_details(nxt_mp_t * mp,X509 * x509,nxt_bool_t issuer)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 *
nxt_cert_alt_names_details(nxt_mp_t * mp,STACK_OF (GENERAL_NAME)* alt_names)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
nxt_cert_info_delete(nxt_str_t * name)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 *
nxt_cert_store_load(nxt_task_t * task,nxt_mp_t * mp)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
nxt_cert_store_release(nxt_array_t * certs)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
nxt_cert_store_get(nxt_task_t * task,nxt_str_t * name,nxt_mp_t * mp,nxt_port_rpc_handler_t handler,void * ctx)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
nxt_cert_buf_completion(nxt_task_t * task,void * obj,void * data)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
nxt_cert_store_get_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)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 (nxt_slow_path(port == NULL)) {
1139 nxt_alert(task, "process port not found (pid %PI, reply_port %d)",
1140 msg->port_msg.pid, msg->port_msg.reply_port);
1141 return;
1142 }
1143
1144 if (nxt_slow_path(port->type != NXT_PROCESS_CONTROLLER
1145 && port->type != NXT_PROCESS_ROUTER))
1146 {
1147 nxt_alert(task, "process %PI cannot store certificates",
1148 msg->port_msg.pid);
1149 return;
1150 }
1151
1152 nxt_memzero(&file, sizeof(nxt_file_t));
1153
1154 file.fd = -1;
1155 type = NXT_PORT_MSG_RPC_ERROR;
1156
1157 rt = task->thread->runtime;
1158
1159 if (nxt_slow_path(rt->certs.start == NULL)) {
1160 nxt_alert(task, "no certificates storage directory");
1161 goto error;
1162 }
1163
1164 name.start = msg->buf->mem.pos;
1165 name.length = nxt_strlen(name.start);
1166
1167 file.name = nxt_malloc(rt->certs.length + name.length + 1);
1168
1169 if (nxt_slow_path(file.name == NULL)) {
1170 goto error;
1171 }
1172
1173 p = nxt_cpymem(file.name, rt->certs.start, rt->certs.length);
1174 p = nxt_cpymem(p, name.start, name.length + 1);
1175
1176 ret = nxt_file_open(task, &file, NXT_FILE_RDWR, NXT_FILE_CREATE_OR_OPEN,
1177 NXT_FILE_OWNER_ACCESS);
1178
1179 nxt_free(file.name);
1180
1181 if (nxt_fast_path(ret == NXT_OK)) {
1182 type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD;
1183 }
1184
1185 error:
1186
1187 (void) nxt_port_socket_write(task, port, type, file.fd,
1188 msg->port_msg.stream, 0, NULL);
1189 }
1190
1191
1192 void
nxt_cert_store_delete(nxt_task_t * task,nxt_str_t * name,nxt_mp_t * mp)1193 nxt_cert_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp)
1194 {
1195 nxt_buf_t *b;
1196 nxt_port_t *main_port;
1197 nxt_runtime_t *rt;
1198
1199 b = nxt_buf_mem_alloc(mp, name->length + 1, 0);
1200
1201 if (nxt_fast_path(b != NULL)) {
1202 nxt_buf_cpystr(b, name);
1203 *b->mem.free++ = '\0';
1204
1205 rt = task->thread->runtime;
1206 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1207
1208 (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_DELETE,
1209 -1, 0, 0, b);
1210 }
1211 }
1212
1213
1214 void
nxt_cert_store_delete_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)1215 nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1216 {
1217 u_char *p;
1218 nxt_str_t name;
1219 nxt_port_t *ctl_port;
1220 nxt_runtime_t *rt;
1221 nxt_file_name_t *path;
1222
1223 rt = task->thread->runtime;
1224 ctl_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
1225
1226 if (nxt_slow_path(ctl_port == NULL)) {
1227 nxt_alert(task, "controller port not found");
1228 return;
1229 }
1230
1231 if (nxt_slow_path(nxt_recv_msg_cmsg_pid(msg) != ctl_port->pid)) {
1232 nxt_alert(task, "process %PI cannot delete certificates",
1233 nxt_recv_msg_cmsg_pid(msg));
1234 return;
1235 }
1236
1237 if (nxt_slow_path(rt->certs.start == NULL)) {
1238 nxt_alert(task, "no certificates storage directory");
1239 return;
1240 }
1241
1242 name.start = msg->buf->mem.pos;
1243 name.length = nxt_strlen(name.start);
1244
1245 path = nxt_malloc(rt->certs.length + name.length + 1);
1246
1247 if (nxt_fast_path(path != NULL)) {
1248 p = nxt_cpymem(path, rt->certs.start, rt->certs.length);
1249 p = nxt_cpymem(p, name.start, name.length + 1);
1250
1251 (void) nxt_file_delete(path);
1252
1253 nxt_free(path);
1254 }
1255 }
1256