/src/freeradius-server/src/lib/tls/verify.c
Line | Count | Source |
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: f028b9c59d8bff5438bc19d23ad3d4067952a811 $ |
19 | | * |
20 | | * @file tls/verify.c |
21 | | * @brief Expose certificate OIDs as attributes, and call validation virtual |
22 | | * server to check cert is valid. |
23 | | * |
24 | | * @copyright 2001 hereUare Communications, Inc. (raghud@hereuare.com) |
25 | | * @copyright 2003 Alan DeKok (aland@freeradius.org) |
26 | | * @copyright 2006-2016 The FreeRADIUS server project |
27 | | */ |
28 | | #ifdef WITH_TLS |
29 | 0 | #define LOG_PREFIX "tls" |
30 | | |
31 | | #include <freeradius-devel/server/exec.h> |
32 | | #include <freeradius-devel/server/pair.h> |
33 | | #include <freeradius-devel/tls/log.h> |
34 | | #include <freeradius-devel/unlang/function.h> |
35 | | #include <freeradius-devel/unlang/subrequest.h> |
36 | | #include <freeradius-devel/util/debug.h> |
37 | | #include <freeradius-devel/util/strerror.h> |
38 | | #include <freeradius-devel/util/syserror.h> |
39 | | |
40 | | #include "attrs.h" |
41 | | #include "base.h" |
42 | | |
43 | | /** Check to see if a verification operation should apply to a certificate |
44 | | * |
45 | | * @param[in] depth starting at 0. |
46 | | * Certificate 0 is the leaf cert (i.e. the client or server cert); |
47 | | * @param[in] untrusted The number of untrusted certificates. |
48 | | * @param[in] mode to check |
49 | | * @return |
50 | | * - true if a given validation check should apply. |
51 | | ** - false if a validation check should not apply. |
52 | | */ |
53 | | static inline CC_HINT(always_inline) |
54 | | bool verify_applies(fr_tls_verify_mode_t mode, int depth, int untrusted) |
55 | 0 | { |
56 | 0 | if (mode == FR_TLS_VERIFY_MODE_ALL) return true; |
57 | 0 | if (mode == FR_TLS_VERIFY_MODE_DISABLED) return false; |
58 | | |
59 | 0 | if ((mode & FR_TLS_VERIFY_MODE_LEAF) && (depth == 0)) return true; |
60 | 0 | if ((mode & FR_TLS_VERIFY_MODE_ISSUER) && (depth == 1)) return true; |
61 | 0 | if ((mode & FR_TLS_VERIFY_MODE_UNTRUSTED) && (depth < untrusted)) return true; |
62 | | |
63 | 0 | return false; |
64 | 0 | } |
65 | | |
66 | | DIAG_OFF(DIAG_UNKNOWN_PRAGMAS) |
67 | | DIAG_OFF(used-but-marked-unused) /* fix spurious warnings for sk macros */ |
68 | | |
69 | | /** Print verbose humanly readable messages about why certificate validation failed |
70 | | * |
71 | | */ |
72 | | static void tls_verify_error_detail(request_t *request, SSL_CTX *ctx, int err) |
73 | 0 | { |
74 | 0 | X509_STORE *store = SSL_CTX_get_ex_data(ctx, FR_TLS_EX_CTX_INDEX_VERIFY_STORE); |
75 | |
|
76 | 0 | switch (err) { |
77 | | /* |
78 | | * We linked the provided cert to at least one |
79 | | * other in a chain, but the chain doesn't terminate |
80 | | * in a root CA. |
81 | | */ |
82 | 0 | case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: |
83 | 0 | FALL_THROUGH; |
84 | | |
85 | | /* |
86 | | * We failed to link the provided cert to any |
87 | | * other local certificates in the chain. |
88 | | */ |
89 | 0 | case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: |
90 | 0 | RDEBUG2("Static certificates in verification store are"); |
91 | 0 | if (RDEBUG_ENABLED2) { |
92 | 0 | RINDENT(); |
93 | 0 | fr_tls_x509_objects_log(request, L_DBG, X509_STORE_get0_objects(store)); |
94 | 0 | REXDENT(); |
95 | 0 | } |
96 | 0 | break; |
97 | | |
98 | 0 | default: |
99 | 0 | break; |
100 | 0 | } |
101 | 0 | } |
102 | | |
103 | | /** Validates a certificate using custom logic |
104 | | * |
105 | | * Before trusting a certificate, we make sure that the certificate is |
106 | | * 'valid'. There are several checks we perform to verify its validity. |
107 | | * |
108 | | * 1. Verify the certificate's signature, and verifying that the certificate has |
109 | | * been issued by a trusted Certificate Authority (this is done for us by OpenSSL). |
110 | | * |
111 | | * 2. Verify that the certificate is valid for the present date (i.e. it is being |
112 | | * presented within its validity dates). |
113 | | * |
114 | | * 3. Verify that the certificate has not been revoked by its issuing Certificate |
115 | | * Authority, by checking with respect to a Certificate Revocation List (CRL). |
116 | | * |
117 | | * @note This callback will be called multiple times based on the depth of the root |
118 | | * certificate chain. |
119 | | * |
120 | | * @note As a byproduct of validation, various OIDs will be extracted from the |
121 | | * certificates, and inserted into the session-state list as fr_pair_t. |
122 | | * |
123 | | * @param ok preverify ok. 1 if true, 0 if false. |
124 | | * @param x509_ctx containing certs to verify. |
125 | | * @return |
126 | | * - 0 if not valid. |
127 | | * - 1 if valid. |
128 | | */ |
129 | | int fr_tls_verify_cert_cb(int ok, X509_STORE_CTX *x509_ctx) |
130 | 0 | { |
131 | 0 | X509 *cert; |
132 | |
|
133 | 0 | SSL_CTX *ssl_ctx; |
134 | 0 | SSL *ssl; |
135 | 0 | fr_tls_session_t *tls_session; |
136 | 0 | int err, depth; |
137 | 0 | fr_tls_conf_t *conf; |
138 | 0 | int my_ok = ok; |
139 | 0 | int untrusted; |
140 | |
|
141 | 0 | request_t *request; |
142 | 0 | fr_pair_t *container = NULL; |
143 | 0 | fr_pair_t *depth_pair; |
144 | |
|
145 | 0 | cert = X509_STORE_CTX_get_current_cert(x509_ctx); |
146 | 0 | err = X509_STORE_CTX_get_error(x509_ctx); |
147 | 0 | depth = X509_STORE_CTX_get_error_depth(x509_ctx); |
148 | 0 | untrusted = X509_STORE_CTX_get_num_untrusted(x509_ctx); |
149 | | |
150 | | /* |
151 | | * Retrieve the pointer to the SSL of the connection currently treated |
152 | | * and the application specific data stored into the SSL object. |
153 | | */ |
154 | 0 | ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); |
155 | 0 | ssl_ctx = SSL_get_SSL_CTX(ssl); |
156 | 0 | conf = fr_tls_session_conf(ssl); |
157 | 0 | tls_session = talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TLS_SESSION), fr_tls_session_t); |
158 | 0 | request = fr_tls_session_request(tls_session->ssl); |
159 | | |
160 | | /* |
161 | | * If this error appears it suggests |
162 | | * that OpenSSL is trying to perform post-handshake |
163 | | * certificate validation which we don't support. |
164 | | */ |
165 | 0 | if (!tls_session->can_pause) { |
166 | 0 | fr_assert_msg("Unexpected call to %s. " |
167 | 0 | "tls_session_async_handshake_cont must be in call stack", __FUNCTION__); |
168 | 0 | return 0; |
169 | 0 | } |
170 | | |
171 | | /* |
172 | | * Bail out as quickly as possible, producing |
173 | | * as few errors as possible. |
174 | | */ |
175 | 0 | if (unlang_request_is_cancelled(request)) { |
176 | 0 | X509_STORE_CTX_set_error(x509_ctx, 0); |
177 | 0 | return 1; |
178 | 0 | } |
179 | | |
180 | | /* |
181 | | * Find or add the chain depth attribute and record the greatest depth we see + 1, |
182 | | * as depth is zero based. |
183 | | */ |
184 | 0 | if (unlikely(fr_pair_find_or_append_by_da(request->session_state_ctx, &depth_pair, &request->session_state_pairs, |
185 | 0 | attr_tls_certificate_chain_depth) < 0)) { |
186 | 0 | RERROR("Failed to add certificate chain depth pair"); |
187 | 0 | return 0; |
188 | 0 | } |
189 | 0 | if (depth_pair->vp_uint32 < ((uint32_t)depth) + 1) depth_pair->vp_uint32 = (uint32_t)depth + 1; |
190 | |
|
191 | 0 | if (RDEBUG_ENABLED3) { |
192 | 0 | char subject[2048]; |
193 | 0 | STACK_OF(X509) *our_chain; |
194 | 0 | int i; |
195 | |
|
196 | 0 | our_chain = X509_STORE_CTX_get0_chain(x509_ctx); |
197 | 0 | RDEBUG3("Certificate chain - %i cert(s) untrusted", untrusted); |
198 | 0 | for (i = sk_X509_num(our_chain); i > 0 ; i--) { |
199 | 0 | X509 *this_cert = sk_X509_value(our_chain, i - 1); |
200 | |
|
201 | 0 | X509_NAME_oneline(X509_get_subject_name(this_cert), subject, sizeof(subject)); |
202 | 0 | subject[sizeof(subject) - 1] = '\0'; |
203 | |
|
204 | 0 | RDEBUG3("%s [%i] %s", this_cert == cert ? ">" : " ", i - 1, subject); |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | | /* |
209 | | * See if the user has disabled verification for |
210 | | * this certificate. If they have, force verification |
211 | | * to succeed. |
212 | | */ |
213 | 0 | if (!my_ok) { |
214 | 0 | char const *p = X509_verify_cert_error_string(err); |
215 | 0 | if (!verify_applies(conf->verify.mode, depth, untrusted)) { |
216 | 0 | RDEBUG2("Ignoring verification error - %s (%i)", p, err); |
217 | 0 | tls_verify_error_detail(request, ssl_ctx, err); |
218 | |
|
219 | 0 | my_ok = 1; |
220 | 0 | X509_STORE_CTX_set_error(x509_ctx, 0); |
221 | 0 | } else { |
222 | 0 | RERROR("Verification error - %s (%i)", p, err); |
223 | 0 | tls_verify_error_detail(request, ssl_ctx, err); |
224 | 0 | goto done; |
225 | 0 | } |
226 | 0 | } |
227 | | |
228 | 0 | if (verify_applies(conf->verify.attribute_mode, depth, untrusted) && |
229 | 0 | (!(container = fr_pair_find_by_da_idx(&request->session_state_pairs, attr_tls_certificate, depth)) || |
230 | 0 | fr_pair_list_empty(&container->vp_group))) { |
231 | 0 | if (!container) { |
232 | 0 | unsigned int i; |
233 | | |
234 | | /* |
235 | | * Build a stack of container attributes. |
236 | | * |
237 | | * OpenSSL passes us the deepest certificate |
238 | | * first, so we need to build out sufficient |
239 | | * TLS-Certificate container TLVs so the TLS-Certificate |
240 | | * indexes match the attribute depth. |
241 | | */ |
242 | 0 | for (i = fr_pair_count_by_da(&request->session_state_pairs, attr_tls_certificate); |
243 | 0 | i <= (unsigned int)depth; |
244 | 0 | i++) { |
245 | 0 | MEM(container = fr_pair_afrom_da(request->session_state_ctx, attr_tls_certificate)); |
246 | 0 | fr_pair_append(&request->session_state_pairs, container); |
247 | 0 | } |
248 | 0 | } |
249 | |
|
250 | | #ifdef STATIC_ANALYZER |
251 | | /* |
252 | | * Container can never be NULL, because if container |
253 | | * was previously NULL, i will be <= depth. |
254 | | */ |
255 | | if (!fr_cond_assert(container)) { |
256 | | my_ok = 0; |
257 | | goto done; |
258 | | } |
259 | | #endif |
260 | | /* |
261 | | * If we fail to populate the cert attributes, |
262 | | * trash all instances in the session-state list |
263 | | * and cause validation to fail. |
264 | | */ |
265 | 0 | if (fr_tls_session_pairs_from_x509_cert(&container->vp_group, container, |
266 | 0 | request, cert, conf->verify.der_decode) < 0) { |
267 | 0 | fr_pair_delete_by_da(&request->session_state_pairs, attr_tls_certificate); |
268 | 0 | if (conf->verify.der_decode) { |
269 | 0 | fr_pair_delete_by_da(&request->session_state_pairs, attr_der_certificate); |
270 | 0 | } |
271 | 0 | my_ok = 0; |
272 | 0 | goto done; |
273 | 0 | } |
274 | | |
275 | 0 | log_request_pair(L_DBG_LVL_2, request, NULL, container, "session-state."); |
276 | 0 | } |
277 | 0 | done: |
278 | | /* |
279 | | * If verification hasn't already failed |
280 | | * and we're meant to verify this cert |
281 | | * then call the virtual server. |
282 | | * |
283 | | * We only call the virtual server for |
284 | | * the certificate at depth 0 as all |
285 | | * other certificate attributes should |
286 | | * have been added by this point. |
287 | | */ |
288 | 0 | if (my_ok && (depth == 0)) { |
289 | 0 | if (conf->verify_certificate && tls_session->verify_client_cert) { |
290 | 0 | RDEBUG2("Requesting certificate validation"); |
291 | | |
292 | | /* |
293 | | * This sets the validation state of the tls_session |
294 | | * so that when we call ASYNC_pause_job(), and execution |
295 | | * jumps back to tls_session_async_handshake_cont |
296 | | * (just under SSL_read()) |
297 | | * the code there knows what job it needs to push onto |
298 | | * the unlang stack. |
299 | | */ |
300 | 0 | fr_tls_verify_cert_request(tls_session, SSL_session_reused(tls_session->ssl)); |
301 | | |
302 | | /* |
303 | | * Jumps back to SSL_read() in session.c |
304 | | * |
305 | | * Be aware that if the request is cancelled |
306 | | * whatever was meant to be done during the |
307 | | * time we yielded may not have been completed. |
308 | | */ |
309 | 0 | ASYNC_pause_job(); |
310 | | |
311 | | /* |
312 | | * Just try and bail out as quickly as possible. |
313 | | */ |
314 | 0 | if (unlang_request_is_cancelled(request)) { |
315 | 0 | X509_STORE_CTX_set_error(x509_ctx, 0); |
316 | 0 | fr_tls_verify_cert_reset(tls_session); |
317 | 0 | return 1; |
318 | 0 | } |
319 | | |
320 | | |
321 | | /* |
322 | | * If we couldn't validate the certificate |
323 | | * then validation overall fails. |
324 | | */ |
325 | 0 | if (!fr_tls_verify_cert_result(tls_session)) { |
326 | 0 | REDEBUG("Certificate validation failed"); |
327 | 0 | my_ok = 0; |
328 | 0 | X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_APPLICATION_VERIFICATION); |
329 | 0 | } |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | 0 | tls_session->client_cert_ok = (my_ok > 0); |
334 | 0 | RDEBUG2("[verify] = %s", my_ok ? "ok" : "invalid"); |
335 | |
|
336 | 0 | return my_ok; |
337 | 0 | } |
338 | | DIAG_ON(used-but-marked-unused) |
339 | | DIAG_ON(DIAG_UNKNOWN_PRAGMAS) |
340 | | |
341 | | /** Revalidates the client's certificate chain |
342 | | * |
343 | | * Wraps the fr_tls_verify_cert_cb callback, allowing us to use the same |
344 | | * validation logic whenever we need to. |
345 | | * |
346 | | * @note Only use so far is forcing the chain to be re-validated on session |
347 | | * resumption. |
348 | | * |
349 | | * @return |
350 | | * - 1 if the chain could be validated. |
351 | | * - 0 if the chain failed validation. |
352 | | */ |
353 | | int fr_tls_verify_cert_chain(request_t *request, SSL *ssl) |
354 | 0 | { |
355 | 0 | int err; |
356 | 0 | int verify; |
357 | 0 | int ret = 1; |
358 | |
|
359 | 0 | SSL_CTX *ssl_ctx; |
360 | 0 | STACK_OF(X509) *chain; |
361 | 0 | X509 *cert; |
362 | 0 | X509_STORE *store; |
363 | 0 | X509_STORE_CTX *store_ctx; |
364 | | |
365 | | /* |
366 | | * If there's no client certificate, we just return OK. |
367 | | */ |
368 | 0 | cert = SSL_get0_peer_certificate(ssl); /* Does not increase ref count */ |
369 | 0 | if (!cert) return 1; |
370 | | |
371 | 0 | ssl_ctx = SSL_get_SSL_CTX(ssl); |
372 | 0 | store_ctx = X509_STORE_CTX_new(); |
373 | 0 | chain = SSL_get_peer_cert_chain(ssl); /* Does not increase ref count */ |
374 | 0 | store = SSL_CTX_get_ex_data(ssl_ctx, FR_TLS_EX_CTX_INDEX_VERIFY_STORE); /* Gets the verification store */ |
375 | | |
376 | | /* |
377 | | * This sets up a store_ctx for doing peer certificate verification. |
378 | | * |
379 | | * store_ctx - Is the ctx to initialise |
380 | | * store - Is an X509_STORE of implicitly |
381 | | * trusted certificates. Here we're using |
382 | | * the verify store that was created when we |
383 | | * allocated the SSL_CTX. |
384 | | * cert - Is the certificate to validate. |
385 | | * chain - Is any other certificates the peer provided |
386 | | * us in order to build a chain from a trusted |
387 | | * root or intermediary to its leaf (cert). |
388 | | * |
389 | | * Note: SSL_CTX_get_cert_store() returns the ctx->cert_store, which |
390 | | * is not the same as the verification cert store. |
391 | | */ |
392 | 0 | X509_STORE_CTX_init(store_ctx, store, cert, chain); |
393 | 0 | X509_STORE_CTX_set_ex_data(store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), ssl); |
394 | 0 | X509_STORE_CTX_set_verify_cb(store_ctx, fr_tls_verify_cert_cb); |
395 | |
|
396 | 0 | verify = X509_verify_cert(store_ctx); |
397 | 0 | if (verify != 1) { |
398 | 0 | err = X509_STORE_CTX_get_error(store_ctx); |
399 | |
|
400 | 0 | if (err != X509_V_OK) { |
401 | 0 | REDEBUG("Failed re-validating resumed session: %s", X509_verify_cert_error_string(err)); |
402 | 0 | ret = 0; |
403 | 0 | } |
404 | 0 | } |
405 | |
|
406 | 0 | X509_STORE_CTX_free(store_ctx); |
407 | |
|
408 | 0 | return ret; |
409 | 0 | } |
410 | | |
411 | | /** Process the result of `verify certificate { ... }` |
412 | | * |
413 | | */ |
414 | | static unlang_action_t tls_verify_client_cert_result(request_t *request, void *uctx) |
415 | 0 | { |
416 | 0 | fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t); |
417 | 0 | fr_pair_t *vp, *next; |
418 | |
|
419 | 0 | fr_assert(tls_session->validate.state == FR_TLS_VALIDATION_REQUESTED); |
420 | |
|
421 | 0 | vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_tls_packet_type); |
422 | 0 | if (!vp || (vp->vp_uint32 != enum_tls_packet_type_success->vb_uint32)) { |
423 | 0 | REDEBUG("Failed (re-)validating certificates"); |
424 | | |
425 | | /* |
426 | | * Hoist any instances of Module-Failure-Message from the subrequest |
427 | | * so they can be used for logging failures. |
428 | | */ |
429 | 0 | vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_module_failure_message); |
430 | 0 | while (vp && request->parent) { |
431 | 0 | next = fr_pair_find_by_da(&request->request_pairs, vp, attr_module_failure_message); |
432 | 0 | fr_pair_remove(&request->request_pairs, vp); |
433 | 0 | fr_pair_steal_append(request->parent->request_ctx, &request->parent->request_pairs, vp); |
434 | 0 | vp = next; |
435 | 0 | } |
436 | |
|
437 | 0 | tls_session->validate.state = FR_TLS_VALIDATION_FAILED; |
438 | 0 | return UNLANG_ACTION_CALCULATE_RESULT; |
439 | 0 | } |
440 | | |
441 | 0 | tls_session->validate.state = FR_TLS_VALIDATION_SUCCESS; |
442 | |
|
443 | 0 | RDEBUG2("Certificates (re-)validated"); |
444 | |
|
445 | 0 | return UNLANG_ACTION_CALCULATE_RESULT; |
446 | 0 | } |
447 | | |
448 | | /** Push a `verify certificate { ... }` call into the current request, using a subrequest |
449 | | * |
450 | | * @param[in] request The current request. |
451 | | * @param[in] tls_session The current TLS session. |
452 | | * @return |
453 | | * - UNLANG_ACTION_CALCULATE_RESULT on noop. |
454 | | * - UNLANG_ACTION_PUSHED_CHILD on success. |
455 | | * - UNLANG_ACTION_FAIL on failure. |
456 | | */ |
457 | | static unlang_action_t tls_verify_client_cert_push(request_t *request, fr_tls_session_t *tls_session) |
458 | 0 | { |
459 | 0 | fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl); |
460 | 0 | request_t *child; |
461 | 0 | fr_pair_t *vp; |
462 | 0 | unlang_action_t ua; |
463 | |
|
464 | 0 | MEM(child = unlang_subrequest_alloc(request, dict_tls)); |
465 | 0 | request = child; |
466 | | |
467 | | /* |
468 | | * Add extra pairs to the subrequest |
469 | | */ |
470 | 0 | fr_tls_session_extra_pairs_copy_to_child(child, tls_session); |
471 | | |
472 | | /* |
473 | | * Setup the child request for loading |
474 | | * session resumption data. |
475 | | */ |
476 | 0 | MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0); |
477 | 0 | vp->vp_uint32 = enum_tls_packet_type_verify_certificate->vb_uint32; |
478 | | |
479 | | /* |
480 | | * Copy certificate pairs to the child session state |
481 | | */ |
482 | 0 | vp = NULL; |
483 | 0 | while ((vp = fr_pair_find_by_da(&request->parent->session_state_pairs, vp, attr_tls_certificate))) { |
484 | 0 | fr_pair_append(&request->session_state_pairs, fr_pair_copy(request->session_state_ctx, vp)); |
485 | 0 | } |
486 | 0 | if (conf->verify.der_decode) { |
487 | 0 | while ((vp = fr_pair_find_by_da(&request->parent->session_state_pairs, vp, attr_der_certificate))) { |
488 | 0 | fr_pair_append(&request->session_state_pairs, fr_pair_copy(request->session_state_ctx, vp)); |
489 | 0 | } |
490 | 0 | } |
491 | |
|
492 | 0 | MEM(pair_append_request(&vp, attr_tls_session_resumed) >= 0); |
493 | 0 | vp->vp_bool = tls_session->validate.resumed; |
494 | | |
495 | | /* |
496 | | * Allocate a child, and set it up to call |
497 | | * the TLS virtual server. |
498 | | */ |
499 | 0 | ua = fr_tls_call_push(child, tls_verify_client_cert_result, conf, tls_session, false); |
500 | 0 | if (ua < 0) { |
501 | 0 | PERROR("Failed calling TLS virtual server"); |
502 | 0 | talloc_free(child); |
503 | 0 | return UNLANG_ACTION_FAIL; |
504 | 0 | } |
505 | | |
506 | 0 | return ua; |
507 | 0 | } |
508 | | |
509 | | /** Clear any previous validation result |
510 | | * |
511 | | * Should be called by the validation requestor to get the result and reset |
512 | | * the validation state. |
513 | | * |
514 | | * @return |
515 | | * - true if the certificate chain was validated. |
516 | | * - false if the certificate chain failed validation. |
517 | | */ |
518 | | bool fr_tls_verify_cert_result(fr_tls_session_t *tls_session) |
519 | 0 | { |
520 | 0 | bool result; |
521 | |
|
522 | 0 | fr_assert(tls_session->validate.state != FR_TLS_VALIDATION_INIT); |
523 | |
|
524 | 0 | result = tls_session->validate.state == FR_TLS_VALIDATION_SUCCESS; |
525 | |
|
526 | 0 | tls_session->validate.state = FR_TLS_VALIDATION_INIT; |
527 | 0 | tls_session->validate.resumed = false; |
528 | |
|
529 | 0 | return result; |
530 | 0 | } |
531 | | |
532 | | /** Reset the verification state |
533 | | * |
534 | | */ |
535 | | void fr_tls_verify_cert_reset(fr_tls_session_t *tls_session) |
536 | 0 | { |
537 | 0 | tls_session->validate.state = FR_TLS_VALIDATION_INIT; |
538 | 0 | tls_session->validate.resumed = false; |
539 | 0 | } |
540 | | |
541 | | /** Setup a verification request |
542 | | * |
543 | | */ |
544 | | void fr_tls_verify_cert_request(fr_tls_session_t *tls_session, bool session_resumed) |
545 | 0 | { |
546 | 0 | fr_assert(tls_session->validate.state == FR_TLS_VALIDATION_INIT); |
547 | |
|
548 | 0 | tls_session->validate.state = FR_TLS_VALIDATION_REQUESTED; |
549 | 0 | tls_session->validate.resumed = session_resumed; |
550 | 0 | } |
551 | | |
552 | | /** Push a `verify certificate { ... }` section |
553 | | * |
554 | | * @param[in] request The current request. |
555 | | * @param[in] tls_session The current TLS session. |
556 | | * @return |
557 | | * - UNLANG_ACTION_CALCULATE_RESULT - No pending actions |
558 | | * - UNLANG_ACTION_PUSHED_CHILD - Pending operations to evaluate. |
559 | | */ |
560 | | unlang_action_t fr_tls_verify_cert_pending_push(request_t *request, fr_tls_session_t *tls_session) |
561 | 0 | { |
562 | 0 | if (tls_session->validate.state == FR_TLS_VALIDATION_REQUESTED) { |
563 | 0 | return tls_verify_client_cert_push(request, tls_session); |
564 | 0 | } |
565 | | |
566 | 0 | return UNLANG_ACTION_CALCULATE_RESULT; |
567 | 0 | } |
568 | | #endif /* WITH_TLS */ |