26RCSID(
"$Id: 71d4f4ebe1dac9464132143e089e76e98ffe8708 $")
 
   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)
#define DICT_AUTOLOAD_TERMINATOR
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.