46#include <freeradius-devel/eap/base.h>
47#include <freeradius-devel/eap/types.h>
48#include <freeradius-devel/server/process_types.h>
49#include <freeradius-devel/server/virtual_servers.h>
50#include <freeradius-devel/server/pair.h>
51#include <freeradius-devel/unlang/module.h>
52#include <freeradius-devel/util/debug.h>
53#include <freeradius-devel/protocol/eap/psk/freeradius.h>
55#include <openssl/rand.h>
112#define YIELD_OR_RESUME(_section, _resume) \
114 module_ctx_t our_mctx; \
115 if (inst->sections._section) { \
116 return unlang_module_yield_to_section(&session->section_result, request, \
117 inst->sections._section, RLM_MODULE_NOOP, \
118 _resume, NULL, 0, session); \
120 session->section_result.rcode = RLM_MODULE_NOOP; \
122 our_mctx.rctx = session; \
123 return _resume(p_result, &our_mctx, request); \
131 uint8_t const *body,
size_t body_len)
147 if (body_len > 0) memcpy(p, body, body_len);
170 header[2] = (
uint8_t) (eap_len >> 8);
171 header[3] = (
uint8_t) (eap_len & 0xff);
192 if (
vp && (
vp->vp_uint32 == FR_PACKET_TYPE_VALUE_FAILURE)) {
193 RDEBUG2(
"Policy overrides the silent discard, failing explicitly");
195 request->reply->code = FR_PACKET_TYPE_VALUE_FAILURE;
199 RDEBUG2(
"Silently discarding invalid message");
200 request->reply->code = FR_PACKET_TYPE_VALUE_DO_NOT_RESPOND;
214 request->reply->code = FR_PACKET_TYPE_VALUE_FAILURE;
249 id_s =
vp->vp_strvalue;
251 if (id_s[0] ==
'\0') {
252 REDEBUG(
"Server-Identity (ID_S) must not be empty");
258 RDEBUG2(
"Sending first message as \"%s\"", session->
id_s);
264 request->reply->code = FR_PACKET_TYPE_VALUE_SUCCESS;
281 eap_session->
opaque = session;
287 if (RAND_bytes(session->
rand_s,
sizeof(session->
rand_s)) != 1) {
288 REDEBUG(
"Failed generating RAND_S");
308 if (
vp && (
vp->vp_uint32 == FR_PACKET_TYPE_VALUE_FAILURE)) {
311 RDEBUG2(
"Policy rejected the peer");
316 request->reply->code = FR_PACKET_TYPE_VALUE_SUCCESS;
346 RDEBUG2(
"Policy rejected the peer");
363 RDEBUG2(
"No control.Password.PSK for Identity \"%pV\"",
374 REDEBUG(
"Password.PSK must be exactly %d octets, got %zu octets",
391 REDEBUG(
"MAC_P computation failed");
396 RDEBUG2(
"MAC_P is incorrect: the peer used the wrong key");
400 RDEBUG2(
"Peer authenticated (MAC_P valid)");
406 kdk, session->
rand_p) < 0) {
407 REDEBUG(
"Session-key derivation failed");
414 REDEBUG(
"MAC_S computation failed");
444 *p++ = (
uint8_t) (nonce >> 24);
445 *p++ = (
uint8_t) (nonce >> 16);
450 header,
sizeof(header), &plain, 1) < 0) {
451 REDEBUG(
"Protected-channel encryption failed");
476 uint8_t const *rand_s_echo, *rand_p, *mac_p, *id_p;
484 RDEBUG2(
"Second message is too short");
489 RDEBUG2(
"Second message has the wrong T flag");
493 rand_s_echo =
in + 1;
503 RDEBUG2(
"Second message did not echo RAND_S");
512 memcpy(session->
rand_p, rand_p,
sizeof(session->
rand_p));
513 memcpy(session->
mac_p, mac_p,
sizeof(session->
mac_p));
515 MEM(session->
id_p = talloc_memdup(session, id_p, id_p_len));
545 request->reply->code = FR_PACKET_TYPE_VALUE_SUCCESS;
563 uint8_t const *pchannel, *tag, *cipher;
572 RDEBUG2(
"Policy rejected the peer");
594 header,
sizeof(header), cipher, 1, tag) < 0) {
595 RDEBUG2(
"Protected-channel verification failed: mutual authentication failed");
601 RDEBUG2(
"Peer reported result %d (not success)", r);
605 RDEBUG2(
"Mutual authentication succeeded");
636 RDEBUG2(
"Fourth message is too short");
641 RDEBUG2(
"Fourth message has the wrong T flag");
646 RDEBUG2(
"Fourth message did not echo RAND_S");
655 if ((pchannel[0] != 0) || (pchannel[1] != 0) || (pchannel[2] != 0) || (pchannel[3] != 1)) {
656 RDEBUG2(
"Fourth message has an unexpected Nonce");
673 request->component =
"eap-psk";
674 request->module = NULL;
677 if (!request->parent || !(eap_session =
eap_session_get(request->parent))) {
678 REDEBUG(
"EAP-PSK requests must be run from within the EAP module");
682 switch (request->packet->code) {
683 case FR_PACKET_TYPE_VALUE_IDENTITY_REQUEST:
684 if (eap_session->
opaque)
goto bad_state;
687 case FR_PACKET_TYPE_VALUE_IDENTITY_RESPONSE:
692 case FR_PACKET_TYPE_VALUE_RESULT_ACKNOWLEDGEMENT:
699 REDEBUG(
"Invalid packet code %u for the current session state", request->packet->code);
721 .section =
SECTION_NAME(
"recv",
"Result-Acknowledgement"),
744 .inst_type =
"process_eap_psk_t",
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
#define CONF_PARSER_TERMINATOR
#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
Defines a CONF_PAIR to C data type mapping.
A section grouping multiple CONF_PAIR.
bool set_request_id
Whether the EAP-Method already set the next request ID.
eap_packet_t * response
Packet we received from the peer.
eap_packet_t * request
Packet we will send to the peer.
Contains a pair of request and response packets.
Constants, session state, and crypto declarations for EAP-PSK (RFC 4764)
#define EAP_PSK_MAX_ID_P_LEN
uint8_t emsk[EAP_PSK_EMSK_LEN]
@ EAP_PSK_STATE_RESULT_INDICATION_SENT
@ EAP_PSK_STATE_IDENTITY_REQUEST_SENT
#define EAP_PSK_PCHANNEL_LEN
#define EAP_PSK_FLAGS_THIRD
uint8_t rand_s[EAP_PSK_RAND_LEN]
uint8_t tek[EAP_PSK_TEK_LEN]
uint8_t mac_p[EAP_PSK_MAC_LEN]
As received, verified once the PSK is known.
#define EAP_PSK_PAYLOAD(_r)
#define EAP_PSK_FLAGS_SECOND
char * id_s
ID_S actually sent in the first message.
#define EAP_PSK_HEADER_LEN
uint8_t msk[EAP_PSK_MSK_LEN]
#define EAP_PSK_R_DONE_SUCCESS
#define EAP_PSK_FLAGS_FIRST
#define EAP_PSK_FLAGS_FOURTH
uint8_t rand_p[EAP_PSK_RAND_LEN]
uint8_t * id_p
ID_P the peer asserted in the second message.
#define EAP_PSK_NONCE_LEN
unlang_result_t section_result
Result of the last policy section.
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.
#define DICT_AUTOLOAD_TERMINATOR
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.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
static fr_dict_t const * dict_freeradius
fr_dict_attr_t const * attr_packet_type
static eap_session_t * eap_session_get(request_t *request)
void * opaque
Opaque data used by EAP methods.
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.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_OCTETS
Raw octets.
int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
Do a comparison of two authentication digests by comparing the FULL data.
unlang_mod_actions_t const mod_actions_authorize
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
module_instance_t const * mi
Instance of the module being instantiated.
void * rctx
Resume ctx that a module previously set.
Temporary structure to hold arguments for module calls.
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.
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.
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
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_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
static unlang_action_t mod_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static const virtual_server_compile_t compile_list[]
static conf_parser_t submodule_config[]
fr_process_module_t process_eap_psk
static unlang_action_t resume_send_identity_request(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Compose the first message once 'send Identity-Request' has run.
static int eap_psk_compose(eap_round_t *eap_round, uint8_t flags, uint8_t const rand_s[static EAP_PSK_RAND_LEN], uint8_t const *body, size_t body_len)
static void eap_psk_header(uint8_t header[static EAP_PSK_HEADER_LEN], uint8_t code, uint8_t id, size_t type_length, uint8_t flags, uint8_t const rand_s[static EAP_PSK_RAND_LEN])
static fr_dict_attr_t const * attr_rand_server
static unlang_action_t resume_recv_identity_response(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Verify MAC_P and build the third message once 'recv Identity-Response' has run.
CONF_SECTION * send_identity_request
static fr_dict_t const * dict_eap_psk
char const * identity
Default ID_S sent in the first message.
#define YIELD_OR_RESUME(_section, _resume)
static unlang_action_t state_identity_request(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Start the conversation: generate RAND_S and run 'send Identity-Request'.
process_eap_psk_sections_t sections
CONF_SECTION * recv_identity_response
static unlang_action_t resume_send_success(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Finish successfully once 'send Success' has run.
static fr_dict_attr_t const * attr_server_identity
CONF_SECTION * send_result_indication
CONF_SECTION * send_failure
static unlang_action_t state_result_acknowledgement(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Parse the fourth message and run 'recv Result-Acknowledgement'.
fr_dict_attr_autoload_t process_eap_psk_dict_attr[]
static unlang_action_t eap_psk_failure(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request, process_eap_psk_t const *inst, eap_psk_session_t *session)
static unlang_action_t resume_recv_result_acknowledgement(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Verify the protected result once 'recv Result-Acknowledgement' has run.
fr_dict_autoload_t process_eap_psk_dict[]
static fr_dict_attr_t const * attr_identity
static fr_dict_attr_t const * attr_rand_peer
CONF_SECTION * recv_result_acknowledgement
static unlang_action_t resume_send_result_indication(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Compose the third message once 'send Result-Indication' has run.
static unlang_action_t eap_psk_discard(unlang_result_t *p_result, request_t *request, eap_psk_session_t *session)
static fr_dict_attr_t const * attr_psk_password
static unlang_action_t state_identity_response(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Parse the second message and run 'recv Identity-Response'.
CONF_SECTION * send_success
static unlang_action_t resume_send_failure(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
int eap_psk_derive_keys(uint8_t tek[static EAP_PSK_TEK_LEN], uint8_t msk[static EAP_PSK_MSK_LEN], uint8_t emsk[static EAP_PSK_EMSK_LEN], uint8_t const kdk[static EAP_PSK_KDK_LEN], uint8_t const rand_p[static EAP_PSK_RAND_LEN])
Session-key derivation: expand RAND_P under KDK into nine output blocks.
int eap_psk_mac_s(uint8_t mac_s[static EAP_PSK_MAC_LEN], uint8_t const ak[static EAP_PSK_AK_LEN], uint8_t const *id_s, size_t id_s_len, uint8_t const rand_p[static EAP_PSK_RAND_LEN])
Compute MAC_S = CMAC-AES-128(AK, ID_S || RAND_P)
int eap_psk_pchannel_encrypt(uint8_t *cipher, uint8_t tag[static EAP_PSK_TAG_LEN], uint8_t const tek[static EAP_PSK_TEK_LEN], uint32_t nonce, uint8_t const *header, size_t header_len, uint8_t const *plain, size_t plain_len)
EAX encrypt for the protected channel (RFC 4764 Section 3.3)
int eap_psk_mac_p(uint8_t mac_p[static EAP_PSK_MAC_LEN], uint8_t const ak[static EAP_PSK_AK_LEN], uint8_t const *id_p, size_t id_p_len, uint8_t const *id_s, size_t id_s_len, uint8_t const rand_s[static EAP_PSK_RAND_LEN], uint8_t const rand_p[static EAP_PSK_RAND_LEN])
Compute MAC_P = CMAC-AES-128(AK, ID_P || ID_S || RAND_S || RAND_P)
int eap_psk_derive_ak_kdk(uint8_t ak[static EAP_PSK_AK_LEN], uint8_t kdk[static EAP_PSK_KDK_LEN], uint8_t const psk[static EAP_PSK_PSK_LEN])
Key setup: derive AK (counter 1) and KDK (counter 2) from the PSK.
int eap_psk_pchannel_decrypt(uint8_t *plain, uint8_t const tek[static EAP_PSK_TEK_LEN], uint32_t nonce, uint8_t const *header, size_t header_len, uint8_t const *cipher, size_t cipher_len, uint8_t const tag[static EAP_PSK_TAG_LEN])
EAX decrypt-and-verify for the protected channel (RFC 4764 Section 3.3)
static const conf_parser_t config[]
module_t common
Common fields for all loadable modules.
Common public symbol definition for all process modules.
#define pair_update_request(_attr, _da)
#define RETURN_UNLANG_HANDLED
#define RETURN_UNLANG_FAIL
#define RETURN_UNLANG_REJECT
@ RLM_MODULE_FAIL
Module failed, don't reply.
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
@ RLM_MODULE_REJECT
Immediately reject the request.
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
size_t inst_size
Size of the module's instance data.
void * data
Module's instance data.
#define pair_append_reply(_attr, _da)
Allocate and append a fr_pair_t to reply list.
eap_aka_sim_process_conf_t * inst
Stores an attribute, a value and various bits of other data.
#define talloc_get_type_abort_const
#define talloc_strdup(_ctx, _str)
#define fr_box_strvalue_len(_val, _len)
section_name_t const * section
Identifier for the section.
#define COMPILE_TERMINATOR
Processing sections which are allowed in this virtual server.