The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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 */
25RCSID("$Id: 5f189df2904b282ad45cb6de014016551ebec279 $")
26USES_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
39DIAG_OFF(used-but-marked-unused) /* fix spurious warnings for sk macros */
40static 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
50static 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
62static 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 */
79void _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 */
97void _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 */
115void _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
139DIAG_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 */
151int _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);
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 */
222int 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}
259DIAG_ON(format-nonliteral)
260#endif /* WITH_TLS */
static int const char char buffer[256]
Definition acutest.h:576
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:470
#define RCSID(id)
Definition build.h:483
#define DIAG_UNKNOWN_PRAGMAS
Definition build.h:456
#define DIAG_ON(_x)
Definition build.h:458
#define DIAG_OFF(_x)
Definition build.h:457
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