diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 1c40975908..20655ecd4e 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -1460,6 +1460,9 @@ SWITCH_DECLARE(char *)switch_html_strip(const char *str); SWITCH_DECLARE(unsigned long) switch_getpid(void); +SWITCH_DECLARE(switch_status_t) switch_digest(const char *digest_name, unsigned char **digest, const void *input, switch_size_t inputLen, unsigned int *outputlen); +SWITCH_DECLARE(switch_status_t) switch_digest_string(const char *digest_name, char **digest_str, const void *input, switch_size_t inputLen, unsigned int *outputlen); + SWITCH_END_EXTERN_C #endif /* For Emacs: diff --git a/src/switch_core.c b/src/switch_core.c index 2a27b57ea3..d4507aa49c 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1945,6 +1945,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc SSL_library_init(); switch_ssl_init_ssl_locks(); + OpenSSL_add_all_algorithms(); switch_curl_init(); switch_core_set_variable("hostname", runtime.hostname); @@ -3037,6 +3038,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void) switch_curl_destroy(); switch_ssl_destroy_ssl_locks(); + EVP_cleanup(); switch_scheduler_task_thread_stop(); diff --git a/src/switch_utils.c b/src/switch_utils.c index 5d6b8f2aaf..0fee81551b 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -51,6 +51,10 @@ #include "gumbo.h" #endif +#if defined(HAVE_OPENSSL) +#include +#endif + struct switch_network_node { ip_t ip; ip_t mask; @@ -4549,6 +4553,89 @@ SWITCH_DECLARE(unsigned long) switch_getpid(void) return (unsigned long)pid; } +SWITCH_DECLARE(switch_status_t) switch_digest(const char *digest_name, unsigned char **digest, const void *input, switch_size_t inputLen, unsigned int *outputlen) +{ +#if defined(HAVE_OPENSSL) + EVP_MD_CTX *mdctx; + const EVP_MD *md; + int size; + + switch_assert(digest); + + if (!digest_name) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Message digest is not set\n"); + return SWITCH_STATUS_FALSE; + } + + md = EVP_get_digestbyname(digest_name); + + if (!md) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown message digest %s\n", digest_name); + return SWITCH_STATUS_FALSE; + } + + size = EVP_MD_size(md); + if (!size || !(*digest = malloc(size))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Zero digest size or can't allocate memory to store results %s\n", digest_name); + return SWITCH_STATUS_FALSE; + } + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + mdctx = EVP_MD_CTX_new(); +#else + mdctx = EVP_MD_CTX_create(); +#endif + + if (!mdctx) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "EVP_MD_CTX_new error\n"); + switch_safe_free(*digest); + return SWITCH_STATUS_FALSE; + } + + EVP_MD_CTX_init(mdctx); + EVP_DigestInit_ex(mdctx, md, NULL); + EVP_DigestUpdate(mdctx, input, inputLen); + EVP_DigestFinal_ex(mdctx, *digest, outputlen); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_MD_CTX_free(mdctx); +#else + EVP_MD_CTX_destroy(mdctx); +#endif + + return SWITCH_STATUS_SUCCESS; +#else + return SWITCH_STATUS_FALSE; +#endif +} + +SWITCH_DECLARE(switch_status_t) switch_digest_string(const char *digest_name, char **digest_str, const void *input, switch_size_t inputLen, unsigned int *outputlen) +{ + unsigned char *digest = NULL; + switch_status_t status; + short i = 0, x; + uint8_t b; + + status = switch_digest(digest_name, &digest, input, inputLen, outputlen); + + if (status == SWITCH_STATUS_SUCCESS) { + if ((*digest_str = malloc(*outputlen * 2 + 1))) { + for (x = i = 0; x < *outputlen; x++) { + b = (digest[x] >> 4) & 15; + (*digest_str)[i++] = b + (b > 9 ? 'a' - 10 : '0'); + b = digest[x] & 15; + (*digest_str)[i++] = b + (b > 9 ? 'a' - 10 : '0'); + } + + (*digest_str)[i] = '\0'; + } + } + + switch_safe_free(digest); + *outputlen = i; + + return status; +} /* For Emacs: * Local Variables: diff --git a/tests/unit/switch_core.c b/tests/unit/switch_core.c index 9f58969a6f..d0d6bacef2 100644 --- a/tests/unit/switch_core.c +++ b/tests/unit/switch_core.c @@ -34,6 +34,10 @@ #include +#if defined(HAVE_OPENSSL) +#include +#endif + FST_CORE_BEGIN("./conf") { FST_SUITE_BEGIN(switch_ivr_originate) @@ -48,6 +52,52 @@ FST_CORE_BEGIN("./conf") } FST_TEARDOWN_END() +#ifdef HAVE_OPENSSL + FST_TEST_BEGIN(test_md5) + { + char *digest_name = "md5"; + char *digest_str = NULL; + const char *str = "test data"; + unsigned int outputlen; + + switch_status_t status = switch_digest_string(digest_name, &digest_str, str, strlen(str), &outputlen); + fst_check_int_equals(status, SWITCH_STATUS_SUCCESS); + fst_check_string_equals(digest_str, "eb733a00c0c9d336e65691a37ab54293"); + switch_safe_free(digest_str); + } + FST_TEST_END() + + FST_TEST_BEGIN(test_sha256) + { + char *digest_name = "sha256"; + char *digest_str = NULL; + const char *str = "test data"; + unsigned int outputlen; + + switch_status_t status = switch_digest_string(digest_name, &digest_str, str, strlen(str), &outputlen); + fst_check_int_equals(status, SWITCH_STATUS_SUCCESS); + fst_check_string_equals(digest_str, "916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9"); + switch_safe_free(digest_str); + } + FST_TEST_END() +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10101000L + FST_TEST_BEGIN(test_sha512_256) + { + char *digest_name = "sha512-256"; + char *digest_str = NULL; + const char *str = "test data"; + unsigned int outputlen; + + switch_status_t status = switch_digest_string(digest_name, &digest_str, str, strlen(str), &outputlen); + fst_check_int_equals(status, SWITCH_STATUS_SUCCESS); + fst_check_string_equals(digest_str, "9fe875600168548c1954aed4f03974ce06b3e17f03a70980190da2d7ef937a43"); + switch_safe_free(digest_str); + } + FST_TEST_END() +#endif + #ifndef WIN32 FST_TEST_BEGIN(test_fork) { diff --git a/tests/unit/test_switch_core.2017.vcxproj b/tests/unit/test_switch_core.2017.vcxproj index 922fb9b51f..c9e1cd5423 100644 --- a/tests/unit/test_switch_core.2017.vcxproj +++ b/tests/unit/test_switch_core.2017.vcxproj @@ -47,6 +47,7 @@ $(DefaultPlatformToolset) +