nxt_cert.c (1813:10aaca1e582e) nxt_cert.c (1820:e969cea13cc3)
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
22struct nxt_cert_s {
23 EVP_PKEY *key;
24 nxt_uint_t count;
25 X509 *chain[];
26};
27
28
29typedef struct {
30 nxt_str_t name;
31 nxt_conf_value_t *value;
32 nxt_mp_t *mp;
33} nxt_cert_info_t;
34
35
36typedef struct {
37 nxt_str_t name;
38 nxt_fd_t fd;
39} nxt_cert_item_t;
40
41
42static nxt_cert_t *nxt_cert_fd(nxt_task_t *task, nxt_fd_t fd);
43static nxt_cert_t *nxt_cert_bio(nxt_task_t *task, BIO *bio);
44static int nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix);
45
46static nxt_conf_value_t *nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert);
47static nxt_conf_value_t *nxt_cert_name_details(nxt_mp_t *mp, X509 *x509,
48 nxt_bool_t issuer);
49
50
51static nxt_lvlhsh_t nxt_cert_info;
52
53
54nxt_cert_t *
55nxt_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
74static nxt_cert_t *
75nxt_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
94static nxt_cert_t *
95nxt_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
264fail:
265
266 nxt_cert_destroy(cert);
267
268 return NULL;
269}
270
271
272static int
273nxt_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
301void
302nxt_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
317static nxt_int_t
318nxt_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
332static 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
342void
343nxt_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
363nxt_int_t
364nxt_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
413fail:
414
415 nxt_mp_destroy(mp);
416 return NXT_ERROR;
417}
418
419
420nxt_conf_value_t *
421nxt_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
442nxt_conf_value_t *
443nxt_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
489static nxt_conf_value_t *
490nxt_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
643typedef struct {
644 int nid;
645 nxt_str_t name;
646} nxt_cert_nid_t;
647
648
649static nxt_conf_value_t *
650nxt_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);
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
22struct nxt_cert_s {
23 EVP_PKEY *key;
24 nxt_uint_t count;
25 X509 *chain[];
26};
27
28
29typedef struct {
30 nxt_str_t name;
31 nxt_conf_value_t *value;
32 nxt_mp_t *mp;
33} nxt_cert_info_t;
34
35
36typedef struct {
37 nxt_str_t name;
38 nxt_fd_t fd;
39} nxt_cert_item_t;
40
41
42static nxt_cert_t *nxt_cert_fd(nxt_task_t *task, nxt_fd_t fd);
43static nxt_cert_t *nxt_cert_bio(nxt_task_t *task, BIO *bio);
44static int nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix);
45
46static nxt_conf_value_t *nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert);
47static nxt_conf_value_t *nxt_cert_name_details(nxt_mp_t *mp, X509 *x509,
48 nxt_bool_t issuer);
49
50
51static nxt_lvlhsh_t nxt_cert_info;
52
53
54nxt_cert_t *
55nxt_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
74static nxt_cert_t *
75nxt_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
94static nxt_cert_t *
95nxt_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
264fail:
265
266 nxt_cert_destroy(cert);
267
268 return NULL;
269}
270
271
272static int
273nxt_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
301void
302nxt_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
317static nxt_int_t
318nxt_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
332static 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
342void
343nxt_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
363nxt_int_t
364nxt_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
413fail:
414
415 nxt_mp_destroy(mp);
416 return NXT_ERROR;
417}
418
419
420nxt_conf_value_t *
421nxt_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
442nxt_conf_value_t *
443nxt_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
489static nxt_conf_value_t *
490nxt_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
643typedef struct {
644 int nid;
645 nxt_str_t name;
646} nxt_cert_nid_t;
647
648
649static nxt_conf_value_t *
650nxt_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 n = 0;
725
726
726 for (n = 0; n != count; n++) {
727 name = sk_GENERAL_NAME_value(alt_names, n);
727 for (i = 0; i != count; i++) {
728 name = sk_GENERAL_NAME_value(alt_names, i);
728
729 if (name->type != GEN_DNS) {
730 continue;
731 }
729
730 if (name->type != GEN_DNS) {
731 continue;
732 }
733
734 n++;
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
766fail:
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
776nxt_int_t
777nxt_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
799nxt_array_t *
800nxt_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
902fail:
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
918void
919nxt_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
937void
938nxt_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
1030fail:
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
1047void
1048nxt_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
1085fail:
1086
1087 handler(task, NULL, ctx);
1088}
1089
1090
1091void
1092nxt_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
1142error:
1143
1144 (void) nxt_port_socket_write(task, port, type, file.fd,
1145 msg->port_msg.stream, 0, NULL);
1146}
1147
1148
1149void
1150nxt_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
1171void
1172nxt_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}
735 }
736
737 names = nxt_conf_create_array(mp, n);
738 if (nxt_slow_path(names == NULL)) {
739 goto fail;
740 }
741
742 for (n = 0, i = 0; n != count; n++) {
743 name = sk_GENERAL_NAME_value(alt_names, n);
744
745 if (name->type != GEN_DNS) {
746 continue;
747 }
748
749 str.length = ASN1_STRING_length(name->d.dNSName);
750#if OPENSSL_VERSION_NUMBER > 0x10100000L
751 str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName);
752#else
753 str.start = ASN1_STRING_data(name->d.dNSName);
754#endif
755
756 ret = nxt_conf_set_element_string_dup(names, mp, i++, &str);
757 if (nxt_slow_path(ret != NXT_OK)) {
758 goto fail;
759 }
760 }
761
762 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
763
764 nxt_conf_set_member(object, &alt_names_str, names, 1);
765 }
766
767 return object;
768
769fail:
770
771 if (alt_names != NULL) {
772 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
773 }
774
775 return NULL;
776}
777
778
779nxt_int_t
780nxt_cert_info_delete(nxt_str_t *name)
781{
782 nxt_int_t ret;
783 nxt_cert_info_t *info;
784 nxt_lvlhsh_query_t lhq;
785
786 lhq.key_hash = nxt_djb_hash(name->start, name->length);
787 lhq.key = *name;
788 lhq.proto = &nxt_cert_info_hash_proto;
789
790 ret = nxt_lvlhsh_delete(&nxt_cert_info, &lhq);
791
792 if (ret == NXT_OK) {
793 info = lhq.value;
794 nxt_mp_destroy(info->mp);
795 }
796
797 return ret;
798}
799
800
801
802nxt_array_t *
803nxt_cert_store_load(nxt_task_t *task, nxt_mp_t *mp)
804{
805 DIR *dir;
806 size_t size, alloc;
807 u_char *buf, *p;
808 nxt_str_t name;
809 nxt_int_t ret;
810 nxt_file_t file;
811 nxt_array_t *certs;
812 nxt_runtime_t *rt;
813 struct dirent *de;
814 nxt_cert_item_t *item;
815
816 rt = task->thread->runtime;
817
818 if (nxt_slow_path(rt->certs.start == NULL)) {
819 nxt_alert(task, "no certificates storage directory");
820 return NULL;
821 }
822
823 certs = nxt_array_create(mp, 16, sizeof(nxt_cert_item_t));
824 if (nxt_slow_path(certs == NULL)) {
825 return NULL;
826 }
827
828 buf = NULL;
829 alloc = 0;
830
831 dir = opendir((char *) rt->certs.start);
832 if (nxt_slow_path(dir == NULL)) {
833 nxt_alert(task, "opendir(\"%s\") failed %E",
834 rt->certs.start, nxt_errno);
835 goto fail;
836 }
837
838 for ( ;; ) {
839 de = readdir(dir);
840 if (de == NULL) {
841 break;
842 }
843
844 nxt_debug(task, "readdir(\"%s\"): \"%s\"", rt->certs.start, de->d_name);
845
846 name.length = nxt_strlen(de->d_name);
847 name.start = (u_char *) de->d_name;
848
849 if (nxt_str_eq(&name, ".", 1) || nxt_str_eq(&name, "..", 2)) {
850 continue;
851 }
852
853 item = nxt_array_add(certs);
854 if (nxt_slow_path(item == NULL)) {
855 goto fail;
856 }
857
858 item->fd = -1;
859
860 size = rt->certs.length + name.length + 1;
861
862 if (size > alloc) {
863 size += 32;
864
865 p = nxt_realloc(buf, size);
866 if (p == NULL) {
867 goto fail;
868 }
869
870 alloc = size;
871 buf = p;
872 }
873
874 p = nxt_cpymem(buf, rt->certs.start, rt->certs.length);
875 p = nxt_cpymem(p, name.start, name.length + 1);
876
877 nxt_memzero(&file, sizeof(nxt_file_t));
878
879 file.name = buf;
880
881 ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN,
882 NXT_FILE_OWNER_ACCESS);
883
884
885 if (nxt_slow_path(ret != NXT_OK)) {
886 nxt_array_remove_last(certs);
887 continue;
888 }
889
890 item->fd = file.fd;
891
892 if (nxt_slow_path(nxt_str_dup(mp, &item->name, &name) == NULL)) {
893 goto fail;
894 }
895 }
896
897 if (buf != NULL) {
898 nxt_free(buf);
899 }
900
901 (void) closedir(dir);
902
903 return certs;
904
905fail:
906
907 if (buf != NULL) {
908 nxt_free(buf);
909 }
910
911 if (dir != NULL) {
912 (void) closedir(dir);
913 }
914
915 nxt_cert_store_release(certs);
916
917 return NULL;
918}
919
920
921void
922nxt_cert_store_release(nxt_array_t *certs)
923{
924 uint32_t i;
925 nxt_cert_item_t *items;
926
927 for (items = certs->elts, i = 0;
928 i < certs->nelts;
929 i++)
930 {
931 nxt_fd_close(items[i].fd);
932 }
933
934 nxt_array_destroy(certs);
935}
936
937
938#if 0
939
940void
941nxt_cert_store_discovery_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
942{
943 DIR *dir;
944 size_t size;
945 nxt_buf_t *b;
946 nxt_int_t ret;
947 nxt_port_t *port;
948 nxt_runtime_t *rt;
949 struct dirent *de;
950
951 port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
952 msg->port_msg.reply_port);
953
954 if (nxt_slow_path(port == NULL)) {
955 return;
956 }
957
958 b = NULL;
959 dir = NULL;
960
961 rt = task->thread->runtime;
962
963 if (nxt_slow_path(rt->certs.start == NULL)) {
964 nxt_alert(task, "no certificates storage directory");
965 goto fail;
966 }
967
968 dir = opendir((char *) rt->certs.start);
969 if (nxt_slow_path(dir == NULL)) {
970 nxt_alert(task, "opendir(\"%s\") failed %E",
971 rt->certs.start, nxt_errno);
972 goto fail;
973 }
974
975 size = 0;
976
977 for ( ;; ) {
978 de = readdir(dir);
979 if (de == NULL) {
980 break;
981 }
982
983 if (de->d_type != DT_REG) {
984 continue;
985 }
986
987 size += nxt_strlen(de->d_name) + 1;
988 }
989
990 b = nxt_port_mmap_get_buf(task, port, size);
991 if (nxt_slow_path(b == NULL)) {
992 goto fail;
993 }
994
995 rewinddir(dir);
996
997 for ( ;; ) {
998 de = readdir(dir);
999 if (de == NULL) {
1000 break;
1001 }
1002
1003 if (de->d_type != DT_REG) {
1004 continue;
1005 }
1006
1007 size = nxt_strlen(de->d_name) + 1;
1008
1009 if (nxt_slow_path(size > (size_t) nxt_buf_mem_free_size(&b->mem))) {
1010 b->mem.free = b->mem.start;
1011 break;
1012 }
1013
1014 b->mem.free = nxt_cpymem(b->mem.free, de->d_name, size);
1015 }
1016
1017 (void) closedir(dir);
1018 dir = NULL;
1019
1020 if (nxt_slow_path(nxt_buf_mem_free_size(&b->mem) != 0)) {
1021 nxt_alert(task, "certificates storage directory "
1022 "has changed while reading it");
1023 goto fail;
1024 }
1025
1026 ret = nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST, -1,
1027 msg->port_msg.stream, 0, b);
1028
1029 if (nxt_fast_path(ret == NXT_OK)) {
1030 return;
1031 }
1032
1033fail:
1034
1035 if (dir != NULL) {
1036 (void) closedir(dir);
1037 }
1038
1039 if (b != NULL) {
1040 b->completion_handler(task, b, b->parent);
1041 }
1042
1043 (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1,
1044 msg->port_msg.stream, 0, NULL);
1045}
1046
1047#endif
1048
1049
1050void
1051nxt_cert_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp,
1052 nxt_port_rpc_handler_t handler, void *ctx)
1053{
1054 uint32_t stream;
1055 nxt_int_t ret;
1056 nxt_buf_t *b;
1057 nxt_port_t *main_port, *recv_port;
1058 nxt_runtime_t *rt;
1059
1060 b = nxt_buf_mem_alloc(mp, name->length + 1, 0);
1061 if (nxt_slow_path(b == NULL)) {
1062 goto fail;
1063 }
1064
1065 nxt_buf_cpystr(b, name);
1066 *b->mem.free++ = '\0';
1067
1068 rt = task->thread->runtime;
1069 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1070 recv_port = rt->port_by_type[rt->type];
1071
1072 stream = nxt_port_rpc_register_handler(task, recv_port, handler, handler,
1073 -1, ctx);
1074 if (nxt_slow_path(stream == 0)) {
1075 goto fail;
1076 }
1077
1078 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_GET, -1,
1079 stream, recv_port->id, b);
1080
1081 if (nxt_slow_path(ret != NXT_OK)) {
1082 nxt_port_rpc_cancel(task, recv_port, stream);
1083 goto fail;
1084 }
1085
1086 return;
1087
1088fail:
1089
1090 handler(task, NULL, ctx);
1091}
1092
1093
1094void
1095nxt_cert_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1096{
1097 u_char *p;
1098 nxt_int_t ret;
1099 nxt_str_t name;
1100 nxt_file_t file;
1101 nxt_port_t *port;
1102 nxt_runtime_t *rt;
1103 nxt_port_msg_type_t type;
1104
1105 port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
1106 msg->port_msg.reply_port);
1107
1108 if (port == NULL) {
1109 return;
1110 }
1111
1112 nxt_memzero(&file, sizeof(nxt_file_t));
1113
1114 file.fd = -1;
1115 type = NXT_PORT_MSG_RPC_ERROR;
1116
1117 rt = task->thread->runtime;
1118
1119 if (nxt_slow_path(rt->certs.start == NULL)) {
1120 nxt_alert(task, "no certificates storage directory");
1121 goto error;
1122 }
1123
1124 name.start = msg->buf->mem.pos;
1125 name.length = nxt_strlen(name.start);
1126
1127 file.name = nxt_malloc(rt->certs.length + name.length + 1);
1128
1129 if (nxt_slow_path(file.name == NULL)) {
1130 goto error;
1131 }
1132
1133 p = nxt_cpymem(file.name, rt->certs.start, rt->certs.length);
1134 p = nxt_cpymem(p, name.start, name.length + 1);
1135
1136 ret = nxt_file_open(task, &file, NXT_FILE_RDWR, NXT_FILE_CREATE_OR_OPEN,
1137 NXT_FILE_OWNER_ACCESS);
1138
1139 nxt_free(file.name);
1140
1141 if (nxt_fast_path(ret == NXT_OK)) {
1142 type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD;
1143 }
1144
1145error:
1146
1147 (void) nxt_port_socket_write(task, port, type, file.fd,
1148 msg->port_msg.stream, 0, NULL);
1149}
1150
1151
1152void
1153nxt_cert_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp)
1154{
1155 nxt_buf_t *b;
1156 nxt_port_t *main_port;
1157 nxt_runtime_t *rt;
1158
1159 b = nxt_buf_mem_alloc(mp, name->length + 1, 0);
1160
1161 if (nxt_fast_path(b != NULL)) {
1162 nxt_buf_cpystr(b, name);
1163 *b->mem.free++ = '\0';
1164
1165 rt = task->thread->runtime;
1166 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1167
1168 (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_DELETE,
1169 -1, 0, 0, b);
1170 }
1171}
1172
1173
1174void
1175nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1176{
1177 u_char *p;
1178 nxt_str_t name;
1179 nxt_runtime_t *rt;
1180 nxt_file_name_t *path;
1181
1182 rt = task->thread->runtime;
1183
1184 if (nxt_slow_path(rt->certs.start == NULL)) {
1185 nxt_alert(task, "no certificates storage directory");
1186 return;
1187 }
1188
1189 name.start = msg->buf->mem.pos;
1190 name.length = nxt_strlen(name.start);
1191
1192 path = nxt_malloc(rt->certs.length + name.length + 1);
1193
1194 if (nxt_fast_path(path != NULL)) {
1195 p = nxt_cpymem(path, rt->certs.start, rt->certs.length);
1196 p = nxt_cpymem(p, name.start, name.length + 1);
1197
1198 (void) nxt_file_delete(path);
1199
1200 nxt_free(path);
1201 }
1202}