]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Actually commit the strerror functions.
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 5 Oct 2022 03:44:25 +0000 (23:44 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 5 Oct 2022 03:44:25 +0000 (23:44 -0400)
src/lib/tls/strerror.c [new file with mode: 0644]
src/lib/tls/strerror.h [new file with mode: 0644]

diff --git a/src/lib/tls/strerror.c b/src/lib/tls/strerror.c
new file mode 100644 (file)
index 0000000..80451e1
--- /dev/null
@@ -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 <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/strerror.h>
+#include <stdatomic.h>
+
+#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 (file)
index 0000000..7f64dd1
--- /dev/null
@@ -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 <openssl/x509.h>
+#include <stdint.h>
+
+#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 */