19 #include <openssl/err.h>
20 #include <openssl/ssl.h>
21 #include <openssl/evp.h>
22 #include <openssl/md5.h>
23 #include <openssl/sha.h>
24 #include <openssl/bio.h>
25 #include <openssl/obj_mac.h>
26 #include <openssl/x509.h>
27 #include <openssl/x509v3.h>
28 #include <openssl/x509_vfy.h>
30 #include "crypto_utils.h"
40 void __attribute__((format(printf, 5, 6)))
41 crypto_log_openssl(
int level,
char *file,
int line, const
char *function,
50 fp = open_memstream(&buffer, &length);
56 if (!ast_strlen_zero(fmt)) {
57 size_t fmt_len = strlen(fmt);
58 if (fmt[fmt_len - 1] ==
'\n') {
60 tmp_fmt[fmt_len - 1] =
'\0';
64 vfprintf(fp, fmt, ap);
66 ERR_print_errors_fp(fp);
70 ast_log(level, file, line,
function,
"%s\n", buffer);
76 int crypto_register_x509_extension(
const char *oid,
const char *short_name,
77 const char *long_name)
81 if (ast_strlen_zero(oid) || ast_strlen_zero(short_name) ||
82 ast_strlen_zero(long_name)) {
83 ast_log(LOG_ERROR,
"One or more of oid, short_name or long_name are NULL or empty\n");
87 nid = OBJ_sn2nid(short_name);
88 if (nid != NID_undef) {
89 ast_log(LOG_NOTICE,
"NID %d, object %s already registered\n", nid, short_name);
93 nid = OBJ_create(oid, short_name, long_name);
94 if (nid == NID_undef) {
95 crypto_log_openssl(LOG_ERROR,
"Couldn't register %s X509 extension\n", short_name);
98 ast_log(LOG_NOTICE,
"Registered object %s as NID %d\n", short_name, nid);
103 ASN1_OCTET_STRING *crypto_get_cert_extension_data(X509 *cert,
104 int nid,
const char *short_name)
110 nid = OBJ_sn2nid(short_name);
111 if (nid == NID_undef) {
112 ast_log(LOG_ERROR,
"Extension object for %s not found\n", short_name);
116 const char *tmp = OBJ_nid2sn(nid);
118 ast_log(LOG_ERROR,
"Extension object for NID %d not found\n", nid);
123 ex_idx = X509_get_ext_by_NID(cert, nid, -1);
125 ast_log(LOG_ERROR,
"Extension index not found in certificate\n");
128 ex = X509_get_ext(cert, ex_idx);
130 ast_log(LOG_ERROR,
"Extension not found in certificate\n");
134 return X509_EXTENSION_get_data(ex);
137 EVP_PKEY *crypto_load_privkey_from_file(
const char *filename)
139 EVP_PKEY *key = NULL;
142 if (ast_strlen_zero(filename)) {
143 ast_log(LOG_ERROR,
"filename was null or empty\n");
147 fp = fopen(filename,
"r");
149 ast_log(LOG_ERROR,
"Failed to open %s: %s\n", filename, strerror(errno));
153 key = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
156 crypto_log_openssl(LOG_ERROR,
"Failed to load private key from %s\n", filename);
161 X509 *crypto_load_cert_from_file(
const char *filename)
166 if (ast_strlen_zero(filename)) {
167 ast_log(LOG_ERROR,
"filename was null or empty\n");
171 fp = fopen(filename,
"r");
173 ast_log(LOG_ERROR,
"Failed to open %s: %s\n", filename, strerror(errno));
177 cert = PEM_read_X509(fp, &cert, NULL, NULL);
180 crypto_log_openssl(LOG_ERROR,
"Failed to create cert from %s\n", filename);
185 X509 *crypto_load_cert_from_memory(
const char *buffer,
size_t size)
187 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
190 if (ast_strlen_zero(buffer) || size <= 0) {
191 ast_log(LOG_ERROR,
"buffer was null or empty\n");
195 bio = BIO_new_mem_buf(buffer, size);
197 crypto_log_openssl(LOG_ERROR,
"Unable to create memory BIO\n");
201 cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
203 crypto_log_openssl(LOG_ERROR,
"Failed to create cert from BIO\n");
208 static EVP_PKEY *load_private_key_from_memory(
const char *buffer,
size_t size)
210 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
211 EVP_PKEY *key = NULL;
213 if (ast_strlen_zero(buffer) || size <= 0) {
214 ast_log(LOG_ERROR,
"buffer was null or empty\n");
218 bio = BIO_new_mem_buf(buffer, size);
220 crypto_log_openssl(LOG_ERROR,
"Unable to create memory BIO\n");
224 key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
229 EVP_PKEY *crypto_load_private_key_from_memory(
const char *buffer,
size_t size)
231 EVP_PKEY *key = load_private_key_from_memory(buffer, size);
233 crypto_log_openssl(LOG_ERROR,
"Unable to load private key from memory\n");
238 int crypto_has_private_key_from_memory(
const char *buffer,
size_t size)
240 RAII_VAR(EVP_PKEY *, key, load_private_key_from_memory(buffer, size), EVP_PKEY_free);
245 static int dump_mem_bio(BIO *bio,
unsigned char **buffer)
250 raw_key_len = BIO_get_mem_data(bio, &temp_ptr);
251 if (raw_key_len <= 0) {
252 crypto_log_openssl(LOG_ERROR,
"Unable to extract raw public key\n");
257 ast_log(LOG_ERROR,
"Unable to allocate memory for raw public key\n");
260 memcpy(*buffer, temp_ptr, raw_key_len);
265 int crypto_extract_raw_pubkey(EVP_PKEY *key,
unsigned char **buffer)
267 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
269 bio = BIO_new(BIO_s_mem());
271 if (!bio || (PEM_write_bio_PUBKEY(bio, key) <= 0)) {
272 crypto_log_openssl(LOG_ERROR,
"Unable to write pubkey to BIO\n");
276 return dump_mem_bio(bio, buffer);
279 int crypto_get_raw_pubkey_from_cert(X509 *cert,
280 unsigned char **buffer)
282 RAII_VAR(EVP_PKEY *, public_key, X509_get_pubkey(cert), EVP_PKEY_free);
285 crypto_log_openssl(LOG_ERROR,
"Unable to retrieve pubkey from cert\n");
289 return crypto_extract_raw_pubkey(public_key, buffer);
292 int crypto_extract_raw_privkey(EVP_PKEY *key,
unsigned char **buffer)
294 RAII_VAR(BIO *, bio, NULL, BIO_free_all);
296 bio = BIO_new(BIO_s_mem());
298 if (!bio || (PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL) <= 0)) {
299 crypto_log_openssl(LOG_ERROR,
"Unable to write privkey to BIO\n");
303 return dump_mem_bio(bio, buffer);
306 static void crypto_cert_store_destructor(
void *obj)
311 X509_STORE_free(store->store);
317 struct crypto_cert_store *store = ao2_alloc(
sizeof(*store), crypto_cert_store_destructor);
319 ast_log(LOG_ERROR,
"Failed to create crypto_cert_store\n");
322 store->store = X509_STORE_new();
325 crypto_log_openssl(LOG_ERROR,
"Failed to create X509_STORE\n");
336 if (ast_strlen_zero(file) && ast_strlen_zero(path)) {
337 ast_log(LOG_ERROR,
"Both file and path can't be NULL");
341 if (!store || !store->store) {
342 ast_log(LOG_ERROR,
"store is NULL");
351 if (!X509_STORE_load_locations(store->store,
S_OR(file, NULL),
S_OR(path, NULL))) {
352 crypto_log_openssl(LOG_ERROR,
"Failed to load store from file '%s' or path '%s'\n",
353 S_OR(file,
"N/A"),
S_OR(path,
"N/A"));
362 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
363 STACK_OF(X509_OBJECT) *certs = NULL;
368 certs = X509_STORE_get0_objects(store->store);
369 count = sk_X509_OBJECT_num(certs);
370 for (i = 0; i < count ; i++) {
371 X509_OBJECT *o = sk_X509_OBJECT_value(certs, i);
372 X509 *c = X509_OBJECT_get0_X509(o);
373 X509_NAME_oneline(X509_get_subject_name(c), subj, 1024);
374 ast_cli(fd,
"%s\n", subj);
378 ast_cli(fd,
"This command is not supported until OpenSSL 1.1.0\n");
383 int crypto_is_cert_time_valid(X509*cert, time_t reftime)
385 ASN1_STRING *notbefore;
386 ASN1_STRING *notafter;
389 reftime = time(NULL);
391 notbefore = X509_get_notBefore(cert);
392 notafter = X509_get_notAfter(cert);
393 if (!notbefore || !notafter) {
394 ast_log(LOG_ERROR,
"Either notbefore or notafter were not present in the cert\n");
398 return (X509_cmp_time(notbefore, &reftime) < 0 &&
399 X509_cmp_time(notafter, &reftime) > 0);
402 int crypto_is_cert_trusted(
struct crypto_cert_store *store, X509 *cert,
const char **err_msg)
404 X509_STORE_CTX *verify_ctx = NULL;
407 if (!(verify_ctx = X509_STORE_CTX_new())) {
408 crypto_log_openssl(LOG_ERROR,
"Unable to create verify_ctx\n");
412 if (X509_STORE_CTX_init(verify_ctx, store->store, cert, NULL) != 1) {
413 X509_STORE_CTX_cleanup(verify_ctx);
414 X509_STORE_CTX_free(verify_ctx);
415 crypto_log_openssl(LOG_ERROR,
"Unable to initialize verify_ctx\n");
419 rc = X509_verify_cert(verify_ctx);
420 if (rc != 1 && err_msg != NULL) {
421 int err = X509_STORE_CTX_get_error(verify_ctx);
422 *err_msg = X509_verify_cert_error_string(err);
424 X509_STORE_CTX_cleanup(verify_ctx);
425 X509_STORE_CTX_free(verify_ctx);
430 #define SECS_PER_DAY 86400
431 time_t crypto_asn_time_as_time_t(ASN1_TIME *at)
435 time_t rt = time(NULL);
437 if (!ASN1_TIME_diff(&pday, &psec, NULL, at)) {
438 crypto_log_openssl(LOG_ERROR,
"Unable to calculate time diff\n");
442 rt += ((pday * SECS_PER_DAY) + psec);
448 char *crypto_get_cert_subject(X509 *cert,
const char *short_name)
451 RAII_VAR(
char *, buffer, NULL, ast_std_free);
452 char *search_buff = NULL;
454 size_t search_len = 0;
463 unsigned long flags =
464 short_name ? XN_FLAG_FN_SN | XN_FLAG_SEP_MULTILINE : XN_FLAG_ONELINE;
465 FILE *fp = open_memstream(&buffer, &len);
466 BIO *bio = fp ? BIO_new_fp(fp, BIO_CLOSE) : NULL;
467 X509_NAME *subject = X509_get_subject_name(cert);
470 if (!fp || !bio || !subject) {
474 rc = X509_NAME_print_ex(bio, subject, 0, flags);
488 search_len = strlen(short_name) + 1;
490 if (rc != search_len) {
494 search_buff = buffer;
497 rtn =
ast_malloc(strlen(line) - search_len + 1);
499 strcpy(rtn, line + search_len);
505 ast_std_free(search);
514 int crypto_unload(
void)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
ao2 object wrapper for X509_STORE that provides locking and refcounting
#define ast_malloc(len)
A wrapper for malloc()
Support for logging to various files, console and syslog Configuration in file logger.conf.
static void crypto_load(int ifd, int ofd)
refresh RSA keys from file
Vector container support.
Standard Command Line Interface.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
char * ast_read_line_from_buffer(char **buffer)
Read lines from a string buffer.