Asterisk - The Open Source Telephony Project GIT-master-f36a736
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
189X509 *crypto_load_cert_from_file(const char *filename)
190{
191 FILE *fp;
192 X509 *cert = NULL;
193
194 if (ast_strlen_zero(filename)) {
195 ast_log(LOG_ERROR, "filename was null or empty\n");
196 return NULL;
197 }
198
199 fp = fopen(filename, "r");
200 if (!fp) {
201 ast_log(LOG_ERROR, "Failed to open %s: %s\n", filename, strerror(errno));
202 return NULL;
203 }
204
205 cert = PEM_read_X509(fp, &cert, NULL, NULL);
206 fclose(fp);
207 if (!cert) {
208 crypto_log_openssl(LOG_ERROR, "Failed to create cert from %s\n", filename);
209 }
210 return cert;
211}
212
213X509 *crypto_load_cert_from_memory(const char *buffer, size_t size)
214{
215 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
216 X509 *cert = NULL;
217
218 if (ast_strlen_zero(buffer) || size <= 0) {
219 ast_log(LOG_ERROR, "buffer was null or empty\n");
220 return NULL;
221 }
222
223 bio = BIO_new_mem_buf(buffer, size);
224 if (!bio) {
225 crypto_log_openssl(LOG_ERROR, "Unable to create memory BIO\n");
226 return NULL;
227 }
228
229 cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
230 if (!cert) {
231 crypto_log_openssl(LOG_ERROR, "Failed to create cert from BIO\n");
232 }
233 return cert;
234}
235
236static EVP_PKEY *load_private_key_from_memory(const char *buffer, size_t size)
237{
238 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
239 EVP_PKEY *key = NULL;
240
241 if (ast_strlen_zero(buffer) || size <= 0) {
242 ast_log(LOG_ERROR, "buffer was null or empty\n");
243 return NULL;
244 }
245
246 bio = BIO_new_mem_buf(buffer, size);
247 if (!bio) {
248 crypto_log_openssl(LOG_ERROR, "Unable to create memory BIO\n");
249 return NULL;
250 }
251
252 key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
253
254 return key;
255}
256
257EVP_PKEY *crypto_load_private_key_from_memory(const char *buffer, size_t size)
258{
259 EVP_PKEY *key = load_private_key_from_memory(buffer, size);
260 if (!key) {
261 crypto_log_openssl(LOG_ERROR, "Unable to load private key from memory\n");
262 }
263 return key;
264}
265
266int crypto_has_private_key_from_memory(const char *buffer, size_t size)
267{
268 RAII_VAR(EVP_PKEY *, key, load_private_key_from_memory(buffer, size), EVP_PKEY_free);
269
270 return key ? 1 : 0;
271}
272
273static int dump_mem_bio(BIO *bio, unsigned char **buffer)
274{
275 char *temp_ptr;
276 int raw_key_len;
277
278 raw_key_len = BIO_get_mem_data(bio, &temp_ptr);
279 if (raw_key_len <= 0) {
280 crypto_log_openssl(LOG_ERROR, "Unable to extract raw public key\n");
281 return -1;
282 }
283 *buffer = ast_malloc(raw_key_len);
284 if (!*buffer) {
285 ast_log(LOG_ERROR, "Unable to allocate memory for raw public key\n");
286 return -1;
287 }
288 memcpy(*buffer, temp_ptr, raw_key_len);
289
290 return raw_key_len;
291}
292
293int crypto_extract_raw_pubkey(EVP_PKEY *key, unsigned char **buffer)
294{
295 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
296
297 bio = BIO_new(BIO_s_mem());
298
299 if (!bio || (PEM_write_bio_PUBKEY(bio, key) <= 0)) {
300 crypto_log_openssl(LOG_ERROR, "Unable to write pubkey to BIO\n");
301 return -1;
302 }
303
304 return dump_mem_bio(bio, buffer);
305}
306
308 unsigned char **buffer)
309{
310 RAII_VAR(EVP_PKEY *, public_key, X509_get_pubkey(cert), EVP_PKEY_free);
311
312 if (!public_key) {
313 crypto_log_openssl(LOG_ERROR, "Unable to retrieve pubkey from cert\n");
314 return -1;
315 }
316
317 return crypto_extract_raw_pubkey(public_key, buffer);
318}
319
320int crypto_extract_raw_privkey(EVP_PKEY *key, unsigned char **buffer)
321{
322 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
323
324 bio = BIO_new(BIO_s_mem());
325
326 if (!bio || (PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL) <= 0)) {
327 crypto_log_openssl(LOG_ERROR, "Unable to write privkey to BIO\n");
328 return -1;
329 }
330
331 return dump_mem_bio(bio, buffer);
332}
333
334/*
335 * Notes on the crypto_cert_store object:
336 *
337 * We've discoverd a few issues with the X509_STORE object in OpenSSL
338 * that requires us to a bit more work to get the desired behavior.
339 *
340 * Basically, although X509_STORE_load_locations() and X509_STORE_load_path()
341 * work file for trusted certs, they refuse to load either CRLs or
342 * untrusted certs from directories, which is needed to support the
343 * crl_path and untrusted_cert_path options. So we have to brute force
344 * it a bit. We now use PEM_read_X509() and PEM_read_X509_CRL() to load
345 * the objects from files and then use X509_STORE_add_cert() and
346 * X509_STORE_add_crl() to add them to the store. This is a bit more
347 * work but it gets the job done. To load from directories, we
348 * simply use ast_file_read_dirs() with a callback that calls
349 * those functions. This also fixes an issue where certificates
350 * loaded using ca_path don't show up when displaying the
351 * verification or profile objects from the CLI.
352 *
353 * NOTE: X509_STORE_load_file() could have been used instead of
354 * PEM_read_X509()/PEM_read_X509_CRL() and
355 * X509_STORE_add_cert()/X509_STORE_add_crl() but X509_STORE_load_file()
356 * didn't appear in OpenSSL until version 1.1.1. :(
357 *
358 * Another issue we have is that, while X509_verify_cert() can use
359 * an X509_STORE of CA certificates directly, it can't use X509_STOREs
360 * of untrusted certs or CRLs. Instead, it needs a stack of X509
361 * objects for untrusted certs and a stack of X509_CRL objects for CRLs.
362 * So we need to extract the untrusted certs and CRLs from their
363 * stores and push them onto the stacks when the configuration is
364 * loaded. We still use the stores as intermediaries because they
365 * make it easy to load the certs and CRLs from files and directories
366 * and they handle freeing the objects when the store is freed.
367 */
368
369static void crypto_cert_store_destructor(void *obj)
370{
371 struct crypto_cert_store *store = obj;
372
373 if (store->certs) {
374 X509_STORE_free(store->certs);
375 }
376 if (store->untrusted) {
377 X509_STORE_free(store->untrusted);
378 }
379 if (store->untrusted_stack) {
380 sk_X509_free(store->untrusted_stack);
381 }
382 if (store->crls) {
383 X509_STORE_free(store->crls);
384 }
385 if (store->crl_stack) {
386 sk_X509_CRL_free(store->crl_stack);
387 }
388}
389
391{
392 struct crypto_cert_store *store = ao2_alloc(sizeof(*store), crypto_cert_store_destructor);
393 if (!store) {
394 ast_log(LOG_ERROR, "Failed to create crypto_cert_store\n");
395 return NULL;
396 }
397
398 store->certs = X509_STORE_new();
399 if (!store->certs) {
400 crypto_log_openssl(LOG_ERROR, "Failed to create X509_STORE\n");
401 ao2_ref(store, -1);
402 return NULL;
403 }
404
405 store->untrusted = X509_STORE_new();
406 if (!store->untrusted) {
407 crypto_log_openssl(LOG_ERROR, "Failed to create untrusted X509_STORE\n");
408 ao2_ref(store, -1);
409 return NULL;
410 }
411 store->untrusted_stack = sk_X509_new_null();
412 if (!store->untrusted_stack) {
413 crypto_log_openssl(LOG_ERROR, "Failed to create untrusted stack\n");
414 ao2_ref(store, -1);
415 return NULL;
416 }
417
418 store->crls = X509_STORE_new();
419 if (!store->crls) {
420 crypto_log_openssl(LOG_ERROR, "Failed to create CRL X509_STORE\n");
421 ao2_ref(store, -1);
422 return NULL;
423 }
424 store->crl_stack = sk_X509_CRL_new_null();
425 if (!store->crl_stack) {
426 crypto_log_openssl(LOG_ERROR, "Failed to create CRL stack\n");
427 ao2_ref(store, -1);
428 return NULL;
429 }
430
431 return store;
432}
433
434static int crypto_load_store_from_cert_file(X509_STORE *store, const char *file)
435{
436 X509 *cert;
437 int rc = 0;
438
439 if (ast_strlen_zero(file)) {
440 ast_log(LOG_ERROR, "file was null or empty\n");
441 return -1;
442 }
443
445 if (!cert) {
446 return -1;
447 }
448 rc = X509_STORE_add_cert(store, cert);
449 X509_free(cert);
450 if (!rc) {
451 crypto_log_openssl(LOG_ERROR, "Failed to load store from file '%s'\n", file);
452 return -1;
453 }
454
455 return 0;
456}
457
458static int crypto_load_store_from_crl_file(X509_STORE *store, const char *file)
459{
460 X509_CRL *crl;
461 int rc = 0;
462
463 if (ast_strlen_zero(file)) {
464 ast_log(LOG_ERROR, "file was null or empty\n");
465 return -1;
466 }
467
469 if (!crl) {
470 return -1;
471 }
472 rc = X509_STORE_add_crl(store, crl);
473 X509_CRL_free(crl);
474 if (!rc) {
475 crypto_log_openssl(LOG_ERROR, "Failed to load store from file '%s'\n", file);
476 return -1;
477 }
478
479 return 0;
480}
481
483 X509_STORE *store;
485};
486
487static int pem_file_cb(const char *dir_name, const char *filename, void *obj)
488{
489 struct pem_file_cb_data* data = obj;
490 char *filename_merged = NULL;
491 struct stat statbuf;
492 int rc = 0;
493
494 if (ast_asprintf(&filename_merged, "%s/%s", dir_name, filename) < 0) {
495 return -1;
496 }
497
498 if (lstat(filename_merged, &statbuf)) {
499 printf("Error reading path stats - %s: %s\n",
500 filename_merged, strerror(errno));
501 ast_free(filename_merged);
502 return -1;
503 }
504
505 /* We only want the symlinks from the directory */
506 if (!S_ISLNK(statbuf.st_mode)) {
507 ast_free(filename_merged);
508 return 0;
509 }
510
511 if (data->is_crl) {
512 rc = crypto_load_store_from_crl_file(data->store, filename_merged);
513 } else {
514 rc = crypto_load_store_from_cert_file(data->store, filename_merged);
515 }
516
517 ast_free(filename_merged);
518 return rc;
519}
520
521static int _crypto_load_cert_store(X509_STORE *store, const char *file, const char *path)
522{
523 int rc = 0;
524
525 if (!ast_strlen_zero(file)) {
527 if (rc != 0) {
528 return -1;
529 }
530 }
531
532 if (!ast_strlen_zero(path)) {
533 struct pem_file_cb_data data = { .store = store, .is_crl = 0 };
534 if (ast_file_read_dirs(path, pem_file_cb, &data, 0)) {
535 return -1;
536 }
537 }
538
539 return 0;
540}
541
542static int _crypto_load_crl_store(X509_STORE *store, const char *file, const char *path)
543{
544 int rc = 0;
545
546 if (!ast_strlen_zero(file)) {
548 if (rc != 0) {
549 return -1;
550 }
551 }
552
553 if (!ast_strlen_zero(path)) {
554 struct pem_file_cb_data data = { .store = store, .is_crl = 1 };
555 if (ast_file_read_dirs(path, pem_file_cb, &data, 0)) {
556 return -1;
557 }
558 }
559
560 return 0;
561}
562
564 const char *path)
565{
566 if (ast_strlen_zero(file) && ast_strlen_zero(path)) {
567 ast_log(LOG_ERROR, "Both file and path can't be NULL\n");
568 return -1;
569 }
570
571 if (!store || !store->certs) {
572 ast_log(LOG_ERROR, "store or store->certs is NULL\n");
573 return -1;
574 }
575
576 return _crypto_load_cert_store(store->certs, file, path);
577}
578
580 const char *path)
581{
582 int rc = 0;
583 STACK_OF(X509_OBJECT) *objs = NULL;
584 int count = 0;
585 int i = 0;
586
587 if (ast_strlen_zero(file) && ast_strlen_zero(path)) {
588 ast_log(LOG_ERROR, "Both file and path can't be NULL\n");
589 return -1;
590 }
591
592 if (!store || !store->untrusted || !store->untrusted_stack) {
593 ast_log(LOG_ERROR, "store wasn't initialized properly\n");
594 return -1;
595 }
596
597 rc = _crypto_load_cert_store(store->untrusted, file, path);
598 if (rc != 0) {
599 return rc;
600 }
601
602 /*
603 * We need to extract the certs from the store and push them onto the
604 * untrusted stack. This is because the verification context needs
605 * a stack of untrusted certs and not the store.
606 * The store holds the references to the certs so we can't
607 * free it.
608 */
609 objs = X509_STORE_get0_objects(store->untrusted);
610 count = sk_X509_OBJECT_num(objs);
611 for (i = 0; i < count ; i++) {
612 X509_OBJECT *o = sk_X509_OBJECT_value(objs, i);
613 if (X509_OBJECT_get_type(o) == X509_LU_X509) {
614 X509 *c = X509_OBJECT_get0_X509(o);
615 sk_X509_push(store->untrusted_stack, c);
616 }
617 }
618
619 return 0;
620}
621
623 const char *path)
624{
625 int rc = 0;
626 STACK_OF(X509_OBJECT) *objs = NULL;
627 int count = 0;
628 int i = 0;
629
630 if (ast_strlen_zero(file) && ast_strlen_zero(path)) {
631 ast_log(LOG_ERROR, "Both file and path can't be NULL\n");
632 return -1;
633 }
634
635 if (!store || !store->untrusted || !store->untrusted_stack) {
636 ast_log(LOG_ERROR, "store wasn't initialized properly\n");
637 return -1;
638 }
639
640 rc = _crypto_load_crl_store(store->crls, file, path);
641 if (rc != 0) {
642 return rc;
643 }
644
645 /*
646 * We need to extract the CRLs from the store and push them onto the
647 * crl stack. This is because the verification context needs
648 * a stack of CRLs and not the store.
649 * The store holds the references to the CRLs so we can't
650 * free it.
651 */
652 objs = X509_STORE_get0_objects(store->crls);
653 count = sk_X509_OBJECT_num(objs);
654 for (i = 0; i < count ; i++) {
655 X509_OBJECT *o = sk_X509_OBJECT_value(objs, i);
656 if (X509_OBJECT_get_type(o) == X509_LU_CRL) {
657 X509_CRL *c = X509_OBJECT_get0_X509_CRL(o);
658 sk_X509_CRL_push(store->crl_stack, c);
659 }
660 }
661
662 return 0;
663}
664
666{
667#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
668 STACK_OF(X509_OBJECT) *objs = NULL;
669 int count = 0;
670 int untrusted_count = 0;
671 int crl_count = 0;
672 int i = 0;
673 char subj[1024];
674
675 /*
676 * The CA certificates are stored in the certs store.
677 */
678 objs = X509_STORE_get0_objects(store->certs);
679 count = sk_X509_OBJECT_num(objs);
680
681 for (i = 0; i < count ; i++) {
682 X509_OBJECT *o = sk_X509_OBJECT_value(objs, i);
683 if (X509_OBJECT_get_type(o) == X509_LU_X509) {
684 X509 *c = X509_OBJECT_get0_X509(o);
685 X509_NAME_oneline(X509_get_subject_name(c), subj, 1024);
686 ast_cli(fd, "Cert: %s\n", subj);
687 } else {
688 ast_log(LOG_ERROR, "CRLs are not allowed in the CA cert store\n");
689 }
690 }
691
692 /*
693 * Although the untrusted certs are stored in the untrusted store,
694 * we already have the stack of certificates so we can just
695 * list them directly.
696 */
697 untrusted_count = sk_X509_num(store->untrusted_stack);
698 for (i = 0; i < untrusted_count ; i++) {
699 X509 *c = sk_X509_value(store->untrusted_stack, i);
700 X509_NAME_oneline(X509_get_subject_name(c), subj, 1024);
701 ast_cli(fd, "Untrusted: %s\n", subj);
702 }
703
704 /*
705 * Same for the CRLs.
706 */
707 crl_count = sk_X509_CRL_num(store->crl_stack);
708 for (i = 0; i < crl_count ; i++) {
709 X509_CRL *crl = sk_X509_CRL_value(store->crl_stack, i);
710 X509_NAME_oneline(X509_CRL_get_issuer(crl), subj, 1024);
711 ast_cli(fd, "CRL: %s\n", subj);
712 }
713
714 return count + untrusted_count + crl_count;
715#else
716 ast_cli(fd, "This command is not supported until OpenSSL 1.1.0\n");
717 return 0;
718#endif
719}
720
721int crypto_is_cert_time_valid(X509*cert, time_t reftime)
722{
723 ASN1_STRING *notbefore;
724 ASN1_STRING *notafter;
725
726 if (!reftime) {
727 reftime = time(NULL);
728 }
729 notbefore = X509_get_notBefore(cert);
730 notafter = X509_get_notAfter(cert);
731 if (!notbefore || !notafter) {
732 ast_log(LOG_ERROR, "Either notbefore or notafter were not present in the cert\n");
733 return 0;
734 }
735
736 return (X509_cmp_time(notbefore, &reftime) < 0 &&
737 X509_cmp_time(notafter, &reftime) > 0);
738}
739
740int crypto_is_cert_trusted(struct crypto_cert_store *store, X509 *cert, const char **err_msg)
741{
742 X509_STORE_CTX *verify_ctx = NULL;
743 int rc = 0;
744
745 if (!(verify_ctx = X509_STORE_CTX_new())) {
746 crypto_log_openssl(LOG_ERROR, "Unable to create verify_ctx\n");
747 return 0;
748 }
749
750 if (X509_STORE_CTX_init(verify_ctx, store->certs, cert, store->untrusted_stack) != 1) {
751 X509_STORE_CTX_cleanup(verify_ctx);
752 X509_STORE_CTX_free(verify_ctx);
753 crypto_log_openssl(LOG_ERROR, "Unable to initialize verify_ctx\n");
754 return 0;
755 }
756 X509_STORE_CTX_set0_crls(verify_ctx, store->crl_stack);
757
758 rc = X509_verify_cert(verify_ctx);
759 if (rc != 1 && err_msg != NULL) {
760 int err = X509_STORE_CTX_get_error(verify_ctx);
761 *err_msg = X509_verify_cert_error_string(err);
762 }
763 X509_STORE_CTX_cleanup(verify_ctx);
764 X509_STORE_CTX_free(verify_ctx);
765
766 return rc;
767}
768
769#define SECS_PER_DAY 86400
770time_t crypto_asn_time_as_time_t(ASN1_TIME *at)
771{
772 int pday;
773 int psec;
774 time_t rt = time(NULL);
775
776 if (!ASN1_TIME_diff(&pday, &psec, NULL, at)) {
777 crypto_log_openssl(LOG_ERROR, "Unable to calculate time diff\n");
778 return 0;
779 }
780
781 rt += ((pday * SECS_PER_DAY) + psec);
782
783 return rt;
784}
785#undef SECS_PER_DAY
786
787char *crypto_get_cert_subject(X509 *cert, const char *short_name)
788{
789 size_t len = 0;
790 RAII_VAR(char *, buffer, NULL, ast_std_free);
791 char *search_buff = NULL;
792 char *search = NULL;
793 size_t search_len = 0;
794 char *rtn = NULL;
795 char *line = NULL;
796 /*
797 * If short_name was supplied, we want a multiline subject
798 * with each component on a separate line. This makes it easier
799 * to iterate over the components to find the one we want.
800 * Otherwise, we just want the whole subject on one line.
801 */
802 unsigned long flags =
803 short_name ? XN_FLAG_FN_SN | XN_FLAG_SEP_MULTILINE : XN_FLAG_ONELINE;
804 FILE *fp = open_memstream(&buffer, &len);
805 BIO *bio = fp ? BIO_new_fp(fp, BIO_CLOSE) : NULL;
806 X509_NAME *subject = X509_get_subject_name(cert);
807 int rc = 0;
808
809 if (!fp || !bio || !subject) {
810 return NULL;
811 }
812
813 rc = X509_NAME_print_ex(bio, subject, 0, flags);
814 BIO_free(bio);
815 if (rc < 0) {
816 return NULL;
817 }
818
819 if (!short_name) {
820 rtn = ast_malloc(len + 1);
821 if (rtn) {
822 strcpy(rtn, buffer); /* Safe */
823 }
824 return rtn;
825 }
826
827 search_len = strlen(short_name) + 1;
828 rc = ast_asprintf(&search, "%s=", short_name);
829 if (rc != search_len) {
830 return NULL;
831 }
832
833 search_buff = buffer;
834 while((line = ast_read_line_from_buffer(&search_buff))) {
835 if (ast_begins_with(line, search)) {
836 rtn = ast_malloc(strlen(line) - search_len + 1);
837 if (rtn) {
838 strcpy(rtn, line + search_len); /* Safe */
839 }
840 break;
841 }
842 }
843
844 ast_std_free(search);
845 return rtn;
846}
847
848int crypto_load(void)
849{
851}
852
854{
855 return 0;
856}
857
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
static int tmp()
Definition: bt_open.c:389
Standard Command Line Interface.
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
X509 * crypto_load_cert_from_memory(const char *buffer, size_t size)
Load an X509 Cert from a NULL terminated buffer.
Definition: crypto_utils.c:213
static EVP_PKEY * load_private_key_from_memory(const char *buffer, size_t size)
Definition: crypto_utils.c:236
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:622
static void crypto_cert_store_destructor(void *obj)
Definition: crypto_utils.c:369
int crypto_is_cert_trusted(struct crypto_cert_store *store, X509 *cert, const char **err_msg)
Check if the cert is trusted.
Definition: crypto_utils.c:740
static int pem_file_cb(const char *dir_name, const char *filename, void *obj)
Definition: crypto_utils.c:487
static int _crypto_load_cert_store(X509_STORE *store, const char *file, const char *path)
Definition: crypto_utils.c:521
static int crypto_load_store_from_crl_file(X509_STORE *store, const char *file)
Definition: crypto_utils.c:458
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:307
int crypto_extract_raw_pubkey(EVP_PKEY *key, unsigned char **buffer)
Extract raw public key from EVP_PKEY.
Definition: crypto_utils.c:293
time_t crypto_asn_time_as_time_t(ASN1_TIME *at)
Return a time_t for an ASN1_TIME.
Definition: crypto_utils.c:770
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:579
int crypto_extract_raw_privkey(EVP_PKEY *key, unsigned char **buffer)
Extract raw private key from EVP_PKEY.
Definition: crypto_utils.c:320
int crypto_load(void)
Initialize the crypto utils.
Definition: crypto_utils.c:848
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:787
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:721
static int crypto_load_store_from_cert_file(X509_STORE *store, const char *file)
Definition: crypto_utils.c:434
struct crypto_cert_store * crypto_create_cert_store(void)
Create an empty X509 store.
Definition: crypto_utils.c:390
static int dump_mem_bio(BIO *bio, unsigned char **buffer)
Definition: crypto_utils.c:273
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:266
int crypto_unload(void)
Clean up the crypto utils.
Definition: crypto_utils.c:853
static int _crypto_load_crl_store(X509_STORE *store, const char *file, const char *path)
Definition: crypto_utils.c:542
X509 * crypto_load_cert_from_file(const char *filename)
Load an X509 Cert from a file.
Definition: crypto_utils.c:189
#define SECS_PER_DAY
Definition: crypto_utils.c:769
EVP_PKEY * crypto_load_private_key_from_memory(const char *buffer, size_t size)
Load a private key from memory.
Definition: crypto_utils.c:257
int crypto_show_cli_store(struct crypto_cert_store *store, int fd)
Dump a cert store to the asterisk CLI.
Definition: crypto_utils.c:665
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:563
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:1274
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 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:371
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:179
X509_STORE * untrusted
Definition: crypto_utils.h:184
X509_STORE * certs
Definition: crypto_utils.h:180
X509_STORE * crls
Definition: crypto_utils.h:181
X509_STORE * store
Definition: crypto_utils.c:483
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:941
Vector container support.