ATTRIBUTE Packet-Type 1 uint32
-VALUE Packet-Type Cache-Load 1
-VALUE Packet-Type Cache-Store 2
-VALUE Packet-Type Cache-Clear 3
-VALUE Packet-Type Certificate 4
+VALUE Packet-Type Session-Load 1
+VALUE Packet-Type Session-Store 2
+VALUE Packet-Type Session-Clear 3
+VALUE Packet-Type Certificate-Validate 4
+
+#
+# We use response packet types instead of rcodes so that
+# the virtual server can be tested in isolation.
+#
+VALUE Packet-Type success 10
+VALUE Packet-Type failure 11
+VALUE Packet-Type notfound 12
ATTRIBUTE Session-Id 10 octets
ATTRIBUTE Session-Data 11 octets
extern fr_dict_t const *dict_radius;
extern fr_dict_attr_t const *attr_chbind_response_code;
+extern fr_dict_attr_t const *attr_eap_identity;
extern fr_dict_attr_t const *attr_eap_session_id;
extern fr_dict_attr_t const *attr_eap_type;
extern fr_dict_attr_t const *attr_virtual_server;
fr_dict_attr_t const *attr_chbind_response_code;
fr_dict_attr_t const *attr_eap_session_id;
+fr_dict_attr_t const *attr_eap_identity;
fr_dict_attr_t const *attr_eap_type;
fr_dict_attr_t const *attr_virtual_server;
extern fr_dict_attr_autoload_t eap_base_dict_attr[];
fr_dict_attr_autoload_t eap_base_dict_attr[] = {
{ .out = &attr_chbind_response_code, .name = "Chbind-Response-Code", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
+ { .out = &attr_eap_identity, .name = "EAP-Identity", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
{ .out = &attr_eap_session_id, .name = "EAP-Session-Id", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
{ .out = &attr_eap_type, .name = "EAP-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
{ .out = &attr_state, .name = "State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
*/
eap_tls_session->tls_session = tls_session = fr_tls_session_alloc_server(eap_tls_session, ssl_ctx,
request, client_cert);
- if (!tls_session) return NULL;
+ if (unlikely(!tls_session)) return NULL;
+
+ /*
+ * Add the EAP-Identity value to the TLS session so
+ * it's available in all the TLS callbacks.
+ */
+ {
+ fr_pair_t *identity;
+
+ MEM(identity = fr_pair_afrom_da(tls_session, attr_eap_identity));
+ fr_pair_value_bstrdup_buffer(identity, eap_session->identity, true);
+ fr_tls_session_extra_pair_add_shallow(tls_session, identity);
+ }
+
+ /*
+ * Add the EAP-Type we're running to the subrequest.
+ */
+ {
+ fr_pair_t *type_vp;
+
+ MEM(type_vp = fr_pair_afrom_da(tls_session, attr_eap_type));
+ type_vp->vp_uint32 = eap_session->type;
+ fr_tls_session_extra_pair_add_shallow(tls_session, type_vp);
+ }
/*
* Associate various bits of opaque data with the session.
engine.c \
log.c \
ocsp.c \
+ pairs.c \
session.c \
utils.c \
validate.c \
extern fr_dict_attr_t const *attr_framed_mtu;
-extern fr_value_box_t const *enum_tls_packet_type_cache_load;
-extern fr_value_box_t const *enum_tls_packet_type_cache_store;
-extern fr_value_box_t const *enum_tls_packet_type_cache_clear;
-extern fr_value_box_t const *enum_tls_packet_type_certificate;
+extern fr_value_box_t const *enum_tls_packet_type_session_load;
+extern fr_value_box_t const *enum_tls_packet_type_session_store;
+extern fr_value_box_t const *enum_tls_packet_type_session_clear;
+extern fr_value_box_t const *enum_tls_packet_type_certificate_validate;
+
+extern fr_value_box_t const *enum_tls_packet_type_success;
+extern fr_value_box_t const *enum_tls_packet_type_failure;
+extern fr_value_box_t const *enum_tls_packet_type_notfound;
int fr_tls_ocsp_staple_cache_compile(fr_tls_cache_t *sections, CONF_SECTION *server_cs);
-/*
- * tls/validate.c
- */
-int fr_tls_validate_cert_cb(int ok, X509_STORE_CTX *ctx);
-
-int fr_tls_validate_client_cert_chain(SSL *ssl);
-
/*
* tls/utils.c
*/
/*
* tls/virtual_server.c
*/
-unlang_action_t fr_tls_call_push(rlm_rcode_t *p_rcode, request_t *child, unlang_function_t resume,
- request_t *request, fr_tls_conf_t *conf, fr_tls_session_t *tls_session);
+unlang_action_t fr_tls_call_push(request_t *child, unlang_function_t resume,
+ fr_tls_conf_t *conf, fr_tls_session_t *tls_session);
#ifdef __cplusplus
}
{ NULL }
};
-fr_value_box_t const *enum_tls_packet_type_cache_load;
-fr_value_box_t const *enum_tls_packet_type_cache_store;
-fr_value_box_t const *enum_tls_packet_type_cache_clear;
-fr_value_box_t const *enum_tls_packet_type_certificate;
+/*
+ * request types
+ */
+fr_value_box_t const *enum_tls_packet_type_session_load;
+fr_value_box_t const *enum_tls_packet_type_session_store;
+fr_value_box_t const *enum_tls_packet_type_session_clear;
+fr_value_box_t const *enum_tls_packet_type_certificate_validate;
+
+/*
+ * response types
+ */
+fr_value_box_t const *enum_tls_packet_type_success;
+fr_value_box_t const *enum_tls_packet_type_failure;
+fr_value_box_t const *enum_tls_packet_type_notfound;
extern fr_dict_enum_autoload_t tls_dict_enum[];
fr_dict_enum_autoload_t tls_dict_enum[] = {
- { .out = &enum_tls_packet_type_cache_load, .name = "Cache-Load", .attr = &attr_tls_packet_type },
- { .out = &enum_tls_packet_type_cache_store, .name = "Cache-Store", .attr = &attr_tls_packet_type },
- { .out = &enum_tls_packet_type_cache_clear, .name = "Cache-Clear", .attr = &attr_tls_packet_type },
- { .out = &enum_tls_packet_type_certificate, .name = "Certificate", .attr = &attr_tls_packet_type },
+ { .out = &enum_tls_packet_type_session_load, .name = "Session-Load", .attr = &attr_tls_packet_type },
+ { .out = &enum_tls_packet_type_session_store, .name = "Session-Store", .attr = &attr_tls_packet_type },
+ { .out = &enum_tls_packet_type_session_clear, .name = "Session-Clear", .attr = &attr_tls_packet_type },
+ { .out = &enum_tls_packet_type_certificate_validate, .name = "Certificate-Validate", .attr = &attr_tls_packet_type },
+
+ { .out = &enum_tls_packet_type_success, .name = "Success", .attr = &attr_tls_packet_type },
+ { .out = &enum_tls_packet_type_failure, .name = "Failure", .attr = &attr_tls_packet_type },
+ { .out = &enum_tls_packet_type_notfound, .name = "Notfound", .attr = &attr_tls_packet_type },
{ NULL }
};
* @brief Functions to support TLS session resumption
*
* @copyright 2015-2016 The FreeRADIUS server project
+ * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
*/
RCSID("$Id$")
USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
#include "cache.h"
#include "log.h"
#include "missing.h"
+#include "validate.h"
/** Retrieve session ID (in binary form) from the session
*
cache->clear.state = FR_TLS_CACHE_CLEAR_INIT;
}
-/** Process the result of `cache store { ... }`
+/** Process the result of `session load { ... }`
+ */
+static unlang_action_t tls_cache_load_result(UNUSED rlm_rcode_t *p_result, UNUSED int *priority,
+ request_t *request, void *uctx)
+{
+ fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
+ fr_tls_cache_t *tls_cache = tls_session->cache;
+ fr_pair_t *vp;
+ uint8_t const *q, **p;
+ SSL_SESSION *sess;
+
+ vp = fr_pair_find_by_da(&request->reply_pairs, attr_tls_packet_type, 0);
+ if (!vp || (vp->vp_uint32 != enum_tls_packet_type_success->vb_uint32)) {
+ RWDEBUG("Failed acquiring session data");
+ error:
+ tls_cache->load.state = FR_TLS_CACHE_LOAD_FAILED;
+ return UNLANG_ACTION_CALCULATE_RESULT;
+ }
+
+ vp = fr_pair_find_by_da(&request->session_state_pairs, attr_tls_session_data, 0);
+ if (!vp) {
+ RWDEBUG("No cached session found");
+ goto error;
+ }
+
+ q = vp->vp_octets; /* openssl will mutate q, so we can't use vp_octets directly */
+ p = (unsigned char const **)&q;
+
+ sess = d2i_SSL_SESSION(NULL, p, vp->vp_length);
+ if (!sess) {
+ fr_tls_log_error(request, "Failed loading persisted session");
+ goto error;
+ }
+ RDEBUG3("Read %zu bytes of session data. Session deserialized successfully", vp->vp_length);
+
+ /*
+ * OpenSSL's API is very inconsistent.
+ *
+ * We need to set external data here, so it can be
+ * retrieved in fr_tls_cache_delete.
+ *
+ * ex_data is not serialised in i2d_SSL_SESSION
+ * so we don't have to bother unsetting it.
+ */
+ SSL_SESSION_set_ex_data(sess, FR_TLS_EX_INDEX_TLS_SESSION,
+ SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION));
+
+ tls_cache->load.state = FR_TLS_CACHE_LOAD_RETRIEVED;
+ tls_cache->load.sess = sess; /* This is consumed in tls_cache_load_cb */
+
+#if 0
+ /*
+ * We set the session here temporarily so that
+ * the certificate validation can run.
+ *
+ * FIXME - Do ASYNC session cert validation.
+ */
+ SSL_set_session(ssl, sess); /* Increases ref count */
+
+ if (fr_tls_validate_client_cert_chain(ssl) != 1) {
+ RWDEBUG("Validation failed, forcefully expiring resumed session");
+ SSL_SESSION_set_timeout(sess, 0);
+ }
+
+ SSL_remove_session(ssl, sess); /* Decreases ref count */
+#endif
+
+ return UNLANG_ACTION_CALCULATE_RESULT;
+}
+
+/** Push a `session load { ... }` call into the current request, using a subrequest
+ *
+ * @param[in] request The current request.
+ * @Param[in] tls_session The current TLS session.
+ * @return
+ * - UNLANG_ACTION_CALCULATE_RESULT on noop.
+ * - UNLANG_ACTION_PUSHED_CHILD on success.
+ * - UNLANG_ACTION_FAIL on failure.
+ */
+static unlang_action_t tls_cache_load_push(request_t *request, fr_tls_session_t *tls_session)
+{
+ fr_tls_cache_t *tls_cache = tls_session->cache;
+ fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl);
+ request_t *child;
+ fr_pair_t *vp;
+
+ if (tls_cache->load.state != FR_TLS_CACHE_LOAD_REQUESTED) return UNLANG_ACTION_CALCULATE_RESULT;
+
+ fr_assert(tls_cache->load.id);
+
+ MEM(child = unlang_subrequest_alloc(request, dict_tls));
+ request = child;
+
+ /*
+ * Setup the child request for loading
+ * session resumption data.
+ */
+ MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0);
+ vp->vp_uint32 = enum_tls_packet_type_session_load->vb_uint32;
+
+ /*
+ * Add the session identifier we're
+ * trying to load.
+ */
+ tls_cache_session_id_to_vp(child, tls_cache->load.id);
+
+ /*
+ * Allocate a child, and set it up to call
+ * the TLS virtual server.
+ */
+ if (fr_tls_call_push(child, tls_cache_load_result, conf, tls_session) < 0) {
+ talloc_free(child);
+ tls_cache_load_state_reset(tls_cache);
+ return UNLANG_ACTION_FAIL;
+ }
+
+ return UNLANG_ACTION_CALCULATE_RESULT;
+}
+
+/** Process the result of `session store { ... }`
*/
static unlang_action_t tls_cache_store_result(UNUSED rlm_rcode_t *p_result, UNUSED int *priority,
request_t *request, void *uctx)
{
fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
fr_tls_cache_t *tls_cache = tls_session->cache;
+ fr_pair_t *vp;
tls_cache_store_state_reset(tls_cache);
- switch (tls_cache->store.rcode) {
- case RLM_MODULE_OK:
- case RLM_MODULE_UPDATED:
+ vp = fr_pair_find_by_da(&request->reply_pairs, attr_tls_packet_type, 0);
+ if (vp && (vp->vp_uint32 == enum_tls_packet_type_success->vb_uint32)) {
tls_cache->store.state = FR_TLS_CACHE_STORE_PERSISTED; /* Avoid spurious clear calls */
- break;
-
- default: /* Every other rcode indicates the cache store ailed */
+ } else {
RWDEBUG("Failed storing session data");
tls_cache->store.state = FR_TLS_CACHE_STORE_INIT;
- break;
}
return UNLANG_ACTION_CALCULATE_RESULT;
}
-/** Push a `cache store { ... }` call into the current request, using a subrequest
+/** Push a `session store { ... }` call into the current request, using a subrequest
*
* @param[in] request The current request.
* @param[in] conf TLS configuration.
* session resumption data.
*/
MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0);
- vp->vp_uint32 = enum_tls_packet_type_cache_store->vb_uint32;
+ vp->vp_uint32 = enum_tls_packet_type_session_store->vb_uint32;
/*
* Add the session identifier we're trying
* Allocate a child, and set it up to call
* the TLS virtual server.
*/
- if (fr_tls_call_push(&tls_cache->store.rcode, child, tls_cache_store_result,
- request, conf, tls_session) < 0) goto error;
+ if (fr_tls_call_push(child, tls_cache_store_result, conf, tls_session) < 0) goto error;
return UNLANG_ACTION_PUSHED_CHILD;
}
-/** Process the result of `cache clear { ... }`
+/** Process the result of `session clear { ... }`
*/
static unlang_action_t tls_cache_clear_result(UNUSED rlm_rcode_t *p_result, UNUSED int *priority,
request_t *request, void *uctx)
{
fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
fr_tls_cache_t *tls_cache = tls_session->cache;
+ fr_pair_t *vp;
tls_cache_clear_state_reset(tls_cache);
- switch (tls_cache->clear.rcode) {
- case RLM_MODULE_OK:
- case RLM_MODULE_UPDATED:
- case RLM_MODULE_NOTFOUND:
- case RLM_MODULE_NOOP:
- return UNLANG_ACTION_CALCULATE_RESULT;
-
- default:
- RWDEBUG("Failed deleting session data - security may be compromised");
+ vp = fr_pair_find_by_da(&request->reply_pairs, attr_tls_packet_type, 0);
+ if (vp &&
+ ((vp->vp_uint32 == enum_tls_packet_type_success->vb_uint32) ||
+ (vp->vp_uint32 == enum_tls_packet_type_notfound->vb_uint32))) {
return UNLANG_ACTION_CALCULATE_RESULT;
}
+
+ RWDEBUG("Failed deleting session data - security may be compromised");
+ return UNLANG_ACTION_CALCULATE_RESULT;
}
-/** Push a `cache clear { ... }` call into the current request, using a subrequest
+/** Push a `session clear { ... }` call into the current request, using a subrequest
*
* @param[in] request The current request.
* @param[in] conf TLS configuration.
* session resumption data.
*/
MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0);
- vp->vp_uint32 = enum_tls_packet_type_cache_clear->vb_uint32;
+ vp->vp_uint32 = enum_tls_packet_type_session_clear->vb_uint32;
/*
* Add the session identifier we're
* Allocate a child, and set it up to call
* the TLS virtual server.
*/
- if (fr_tls_call_push(&tls_cache->clear.rcode, child, tls_cache_clear_result,
- request, conf, tls_session) < 0) {
+ if (fr_tls_call_push(child, tls_cache_clear_result, conf, tls_session) < 0) {
talloc_free(child);
tls_cache_clear_state_reset(tls_cache);
return UNLANG_ACTION_FAIL;
return UNLANG_ACTION_CALCULATE_RESULT;
}
-/** Push a `cache clear { ... }` or `cache load { ... }` depending on what operations are pending
+/** Push a `session store { ... }` or session clear { ... }` or `session load { ... }` depending on what operations are pending
*
* @param[in] request The current request.
* @Param[in] tls_session The current TLS session.
* @return
- * - 1 on noop.
- * - 0 on success.
- * - -1 on failure.
+ * - UNLANG_ACTION_CALCULATE_RESULT - No pending actions
+ * - UNLANG_ACTION_PUSHED_CHILD - Pending operations to evaluate.
*/
-int fr_tls_cache_pending_push(request_t *request, fr_tls_session_t *tls_session)
+unlang_action_t fr_tls_cache_pending_push(request_t *request, fr_tls_session_t *tls_session)
{
fr_tls_cache_t *tls_cache = tls_session->cache;
fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl);
- if (!tls_cache) return 1; /* No caching allowed */
+ if (!tls_cache) return UNLANG_ACTION_CALCULATE_RESULT; /* No caching allowed */
+
+ /*
+ * Load stateful session data
+ */
+ if (tls_cache->load.state == FR_TLS_CACHE_LOAD_REQUESTED) {
+ return tls_cache_load_push(request, tls_session);
+ }
/*
* We only support a single session
return tls_cache_store_push(request, conf, tls_session);
}
- return 1;
-}
-
-/** Process the result of `cache load { ... }`
- */
-static unlang_action_t tls_cache_load_result(UNUSED rlm_rcode_t *p_result, UNUSED int *priority,
- request_t *request, void *uctx)
-{
- fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
- fr_tls_cache_t *tls_cache = tls_session->cache;
- fr_pair_t *vp;
- uint8_t const *q, **p;
- SSL_SESSION *sess;
-
- switch (tls_cache->load.rcode) {
- case RLM_MODULE_OK:
- case RLM_MODULE_UPDATED:
- break;
-
- default: /* Every other rcode indicates the cache load failed */
- RWDEBUG("Failed acquiring session data");
- error:
- tls_cache->load.state = FR_TLS_CACHE_LOAD_FAILED;
- return UNLANG_ACTION_CALCULATE_RESULT;
- }
-
- vp = fr_pair_find_by_da(&request->session_state_pairs, attr_tls_session_data, 0);
- if (!vp) {
- RWDEBUG("No cached session found");
- goto error;
- }
-
- q = vp->vp_octets; /* openssl will mutate q, so we can't use vp_octets directly */
- p = (unsigned char const **)&q;
-
- sess = d2i_SSL_SESSION(NULL, p, vp->vp_length);
- if (!sess) {
- fr_tls_log_error(request, "Failed loading persisted session");
- goto error;
- }
- RDEBUG3("Read %zu bytes of session data. Session deserialized successfully", vp->vp_length);
-
- /*
- * OpenSSL's API is very inconsistent.
- *
- * We need to set external data here, so it can be
- * retrieved in fr_tls_cache_delete.
- *
- * ex_data is not serialised in i2d_SSL_SESSION
- * so we don't have to bother unsetting it.
- */
- SSL_SESSION_set_ex_data(sess, FR_TLS_EX_INDEX_TLS_SESSION,
- SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION));
-
- tls_cache->load.state = FR_TLS_CACHE_LOAD_RETRIEVED;
- tls_cache->load.sess = sess; /* This is consumed in tls_cache_load_cb */
-
-#if 0
- /*
- * We set the session here temporarily so that
- * the certificate validation can run.
- *
- * FIXME - Do ASYNC session cert validation.
- */
- SSL_set_session(ssl, sess); /* Increases ref count */
-
- if (fr_tls_validate_client_cert_chain(ssl) != 1) {
- RWDEBUG("Validation failed, forcefully expiring resumed session");
- SSL_SESSION_set_timeout(sess, 0);
- }
-
- SSL_remove_session(ssl, sess); /* Decreases ref count */
-#endif
-
- return UNLANG_ACTION_CALCULATE_RESULT;
-}
-
-/** Push a `cache load { ... }` call into the current request, using a subrequest
- *
- * @param[in] request The current request.
- * @Param[in] tls_session The current TLS session.
- * @return
- * - UNLANG_ACTION_CALCULATE_RESULT on noop.
- * - UNLANG_ACTION_PUSHED_CHILD on success.
- * - UNLANG_ACTION_FAIL on failure.
- */
-unlang_action_t fr_tls_cache_load_push(request_t *request, fr_tls_session_t *tls_session)
-{
- fr_tls_cache_t *tls_cache = tls_session->cache;
- fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl);
- request_t *child;
- fr_pair_t *vp;
-
- if (tls_cache->load.state != FR_TLS_CACHE_LOAD_REQUESTED) return UNLANG_ACTION_CALCULATE_RESULT;
-
- fr_assert(tls_cache->load.id);
-
- MEM(child = unlang_subrequest_alloc(request, dict_tls));
- request = child;
-
- /*
- * Setup the child request for loading
- * session resumption data.
- */
- MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0);
- vp->vp_uint32 = enum_tls_packet_type_cache_load->vb_uint32;
-
- /*
- * Add the session identifier we're
- * trying to load.
- */
- tls_cache_session_id_to_vp(child, tls_cache->load.id);
-
- /*
- * Allocate a child, and set it up to call
- * the TLS virtual server.
- */
- if (fr_tls_call_push(&tls_cache->load.rcode, child, tls_cache_load_result,
- request, conf, tls_session) < 0) {
- talloc_free(child);
- tls_cache_load_state_reset(tls_cache);
- return UNLANG_ACTION_FAIL;
- }
-
return UNLANG_ACTION_CALCULATE_RESULT;
}
* load session information from a datastore and associated
* it with the SSL session.
* 3. We asynchronously validate the certificate information
- * retrieved during the session cache load.
+ * retrieved during the session session load.
* 3. We call SSL_read() again, which in turn calls this callback
* again.
*/
return 1;
}
- RDEBUG2("Session-resumption enabled");
+ RDEBUG2("Allowing future session-resumption");
return 0;
}
void *arg)
{
fr_tls_session_t *tls_session = fr_tls_session(ssl);
+ fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl);
fr_tls_cache_conf_t *tls_cache_conf = arg; /* Not talloced */
request_t *request = NULL;
uint8_t *data;
if (!tls_session->allow_session_resumption ||
(!(tls_cache_conf->mode & FR_TLS_CACHE_STATELESS))) {
ROPTIONAL(RDEBUG2, DEBUG2, "Session resumption not enabled for this TLS session, "
- "denying session resumption");
+ "denying session resumption via session-ticket");
return SSL_TICKET_RETURN_IGNORE;
}
*/
if (SSL_SESSION_get0_ticket_appdata(sess, (void **)&data, &data_len) != 1) {
fr_tls_log_error(request, "Failed retrieving application data from session-ticket, "
- "denying session resumption");
+ "denying session resumption via session-ticket");
return SSL_TICKET_RETURN_IGNORE_RENEW;
}
if (fr_internal_decode_pair_dbuff(request->session_state_ctx, &cursor,
request->dict, &dbuff, NULL) < 0) {
fr_pair_list_free(&tmp);
- RPEDEBUG("Failed decoding session-state, denying session resumption");
+ RPEDEBUG("Failed decoding session-state, denying session resumption via session-ticket");
return SSL_TICKET_RETURN_IGNORE_RENEW;
}
}
fr_pair_list_append(&request->session_state_pairs, &tmp);
- /*
- * TODO - Run TLS certificate recv { ... } section
- */
+ if (conf->virtual_server && tls_session->verify_client_cert) {
+ RDEBUG2("Requesting certificate re-validation for session-ticket");
+ /*
+ * This sets the validation state of the tls_session
+ * so that when we call ASYNC_pause_job(), and execution
+ * jumps back to tls_session_async_handshake_cont
+ * (just under SSL_read())
+ * the code there knows what job it needs to push onto
+ * the unlang stack.
+ */
+ fr_tls_validate_client_cert_request(tls_session);
+
+ ASYNC_pause_job();
+
+ /*
+ * If we couldn't validate the client certificate
+ * give the client the opportunity to send a new
+ * one, but _don't_ allow session resumption.
+ */
+ if (!fr_tls_validate_client_cert_success(tls_session)) {
+ RDEBUG2("Certificate re-validation failed, denying session resumption via session-ticket");
+ return SSL_TICKET_RETURN_IGNORE_RENEW;
+ }
+ }
return (status == SSL_TICKET_SUCCESS_RENEW) ? SSL_TICKET_RETURN_USE_RENEW : SSL_TICKET_RETURN_USE;
}
struct {
fr_tls_cache_store_state_t state; //!< Tracks store state.
SSL_SESSION *sess; //!< Session to store.
- rlm_rcode_t rcode; //!< Result of calling `cache store { ... }`.
} store;
struct {
fr_tls_cache_load_state_t state; //!< Tracks load requests from OpenSSL.
uint8_t *id; //!< Session ID to load.
SSL_SESSION *sess; //!< Deserialized session.
- rlm_rcode_t rcode; //!< Result of calling `cache load { ... }`.
} load;
struct {
fr_tls_cache_clear_state_t state; //!< Tracks delete requests from OpenSSL.
uint8_t *id; //!< Session ID to be deleted.
- rlm_rcode_t rcode; //!< Result of calling `cache clear { ... }`.
} clear;
} fr_tls_cache_t;
unlang_action_t fr_tls_cache_pending_push(request_t *request, fr_tls_session_t *tls_session);
-unlang_action_t fr_tls_cache_load_push(request_t *request, fr_tls_session_t *tls_session);
-
void fr_tls_cache_deny(fr_tls_session_t *tls_session);
int fr_tls_cache_disable_cb(SSL *ssl, int is_forward_secure);
uint32_t lifetime; //!< The maximum period a session can be resumed after.
- bool verify; //!< Revalidate any sessions read in from the cache.
-
bool require_extms; //!< Only allow session resumption if the client/server
//!< supports the extended master session key. This protects
//!< against the triple handshake attack.
{ FR_CONF_OFFSET("name", FR_TYPE_TMPL, fr_tls_cache_conf_t, id_name),
.dflt = "%{EAP-Type}%{Virtual-Server}", .quote = T_DOUBLE_QUOTED_STRING },
{ FR_CONF_OFFSET("lifetime", FR_TYPE_UINT32, fr_tls_cache_conf_t, lifetime), .dflt = "86400" },
- { FR_CONF_OFFSET("verify", FR_TYPE_BOOL, fr_tls_cache_conf_t, verify), .dflt = "no" },
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
{ FR_CONF_OFFSET("require_extended_master_secret", FR_TYPE_BOOL, fr_tls_cache_conf_t, require_extms), .dflt = "no" },
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file tls/pairs.c
+ * @brief Functions to convert certificate OIDs to attribute pairs
+ *
+ * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ */
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#ifdef WITH_TLS
+#define LOG_PREFIX "tls - "
+
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+
+#include <freeradius-devel/util/pair.h>
+#include <freeradius-devel/server/request.h>
+
+#include "attrs.h"
+#include "base.h"
+#include "session.h"
+
+/*
+ * For creating certificate attributes.
+ */
+static fr_dict_attr_t const **cert_attr_names[][2] = {
+ { &attr_tls_client_cert_common_name, &attr_tls_cert_common_name },
+ { &attr_tls_client_cert_expiration, &attr_tls_cert_expiration },
+ { &attr_tls_client_cert_issuer, &attr_tls_cert_issuer },
+ { &attr_tls_client_cert_serial, &attr_tls_cert_serial },
+ { &attr_tls_client_cert_subject, &attr_tls_cert_subject },
+ { &attr_tls_client_cert_subject_alt_name_dns, &attr_tls_cert_subject_alt_name_dns },
+ { &attr_tls_client_cert_subject_alt_name_email, &attr_tls_cert_subject_alt_name_email },
+ { &attr_tls_client_cert_subject_alt_name_upn, &attr_tls_cert_subject_alt_name_upn }
+};
+
+#define IDX_COMMON_NAME (0)
+#define IDX_EXPIRATION (1)
+#define IDX_ISSUER (2)
+#define IDX_SERIAL (3)
+#define IDX_SUBJECT (4)
+#define IDX_SUBJECT_ALT_NAME_DNS (5)
+#define IDX_SUBJECT_ALT_NAME_EMAIL (6)
+#define IDX_SUBJECT_ALT_NAME_UPN (7)
+
+static inline CC_HINT(always_inline)
+fr_pair_t *fr_tls_session_cert_attr_add(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *pair_list,
+ int attr, int attr_index, char const *value)
+{
+ fr_pair_t *vp;
+ fr_dict_attr_t const *da = *(cert_attr_names[attr][attr_index]);
+
+ MEM(vp = fr_pair_afrom_da(ctx, da));
+ if (value) {
+ if (fr_pair_value_from_str(vp, value, -1, '\0', true) < 0) {
+ RPWDEBUG("Failed creating attribute %s", da->name);
+ talloc_free(vp);
+ return NULL;
+ }
+ }
+ RINDENT();
+ RDEBUG3("%pP", vp);
+ REXDENT();
+ fr_pair_append(pair_list, vp);
+
+ return vp;
+}
+
+DIAG_OFF(DIAG_UNKNOWN_PRAGMAS)
+DIAG_OFF(used-but-marked-unused) /* fix spurious warnings for sk macros */
+/** Extract attributes from an X509 certificate
+ *
+ * @param[out] pair_list to copy attributes to.
+ * @param[in] ctx to allocate attributes in.
+ * @param[in] tls_session current TLS session.
+ * @param[in] cert to validate.
+ * @param[in] depth the certificate is in the certificate chain (0 == leaf).
+ * @return
+ * - 0 on success.
+ * - < 0 on failure.
+ */
+int fr_tls_session_pairs_from_x509_cert(fr_pair_list_t *pair_list, TALLOC_CTX *ctx,
+ fr_tls_session_t *tls_session, X509 *cert, int depth)
+{
+ char buffer[2048];
+ char attribute[256];
+ char **identity;
+ int attr_index, loc;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ STACK_OF(X509_EXTENSION) const *ext_list = NULL;
+#else
+ STACK_OF(X509_EXTENSION) *ext_list = NULL;
+#endif
+
+ ASN1_INTEGER *sn = NULL;
+ ASN1_TIME *asn_time = NULL;
+
+ fr_pair_t *vp = NULL;
+
+ request_t *request;
+
+#define CERT_ATTR_ADD(_attr, _attr_index, _value) fr_tls_session_cert_attr_add(ctx, request, pair_list, _attr, _attr_index, _value)
+
+ attr_index = depth;
+ if (attr_index > 1) attr_index = 1;
+
+ request = fr_tls_session_request(tls_session->ssl);
+ identity = (char **)SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_IDENTITY);
+
+ if (RDEBUG_ENABLED3) {
+ buffer[0] = '\0';
+ X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer));
+ buffer[sizeof(buffer) - 1] = '\0';
+ RDEBUG3("Creating attributes for \"%s\":", buffer[0] ? buffer : "Cert missing subject OID");
+ }
+
+ /*
+ * Get the Serial Number
+ */
+ sn = X509_get_serialNumber(cert);
+ if (sn && ((size_t) sn->length < (sizeof(buffer) / 2))) {
+ char *p = buffer;
+ int i;
+
+ for (i = 0; i < sn->length; i++) {
+ sprintf(p, "%02x", (unsigned int)sn->data[i]);
+ p += 2;
+ }
+
+ CERT_ATTR_ADD(IDX_SERIAL, attr_index, buffer);
+ }
+
+ /*
+ * Get the Expiration Date
+ */
+ buffer[0] = '\0';
+ asn_time = X509_get_notAfter(cert);
+ if (identity && asn_time && (asn_time->length < (int)sizeof(buffer))) {
+ time_t expires;
+
+ /*
+ * Add expiration as a time since the epoch
+ */
+ if (fr_tls_utils_asn1time_to_epoch(&expires, asn_time) < 0) {
+ RPWDEBUG("Failed parsing certificate expiry time");
+ } else {
+ vp = CERT_ATTR_ADD(IDX_EXPIRATION, attr_index, NULL);
+ vp->vp_date = fr_unix_time_from_sec(expires);
+ }
+ }
+
+ /*
+ * Get the Subject & Issuer
+ */
+ buffer[0] = '\0';
+ X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer));
+ buffer[sizeof(buffer) - 1] = '\0';
+ if (identity && buffer[0]) {
+ CERT_ATTR_ADD(IDX_SUBJECT, attr_index, buffer);
+
+ /*
+ * Get the Common Name, if there is a subject.
+ */
+ X509_NAME_get_text_by_NID(X509_get_subject_name(cert),
+ NID_commonName, buffer, sizeof(buffer));
+ buffer[sizeof(buffer) - 1] = '\0';
+
+ if (buffer[0]) {
+ CERT_ATTR_ADD(IDX_COMMON_NAME, attr_index, buffer);
+ }
+ }
+
+ X509_NAME_oneline(X509_get_issuer_name(cert), buffer, sizeof(buffer));
+ buffer[sizeof(buffer) - 1] = '\0';
+ if (identity && buffer[0]) {
+ CERT_ATTR_ADD(IDX_ISSUER, attr_index, buffer);
+ }
+
+ /*
+ * Get the RFC822 Subject Alternative Name
+ */
+ loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, 0);
+ if (loc >= 0) {
+ X509_EXTENSION *ext = NULL;
+ GENERAL_NAMES *names = NULL;
+ int i;
+
+ ext = X509_get_ext(cert, loc);
+ if (ext && (names = X509V3_EXT_d2i(ext))) {
+ for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
+ GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
+
+ switch (name->type) {
+#ifdef GEN_EMAIL
+ case GEN_EMAIL: {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ char const *rfc822Name = (char const *)ASN1_STRING_get0_data(name->d.rfc822Name);
+#else
+ char *rfc822Name = (char *)ASN1_STRING_data(name->d.rfc822Name);
+#endif
+
+ CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_EMAIL, attr_index, rfc822Name);
+ break;
+ }
+#endif /* GEN_EMAIL */
+#ifdef GEN_DNS
+ case GEN_DNS: {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ char const *dNSName = (char const *)ASN1_STRING_get0_data(name->d.dNSName);
+#else
+ char *dNSName = (char *)ASN1_STRING_data(name->d.dNSName);
+#endif
+ CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_DNS, attr_index, dNSName);
+ break;
+ }
+#endif /* GEN_DNS */
+#ifdef GEN_OTHERNAME
+ case GEN_OTHERNAME:
+ /* look for a MS UPN */
+ if (NID_ms_upn != OBJ_obj2nid(name->d.otherName->type_id)) break;
+
+ /* we've got a UPN - Must be ASN1-encoded UTF8 string */
+ if (name->d.otherName->value->type == V_ASN1_UTF8STRING) {
+ CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_UPN, attr_index,
+ (char *)name->d.otherName->value->value.utf8string);
+ break;
+ }
+
+ RWARN("Invalid UPN in Subject Alt Name (should be UTF-8)");
+ break;
+#endif /* GEN_OTHERNAME */
+ default:
+ /* XXX TODO handle other SAN types */
+ break;
+ }
+ }
+ }
+ if (names != NULL) GENERAL_NAMES_free(names);
+ }
+
+ /*
+ * Only add extensions for the actual client certificate
+ */
+ if (attr_index == 0) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ ext_list = X509_get0_extensions(cert);
+#else
+ ext_list = cert->cert_info->extensions;
+#endif
+
+ /*
+ * Grab the X509 extensions, and create attributes out of them.
+ * For laziness, we re-use the OpenSSL names
+ */
+ if (sk_X509_EXTENSION_num(ext_list) > 0) {
+ int i, len;
+ char *p;
+ BIO *out;
+
+ MEM(out = BIO_new(BIO_s_mem()));
+ strlcpy(attribute, "TLS-Client-Cert-", sizeof(attribute));
+
+ for (i = 0; i < sk_X509_EXTENSION_num(ext_list); i++) {
+ char value[1024];
+ ASN1_OBJECT *obj;
+ X509_EXTENSION *ext;
+ fr_dict_attr_t const *da;
+
+ ext = sk_X509_EXTENSION_value(ext_list, i);
+
+ obj = X509_EXTENSION_get_object(ext);
+ if (i2a_ASN1_OBJECT(out, obj) <= 0) {
+ RPWDEBUG("Skipping X509 Extension (%i) conversion to attribute. "
+ "Conversion from ASN1 failed...", i);
+ continue;
+ }
+
+ len = BIO_read(out, attribute + 16 , sizeof(attribute) - 16 - 1);
+ if (len <= 0) continue;
+
+ attribute[16 + len] = '\0';
+
+ for (p = attribute + 16; *p != '\0'; p++) if (*p == ' ') *p = '-';
+
+ X509V3_EXT_print(out, ext, 0, 0);
+ len = BIO_read(out, value , sizeof(value) - 1);
+ if (len <= 0) continue;
+
+ value[len] = '\0';
+
+ da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), attribute);
+ if (!da) {
+ RWDEBUG3("Skipping attribute %s: "
+ "Add dictionary definition if you want to access it", attribute);
+ continue;
+ }
+
+ MEM(vp = fr_pair_afrom_da(ctx, da));
+ if (fr_pair_value_from_str(vp, value, -1, '\0', true) < 0) {
+ RPWDEBUG3("Skipping: %s += '%s'", attribute, value);
+ talloc_free(vp);
+ continue;
+ }
+
+ fr_pair_append(pair_list, vp);
+ }
+ BIO_free_all(out);
+ }
+ }
+
+ return 0;
+}
+DIAG_ON(used-but-marked-unused)
+DIAG_ON(DIAG_UNKNOWN_PRAGMAS)
+#endif
#include "log.h"
#include "missing.h"
-/*
- * For creating certificate attributes.
- */
-static fr_dict_attr_t const **cert_attr_names[][2] = {
- { &attr_tls_client_cert_common_name, &attr_tls_cert_common_name },
- { &attr_tls_client_cert_expiration, &attr_tls_cert_expiration },
- { &attr_tls_client_cert_issuer, &attr_tls_cert_issuer },
- { &attr_tls_client_cert_serial, &attr_tls_cert_serial },
- { &attr_tls_client_cert_subject, &attr_tls_cert_subject },
- { &attr_tls_client_cert_subject_alt_name_dns, &attr_tls_cert_subject_alt_name_dns },
- { &attr_tls_client_cert_subject_alt_name_email, &attr_tls_cert_subject_alt_name_email },
- { &attr_tls_client_cert_subject_alt_name_upn, &attr_tls_cert_subject_alt_name_upn }
-};
-
-#define IDX_COMMON_NAME (0)
-#define IDX_EXPIRATION (1)
-#define IDX_ISSUER (2)
-#define IDX_SERIAL (3)
-#define IDX_SUBJECT (4)
-#define IDX_SUBJECT_ALT_NAME_DNS (5)
-#define IDX_SUBJECT_ALT_NAME_EMAIL (6)
-#define IDX_SUBJECT_ALT_NAME_UPN (7)
-
static char const *tls_version_str[] = {
[SSL2_VERSION] = "SSL 2.0",
[SSL3_VERSION] = "SSL 3.0",
{
size_t psk_len = 0;
fr_tls_conf_t *conf;
- request_t *request;
+ request_t *request;
conf = (fr_tls_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
if (!conf) return 0;
#endif
}
-static inline CC_HINT(always_inline)
-fr_pair_t *fr_tls_session_cert_attr_add(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *pair_list,
- int attr, int attr_index, char const *value)
-{
- fr_pair_t *vp;
- fr_dict_attr_t const *da = *(cert_attr_names[attr][attr_index]);
-
- MEM(vp = fr_pair_afrom_da(ctx, da));
- if (value) {
- if (fr_pair_value_from_str(vp, value, -1, '\0', true) < 0) {
- RPWDEBUG("Failed creating attribute %s", da->name);
- talloc_free(vp);
- return NULL;
- }
- }
- RINDENT();
- RDEBUG3("%pP", vp);
- REXDENT();
- fr_pair_append(pair_list, vp);
-
- return vp;
-}
-
-DIAG_OFF(DIAG_UNKNOWN_PRAGMAS)
-DIAG_OFF(used-but-marked-unused) /* fix spurious warnings for sk macros */
-/** Extract attributes from an X509 certificate
- *
- * @param[out] pair_list to copy attributes to.
- * @param[in] ctx to allocate attributes in.
- * @param[in] tls_session current TLS session.
- * @param[in] cert to validate.
- * @param[in] depth the certificate is in the certificate chain (0 == leaf).
- * @return
- * - 0 on success.
- * - < 0 on failure.
- */
-int fr_tls_session_pairs_from_x509_cert(fr_pair_list_t *pair_list, TALLOC_CTX *ctx,
- fr_tls_session_t *tls_session, X509 *cert, int depth)
-{
- char buffer[1024];
- char attribute[256];
- char **identity;
- int attr_index, loc;
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- STACK_OF(X509_EXTENSION) const *ext_list = NULL;
-#else
- STACK_OF(X509_EXTENSION) *ext_list = NULL;
-#endif
-
- ASN1_INTEGER *sn = NULL;
- ASN1_TIME *asn_time = NULL;
-
- fr_pair_t *vp = NULL;
-
- request_t *request;
-
-#define CERT_ATTR_ADD(_attr, _attr_index, _value) fr_tls_session_cert_attr_add(ctx, request, pair_list, _attr, _attr_index, _value)
-
- attr_index = depth;
- if (attr_index > 1) attr_index = 1;
-
- request = fr_tls_session_request(tls_session->ssl);
- identity = (char **)SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_IDENTITY);
-
- if (RDEBUG_ENABLED3) {
- buffer[0] = '\0';
- X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = '\0';
- RDEBUG3("Creating attributes for \"%s\":", buffer[0] ? buffer : "Cert missing subject OID");
- }
-
- /*
- * Get the Serial Number
- */
- sn = X509_get_serialNumber(cert);
- if (sn && ((size_t) sn->length < (sizeof(buffer) / 2))) {
- char *p = buffer;
- int i;
-
- for (i = 0; i < sn->length; i++) {
- sprintf(p, "%02x", (unsigned int)sn->data[i]);
- p += 2;
- }
-
- CERT_ATTR_ADD(IDX_SERIAL, attr_index, buffer);
- }
-
- /*
- * Get the Expiration Date
- */
- buffer[0] = '\0';
- asn_time = X509_get_notAfter(cert);
- if (identity && asn_time && (asn_time->length < (int)sizeof(buffer))) {
- time_t expires;
-
- /*
- * Add expiration as a time since the epoch
- */
- if (fr_tls_utils_asn1time_to_epoch(&expires, asn_time) < 0) {
- RPWDEBUG("Failed parsing certificate expiry time");
- } else {
- vp = CERT_ATTR_ADD(IDX_EXPIRATION, attr_index, NULL);
- vp->vp_date = fr_unix_time_from_sec(expires);
- }
- }
-
- /*
- * Get the Subject & Issuer
- */
- buffer[0] = '\0';
- X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = '\0';
- if (identity && buffer[0]) {
- CERT_ATTR_ADD(IDX_SUBJECT, attr_index, buffer);
-
- /*
- * Get the Common Name, if there is a subject.
- */
- X509_NAME_get_text_by_NID(X509_get_subject_name(cert),
- NID_commonName, buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = '\0';
-
- if (buffer[0]) {
- CERT_ATTR_ADD(IDX_COMMON_NAME, attr_index, buffer);
- }
- }
-
- X509_NAME_oneline(X509_get_issuer_name(cert), buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = '\0';
- if (identity && buffer[0]) {
- CERT_ATTR_ADD(IDX_ISSUER, attr_index, buffer);
- }
-
- /*
- * Get the RFC822 Subject Alternative Name
- */
- loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, 0);
- if (loc >= 0) {
- X509_EXTENSION *ext = NULL;
- GENERAL_NAMES *names = NULL;
- int i;
-
- ext = X509_get_ext(cert, loc);
- if (ext && (names = X509V3_EXT_d2i(ext))) {
- for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
- GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
-
- switch (name->type) {
-#ifdef GEN_EMAIL
- case GEN_EMAIL: {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- char const *rfc822Name = (char const *)ASN1_STRING_get0_data(name->d.rfc822Name);
-#else
- char *rfc822Name = (char *)ASN1_STRING_data(name->d.rfc822Name);
-#endif
-
- CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_EMAIL, attr_index, rfc822Name);
- break;
- }
-#endif /* GEN_EMAIL */
-#ifdef GEN_DNS
- case GEN_DNS: {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- char const *dNSName = (char const *)ASN1_STRING_get0_data(name->d.dNSName);
-#else
- char *dNSName = (char *)ASN1_STRING_data(name->d.dNSName);
-#endif
- CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_DNS, attr_index, dNSName);
- break;
- }
-#endif /* GEN_DNS */
-#ifdef GEN_OTHERNAME
- case GEN_OTHERNAME:
- /* look for a MS UPN */
- if (NID_ms_upn != OBJ_obj2nid(name->d.otherName->type_id)) break;
-
- /* we've got a UPN - Must be ASN1-encoded UTF8 string */
- if (name->d.otherName->value->type == V_ASN1_UTF8STRING) {
- CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_UPN, attr_index,
- (char *)name->d.otherName->value->value.utf8string);
- break;
- }
-
- RWARN("Invalid UPN in Subject Alt Name (should be UTF-8)");
- break;
-#endif /* GEN_OTHERNAME */
- default:
- /* XXX TODO handle other SAN types */
- break;
- }
- }
- }
- if (names != NULL) GENERAL_NAMES_free(names);
- }
-
- /*
- * Only add extensions for the actual client certificate
- */
- if (attr_index == 0) {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- ext_list = X509_get0_extensions(cert);
-#else
- ext_list = cert->cert_info->extensions;
-#endif
-
- /*
- * Grab the X509 extensions, and create attributes out of them.
- * For laziness, we re-use the OpenSSL names
- */
- if (sk_X509_EXTENSION_num(ext_list) > 0) {
- int i, len;
- char *p;
- BIO *out;
-
- MEM(out = BIO_new(BIO_s_mem()));
- strlcpy(attribute, "TLS-Client-Cert-", sizeof(attribute));
-
- for (i = 0; i < sk_X509_EXTENSION_num(ext_list); i++) {
- char value[1024];
- ASN1_OBJECT *obj;
- X509_EXTENSION *ext;
- fr_dict_attr_t const *da;
-
- ext = sk_X509_EXTENSION_value(ext_list, i);
-
- obj = X509_EXTENSION_get_object(ext);
- if (i2a_ASN1_OBJECT(out, obj) <= 0) {
- RPWDEBUG("Skipping X509 Extension (%i) conversion to attribute. "
- "Conversion from ASN1 failed...", i);
- continue;
- }
-
- len = BIO_read(out, attribute + 16 , sizeof(attribute) - 16 - 1);
- if (len <= 0) continue;
-
- attribute[16 + len] = '\0';
-
- for (p = attribute + 16; *p != '\0'; p++) if (*p == ' ') *p = '-';
-
- X509V3_EXT_print(out, ext, 0, 0);
- len = BIO_read(out, value , sizeof(value) - 1);
- if (len <= 0) continue;
-
- value[len] = '\0';
-
- da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), attribute);
- if (!da) {
- RWDEBUG3("Skipping attribute %s: "
- "Add dictionary definition if you want to access it", attribute);
- continue;
- }
-
- MEM(vp = fr_pair_afrom_da(ctx, da));
- if (fr_pair_value_from_str(vp, value, -1, '\0', true) < 0) {
- RPWDEBUG3("Skipping: %s += '%s'", attribute, value);
- talloc_free(vp);
- continue;
- }
-
- fr_pair_append(pair_list, vp);
- }
- BIO_free_all(out);
- }
- }
-
- return 0;
-}
-DIAG_ON(used-but-marked-unused)
-DIAG_ON(DIAG_UNKNOWN_PRAGMAS)
-
/** Decrypt application data
*
* @note Handshake must have completed before this function may be called.
* asynchronously.
*/
switch (SSL_get_error(tls_session->ssl, ret)) {
- case SSL_ERROR_WANT_ASYNC: /* Certification validation */
+ case SSL_ERROR_WANT_ASYNC: /* Certification validation or cache loads */
+ {
+ unlang_action_t ua;
/*
* Call this function again once we're done
* asynchronously satisfying the load request.
goto finish;
}
- if (fr_tls_cache_load_push(request, tls_session) < 0) {
+ /*
+ * First service any pending cache actions
+ */
+ ua = fr_tls_cache_pending_push(request, tls_session);
+ switch (ua) {
+ case UNLANG_ACTION_FAIL:
if (unlang_function_clear(request) < 0) goto error;
goto error;
+
+ case UNLANG_ACTION_PUSHED_CHILD:
+ return ua;
+
+ default:
+ break;
}
- return UNLANG_ACTION_PUSHED_CHILD;
+
+ /*
+ * Next service any pending certificate
+ * validation actions.
+ */
+ ua = fr_tls_validate_client_cert_pending_push(request, tls_session);
+ switch (ua) {
+ case UNLANG_ACTION_FAIL:
+ if (unlang_function_clear(request) < 0) goto error;
+ goto error;
+
+ default:
+ return ua;
+ }
+ }
default:
/*
request_t *request;
fr_tls_conf_t *conf = fr_tls_ctx_conf(ssl_ctx);
- tls_session = talloc_zero(ctx, fr_tls_session_t);
- if (!tls_session) return NULL;
-
+ MEM(tls_session = talloc_zero(ctx, fr_tls_session_t));
talloc_set_destructor(tls_session, _fr_tls_session_free);
+ fr_pair_list_init(&tls_session->extra_pairs);
tls_session->ssl = SSL_new(ssl_ctx);
if (!tls_session->ssl) {
fr_tls_session_t *fr_tls_session_alloc_server(TALLOC_CTX *ctx, SSL_CTX *ssl_ctx, request_t *request, bool client_cert)
{
fr_tls_session_t *tls_session = NULL;
- SSL *new_tls = NULL;
+ SSL *ssl = NULL;
int verify_mode = 0;
fr_pair_t *vp;
fr_tls_conf_t *conf = fr_tls_ctx_conf(ssl_ctx);
RDEBUG2("Initiating new TLS session");
- new_tls = SSL_new(ssl_ctx);
- if (new_tls == NULL) {
+ MEM(tls_session = talloc_zero(ctx, fr_tls_session_t));
+
+ ssl = SSL_new(ssl_ctx);
+ if (ssl == NULL) {
fr_tls_log_error(request, "Error creating new TLS session");
return NULL;
}
+ fr_pair_list_init(&tls_session->extra_pairs);
- tls_session = talloc_zero(ctx, fr_tls_session_t);
- if (tls_session == NULL) {
- RERROR("Error allocating memory for TLS session");
- SSL_free(new_tls);
- return NULL;
- }
session_init(tls_session);
tls_session->ctx = ssl_ctx;
- tls_session->ssl = new_tls;
+ tls_session->ssl = ssl;
talloc_set_destructor(tls_session, _fr_tls_session_free);
fr_tls_session_request_bind(tls_session->ssl, request);
* Add the message callback to identify what type of
* message/handshake is passed
*/
- SSL_set_msg_callback(new_tls, fr_tls_session_msg_cb);
- SSL_set_msg_callback_arg(new_tls, tls_session);
- SSL_set_info_callback(new_tls, fr_tls_session_info_cb);
+ SSL_set_msg_callback(ssl, fr_tls_session_msg_cb);
+ SSL_set_msg_callback_arg(ssl, tls_session);
+ SSL_set_info_callback(ssl, fr_tls_session_info_cb);
/*
* This sets the context sessions can be resumed in.
verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
verify_mode |= SSL_VERIFY_CLIENT_ONCE;
}
+ tls_session->verify_client_cert = client_cert;
+
SSL_set_verify(tls_session->ssl, verify_mode, fr_tls_validate_cert_cb);
SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF, (void *)conf);
SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (void *)tls_session);
#include <openssl/ssl.h>
#include <openssl/err.h>
+typedef struct fr_tls_session_s fr_tls_session_t;
+
+#include "cache.h"
#include "conf.h"
#include "index.h"
+#include "validate.h"
#ifdef __cplusplus
extern "C" {
* In the case of EAP-TLS + dependents a #eap_tls_session_t struct is used to track
* the transfer of TLS records.
*/
-typedef struct {
+struct fr_tls_session_s {
SSL_CTX *ctx; //!< TLS configuration context.
SSL *ssl; //!< This SSL session.
SSL_SESSION *session; //!< Session resumption data.
fr_tls_cache_t *cache; //!< Current session resumption state.
bool allow_session_resumption; //!< Whether session resumption is allowed.
+ bool verify_client_cert; //!< Whether client cert verification has been requested.
+
+ fr_tls_validate_t validate; //!< Current session certificate validation state.
bool invalid; //!< Whether heartbleed attack was detected.
bool pending_alert;
uint8_t pending_alert_level;
uint8_t pending_alert_description;
-} fr_tls_session_t;
+
+ fr_pair_list_t extra_pairs; //!< Pairs to add to cache and certificate validation
+ ///< calls. These will be duplicated for every call.
+};
/** Return the tls config associated with a tls_session
*
return talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST), request_t);
}
+/** Add extra pairs to the temporary subrequests
+ *
+ * @param[in] child to add extra pairs to.
+ * @param[in] tls_session to add extra pairs from.
+ */
+static inline CC_HINT(nonnull)
+void fr_tls_session_extra_pairs_copy_to_child(request_t *child, fr_tls_session_t *tls_session)
+{
+ if (!fr_pair_list_empty(&tls_session->extra_pairs)) {
+ MEM(fr_pair_list_copy(child->request_ctx, &child->request_pairs, &tls_session->extra_pairs) >= 0);
+ }
+}
+
+/** Add an additional pair (copying it) to the list of extra pairs
+ *
+ * @param[in] tls_session to add extra pairs to.
+ * @param[in] vp to add to tls_session.
+ */
+static inline CC_HINT(nonnull)
+void fr_tls_session_extra_pair_add(fr_tls_session_t *tls_session, fr_pair_t *vp)
+{
+ fr_pair_t *copy;
+
+ MEM(copy = fr_pair_copy(tls_session, vp));
+ fr_pair_append(&tls_session->extra_pairs, copy);
+}
+
+/** Add an additional pair to the list of extra pairs
+ *
+ * @param[in] tls_session to add extra pairs to.
+ * @param[in] vp to add to tls_session.
+ */
+static inline CC_HINT(nonnull)
+void fr_tls_session_extra_pair_add_shallow(fr_tls_session_t *tls_session, fr_pair_t *vp)
+{
+ fr_assert(talloc_parent(vp) == tls_session);
+ fr_pair_append(&tls_session->extra_pairs, vp);
+}
+
+
int fr_tls_session_password_cb(char *buf, int num, int rwflag, void *userdata);
unsigned int fr_tls_session_psk_client_cb(SSL *ssl, UNUSED char const *hint,
#include <freeradius-devel/server/exec.h>
#include <freeradius-devel/server/pair.h>
+#include <freeradius-devel/unlang/function.h>
+#include <freeradius-devel/unlang/subrequest.h>
#include <freeradius-devel/util/debug.h>
-
#include <freeradius-devel/util/strerror.h>
#include <freeradius-devel/util/syserror.h>
return ret;
}
+
+/** Process the result of `validate certificate { ... }`
+ *
+ */
+static unlang_action_t tls_validate_client_cert_result(UNUSED rlm_rcode_t *p_result, UNUSED int *priority,
+ request_t *request, void *uctx)
+{
+ fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
+ fr_pair_t *vp;
+
+ fr_assert(tls_session->validate.state == FR_TLS_VALIDATION_REQUESTED);
+
+ vp = fr_pair_find_by_da(&request->reply_pairs, attr_tls_packet_type, 0);
+ if (!vp || (vp->vp_uint32 != enum_tls_packet_type_success->vb_uint32)) {
+ REDEBUG("Failed (re-)validating certificates");
+ tls_session->validate.state = FR_TLS_VALIDATION_FAILED;
+ return UNLANG_ACTION_CALCULATE_RESULT;
+ }
+
+ tls_session->validate.state = FR_TLS_VALIDATION_SUCCESS;
+
+ RDEBUG2("Certificates (re-)validated");
+
+ return UNLANG_ACTION_CALCULATE_RESULT;
+}
+
+/** Push a `validate certificate { ... }` call into the current request, using a subrequest
+ *
+ * @param[in] request The current request.
+ * @Param[in] tls_session The current TLS session.
+ * @return
+ * - UNLANG_ACTION_CALCULATE_RESULT on noop.
+ * - UNLANG_ACTION_PUSHED_CHILD on success.
+ * - UNLANG_ACTION_FAIL on failure.
+ */
+static unlang_action_t tls_validate_client_cert_push(request_t *request, fr_tls_session_t *tls_session)
+{
+ fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl);
+ request_t *child;
+ fr_pair_t *vp;
+ unlang_action_t ua;
+
+ MEM(child = unlang_subrequest_alloc(request, dict_tls));
+ request = child;
+
+ /*
+ * Add extra pairs to the subrequest
+ */
+ fr_tls_session_extra_pairs_copy_to_child(child, tls_session);
+
+ /*
+ * Setup the child request for loading
+ * session resumption data.
+ */
+ MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0);
+ vp->vp_uint32 = enum_tls_packet_type_certificate_validate->vb_uint32;
+
+ /*
+ * Allocate a child, and set it up to call
+ * the TLS virtual server.
+ */
+ ua = fr_tls_call_push(child, tls_validate_client_cert_result, conf, tls_session);
+ if (ua < 0) {
+ PERROR("Failed calling TLS virtual server");
+ talloc_free(child);
+ return UNLANG_ACTION_FAIL;
+ }
+
+ return ua;
+}
+
+/** Check we validated the client cert successfully
+ *
+ */
+bool fr_tls_validate_client_cert_success(fr_tls_session_t *tls_session)
+{
+ return tls_session->validate.state == FR_TLS_VALIDATION_SUCCESS;
+}
+
+/** Setup a validation request
+ *
+ */
+void fr_tls_validate_client_cert_request(fr_tls_session_t *tls_session)
+{
+ fr_assert(tls_session->validate.state == FR_TLS_VALIDATION_INIT);
+
+ tls_session->validate.state = FR_TLS_VALIDATION_REQUESTED;
+}
+
+/** Push a `validate certificate { ... }` section
+ *
+ * @param[in] request The current request.
+ * @Param[in] tls_session The current TLS session.
+ * @return
+ * - UNLANG_ACTION_CALCULATE_RESULT - No pending actions
+ * - UNLANG_ACTION_PUSHED_CHILD - Pending operations to evaluate.
+ */
+unlang_action_t fr_tls_validate_client_cert_pending_push(request_t *request, fr_tls_session_t *tls_session)
+{
+ if (tls_session->validate.state == FR_TLS_VALIDATION_REQUESTED) {
+ return tls_validate_client_cert_push(request, tls_session);
+ }
+
+ return UNLANG_ACTION_CALCULATE_RESULT;
+}
#endif /* WITH_TLS */
--- /dev/null
+#pragma once
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifdef WITH_TLS
+/**
+ * $Id$
+ *
+ * @file lib/tls/validate.h
+ * @brief Structures for session-resumption management.
+ *
+ * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ */
+RCSIDH(validate_h, "$Id$")
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Certificate validation states
+ *
+ */
+typedef enum {
+ FR_TLS_VALIDATION_INIT = 0, //!< OpenSSL hasn't requested certificate validation.
+ FR_TLS_VALIDATION_REQUESTED, //!< OpenSSL requested validation.
+ FR_TLS_VALIDATION_SUCCESS, //!< Certificate chain was validate.
+ FR_TLS_VALIDATION_FAILED //!< Certificate validation failed.
+} fr_tls_validation_state_t;
+
+/** Certificate validation state
+ *
+ */
+typedef struct {
+ rlm_rcode_t rcode;
+ fr_tls_validation_state_t state; //!< Whether OpenSSL has requested
+ ///< certificate validation.
+} fr_tls_validate_t;
+
+int fr_tls_validate_cert_cb(int ok, X509_STORE_CTX *ctx);
+
+int fr_tls_validate_client_cert_chain(SSL *ssl);
+
+bool fr_tls_validate_client_cert_success(fr_tls_session_t *tls_session);
+
+void fr_tls_validate_client_cert_request(fr_tls_session_t *tls_session);
+
+unlang_action_t fr_tls_validate_client_cert_pending_push(request_t *request, fr_tls_session_t *tls_session);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* WITH_TLS */
-TARGETNAME := process_tls
+TARGETNAME := process_tls
+
+ifneq "$(OPENSSL_LIBS)" ""
+TARGET := $(TARGETNAME).a
+endif
SOURCES := base.c
TGT_PREREQS := libfreeradius-tls.a
-TGT_LDLIBS := $(PCAP_LIBS)
/**
* $Id$
* @file src/process/tls/base.c
- * @brief ARP processing.
+ * @brief TLS processing.
*
* @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
*/
#include <freeradius-devel/server/protocol.h>
#include <freeradius-devel/unlang/base.h>
#include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/protocol/tls/freeradius.h>
static fr_dict_t const *dict_tls;
};
typedef struct {
- uint64_t nothing; // so that the next field isn't at offset 0
-
- CONF_SECTION *request;
- CONF_SECTION *reply;
- CONF_SECTION *recv_reply;
- CONF_SECTION *reverse_request;
- CONF_SECTION *reverse_reply;
- CONF_SECTION *do_not_respond;
+ CONF_SECTION *session_load;
+ CONF_SECTION *session_store;
+ CONF_SECTION *session_clear;
+ CONF_SECTION *certificate_validate;
} process_tls_sections_t;
typedef struct {
- bool test;
-
process_tls_sections_t sections;
} process_tls_t;
-#define PROCESS_PACKET_TYPE fr_tls_packet_code_t
-#define PROCESS_CODE_MAX FR_ARP_CODE_MAX
-#define PROCESS_CODE_DO_NOT_RESPOND FR_ARP_DO_NOT_RESPOND
-#define PROCESS_PACKET_CODE_VALID FR_ARP_PACKET_CODE_VALID
+#define FR_TLS_PACKET_CODE_VALID(_code) (((_code) > 0) && ((_code) <= FR_PACKET_TYPE_VALUE_NOTFOUND))
+
#define PROCESS_INST process_tls_t
+#define PROCESS_PACKET_TYPE uint32_t
+#define PROCESS_PACKET_CODE_VALID FR_TLS_PACKET_CODE_VALID
+
#include <freeradius-devel/server/process.h>
static fr_process_state_t const process_state[] = {
- [ FR_ARP_REQUEST ] = {
+ [FR_PACKET_TYPE_VALUE_SESSION_LOAD] = {
.packet_type = {
- [RLM_MODULE_NOOP] = FR_ARP_REPLY,
- [RLM_MODULE_OK] = FR_ARP_REPLY,
- [RLM_MODULE_UPDATED] = FR_ARP_REPLY,
-
- [RLM_MODULE_REJECT] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_FAIL] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_INVALID] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_DISALLOW] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_NOTFOUND] = FR_ARP_DO_NOT_RESPOND,
+ [RLM_MODULE_OK] = FR_PACKET_TYPE_VALUE_SUCCESS,
+ [RLM_MODULE_UPDATED] = FR_PACKET_TYPE_VALUE_SUCCESS,
+
+ [RLM_MODULE_NOOP] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_REJECT] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_FAIL] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_INVALID] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_DISALLOW] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_NOTFOUND] = FR_PACKET_TYPE_VALUE_NOTFOUND,
},
.rcode = RLM_MODULE_NOOP,
.recv = recv_generic,
- .resume = resume_recv_generic,
- .section_offset = PROCESS_CONF_OFFSET(request),
+ .resume = resume_recv_no_send,
+ .section_offset = PROCESS_CONF_OFFSET(session_load),
},
- [ FR_ARP_REPLY ] = {
+ [FR_PACKET_TYPE_VALUE_SESSION_STORE] = {
.packet_type = {
- [RLM_MODULE_NOOP] = FR_ARP_REPLY,
- [RLM_MODULE_OK] = FR_ARP_REPLY,
- [RLM_MODULE_UPDATED] = FR_ARP_REPLY,
-
- [RLM_MODULE_REJECT] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_FAIL] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_INVALID] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_DISALLOW] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_NOTFOUND] = FR_ARP_DO_NOT_RESPOND,
- },
- .rcode = RLM_MODULE_NOOP,
- .send = send_generic,
- .resume = resume_send_generic,
- .section_offset = PROCESS_CONF_OFFSET(reply),
- },
-
- [ FR_ARP_REVERSE_REQUEST ] = {
- .packet_type = {
- [RLM_MODULE_NOOP] = FR_ARP_REVERSE_REPLY,
- [RLM_MODULE_OK] = FR_ARP_REVERSE_REPLY,
- [RLM_MODULE_UPDATED] = FR_ARP_REVERSE_REPLY,
-
- [RLM_MODULE_REJECT] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_FAIL] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_INVALID] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_DISALLOW] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_NOTFOUND] = FR_ARP_DO_NOT_RESPOND,
+ [RLM_MODULE_OK] = FR_PACKET_TYPE_VALUE_SUCCESS,
+ [RLM_MODULE_UPDATED] = FR_PACKET_TYPE_VALUE_SUCCESS,
+
+ [RLM_MODULE_NOOP] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_REJECT] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_FAIL] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_INVALID] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_DISALLOW] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_NOTFOUND] = FR_PACKET_TYPE_VALUE_NOTFOUND,
},
.rcode = RLM_MODULE_NOOP,
.recv = recv_generic,
- .resume = resume_recv_generic,
- .section_offset = PROCESS_CONF_OFFSET(reverse_request),
+ .resume = resume_recv_no_send,
+ .section_offset = PROCESS_CONF_OFFSET(session_store),
},
- [ FR_ARP_REVERSE_REPLY ] = {
+ [FR_PACKET_TYPE_VALUE_SESSION_CLEAR] = {
.packet_type = {
- [RLM_MODULE_NOOP] = FR_ARP_REVERSE_REPLY,
- [RLM_MODULE_OK] = FR_ARP_REVERSE_REPLY,
- [RLM_MODULE_UPDATED] = FR_ARP_REVERSE_REPLY,
-
- [RLM_MODULE_REJECT] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_FAIL] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_INVALID] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_DISALLOW] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_NOTFOUND] = FR_ARP_DO_NOT_RESPOND,
+ [RLM_MODULE_OK] = FR_PACKET_TYPE_VALUE_SUCCESS,
+ [RLM_MODULE_UPDATED] = FR_PACKET_TYPE_VALUE_SUCCESS,
+
+ [RLM_MODULE_NOOP] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_REJECT] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_FAIL] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_INVALID] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_DISALLOW] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_NOTFOUND] = FR_PACKET_TYPE_VALUE_NOTFOUND,
},
.rcode = RLM_MODULE_NOOP,
- .send = send_generic,
- .resume = resume_send_generic,
- .section_offset = PROCESS_CONF_OFFSET(reverse_reply),
+ .recv = recv_generic,
+ .resume = resume_recv_no_send,
+ .section_offset = PROCESS_CONF_OFFSET(session_clear),
},
-
- // @todo - recv reply, to look at other replies.
-
- [ FR_ARP_DO_NOT_RESPOND ] = {
+ [FR_PACKET_TYPE_VALUE_CERTIFICATE_VALIDATE] = {
.packet_type = {
- [RLM_MODULE_NOOP] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_OK] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_UPDATED] = FR_ARP_DO_NOT_RESPOND,
-
- [RLM_MODULE_REJECT] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_FAIL] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_INVALID] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_DISALLOW] = FR_ARP_DO_NOT_RESPOND,
- [RLM_MODULE_NOTFOUND] = FR_ARP_DO_NOT_RESPOND,
+ [RLM_MODULE_OK] = FR_PACKET_TYPE_VALUE_SUCCESS,
+
+ [RLM_MODULE_UPDATED] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_NOOP] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_REJECT] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_FAIL] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_INVALID] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_DISALLOW] = FR_PACKET_TYPE_VALUE_FAILURE,
+ [RLM_MODULE_NOTFOUND] = FR_PACKET_TYPE_VALUE_NOTFOUND,
},
.rcode = RLM_MODULE_NOOP,
- .send = send_generic,
- .resume = resume_send_generic,
- .section_offset = PROCESS_CONF_OFFSET(do_not_respond),
+ .recv = recv_generic,
+ .resume = resume_recv_no_send,
+ .section_offset = PROCESS_CONF_OFFSET(certificate_validate),
},
};
-/*
- * Debug the packet if requested.
- */
-static void tls_packet_debug(request_t *request, fr_radius_packet_t const *packet, fr_pair_list_t const *list, bool received)
-{
- if (!packet) return;
- if (!RDEBUG_ENABLED) return;
-
- log_request(L_DBG, L_DBG_LVL_1, request, __FILE__, __LINE__, "%s %s",
- received ? "Received" : "Sending",
- fr_tls_packet_codes[packet->code]);
-
- if (received || request->parent) {
- log_request_pair_list(L_DBG_LVL_1, request, NULL, list, NULL);
- } else {
- log_request_proto_pair_list(L_DBG_LVL_1, request, NULL, list, NULL);
- }
-}
-
static unlang_action_t mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
{
fr_process_state_t const *state;
PROCESS_TRACE;
(void)talloc_get_type_abort_const(mctx->instance, process_tls_t);
- fr_assert(PROCESS_PACKET_CODE_VALID(request->packet->code));
request->component = "tls";
request->module = NULL;
UPDATE_STATE(packet);
- tls_packet_debug(request, request->packet, &request->request_pairs, true);
+ log_request_pair_list(L_DBG_LVL_1, request, NULL, &request->request_pairs, NULL);
return state->recv(p_result, mctx, request);
}
-
static const virtual_server_compile_t compile_list[] = {
{
.name = "store",
.name2 = "session",
.component = MOD_AUTHORIZE,
- .offset = offsetof(eap_aka_sim_process_conf_t, actions.store_session)
+ .offset = PROCESS_CONF_OFFSET(session_store)
},
{
.name = "load",
.name2 = "session",
.component = MOD_AUTHORIZE,
- .offset = offsetof(eap_aka_sim_process_conf_t, actions.load_session)
+ .offset = PROCESS_CONF_OFFSET(session_load)
},
{
.name = "clear",
.name2 = "session",
.component = MOD_AUTHORIZE,
- .offset = offsetof(eap_aka_sim_process_conf_t, actions.clear_session)
+ .offset = PROCESS_CONF_OFFSET(session_clear)
},
{
- .name = "recv",
+ .name = "validate",
.name2 = "certificate",
.component = MOD_AUTHORIZE,
- .offset = offsetof(eap_aka_sim_process_conf_t, actions.recv_certificate)
+ .offset = PROCESS_CONF_OFFSET(certificate_validate)
},
- {
- .name = "send",
- .name2 = "success",
- .component = MOD_POST_AUTH,
- .offset = offsetof(eap_aka_sim_process_conf_t, actions.send_success)
- },
- {
- .name = "send",
- .name2 = "failure",
- .component = MOD_POST_AUTH,
- .offset = offsetof(eap_aka_sim_process_conf_t, actions.send_failure)
- }
COMPILE_TERMINATOR
};
+#
+# Should use the same set of snakeoil certs as
+# eapol_test.
+#
+tls-config eap-tls-test {
+ virtual_server = eap-tls-test
+ chain {
+ certificate_file = ${certdir}/rsa/server.pem
+
+ private_key_password = whatever
+ private_key_file = ${certdir}/rsa/server.pem
+ ca_file = ${cadir}/rsa/ca.pem
+ }
+
+ ca_file = ${cadir}/rsa/ca.pem
+ ca_path = ${cadir}
+ dh_file = ${certdir}/dh
+
+ fragment_size = 1024
+ include_length = no
+
+ cipher_list = "DEFAULT"
+ ecdh_curve = "prime256v1"
+
+ verify {
+ }
+
+ ocsp {
+ }
+}
+
type = tls
tls {
# Point to the common TLS configuration
- tls = tls-common
-
- #
- # As part of checking a client certificate, the EAP-TLS
- # sets some attributes such as TLS-Client-Cert-CN. This
- # virtual server has access to these attributes, and can
- # be used to accept or reject the request.
- #
-# virtual_server = check-eap-tls
+ tls = eap-tls-test
}
-server inner-tunnel {
- namespace = radius
- listen {
- type = Access-Request
- }
-
- recv Access-Request {
- update request {
- &User-Name := &outer.User-Name
- }
- files
- pap
- chap
- mschap
- eap
- }
-
- authenticate pap {
- pap
- }
-
- authenticate chap {
- chap
- }
-
- authenticate mschap {
- mschap
- }
-
- authenticate eap {
- eap
- }
-
- send Access-Accept {
- }
-
- send Access-Reject {
- }
+server eap-tls-test {
+ namespace = tls
- send Access-Challenge {
+ validate certificate {
+ ok
}
}