Asterisk - The Open Source Telephony Project GIT-master-4522eb1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
crypto_utils.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2023, Sangoma Technologies Corporation
5 *
6 * George Joseph <gjoseph@sangoma.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19#include <sys/stat.h>
20
21#include <openssl/err.h>
22#include <openssl/ssl.h>
23#include <openssl/evp.h>
24#include <openssl/md5.h>
25#include <openssl/sha.h>
26#include <openssl/bio.h>
27#include <openssl/obj_mac.h>
28#include <openssl/x509.h>
29#include <openssl/x509v3.h>
30#include <openssl/x509_vfy.h>
31
32#include "crypto_utils.h"
33
34#include "asterisk.h"
35#include "asterisk/cli.h"
36#include "asterisk/file.h"
37#include "asterisk/logger.h"
38#include "asterisk/module.h"
40#include "asterisk/utils.h"
41#include "asterisk/vector.h"
42#include "asterisk/cli.h"
43
44void __attribute__((format(printf, 5, 6)))
45crypto_log_openssl(int level, char *file, int line, const char *function,
46 const char *fmt, ...)
47{
48 FILE *fp;
49 char *buffer;
50 size_t length;
51 va_list ap;
52 char *tmp_fmt;
53
54 fp = open_memstream(&buffer, &length);
55 if (!fp) {
56 return;
57 }
58
59 va_start(ap, fmt);
60 if (!ast_strlen_zero(fmt)) {
61 size_t fmt_len = strlen(fmt);
62 if (fmt[fmt_len - 1] == '\n') {
63 tmp_fmt = ast_strdupa(fmt);
64 tmp_fmt[fmt_len - 1] = '\0';
65 fmt = tmp_fmt;
66 }
67 }
68 vfprintf(fp, fmt, ap);
69 fputs(": ", fp);
70 ERR_print_errors_fp(fp);
71 fclose(fp);
72
73 if (length) {
74 ast_log(level, file, line, function, "%s\n", buffer);
75 }
76
77 ast_std_free(buffer);
78}
79
80int crypto_register_x509_extension(const char *oid, const char *short_name,
81 const char *long_name)
82{
83 int nid = 0;
84
85 if (ast_strlen_zero(oid) || ast_strlen_zero(short_name) ||
86 ast_strlen_zero(long_name)) {
87 ast_log(LOG_ERROR, "One or more of oid, short_name or long_name are NULL or empty\n");
88 return -1;
89 }
90
91 nid = OBJ_sn2nid(short_name);
92 if (nid != NID_undef) {
93 ast_log(LOG_NOTICE, "NID %d, object %s already registered\n", nid, short_name);
94 return nid;
95 }
96
97 nid = OBJ_create(oid, short_name, long_name);
98 if (nid == NID_undef) {
99 crypto_log_openssl(LOG_ERROR, "Couldn't register %s X509 extension\n", short_name);
100 return -1;
101 }
102 ast_log(LOG_NOTICE, "Registered object %s as NID %d\n", short_name, nid);
103
104 return nid;
105}
106
107ASN1_OCTET_STRING *crypto_get_cert_extension_data(X509 *cert,
108 int nid, const char *short_name)
109{
110 int ex_idx;
111 X509_EXTENSION *ex;
112
113 if (nid <= 0) {
114 nid = OBJ_sn2nid(short_name);
115 if (nid == NID_undef) {
116 ast_log(LOG_ERROR, "Extension object for %s not found\n", short_name);
117 return NULL;
118 }
119 } else {
120 const char *tmp = OBJ_nid2sn(nid);
121 if (!tmp) {
122 ast_log(LOG_ERROR, "Extension object for NID %d not found\n", nid);
123 return NULL;
124 }
125 }
126
127 ex_idx = X509_get_ext_by_NID(cert, nid, -1);
128 if (ex_idx < 0) {
129 ast_log(LOG_ERROR, "Extension index not found in certificate\n");
130 return NULL;
131 }
132 ex = X509_get_ext(cert, ex_idx);
133 if (!ex) {
134 ast_log(LOG_ERROR, "Extension not found in certificate\n");
135 return NULL;
136 }
137
138 return X509_EXTENSION_get_data(ex);
139}
140
141EVP_PKEY *crypto_load_privkey_from_file(const char *filename)
142{
143 EVP_PKEY *key = NULL;
144 FILE *fp;
145
146 if (ast_strlen_zero(filename)) {
147 ast_log(LOG_ERROR, "filename was null or empty\n");
148 return NULL;
149 }
150
151 fp = fopen(filename, "r");
152 if (!fp) {
153 ast_log(LOG_ERROR, "Failed to open %s: %s\n", filename, strerror(errno));
154 return NULL;
155 }
156
157 key = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
158 fclose(fp);
159 if (!key) {
160 crypto_log_openssl(LOG_ERROR, "Failed to load private key from %s\n", filename);
161 }
162 return key;
163}
164
165X509_CRL *crypto_load_crl_from_file(const char *filename)
166{
167 FILE *fp;
168 X509_CRL *crl = NULL;
169
170 if (ast_strlen_zero(filename)) {
171 ast_log(LOG_ERROR, "filename was null or empty\n");
172 return NULL;
173 }
174
175 fp = fopen(filename, "r");
176 if (!fp) {
177 ast_log(LOG_ERROR, "Failed to open %s: %s\n", filename, strerror(errno));
178 return NULL;
179 }
180
181 crl = PEM_read_X509_CRL(fp, &crl, NULL, NULL);
182 fclose(fp);
183 if (!crl) {
184 crypto_log_openssl(LOG_ERROR, "Failed to create CRL from %s\n", filename);
185 }
186 return crl;
187}
188
189#define debug_cert_chain(level, cert_chain) \
190({ \
191 int i; \
192 char subj[1024]; \
193 if (cert_chain && sk_X509_num(cert_chain) > 0) { \
194 for (i = 0; i < sk_X509_num(cert_chain); i++) { \
195 X509 *cert = sk_X509_value(cert_chain, i); \
196 subj[0] = '\0'; \
197 X509_NAME_oneline(X509_get_subject_name(cert), subj, 1024); \
198 ast_debug(level, "Chain cert %d: '%s'\n", i, subj); \
199 } \
200 } \
201})
202
203X509 *crypto_load_cert_chain_from_file(const char *filename, STACK_OF(X509) **cert_chain)
204{
205 FILE *fp;
206 X509 *end_cert = NULL;
207
208 if (ast_strlen_zero(filename)) {
209 ast_log(LOG_ERROR, "filename was null or empty\n");
210 return NULL;
211 }
212
213 fp = fopen(filename, "r");
214 if (!fp) {
215 ast_log(LOG_ERROR, "Failed to open %s: %s\n", filename, strerror(errno));
216 return NULL;
217 }
218
219 end_cert = PEM_read_X509(fp, &end_cert, NULL, NULL);
220 if (!end_cert) {
221 crypto_log_openssl(LOG_ERROR, "Failed to create end_cert from %s\n", filename);
222 fclose(fp);
223 return NULL;
224 }
225
226 /*
227 * If the caller provided a stack, we will read the chain certs
228 * (if any) into it.
229 */
230 if (cert_chain) {
231 X509 *chain_cert = NULL;
232
233 *cert_chain = sk_X509_new_null();
234 while ((chain_cert = PEM_read_X509(fp, &chain_cert, NULL, NULL)) != NULL) {
235 if (sk_X509_push(*cert_chain, chain_cert) <= 0) {
236 crypto_log_openssl(LOG_ERROR, "Failed to add chain cert from %s to list\n",
237 filename);
238 fclose(fp);
239 X509_free(end_cert);
240 sk_X509_pop_free(*cert_chain, X509_free);
241 return NULL;
242 }
243 /* chain_cert needs to be reset to NULL after every call to PEM_read_X509 */
244 chain_cert = NULL;
245 }
246 }
247
248 if (DEBUG_ATLEAST(4)) {
249 char subj[1024];
250
251 X509_NAME_oneline(X509_get_subject_name(end_cert), subj, 1024);
252 ast_debug(4, "Opened end cert '%s' from '%s'\n", subj, filename);
253
254 if (cert_chain && *cert_chain) {
255 debug_cert_chain(4, *cert_chain);
256 } else {
257 ast_debug(4, "No chain certs found in '%s'\n", filename);
258 }
259 }
260
261 fclose(fp);
262
263 return end_cert;
264}
265
266X509 *crypto_load_cert_chain_from_memory(const char *buffer, size_t size,
267 STACK_OF(X509) **cert_chain)
268{
269 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
270 X509 *end_cert = NULL;
271
272 if (ast_strlen_zero(buffer) || size <= 0) {
273 ast_log(LOG_ERROR, "buffer was null or empty\n");
274 return NULL;
275 }
276
277 bio = BIO_new_mem_buf(buffer, size);
278 if (!bio) {
279 crypto_log_openssl(LOG_ERROR, "Unable to create memory BIO\n");
280 return NULL;
281 }
282
283 end_cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
284 if (!end_cert) {
285 crypto_log_openssl(LOG_ERROR, "Failed to create end_cert from BIO\n");
286 return NULL;
287 }
288
289 /*
290 * If the caller provided a stack, we will read the chain certs
291 * (if any) into it.
292 */
293 if (cert_chain) {
294 X509 *chain_cert = NULL;
295
296 *cert_chain = sk_X509_new_null();
297 while ((chain_cert = PEM_read_bio_X509(bio, &chain_cert, NULL, NULL)) != NULL) {
298 if (sk_X509_push(*cert_chain, chain_cert) <= 0) {
299 crypto_log_openssl(LOG_ERROR, "Failed to add chain cert from BIO to list\n");
300 X509_free(end_cert);
301 sk_X509_pop_free(*cert_chain, X509_free);
302 return NULL;
303 }
304 /* chain_cert needs to be reset to NULL after every call to PEM_read_X509 */
305 chain_cert = NULL;
306 }
307 }
308
309 if (DEBUG_ATLEAST(4)) {
310 char subj[1024];
311
312 X509_NAME_oneline(X509_get_subject_name(end_cert), subj, 1024);
313 ast_debug(4, "Opened end cert '%s' from BIO\n", subj);
314
315 if (cert_chain && *cert_chain) {
316 debug_cert_chain(4, *cert_chain);
317 } else {
318 ast_debug(4, "No chain certs found in BIO\n");
319 }
320 }
321
322 return end_cert;
323}
324
325static EVP_PKEY *load_private_key_from_memory(const char *buffer, size_t size)
326{
327 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
328 EVP_PKEY *key = NULL;
329
330 if (ast_strlen_zero(buffer) || size <= 0) {
331 ast_log(LOG_ERROR, "buffer was null or empty\n");
332 return NULL;
333 }
334
335 bio = BIO_new_mem_buf(buffer, size);
336 if (!bio) {
337 crypto_log_openssl(LOG_ERROR, "Unable to create memory BIO\n");
338 return NULL;
339 }
340
341 key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
342
343 return key;
344}
345
346EVP_PKEY *crypto_load_private_key_from_memory(const char *buffer, size_t size)
347{
348 EVP_PKEY *key = load_private_key_from_memory(buffer, size);
349 if (!key) {
350 crypto_log_openssl(LOG_ERROR, "Unable to load private key from memory\n");
351 }
352 return key;
353}
354
355int crypto_has_private_key_from_memory(const char *buffer, size_t size)
356{
357 RAII_VAR(EVP_PKEY *, key, load_private_key_from_memory(buffer, size), EVP_PKEY_free);
358
359 return key ? 1 : 0;
360}
361
362static int dump_mem_bio(BIO *bio, unsigned char **buffer)
363{
364 char *temp_ptr;
365 int raw_key_len;
366
367 raw_key_len = BIO_get_mem_data(bio, &temp_ptr);
368 if (raw_key_len <= 0) {
369 crypto_log_openssl(LOG_ERROR, "Unable to extract raw public key\n");
370 return -1;
371 }
372 *buffer = ast_malloc(raw_key_len);
373 if (!*buffer) {
374 ast_log(LOG_ERROR, "Unable to allocate memory for raw public key\n");
375 return -1;
376 }
377 memcpy(*buffer, temp_ptr, raw_key_len);
378
379 return raw_key_len;
380}
381
382int crypto_extract_raw_pubkey(EVP_PKEY *key, unsigned char **buffer)
383{
384 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
385
386 bio = BIO_new(BIO_s_mem());
387
388 if (!bio || (PEM_write_bio_PUBKEY(bio, key) <= 0)) {
389 crypto_log_openssl(LOG_ERROR, "Unable to write pubkey to BIO\n");
390 return -1;
391 }
392
393 return dump_mem_bio(bio, buffer);
394}
395
397 unsigned char **buffer)
398{
399 RAII_VAR(EVP_PKEY *, public_key, X509_get_pubkey(cert), EVP_PKEY_free);
400
401 if (!public_key) {
402 crypto_log_openssl(LOG_ERROR, "Unable to retrieve pubkey from cert\n");
403 return -1;
404 }
405
406 return crypto_extract_raw_pubkey(public_key, buffer);
407}
408
409int crypto_extract_raw_privkey(EVP_PKEY *key, unsigned char **buffer)
410{
411 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
412
413 bio = BIO_new(BIO_s_mem());
414
415 if (!bio || (PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL) <= 0)) {
416 crypto_log_openssl(LOG_ERROR, "Unable to write privkey to BIO\n");
417 return -1;
418 }
419
420 return dump_mem_bio(bio, buffer);
421}
422
423/*
424 * Notes on the crypto_cert_store object:
425 *
426 * We've discoverd a few issues with the X509_STORE object in OpenSSL
427 * that requires us to a bit more work to get the desired behavior.
428 *
429 * Basically, although X509_STORE_load_locations() and X509_STORE_load_path()
430 * work file for trusted certs, they refuse to load either CRLs or
431 * untrusted certs from directories, which is needed to support the
432 * crl_path and untrusted_cert_path options. So we have to brute force
433 * it a bit. We now use PEM_read_X509() and PEM_read_X509_CRL() to load
434 * the objects from files and then use X509_STORE_add_cert() and
435 * X509_STORE_add_crl() to add them to the store. This is a bit more
436 * work but it gets the job done. To load from directories, we
437 * simply use ast_file_read_dirs() with a callback that calls
438 * those functions. This also fixes an issue where certificates
439 * loaded using ca_path don't show up when displaying the
440 * verification or profile objects from the CLI.
441 *
442 * NOTE: X509_STORE_load_file() could have been used instead of
443 * PEM_read_X509()/PEM_read_X509_CRL() and
444 * X509_STORE_add_cert()/X509_STORE_add_crl() but X509_STORE_load_file()
445 * didn't appear in OpenSSL until version 1.1.1. :(
446 *
447 * Another issue we have is that, while X509_verify_cert() can use
448 * an X509_STORE of CA certificates directly, it can't use X509_STOREs
449 * of untrusted certs or CRLs. Instead, it needs a stack of X509
450 * objects for untrusted certs and a stack of X509_CRL objects for CRLs.
451 * So we need to extract the untrusted certs and CRLs from their
452 * stores and push them onto the stacks when the configuration is
453 * loaded. We still use the stores as intermediaries because they
454 * make it easy to load the certs and CRLs from files and directories
455 * and they handle freeing the objects when the store is freed.
456 */
457
458static void crypto_cert_store_destructor(void *obj)
459{
460 struct crypto_cert_store *store = obj;
461
462 if (store->certs) {
463 X509_STORE_free(store->certs);
464 }
465 if (store->untrusted) {
466 X509_STORE_free(store->untrusted);
467 }
468 if (store->untrusted_stack) {
469 sk_X509_free(store->untrusted_stack);
470 }
471 if (store->crls) {
472 X509_STORE_free(store->crls);
473 }
474 if (store->crl_stack) {
475 sk_X509_CRL_free(store->crl_stack);
476 }
477}
478
480{
481 struct crypto_cert_store *store = ao2_alloc(sizeof(*store), crypto_cert_store_destructor);
482 if (!store) {
483 ast_log(LOG_ERROR, "Failed to create crypto_cert_store\n");
484 return NULL;
485 }
486
487 store->certs = X509_STORE_new();
488 if (!store->certs) {
489 crypto_log_openssl(LOG_ERROR, "Failed to create X509_STORE\n");
490 ao2_ref(store, -1);
491 return NULL;
492 }
493
494 store->untrusted = X509_STORE_new();
495 if (!store->untrusted) {
496 crypto_log_openssl(LOG_ERROR, "Failed to create untrusted X509_STORE\n");
497 ao2_ref(store, -1);
498 return NULL;
499 }
500 store->untrusted_stack = sk_X509_new_null();
501 if (!store->untrusted_stack) {
502 crypto_log_openssl(LOG_ERROR, "Failed to create untrusted stack\n");
503 ao2_ref(store, -1);
504 return NULL;
505 }
506
507 store->crls = X509_STORE_new();
508 if (!store->crls) {
509 crypto_log_openssl(LOG_ERROR, "Failed to create CRL X509_STORE\n");
510 ao2_ref(store, -1);
511 return NULL;
512 }
513 store->crl_stack = sk_X509_CRL_new_null();
514 if (!store->crl_stack) {
515 crypto_log_openssl(LOG_ERROR, "Failed to create CRL stack\n");
516 ao2_ref(store, -1);
517 return NULL;
518 }
519
520 return store;
521}
522
523static int crypto_load_store_from_cert_file(X509_STORE *store, const char *file)
524{
525 X509 *cert;
526 int rc = 0;
527
528 if (ast_strlen_zero(file)) {
529 ast_log(LOG_ERROR, "file was null or empty\n");
530 return -1;
531 }
532
534 if (!cert) {
535 return -1;
536 }
537 rc = X509_STORE_add_cert(store, cert);
538 X509_free(cert);
539 if (!rc) {
540 crypto_log_openssl(LOG_ERROR, "Failed to load store from file '%s'\n", file);
541 return -1;
542 }
543
544 return 0;
545}
546
547static int crypto_load_store_from_crl_file(X509_STORE *store, const char *file)
548{
549 X509_CRL *crl;
550 int rc = 0;
551
552 if (ast_strlen_zero(file)) {
553 ast_log(LOG_ERROR, "file was null or empty\n");
554 return -1;
555 }
556
558 if (!crl) {
559 return -1;
560 }
561 rc = X509_STORE_add_crl(store, crl);
562 X509_CRL_free(crl);
563 if (!rc) {
564 crypto_log_openssl(LOG_ERROR, "Failed to load store from file '%s'\n", file);
565 return -1;
566 }
567
568 return 0;
569}
570
572 X509_STORE *store;
574};
575
576static int pem_file_cb(const char *dir_name, const char *filename, void *obj)
577{
578 struct pem_file_cb_data* data = obj;
579 char *filename_merged = NULL;
580 struct stat statbuf;
581 int rc = 0;
582
583 if (ast_asprintf(&filename_merged, "%s/%s", dir_name, filename) < 0) {
584 return -1;
585 }
586
587 if (lstat(filename_merged, &statbuf)) {
588 printf("Error reading path stats - %s: %s\n",
589 filename_merged, strerror(errno));
590 ast_free(filename_merged);
591 return -1;
592 }
593
594 /* We only want the symlinks from the directory */
595 if (!S_ISLNK(statbuf.st_mode)) {
596 ast_free(filename_merged);
597 return 0;
598 }
599
600 if (data->is_crl) {
601 rc = crypto_load_store_from_crl_file(data->store, filename_merged);
602 } else {
603 rc = crypto_load_store_from_cert_file(data->store, filename_merged);
604 }
605
606 ast_free(filename_merged);
607 return rc;
608}
609
610static int _crypto_load_cert_store(X509_STORE *store, const char *file, const char *path)
611{
612 int rc = 0;
613
614 if (!ast_strlen_zero(file)) {
616 if (rc != 0) {
617 return -1;
618 }
619 }
620
621 if (!ast_strlen_zero(path)) {
622 struct pem_file_cb_data data = { .store = store, .is_crl = 0 };
623 if (ast_file_read_dirs(path, pem_file_cb, &data, 0)) {
624 return -1;
625 }
626 }
627
628 return 0;
629}
630
631static int _crypto_load_crl_store(X509_STORE *store, const char *file, const char *path)
632{
633 int rc = 0;
634
635 if (!ast_strlen_zero(file)) {
637 if (rc != 0) {
638 return -1;
639 }
640 }
641
642 if (!ast_strlen_zero(path)) {
643 struct pem_file_cb_data data = { .store = store, .is_crl = 1 };
644 if (ast_file_read_dirs(path, pem_file_cb, &data, 0)) {
645 return -1;
646 }
647 }
648
649 return 0;
650}
651
653 const char *path)
654{
655 if (ast_strlen_zero(file) && ast_strlen_zero(path)) {
656 ast_log(LOG_ERROR, "Both file and path can't be NULL\n");
657 return -1;
658 }
659
660 if (!store || !store->certs) {
661 ast_log(LOG_ERROR, "store or store->certs is NULL\n");
662 return -1;
663 }
664
665 return _crypto_load_cert_store(store->certs, file, path);
666}
667
669 const char *path)
670{
671 int rc = 0;
672 STACK_OF(X509_OBJECT) *objs = NULL;
673 int count = 0;
674 int i = 0;
675
676 if (ast_strlen_zero(file) && ast_strlen_zero(path)) {
677 ast_log(LOG_ERROR, "Both file and path can't be NULL\n");
678 return -1;
679 }
680
681 if (!store || !store->untrusted || !store->untrusted_stack) {
682 ast_log(LOG_ERROR, "store wasn't initialized properly\n");
683 return -1;
684 }
685
686 rc = _crypto_load_cert_store(store->untrusted, file, path);
687 if (rc != 0) {
688 return rc;
689 }
690
691 /*
692 * We need to extract the certs from the store and push them onto the
693 * untrusted stack. This is because the verification context needs
694 * a stack of untrusted certs and not the store.
695 * The store holds the references to the certs so we can't
696 * free it.
697 */
698 objs = X509_STORE_get0_objects(store->untrusted);
699 count = sk_X509_OBJECT_num(objs);
700 for (i = 0; i < count ; i++) {
701 X509_OBJECT *o = sk_X509_OBJECT_value(objs, i);
702 if (X509_OBJECT_get_type(o) == X509_LU_X509) {
703 X509 *c = X509_OBJECT_get0_X509(o);
704 sk_X509_push(store->untrusted_stack, c);
705 }
706 }
707
708 return 0;
709}
710
712 const char *path)
713{
714 int rc = 0;
715 STACK_OF(X509_OBJECT) *objs = NULL;
716 int count = 0;
717 int i = 0;
718
719 if (ast_strlen_zero(file) && ast_strlen_zero(path)) {
720 ast_log(LOG_ERROR, "Both file and path can't be NULL\n");
721 return -1;
722 }
723
724 if (!store || !store->untrusted || !store->untrusted_stack) {
725 ast_log(LOG_ERROR, "store wasn't initialized properly\n");
726 return -1;
727 }
728
729 rc = _crypto_load_crl_store(store->crls, file, path);
730 if (rc != 0) {
731 return rc;
732 }
733
734 /*
735 * We need to extract the CRLs from the store and push them onto the
736 * crl stack. This is because the verification context needs
737 * a stack of CRLs and not the store.
738 * The store holds the references to the CRLs so we can't
739 * free it.
740 */
741 objs = X509_STORE_get0_objects(store->crls);
742 count = sk_X509_OBJECT_num(objs);
743 for (i = 0; i < count ; i++) {
744 X509_OBJECT *o = sk_X509_OBJECT_value(objs, i);
745 if (X509_OBJECT_get_type(o) == X509_LU_CRL) {
746 X509_CRL *c = X509_OBJECT_get0_X509_CRL(o);
747 sk_X509_CRL_push(store->crl_stack, c);
748 }
749 }
750
751 return 0;
752}
753
755{
756#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
757 STACK_OF(X509_OBJECT) *objs = NULL;
758 int count = 0;
759 int untrusted_count = 0;
760 int crl_count = 0;
761 int i = 0;
762 char subj[1024];
763
764 /*
765 * The CA certificates are stored in the certs store.
766 */
767 objs = X509_STORE_get0_objects(store->certs);
768 count = sk_X509_OBJECT_num(objs);
769
770 for (i = 0; i < count ; i++) {
771 X509_OBJECT *o = sk_X509_OBJECT_value(objs, i);
772 if (X509_OBJECT_get_type(o) == X509_LU_X509) {
773 X509 *c = X509_OBJECT_get0_X509(o);
774 X509_NAME_oneline(X509_get_subject_name(c), subj, 1024);
775 ast_cli(fd, "Cert: %s\n", subj);
776 } else {
777 ast_log(LOG_ERROR, "CRLs are not allowed in the CA cert store\n");
778 }
779 }
780
781 /*
782 * Although the untrusted certs are stored in the untrusted store,
783 * we already have the stack of certificates so we can just
784 * list them directly.
785 */
786 untrusted_count = sk_X509_num(store->untrusted_stack);
787 for (i = 0; i < untrusted_count ; i++) {
788 X509 *c = sk_X509_value(store->untrusted_stack, i);
789 X509_NAME_oneline(X509_get_subject_name(c), subj, 1024);
790 ast_cli(fd, "Untrusted: %s\n", subj);
791 }
792
793 /*
794 * Same for the CRLs.
795 */
796 crl_count = sk_X509_CRL_num(store->crl_stack);
797 for (i = 0; i < crl_count ; i++) {
798 X509_CRL *crl = sk_X509_CRL_value(store->crl_stack, i);
799 X509_NAME_oneline(X509_CRL_get_issuer(crl), subj, 1024);
800 ast_cli(fd, "CRL: %s\n", subj);
801 }
802
803 return count + untrusted_count + crl_count;
804#else
805 ast_cli(fd, "This command is not supported until OpenSSL 1.1.0\n");
806 return 0;
807#endif
808}
809
810int crypto_is_cert_time_valid(X509*cert, time_t reftime)
811{
812 ASN1_STRING *notbefore;
813 ASN1_STRING *notafter;
814
815 if (!reftime) {
816 reftime = time(NULL);
817 }
818 notbefore = X509_get_notBefore(cert);
819 notafter = X509_get_notAfter(cert);
820 if (!notbefore || !notafter) {
821 ast_log(LOG_ERROR, "Either notbefore or notafter were not present in the cert\n");
822 return 0;
823 }
824
825 return (X509_cmp_time(notbefore, &reftime) < 0 &&
826 X509_cmp_time(notafter, &reftime) > 0);
827}
828
830 STACK_OF(X509) *cert_chain, const char **err_msg)
831{
832 X509_STORE_CTX *verify_ctx = NULL;
833 RAII_VAR(STACK_OF(X509) *, untrusted_stack, NULL, sk_X509_free);
834 int rc = 0;
835
836 if (!(verify_ctx = X509_STORE_CTX_new())) {
837 crypto_log_openssl(LOG_ERROR, "Unable to create verify_ctx\n");
838 return 0;
839 }
840
841 if (cert_chain && sk_X509_num(cert_chain) > 0) {
842 int untrusted_count = store->untrusted_stack ? sk_X509_num(store->untrusted_stack) : 0;
843 int i = 0;
844
845 untrusted_stack = sk_X509_dup(cert_chain);
846 if (!untrusted_stack) {
847 crypto_log_openssl(LOG_ERROR, "Unable to duplicate untrusted stack\n");
848 X509_STORE_CTX_free(verify_ctx);
849 return 0;
850 }
851 /*
852 * If store->untrusted_stack was NULL for some reason then
853 * untrusted_count will be 0 so the loop will never run.
854 */
855 for (i = 0; i < untrusted_count; i++) {
856 X509 *c = sk_X509_value(store->untrusted_stack, i);
857 if (sk_X509_push(untrusted_stack, c) <= 0) {
858 crypto_log_openssl(LOG_ERROR, "Unable to push untrusted cert onto stack\n");
859 sk_X509_free(untrusted_stack);
860 X509_STORE_CTX_free(verify_ctx);
861 return 0;
862 }
863 }
864 /*
865 * store->untrusted_stack should always be allocated even if empty
866 * but we'll make sure.
867 */
868 } else if (store->untrusted_stack){
869 /* This is a dead simple shallow clone */
870 ast_debug(4, "cert_chain had no certs\n");
871 untrusted_stack = sk_X509_dup(store->untrusted_stack);
872 if (!untrusted_stack) {
873 crypto_log_openssl(LOG_ERROR, "Unable to duplicate untrusted stack\n");
874 X509_STORE_CTX_free(verify_ctx);
875 return 0;
876 }
877 }
878
879 if (X509_STORE_CTX_init(verify_ctx, store->certs, cert, untrusted_stack) != 1) {
880 X509_STORE_CTX_cleanup(verify_ctx);
881 X509_STORE_CTX_free(verify_ctx);
882 crypto_log_openssl(LOG_ERROR, "Unable to initialize verify_ctx\n");
883 return 0;
884 }
885 X509_STORE_CTX_set0_crls(verify_ctx, store->crl_stack);
886
887 rc = X509_verify_cert(verify_ctx);
888 if (rc != 1 && err_msg != NULL) {
889 int err = X509_STORE_CTX_get_error(verify_ctx);
890 *err_msg = X509_verify_cert_error_string(err);
891 }
892
893 X509_STORE_CTX_cleanup(verify_ctx);
894 X509_STORE_CTX_free(verify_ctx);
895
896 return rc;
897}
898
899#define SECS_PER_DAY 86400
900time_t crypto_asn_time_as_time_t(ASN1_TIME *at)
901{
902 int pday;
903 int psec;
904 time_t rt = time(NULL);
905
906 if (!ASN1_TIME_diff(&pday, &psec, NULL, at)) {
907 crypto_log_openssl(LOG_ERROR, "Unable to calculate time diff\n");
908 return 0;
909 }
910
911 rt += ((pday * SECS_PER_DAY) + psec);
912
913 return rt;
914}
915#undef SECS_PER_DAY
916
917char *crypto_get_cert_subject(X509 *cert, const char *short_name)
918{
919 size_t len = 0;
920 RAII_VAR(char *, buffer, NULL, ast_std_free);
921 char *search_buff = NULL;
922 char *search = NULL;
923 size_t search_len = 0;
924 char *rtn = NULL;
925 char *line = NULL;
926 /*
927 * If short_name was supplied, we want a multiline subject
928 * with each component on a separate line. This makes it easier
929 * to iterate over the components to find the one we want.
930 * Otherwise, we just want the whole subject on one line.
931 */
932 unsigned long flags =
933 short_name ? XN_FLAG_FN_SN | XN_FLAG_SEP_MULTILINE : XN_FLAG_ONELINE;
934 FILE *fp = open_memstream(&buffer, &len);
935 BIO *bio = fp ? BIO_new_fp(fp, BIO_CLOSE) : NULL;
936 X509_NAME *subject = X509_get_subject_name(cert);
937 int rc = 0;
938
939 if (!fp || !bio || !subject) {
940 return NULL;
941 }
942
943 rc = X509_NAME_print_ex(bio, subject, 0, flags);
944 BIO_free(bio);
945 if (rc < 0) {
946 return NULL;
947 }
948
949 if (!short_name) {
950 rtn = ast_malloc(len + 1);
951 if (rtn) {
952 strcpy(rtn, buffer); /* Safe */
953 }
954 return rtn;
955 }
956
957 search_len = strlen(short_name) + 1;
958 rc = ast_asprintf(&search, "%s=", short_name);
959 if (rc != search_len) {
960 return NULL;
961 }
962
963 search_buff = buffer;
964 while((line = ast_read_line_from_buffer(&search_buff))) {
965 if (ast_begins_with(line, search)) {
966 rtn = ast_malloc(strlen(line) - search_len + 1);
967 if (rtn) {
968 strcpy(rtn, line + search_len); /* Safe */
969 }
970 break;
971 }
972 }
973
974 ast_std_free(search);
975 return rtn;
976}
977
978int crypto_load(void)
979{
981}
982
984{
985 return 0;
986}
987
Asterisk main include file. File version handling, generic pbx functions.
void ast_std_free(void *ptr)
Definition: astmm.c:1734
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
Standard Command Line Interface.
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static EVP_PKEY * load_private_key_from_memory(const char *buffer, size_t size)
Definition: crypto_utils.c:325
int crypto_load_crl_store(struct crypto_cert_store *store, const char *file, const char *path)
Load an X509 Store with certificate revocation lists.
Definition: crypto_utils.c:711
static void crypto_cert_store_destructor(void *obj)
Definition: crypto_utils.c:458
X509 * crypto_load_cert_chain_from_memory(const char *buffer, size_t size, STACK_OF(X509) **cert_chain)
Load an X509 Cert and any chained certs from a NULL terminated buffer.
Definition: crypto_utils.c:266
#define debug_cert_chain(level, cert_chain)
Definition: crypto_utils.c:189
static int pem_file_cb(const char *dir_name, const char *filename, void *obj)
Definition: crypto_utils.c:576
static int _crypto_load_cert_store(X509_STORE *store, const char *file, const char *path)
Definition: crypto_utils.c:610
static int crypto_load_store_from_crl_file(X509_STORE *store, const char *file)
Definition: crypto_utils.c:547
void crypto_log_openssl(int level, char *file, int line, const char *function, const char *fmt,...)
Print a log message with any OpenSSL errors appended.
Definition: crypto_utils.c:45
int crypto_get_raw_pubkey_from_cert(X509 *cert, unsigned char **buffer)
Retrieve RAW public key from cert.
Definition: crypto_utils.c:396
int crypto_extract_raw_pubkey(EVP_PKEY *key, unsigned char **buffer)
Extract raw public key from EVP_PKEY.
Definition: crypto_utils.c:382
time_t crypto_asn_time_as_time_t(ASN1_TIME *at)
Return a time_t for an ASN1_TIME.
Definition: crypto_utils.c:900
X509 * crypto_load_cert_chain_from_file(const char *filename, STACK_OF(X509) **cert_chain)
Load an X509 Cert and any chained certs from a file.
Definition: crypto_utils.c:203
X509_CRL * crypto_load_crl_from_file(const char *filename)
Load an X509 CRL from a PEM file.
Definition: crypto_utils.c:165
EVP_PKEY * crypto_load_privkey_from_file(const char *filename)
Load a private key from a file.
Definition: crypto_utils.c:141
int crypto_register_x509_extension(const char *oid, const char *short_name, const char *long_name)
Register a certificate extension to openssl.
Definition: crypto_utils.c:80
int crypto_load_untrusted_cert_store(struct crypto_cert_store *store, const char *file, const char *path)
Load an X509 Store with untrusted certificates.
Definition: crypto_utils.c:668
int crypto_extract_raw_privkey(EVP_PKEY *key, unsigned char **buffer)
Extract raw private key from EVP_PKEY.
Definition: crypto_utils.c:409
int crypto_load(void)
Initialize the crypto utils.
Definition: crypto_utils.c:978
char * crypto_get_cert_subject(X509 *cert, const char *short_name)
Returns the Subject (or component of Subject) from a certificate.
Definition: crypto_utils.c:917
int crypto_is_cert_time_valid(X509 *cert, time_t reftime)
Check if the reftime is within the cert's valid dates.
Definition: crypto_utils.c:810
static int crypto_load_store_from_cert_file(X509_STORE *store, const char *file)
Definition: crypto_utils.c:523
struct crypto_cert_store * crypto_create_cert_store(void)
Create an empty X509 store.
Definition: crypto_utils.c:479
static int dump_mem_bio(BIO *bio, unsigned char **buffer)
Definition: crypto_utils.c:362
int crypto_has_private_key_from_memory(const char *buffer, size_t size)
Check if the supplied buffer has a private key.
Definition: crypto_utils.c:355
int crypto_unload(void)
Clean up the crypto utils.
Definition: crypto_utils.c:983
static int _crypto_load_crl_store(X509_STORE *store, const char *file, const char *path)
Definition: crypto_utils.c:631
#define SECS_PER_DAY
Definition: crypto_utils.c:899
int crypto_is_cert_trusted(struct crypto_cert_store *store, X509 *cert, STACK_OF(X509) *cert_chain, const char **err_msg)
Check if the cert is trusted.
Definition: crypto_utils.c:829
EVP_PKEY * crypto_load_private_key_from_memory(const char *buffer, size_t size)
Load a private key from memory.
Definition: crypto_utils.c:346
int crypto_show_cli_store(struct crypto_cert_store *store, int fd)
Dump a cert store to the asterisk CLI.
Definition: crypto_utils.c:754
ASN1_OCTET_STRING * crypto_get_cert_extension_data(X509 *cert, int nid, const char *short_name)
Return the data from a specific extension in a cert.
Definition: crypto_utils.c:107
int crypto_load_cert_store(struct crypto_cert_store *store, const char *file, const char *path)
Load an X509 Store with either certificates or CRLs.
Definition: crypto_utils.c:652
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth)
Recursively iterate through files and directories up to max_depth.
Definition: file.c:1282
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Support for logging to various files, console and syslog Configuration in file logger....
#define DEBUG_ATLEAST(level)
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
int errno
Asterisk module definitions.
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
char * ast_read_line_from_buffer(char **buffer)
Read lines from a string buffer.
Definition: strings.c:385
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition: strings.h:97
ao2 object wrapper for X509_STORE that provides locking and refcounting
Definition: crypto_utils.h:191
X509_STORE * untrusted
Definition: crypto_utils.h:196
X509_STORE * certs
Definition: crypto_utils.h:192
X509_STORE * crls
Definition: crypto_utils.h:193
X509_STORE * store
Definition: crypto_utils.c:572
static struct test_val c
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:947
Vector container support.