28#define LOG_PREFIX "tls"
32#include <freeradius-devel/server/exec.h>
33#include <freeradius-devel/server/pair.h>
34#include <freeradius-devel/tls/log.h>
35#include <freeradius-devel/unlang/function.h>
36#include <freeradius-devel/unlang/subrequest.h>
37#include <freeradius-devel/util/debug.h>
38#include <freeradius-devel/util/strerror.h>
39#include <freeradius-devel/util/syserror.h>
41#include <freeradius-devel/protocol/tls/freeradius.h>
43#include <openssl/x509v3.h>
58static inline CC_HINT(always_inline)
59bool verify_applies(fr_tls_verify_mode_t mode,
int depth,
int untrusted)
61 if (mode == FR_TLS_VERIFY_MODE_ALL)
return true;
62 if (mode == FR_TLS_VERIFY_MODE_DISABLED)
return false;
64 if ((mode & FR_TLS_VERIFY_MODE_LEAF) && (
depth == 0))
return true;
65 if ((mode & FR_TLS_VERIFY_MODE_ISSUER) && (
depth == 1))
return true;
66 if ((mode & FR_TLS_VERIFY_MODE_UNTRUSTED) && (
depth < untrusted))
return true;
76static void tls_verify_error_detail(
request_t *
request, SSL_CTX *ctx,
int err)
78 X509_STORE *
store = SSL_CTX_get_ex_data(ctx, FR_TLS_EX_CTX_INDEX_VERIFY_STORE);
86 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
93 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
94 RDEBUG2(
"(TLS) Static certificates in verification store are");
136int fr_tls_verify_cert_cb(
int ok, X509_STORE_CTX *x509_ctx)
142 fr_tls_session_t *tls_session;
151 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
152 err = X509_STORE_CTX_get_error(x509_ctx);
153 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
154 untrusted = X509_STORE_CTX_get_num_untrusted(x509_ctx);
160 ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
161 ssl_ctx = SSL_get_SSL_CTX(ssl);
162 conf = fr_tls_session_conf(ssl);
163 tls_session = talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TLS_SESSION), fr_tls_session_t);
164 request = fr_tls_session_request(tls_session->ssl);
171 if (!tls_session->can_pause) {
173 "tls_session_async_handshake_cont must be in call stack", __FUNCTION__);
182 X509_STORE_CTX_set_error(x509_ctx, 0);
192 REDEBUG(
"(TLS) Failed to add certificate chain depth pair");
199 STACK_OF(X509) *our_chain;
202 our_chain = X509_STORE_CTX_get0_chain(x509_ctx);
203 RDEBUG3(
"(TLS) Certificate chain - %i cert(s) untrusted", untrusted);
204 for (i = sk_X509_num(our_chain); i > 0 ; i--) {
205 X509 *this_cert = sk_X509_value(our_chain, i - 1);
207 X509_NAME_oneline(X509_get_subject_name(this_cert), subject,
sizeof(subject));
208 subject[
sizeof(subject) - 1] =
'\0';
210 RDEBUG3(
"(TLS) %s [%i] %s", this_cert == cert ?
">" :
" ", i - 1, subject);
220 char const *p = X509_verify_cert_error_string(err);
221 if (!verify_applies(
conf->verify.mode,
depth, untrusted)) {
222 RDEBUG2(
"(TLS) Ignoring verification error - %s (%i)", p, err);
223 tls_verify_error_detail(
request, ssl_ctx, err);
226 X509_STORE_CTX_set_error(x509_ctx, 0);
228 REDEBUG(
"(TLS) Verification error - %s (%i)", p, err);
229 fr_tls_session_error_add(
request, FR_ERROR_VALUE_CERTIFICATE_VERIFY_FAILED);
230 tls_verify_error_detail(
request, ssl_ctx, err);
242 if (my_ok && (
depth == 0)) {
243 bool want_pairs =
conf->verify.attribute_mode != FR_TLS_VERIFY_MODE_DISABLED;
244 bool want_verify =
conf->verify_certificate && tls_session->verify_peer_cert;
246 if (want_pairs || want_verify) {
247 fr_tls_verify_cert_request(tls_session, x509_ctx);
260 X509_STORE_CTX_set_error(x509_ctx, 0);
261 fr_tls_verify_cert_reset(tls_session);
270 if (!fr_tls_verify_cert_result(tls_session)) {
271 REDEBUG(
"(TLS) Certificate validation failed");
273 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_APPLICATION_VERIFICATION);
278 tls_session->peer_cert_ok = (my_ok > 0);
279 RDEBUG2(
"(TLS) [verify] = %s", my_ok ?
"ok" :
"invalid");
304 STACK_OF(X509) *chain;
307 X509_STORE_CTX *store_ctx;
312 cert = SSL_get0_peer_certificate(ssl);
315 ssl_ctx = SSL_get_SSL_CTX(ssl);
316 store_ctx = X509_STORE_CTX_new();
318 REDEBUG(
"(TLS) Failed allocating X509_STORE_CTX");
322 chain = SSL_get_peer_cert_chain(ssl);
323 store = SSL_CTX_get_ex_data(ssl_ctx, FR_TLS_EX_CTX_INDEX_VERIFY_STORE);
341 if (
unlikely(X509_STORE_CTX_init(store_ctx,
store, cert, chain) != 1)) {
342 REDEBUG(
"(TLS) Failed initialising X509_STORE_CTX");
343 X509_STORE_CTX_free(store_ctx);
347 X509_STORE_CTX_set_ex_data(store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), ssl);
348 X509_STORE_CTX_set_verify_cb(store_ctx, fr_tls_verify_cert_cb);
350 verify = X509_verify_cert(store_ctx);
352 err = X509_STORE_CTX_get_error(store_ctx);
354 if (err != X509_V_OK) {
355 REDEBUG(
"(TLS) Failed re-validating resumed session: %s", X509_verify_cert_error_string(err));
356 fr_tls_session_error_add(
request, FR_ERROR_VALUE_CERTIFICATE_REVALIDATION_FAILED);
361 X509_STORE_CTX_free(store_ctx);
371 fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
374 fr_assert(tls_session->validate.state == FR_TLS_VALIDATION_REQUESTED);
378 REDEBUG(
"(TLS) Failed (re-)validating certificates");
379 fr_tls_session_error_add(
request->parent, FR_ERROR_VALUE_VERIFY_CERTIFICATE_FAILED);
393 tls_session->validate.state = FR_TLS_VALIDATION_FAILED;
397 tls_session->validate.state = FR_TLS_VALIDATION_SUCCESS;
399 RDEBUG2(
"(TLS) Certificates (re-)validated");
415 fr_tls_conf_t *
conf = tls_session->conf;
423 &tls_session->session_id));
429 fr_tls_session_extra_pairs_copy_to_child(child, tls_session);
438 if (
conf->verify.der_decode) {
445 vp->vp_bool = tls_session->validate.resumed;
451 ua = fr_tls_call_push(child, tls_verify_peer_cert_result,
conf, tls_session,
false);
453 REDEBUG(
"(TLS) Failed calling TLS virtual server");
470bool fr_tls_verify_cert_result(fr_tls_session_t *tls_session)
474 fr_assert(tls_session->validate.state != FR_TLS_VALIDATION_INIT);
476 result = tls_session->validate.state == FR_TLS_VALIDATION_SUCCESS;
478 tls_session->validate.state = FR_TLS_VALIDATION_INIT;
479 tls_session->validate.resumed =
false;
487void fr_tls_verify_cert_reset(fr_tls_session_t *tls_session)
489 tls_session->validate.state = FR_TLS_VALIDATION_INIT;
490 tls_session->validate.resumed =
false;
491 tls_session->validate.x509_ctx = NULL;
502void fr_tls_verify_cert_request(fr_tls_session_t *tls_session, X509_STORE_CTX *x509_ctx)
504 fr_assert(tls_session->validate.state == FR_TLS_VALIDATION_INIT);
506 tls_session->validate.state = FR_TLS_VALIDATION_REQUESTED;
507 TLS_PENDING_SET(tls_session, FR_TLS_PENDING_VERIFY);
508 tls_session->validate.resumed =
false;
509 tls_session->validate.x509_ctx = x509_ctx;
520void fr_tls_verify_resumed_request(fr_tls_session_t *tls_session)
522 fr_assert(tls_session->validate.state == FR_TLS_VALIDATION_INIT);
524 tls_session->validate.state = FR_TLS_VALIDATION_REQUESTED;
525 TLS_PENDING_SET(tls_session, FR_TLS_PENDING_VERIFY);
526 tls_session->validate.resumed =
true;
527 tls_session->validate.x509_ctx = NULL;
545static int tls_verify_chain_pairs_add(
request_t *
request, fr_tls_session_t *tls_session, fr_tls_conf_t
const *
conf)
547 X509_STORE_CTX *x509_ctx = tls_session->validate.x509_ctx;
548 STACK_OF(X509) *chain = X509_STORE_CTX_get0_chain(x509_ctx);
549 int untrusted = X509_STORE_CTX_get_num_untrusted(x509_ctx);
550 int num = sk_X509_num(chain);
558 X509 *cert = sk_X509_value(chain,
depth);
563 if (!verify_applies(
conf->verify.attribute_mode,
depth, untrusted))
continue;
576 i <= (
unsigned int)
depth;
582#ifdef STATIC_ANALYZER
596 if ((
depth + 1) < num) {
597 issuer = sk_X509_value(chain,
depth + 1);
598 }
else if (X509_check_issued(cert, cert) == X509_V_OK) {
609 if (fr_tls_session_pairs_from_x509_cert(&container->vp_group, container,
610 request, cert, issuer,
conf->verify.der_decode) < 0) {
612 if (
conf->verify.der_decode) {
615 fr_tls_session_error_add(
request, FR_ERROR_VALUE_CERTIFICATE_ATTRIBUTES_FAILED);
640 fr_tls_conf_t *
conf = tls_session->conf;
647 if (!tls_session->validate.resumed) {
648 RDEBUG2(
"(TLS) Decoding certificate chain");
649 if (tls_verify_chain_pairs_add(
request, tls_session,
conf) < 0) {
650 tls_session->validate.state = FR_TLS_VALIDATION_FAILED;
658 if (!
conf->verify_certificate || !tls_session->verify_peer_cert) {
659 tls_session->validate.state = FR_TLS_VALIDATION_SUCCESS;
663 RDEBUG2(
"(TLS) Requesting certificate validation");
665 return tls_verify_peer_cert_push(
request, tls_session);
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
#define store(_store, _var)
static uint8_t request[4]
#define DIAG_OFF_OPTIONAL(_x)
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define DIAG_ON_OPTIONAL(_x)
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
bool unlang_request_is_cancelled(request_t const *request)
Return whether a request has been cancelled.
HIDDEN fr_dict_attr_t const * attr_tls_certificate
Attribute definitions for lib curl.
static fr_dict_attr_t const * attr_module_failure_message
void log_request_pair(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_t const *vp, char const *prefix)
Print a fr_pair_t.
#define REXDENT()
Exdent (unindent) R* messages by one level.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
#define RINDENT()
Indent R* messages by one level.
HIDDEN fr_dict_attr_t const * attr_tls_packet_type
HIDDEN fr_dict_attr_t const * attr_tls_session_resumed
fr_value_box_t const * enum_tls_packet_type_success
HIDDEN fr_dict_attr_t const * attr_der_certificate
fr_value_box_t const * enum_tls_packet_type_verify_certificate
HIDDEN fr_dict_attr_t const * attr_tls_certificate_chain_depth
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
@ L_DBG
Only displayed when debugging is enabled.
static uint8_t depth(fr_minmax_heap_index_t i)
unsigned int fr_pair_count_by_da(fr_pair_list_t const *list, fr_dict_attr_t const *da)
Return the number of instances of a given da in the specified list.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
int fr_pair_delete_by_da(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list.
fr_pair_t * fr_pair_find_by_da_idx(fr_pair_list_t const *list, fr_dict_attr_t const *da, unsigned int idx)
Find a pair with a matching da at a given index.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
int fr_pair_steal_append(TALLOC_CTX *list_ctx, fr_pair_list_t *list, fr_pair_t *vp)
Change a vp's talloc ctx and insert it into a new list.
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
#define RDEBUG_ENABLED2()
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
Stores an attribute, a value and various bits of other data.
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
static int fr_pair_find_or_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)