26RCSID(
"$Id: 2df37f0e540692ac185cb0d4c079d883f5b665a5 $")
29#include <freeradius-devel/eap/tls.h>
30#include <freeradius-devel/eap/chbind.h>
31#include <freeradius-devel/tls/strerror.h>
123#define FR_DIAMETER_AVP_FLAG_VENDOR 0x80
124#define FR_DIAMETER_AVP_FLAG_MANDATORY 0x40
146 unsigned int hdr_len;
147 unsigned int remaining = data_len;
149 while (remaining > 0) {
152 if (remaining < hdr_len) {
153 RDEBUG2(
"Diameter attribute is too small (%u) to contain a Diameter header", remaining);
157 memcpy(&attr,
data,
sizeof(attr));
159 memcpy(&length,
data + 4,
sizeof(length));
160 length = ntohl(length);
162 if ((
data[4] & 0x80) != 0) {
163 if (remaining < 16) {
164 RDEBUG2(
"Diameter attribute is too small to contain a Diameter header with Vendor-Id");
174 length &= 0x00ffffff;
179 if (length <= (hdr_len - 4)) {
180 RDEBUG2(
"Tunneled attribute %u is too short (%u < %u) to contain anything useful.", attr,
185 if (length > remaining) {
186 RDEBUG2(
"Tunneled attribute %u is longer than room remaining in the packet (%u > %u).", attr,
195 if (remaining == length)
break;
212 if (remaining < length) {
213 REDEBUG2(
"Diameter attribute overflows packet!");
241 SSL *ssl = decode_ctx;
244 TALLOC_CTX *tmp_ctx = NULL;
256 fr_strerror_printf(
"Malformed diameter attribute at offset %zu. Needed at least 8 bytes, got %zu bytes",
264 RDEBUG3(
"%04zu %02x%02x%02x%02x %02x%02x%02x%02x ...", p -
data,
265 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
277 fr_strerror_printf(
"Malformed diameter attribute at offset %zu. Needed at least length of 8, got %u",
278 p -
data, (
unsigned int) value_len);
285 if ((p + ((value_len + 0x03) & ~0x03)) - 8 > end) {
286 fr_strerror_printf(
"Malformed diameter attribute at offset %zu. Value length %u overflows input",
287 p -
data, (
unsigned int) value_len);
318 our_parent = attr_radius;
356 p += (value_len + 0x03) & ~0x03;
358 if (
vp->
da->flags.is_unknown)
continue;
377 static const char label[] =
"ttls challenge";
379 if ((
vp->vp_length < 8) || (
vp->vp_length > 16)) {
388 if (SSL_export_keying_material(ssl, challenge,
vp->vp_length + 1,
389 label,
sizeof(label) - 1, NULL, 0, 0) != 1) {
390 fr_tls_strerror_printf(
"Failed generating phase2 challenge");
394 if (memcmp(challenge,
vp->vp_octets,
vp->vp_length) != 0) {
446 if ((total +
vp->vp_length + 12) >=
sizeof(
buffer)) {
447 RDEBUG2(
"output buffer is full!");
456 length =
vp->vp_length;
459 attr =
vp->
da->attr & 0xffff;
472 memcpy(p, &attr,
sizeof(attr));
481 length = ntohl(length);
482 memcpy(p, &length,
sizeof(length));
486 vendor = ntohl(vendor);
487 memcpy(p, &vendor,
sizeof(vendor));
491 length = ntohl(length);
492 memcpy(p, &length,
sizeof(length));
497 switch (
vp->vp_type) {
500 memcpy(p, &attr,
sizeof(attr));
505 attr = htonl(
vp->vp_uint32);
506 memcpy(p, &attr,
sizeof(attr));
511 attr64 = htonll(
vp->vp_uint64);
512 memcpy(p, &attr64,
sizeof(attr64));
517 memcpy(p, &
vp->vp_ipv4addr, 4);
524 memcpy(p,
vp->vp_strvalue,
vp->vp_length);
525 length =
vp->vp_length;
538 if ((total & 0x03) != 0) {
541 length = 4 - (total & 0x03);
542 for (i = 0; i < length; i++) {
554 (tls_session->record_from_buff)(&tls_session->clean_in,
buffer, total);
559 fr_tls_session_send(request, tls_session);
572 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
576 "ttls keying material",
577 sizeof(
"ttls keying material") - 1);
601 return fr_tls_cache_pending_push(request, tls_session);
612 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
642 switch (reply->
code) {
644 RDEBUG2(
"Got tunneled Access-Accept");
651 RDEBUG2(
"Got MS-CHAP2-Success, tunneling it to the client in a challenge");
668 REDEBUG(
"Got tunneled Access-Reject");
679 RDEBUG2(
"Got tunneled Access-Challenge");
696 REDEBUG(
"Unknown RADIUS packet type %d: rejecting tunneled user", reply->
code);
707 RDEBUG2(
"Sending tunneled reply attributes");
736 data_len = tls_session->clean_out.used;
737 tls_session->clean_out.used = 0;
738 data = tls_session->clean_out.data;
748 RDEBUG2(
"Got ACK, and the user was already authenticated");
766 data, data_len, tls_session->ssl) < 0) {
767 RPEDEBUG(
"Decoding TTLS TLVs failed");
798 (
char const *)
vp->vp_octets + 5,
vp->vp_length - 5,
true);
807 RWDEBUG2(
"No EAP-Identity found to start EAP conversation");
825 RDEBUG2(
"received chbind request");
836 RDEBUG2(
"sending chbind response");
880 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
890 switch (eap_tls_session->
state) {
899 if (SSL_session_reused(tls_session->ssl)) {
900 RDEBUG2(
"Skipping Phase2 due to session resumption");
935 RDEBUG2(
"Session established. Decoding Diameter attributes");
969 fr_tls_session_t *tls_session;
979 client_cert =
vp->vp_uint32 ? true :
false;
981 client_cert =
inst->req_client_cert;
999 tls_session->opaque =
ttls_alloc(tls_session);
1014 eap_session->
tls =
true;
1018 if (
inst->tls_conf->new_session)
return fr_tls_new_session_push(request,
inst->tls_conf);
1028 t->
ssl_ctx = fr_tls_ctx_alloc(
inst->tls_conf,
false);
1059 if (!
inst->tls_conf) {
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.
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
static int const char char buffer[256]
#define USES_APPLE_DEPRECATED_API
#define CONF_PARSER_TERMINATOR
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
#define FR_CONF_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR is found
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Defines a CONF_PAIR to C data type mapping.
A section grouping multiple CONF_PAIR.
#define cf_log_err(_cf, _fmt,...)
fr_pair_t * eap_chbind_packet2vp(TALLOC_CTX *ctx, chbind_packet_t *chbind)
fr_radius_packet_code_t chbind_process(request_t *request, CHBIND_REQ *chbind)
chbind_packet_t * eap_chbind_vp2packet(TALLOC_CTX *ctx, fr_pair_list_t *vps)
chbind_packet_t * response
chbind_packet_t * request
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
fr_radius_packet_code_t
RADIUS packet codes.
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
static fr_dict_attr_t * fr_dict_attr_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor)
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
fr_dict_attr_t const * fr_dict_vendor_da_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen)
Return vendor attribute for the specified dictionary and pen.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
fr_dict_t const * fr_dict_internal(void)
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
void eap_crypto_prf_label_init(eap_tls_prf_label_t *prf_label, eap_session_t *eap_session, char const *keying_prf_label, size_t keying_prf_label_len)
Initialize the PRF label fields.
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
unlang_action_t eap_virtual_server(request_t *request, eap_session_t *eap_session, virtual_server_t *virtual_server)
Run a subrequest through a virtual server.
static eap_session_t * eap_session_get(request_t *request)
void * opaque
Opaque data used by EAP methods.
bool tls
Whether EAP method uses TLS.
module_method_t process
Callback that should be used to process the next round.
request_t * request
Current request.
Tracks the progress of a single session of any EAP method.
void log_request_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a fr_pair_list_t.
#define RWDEBUG2(fmt,...)
#define RPEDEBUG(fmt,...)
#define REDEBUG2(fmt,...)
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
module_instance_t const * mi
Instance of the module being instantiated.
void * thread
Thread specific instance data.
void * rctx
Resume ctx that a module previously set.
void * thread
Thread instance data.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
Temporary structure to hold arguments for thread_instantiation calls.
static uint64_t fr_nbo_to_uint64v(uint8_t const *data, size_t data_len)
Read an unsigned 64bit integer from wire format (big endian) with a variable length encoding.
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
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.
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.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
int fr_pair_value_strtrim(fr_pair_t *vp)
Trim the length of the string buffer to match the length of the C string.
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
int fr_pair_prepend(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the start of the list.
int fr_pair_raw_afrom_pair(fr_pair_t *vp, uint8_t const *data, size_t data_len)
Mark malformed attribute as raw.
static const conf_parser_t config[]
#define RETURN_UNLANG_HANDLED
#define RETURN_UNLANG_INVALID
#define RETURN_UNLANG_FAIL
#define RETURN_UNLANG_REJECT
@ RLM_MODULE_OK
The module is OK, continue.
static unlang_action_t mod_handshake_process(UNUSED unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_handshake_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_attr_t const * attr_user_password
char const * tls_conf_name
virtual_server_t * virtual_server
static fr_dict_attr_t const * attr_eap_message
static fr_dict_attr_t const * attr_eap_channel_binding_message
#define FR_DIAMETER_AVP_FLAG_MANDATORY
static fr_dict_t const * dict_freeradius
static fr_dict_attr_t const * attr_eap_tls_require_client_cert
SSL_CTX * ssl_ctx
Thread local SSL_CTX.
static fr_dict_attr_t const * attr_ms_chap2_success
static unlang_action_t mod_session_init_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_t const * dict_radius
static fr_dict_attr_t const * attr_ms_chap_challenge
static fr_dict_attr_t const * attr_chap_challenge
static fr_dict_attr_t const * attr_vendor_specific
static fr_dict_attr_t const * attr_reply_message
static unlang_action_t eap_ttls_success(unlang_result_t *p_result, request_t *request, eap_session_t *eap_session)
static int vp2diameter(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *list)
static unlang_action_t process_reply(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static int diameter_verify(request_t *request, uint8_t const *data, unsigned int data_len)
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static ssize_t eap_ttls_decode_pair(request_t *request, TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
static fr_dict_attr_t const * attr_user_name
static conf_parser_t submodule_config[]
#define FR_DIAMETER_AVP_FLAG_VENDOR
static unlang_action_t mod_session_init(UNUSED unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
fr_dict_attr_autoload_t rlm_eap_ttls_dict_attr[]
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static unlang_action_t eap_ttls_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_dict_autoload_t rlm_eap_ttls_dict[]
rlm_eap_submodule_t rlm_eap_ttls
static ttls_tunnel_t * ttls_alloc(TALLOC_CTX *ctx)
CONF_SECTION * conf
Module's instance configuration.
size_t inst_size
Size of the module's instance data.
void * data
Module's instance data.
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
eap_aka_sim_process_conf_t * inst
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
module_t common
Common fields provided by all modules.
Interface exported by EAP submodules.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
int eap_tls_success(request_t *request, eap_session_t *eap_session, eap_tls_prf_label_t *prf_label)
Send an EAP-TLS success.
eap_tls_session_t * eap_tls_session_init(request_t *request, eap_session_t *eap_session, SSL_CTX *ssl_ctx, bool client_cert)
Create a new fr_tls_session_t associated with an eap_session_t.
int eap_tls_start(request_t *request, eap_session_t *eap_session)
Send an initial EAP-TLS request to the peer.
int eap_tls_request(request_t *request, eap_session_t *eap_session)
Frames the OpenSSL data that needs to be sent to the client in an EAP-Request.
int eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
USES_APPLE_DEPRECATED_API fr_table_num_ordered_t const eap_tls_status_table[]
fr_tls_conf_t * eap_tls_conf_parse(CONF_SECTION *cs)
Parse TLS configuration.
unlang_action_t eap_tls_process(request_t *request, eap_session_t *eap_session)
Process an EAP TLS request.
eap_tls_status_t state
The state of the EAP-TLS session.
@ EAP_TLS_INVALID
Invalid, don't reply.
@ EAP_TLS_HANDLED
TLS code has handled it.
@ EAP_TLS_RECORD_RECV_COMPLETE
Received final fragment of a record.
@ EAP_TLS_FAIL
Fail, send fail.
@ EAP_TLS_ESTABLISHED
Session established, send success (or start phase2).
fr_tls_session_t * tls_session
TLS session used to authenticate peer or tunnel sensitive data.
bool include_length
A flag to include length in every TLS Data/Alert packet.
Tracks the state of an EAP-TLS session.
unsigned int code
Packet code (type).
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
static size_t char ** out
int virtual_server_cf_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Wrapper for the config parser to allow pass1 resolution of virtual servers.
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
Additional validation rules for virtual server lookup.