27 RCSID(
"$Id: cf84959a488cf9cfd1a71b796b97c86847de9bc8 $")
31 #include <freeradius-devel/tls/utils.h>
32 #include <freeradius-devel/util/sha1.h>
33 #include <freeradius-devel/tls/openssl_user_macros.h>
34 #include <openssl/rand.h>
35 #include <openssl/ssl.h>
37 #define RANDFILL(x) do { fr_assert(sizeof(x) % sizeof(uint32_t) == 0); for (size_t i = 0; i < sizeof(x); i += sizeof(uint32_t)) *((uint32_t *)&x[i]) = fr_rand(); } while(0)
49 RDEBUG2(
"Deriving EAP-FAST keys");
62 memset(buf, 0, ksize +
sizeof(*t->
keyblock));
113 hdr[1] = htons(length);
115 tls_session->record_from_buff(&tls_session->clean_in, &hdr, 4);
116 tls_session->record_from_buff(&tls_session->clean_in,
data, length);
122 value = htonl(error);
144 RDEBUG2(
"Sending EAP-Identity");
162 memset(&pac, 0,
sizeof(pac));
163 memset(&opaque_plaintext, 0,
sizeof(opaque_plaintext));
183 #define MIN(a,b) (((a)>(b)) ? (b) : (a))
197 memcpy(&opaque_plaintext.
type, &pac.
info.
type,
sizeof(opaque_plaintext.
type));
199 memcpy(&opaque_plaintext.
key, &pac.
key,
sizeof(opaque_plaintext.
key));
201 RHEXDUMP3((
uint8_t const *)&opaque_plaintext,
sizeof(opaque_plaintext),
"PAC-Opaque plaintext data section");
206 dlen =
eap_fast_encrypt((
unsigned const char *)&opaque_plaintext,
sizeof(opaque_plaintext),
221 int const len =
sizeof(binding) - (&binding.
reserved - (
uint8_t *)&binding);
223 RDEBUG2(
"Sending Cryptobinding");
226 binding.
length = htons(len);
233 binding.
nonce[
sizeof(binding.
nonce) - 1] &= ~0x01;
236 RHEXDUMP3((
uint8_t const *) &binding,
sizeof(binding),
"Crypto-Binding TLV for Compound MAC calculation");
244 #define EAP_FAST_TLV_MAX 11
250 unsigned int remaining = data_len;
258 while (remaining > 0) {
260 RDEBUG2(
"EAP-FAST TLV is too small (%u) to contain a EAP-FAST TLV header", remaining);
264 memcpy(&attr,
data,
sizeof(attr));
276 present |= 1 << attr;
279 REDEBUG(
"Too many EAP-Payload TLVs");
282 if (present & (1 << i))
RDEBUG2(
" - attribute %d is present", i);
289 REDEBUG(
"Too many Intermediate-Result TLVs");
293 if ((
data[0] & 0x80) != 0) {
294 REDEBUG(
"Unknown mandatory TLV %02x", attr);
303 memcpy(&length,
data + 2,
sizeof(length));
304 length = ntohs(length);
309 if (length > remaining) {
310 RDEBUG2(
"EAP-FAST TLV %u is longer than room remaining in the packet (%u > %u).", attr,
322 if (remaining < length) {
323 RDEBUG2(
"EAP-FAST TLV overflows packet!");
336 REDEBUG(
"EAP-FAST TLV %u is too short. Expected 2, got %d", attr, length);
340 memcpy(&status,
data, 2);
341 status = ntohs(status);
344 REDEBUG(
"EAP-FAST TLV %u indicates failure. Rejecting request", attr);
349 REDEBUG(
"EAP-FAST TLV %u contains unknown value. Rejecting request", attr);
365 REDEBUG(
"NAK TLV sent with non-NAK TLVs. Rejecting request");
370 REDEBUG(
"NAK TLV sent with non-NAK TLVs. Rejecting request");
380 REDEBUG(
"Unexpected TLVs in TLS Session Handshake stage");
386 REDEBUG(
"Unexpected TLVs in authentication stage");
396 REDEBUG(
"Unexpected TLVs in cryptobind checking stage");
403 REDEBUG(
"Unexpected TLVs in provisioning stage");
409 REDEBUG(
"Unexpected TLVs in complete stage");
478 fr_tls_session_t *tls_session,
495 switch (reply->
code) {
497 RDEBUG2(
"Got tunneled Access-Accept");
509 switch (
vp->
da->attr) {
513 REDEBUG(
"Found %s with incorrect length. Expected %u, got %zu",
528 RDEBUG2(
"Got %s, tunneling it to the client in a challenge",
vp->
da->name);
541 REDEBUG(
"Got tunneled Access-Reject");
546 RDEBUG2(
"Got tunneled Access-Challenge");
562 REDEBUG(
"Unknown RADIUS packet type %d: rejecting tunneled user", reply->
code);
571 fr_tls_session_t *tls_session,
fr_pair_t *tlv_eap_payload)
579 RDEBUG2(
"Processing received EAP Payload");
597 RDEBUG2(
"Got tunneled request");
631 RWDEBUG2(
"No EAP-Identity found to start EAP conversation");
672 switch (
fake->reply->code) {
680 RDEBUG2(
"Tunneled authentication will be proxied to %pV", &
vp->data);
698 request->proxy->packet = talloc_steal(request->proxy,
fake->packet);
699 memset(&request->proxy->packet->src_ipaddr, 0,
700 sizeof(request->proxy->packet->src_ipaddr));
701 memset(&request->proxy->packet->src_ipaddr, 0,
702 sizeof(request->proxy->packet->src_ipaddr));
703 request->proxy->packet->src_port = 0;
704 request->proxy->packet->dst_port = 0;
719 tunnel,
false,
false,
false);
729 fake,
true,
false,
false);
742 REDEBUG(
"No tunneled reply was found, and the request was not proxied: rejecting the user");
786 RHEXDUMP3((
uint8_t const *) binding,
sizeof(*binding),
"Crypto-Binding TLV for Compound MAC calculation");
787 RHEXDUMP3(cmac,
sizeof(cmac),
"Received Compound MAC");
790 if (memcmp(binding->
compound_mac, cmac,
sizeof(cmac))) {
791 RDEBUG2(
"Crypto-Binding TLV mismatch");
793 sizeof(binding->
compound_mac),
"Calculated Compound MAC");
807 memset(&my_binding, 0,
sizeof(my_binding));
826 binding = &my_binding;
831 switch (
vp->
da->attr) {
845 if (
vp->vp_length >=
sizeof(binding->
nonce)) {
846 memcpy(binding->
nonce,
vp->vp_octets,
vp->vp_length);
861 t->
pac.expired =
false;
866 RDEBUG2(
"only able to serve Tunnel PAC's, ignoring request");
872 RDEBUG2(
"ignoring unknown EAP-FAST-PAC-TLV %pP",
vp);
876 RDEBUG2(
"ignoring non-EAP-FAST TLV %pP",
vp);
911 data_len = tls_session->clean_out.used;
912 tls_session->clean_out.used = 0;
913 data = tls_session->clean_out.data;
927 if (strstr(SSL_CIPHER_description(SSL_get_current_cipher(tls_session->ssl),
928 buf,
sizeof(buf)),
"Au=None")) {
930 RDEBUG2(
"Using anonymous provisioning");
936 if (SSL_session_reused(tls_session->ssl)) {
937 RDEBUG2(
"Session Resumed from PAC");
940 RDEBUG2(
"Using authenticated provisioning");
968 RDEBUG2(
"Got Tunneled FAST TLVs");
999 RDEBUG2(
"Peer requires new PAC");
1012 if (t->
pac.type && t->
pac.expired) {
1013 REDEBUG(
"Rejecting expired PAC.");
1019 REDEBUG(
"Rejecting unauthenticated provisioning");
1028 #define EAPTLS_MPPE_KEY_LEN 32
1037 RERROR(
"Internal sanity check failed in EAP-FAST at %d", t->
stage);
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
eap_packet_t * response
Packet we received from the peer.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define FR_MSCHAP_MPPE_RECV_KEY
fr_radius_packet_code_t
RADIUS packet codes.
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
@ FR_RADIUS_CODE_STATUS_CLIENT
RFC2865/RFC5997 - Status Server (response)
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
#define VENDORPEC_MICROSOFT
#define FR_MSCHAP_MPPE_SEND_KEY
#define FR_MSCHAP2_SUCCESS
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_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.
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
#define REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK
#define REQUEST_DATA_EAP_TUNNEL_CALLBACK
Structure to represent packet format of eap on wire
ssize_t eap_fast_decode_pair(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)
FIXME do something with mandatory.
static int eap_fast_verify(request_t *request, fr_tls_session_t *tls_session, uint8_t const *data, unsigned int data_len)
static fr_radius_packet_code_t eap_fast_eap_payload(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session, fr_pair_t *tlv_eap_payload)
static void eap_fast_send_identity_request(request_t *request, fr_tls_session_t *tls_session, eap_session_t *eap_session)
#define EAPTLS_MPPE_KEY_LEN
void eap_fast_tlv_append(fr_tls_session_t *tls_session, fr_dict_attr_t const *tlv, bool mandatory, int length, void const *data)
static void eap_fast_append_result(fr_tls_session_t *tls_session, fr_radius_packet_code_t code)
static void eap_fast_send_error(fr_tls_session_t *tls_session, int error)
static fr_radius_packet_code_t eap_fast_crypto_binding(request_t *request, UNUSED eap_session_t *eap_session, fr_tls_session_t *tls_session, eap_tlv_crypto_binding_tlv_t *binding)
static void eap_fast_init_keys(request_t *request, fr_tls_session_t *tls_session)
RFC 4851 section 5.1 - EAP-FAST Authentication Phase 1: Key Derivations.
fr_radius_packet_code_t eap_fast_process(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
static rlm_rcode_t process_reply(UNUSED eap_session_t *eap_session, fr_tls_session_t *tls_session, request_t *request, fr_packet_t *reply, fr_pair_list_t *reply_list)
static void eap_fast_send_pac_tunnel(request_t *request, fr_tls_session_t *tls_session)
static void eap_fast_append_crypto_binding(request_t *request, fr_tls_session_t *tls_session)
static fr_radius_packet_code_t eap_fast_process_tlvs(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session, fr_pair_list_t *fast_vps)
static void eap_fast_update_icmk(request_t *request, fr_tls_session_t *tls_session, uint8_t *msk)
RFC 4851 section 5.2 - Intermediate Compound Key Derivations.
HIDDEN fr_dict_attr_t const * attr_eap_fast_result
HIDDEN fr_dict_attr_t const * attr_eap_fast_nak
#define EAP_FAST_TLV_MANDATORY
HIDDEN fr_dict_attr_t const * attr_proxy_to_realm
unsigned char aad[PAC_A_ID_LENGTH]
eap_fast_pac_attr_lifetime_t lifetime
eap_fast_pac_attr_hdr_t hdr
HIDDEN fr_dict_attr_t const * attr_eap_fast_pac_key
uint8_t client_challenge[MD5_DIGEST_LENGTH]
HIDDEN fr_dict_attr_t const * attr_eap_fast_pac_info_tlv
eap_fast_pac_attr_lifetime_t lifetime
HIDDEN fr_dict_attr_t const * attr_eap_fast_error
eap_fast_pac_attr_pac_key_t key
eap_fast_keyblock_t * keyblock
eap_fast_pac_attr_hdr_t hdr
fr_time_delta_t pac_lifetime
@ EAP_FAST_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST
HIDDEN fr_dict_attr_t const * attr_eap_fast_pac_info_pac_type
#define EAP_FAST_SIMCK_LEN
HIDDEN fr_dict_attr_t const * attr_eap_fast_pac_info_pac_lifetime
eap_fast_pac_attr_a_id_info_t a_id_info
HIDDEN fr_dict_attr_t const * attr_ms_chap_peer_challenge
#define EAP_FAST_TLV_TYPE
uint8_t data[PAC_A_ID_INFO_LENGTH]
int default_provisioning_method
eap_fast_pac_attr_hdr_t hdr
unsigned char iv[EVP_MAX_IV_LENGTH]
uint8_t data[PAC_KEY_LENGTH]
eap_fast_pac_attr_hdr_t hdr
HIDDEN fr_dict_attr_t const * attr_eap_fast_intermediate_result
unsigned char tag[EVP_GCM_TLS_TAG_LEN]
HIDDEN fr_dict_attr_t const * attr_eap_fast_pac_tlv
eap_fast_pac_attr_hdr_t hdr
eap_fast_attr_pac_opaque_t opaque
struct eap_fast_tunnel_t::@158 isk
HIDDEN fr_dict_attr_t const * attr_eap_fast_eap_payload
#define EAP_FAST_TLV_RESULT_SUCCESS
eap_fast_pac_attr_pac_type_t type
HIDDEN fr_dict_attr_t const * attr_eap_fast_crypto_binding
#define EAP_FAST_ERR_UNEXPECTED_TLV
HIDDEN fr_dict_attr_t const * attr_eap_fast_vendor_specific
eap_fast_pac_attr_hdr_t hdr
HIDDEN fr_dict_t const * dict_eap_fast
uint8_t data[PAC_A_ID_LENGTH]
char const * authority_identity
eap_fast_attr_pac_info_t info
struct eap_fast_tunnel_t::@159 pac
eap_fast_pac_attr_a_id_t a_id
eap_fast_pac_attr_hdr_t hdr
uint8_t server_challenge[MD5_DIGEST_LENGTH]
uint8_t data[sizeof(eap_fast_attr_pac_opaque_plaintext_t) *2]
eap_fast_pac_attr_pac_type_t type
@ EAP_FAST_AUTHENTICATION
@ EAP_FAST_CRYPTOBIND_CHECK
@ EAP_FAST_TLS_SESSION_HANDSHAKE
@ EAP_FAST_PROVISIONING_ANON
@ EAP_FAST_PROVISIONING_AUTH
HIDDEN fr_dict_attr_t const * attr_eap_fast_pac_opaque_tlv
eap_fast_pac_attr_pac_key_t key
#define EAP_FAST_TLV_RESULT_FAILURE
HIDDEN fr_dict_attr_t const * attr_eap_fast_pac_a_id
uint8_t const * pac_opaque_key
HIDDEN fr_dict_attr_t const * attr_eap_fast_pac_acknowledge
void eap_fast_tls_gen_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
int eap_fast_encrypt(uint8_t const *plaintext, size_t plaintext_len, uint8_t const *aad, size_t aad_len, uint8_t const *key, uint8_t *iv, unsigned char *ciphertext, uint8_t *tag)
USES_APPLE_DEPRECATED_API void T_PRF(unsigned char const *secret, unsigned int secret_len, char const *prf_label, unsigned char const *seed, unsigned int seed_len, unsigned char *out, unsigned int out_len)
Crypto function declarations.
int fr_hmac_sha1(uint8_t digest[static SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen, uint8_t const *key, size_t key_len)
Calculate HMAC using internal SHA1 implementation.
HIDDEN fr_dict_attr_t const * attr_ms_mppe_send_key
HIDDEN fr_dict_attr_t const * attr_ms_mppe_recv_key
HIDDEN fr_dict_attr_t const * attr_freeradius_proxied_to
HIDDEN fr_dict_attr_t const * attr_eap_msk
HIDDEN fr_dict_attr_t const * attr_eap_emsk
HIDDEN fr_dict_attr_t const * attr_eap_message
HIDDEN fr_dict_attr_t const * attr_eap_type
unlang_action_t eap_virtual_server(request_t *request, eap_session_t *eap_session, CONF_SECTION *server_cs)
Run a subrequest through a virtual server.
void eap_add_reply(request_t *request, fr_dict_attr_t const *da, uint8_t const *value, int len)
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
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 RHEXDUMP3(_data, _len, _fmt,...)
@ L_DBG_LVL_1
Highest priority debug messages (-x).
void fr_packet_free(fr_packet_t **packet_p)
Free a fr_packet_t.
#define MD5_DIGEST_LENGTH
@ FR_TYPE_TLV
Contains nested attributes.
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
int fr_pair_list_copy_by_da(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from, fr_dict_attr_t const *da, unsigned int count)
Duplicate pairs in a list matching the specified da.
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.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
fr_pair_t * fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Create a new valuepair.
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_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, bool tainted)
Convert string value to native attribute value.
int fr_pair_raw_afrom_pair(fr_pair_t *vp, uint8_t const *data, size_t data_len)
Mark malformed attribute as raw.
int fr_pair_prepend_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and prepend)
static fr_dict_attr_t const * attr_ms_chap_challenge
static fr_dict_attr_t const * attr_user_name
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_INVALID
The module considers the request invalid.
@ RLM_MODULE_OK
The module is OK, continue.
@ RLM_MODULE_REJECT
Immediately reject the request.
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
#define request_alloc_internal(_ctx, _args)
Allocate a new internal request.
Optional arguments for initialising requests.
#define request_data_add(_request, _unique_ptr, _unique_int, _opaque, _free_on_replace, _free_on_parent, _persist)
Add opaque data to a request_t.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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.
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
#define fr_time_delta_wrap(_time)
#define fr_time_wrap(_time)
#define fr_time_lteq(_a, _b)
#define fr_time_eq(_a, _b)
#define fr_time_add(_a, _b)
Add a time/time delta together.
unsigned int code
Packet code (type).
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
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.
int fr_tls_utils_keyblock_size_get(request_t *request, SSL *ssl)
Returns the OpenSSL keyblock size.
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