The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
rlm_eap_psk.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 170ddc549833688b444471d7b2a59fb562eb7bfd $
19 *
20 * @file rlm_eap_psk.c
21 * @brief EAP-PSK (RFC 4764) interface to the EAP module
22 *
23 * The protocol state machine, message parsing, and cryptography all live
24 * in the eap_psk process module (src/process/eap_psk). This submodule
25 * derives the next Packet-Type from the session state, pushes the request
26 * into the configured eap-psk virtual server, and translates the reply
27 * Packet-Type back into an EAP result.
28 *
29 * @copyright 2026 Network RADIUS SAS (legal@networkradius.com)
30 */
31RCSID("$Id: 170ddc549833688b444471d7b2a59fb562eb7bfd $")
32
33#include <freeradius-devel/server/base.h>
34#include <freeradius-devel/server/module_rlm.h>
35#include <freeradius-devel/server/virtual_servers.h>
36#include <freeradius-devel/unlang/module.h>
37#include <freeradius-devel/unlang/call.h>
38#include <freeradius-devel/protocol/eap/psk/freeradius.h>
39
40#include "crypto.h"
41
42typedef struct {
43 virtual_server_t *virtual_server; //!< eap-psk virtual server providing the
44 ///< policy sections for the exchange.
46
48 { FR_CONF_OFFSET_TYPE_FLAGS("virtual_server", FR_TYPE_VOID, CONF_FLAG_REQUIRED, rlm_eap_psk_t, virtual_server),
51 .process_module_name = "eap_psk",
52 } },
53
55};
56
57static fr_dict_t const *dict_eap_psk;
58static fr_dict_t const *dict_radius;
59
62 { .out = &dict_eap_psk, .base_dir = "eap/psk", .proto = "eap-psk" },
63 { .out = &dict_radius, .proto = "radius" },
65};
66
69
72 { .out = &attr_ms_mppe_send_key, .name = "Vendor-Specific.Microsoft.MPPE-Send-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
73 { .out = &attr_ms_mppe_recv_key, .name = "Vendor-Specific.Microsoft.MPPE-Recv-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
75};
76
77/*
78 * The MSK is split into a 32-byte MS-MPPE-Recv-Key and a 32-byte
79 * MS-MPPE-Send-Key, as is done with all other EAP methods.
80 */
81#define EAP_PSK_MPPE_KEY_LEN 32
82
83/** Translate the state machine's reply Packet-Type into an EAP result
84 *
85 * Runs after the virtual server (and the eap_psk process module inside
86 * of it) finishes with this round.
87 */
89{
90 eap_session_t *eap_session = eap_session_get(request->parent);
91 eap_psk_session_t *session = eap_session->opaque ?
92 talloc_get_type_abort(eap_session->opaque, eap_psk_session_t) : NULL;
93
94 switch (request->reply->code) {
95 case FR_PACKET_TYPE_VALUE_SUCCESS:
96 if (session && (session->state == EAP_PSK_STATE_DONE)) {
97 /*
98 * Deliver the keying material. The MSK is split
99 * into the MS-MPPE-Recv-Key and MS-MPPE-Send-Key
100 * halves.
101 */
102 eap_add_reply(request->parent, attr_ms_mppe_recv_key,
103 session->msk, EAP_PSK_MPPE_KEY_LEN);
104 eap_add_reply(request->parent, attr_ms_mppe_send_key,
106
108 }
110
111 /*
112 * The message failed validation and was not processed
113 * (RFC 4764 Section 4.1). A true silent discard cannot be
114 * expressed through the EAP module, which sends a canned
115 * EAP-Failure and discards the session on any failure
116 * result, so an invalid message ends the session, as with
117 * every other EAP method.
118 */
119 case FR_PACKET_TYPE_VALUE_DO_NOT_RESPOND:
121
122 case FR_PACKET_TYPE_VALUE_FAILURE:
124
125 default:
127 }
128}
129
130/** Derive the next Packet-Type from the session state, and enter the virtual server
131 *
132 */
133static unlang_action_t mod_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
134{
135 rlm_eap_psk_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_psk_t);
136 eap_session_t *eap_session = eap_session_get(request->parent);
137 eap_psk_session_t *session;
138
139 if (!eap_session->opaque) {
140 request->packet->code = FR_PACKET_TYPE_VALUE_IDENTITY_REQUEST;
141 goto yield;
142 }
143
144 /*
145 * Every EAP-PSK message from the peer must be of type
146 * EAP-PSK, and carry at least a Flags byte.
147 */
148 if ((eap_session->this_round->response->type.num != FR_EAP_METHOD_PSK) ||
149 !eap_session->this_round->response->type.data ||
150 (eap_session->this_round->response->type.length < 1)) {
151 REDEBUG("Invalid EAP-PSK response");
153 }
154
155 session = talloc_get_type_abort(eap_session->opaque, eap_psk_session_t);
156 switch (session->state) {
158 request->packet->code = FR_PACKET_TYPE_VALUE_IDENTITY_RESPONSE;
159 break;
160
162 request->packet->code = FR_PACKET_TYPE_VALUE_RESULT_ACKNOWLEDGEMENT;
163 break;
164
165 default:
166 REDEBUG("Unexpected EAP-PSK session state");
168 }
169
170yield:
171 /*
172 * Once the state machine finishes with this round, translate
173 * the reply Packet-Type into an EAP result.
174 */
175 (void)unlang_module_yield(request, mod_encode, NULL, 0, NULL);
176
177 if (unlang_call_push(NULL, request, virtual_server_cs(inst->virtual_server), UNLANG_SUB_FRAME) < 0) {
180 }
181
183}
184
186{
187 eap_session_t *eap_session = eap_session_get(request->parent);
188
189 fr_assert(eap_session != NULL);
190
191 eap_session->process = mod_process;
192
193 return eap_session->process(p_result, mctx, request);
194}
195
196/*
197 * The module name should be the only globally exported symbol.
198 * That is, everything else should be 'static'.
199 */
202 .common = {
203 .magic = MODULE_MAGIC_INIT,
204 .name = "eap_psk",
205 .inst_size = sizeof(rlm_eap_psk_t),
207 },
208 .provides = { FR_EAP_METHOD_PSK },
209 .session_init = mod_session_init, /* Initialise a new EAP session */
210 .namespace = &dict_eap_psk
211};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
#define RCSID(id)
Definition build.h:560
#define UNUSED
Definition build.h:384
unlang_action_t unlang_call_push(unlang_result_t *p_result, request_t *request, CONF_SECTION *server_cs, bool top_frame)
Push a virtual server CONF_SECTION as a call frame onto the stack.
Definition call.c:151
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:669
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:623
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:429
#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
Definition cf_parse.h:238
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:606
eap_type_data_t type
Definition compose.h:38
eap_packet_t * response
Packet we received from the peer.
Definition compose.h:48
Constants, session state, and crypto declarations for EAP-PSK (RFC 4764)
@ EAP_PSK_STATE_RESULT_INDICATION_SENT
Definition crypto.h:88
@ EAP_PSK_STATE_DONE
Definition crypto.h:89
@ EAP_PSK_STATE_IDENTITY_REQUEST_SENT
Definition crypto.h:87
eap_psk_state_t state
Definition crypto.h:99
uint8_t msk[EAP_PSK_MSK_LEN]
Definition crypto.h:111
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
eap_type_t num
Definition types.h:110
size_t length
Definition types.h:111
uint8_t * data
Definition types.h:112
@ FR_EAP_METHOD_PSK
Definition types.h:93
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
Definition interpret.c:2433
#define UNLANG_SUB_FRAME
Definition interpret.h:37
void eap_add_reply(request_t *request, fr_dict_attr_t const *da, uint8_t const *value, int len)
Definition base.c:345
static eap_session_t * eap_session_get(request_t *request)
Definition session.h:85
void * opaque
Opaque data used by EAP methods.
Definition session.h:63
module_method_t process
Callback that should be used to process the next round.
Definition session.h:65
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
Definition session.h:60
Tracks the progress of a single session of any EAP method.
Definition session.h:41
@ FR_TYPE_VOID
User data.
@ FR_TYPE_OCTETS
Raw octets.
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
static const conf_parser_t config[]
Definition base.c:162
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RETURN_UNLANG_HANDLED
Definition rcode.h:65
#define RETURN_UNLANG_INVALID
Definition rcode.h:66
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
#define RETURN_UNLANG_REJECT
Definition rcode.h:62
#define RETURN_UNLANG_OK
Definition rcode.h:64
fr_dict_autoload_t rlm_eap_psk_dict[]
Definition rlm_eap_psk.c:61
static unlang_action_t mod_encode(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
Translate the state machine's reply Packet-Type into an EAP result.
Definition rlm_eap_psk.c:88
virtual_server_t * virtual_server
eap-psk virtual server providing the policy sections for the exchange.
Definition rlm_eap_psk.c:43
static unlang_action_t mod_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Derive the next Packet-Type from the session state, and enter the virtual server.
static fr_dict_t const * dict_radius
Definition rlm_eap_psk.c:58
static fr_dict_t const * dict_eap_psk
Definition rlm_eap_psk.c:57
#define EAP_PSK_MPPE_KEY_LEN
Definition rlm_eap_psk.c:81
static fr_dict_attr_t const * attr_ms_mppe_send_key
Definition rlm_eap_psk.c:67
fr_dict_attr_autoload_t rlm_eap_psk_dict_attr[]
Definition rlm_eap_psk.c:71
rlm_eap_submodule_t rlm_eap_psk
static fr_dict_attr_t const * attr_ms_mppe_recv_key
Definition rlm_eap_psk.c:68
static conf_parser_t submodule_config[]
Definition rlm_eap_psk.c:47
static unlang_action_t mod_session_init(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:293
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.
Definition module.c:431
eap_aka_sim_process_conf_t * inst
module_t common
Common fields provided by all modules.
Definition submodule.h:50
Interface exported by EAP submodules.
Definition submodule.h:49
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.