xref: /unit/src/nxt_cert.c (revision 2069:a74adcc53b78)
1774Svbart@nginx.com 
2774Svbart@nginx.com /*
3774Svbart@nginx.com  * Copyright (C) Valentin V. Bartenev
4774Svbart@nginx.com  * Copyright (C) NGINX, Inc.
5774Svbart@nginx.com  */
6774Svbart@nginx.com 
7774Svbart@nginx.com #include <nxt_main.h>
8774Svbart@nginx.com #include <nxt_conf.h>
9774Svbart@nginx.com #include <nxt_cert.h>
10774Svbart@nginx.com 
11774Svbart@nginx.com #include <dirent.h>
12774Svbart@nginx.com 
13774Svbart@nginx.com #include <openssl/bio.h>
14774Svbart@nginx.com #include <openssl/pem.h>
15774Svbart@nginx.com #include <openssl/evp.h>
16774Svbart@nginx.com #include <openssl/x509.h>
17774Svbart@nginx.com #include <openssl/x509v3.h>
18774Svbart@nginx.com #include <openssl/rsa.h>
19774Svbart@nginx.com #include <openssl/err.h>
20774Svbart@nginx.com 
21774Svbart@nginx.com 
22774Svbart@nginx.com struct nxt_cert_s {
23774Svbart@nginx.com     EVP_PKEY          *key;
24774Svbart@nginx.com     nxt_uint_t        count;
25774Svbart@nginx.com     X509              *chain[];
26774Svbart@nginx.com };
27774Svbart@nginx.com 
28774Svbart@nginx.com 
29774Svbart@nginx.com typedef struct {
30774Svbart@nginx.com     nxt_str_t         name;
31774Svbart@nginx.com     nxt_conf_value_t  *value;
32774Svbart@nginx.com     nxt_mp_t          *mp;
33774Svbart@nginx.com } nxt_cert_info_t;
34774Svbart@nginx.com 
35774Svbart@nginx.com 
36774Svbart@nginx.com typedef struct {
37774Svbart@nginx.com     nxt_str_t         name;
38774Svbart@nginx.com     nxt_fd_t          fd;
39774Svbart@nginx.com } nxt_cert_item_t;
40774Svbart@nginx.com 
41774Svbart@nginx.com 
42774Svbart@nginx.com static nxt_cert_t *nxt_cert_fd(nxt_task_t *task, nxt_fd_t fd);
43774Svbart@nginx.com static nxt_cert_t *nxt_cert_bio(nxt_task_t *task, BIO *bio);
44774Svbart@nginx.com static int nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix);
45774Svbart@nginx.com 
46774Svbart@nginx.com static nxt_conf_value_t *nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert);
47774Svbart@nginx.com static nxt_conf_value_t *nxt_cert_name_details(nxt_mp_t *mp, X509 *x509,
48774Svbart@nginx.com     nxt_bool_t issuer);
491821Svbart@nginx.com static nxt_conf_value_t *nxt_cert_alt_names_details(nxt_mp_t *mp,
501821Svbart@nginx.com     STACK_OF(GENERAL_NAME) *alt_names);
511869Sa.suvorov@f5.com static void nxt_cert_buf_completion(nxt_task_t *task, void *obj, void *data);
52774Svbart@nginx.com 
53774Svbart@nginx.com 
54774Svbart@nginx.com static nxt_lvlhsh_t  nxt_cert_info;
55774Svbart@nginx.com 
56774Svbart@nginx.com 
57774Svbart@nginx.com nxt_cert_t *
nxt_cert_mem(nxt_task_t * task,nxt_buf_mem_t * mbuf)58774Svbart@nginx.com nxt_cert_mem(nxt_task_t *task, nxt_buf_mem_t *mbuf)
59774Svbart@nginx.com {
60774Svbart@nginx.com     BIO         *bio;
61774Svbart@nginx.com     nxt_cert_t  *cert;
62774Svbart@nginx.com 
63774Svbart@nginx.com     bio = BIO_new_mem_buf(mbuf->pos, nxt_buf_mem_used_size(mbuf));
64774Svbart@nginx.com     if (nxt_slow_path(bio == NULL)) {
65774Svbart@nginx.com         nxt_openssl_log_error(task, NXT_LOG_ALERT, "BIO_new_mem_buf() failed");
66774Svbart@nginx.com         return NULL;
67774Svbart@nginx.com     }
68774Svbart@nginx.com 
69774Svbart@nginx.com     cert = nxt_cert_bio(task, bio);
70774Svbart@nginx.com 
71774Svbart@nginx.com     BIO_free(bio);
72774Svbart@nginx.com 
73774Svbart@nginx.com     return cert;
74774Svbart@nginx.com }
75774Svbart@nginx.com 
76774Svbart@nginx.com 
77774Svbart@nginx.com static nxt_cert_t *
nxt_cert_fd(nxt_task_t * task,nxt_fd_t fd)78774Svbart@nginx.com nxt_cert_fd(nxt_task_t *task, nxt_fd_t fd)
79774Svbart@nginx.com {
80774Svbart@nginx.com     BIO         *bio;
81774Svbart@nginx.com     nxt_cert_t  *cert;
82774Svbart@nginx.com 
83774Svbart@nginx.com     bio = BIO_new_fd(fd, 0);
84774Svbart@nginx.com     if (nxt_slow_path(bio == NULL)) {
85774Svbart@nginx.com         nxt_openssl_log_error(task, NXT_LOG_ALERT, "BIO_new_fd() failed");
86774Svbart@nginx.com         return NULL;
87774Svbart@nginx.com     }
88774Svbart@nginx.com 
89774Svbart@nginx.com     cert = nxt_cert_bio(task, bio);
90774Svbart@nginx.com 
91774Svbart@nginx.com     BIO_free(bio);
92774Svbart@nginx.com 
93774Svbart@nginx.com     return cert;
94774Svbart@nginx.com }
95774Svbart@nginx.com 
96774Svbart@nginx.com 
97774Svbart@nginx.com static nxt_cert_t *
nxt_cert_bio(nxt_task_t * task,BIO * bio)98774Svbart@nginx.com nxt_cert_bio(nxt_task_t *task, BIO *bio)
99774Svbart@nginx.com {
100774Svbart@nginx.com     int                         ret, suffix, key_id;
101774Svbart@nginx.com     long                        length, reason;
102774Svbart@nginx.com     char                        *type, *header;
103774Svbart@nginx.com     X509                        *x509;
104774Svbart@nginx.com     EVP_PKEY                    *key;
105774Svbart@nginx.com     nxt_uint_t                  nalloc;
106774Svbart@nginx.com     nxt_cert_t                  *cert, *new_cert;
107774Svbart@nginx.com     u_char                      *data;
108774Svbart@nginx.com     const u_char                *data_copy;
109774Svbart@nginx.com     PKCS8_PRIV_KEY_INFO         *p8inf;
110774Svbart@nginx.com     const EVP_PKEY_ASN1_METHOD  *ameth;
111774Svbart@nginx.com 
112774Svbart@nginx.com     nalloc = 4;
113774Svbart@nginx.com 
114774Svbart@nginx.com     cert = nxt_zalloc(sizeof(nxt_cert_t) + nalloc * sizeof(X509 *));
115774Svbart@nginx.com     if (cert == NULL) {
116774Svbart@nginx.com         return NULL;
117774Svbart@nginx.com     }
118774Svbart@nginx.com 
119774Svbart@nginx.com     for ( ;; ) {
120774Svbart@nginx.com         ret = PEM_read_bio(bio, &type, &header, &data, &length);
121774Svbart@nginx.com 
122774Svbart@nginx.com         if (ret == 0) {
123774Svbart@nginx.com             reason = ERR_GET_REASON(ERR_peek_last_error());
124774Svbart@nginx.com             if (reason != PEM_R_NO_START_LINE) {
125774Svbart@nginx.com                 nxt_openssl_log_error(task, NXT_LOG_ALERT,
126774Svbart@nginx.com                                       "PEM_read_bio() failed");
127774Svbart@nginx.com                 goto fail;
128774Svbart@nginx.com             }
129774Svbart@nginx.com 
130774Svbart@nginx.com             ERR_clear_error();
131774Svbart@nginx.com             break;
132774Svbart@nginx.com         }
133774Svbart@nginx.com 
134774Svbart@nginx.com         nxt_debug(task, "PEM type: \"%s\"", type);
135774Svbart@nginx.com 
136774Svbart@nginx.com         key = NULL;
137774Svbart@nginx.com         x509 = NULL;
138774Svbart@nginx.com /*
139774Svbart@nginx.com         EVP_CIPHER_INFO  cipher;
140774Svbart@nginx.com 
141774Svbart@nginx.com         if (PEM_get_EVP_CIPHER_INFO(header, &cipher) != 0) {
142774Svbart@nginx.com             nxt_alert(task, "encrypted PEM isn't supported");
143774Svbart@nginx.com             goto done;
144774Svbart@nginx.com         }
145774Svbart@nginx.com */
146774Svbart@nginx.com         if (nxt_strcmp(type, PEM_STRING_PKCS8) == 0) {
147774Svbart@nginx.com             nxt_alert(task, "PEM PKCS8 isn't supported");
148774Svbart@nginx.com             goto done;
149774Svbart@nginx.com         }
150774Svbart@nginx.com 
151774Svbart@nginx.com         if (nxt_strcmp(type, PEM_STRING_PKCS8INF) == 0) {
152774Svbart@nginx.com             data_copy = data;
153774Svbart@nginx.com 
154774Svbart@nginx.com             p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &data_copy, length);
155774Svbart@nginx.com 
156774Svbart@nginx.com             if (p8inf == NULL) {
157774Svbart@nginx.com                 nxt_openssl_log_error(task, NXT_LOG_ALERT,
158774Svbart@nginx.com                                       "d2i_PKCS8_PRIV_KEY_INFO() failed");
159774Svbart@nginx.com                 goto done;
160774Svbart@nginx.com             }
161774Svbart@nginx.com 
162774Svbart@nginx.com             key = EVP_PKCS82PKEY(p8inf);
163774Svbart@nginx.com 
164774Svbart@nginx.com             PKCS8_PRIV_KEY_INFO_free(p8inf);
165774Svbart@nginx.com             goto done;
166774Svbart@nginx.com         }
167774Svbart@nginx.com 
168774Svbart@nginx.com         suffix = nxt_nxt_cert_pem_suffix(type, PEM_STRING_PKCS8INF);
169774Svbart@nginx.com 
170774Svbart@nginx.com         if (suffix != 0) {
171774Svbart@nginx.com 
172774Svbart@nginx.com             ameth = EVP_PKEY_asn1_find_str(NULL, type, suffix);
173774Svbart@nginx.com             if (ameth == NULL) {
174774Svbart@nginx.com                 nxt_openssl_log_error(task, NXT_LOG_ALERT,
175774Svbart@nginx.com                                       "EVP_PKEY_asn1_find_str() failed");
176774Svbart@nginx.com                 goto done;
177774Svbart@nginx.com             }
178774Svbart@nginx.com 
179774Svbart@nginx.com             EVP_PKEY_asn1_get0_info(&key_id, NULL, NULL, NULL, NULL, ameth);
180774Svbart@nginx.com 
181774Svbart@nginx.com             data_copy = data;
182774Svbart@nginx.com 
183774Svbart@nginx.com             key = d2i_PrivateKey(key_id, NULL, &data_copy, length);
184774Svbart@nginx.com             goto done;
185774Svbart@nginx.com         }
186774Svbart@nginx.com 
187774Svbart@nginx.com         if (nxt_strcmp(type, PEM_STRING_X509) == 0
188774Svbart@nginx.com             || nxt_strcmp(type, PEM_STRING_X509_OLD) == 0)
189774Svbart@nginx.com         {
190774Svbart@nginx.com             data_copy = data;
191774Svbart@nginx.com 
192774Svbart@nginx.com             x509 = d2i_X509(NULL, &data_copy, length);
193774Svbart@nginx.com             if (x509 == NULL) {
194774Svbart@nginx.com                 nxt_openssl_log_error(task, NXT_LOG_ALERT,
195774Svbart@nginx.com                                       "d2i_X509() failed");
196774Svbart@nginx.com             }
197774Svbart@nginx.com 
198774Svbart@nginx.com             goto done;
199774Svbart@nginx.com         }
200774Svbart@nginx.com 
201774Svbart@nginx.com         if (nxt_strcmp(type, PEM_STRING_X509_TRUSTED) == 0) {
202774Svbart@nginx.com             data_copy = data;
203774Svbart@nginx.com 
204774Svbart@nginx.com             x509 = d2i_X509_AUX(NULL, &data_copy, length);
205774Svbart@nginx.com             if (x509 == NULL) {
206774Svbart@nginx.com                 nxt_openssl_log_error(task, NXT_LOG_ALERT,
207774Svbart@nginx.com                                       "d2i_X509_AUX() failed");
208774Svbart@nginx.com             }
209774Svbart@nginx.com 
210774Svbart@nginx.com             goto done;
211774Svbart@nginx.com         }
212774Svbart@nginx.com 
213774Svbart@nginx.com         nxt_alert(task, "unsupported PEM type: \"%s\"", type);
214774Svbart@nginx.com 
215774Svbart@nginx.com     done:
216774Svbart@nginx.com 
217774Svbart@nginx.com         OPENSSL_free(data);
218774Svbart@nginx.com         OPENSSL_free(header);
219774Svbart@nginx.com         OPENSSL_free(type);
220774Svbart@nginx.com 
221774Svbart@nginx.com         if (key != NULL) {
222774Svbart@nginx.com             if (cert->key != NULL) {
223774Svbart@nginx.com                 EVP_PKEY_free(key);
224774Svbart@nginx.com                 nxt_alert(task, "multiple private keys in PEM");
225774Svbart@nginx.com                 goto fail;
226774Svbart@nginx.com             }
227774Svbart@nginx.com 
228774Svbart@nginx.com             cert->key = key;
229774Svbart@nginx.com             continue;
230774Svbart@nginx.com         }
231774Svbart@nginx.com 
232774Svbart@nginx.com         if (x509 != NULL) {
233774Svbart@nginx.com 
234774Svbart@nginx.com             if (cert->count == nalloc) {
235774Svbart@nginx.com                 nalloc += 4;
236774Svbart@nginx.com 
237774Svbart@nginx.com                 new_cert = nxt_realloc(cert, sizeof(nxt_cert_t)
238774Svbart@nginx.com                                              + nalloc * sizeof(X509 *));
239774Svbart@nginx.com                 if (new_cert == NULL) {
240774Svbart@nginx.com                     X509_free(x509);
241774Svbart@nginx.com                     goto fail;
242774Svbart@nginx.com                 }
243774Svbart@nginx.com 
244774Svbart@nginx.com                 cert = new_cert;
245774Svbart@nginx.com             }
246774Svbart@nginx.com 
247774Svbart@nginx.com             cert->chain[cert->count++] = x509;
248774Svbart@nginx.com             continue;
249774Svbart@nginx.com         }
250774Svbart@nginx.com 
251774Svbart@nginx.com         goto fail;
252774Svbart@nginx.com     }
253774Svbart@nginx.com 
254774Svbart@nginx.com     if (cert->key == NULL) {
255774Svbart@nginx.com         nxt_alert(task, "no key found");
256774Svbart@nginx.com         goto fail;
257774Svbart@nginx.com     }
258774Svbart@nginx.com 
259774Svbart@nginx.com     if (cert->count == 0) {
260774Svbart@nginx.com         nxt_alert(task, "no certificates found");
261774Svbart@nginx.com         goto fail;
262774Svbart@nginx.com     }
263774Svbart@nginx.com 
264774Svbart@nginx.com     return cert;
265774Svbart@nginx.com 
266774Svbart@nginx.com fail:
267774Svbart@nginx.com 
268774Svbart@nginx.com     nxt_cert_destroy(cert);
269774Svbart@nginx.com 
270774Svbart@nginx.com     return NULL;
271774Svbart@nginx.com }
272774Svbart@nginx.com 
273774Svbart@nginx.com 
274774Svbart@nginx.com static int
nxt_nxt_cert_pem_suffix(char * pem_str,const char * suffix)275774Svbart@nginx.com nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix)
276774Svbart@nginx.com {
277774Svbart@nginx.com     char        *p;
278774Svbart@nginx.com     nxt_uint_t  pem_len, suffix_len;
279774Svbart@nginx.com 
280774Svbart@nginx.com     pem_len = strlen(pem_str);
281774Svbart@nginx.com     suffix_len = strlen(suffix);
282774Svbart@nginx.com 
283774Svbart@nginx.com     if (suffix_len + 1 >= pem_len) {
284774Svbart@nginx.com         return 0;
285774Svbart@nginx.com     }
286774Svbart@nginx.com 
287774Svbart@nginx.com     p = pem_str + pem_len - suffix_len;
288774Svbart@nginx.com 
289774Svbart@nginx.com     if (nxt_strcmp(p, suffix) != 0) {
290774Svbart@nginx.com         return 0;
291774Svbart@nginx.com     }
292774Svbart@nginx.com 
293774Svbart@nginx.com     p--;
294774Svbart@nginx.com 
295774Svbart@nginx.com     if (*p != ' ') {
296774Svbart@nginx.com         return 0;
297774Svbart@nginx.com     }
298774Svbart@nginx.com 
299774Svbart@nginx.com     return p - pem_str;
300774Svbart@nginx.com }
301774Svbart@nginx.com 
302774Svbart@nginx.com 
303774Svbart@nginx.com void
nxt_cert_destroy(nxt_cert_t * cert)304774Svbart@nginx.com nxt_cert_destroy(nxt_cert_t *cert)
305774Svbart@nginx.com {
306774Svbart@nginx.com     nxt_uint_t  i;
307774Svbart@nginx.com 
308774Svbart@nginx.com     EVP_PKEY_free(cert->key);
309774Svbart@nginx.com 
310774Svbart@nginx.com     for (i = 0; i != cert->count; i++) {
311774Svbart@nginx.com         X509_free(cert->chain[i]);
312774Svbart@nginx.com     }
313774Svbart@nginx.com 
314774Svbart@nginx.com     nxt_free(cert);
315774Svbart@nginx.com }
316774Svbart@nginx.com 
317774Svbart@nginx.com 
318774Svbart@nginx.com 
319774Svbart@nginx.com static nxt_int_t
nxt_cert_info_hash_test(nxt_lvlhsh_query_t * lhq,void * data)320774Svbart@nginx.com nxt_cert_info_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
321774Svbart@nginx.com {
322774Svbart@nginx.com     nxt_cert_info_t  *info;
323774Svbart@nginx.com 
324774Svbart@nginx.com     info = data;
325774Svbart@nginx.com 
326774Svbart@nginx.com     if (nxt_strcasestr_eq(&lhq->key, &info->name)) {
327774Svbart@nginx.com         return NXT_OK;
328774Svbart@nginx.com     }
329774Svbart@nginx.com 
330774Svbart@nginx.com     return NXT_DECLINED;
331774Svbart@nginx.com }
332774Svbart@nginx.com 
333774Svbart@nginx.com 
334774Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_cert_info_hash_proto
335774Svbart@nginx.com     nxt_aligned(64) =
336774Svbart@nginx.com {
337774Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
338774Svbart@nginx.com     nxt_cert_info_hash_test,
339774Svbart@nginx.com     nxt_lvlhsh_alloc,
340774Svbart@nginx.com     nxt_lvlhsh_free,
341774Svbart@nginx.com };
342774Svbart@nginx.com 
343774Svbart@nginx.com 
344774Svbart@nginx.com void
nxt_cert_info_init(nxt_task_t * task,nxt_array_t * certs)345774Svbart@nginx.com nxt_cert_info_init(nxt_task_t *task, nxt_array_t *certs)
346774Svbart@nginx.com {
347774Svbart@nginx.com     uint32_t         i;
348774Svbart@nginx.com     nxt_cert_t       *cert;
349774Svbart@nginx.com     nxt_cert_item_t  *items;
350774Svbart@nginx.com 
351774Svbart@nginx.com     for (items = certs->elts, i = 0; i < certs->nelts; i++) {
352774Svbart@nginx.com         cert = nxt_cert_fd(task, items[i].fd);
353774Svbart@nginx.com 
354774Svbart@nginx.com         if (nxt_slow_path(cert == NULL)) {
355774Svbart@nginx.com             continue;
356774Svbart@nginx.com         }
357774Svbart@nginx.com 
358774Svbart@nginx.com         (void) nxt_cert_info_save(&items[i].name, cert);
359774Svbart@nginx.com 
360774Svbart@nginx.com         nxt_cert_destroy(cert);
361774Svbart@nginx.com     }
362774Svbart@nginx.com }
363774Svbart@nginx.com 
364774Svbart@nginx.com 
365774Svbart@nginx.com nxt_int_t
nxt_cert_info_save(nxt_str_t * name,nxt_cert_t * cert)366774Svbart@nginx.com nxt_cert_info_save(nxt_str_t *name, nxt_cert_t *cert)
367774Svbart@nginx.com {
368774Svbart@nginx.com     nxt_mp_t            *mp;
369774Svbart@nginx.com     nxt_int_t           ret;
370774Svbart@nginx.com     nxt_cert_info_t     *info;
371774Svbart@nginx.com     nxt_conf_value_t    *value;
372774Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
373774Svbart@nginx.com 
374774Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
375774Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
376774Svbart@nginx.com         return NXT_ERROR;
377774Svbart@nginx.com     }
378774Svbart@nginx.com 
379774Svbart@nginx.com     info = nxt_mp_get(mp, sizeof(nxt_cert_info_t));
380774Svbart@nginx.com     if (nxt_slow_path(info == NULL)) {
381774Svbart@nginx.com         goto fail;
382774Svbart@nginx.com     }
383774Svbart@nginx.com 
384774Svbart@nginx.com     name = nxt_str_dup(mp, &info->name, name);
385774Svbart@nginx.com     if (nxt_slow_path(name == NULL)) {
386774Svbart@nginx.com         goto fail;
387774Svbart@nginx.com     }
388774Svbart@nginx.com 
389774Svbart@nginx.com     value = nxt_cert_details(mp, cert);
390774Svbart@nginx.com     if (nxt_slow_path(value == NULL)) {
391774Svbart@nginx.com         goto fail;
392774Svbart@nginx.com     }
393774Svbart@nginx.com 
394774Svbart@nginx.com     info->mp = mp;
395774Svbart@nginx.com     info->value = value;
396774Svbart@nginx.com 
397774Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(name->start, name->length);
398774Svbart@nginx.com     lhq.replace = 1;
399774Svbart@nginx.com     lhq.key = *name;
400774Svbart@nginx.com     lhq.value = info;
401774Svbart@nginx.com     lhq.proto = &nxt_cert_info_hash_proto;
402774Svbart@nginx.com 
403774Svbart@nginx.com     ret = nxt_lvlhsh_insert(&nxt_cert_info, &lhq);
404774Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
405774Svbart@nginx.com         goto fail;
406774Svbart@nginx.com     }
407774Svbart@nginx.com 
408774Svbart@nginx.com     if (lhq.value != info) {
409774Svbart@nginx.com         info = lhq.value;
410774Svbart@nginx.com         nxt_mp_destroy(info->mp);
411774Svbart@nginx.com     }
412774Svbart@nginx.com 
413774Svbart@nginx.com     return NXT_OK;
414774Svbart@nginx.com 
415774Svbart@nginx.com fail:
416774Svbart@nginx.com 
417774Svbart@nginx.com     nxt_mp_destroy(mp);
418774Svbart@nginx.com     return NXT_ERROR;
419774Svbart@nginx.com }
420774Svbart@nginx.com 
421774Svbart@nginx.com 
422774Svbart@nginx.com nxt_conf_value_t *
nxt_cert_info_get(nxt_str_t * name)423774Svbart@nginx.com nxt_cert_info_get(nxt_str_t *name)
424774Svbart@nginx.com {
425774Svbart@nginx.com     nxt_int_t           ret;
426774Svbart@nginx.com     nxt_cert_info_t     *info;
427774Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
428774Svbart@nginx.com 
429774Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(name->start, name->length);
430774Svbart@nginx.com     lhq.key = *name;
431774Svbart@nginx.com     lhq.proto = &nxt_cert_info_hash_proto;
432774Svbart@nginx.com 
433774Svbart@nginx.com     ret = nxt_lvlhsh_find(&nxt_cert_info, &lhq);
434774Svbart@nginx.com     if (ret != NXT_OK) {
435774Svbart@nginx.com         return NULL;
436774Svbart@nginx.com     }
437774Svbart@nginx.com 
438774Svbart@nginx.com     info = lhq.value;
439774Svbart@nginx.com 
440774Svbart@nginx.com     return info->value;
441774Svbart@nginx.com }
442774Svbart@nginx.com 
443774Svbart@nginx.com 
444774Svbart@nginx.com nxt_conf_value_t *
nxt_cert_info_get_all(nxt_mp_t * mp)445774Svbart@nginx.com nxt_cert_info_get_all(nxt_mp_t *mp)
446774Svbart@nginx.com {
447774Svbart@nginx.com     uint32_t           i;
448774Svbart@nginx.com     nxt_cert_info_t    *info;
449774Svbart@nginx.com     nxt_conf_value_t   *all;
450774Svbart@nginx.com     nxt_lvlhsh_each_t  lhe;
451774Svbart@nginx.com 
452774Svbart@nginx.com     nxt_lvlhsh_each_init(&lhe, &nxt_cert_info_hash_proto);
453774Svbart@nginx.com 
454774Svbart@nginx.com     i = 0;
455774Svbart@nginx.com 
456774Svbart@nginx.com     for ( ;; ) {
457774Svbart@nginx.com         info = nxt_lvlhsh_each(&nxt_cert_info, &lhe);
458774Svbart@nginx.com 
459774Svbart@nginx.com         if (info == NULL) {
460774Svbart@nginx.com             break;
461774Svbart@nginx.com         }
462774Svbart@nginx.com 
463774Svbart@nginx.com         i++;
464774Svbart@nginx.com     }
465774Svbart@nginx.com 
466774Svbart@nginx.com     all = nxt_conf_create_object(mp, i);
467774Svbart@nginx.com     if (nxt_slow_path(all == NULL)) {
468774Svbart@nginx.com         return NULL;
469774Svbart@nginx.com     }
470774Svbart@nginx.com 
471774Svbart@nginx.com     nxt_lvlhsh_each_init(&lhe, &nxt_cert_info_hash_proto);
472774Svbart@nginx.com 
473774Svbart@nginx.com     i = 0;
474774Svbart@nginx.com 
475774Svbart@nginx.com     for ( ;; ) {
476774Svbart@nginx.com         info = nxt_lvlhsh_each(&nxt_cert_info, &lhe);
477774Svbart@nginx.com 
478774Svbart@nginx.com         if (info == NULL) {
479774Svbart@nginx.com             break;
480774Svbart@nginx.com         }
481774Svbart@nginx.com 
482774Svbart@nginx.com         nxt_conf_set_member(all, &info->name, info->value, i);
483774Svbart@nginx.com 
484774Svbart@nginx.com         i++;
485774Svbart@nginx.com     }
486774Svbart@nginx.com 
487774Svbart@nginx.com     return all;
488774Svbart@nginx.com }
489774Svbart@nginx.com 
490774Svbart@nginx.com 
491774Svbart@nginx.com static nxt_conf_value_t *
nxt_cert_details(nxt_mp_t * mp,nxt_cert_t * cert)492774Svbart@nginx.com nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert)
493774Svbart@nginx.com {
494774Svbart@nginx.com     BIO               *bio;
495774Svbart@nginx.com     X509              *x509;
496774Svbart@nginx.com     u_char            *end;
497774Svbart@nginx.com     EVP_PKEY          *key;
498774Svbart@nginx.com     ASN1_TIME         *asn1_time;
499774Svbart@nginx.com     nxt_str_t         str;
500774Svbart@nginx.com     nxt_int_t         ret;
501774Svbart@nginx.com     nxt_uint_t        i;
502774Svbart@nginx.com     nxt_conf_value_t  *object, *chain, *element, *value;
503774Svbart@nginx.com     u_char            buf[256];
504774Svbart@nginx.com 
505774Svbart@nginx.com     static nxt_str_t key_str = nxt_string("key");
506774Svbart@nginx.com     static nxt_str_t chain_str = nxt_string("chain");
507774Svbart@nginx.com     static nxt_str_t since_str = nxt_string("since");
508774Svbart@nginx.com     static nxt_str_t until_str = nxt_string("until");
509774Svbart@nginx.com     static nxt_str_t issuer_str = nxt_string("issuer");
510774Svbart@nginx.com     static nxt_str_t subject_str = nxt_string("subject");
511774Svbart@nginx.com     static nxt_str_t validity_str = nxt_string("validity");
512774Svbart@nginx.com 
513774Svbart@nginx.com     object = nxt_conf_create_object(mp, 2);
514774Svbart@nginx.com     if (nxt_slow_path(object == NULL)) {
515774Svbart@nginx.com         return NULL;
516774Svbart@nginx.com     }
517774Svbart@nginx.com 
518774Svbart@nginx.com     if (cert->key != NULL) {
519774Svbart@nginx.com         key = cert->key;
520774Svbart@nginx.com 
521774Svbart@nginx.com         switch (EVP_PKEY_base_id(key)) {
522774Svbart@nginx.com         case EVP_PKEY_RSA:
523774Svbart@nginx.com             end = nxt_sprintf(buf, buf + sizeof(buf), "RSA (%d bits)",
524774Svbart@nginx.com                               EVP_PKEY_bits(key));
525774Svbart@nginx.com 
526774Svbart@nginx.com             str.length = end - buf;
527774Svbart@nginx.com             str.start = buf;
528774Svbart@nginx.com             break;
529774Svbart@nginx.com 
530774Svbart@nginx.com         case EVP_PKEY_DH:
531774Svbart@nginx.com             end = nxt_sprintf(buf, buf + sizeof(buf), "DH (%d bits)",
532774Svbart@nginx.com                               EVP_PKEY_bits(key));
533774Svbart@nginx.com 
534774Svbart@nginx.com             str.length = end - buf;
535774Svbart@nginx.com             str.start = buf;
536774Svbart@nginx.com             break;
537774Svbart@nginx.com 
538774Svbart@nginx.com         case EVP_PKEY_EC:
539774Svbart@nginx.com             nxt_str_set(&str, "ECDH");
540774Svbart@nginx.com             break;
541774Svbart@nginx.com 
542774Svbart@nginx.com         default:
543774Svbart@nginx.com             nxt_str_set(&str, "unknown");
544774Svbart@nginx.com         }
545774Svbart@nginx.com 
546774Svbart@nginx.com         ret = nxt_conf_set_member_string_dup(object, mp, &key_str, &str, 0);
547774Svbart@nginx.com 
548774Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
549774Svbart@nginx.com             return NULL;
550774Svbart@nginx.com         }
551774Svbart@nginx.com 
552774Svbart@nginx.com     } else {
553774Svbart@nginx.com         nxt_conf_set_member_null(object, &key_str, 0);
554774Svbart@nginx.com     }
555774Svbart@nginx.com 
556774Svbart@nginx.com     chain = nxt_conf_create_array(mp, cert->count);
557774Svbart@nginx.com     if (nxt_slow_path(chain == NULL)) {
558774Svbart@nginx.com         return NULL;
559774Svbart@nginx.com     }
560774Svbart@nginx.com 
561774Svbart@nginx.com     for (i = 0; i < cert->count; i++) {
562774Svbart@nginx.com         element = nxt_conf_create_object(mp, 3);
563774Svbart@nginx.com         if (nxt_slow_path(element == NULL)) {
564774Svbart@nginx.com             return NULL;
565774Svbart@nginx.com         }
566774Svbart@nginx.com 
567774Svbart@nginx.com         x509 = cert->chain[i];
568774Svbart@nginx.com 
569774Svbart@nginx.com         value = nxt_cert_name_details(mp, x509, 0);
570774Svbart@nginx.com         if (value == NULL) {
571774Svbart@nginx.com             return NULL;
572774Svbart@nginx.com         }
573774Svbart@nginx.com 
574774Svbart@nginx.com         nxt_conf_set_member(element, &subject_str, value, 0);
575774Svbart@nginx.com 
576774Svbart@nginx.com         value = nxt_cert_name_details(mp, x509, 1);
577774Svbart@nginx.com         if (value == NULL) {
578774Svbart@nginx.com             return NULL;
579774Svbart@nginx.com         }
580774Svbart@nginx.com 
581774Svbart@nginx.com         nxt_conf_set_member(element, &issuer_str, value, 1);
582774Svbart@nginx.com 
583774Svbart@nginx.com         value = nxt_conf_create_object(mp, 2);
584774Svbart@nginx.com         if (nxt_slow_path(value == NULL)) {
585774Svbart@nginx.com             return NULL;
586774Svbart@nginx.com         }
587774Svbart@nginx.com 
588774Svbart@nginx.com         bio = BIO_new(BIO_s_mem());
589774Svbart@nginx.com         if (nxt_slow_path(bio == NULL)) {
590774Svbart@nginx.com             return NULL;
591774Svbart@nginx.com         }
592774Svbart@nginx.com 
593774Svbart@nginx.com         asn1_time = X509_get_notBefore(x509);
594774Svbart@nginx.com 
595774Svbart@nginx.com         ret = ASN1_TIME_print(bio, asn1_time);
596774Svbart@nginx.com 
597774Svbart@nginx.com         if (nxt_fast_path(ret == 1)) {
598774Svbart@nginx.com             str.length = BIO_get_mem_data(bio, &str.start);
599774Svbart@nginx.com             ret = nxt_conf_set_member_string_dup(value, mp, &since_str, &str,
600774Svbart@nginx.com                                                  0);
601774Svbart@nginx.com         } else {
602774Svbart@nginx.com             ret = NXT_ERROR;
603774Svbart@nginx.com         }
604774Svbart@nginx.com 
605774Svbart@nginx.com         BIO_free(bio);
606774Svbart@nginx.com 
607774Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
608774Svbart@nginx.com             return NULL;
609774Svbart@nginx.com         }
610774Svbart@nginx.com 
611774Svbart@nginx.com         bio = BIO_new(BIO_s_mem());
612774Svbart@nginx.com         if (nxt_slow_path(bio == NULL)) {
613774Svbart@nginx.com             return NULL;
614774Svbart@nginx.com         }
615774Svbart@nginx.com 
616774Svbart@nginx.com         asn1_time = X509_get_notAfter(x509);
617774Svbart@nginx.com 
618774Svbart@nginx.com         ret = ASN1_TIME_print(bio, asn1_time);
619774Svbart@nginx.com 
620774Svbart@nginx.com         if (nxt_fast_path(ret == 1)) {
621774Svbart@nginx.com             str.length = BIO_get_mem_data(bio, &str.start);
622774Svbart@nginx.com             ret = nxt_conf_set_member_string_dup(value, mp, &until_str, &str,
623774Svbart@nginx.com                                                  1);
624774Svbart@nginx.com         } else {
625774Svbart@nginx.com             ret = NXT_ERROR;
626774Svbart@nginx.com         }
627774Svbart@nginx.com 
628774Svbart@nginx.com         BIO_free(bio);
629774Svbart@nginx.com 
630774Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
631774Svbart@nginx.com             return NULL;
632774Svbart@nginx.com         }
633774Svbart@nginx.com 
634774Svbart@nginx.com         nxt_conf_set_member(element, &validity_str, value, 2);
635774Svbart@nginx.com 
636774Svbart@nginx.com         nxt_conf_set_element(chain, i, element);
637774Svbart@nginx.com     }
638774Svbart@nginx.com 
639774Svbart@nginx.com     nxt_conf_set_member(object, &chain_str, chain, 1);
640774Svbart@nginx.com 
641774Svbart@nginx.com     return object;
642774Svbart@nginx.com }
643774Svbart@nginx.com 
644774Svbart@nginx.com 
645774Svbart@nginx.com typedef struct {
646774Svbart@nginx.com     int        nid;
647774Svbart@nginx.com     nxt_str_t  name;
648774Svbart@nginx.com } nxt_cert_nid_t;
649774Svbart@nginx.com 
650774Svbart@nginx.com 
651774Svbart@nginx.com static nxt_conf_value_t *
nxt_cert_name_details(nxt_mp_t * mp,X509 * x509,nxt_bool_t issuer)652774Svbart@nginx.com nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer)
653774Svbart@nginx.com {
654774Svbart@nginx.com     int                     len;
655774Svbart@nginx.com     X509_NAME               *x509_name;
656774Svbart@nginx.com     nxt_str_t               str;
657774Svbart@nginx.com     nxt_int_t               ret;
658774Svbart@nginx.com     nxt_uint_t              i, n, count;
659774Svbart@nginx.com     nxt_conf_value_t        *object, *names;
660774Svbart@nginx.com     STACK_OF(GENERAL_NAME)  *alt_names;
661774Svbart@nginx.com     u_char                  buf[256];
662774Svbart@nginx.com 
663774Svbart@nginx.com     static nxt_cert_nid_t  nids[] = {
664774Svbart@nginx.com         { NID_commonName, nxt_string("common_name") },
665774Svbart@nginx.com         { NID_countryName, nxt_string("country") },
666774Svbart@nginx.com         { NID_stateOrProvinceName, nxt_string("state_or_province") },
667774Svbart@nginx.com         { NID_localityName, nxt_string("locality") },
668774Svbart@nginx.com         { NID_organizationName, nxt_string("organization") },
669774Svbart@nginx.com         { NID_organizationalUnitName, nxt_string("department") },
670774Svbart@nginx.com     };
671774Svbart@nginx.com 
672774Svbart@nginx.com     static nxt_str_t alt_names_str = nxt_string("alt_names");
673774Svbart@nginx.com 
674774Svbart@nginx.com     count = 0;
675774Svbart@nginx.com 
676774Svbart@nginx.com     x509_name = issuer ? X509_get_issuer_name(x509)
677774Svbart@nginx.com                        : X509_get_subject_name(x509);
678774Svbart@nginx.com 
679774Svbart@nginx.com     for (n = 0; n != nxt_nitems(nids); n++) {
680774Svbart@nginx.com 
681774Svbart@nginx.com         if (X509_NAME_get_index_by_NID(x509_name, nids[n].nid, -1) < 0) {
682774Svbart@nginx.com             continue;
683774Svbart@nginx.com         }
684774Svbart@nginx.com 
685774Svbart@nginx.com         count++;
686774Svbart@nginx.com     }
687774Svbart@nginx.com 
688774Svbart@nginx.com     alt_names = X509_get_ext_d2i(x509, issuer ? NID_issuer_alt_name
689774Svbart@nginx.com                                               : NID_subject_alt_name,
690774Svbart@nginx.com                                  NULL, NULL);
691774Svbart@nginx.com 
692774Svbart@nginx.com     if (alt_names != NULL) {
6931822Svbart@nginx.com         names = nxt_cert_alt_names_details(mp, alt_names);
6941822Svbart@nginx.com 
6951822Svbart@nginx.com         sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
6961822Svbart@nginx.com 
6971822Svbart@nginx.com         if (nxt_slow_path(names == NULL)) {
6981822Svbart@nginx.com             return NULL;
6991822Svbart@nginx.com         }
7001822Svbart@nginx.com 
701774Svbart@nginx.com         count++;
7021822Svbart@nginx.com 
7031822Svbart@nginx.com     } else {
7041822Svbart@nginx.com         names = NULL;
705774Svbart@nginx.com     }
706774Svbart@nginx.com 
707774Svbart@nginx.com     object = nxt_conf_create_object(mp, count);
708774Svbart@nginx.com     if (nxt_slow_path(object == NULL)) {
7091822Svbart@nginx.com         return NULL;
710774Svbart@nginx.com     }
711774Svbart@nginx.com 
712774Svbart@nginx.com     for (n = 0, i = 0; n != nxt_nitems(nids) && i != count; n++) {
713774Svbart@nginx.com 
714774Svbart@nginx.com         len = X509_NAME_get_text_by_NID(x509_name, nids[n].nid,
715774Svbart@nginx.com                                         (char *) buf, sizeof(buf));
716774Svbart@nginx.com 
7171822Svbart@nginx.com         if (n == 1 && names != NULL) {
7181822Svbart@nginx.com             nxt_conf_set_member(object, &alt_names_str, names, i++);
7191822Svbart@nginx.com         }
7201822Svbart@nginx.com 
721774Svbart@nginx.com         if (len < 0) {
722774Svbart@nginx.com             continue;
723774Svbart@nginx.com         }
724774Svbart@nginx.com 
725774Svbart@nginx.com         str.length = len;
726774Svbart@nginx.com         str.start = buf;
727774Svbart@nginx.com 
728774Svbart@nginx.com         ret = nxt_conf_set_member_string_dup(object, mp, &nids[n].name,
729774Svbart@nginx.com                                              &str, i++);
730774Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
7311822Svbart@nginx.com             return NULL;
732774Svbart@nginx.com         }
733774Svbart@nginx.com     }
734774Svbart@nginx.com 
735774Svbart@nginx.com     return object;
736774Svbart@nginx.com }
737774Svbart@nginx.com 
738774Svbart@nginx.com 
7391821Svbart@nginx.com static nxt_conf_value_t *
nxt_cert_alt_names_details(nxt_mp_t * mp,STACK_OF (GENERAL_NAME)* alt_names)7401821Svbart@nginx.com nxt_cert_alt_names_details(nxt_mp_t *mp, STACK_OF(GENERAL_NAME) *alt_names)
7411821Svbart@nginx.com {
7421821Svbart@nginx.com     nxt_str_t         str;
7431821Svbart@nginx.com     nxt_int_t         ret;
7441821Svbart@nginx.com     nxt_uint_t        i, n, count;
7451821Svbart@nginx.com     GENERAL_NAME      *name;
7461821Svbart@nginx.com     nxt_conf_value_t  *array;
7471821Svbart@nginx.com 
7481821Svbart@nginx.com     count = sk_GENERAL_NAME_num(alt_names);
7491821Svbart@nginx.com     n = 0;
7501821Svbart@nginx.com 
7511821Svbart@nginx.com     for (i = 0; i != count; i++) {
7521821Svbart@nginx.com         name = sk_GENERAL_NAME_value(alt_names, i);
7531821Svbart@nginx.com 
7541821Svbart@nginx.com         if (name->type != GEN_DNS) {
7551821Svbart@nginx.com             continue;
7561821Svbart@nginx.com         }
7571821Svbart@nginx.com 
7581821Svbart@nginx.com         n++;
7591821Svbart@nginx.com     }
7601821Svbart@nginx.com 
7611821Svbart@nginx.com     array = nxt_conf_create_array(mp, n);
7621821Svbart@nginx.com     if (nxt_slow_path(array == NULL)) {
7631821Svbart@nginx.com         return NULL;
7641821Svbart@nginx.com     }
7651821Svbart@nginx.com 
7661821Svbart@nginx.com     for (n = 0, i = 0; n != count; n++) {
7671821Svbart@nginx.com         name = sk_GENERAL_NAME_value(alt_names, n);
7681821Svbart@nginx.com 
7691821Svbart@nginx.com         if (name->type != GEN_DNS) {
7701821Svbart@nginx.com             continue;
7711821Svbart@nginx.com         }
7721821Svbart@nginx.com 
7731821Svbart@nginx.com         str.length = ASN1_STRING_length(name->d.dNSName);
7741821Svbart@nginx.com #if OPENSSL_VERSION_NUMBER > 0x10100000L
7751821Svbart@nginx.com         str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName);
7761821Svbart@nginx.com #else
7771821Svbart@nginx.com         str.start = ASN1_STRING_data(name->d.dNSName);
7781821Svbart@nginx.com #endif
7791821Svbart@nginx.com 
7801821Svbart@nginx.com         ret = nxt_conf_set_element_string_dup(array, mp, i++, &str);
7811821Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
7821821Svbart@nginx.com             return NULL;
7831821Svbart@nginx.com         }
7841821Svbart@nginx.com     }
7851821Svbart@nginx.com 
7861821Svbart@nginx.com     return array;
7871821Svbart@nginx.com }
7881821Svbart@nginx.com 
7891821Svbart@nginx.com 
790774Svbart@nginx.com nxt_int_t
nxt_cert_info_delete(nxt_str_t * name)791774Svbart@nginx.com nxt_cert_info_delete(nxt_str_t *name)
792774Svbart@nginx.com {
793774Svbart@nginx.com     nxt_int_t           ret;
794774Svbart@nginx.com     nxt_cert_info_t     *info;
795774Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
796774Svbart@nginx.com 
797774Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(name->start, name->length);
798774Svbart@nginx.com     lhq.key = *name;
799774Svbart@nginx.com     lhq.proto = &nxt_cert_info_hash_proto;
800774Svbart@nginx.com 
801774Svbart@nginx.com     ret = nxt_lvlhsh_delete(&nxt_cert_info, &lhq);
802774Svbart@nginx.com 
803774Svbart@nginx.com     if (ret == NXT_OK) {
804774Svbart@nginx.com         info = lhq.value;
805774Svbart@nginx.com         nxt_mp_destroy(info->mp);
806774Svbart@nginx.com     }
807774Svbart@nginx.com 
808774Svbart@nginx.com     return ret;
809774Svbart@nginx.com }
810774Svbart@nginx.com 
811774Svbart@nginx.com 
812774Svbart@nginx.com 
813774Svbart@nginx.com nxt_array_t *
nxt_cert_store_load(nxt_task_t * task,nxt_mp_t * mp)8141488St.nateldemoura@f5.com nxt_cert_store_load(nxt_task_t *task, nxt_mp_t *mp)
815774Svbart@nginx.com {
816774Svbart@nginx.com     DIR              *dir;
817774Svbart@nginx.com     size_t           size, alloc;
818774Svbart@nginx.com     u_char           *buf, *p;
819774Svbart@nginx.com     nxt_str_t        name;
820774Svbart@nginx.com     nxt_int_t        ret;
821774Svbart@nginx.com     nxt_file_t       file;
822774Svbart@nginx.com     nxt_array_t      *certs;
823774Svbart@nginx.com     nxt_runtime_t    *rt;
824774Svbart@nginx.com     struct dirent    *de;
825774Svbart@nginx.com     nxt_cert_item_t  *item;
826774Svbart@nginx.com 
827774Svbart@nginx.com     rt = task->thread->runtime;
828774Svbart@nginx.com 
829774Svbart@nginx.com     if (nxt_slow_path(rt->certs.start == NULL)) {
830774Svbart@nginx.com         nxt_alert(task, "no certificates storage directory");
831774Svbart@nginx.com         return NULL;
832774Svbart@nginx.com     }
833774Svbart@nginx.com 
834774Svbart@nginx.com     certs = nxt_array_create(mp, 16, sizeof(nxt_cert_item_t));
835774Svbart@nginx.com     if (nxt_slow_path(certs == NULL)) {
836774Svbart@nginx.com         return NULL;
837774Svbart@nginx.com     }
838774Svbart@nginx.com 
839774Svbart@nginx.com     buf = NULL;
840774Svbart@nginx.com     alloc = 0;
841774Svbart@nginx.com 
842774Svbart@nginx.com     dir = opendir((char *) rt->certs.start);
843774Svbart@nginx.com     if (nxt_slow_path(dir == NULL)) {
844774Svbart@nginx.com         nxt_alert(task, "opendir(\"%s\") failed %E",
845774Svbart@nginx.com                   rt->certs.start, nxt_errno);
846774Svbart@nginx.com         goto fail;
847774Svbart@nginx.com     }
848774Svbart@nginx.com 
849774Svbart@nginx.com     for ( ;; ) {
850774Svbart@nginx.com         de = readdir(dir);
851774Svbart@nginx.com         if (de == NULL) {
852774Svbart@nginx.com             break;
853774Svbart@nginx.com         }
854774Svbart@nginx.com 
8551813Svbart@nginx.com         nxt_debug(task, "readdir(\"%s\"): \"%s\"", rt->certs.start, de->d_name);
8561813Svbart@nginx.com 
8571813Svbart@nginx.com         name.length = nxt_strlen(de->d_name);
8581813Svbart@nginx.com         name.start = (u_char *) de->d_name;
8591813Svbart@nginx.com 
8601813Svbart@nginx.com         if (nxt_str_eq(&name, ".", 1) || nxt_str_eq(&name, "..", 2)) {
861774Svbart@nginx.com             continue;
862774Svbart@nginx.com         }
863774Svbart@nginx.com 
864774Svbart@nginx.com         item = nxt_array_add(certs);
865774Svbart@nginx.com         if (nxt_slow_path(item == NULL)) {
866774Svbart@nginx.com             goto fail;
867774Svbart@nginx.com         }
868774Svbart@nginx.com 
869774Svbart@nginx.com         item->fd = -1;
870774Svbart@nginx.com 
871774Svbart@nginx.com         size = rt->certs.length + name.length + 1;
872774Svbart@nginx.com 
873774Svbart@nginx.com         if (size > alloc) {
874774Svbart@nginx.com             size += 32;
875774Svbart@nginx.com 
876774Svbart@nginx.com             p = nxt_realloc(buf, size);
877774Svbart@nginx.com             if (p == NULL) {
878774Svbart@nginx.com                 goto fail;
879774Svbart@nginx.com             }
880774Svbart@nginx.com 
881774Svbart@nginx.com             alloc = size;
882774Svbart@nginx.com             buf = p;
883774Svbart@nginx.com         }
884774Svbart@nginx.com 
885774Svbart@nginx.com         p = nxt_cpymem(buf, rt->certs.start, rt->certs.length);
886774Svbart@nginx.com         p = nxt_cpymem(p, name.start, name.length + 1);
887774Svbart@nginx.com 
888774Svbart@nginx.com         nxt_memzero(&file, sizeof(nxt_file_t));
889774Svbart@nginx.com 
890774Svbart@nginx.com         file.name = buf;
891774Svbart@nginx.com 
892774Svbart@nginx.com         ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN,
893774Svbart@nginx.com                             NXT_FILE_OWNER_ACCESS);
894774Svbart@nginx.com 
895774Svbart@nginx.com 
896774Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
897774Svbart@nginx.com             nxt_array_remove_last(certs);
898774Svbart@nginx.com             continue;
899774Svbart@nginx.com         }
900774Svbart@nginx.com 
901774Svbart@nginx.com         item->fd = file.fd;
902774Svbart@nginx.com 
903774Svbart@nginx.com         if (nxt_slow_path(nxt_str_dup(mp, &item->name, &name) == NULL)) {
904774Svbart@nginx.com             goto fail;
905774Svbart@nginx.com         }
906774Svbart@nginx.com     }
907774Svbart@nginx.com 
908774Svbart@nginx.com     if (buf != NULL) {
909774Svbart@nginx.com         nxt_free(buf);
910774Svbart@nginx.com     }
911774Svbart@nginx.com 
912774Svbart@nginx.com     (void) closedir(dir);
913774Svbart@nginx.com 
914774Svbart@nginx.com     return certs;
915774Svbart@nginx.com 
916774Svbart@nginx.com fail:
917774Svbart@nginx.com 
918774Svbart@nginx.com     if (buf != NULL) {
919774Svbart@nginx.com         nxt_free(buf);
920774Svbart@nginx.com     }
921774Svbart@nginx.com 
922774Svbart@nginx.com     if (dir != NULL) {
923774Svbart@nginx.com         (void) closedir(dir);
924774Svbart@nginx.com     }
925774Svbart@nginx.com 
926774Svbart@nginx.com     nxt_cert_store_release(certs);
927774Svbart@nginx.com 
928774Svbart@nginx.com     return NULL;
929774Svbart@nginx.com }
930774Svbart@nginx.com 
931774Svbart@nginx.com 
932774Svbart@nginx.com void
nxt_cert_store_release(nxt_array_t * certs)933774Svbart@nginx.com nxt_cert_store_release(nxt_array_t *certs)
934774Svbart@nginx.com {
935774Svbart@nginx.com     uint32_t         i;
936774Svbart@nginx.com     nxt_cert_item_t  *items;
937774Svbart@nginx.com 
938774Svbart@nginx.com     for (items = certs->elts, i = 0;
939774Svbart@nginx.com          i < certs->nelts;
940774Svbart@nginx.com          i++)
941774Svbart@nginx.com     {
942774Svbart@nginx.com         nxt_fd_close(items[i].fd);
943774Svbart@nginx.com     }
944774Svbart@nginx.com 
9451488St.nateldemoura@f5.com     nxt_array_destroy(certs);
946774Svbart@nginx.com }
947774Svbart@nginx.com 
948774Svbart@nginx.com 
949774Svbart@nginx.com #if 0
950774Svbart@nginx.com 
951774Svbart@nginx.com void
952774Svbart@nginx.com nxt_cert_store_discovery_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
953774Svbart@nginx.com {
954774Svbart@nginx.com     DIR            *dir;
955774Svbart@nginx.com     size_t         size;
956774Svbart@nginx.com     nxt_buf_t      *b;
957774Svbart@nginx.com     nxt_int_t      ret;
958774Svbart@nginx.com     nxt_port_t     *port;
959774Svbart@nginx.com     nxt_runtime_t  *rt;
960774Svbart@nginx.com     struct dirent  *de;
961774Svbart@nginx.com 
962774Svbart@nginx.com     port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
963774Svbart@nginx.com                                  msg->port_msg.reply_port);
964774Svbart@nginx.com 
965774Svbart@nginx.com     if (nxt_slow_path(port == NULL)) {
966774Svbart@nginx.com         return;
967774Svbart@nginx.com     }
968774Svbart@nginx.com 
969774Svbart@nginx.com     b = NULL;
970774Svbart@nginx.com     dir = NULL;
971774Svbart@nginx.com 
972774Svbart@nginx.com     rt = task->thread->runtime;
973774Svbart@nginx.com 
974774Svbart@nginx.com     if (nxt_slow_path(rt->certs.start == NULL)) {
975774Svbart@nginx.com         nxt_alert(task, "no certificates storage directory");
976774Svbart@nginx.com         goto fail;
977774Svbart@nginx.com     }
978774Svbart@nginx.com 
979774Svbart@nginx.com     dir = opendir((char *) rt->certs.start);
980774Svbart@nginx.com     if (nxt_slow_path(dir == NULL)) {
981774Svbart@nginx.com         nxt_alert(task, "opendir(\"%s\") failed %E",
982774Svbart@nginx.com                   rt->certs.start, nxt_errno);
983774Svbart@nginx.com         goto fail;
984774Svbart@nginx.com     }
985774Svbart@nginx.com 
986774Svbart@nginx.com     size = 0;
987774Svbart@nginx.com 
988774Svbart@nginx.com     for ( ;; ) {
989774Svbart@nginx.com         de = readdir(dir);
990774Svbart@nginx.com         if (de == NULL) {
991774Svbart@nginx.com             break;
992774Svbart@nginx.com         }
993774Svbart@nginx.com 
994774Svbart@nginx.com         if (de->d_type != DT_REG) {
995774Svbart@nginx.com             continue;
996774Svbart@nginx.com         }
997774Svbart@nginx.com 
998774Svbart@nginx.com         size += nxt_strlen(de->d_name) + 1;
999774Svbart@nginx.com     }
1000774Svbart@nginx.com 
1001774Svbart@nginx.com     b = nxt_port_mmap_get_buf(task, port, size);
1002774Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
1003774Svbart@nginx.com         goto fail;
1004774Svbart@nginx.com     }
1005774Svbart@nginx.com 
1006774Svbart@nginx.com     rewinddir(dir);
1007774Svbart@nginx.com 
1008774Svbart@nginx.com     for ( ;; ) {
1009774Svbart@nginx.com         de = readdir(dir);
1010774Svbart@nginx.com         if (de == NULL) {
1011774Svbart@nginx.com             break;
1012774Svbart@nginx.com         }
1013774Svbart@nginx.com 
1014774Svbart@nginx.com         if (de->d_type != DT_REG) {
1015774Svbart@nginx.com             continue;
1016774Svbart@nginx.com         }
1017774Svbart@nginx.com 
1018774Svbart@nginx.com         size = nxt_strlen(de->d_name) + 1;
1019774Svbart@nginx.com 
1020774Svbart@nginx.com         if (nxt_slow_path(size > (size_t) nxt_buf_mem_free_size(&b->mem))) {
1021774Svbart@nginx.com             b->mem.free = b->mem.start;
1022774Svbart@nginx.com             break;
1023774Svbart@nginx.com         }
1024774Svbart@nginx.com 
1025774Svbart@nginx.com         b->mem.free = nxt_cpymem(b->mem.free, de->d_name, size);
1026774Svbart@nginx.com     }
1027774Svbart@nginx.com 
1028774Svbart@nginx.com     (void) closedir(dir);
1029774Svbart@nginx.com     dir = NULL;
1030774Svbart@nginx.com 
1031774Svbart@nginx.com     if (nxt_slow_path(nxt_buf_mem_free_size(&b->mem) != 0)) {
1032774Svbart@nginx.com         nxt_alert(task, "certificates storage directory "
1033774Svbart@nginx.com                   "has changed while reading it");
1034774Svbart@nginx.com         goto fail;
1035774Svbart@nginx.com     }
1036774Svbart@nginx.com 
1037774Svbart@nginx.com     ret = nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST, -1,
1038774Svbart@nginx.com                                 msg->port_msg.stream, 0, b);
1039774Svbart@nginx.com 
1040774Svbart@nginx.com     if (nxt_fast_path(ret == NXT_OK)) {
1041774Svbart@nginx.com         return;
1042774Svbart@nginx.com     }
1043774Svbart@nginx.com 
1044774Svbart@nginx.com fail:
1045774Svbart@nginx.com 
1046774Svbart@nginx.com     if (dir != NULL) {
1047774Svbart@nginx.com         (void) closedir(dir);
1048774Svbart@nginx.com     }
1049774Svbart@nginx.com 
1050774Svbart@nginx.com     if (b != NULL) {
1051774Svbart@nginx.com         b->completion_handler(task, b, b->parent);
1052774Svbart@nginx.com     }
1053774Svbart@nginx.com 
1054774Svbart@nginx.com     (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1,
1055774Svbart@nginx.com                                  msg->port_msg.stream, 0, NULL);
1056774Svbart@nginx.com }
1057774Svbart@nginx.com 
1058774Svbart@nginx.com #endif
1059774Svbart@nginx.com 
1060774Svbart@nginx.com 
1061774Svbart@nginx.com 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)1062774Svbart@nginx.com nxt_cert_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp,
1063774Svbart@nginx.com     nxt_port_rpc_handler_t handler, void *ctx)
1064774Svbart@nginx.com {
1065774Svbart@nginx.com     uint32_t       stream;
1066774Svbart@nginx.com     nxt_int_t      ret;
1067774Svbart@nginx.com     nxt_buf_t      *b;
1068774Svbart@nginx.com     nxt_port_t     *main_port, *recv_port;
1069774Svbart@nginx.com     nxt_runtime_t  *rt;
1070774Svbart@nginx.com 
1071774Svbart@nginx.com     b = nxt_buf_mem_alloc(mp, name->length + 1, 0);
1072774Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
1073774Svbart@nginx.com         goto fail;
1074774Svbart@nginx.com     }
1075774Svbart@nginx.com 
10761869Sa.suvorov@f5.com     nxt_mp_retain(mp);
10771869Sa.suvorov@f5.com     b->completion_handler = nxt_cert_buf_completion;
10781869Sa.suvorov@f5.com 
1079774Svbart@nginx.com     nxt_buf_cpystr(b, name);
1080774Svbart@nginx.com     *b->mem.free++ = '\0';
1081774Svbart@nginx.com 
1082774Svbart@nginx.com     rt = task->thread->runtime;
1083774Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1084774Svbart@nginx.com     recv_port = rt->port_by_type[rt->type];
1085774Svbart@nginx.com 
1086774Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, recv_port, handler, handler,
1087774Svbart@nginx.com                                            -1, ctx);
1088774Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
1089774Svbart@nginx.com         goto fail;
1090774Svbart@nginx.com     }
1091774Svbart@nginx.com 
1092774Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_GET, -1,
1093774Svbart@nginx.com                                 stream, recv_port->id, b);
1094774Svbart@nginx.com 
1095774Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1096774Svbart@nginx.com         nxt_port_rpc_cancel(task, recv_port, stream);
1097774Svbart@nginx.com         goto fail;
1098774Svbart@nginx.com     }
1099774Svbart@nginx.com 
1100774Svbart@nginx.com     return;
1101774Svbart@nginx.com 
1102774Svbart@nginx.com fail:
1103774Svbart@nginx.com 
1104774Svbart@nginx.com     handler(task, NULL, ctx);
1105774Svbart@nginx.com }
1106774Svbart@nginx.com 
1107774Svbart@nginx.com 
1108