From b23f089472600ccff34a7d6ce1ff6f328f51e52e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 1 Apr 2024 14:10:32 -0600 Subject: [PATCH] res_stir_shaken: Fix compilation for CentOS7 (openssl 1.0.2) * OpenSSL 1.0.2 doesn't support X509_get0_pubkey so we now use X509_get_pubkey. The difference is that X509_get_pubkey requires the caller to free the EVP_PKEY themselves so we now let RAII_VAR do that. * OpenSSL 1.0.2 doesn't support upreffing an X509_STORE so we now wrap it in an ao2 object. * OpenSSL 1.0.2 doesn't support X509_STORE_get0_objects to get all the certs from an X509_STORE and there's no easy way to polyfill it so the CLI commands that list profiles will show a "not supported" message instead of listing the certs in a store. Resolves: #676 --- res/res_stir_shaken/common_config.h | 2 +- res/res_stir_shaken/crypto_utils.c | 57 ++++++++++------------- res/res_stir_shaken/crypto_utils.h | 23 +++++---- res/res_stir_shaken/verification_config.c | 6 +-- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/res/res_stir_shaken/common_config.h b/res/res_stir_shaken/common_config.h index 69e9b05549..c0e56b9a91 100644 --- a/res/res_stir_shaken/common_config.h +++ b/res/res_stir_shaken/common_config.h @@ -351,7 +351,7 @@ struct verification_cfg_common { enum load_system_certs_enum load_system_certs; struct ast_acl_list *acl; - X509_STORE *tcs; + struct crypto_cert_store *tcs; }; #define generate_vcfg_common_sorcery_handlers(object) \ diff --git a/res/res_stir_shaken/crypto_utils.c b/res/res_stir_shaken/crypto_utils.c index 201564bcce..7c4667fbb1 100644 --- a/res/res_stir_shaken/crypto_utils.c +++ b/res/res_stir_shaken/crypto_utils.c @@ -279,10 +279,8 @@ int crypto_extract_raw_pubkey(EVP_PKEY *key, unsigned char **buffer) int crypto_get_raw_pubkey_from_cert(X509 *cert, unsigned char **buffer) { - RAII_VAR(BIO *, bio, NULL, BIO_free_all); - EVP_PKEY *public_key; + RAII_VAR(EVP_PKEY *, public_key, X509_get_pubkey(cert), EVP_PKEY_free); - public_key = X509_get0_pubkey(cert); if (!public_key) { crypto_log_openssl(LOG_ERROR, "Unable to retrieve pubkey from cert\n"); return -1; @@ -305,45 +303,34 @@ int crypto_extract_raw_privkey(EVP_PKEY *key, unsigned char **buffer) return dump_mem_bio(bio, buffer); } -void crypto_free_cert_store(X509_STORE *store) +static void crypto_cert_store_destructor(void *obj) { - if (!store) { - return; - } - X509_STORE_free(store); -} + struct crypto_cert_store *store = obj; -int crypto_lock_cert_store(X509_STORE *store) -{ - if (!store) { - return -1; + if (store->store) { + X509_STORE_free(store->store); } - /* lock returns 1 on success */ - return X509_STORE_lock(store) == 1 ? 0 : -1; } -int crypto_unlock_cert_store(X509_STORE *store) +struct crypto_cert_store *crypto_create_cert_store(void) { + struct crypto_cert_store *store = ao2_alloc(sizeof(*store), crypto_cert_store_destructor); if (!store) { - return -1; + ast_log(LOG_ERROR, "Failed to create crypto_cert_store\n"); + return NULL; } - /* unlock returns 1 on success */ - return X509_STORE_unlock(store) == 1 ? 0 : -1; -} - -X509_STORE *crypto_create_cert_store(void) -{ - X509_STORE *store = X509_STORE_new(); + store->store = X509_STORE_new(); - if (!store) { + if (!store->store) { crypto_log_openssl(LOG_ERROR, "Failed to create X509_STORE\n"); + ao2_ref(store, -1); return NULL; } return store; } -int crypto_load_cert_store(X509_STORE *store, const char *file, +int crypto_load_cert_store(struct crypto_cert_store *store, const char *file, const char *path) { if (ast_strlen_zero(file) && ast_strlen_zero(path)) { @@ -351,7 +338,7 @@ int crypto_load_cert_store(X509_STORE *store, const char *file, return -1; } - if (!store) { + if (!store || !store->store) { ast_log(LOG_ERROR, "store is NULL"); return -1; } @@ -361,7 +348,7 @@ int crypto_load_cert_store(X509_STORE *store, const char *file, * so openssl ignores it otherwise it'll try to open a file or * path named ''. */ - if (!X509_STORE_load_locations(store, S_OR(file, NULL), S_OR(path, NULL))) { + if (!X509_STORE_load_locations(store->store, S_OR(file, NULL), S_OR(path, NULL))) { crypto_log_openssl(LOG_ERROR, "Failed to load store from file '%s' or path '%s'\n", S_OR(file, "N/A"), S_OR(path, "N/A")); return -1; @@ -370,14 +357,15 @@ int crypto_load_cert_store(X509_STORE *store, const char *file, return 0; } -int crypto_show_cli_store(X509_STORE *store, int fd) +int crypto_show_cli_store(struct crypto_cert_store *store, int fd) { +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) STACK_OF(X509_OBJECT) *certs = NULL; int count = 0; int i = 0; char subj[1024]; - certs = X509_STORE_get0_objects(store); + certs = X509_STORE_get0_objects(store->store); count = sk_X509_OBJECT_num(certs); for (i = 0; i < count ; i++) { X509_OBJECT *o = sk_X509_OBJECT_value(certs, i); @@ -386,7 +374,12 @@ int crypto_show_cli_store(X509_STORE *store, int fd) ast_cli(fd, "%s\n", subj); } return count; +#else + ast_cli(fd, "This command is not supported until OpenSSL 1.1.0\n"); + return 0; +#endif } + int crypto_is_cert_time_valid(X509*cert, time_t reftime) { ASN1_STRING *notbefore; @@ -406,7 +399,7 @@ int crypto_is_cert_time_valid(X509*cert, time_t reftime) X509_cmp_time(notafter, &reftime) > 0); } -int crypto_is_cert_trusted(X509_STORE *store, X509 *cert, const char **err_msg) +int crypto_is_cert_trusted(struct crypto_cert_store *store, X509 *cert, const char **err_msg) { X509_STORE_CTX *verify_ctx = NULL; int rc = 0; @@ -416,7 +409,7 @@ int crypto_is_cert_trusted(X509_STORE *store, X509 *cert, const char **err_msg) return 0; } - if (X509_STORE_CTX_init(verify_ctx, store, cert, NULL) != 1) { + if (X509_STORE_CTX_init(verify_ctx, store->store, cert, NULL) != 1) { X509_STORE_CTX_cleanup(verify_ctx); X509_STORE_CTX_free(verify_ctx); crypto_log_openssl(LOG_ERROR, "Unable to initialize verify_ctx\n"); diff --git a/res/res_stir_shaken/crypto_utils.h b/res/res_stir_shaken/crypto_utils.h index 70538709f7..1f475c6521 100644 --- a/res/res_stir_shaken/crypto_utils.h +++ b/res/res_stir_shaken/crypto_utils.h @@ -164,20 +164,27 @@ int crypto_extract_raw_privkey(EVP_PKEY *key, unsigned char **buffer); */ EVP_PKEY *crypto_load_privkey_from_file(const char *filename); +/*! + * \brief ao2 object wrapper for X509_STORE that provides locking and refcounting + */ +struct crypto_cert_store { + X509_STORE *store; +}; + /*! * \brief Free an X509 store * * \param store X509 Store to free * */ -void crypto_free_cert_store(X509_STORE *store); +#define crypto_free_cert_store(store) ao2_cleanup(store) /*! * \brief Create an empty X509 store * - * \returns X509_STORE* or NULL on error + * \returns crypto_cert_store * or NULL on error */ -X509_STORE *crypto_create_cert_store(void); +struct crypto_cert_store *crypto_create_cert_store(void); /*! * \brief Dump a cert store to the asterisk CLI @@ -187,7 +194,7 @@ X509_STORE *crypto_create_cert_store(void); * \retval Count of objects printed */ -int crypto_show_cli_store(X509_STORE *store, int fd); +int crypto_show_cli_store(struct crypto_cert_store *store, int fd); /*! * \brief Load an X509 Store with either certificates or CRLs @@ -201,7 +208,7 @@ int crypto_show_cli_store(X509_STORE *store, int fd); * \retval <= 0 failure * \retval 0 success */ -int crypto_load_cert_store(X509_STORE *store, const char *file, +int crypto_load_cert_store(struct crypto_cert_store *store, const char *file, const char *path); /*! @@ -212,7 +219,7 @@ int crypto_load_cert_store(X509_STORE *store, const char *file, * \retval <= 0 failure * \retval 0 success */ -int crypto_lock_cert_store(X509_STORE *store); +#define crypto_lock_cert_store(store) ao2_lock(store) /*! * \brief Unlocks an X509 Store @@ -222,7 +229,7 @@ int crypto_lock_cert_store(X509_STORE *store); * \retval <= 0 failure * \retval 0 success */ -int crypto_unlock_cert_store(X509_STORE *store); +#define crypto_unlock_cert_store(store) ao2_unlock(store) /*! * \brief Check if the reftime is within the cert's valid dates @@ -245,7 +252,7 @@ int crypto_is_cert_time_valid(X509 *cert, time_t reftime); * \retval 1 Cert is trusted * \retval 0 Cert is not trusted */ -int crypto_is_cert_trusted(X509_STORE *store, X509 *cert, const char **err_msg); +int crypto_is_cert_trusted(struct crypto_cert_store *store, X509 *cert, const char **err_msg); /*! * \brief Return a time_t for an ASN1_TIME diff --git a/res/res_stir_shaken/verification_config.c b/res/res_stir_shaken/verification_config.c index 4f44995b75..0cade6bd52 100644 --- a/res/res_stir_shaken/verification_config.c +++ b/res/res_stir_shaken/verification_config.c @@ -129,7 +129,7 @@ int vs_copy_cfg_common(const char *id, struct verification_cfg_common *cfg_dst, cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, ca_path); cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, crl_file); cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, crl_path); - X509_STORE_up_ref(cfg_src->tcs); + ao2_bump(cfg_src->tcs); cfg_dst->tcs = cfg_src->tcs; } @@ -230,12 +230,12 @@ int vs_check_common_config(const char *id, if (vcfg_common->tcs) { if (ENUM_BOOL(vcfg_common->load_system_certs, load_system_certs)) { - X509_STORE_set_default_paths(vcfg_common->tcs); + X509_STORE_set_default_paths(vcfg_common->tcs->store); } if (!ast_strlen_zero(vcfg_common->crl_file) || !ast_strlen_zero(vcfg_common->crl_path)) { - X509_STORE_set_flags(vcfg_common->tcs, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + X509_STORE_set_flags(vcfg_common->tcs->store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); } }