Asterisk - The Open Source Telephony Project GIT-master-97770a9
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 return -1;
502 }
503
504 /* We only want the symlinks from the directory */
505 if (!S_ISLNK(statbuf.st_mode)) {
506 return 0;
507 }
508
509 if (data->is_crl) {
510 rc = crypto_load_store_from_crl_file(data->store, filename_merged);
511 } else {
512 rc = crypto_load_store_from_cert_file(data->store, filename_merged);
513 }
514
515 return rc;
516}
517
518static int _crypto_load_cert_store(X509_STORE *store, const char *file, const char *path)
519{
520 int rc = 0;
521
522 if (!ast_strlen_zero(file)) {
524 if (rc != 0) {
525 return -1;
526 }
527 }
528
529 if (!ast_strlen_zero(path)) {
530 struct pem_file_cb_data data = { .store = store, .is_crl = 0 };
531 if (ast_file_read_dirs(path, pem_file_cb, &data, 0)) {
532 return -1;
533 }
534 }
535
536 return 0;
537}
538
539static int _crypto_load_crl_store(X509_STORE *store, const char *file, const char *path)
540{
541 int rc = 0;
542
543 if (!ast_strlen_zero(file)) {
545 if (rc != 0) {
546 return -1;
547 }
548 }
549
550 if (!ast_strlen_zero(path)) {
551 struct pem_file_cb_data data = { .store = store, .is_crl = 1 };
552 if (ast_file_read_dirs(path, pem_file_cb, &data, 0)) {
553 return -1;
554 }
555 }
556
557 return 0;
558}
559
561 const char *path)
562{
563 if (ast_strlen_zero(file) && ast_strlen_zero(path)) {
564 ast_log(LOG_ERROR, "Both file and path can't be NULL\n");
565 return -1;
566 }
567
568 if (!store || !store->certs) {
569 ast_log(LOG_ERROR, "store or store->certs is NULL\n");
570 return -1;
571 }
572
573 return _crypto_load_cert_store(store->certs, file, path);
574}
575
577 const char *path)
578{
579 int rc = 0;
580 STACK_OF(X509_OBJECT) *objs = NULL;
581 int count = 0;
582 int i = 0;
583
584 if (ast_strlen_zero(file) && ast_strlen_zero(path)) {
585 ast_log(LOG_ERROR, "Both file and path can't be NULL\n");
586 return -1;
587 }
588
589 if (!store || !store->untrusted || !store->untrusted_stack) {
590 ast_log(LOG_ERROR, "store wasn't initialized properly\n");
591 return -1;
592 }
593
594 rc = _crypto_load_cert_store(store->untrusted, file, path);
595 if (rc != 0) {
596 return rc;
597 }
598
599 /*
600 * We need to extract the certs from the store and push them onto the
601 * untrusted stack. This is because the verification context needs
602 * a stack of untrusted certs and not the store.
603 * The store holds the references to the certs so we can't
604 * free it.
605 */
606 objs = X509_STORE_get0_objects(store->untrusted);
607 count = sk_X509_OBJECT_num(objs);
608 for (i = 0; i < count ; i++) {
609 X509_OBJECT *o = sk_X509_OBJECT_value(objs, i);
610 if (X509_OBJECT_get_type(o) == X509_LU_X509) {
611 X509 *c = X509_OBJECT_get0_X509(o);
612 sk_X509_push(store->untrusted_stack, c);
613 }
614 }
615
616 return 0;
617}
618
620 const char *path)
621{
622 int rc = 0;
623 STACK_OF(X509_OBJECT) *objs = NULL;
624 int count = 0;
625 int i = 0;
626
627 if (ast_strlen_zero(file) && ast_strlen_zero(path)) {
628 ast_log(LOG_ERROR, "Both file and path can't be NULL\n");
629 return -1;
630 }
631
632 if (!store || !store->untrusted || !store->untrusted_stack) {
633 ast_log(LOG_ERROR, "store wasn't initialized properly\n");
634 return -1;
635 }
636
637 rc = _crypto_load_crl_store(store->crls, file, path);
638 if (rc != 0) {
639 return rc;
640 }
641
642 /*
643 * We need to extract the CRLs from the store and push them onto the
644 * crl stack. This is because the verification context needs
645 * a stack of CRLs and not the store.
646 * The store holds the references to the CRLs so we can't
647 * free it.
648 */
649 objs = X509_STORE_get0_objects(store->crls);
650 count = sk_X509_OBJECT_num(objs);
651 for (i = 0; i < count ; i++) {
652 X509_OBJECT *o = sk_X509_OBJECT_value(objs, i);
653 if (X509_OBJECT_get_type(o) == X509_LU_CRL) {
654 X509_CRL *c = X509_OBJECT_get0_X509_CRL(o);
655 sk_X509_CRL_push(store->crl_stack, c);
656 }
657 }
658
659 return 0;
660}
661
663{
664#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
665 STACK_OF(X509_OBJECT) *objs = NULL;
666 int count = 0;
667 int untrusted_count = 0;
668 int crl_count = 0;
669 int i = 0;
670 char subj[1024];
671
672 /*
673 * The CA certificates are stored in the certs store.
674 */
675 objs = X509_STORE_get0_objects(store->certs);
676 count = sk_X509_OBJECT_num(objs);
677
678 for (i = 0; i < count ; i++) {
679 X509_OBJECT *o = sk_X509_OBJECT_value(objs, i);
680 if (X509_OBJECT_get_type(o) == X509_LU_X509) {
681 X509 *c = X509_OBJECT_get0_X509(o);
682 X509_NAME_oneline(X509_get_subject_name(c), subj, 1024);
683 ast_cli(fd, "Cert: %s\n", subj);
684 } else {
685 ast_log(LOG_ERROR, "CRLs are not allowed in the CA cert store\n");
686 }
687 }
688
689 /*
690 * Although the untrusted certs are stored in the untrusted store,
691 * we already have the stack of certificates so we can just
692 * list them directly.
693 */
694 untrusted_count = sk_X509_num(store->untrusted_stack);
695 for (i = 0; i < untrusted_count ; i++) {
696 X509 *c = sk_X509_value(store->untrusted_stack, i);
697 X509_NAME_oneline(X509_get_subject_name(c), subj, 1024);
698 ast_cli(fd, "Untrusted: %s\n", subj);
699 }
700
701 /*
702 * Same for the CRLs.
703 */
704 crl_count = sk_X509_CRL_num(store->crl_stack);
705 for (i = 0; i < crl_count ; i++) {
706 X509_CRL *crl = sk_X509_CRL_value(store->crl_stack, i);
707 X509_NAME_oneline(X509_CRL_get_issuer(crl), subj, 1024);
708 ast_cli(fd, "CRL: %s\n", subj);
709 }
710
711 return count + untrusted_count + crl_count;
712#else
713 ast_cli(fd, "This command is not supported until OpenSSL 1.1.0\n");
714 return 0;
715#endif
716}
717
718int crypto_is_cert_time_valid(X509*cert, time_t reftime)
719{
720 ASN1_STRING *notbefore;
721 ASN1_STRING *notafter;
722
723 if (!reftime) {
724 reftime = time(NULL);
725 }
726 notbefore = X509_get_notBefore(cert);
727 notafter = X509_get_notAfter(cert);
728 if (!notbefore || !notafter) {
729 ast_log(LOG_ERROR, "Either notbefore or notafter were not present in the cert\n");
730 return 0;
731 }
732
733 return (X509_cmp_time(notbefore, &reftime) < 0 &&
734 X509_cmp_time(notafter, &reftime) > 0);
735}
736
737int crypto_is_cert_trusted(struct crypto_cert_store *store, X509 *cert, const char **err_msg)
738{
739 X509_STORE_CTX *verify_ctx = NULL;
740 int rc = 0;
741
742 if (!(verify_ctx = X509_STORE_CTX_new())) {
743 crypto_log_openssl(LOG_ERROR, "Unable to create verify_ctx\n");
744 return 0;
745 }
746
747 if (X509_STORE_CTX_init(verify_ctx, store->certs, cert, store->untrusted_stack) != 1) {
748 X509_STORE_CTX_cleanup(verify_ctx);
749 X509_STORE_CTX_free(verify_ctx);
750 crypto_log_openssl(LOG_ERROR, "Unable to initialize verify_ctx\n");
751 return 0;
752 }
753 X509_STORE_CTX_set0_crls(verify_ctx, store->crl_stack);
754
755 rc = X509_verify_cert(verify_ctx);
756 if (rc != 1 && err_msg != NULL) {
757 int err = X509_STORE_CTX_get_error(verify_ctx);
758 *err_msg = X509_verify_cert_error_string(err);
759 }
760 X509_STORE_CTX_cleanup(verify_ctx);
761 X509_STORE_CTX_free(verify_ctx);
762
763 return rc;
764}
765
766#define SECS_PER_DAY 86400
767time_t crypto_asn_time_as_time_t(ASN1_TIME *at)
768{
769 int pday;
770 int psec;
771 time_t rt = time(NULL);
772
773 if (!ASN1_TIME_diff(&pday, &psec, NULL, at)) {
774 crypto_log_openssl(LOG_ERROR, "Unable to calculate time diff\n");
775 return 0;
776 }
777
778 rt += ((pday * SECS_PER_DAY) + psec);
779
780 return rt;
781}
782#undef SECS_PER_DAY
783
784char *crypto_get_cert_subject(X509 *cert, const char *short_name)
785{
786 size_t len = 0;
787 RAII_VAR(char *, buffer, NULL, ast_std_free);
788 char *search_buff = NULL;
789 char *search = NULL;
790 size_t search_len = 0;
791 char *rtn = NULL;
792 char *line = NULL;
793 /*
794 * If short_name was supplied, we want a multiline subject
795 * with each component on a separate line. This makes it easier
796 * to iterate over the components to find the one we want.
797 * Otherwise, we just want the whole subject on one line.
798 */
799 unsigned long flags =
800 short_name ? XN_FLAG_FN_SN | XN_FLAG_SEP_MULTILINE : XN_FLAG_ONELINE;
801 FILE *fp = open_memstream(&buffer, &len);
802 BIO *bio = fp ? BIO_new_fp(fp, BIO_CLOSE) : NULL;
803 X509_NAME *subject = X509_get_subject_name(cert);
804 int rc = 0;
805
806 if (!fp || !bio || !subject) {
807 return NULL;
808 }
809
810 rc = X509_NAME_print_ex(bio, subject, 0, flags);
811 BIO_free(bio);
812 if (rc < 0) {
813 return NULL;
814 }
815
816 if (!short_name) {
817 rtn = ast_malloc(len + 1);
818 if (rtn) {
819 strcpy(rtn, buffer); /* Safe */
820 }
821 return rtn;
822 }
823
824 search_len = strlen(short_name) + 1;
825 rc = ast_asprintf(&search, "%s=", short_name);
826 if (rc != search_len) {
827 return NULL;
828 }
829
830 search_buff = buffer;
831 while((line = ast_read_line_from_buffer(&search_buff))) {
832 if (ast_begins_with(line, search)) {
833 rtn = ast_malloc(strlen(line) - search_len + 1);
834 if (rtn) {
835 strcpy(rtn, line + search_len); /* Safe */
836 }
837 break;
838 }
839 }
840
841 ast_std_free(search);
842 return rtn;
843}
844
845int crypto_load(void)
846{
848}
849
851{
852 return 0;
853}
854
Asterisk main include file. File version handling, generic pbx functions.
void ast_std_free(void *ptr)
Definition: astmm.c:1734
#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:619
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:737
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:518
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:767
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:576
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:845
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:784
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:718
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:850
static int _crypto_load_crl_store(X509_STORE *store, const char *file, const char *path)
Definition: crypto_utils.c:539
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:766
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:662
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:560
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.