The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
strerror.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 80451e14a99890819a08e8afc4bd6aad74435aff $
19  *
20  * @file tls/strerror.c
21  * @brief Convert the contents of OpenSSL's error stack to our thread local error stack
22  *
23  * @copyright 2022 The FreeRADIUS server project
24  */
25 RCSID("$Id: 80451e14a99890819a08e8afc4bd6aad74435aff $")
26 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
27 
28 #ifdef WITH_TLS
29 #define LOG_PREFIX "tls"
30 
31 #include <freeradius-devel/util/debug.h>
32 #include <freeradius-devel/util/strerror.h>
33 #include <stdatomic.h>
34 
35 #include "strerror.h"
36 #include "utils.h"
37 
38 #if OPENSSL_VERSION_NUMBER < 0x30000000L
39 static inline unsigned long ERR_get_error_all(const char **file, int *line,
40  const char **func,
41  const char **data, int *flags)
42 {
43  if (func != NULL) *func = "";
44 
45  return ERR_get_error_line_data(file, line, data, flags);
46 }
47 #endif
48 
50 DIAG_OFF(used-but-marked-unused) /* fix spurious warnings for sk macros */
51 static void _tls_cert_line_push(char const *file, int line, int idx, X509 *cert)
52 {
53  char subject[1024];
54 
55  X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject));
56  subject[sizeof(subject) - 1] = '\0';
57 
58  _fr_strerror_printf_push(file, line, "[%i] %s %s", idx, fr_tls_utils_x509_pkey_type(cert), subject);
59 }
60 
61 static void _tls_cert_line_marker_push(char const *file, int line,
62  int idx, X509 *cert, bool marker)
63 {
64  char subject[1024];
65 
66  X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject));
67  subject[sizeof(subject) - 1] = '\0';
68 
69  _fr_strerror_printf_push(file, line, "%s [%i] %s %s", marker ? ">" : " ",
70  idx, fr_tls_utils_x509_pkey_type(cert), subject);
71 }
72 
73 static void _tls_cert_line_marker_no_idx_push(char const *file, int line, X509 *cert)
74 {
75  char subject[1024];
76 
77  X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject));
78  subject[sizeof(subject) - 1] = '\0';
79 
81 }
82 
83 /** Print out the current stack of certs to the thread local error buffer
84  *
85  * @param[in] file File where this function is being called.
86  * @param[in] line Line where this function is being called.
87  * @param[in] chain The certificate chain.
88  * @param[in] cert The leaf certificate.
89  */
90 void _fr_tls_strerror_push_chain(char const *file, int line, STACK_OF(X509) *chain, X509 *cert)
91 {
92  int i;
93 
94  for (i = sk_X509_num(chain); i > 0 ; i--) {
95  _tls_cert_line_push(file, line, i, sk_X509_value(chain, i - 1));
96  }
97  if (cert) _tls_cert_line_push(file, line, i, cert);
98 }
99 
100 /** Print out the current stack of certs to the thread local error buffer
101  *
102  * @param[in] file File where this function is being called.
103  * @param[in] line Line where this function is being called.
104  * @param[in] chain The certificate chain.
105  * @param[in] cert The leaf certificate.
106  * @param[in] marker The certificate we want to mark.
107  */
108 void _fr_tls_strerror_push_chain_marker(char const *file, int line,
109  STACK_OF(X509) *chain, X509 *cert, X509 *marker)
110 {
111  int i;
112 
113  for (i = sk_X509_num(chain); i > 0 ; i--) {
114  X509 *selected = sk_X509_value(chain, i - 1);
115  _tls_cert_line_marker_push(file, line, i, selected, (selected == marker));
116  }
117  if (cert) _tls_cert_line_marker_push(file, line, i, cert, (cert == marker));
118 }
119 
120 /** Print out the current stack of X509 objects (certificates only)
121  *
122  * @param[in] file File where this function is being called.
123  * @param[in] line Line where this function is being called.
124  * @param[in] objects A stack of X509 objects
125  */
126 void _fr_tls_strerror_push_x509_objects(char const *file, int line, STACK_OF(X509_OBJECT) *objects)
127 {
128  int i;
129 
130  for (i = sk_X509_OBJECT_num(objects); i > 0 ; i--) {
131  X509_OBJECT *obj = sk_X509_OBJECT_value(objects, i - 1);
132 
133  switch (X509_OBJECT_get_type(obj)) {
134  case X509_LU_X509: /* X509 certificate */
135  /*
136  * Dump to the thread local buffer
137  */
138  _tls_cert_line_marker_no_idx_push(file, line, X509_OBJECT_get0_X509(obj));
139  break;
140 
141  case X509_LU_CRL: /* Certificate revocation list */
142  continue;
143 
144  default:
145  continue;
146  }
147  }
148 }
149 
150 DIAG_OFF(format-nonliteral)
151 /** Print errors in the TLS thread local error stack
152  *
153  * Drains the thread local OpenSSL error queue, and prints out the first error
154  * storing it in libfreeradius's error buffer.
155  *
156  * @param[in] msg Error message describing the operation being attempted.
157  * @param[in] ap Arguments for msg.
158  * @return the number of errors drained from the stack.
159  */
160 int _fr_tls_strerror_vprintf(char const *file, int line, char const *msg, va_list ap)
161 {
162  unsigned long error;
163  char *p = NULL;
164  int drained = 0;
165  char buffer[256];
166 
167  int openssl_line;
168  char const *openssl_file;
169  char const *func;
170  char const *data;
171  int flags = 0;
172 
173  /*
174  * Pop the first error, so ERR_peek_error()
175  * can be used to determine if there are
176  * multiple errors.
177  */
178  error = ERR_get_error_all(&openssl_file, &openssl_line, &func, &data, &flags);
179  if (!(flags & ERR_TXT_STRING)) data = NULL;
180 
181  if (msg) {
182  /*
183  * Print the error we were passed, and
184  * OpenSSL's error.
185  */
186  if (error) {
187  p = talloc_vasprintf(NULL, msg, ap);
188  ERR_error_string_n(error, buffer, sizeof(buffer));
189  _fr_strerror_printf(openssl_file, openssl_line,
190  "%s: %s%c%s", p, buffer, data ? ':' : '\0', data ? data : "");
191  talloc_free(p);
192  drained++;
193  /*
194  * Print the error we were given, irrespective
195  * of whether there were any OpenSSL errors.
196  */
197  } else {
198  va_list our_ap;
199 
200  va_copy(our_ap, ap);
201  _fr_strerror_vprintf(file, line, msg, our_ap);
202  va_end(our_ap);
203  }
204  } else if (error) {
205  ERR_error_string_n(error, buffer, sizeof(buffer));
206  _fr_strerror_printf(openssl_file, openssl_line, "%s%c%s", buffer, data ? ':' : '\0', data ? data : "");
207  drained++;
208  } else {
209  return 0;
210  }
211 
212  while ((error = ERR_get_error_all(&openssl_file, &openssl_line, &func, &data, &flags))) {
213  if (!(flags & ERR_TXT_STRING)) data = NULL;
214 
215  ERR_error_string_n(error, buffer, sizeof(buffer));
216 
217  _fr_strerror_printf_push(openssl_file, openssl_line, "%s%c%s", buffer, data ? ':' : '\0', data ? data : "");
218  drained++;
219  }
220 
221  return drained;
222 }
223 DIAG_ON(format-nonliteral)
224 #endif /* WITH_TLS */
static int const char char buffer[256]
Definition: acutest.h:574
int const char * file
Definition: acutest.h:702
va_end(args)
log_entry msg
Definition: acutest.h:794
int const char int line
Definition: acutest.h:702
#define USES_APPLE_DEPRECATED_API
Definition: build.h:431
#define RCSID(id)
Definition: build.h:444
#define DIAG_UNKNOWN_PRAGMAS
Definition: build.h:417
#define DIAG_ON(_x)
Definition: build.h:419
#define DIAG_OFF(_x)
Definition: build.h:418
talloc_free(reap)
static size_t used
void _fr_strerror_vprintf(char const *file, int line, char const *fmt, va_list ap)
Log to thread local error buffer.
Definition: strerror.c:245
static void _fr_strerror_printf(char const *file, int line, char const *fmt,...)
Definition: strerror.h:68
static void _fr_strerror_printf_push(char const *file, int line, char const *fmt,...)
Definition: strerror.h:88
char const * fr_tls_utils_x509_pkey_type(X509 *cert)
Returns a friendly identifier for the public key type of a certificate.
Definition: utils.c:45
static fr_slen_t data
Definition: value.h:1259
int format(printf, 5, 0))