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: 5f189df2904b282ad45cb6de014016551ebec279 $
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: 5f189df2904b282ad45cb6de014016551ebec279 $")
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 
39 DIAG_OFF(used-but-marked-unused) /* fix spurious warnings for sk macros */
40 static void _tls_cert_line_push(char const *file, int line, int idx, X509 *cert)
41 {
42  char subject[1024];
43 
44  X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject));
45  subject[sizeof(subject) - 1] = '\0';
46 
47  _fr_strerror_printf_push(file, line, "[%i] %s %s", idx, fr_tls_utils_x509_pkey_type(cert), subject);
48 }
49 
50 static void _tls_cert_line_marker_push(char const *file, int line,
51  int idx, X509 *cert, bool marker)
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, "%s [%i] %s %s", marker ? ">" : " ",
59  idx, fr_tls_utils_x509_pkey_type(cert), subject);
60 }
61 
62 static void _tls_cert_line_marker_no_idx_push(char const *file, int line, X509 *cert)
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 
70 }
71 
72 /** Print out the current stack of certs to the thread local error buffer
73  *
74  * @param[in] file File where this function is being called.
75  * @param[in] line Line where this function is being called.
76  * @param[in] chain The certificate chain.
77  * @param[in] cert The leaf certificate.
78  */
79 void _fr_tls_strerror_push_chain(char const *file, int line, STACK_OF(X509) *chain, X509 *cert)
80 {
81  int i;
82 
83  for (i = sk_X509_num(chain); i > 0 ; i--) {
84  _tls_cert_line_push(file, line, i, sk_X509_value(chain, i - 1));
85  }
86  if (cert) _tls_cert_line_push(file, line, i, cert);
87 }
88 
89 /** Print out the current stack of certs to the thread local error buffer
90  *
91  * @param[in] file File where this function is being called.
92  * @param[in] line Line where this function is being called.
93  * @param[in] chain The certificate chain.
94  * @param[in] cert The leaf certificate.
95  * @param[in] marker The certificate we want to mark.
96  */
97 void _fr_tls_strerror_push_chain_marker(char const *file, int line,
98  STACK_OF(X509) *chain, X509 *cert, X509 *marker)
99 {
100  int i;
101 
102  for (i = sk_X509_num(chain); i > 0 ; i--) {
103  X509 *selected = sk_X509_value(chain, i - 1);
104  _tls_cert_line_marker_push(file, line, i, selected, (selected == marker));
105  }
106  if (cert) _tls_cert_line_marker_push(file, line, i, cert, (cert == marker));
107 }
108 
109 /** Print out the current stack of X509 objects (certificates only)
110  *
111  * @param[in] file File where this function is being called.
112  * @param[in] line Line where this function is being called.
113  * @param[in] objects A stack of X509 objects
114  */
115 void _fr_tls_strerror_push_x509_objects(char const *file, int line, STACK_OF(X509_OBJECT) *objects)
116 {
117  int i;
118 
119  for (i = sk_X509_OBJECT_num(objects); i > 0 ; i--) {
120  X509_OBJECT *obj = sk_X509_OBJECT_value(objects, i - 1);
121 
122  switch (X509_OBJECT_get_type(obj)) {
123  case X509_LU_X509: /* X509 certificate */
124  /*
125  * Dump to the thread local buffer
126  */
127  _tls_cert_line_marker_no_idx_push(file, line, X509_OBJECT_get0_X509(obj));
128  break;
129 
130  case X509_LU_CRL: /* Certificate revocation list */
131  continue;
132 
133  default:
134  continue;
135  }
136  }
137 }
138 
139 DIAG_OFF(format-nonliteral)
140 /** Print errors in the TLS thread local error stack
141  *
142  * Drains the thread local OpenSSL error queue, and prints out the first error
143  * storing it in libfreeradius's error buffer.
144  *
145  * @param[in] file The function was called from.
146  * @param[in] line The line the function was called from.
147  * @param[in] msg Error message describing the operation being attempted.
148  * @param[in] ap Arguments for msg.
149  * @return the number of errors drained from the stack.
150  */
151 int _fr_tls_strerror_vprintf(char const *file, int line, char const *msg, va_list ap)
152 {
153  unsigned long error;
154  char *p = NULL;
155  int drained = 0;
156  char buffer[256];
157 
158  int openssl_line;
159  char const *openssl_file;
160  char const *func;
161  char const *data;
162  int flags = 0;
163 
164  /*
165  * Pop the first error, so ERR_peek_error()
166  * can be used to determine if there are
167  * multiple errors.
168  */
169  error = ERR_get_error_all(&openssl_file, &openssl_line, &func, &data, &flags);
170  if (!(flags & ERR_TXT_STRING)) data = NULL;
171 
172  if (msg) {
173  /*
174  * Print the error we were passed, and
175  * OpenSSL's error.
176  */
177  if (error) {
178  p = talloc_vasprintf(NULL, msg, ap);
179  ERR_error_string_n(error, buffer, sizeof(buffer));
180  _fr_strerror_printf(openssl_file, openssl_line,
181  "%s: %s%c%s", p, buffer, data ? ':' : '\0', data ? data : "");
182  talloc_free(p);
183  drained++;
184  /*
185  * Print the error we were given, irrespective
186  * of whether there were any OpenSSL errors.
187  */
188  } else {
189  va_list our_ap;
190 
191  va_copy(our_ap, ap);
192  _fr_strerror_vprintf(file, line, msg, our_ap);
193  va_end(our_ap);
194  }
195  } else if (error) {
196  ERR_error_string_n(error, buffer, sizeof(buffer));
197  _fr_strerror_printf(openssl_file, openssl_line, "%s%c%s", buffer, data ? ':' : '\0', data ? data : "");
198  drained++;
199  } else {
200  return 0;
201  }
202 
203  while ((error = ERR_get_error_all(&openssl_file, &openssl_line, &func, &data, &flags))) {
204  if (!(flags & ERR_TXT_STRING)) data = NULL;
205 
206  ERR_error_string_n(error, buffer, sizeof(buffer));
207 
208  _fr_strerror_printf_push(openssl_file, openssl_line, "%s%c%s", buffer, data ? ':' : '\0', data ? data : "");
209  drained++;
210  }
211 
212  return drained;
213 }
214 
215 /** Print errors in the TLS thread local error stack
216  *
217  * Drains the thread local OpenSSL error queue, and prints out the first error
218  * storing it in libfreeradius's error buffer.
219  *
220  * @return the number of errors drained from the stack.
221  */
222 int fr_tls_strerror_drain(void)
223 {
224  unsigned long error;
225 
226  int openssl_line;
227  char const *openssl_file;
228  char const *func;
229  char const *data;
230  int flags = 0;
231 
232  int drained = 0;
233  char buffer[256];
234 
235  /*
236  * Pop the first error, so ERR_peek_error()
237  * can be used to determine if there are
238  * multiple errors.
239  */
240  error = ERR_get_error_all(&openssl_file, &openssl_line, &func, &data, &flags);
241  if (!error) return 0;
242  if (!(flags & ERR_TXT_STRING)) data = NULL;
243 
244  ERR_error_string_n(error, buffer, sizeof(buffer));
245  _fr_strerror_printf(openssl_file, openssl_line, "%s%c%s", buffer, data ? ':' : '\0', data ? data : "");
246  drained++;
247 
248  while ((error = ERR_get_error_all(&openssl_file, &openssl_line, &func, &data, &flags))) {
249  if (!(flags & ERR_TXT_STRING)) continue;
250 
251  ERR_error_string_n(error, buffer, sizeof(buffer));
252 
253  _fr_strerror_printf_push(openssl_file, openssl_line, "%s%c%s", buffer, data ? ':' : '\0', data ? data : "");
254  drained++;
255  }
256 
257  return drained;
258 }
259 DIAG_ON(format-nonliteral)
260 #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:468
#define RCSID(id)
Definition: build.h:481
#define DIAG_UNKNOWN_PRAGMAS
Definition: build.h:454
#define DIAG_ON(_x)
Definition: build.h:456
#define DIAG_OFF(_x)
Definition: build.h:455
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:1265
int format(printf, 5, 0))