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