From d3ada7279a4bfd452f1eae81a40bf7c5ea549976 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Thu, 21 Apr 2016 13:15:53 +0200 Subject: [PATCH] Add helper functions for openssl error handling Change-Id: Ibc20d9e37bc2d90a92646e1115d9a1b63f5342e6 --- api/yaca/error.h | 18 ++++++++++++ src/crypto.c | 3 ++ src/error.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/internal.h | 3 ++ 4 files changed, 110 insertions(+) create mode 100644 src/error.c diff --git a/api/yaca/error.h b/api/yaca/error.h index 1e5ee16..5012c34 100644 --- a/api/yaca/error.h +++ b/api/yaca/error.h @@ -41,6 +41,24 @@ enum __yaca_error_code { YACA_ERROR_SIGNATURE_INVALID = -7 }; +// TODO disable debug function in release? + +/** + * @brief Debug callback type. + */ +typedef void (*yaca_debug_func)(const char*); + +/** + * @brief yaca_error_set_debug_func Sets a current thread debug callback that will be called each + * time an internal error occurs. A NULL terminated string with + * location and description of the error will be passed as an + * argument. + * + * @param[in] fn Function to set as internal error callback. + */ +void yaca_error_set_debug_func(yaca_debug_func fn); + + #ifdef __cplusplus } /* extern */ #endif diff --git a/src/crypto.c b/src/crypto.c index 2ffb10c..4cc313f 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,8 @@ API int yaca_init(void) API void yaca_exit(void) { + ERR_free_strings(); + ERR_remove_thread_state(NULL); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); } diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..140d1b4 --- /dev/null +++ b/src/error.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file error.c + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + */ + +#include +#include +#include + +#include + +#include +#include "internal.h" + +// TODO any better idea than to use __thread? +static __thread yaca_debug_func debug_fn = NULL; +static bool error_strings_loaded = false; + +API void yaca_error_set_debug_func(yaca_debug_func fn) +{ + debug_fn = fn; +} + +// TODO use peeking function to intercept common errors +//unsigned long ERR_peek_error(); + +void error_dump(const char *file, int line, const char *function, int code) +{ + if (debug_fn == NULL) + return; + + static const size_t BUF_SIZE = 512; + static const char ELLIPSIS[] = "...\n"; + static const size_t ELLIPSIS_SIZE = sizeof(ELLIPSIS) / sizeof(ELLIPSIS[0]); + char buf[BUF_SIZE]; + unsigned long err; + size_t written; + + written = snprintf(buf, BUF_SIZE, "%s:%d %s() API error: %d\n", file, line, function, code); + + while ((err = ERR_get_error()) != 0 && written < BUF_SIZE - 1) { + if (!error_strings_loaded) { + /* + * Both these functions are thread-safe as long as static locks are + * installed according to doc so calling them twice won't break + * anything and I don't want to use synchronization mechanisms + * here. + */ + ERR_load_crypto_strings(); + ERR_clear_error(); + error_strings_loaded = true; + } + + ERR_error_string_n(err, buf + written, BUF_SIZE - written); + written = strlen(buf); /* I trust you, openssl */ + if (written < BUF_SIZE - 1) { + buf[written] = '\n'; + written++; + } + } + + if (written >= BUF_SIZE - 1) { + strncpy(buf + BUF_SIZE - ELLIPSIS_SIZE, ELLIPSIS, ELLIPSIS_SIZE); + written = BUF_SIZE - 1; + ERR_clear_error(); + } + buf[written] = '\0'; + + (*debug_fn)(buf); +} + diff --git a/src/internal.h b/src/internal.h index 25f0edc..2b5dc9f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -94,4 +94,7 @@ int digest_get_algorithm(yaca_digest_algo_e algo, const EVP_MD **md); struct yaca_key_simple_s *key_get_simple(const yaca_key_h key); struct yaca_key_evp_s *key_get_evp(const yaca_key_h key); +void error_dump(const char *file, int line, const char *function, int code); +#define ERROR_DUMP(code) error_dump(__FILE__, __LINE__, __FUNCTION__, (code)) + #endif -- 2.7.4