From: Arran Cudbard-Bell Date: Wed, 5 Oct 2022 03:44:25 +0000 (-0400) Subject: Actually commit the strerror functions. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dd55c6adf9d657a581df971bc14de4664e73d89a;p=thirdparty%2Ffreeradius-server.git Actually commit the strerror functions. --- diff --git a/src/lib/tls/strerror.c b/src/lib/tls/strerror.c new file mode 100644 index 00000000000..80451e14a99 --- /dev/null +++ b/src/lib/tls/strerror.c @@ -0,0 +1,224 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @file tls/strerror.c + * @brief Convert the contents of OpenSSL's error stack to our thread local error stack + * + * @copyright 2022 The FreeRADIUS server project + */ +RCSID("$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#ifdef WITH_TLS +#define LOG_PREFIX "tls" + +#include +#include +#include + +#include "strerror.h" +#include "utils.h" + +#if OPENSSL_VERSION_NUMBER < 0x30000000L +static inline unsigned long ERR_get_error_all(const char **file, int *line, + const char **func, + const char **data, int *flags) +{ + if (func != NULL) *func = ""; + + return ERR_get_error_line_data(file, line, data, flags); +} +#endif + +DIAG_OFF(DIAG_UNKNOWN_PRAGMAS) +DIAG_OFF(used-but-marked-unused) /* fix spurious warnings for sk macros */ +static void _tls_cert_line_push(char const *file, int line, int idx, X509 *cert) +{ + char subject[1024]; + + X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject)); + subject[sizeof(subject) - 1] = '\0'; + + _fr_strerror_printf_push(file, line, "[%i] %s %s", idx, fr_tls_utils_x509_pkey_type(cert), subject); +} + +static void _tls_cert_line_marker_push(char const *file, int line, + int idx, X509 *cert, bool marker) +{ + char subject[1024]; + + X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject)); + subject[sizeof(subject) - 1] = '\0'; + + _fr_strerror_printf_push(file, line, "%s [%i] %s %s", marker ? ">" : " ", + idx, fr_tls_utils_x509_pkey_type(cert), subject); +} + +static void _tls_cert_line_marker_no_idx_push(char const *file, int line, X509 *cert) +{ + char subject[1024]; + + X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject)); + subject[sizeof(subject) - 1] = '\0'; + + _fr_strerror_printf_push(file, line, "%s %s", fr_tls_utils_x509_pkey_type(cert), subject); +} + +/** Print out the current stack of certs to the thread local error buffer + * + * @param[in] file File where this function is being called. + * @param[in] line Line where this function is being called. + * @param[in] chain The certificate chain. + * @param[in] cert The leaf certificate. + */ +void _fr_tls_strerror_push_chain(char const *file, int line, STACK_OF(X509) *chain, X509 *cert) +{ + int i; + + for (i = sk_X509_num(chain); i > 0 ; i--) { + _tls_cert_line_push(file, line, i, sk_X509_value(chain, i - 1)); + } + if (cert) _tls_cert_line_push(file, line, i, cert); +} + +/** Print out the current stack of certs to the thread local error buffer + * + * @param[in] file File where this function is being called. + * @param[in] line Line where this function is being called. + * @param[in] chain The certificate chain. + * @param[in] cert The leaf certificate. + * @param[in] marker The certificate we want to mark. + */ +void _fr_tls_strerror_push_chain_marker(char const *file, int line, + STACK_OF(X509) *chain, X509 *cert, X509 *marker) +{ + int i; + + for (i = sk_X509_num(chain); i > 0 ; i--) { + X509 *selected = sk_X509_value(chain, i - 1); + _tls_cert_line_marker_push(file, line, i, selected, (selected == marker)); + } + if (cert) _tls_cert_line_marker_push(file, line, i, cert, (cert == marker)); +} + +/** Print out the current stack of X509 objects (certificates only) + * + * @param[in] file File where this function is being called. + * @param[in] line Line where this function is being called. + * @param[in] objects A stack of X509 objects + */ +void _fr_tls_strerror_push_x509_objects(char const *file, int line, STACK_OF(X509_OBJECT) *objects) +{ + int i; + + for (i = sk_X509_OBJECT_num(objects); i > 0 ; i--) { + X509_OBJECT *obj = sk_X509_OBJECT_value(objects, i - 1); + + switch (X509_OBJECT_get_type(obj)) { + case X509_LU_X509: /* X509 certificate */ + /* + * Dump to the thread local buffer + */ + _tls_cert_line_marker_no_idx_push(file, line, X509_OBJECT_get0_X509(obj)); + break; + + case X509_LU_CRL: /* Certificate revocation list */ + continue; + + default: + continue; + } + } +} + +DIAG_OFF(format-nonliteral) +/** Print errors in the TLS thread local error stack + * + * Drains the thread local OpenSSL error queue, and prints out the first error + * storing it in libfreeradius's error buffer. + * + * @param[in] msg Error message describing the operation being attempted. + * @param[in] ap Arguments for msg. + * @return the number of errors drained from the stack. + */ +int _fr_tls_strerror_vprintf(char const *file, int line, char const *msg, va_list ap) +{ + unsigned long error; + char *p = NULL; + int drained = 0; + char buffer[256]; + + int openssl_line; + char const *openssl_file; + char const *func; + char const *data; + int flags = 0; + + /* + * Pop the first error, so ERR_peek_error() + * can be used to determine if there are + * multiple errors. + */ + error = ERR_get_error_all(&openssl_file, &openssl_line, &func, &data, &flags); + if (!(flags & ERR_TXT_STRING)) data = NULL; + + if (msg) { + /* + * Print the error we were passed, and + * OpenSSL's error. + */ + if (error) { + p = talloc_vasprintf(NULL, msg, ap); + ERR_error_string_n(error, buffer, sizeof(buffer)); + _fr_strerror_printf(openssl_file, openssl_line, + "%s: %s%c%s", p, buffer, data ? ':' : '\0', data ? data : ""); + talloc_free(p); + drained++; + /* + * Print the error we were given, irrespective + * of whether there were any OpenSSL errors. + */ + } else { + va_list our_ap; + + va_copy(our_ap, ap); + _fr_strerror_vprintf(file, line, msg, our_ap); + va_end(our_ap); + } + } else if (error) { + ERR_error_string_n(error, buffer, sizeof(buffer)); + _fr_strerror_printf(openssl_file, openssl_line, "%s%c%s", buffer, data ? ':' : '\0', data ? data : ""); + drained++; + } else { + return 0; + } + + while ((error = ERR_get_error_all(&openssl_file, &openssl_line, &func, &data, &flags))) { + if (!(flags & ERR_TXT_STRING)) data = NULL; + + ERR_error_string_n(error, buffer, sizeof(buffer)); + + _fr_strerror_printf_push(openssl_file, openssl_line, "%s%c%s", buffer, data ? ':' : '\0', data ? data : ""); + drained++; + } + + return drained; +} +DIAG_ON(format-nonliteral) +#endif /* WITH_TLS */ diff --git a/src/lib/tls/strerror.h b/src/lib/tls/strerror.h new file mode 100644 index 00000000000..7f64dd12429 --- /dev/null +++ b/src/lib/tls/strerror.h @@ -0,0 +1,99 @@ +#pragma once +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifdef WITH_TLS +/** + * $Id$ + * + * @file lib/tls/strerror.h + * @brief Prototypes for TLS strerror + * + * @copyright 2022 Arran Cudbard-Bell (a.cudbardb@freeradius.org) + */ +RCSIDH(tls_strerror_h, "$Id$") + +#include "openssl_user_macros.h" + +#include +#include + +#include "base.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Push a representation of a certificate chain onto the thread local error stack + * + * @param[in] _chain A stack of X509 certificates representing the chain. + * @param[in] _leaf The leaf certificate. May be NULL. + * @param[in] _marker The certificate to emit a marker for. + */ +#define fr_tls_strerror_push_chain(_chain, _leaf) \ + _fr_tls_strerror_push_chain( __FILE__, __LINE__, _chain, _leaf) +void _fr_tls_strerror_push_chain(char const *file, int line, STACK_OF(X509) *chain, X509 *cert); + +/** Push a representation of a certificate chain with a marker onto the thread local error stack + * + * @param[in] _chain A stack of X509 certificates representing the chain. + * @param[in] _leaf The leaf certificate. May be NULL. + * @param[in] _marker The certificate to emit a marker for. + */ +#define fr_tls_strerror_push_chain_marker(_chain, _leaf, _marker) \ + _fr_tls_strerror_push_chain( __FILE__, __LINE__, _chain, _leaf, _marker) +void _fr_tls_strerror_push_chain_marker(char const *file, int line, + STACK_OF(X509) *chain, X509 *cert, X509 *marker); + +/** Push a collection of X509 objects into the thread local error stack + * + * @param[in] _objects to push onto the thread local error stack + */ +#define fr_tls_strerror_push_x509_objects(_objects) \ + _fr_tls_strerror_push_x509_objects( __FILE__, __LINE__, _objects) +void _fr_tls_strerror_push_x509_objects(char const *file, int line, + STACK_OF(X509_OBJECT) *objects); + +#define fr_tls_strerror_vprintf(_msg, _ap) \ + _fr_tls_strerror_vprintf(__FILE__, __LINE__, _msg, _ap) +int _fr_tls_strerror_vprintf(char const *file, int line, char const *msg, va_list ap); + +/** Wrapper around fr_strerror_printf to log error messages for library functions calling libssl + * + * @note Will only drain the first error. + * + * @param[in] msg Error message describing the operation being attempted. + * @param[in] ... Arguments for msg. + * @return the number of errors drained from the stack. + */ +#define fr_tls_strerror_printf(_msg, ...) \ + _fr_tls_strerror_printf(__FILE__, __LINE__, _msg, ##__VA_ARGS__) + +static inline CC_HINT(format (printf, 3, 4)) +int _fr_tls_strerror_printf(char const *file, int line, char const *msg, ...) +{ + va_list ap; + int ret; + + va_start(ap, msg); + ret = _fr_tls_strerror_vprintf(file, line, msg, ap); + va_end(ap); + + return ret; +} +#ifdef __cplusplus +} +#endif +#endif /* WITH_TLS */