The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
state_machine.c
Go to the documentation of this file.
1/*
2 * This program is 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 (at
5 * 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 * @file src/lib/eap_aka_sim/state_machine.c
19 * @brief Implement a common state machine for EAP-SIM, EAP-AKA, EAP-AKA'.
20 *
21 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
22 *
23 * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 * @copyright 2019 The FreeRADIUS server project
25 * @copyright 2019 Network RADIUS (legal@networkradius.com)
26 */
27RCSID("$Id: 110332a2a9e84d765fb8210fdf97d6a6f282bdb3 $")
28#include <freeradius-devel/eap/base.h>
29#include <freeradius-devel/eap/types.h>
30#include <freeradius-devel/server/pair.h>
31#include <freeradius-devel/unlang/interpret.h>
32#include <freeradius-devel/unlang/module.h>
33#include <freeradius-devel/util/table.h>
34#include <freeradius-devel/util/rand.h>
35
36#include "base.h"
37#include "state_machine.h"
38#include "attrs.h"
39
40#ifndef EAP_TLS_MPPE_KEY_LEN
41# define EAP_TLS_MPPE_KEY_LEN 32
42#endif
43
44#define STATE(_x) static inline unlang_action_t state_ ## _x(unlang_result_t *p_result, \
45 module_ctx_t const *mctx, \
46 request_t *request)
47
48#define STATE_GUARD(_x) static unlang_action_t guard_ ## _x(unlang_result_t *p_result, \
49 module_ctx_t const *mctx, \
50 request_t *request)
51
52#define RESUME(_x) static inline unlang_action_t resume_ ## _x(unlang_result_t *p_result, \
53 module_ctx_t const *mctx, \
54 request_t *request)
55
56#define STATE_NO_RESULT(_x) \
57 static inline unlang_action_t state_ ## _x(UNUSED unlang_result_t *p_result, \
58 module_ctx_t const *mctx, \
59 request_t *request)
60
61#define STATE_GUARD_NO_RESULT(_x) \
62 static unlang_action_t guard_ ## _x(UNUSED unlang_result_t *p_result, \
63 module_ctx_t const *mctx, \
64 request_t *request)
65
66#define RESUME_NO_RESULT(_x) \
67 static inline unlang_action_t resume_ ## _x(UNUSED unlang_result_t *p_result, \
68 module_ctx_t const *mctx, \
69 request_t *request)
70
71
72#define STATE_TRANSITION(_x) guard_ ## _x(p_result, mctx, request)
73
74#define CALL_SECTION(_x) unlang_module_yield_to_section(&eap_aka_sim_session->result, \
75 request, \
76 inst->actions._x, \
77 RLM_MODULE_NOOP, \
78 resume_ ## _x, \
79 mod_signal, \
80 ~FR_SIGNAL_CANCEL, \
81 talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t))
82
83/*
84 * Declare all state and guard functions to
85 * avoid ordering issues.
86 */
101STATE_GUARD(common_challenge);
106STATE_GUARD(common_identity);
108
110 { L("INIT"), NULL },
111
112 { L("EAP-IDENTITY"), (void *)state_init },
113 { L("SIM-START"), (void *)state_sim_start },
114 { L("AKA-IDENTITY"), (void *)state_aka_identity },
115
116 { L("SIM-CHALLENGE"), (void *)state_sim_challenge },
117 { L("AKA-CHALLENGE"), (void *)state_aka_challenge },
118
119 { L("SUCCESS-NOTIFICATION"), (void *)state_common_success_notification },
120 { L("FAILURE-NOTIFICATION"), (void *)state_common_failure_notification },
121
122 { L("REAUTHENTICATION"), (void *)state_common_reauthentication },
123
124 { L("EAP-SUCCESS"), (void *)state_eap_success },
125 { L("EAP-FAILURE"), (void *)state_eap_failure }
126};
128
129/** Cancel a call to a submodule
130 *
131 * @param[in] mctx UNUSED.
132 * @param[in] request The current request.
133 * @param[in] action to perform.
134 */
135static void mod_signal(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
136{
137 RDEBUG2("Request cancelled - Destroying session");
138
139 /*
140 * Remove data from the request to
141 * avoid double free.
142 */
143 if (!fr_cond_assert(request_data_get(request, (void *)eap_aka_sim_state_machine_process, 0) == mctx->rctx)) return;
144
145 talloc_free(mctx->rctx);
146}
147
148/** Warn the user that the rcode they provided is being ignored in this section
149 *
150 */
151#define SECTION_RCODE_IGNORED \
152do { \
153 switch (eap_aka_sim_session->result.rcode) { \
154 case RLM_MODULE_USER_SECTION_REJECT: \
155 RWDEBUG("Ignoring rcode (%s)", \
156 fr_table_str_by_value(rcode_table, eap_aka_sim_session->result.rcode, "<invalid>")); \
157 break; \
158 default: \
159 break; \
160 } \
161} while(0)
162
163/** Trigger a state transition to FAILURE-NOTIFICATION if the section returned a failure code
164 *
165 */
166#define SECTION_RCODE_PROCESS \
167do { \
168 if (after_authentication(eap_aka_sim_session)) { \
169 switch (eap_aka_sim_session->result.rcode) { \
170 case RLM_MODULE_REJECT: \
171 case RLM_MODULE_DISALLOW: \
172 eap_aka_sim_session->failure_type = FR_NOTIFICATION_VALUE_TEMPORARILY_DENIED; \
173 return STATE_TRANSITION(common_failure_notification); \
174 case RLM_MODULE_NOTFOUND: \
175 eap_aka_sim_session->failure_type = FR_NOTIFICATION_VALUE_NOT_SUBSCRIBED; \
176 return STATE_TRANSITION(common_failure_notification); \
177 case RLM_MODULE_INVALID: \
178 case RLM_MODULE_FAIL: \
179 eap_aka_sim_session->failure_type = FR_NOTIFICATION_VALUE_GENERAL_FAILURE_AFTER_AUTHENTICATION;\
180 return STATE_TRANSITION(common_failure_notification); \
181 default: \
182 break; \
183 } \
184 } else { \
185 switch (eap_aka_sim_session->result.rcode) { \
186 case RLM_MODULE_USER_SECTION_REJECT: \
187 REDEBUG("Section rcode (%s) indicates we should reject the user", \
188 fr_table_str_by_value(rcode_table, eap_aka_sim_session->result.rcode, "<INVALID>")); \
189 return STATE_TRANSITION(common_failure_notification); \
190 default: \
191 break; \
192 } \
193 } \
194} while(0)
195
196/** Print debugging information, and write new state to eap_aka_sim_session->state
197 *
198 */
199static inline CC_HINT(always_inline) void state_set(request_t *request,
201 module_method_t new_state)
202{
204
205 if (new_state != old_state) {
206 RDEBUG2("Changed state %s -> %s",
207 fr_table_str_by_value(aka_sim_state_table, (void *)old_state, "<unknown>"),
208 fr_table_str_by_value(aka_sim_state_table, (void *)new_state, "<unknown>"));
209 } else {
210 RDEBUG2("Reentering state %s",
211 fr_table_str_by_value(aka_sim_state_table, (void *)old_state, "<unknown>"));
212 }
213
214 eap_aka_sim_session->state = new_state;
215}
216#define STATE_SET(_new_state) state_set(request, talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t), state_ ## _new_state)
217
218/** Determine if we're after authentication
219 *
220 */
225
226/** Print out the error the client returned
227 *
228 */
229static inline CC_HINT(always_inline) void client_error_debug(request_t *request)
230{
231 fr_pair_t *vp;
232
233 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_client_error_code);
234 if (!vp) {
235 REDEBUG("Peer has not supplied a AT_ERROR_CODE");
236 } else {
237 REDEBUG("Peer rejected request with error: %i (%pV)", vp->vp_uint16, &vp->data);
238 }
239}
240
241/** Sync up what identity we're requesting with attributes in the reply
242 *
243 */
245{
246 bool set_by_user = false;
247
248 /*
249 * Check if the user included any of the
250 * ID req attributes. If they did, use
251 * them to inform what we do next, and
252 * then delete them so they don't screw
253 * up any of the other code.
254 */
255 fr_pair_list_foreach(&request->reply_pairs, vp) {
258 found:
259 set_by_user = true;
260 RDEBUG2("Previous section added reply.%pP, will request additional identity", vp);
261 fr_pair_delete(&request->reply_pairs, vp);
262 }
265 goto found;
266 }
267 else if (vp->da == attr_eap_aka_sim_any_id_req) {
269 goto found;
270 }
271 }
272
273 return set_by_user;
274}
275
276/** Based on the hint byte in the identity, add &Identity-Type and &Method-Hint attributes
277 *
278 */
280 request_t *request, char const *identity)
281{
284
285 /*
286 * Process the identity that we received.
287 */
288 if (fr_aka_sim_id_type(&type, &method,
289 identity, talloc_array_length(identity) - 1) < 0) {
290 RPWDEBUG2("Failed parsing identity, continuing anyway");
291 }
292
293 /*
294 * Map the output from the generic ID parser
295 * function to specific EAP-AKA internal
296 * attributes in the subrequest.
297 */
299 fr_pair_t *vp = NULL;
300
302 switch (type) {
304 vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_PERMANENT;
305 break;
306
308 vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_PSEUDONYM;
309 break;
310
312 vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_FASTAUTH;
313 break;
314
315 default:
316 fr_assert(0);
317 }
318 }
319
320 /*
321 * Map the output from the generic ID parser
322 * function to specific EAP-AKA internal
323 * attributes in the subrequest.
324 */
325 if (method != AKA_SIM_METHOD_HINT_UNKNOWN) {
326 fr_pair_t *vp = NULL;
327
329 switch (method) {
331 vp->vp_uint32 = FR_METHOD_HINT_VALUE_AKA_PRIME;
332 break;
333
335 vp->vp_uint32 = FR_METHOD_HINT_VALUE_AKA;
336 break;
337
339 vp->vp_uint32 = FR_METHOD_HINT_VALUE_SIM;
340 break;
341
342 default:
343 fr_assert(0);
344 }
345 }
346
347 if (type_p) *type_p = type;
348 if (method_p) *method_p = method;
349}
350
351/** Add an Identity Request attribute to the reply
352 *
353 * Verify the progression of identity requests is valid.
354 *
355 * @param[in] request The current request.
356 * @param[in] eap_aka_sim_session The current eap_aka_sim_session.
357 * @return
358 * - 0 on success.
359 * - -1 on failure (progression of identities was not valid).
360 */
362{
363 fr_pair_t *vp;
364
365 switch (eap_aka_sim_session->id_req) {
366 /*
367 * This is allowed for EAP-SIM.
368 *
369 * The EAP-SIM-Start packet gets used both for "version negotiation" and
370 * for request identities, so for EAP-SIM it's perfectly acceptable
371 * to send four Sim-Start packets:
372 *
373 * - No ID
374 * - Any ID
375 * - Fullauth ID
376 * - Permanent ID
377 *
378 * We need to represent the starting state as separate from no id req,
379 * so that we can catch potential loops in the identity statate machine
380 */
383 id_out_of_order:
384 REDEBUG("Cannot send %s, already sent %s",
386 eap_aka_sim_session->id_req, "<INVALID>"),
388 eap_aka_sim_session->last_id_req, "<INVALID>"));
389 return -1;
390 }
391 break;
392
397 break;
398
399 default:
400 goto id_out_of_order;
401 }
403 vp->vp_bool = true;
404 break;
405
409 case AKA_SIM_NO_ID_REQ: /* Not sent anything before */
410 case AKA_SIM_ANY_ID_REQ: /* Last request was for any ID, but the re-auth ID was bad */
411 break;
412
413 default:
414 goto id_out_of_order;
415 }
417 vp->vp_bool = true;
418 break;
419
423 case AKA_SIM_NO_ID_REQ: /* Not sent anything before */
424 case AKA_SIM_ANY_ID_REQ: /* Last request was for any ID, but the re-auth ID was bad */
425 case AKA_SIM_FULLAUTH_ID_REQ: /* ...didn't understand the pseudonym either */
426 break;
427
428 default:
429 goto id_out_of_order;
430 }
432 vp->vp_bool = true;
433 break;
434
435 default:
436 fr_assert(0);
437 }
438
439 return 0;
440}
441
442/** Copy the incoming identity to the permanent identity attribute
443 *
444 * If the incoming ID really looks like a permanent ID, and we were
445 * told it was a permanent ID, then (optionally) trim the first byte
446 * to form the real permanent ID.
447 *
448 * Otherwise copy the entire incoming Identity to the
449 * &session-state.Permanent-Identity attribute.
450 *
451 * @param[in] request The current request.
452 * @param[in] in current identity.
453 * @param[in] eap_type The current eap_type.
454 * @param[in] strip_hint Whether to strip the hint byte off the permanent identity
455 */
457{
458 fr_aka_sim_id_type_t our_type;
459 fr_aka_sim_method_hint_t our_method, expected_method;
460 fr_pair_t *vp;
461
462 if (in->vp_length == 0) {
463 RDEBUG2("Not processing zero length identity");
464 return -1;
465 }
466
467 /*
468 * Not requested to strip hint, don't do anything
469 * fancy, just copy Identity -> Permanent-Identity.
470 */
471 if (!strip_hint) {
473 fr_pair_value_bstrndup(vp, in->vp_strvalue, in->vp_length, true);
474 return 0;
475 }
476
477 switch (eap_type) {
479 expected_method = AKA_SIM_METHOD_HINT_SIM;
480 break;
481
483 expected_method = AKA_SIM_METHOD_HINT_AKA;
484 break;
485
487 expected_method = AKA_SIM_METHOD_HINT_AKA_PRIME;
488 break;
489
490 default:
491 return -1;
492 }
493
494 /*
495 * First, lets see if this looks like an identity
496 * we can process.
497 *
498 * For now we allow all permanent identities no
499 * matter what EAP method.
500 *
501 * This is because we could be starting a different
502 * EAP method to the one the identity hinted,
503 * but we still want to strip the first byte.
504 */
505 if ((fr_aka_sim_id_type(&our_type, &our_method, in->vp_strvalue, in->vp_length) < 0) ||
506 (our_type != AKA_SIM_ID_TYPE_PERMANENT)) {
508 fr_pair_value_bstrndup(vp, in->vp_strvalue, in->vp_length, true);
509
510 RDEBUG2("%s has incorrect hint byte, expected '%c', got '%c'. "
511 "'hint' byte not stripped",
514 fr_aka_sim_hint_byte(our_type, our_method));
515 RINDENT();
516 RDEBUG2("session-state.%pP", vp);
517 REXDENT();
518 } else {
519 /*
520 * To get here the identity must be >= 1 and must have
521 * had the expected hint byte.
522 *
523 * Strip off the hint byte, and then add the permanent
524 * identity to the output list.
525 */
527 fr_pair_value_bstrndup(vp, in->vp_strvalue + 1, in->vp_length - 1, true);
528
529 RDEBUG2("Stripping 'hint' byte from %s", attr_eap_aka_sim_permanent_identity->name);
530 RINDENT();
531 RDEBUG2("session-state.%pP", vp);
532 REXDENT();
533 }
534
535 return 0;
536}
537
538/** Check &control.checkcode matches &reply.checkcode
539 *
540 * @param[in] request The current request.
541 * @return
542 * - 1 if the check was skipped.
543 * - 0 if the check was successful.
544 * - -1 if the check failed.
545 */
546static int checkcode_validate(request_t *request)
547{
548 fr_pair_t *peer_checkcode, *our_checkcode;
549 /*
550 * Checkcode validation
551 *
552 * The actual cryptographic calculations are
553 * done by the calling module, we just check
554 * the result.
555 */
556 our_checkcode = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_checkcode);
557 if (our_checkcode) {
558 /*
559 * If the peer doesn't include a checkcode then that
560 * means they don't support it, and we can't validate
561 * their view of the identity packets.
562 */
563 peer_checkcode = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_checkcode);
564 if (peer_checkcode) {
565 if (fr_pair_cmp(peer_checkcode, our_checkcode) == 0) {
566 RDEBUG2("Received AT_CHECKCODE matches calculated AT_CHECKCODE");
567 return 0;
568 } else {
569 REDEBUG("Received AT_CHECKCODE does not match calculated AT_CHECKCODE");
570 RHEXDUMP_INLINE2(peer_checkcode->vp_octets, peer_checkcode->vp_length, "Received");
571 RHEXDUMP_INLINE2(our_checkcode->vp_octets, our_checkcode->vp_length, "Expected");
572 return -1;
573 }
574 /*
575 * Only print something if we calculated a checkcode
576 */
577 } else {
578 RDEBUG2("Peer didn't include AT_CHECKCODE, skipping checkcode validation");
579 }
580 }
581 return 1;
582}
583
584/** Check &control.mac matches &reply.mac
585 *
586 * @param[in] request The current request.
587 * @return
588 * - 0 if the check was successful.
589 * - -1 if the check failed.
590 */
591static int mac_validate(request_t *request)
592{
593 fr_pair_t *peer_mac, *our_mac;
594 /*
595 * mac validation
596 *
597 * The actual cryptographic calculations are
598 * done by the calling module, we just check
599 * the result.
600 */
601 our_mac = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_mac);
602 if (!our_mac) {
603 REDEBUG("Missing control.%s", attr_eap_aka_sim_mac->name);
604 return -1;
605
606 }
607
608 /*
609 * If the peer doesn't include a mac then that
610 * means they don't support it, and we can't validate
611 * their view of the identity packets.
612 */
613 peer_mac = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_mac);
614 if (!peer_mac) {
615 REDEBUG("Peer didn't include AT_MAC");
616 return -1;
617 }
618
619 if (fr_pair_cmp(peer_mac, our_mac) != 0) {
620 REDEBUG("Received AT_MAC does not match calculated AT_MAC");
621 RHEXDUMP_INLINE2(peer_mac->vp_octets, peer_mac->vp_length, "Received");
622 RHEXDUMP_INLINE2(our_mac->vp_octets, our_mac->vp_length, "Expected");
623 return -1;
624 }
625
626 RDEBUG2("Received AT_MAC matches calculated AT_MAC");
627 return 0;
628}
629
630/** Set the crypto identity from a received identity
631 *
632 */
634 uint8_t const *identity, size_t len)
635{
636 RDEBUG3("Setting cryptographic identity to \"%pV\"", fr_box_strvalue_len((char const *)identity, len));
637
640 MEM(eap_aka_sim_session->keys.identity = talloc_memdup(eap_aka_sim_session, identity, len));
641
642}
643
644/** Resume after 'store session { ... }'
645 *
646 */
647RESUME(store_session)
648{
649 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
650
652 /*
653 * Store failed. Don't send fastauth id
654 */
657 break;
658
659 default:
660 break;
661 }
662
664
665 return eap_aka_sim_session->next(p_result, mctx, request);
666}
667
668/** Resume after 'store pseudonym { ... }'
669 *
670 * Stores session data if required.
671 */
672RESUME(store_pseudonym)
673{
674 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
675 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
676 fr_pair_t *vp;
677 fr_pair_t *new;
678
680 /*
681 * Store failed. Don't send pseudonym
682 */
685 break;
686
687 default:
688 break;
689 }
690
691 eap_aka_sim_session->result.rcode = RLM_MODULE_NOOP; /* Needed because we may call resume functions directly */
692
694
695 /*
696 * Generate fast-reauth data if we
697 * find a next_reauth_id pair in the
698 * reply list.
699 */
700 vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_eap_aka_sim_next_reauth_id);
701 if (vp) {
702 /*
703 * Generate a random fastauth string
704 */
705 if (vp->vp_length == 0) {
706 char *identity;
707
709 RWDEBUG("Found empty Next-Reauth-Id, and told not to generate one. "
710 "Skipping store session { ... } section");
711
712 goto done;
713 }
714
715 MEM(identity = talloc_array(vp, char, inst->ephemeral_id_length + 2));
716 switch (eap_aka_sim_session->type) {
718 identity[0] = (char)ID_TAG_SIM_FASTAUTH;
719 break;
720
722 identity[0] = (char)ID_TAG_AKA_FASTAUTH;
723 break;
724
726 identity[0] = (char)ID_TAG_AKA_PRIME_FASTAUTH;
727 break;
728
729 default:
730 break;
731 }
732 fr_rand_str((uint8_t *)identity + 1, inst->ephemeral_id_length, 'a');
733 identity[talloc_array_length(identity) - 1] = '\0';
734
735 fr_value_box_bstrdup_buffer_shallow(NULL, &vp->data, NULL, identity, false);
736 }
738 fr_pair_value_memdup(new, (uint8_t const *)vp->vp_strvalue, vp->vp_length, vp->vp_tainted);
739
741 vp->vp_strvalue, vp->vp_length));
742
743 switch (eap_aka_sim_session->type) {
744 /*
745 * AKA and SIM use the original MK for session resumption.
746 */
750
754 false);
755 break;
756 /*
757 * AKA' KDF 1 generates an additional key k_re
758 * which is used for reauthentication instead
759 * of the MK.
760 */
763
767 false); /* truncates */
768 break;
769
770 default:
771 fr_assert(0);
772 break;
773 }
774
775 /*
776 * If the counter already exists in session
777 * state increment by 1, otherwise, add the
778 * attribute and set to zero.
779 */
780 vp = fr_pair_find_by_da_nested(&request->session_state_pairs, NULL, attr_eap_aka_sim_counter);
781 if (vp) {
782 vp->vp_uint16++;
783 /*
784 * Will get incremented by 1 in
785 * reauthentication_send, so when
786 * used, it'll be 1 (as per the standard).
787 */
788 } else {
790 vp->vp_uint16 = 0;
791 }
792
793 return CALL_SECTION(store_session);
794 }
795
796 /*
797 * We didn't store any fast-reauth data
798 */
799done:
800 return eap_aka_sim_session->next(p_result, mctx, request);
801}
802
803/** Implements a set of states for storing pseudonym and fastauth identities
804 *
805 * At the end of challenge or reauthentication rounds, the user may have specified
806 * a pseudonym and fastauth identity to return to the supplicant.
807 *
808 * Call the appropriate sections to persist those values.
809 *
810 * @param[out] p_result Result of calling the module.
811 * @param[in] mctx Module calling ctx.
812 * @param[in] request the current request.
813 * @param[in] eap_aka_sim_session the EAP session
814 * @param[in] next function to call after storing sessions and pseudonyms.
815 */
817 request_t *request,
819 module_method_t next)
820{
821 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
822 fr_pair_t *vp;
823 fr_pair_t *new;
824
826
828
829 eap_aka_sim_session->result.rcode = RLM_MODULE_NOOP; /* Reset the result code, as we may call resume functions directly */
830
831 vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_eap_aka_sim_next_pseudonym);
832 if (vp) {
833 /*
834 * Generate a random pseudonym string
835 */
836 if (vp->vp_length == 0) {
837 char *identity;
838
840 RWDEBUG("Found empty Pseudonym-Id, and told not to generate one. "
841 "Skipping store pseudonym { ... } section");
842
843 return resume_store_pseudonym(p_result, mctx, request);
844 }
845
846 MEM(identity = talloc_array(vp, char, inst->ephemeral_id_length + 2));
847 fr_rand_str((uint8_t *)identity + 1, inst->ephemeral_id_length, 'a');
848 switch (eap_aka_sim_session->type) {
850 identity[0] = (char)ID_TAG_SIM_PSEUDONYM;
851 break;
852
854 identity[0] = (char)ID_TAG_AKA_PSEUDONYM;
855 break;
856
858 identity[0] = (char)ID_TAG_AKA_PRIME_PSEUDONYM;
859 break;
860
861 default:
862 break;
863 }
864 identity[talloc_array_length(identity) - 1] = '\0';
865 fr_value_box_bstrdup_buffer_shallow(NULL, &vp->data, NULL, identity, false);
866 }
869
871 vp->vp_strvalue, vp->vp_length));
872 return CALL_SECTION(store_pseudonym);
873 }
874
875 return resume_store_pseudonym(p_result, mctx, request);
876}
877
878/** Resume after 'clear session { ... }'
879 *
880 */
881RESUME(clear_session)
882{
883 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
884
886
887 return eap_aka_sim_session->next(p_result, mctx, request);
888}
889
890/** Resume after 'clear pseudonym { ... }'
891 *
892 */
893RESUME(clear_pseudonym)
894{
895 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
896 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
897
899
900 /*
901 * Clear session (if one was stored)
902 */
904 fr_pair_t *vp;
905
907
909 fr_value_box_memdup(vp, &vp->data, NULL,
911 talloc_array_length(eap_aka_sim_session->fastauth_sent) - 1, true);
913
914 return CALL_SECTION(clear_session);
915 }
916
917 return eap_aka_sim_session->next(p_result, mctx, request);
918}
919
920/** Implements a set of states for clearing out pseudonym and fastauth identities
921 *
922 * If either a Challenge round or Reauthentication round fail, we need to clear
923 * any identities that were provided during those rounds, as the supplicant
924 * will have discarded them.
925 *
926 * @param[out] p_result Result of calling the module.
927 * @param[in] mctx module calling ctx.
928 * @param[in] request the current request.
929 * @param[in] eap_aka_sim_session the current EAP session
930 * @param[in] next function to call after clearing sessions and pseudonyms.
931 */
933 request_t *request,
935 module_method_t next)
936{
937 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
938
940
942
943 eap_aka_sim_session->result.rcode = RLM_MODULE_NOOP; /* Reset the result code, as we may call resume functions directly */
944
945 /*
946 * Clear out pseudonyms (if we sent one)
947 */
949 fr_pair_t *vp;
950
954
955 return CALL_SECTION(clear_pseudonym);
956 }
957
958 return resume_clear_pseudonym(p_result, mctx, request);
959}
960
961/** Export EAP-SIM/AKA['] attributes
962 *
963 * Makes any internal data available as attributes in the response.
964 * This allows test frameworks and the encoder to access any data they need without
965 * needing to look at the eap_aka_session_t.
966 */
968{
970
971 /*
972 * Set the subtype to identity request
973 */
975 subtype_vp->vp_uint16 = subtype;
976
978 fr_pair_list_foreach(&request->reply_pairs, vp) {
980 RWDEBUG("Silently discarding reply.%pP: Encrypted attributes not "
981 "allowed in this round", vp);
982 fr_pair_delete(&request->reply_pairs, vp);
983 }
984 }
985 }
986}
987
988static void CC_HINT(nonnull(1,2))
990 uint8_t const *hmac_extra_request, size_t hmac_extra_request_len,
991 uint8_t const *hmac_extra_response, size_t hmac_extra_response_len)
992{
993 fr_pair_t *vp;
994
995 /*
996 * Export keying material necessary for
997 * the encoder to encrypt and sign
998 * packets.
999 */
1000 if (hmac_extra_request && hmac_extra_request_len) {
1002 MEM(fr_pair_value_memdup(vp, hmac_extra_request, hmac_extra_request_len, true) == 0);
1003 }
1004
1005 if (hmac_extra_response && hmac_extra_response_len) {
1007 MEM(fr_pair_value_memdup(vp, hmac_extra_response, hmac_extra_response_len, true) == 0);
1008 }
1009
1014 true) == 0);
1015
1020 true) == 0);
1021}
1022
1023/** Called after 'store session { ... }' and 'store pseudonym { ... }'
1024 *
1025 */
1027 module_ctx_t const *mctx, request_t *request)
1028{
1030
1031 /*
1032 * Return reply attributes - AT_IV is handled automatically by the encoder
1033 */
1034 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_SIM_REAUTHENTICATION);
1035
1036 /*
1037 * 9.5. EAP-Request/SIM/Re-authentication
1038 *
1039 * AT_MAC MUST be included. No message-specific data is included in the
1040 * MAC calculation. See Section 10.14.
1041 *
1042 * 9.6. EAP-Response/SIM/Re-authentication
1043 *
1044 * The AT_MAC attribute MUST be included. For
1045 * EAP-Response/SIM/Re-authentication, the MAC code is calculated over
1046 * the following data: EAP packet| NONCE_S
1047 *
1048 * 9.7. EAP-Request/AKA-Reauthentication
1049 *
1050 * The AT_MAC attribute MUST be included. No message-specific data is
1051 * included in the MAC calculation, see Section 10.15.
1052 *
1053 * 9.8. EAP-Response/AKA-Reauthentication
1054 *
1055 * The AT_MAC attribute MUST be included. For
1056 * EAP-Response/AKA-Reauthentication, the MAC code is calculated over
1057 * the following data: EAP packet| NONCE_S.
1058 */
1060 NULL, 0,
1061 eap_aka_sim_session->keys.reauth.nonce_s,
1062 sizeof(eap_aka_sim_session->keys.reauth.nonce_s));
1063
1065}
1066
1067/** Called after 'store session { ... }' and 'store pseudonym { ... }'
1068 *
1069 */
1071{
1073
1074 /*
1075 * Encode the packet - AT_IV is handled automatically
1076 * by the encoder.
1077 */
1078 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_CHALLENGE);
1079
1080 /*
1081 * 9.3. EAP-Request/AKA-Challenge
1082 *
1083 * AT_MAC MUST be included. In EAP-Request/AKA-Challenge, there is no
1084 * message-specific data covered by the MAC, see Section 10.15.
1085 *
1086 * 9.4. EAP-Response/AKA-Challenge
1087 *
1088 * The AT_MAC attribute MUST be included. In
1089 * EAP-Response/AKA-Challenge, there is no message-specific data covered
1090 * by the MAC, see Section 10.15.
1091 */
1092 common_crypto_export(request, eap_aka_sim_session, NULL, 0, NULL, 0);
1093
1095}
1096
1097/** Called after 'store session { ... }' and 'store pseudonym { ... }'
1098 *
1099 */
1101{
1104 uint8_t *p = sres_cat;
1105
1106 /*
1107 * Encode the packet - AT_IV is handled automatically
1108 * by the encoder.
1109 */
1110 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_SIM_CHALLENGE);
1111
1112 memcpy(p, eap_aka_sim_session->keys.gsm.vector[0].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
1114 memcpy(p, eap_aka_sim_session->keys.gsm.vector[1].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
1116 memcpy(p, eap_aka_sim_session->keys.gsm.vector[2].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
1117
1118 /*
1119 * 9.3. EAP-Request/SIM/Challenge
1120 *
1121 * The AT_MAC attribute MUST be included. For
1122 * EAP-Request/SIM/Challenge, the MAC code is calculated over the
1123 * following data: EAP packet| NONCE_MT
1124 *
1125 * 9.4. EAP-Response/SIM/Challenge
1126 *
1127 * The AT_MAC attribute MUST be included. For EAP-
1128 * Response/SIM/Challenge, the MAC code is calculated over the following
1129 * data: EAP packet| n*SRES
1130 */
1132 eap_aka_sim_session->keys.gsm.nonce_mt, sizeof(eap_aka_sim_session->keys.gsm.nonce_mt),
1133 sres_cat, sizeof(sres_cat));
1134
1136}
1137
1138/** Helper function to check for the presence and length of AT_SELECTED_VERSION and copy its value into the keys structure
1139 *
1140 * Also checks the version matches one of the ones we advertised in our version list,
1141 * which is a bit redundant seeing as there's only one version of EAP-SIM.
1142 */
1144{
1145 fr_pair_t *selected_version_vp;
1146
1147 /*
1148 * Check that we got an AT_SELECTED_VERSION
1149 */
1150 selected_version_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_selected_version);
1151 if (!selected_version_vp) {
1152 REDEBUG("EAP-Response/SIM/Start does not contain AT_SELECTED_VERSION");
1153 return -1;
1154 }
1155
1156 /*
1157 * See if the selected version was in our list
1158 */
1159 {
1160 uint8_t selected_version[2];
1161 uint8_t *p, *end;
1162 bool found = false;
1163
1164 p = eap_aka_sim_session->keys.gsm.version_list;
1165 end = p + eap_aka_sim_session->keys.gsm.version_list_len;
1166
1167 selected_version[0] = (selected_version_vp->vp_uint16 & 0xff00) >> 8;
1168 selected_version[1] = (selected_version_vp->vp_uint16 & 0x00ff);
1169
1170 while (p < end) {
1171 if ((p[0] == selected_version[0]) && (p[1] == selected_version[1])) {
1172 found = true;
1173 /*
1174 * Update our keying material
1175 */
1176 eap_aka_sim_session->keys.gsm.version_select[0] = selected_version[0];
1177 eap_aka_sim_session->keys.gsm.version_select[1] = selected_version[1];
1178 break;
1179 }
1180 }
1181
1182 if (!found) {
1183 REDEBUG("AT_SELECTED_VERSION (%u) does not match a value in our version list",
1184 selected_version_vp->vp_uint16);
1185 return -1;
1186 }
1187 }
1188
1189 return 0;
1190}
1191
1192/** Helper function to check for the presence and length of AT_NONCE_MT and copy its value into the keys structure
1193 *
1194 * Does not actually perform cryptographic validation of AT_NONCE_MT, this is done later.
1195 */
1197{
1198 fr_pair_t *nonce_mt_vp;
1199
1200 /*
1201 * Copy nonce_mt to the keying material
1202 */
1203 nonce_mt_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_nonce_mt);
1204 if (!nonce_mt_vp) {
1205 REDEBUG("EAP-Response/SIM/Start does not contain AT_NONCE_MT");
1206 return -1;
1207 }
1208
1209 if (nonce_mt_vp->vp_length != sizeof(eap_aka_sim_session->keys.gsm.nonce_mt)) {
1210 REDEBUG("AT_NONCE_MT must be exactly %zu bytes, not %zu bytes",
1211 sizeof(eap_aka_sim_session->keys.gsm.nonce_mt), nonce_mt_vp->vp_length);
1212 return -1;
1213 }
1214 memcpy(eap_aka_sim_session->keys.gsm.nonce_mt, nonce_mt_vp->vp_octets,
1215 sizeof(eap_aka_sim_session->keys.gsm.nonce_mt));
1216
1217 return 0;
1218}
1219
1220/** FAILURE state - State machine exit point after sending EAP-Failure
1221 *
1222 * Should never actually be called. Is just a placeholder function to represent the FAILURE
1223 * termination state. Could equally be a NULL pointer, but then on a logic error
1224 * we'd get a SEGV instead of a more friendly assert/failure rcode.
1225 */
1227{
1228 if (!fr_cond_assert(request && mctx && mctx->rctx)) RETURN_UNLANG_FAIL; /* unused args */
1229
1230 fr_assert(0); /* Should never actually be called */
1231
1233}
1234
1235/** Resume after 'send EAP-Failure { ... }'
1236 *
1237 */
1238RESUME(send_eap_failure)
1239{
1240 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1241
1242 if (!fr_cond_assert(mctx && mctx->rctx)) RETURN_UNLANG_FAIL; /* unused args */
1243
1245
1246 RDEBUG2("Sending EAP-Failure");
1247
1249}
1250
1251/** Enter EAP-FAILURE state
1252 *
1253 */
1255{
1256 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1257 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1258
1259 /*
1260 * Free anything we were going to send out...
1261 */
1262 fr_pair_list_free(&request->reply_pairs);
1263
1264 /*
1265 * If we're failing, then any identities
1266 * we sent are now invalid.
1267 */
1269 return session_and_pseudonym_clear(p_result, mctx,
1270 request, eap_aka_sim_session, guard_eap_failure);
1271 /* come back when we're done */
1272 }
1273
1275
1276 return CALL_SECTION(send_eap_failure);
1277}
1278
1279/** Resume after 'recv Failure-Notification-Ack { ... }'
1280 *
1281 * - Enter the EAP-FAILURE state.
1282 */
1283RESUME(recv_common_failure_notification_ack)
1284{
1285 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1286
1288
1289 /*
1290 * Case 2 where we're allowed to send an EAP-Failure
1291 */
1293}
1294
1295/** FAILURE-NOTIFICATION state - Continue the state machine after receiving a response to our EAP-Request/(AKA|SIM)-Notification
1296 *
1297 * - Continue based on received AT_SUBTYPE value:
1298 * - EAP-Response/SIM-Client-Error - Call 'recv Failure-Notification-Ack { ... }'
1299 * - Anything else, enter the FAILURE-NOTIFICATION state.
1300 */
1302{
1303 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1306
1307 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
1308 if (!subtype_vp) goto fail;
1309
1310 switch (subtype_vp->vp_uint16) {
1311 case FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION:
1312 RDEBUG2("Failure-Notification ACKed, sending EAP-Failure");
1313 return CALL_SECTION(recv_common_failure_notification_ack);
1314
1315 default:
1316 fail:
1317 RWDEBUG("Failure-Notification not ACKed correctly, sending EAP-Failure anyway");
1319 }
1320}
1321
1322/** Resume after 'send Failure-Notification { ... }'
1323 *
1324 * Ignores return code from send Failure-Notification { ... } section.
1325 */
1326RESUME(send_common_failure_notification)
1327{
1328 fr_pair_t *vp, *notification_vp;
1329 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx,
1331
1332 if (!fr_cond_assert(mctx)) RETURN_UNLANG_FAIL; /* quiet unused warning */
1333
1335
1336 /*
1337 * Allow the user to specify specific failure notification
1338 * types. We assume the user knows what they're doing and
1339 * only toggle success and phase bits.
1340 *
1341 * This allows custom notification schemes to be implemented.
1342 *
1343 * If this is prior to authentication, valid values are:
1344 * - FR_NOTIFICATION_VALUE_GENERAL_FAILURE
1345 *
1346 * If this is after authentication, valid values are:
1347 * - FR_NOTIFICATION_VALUE_GENERAL_FAILURE_AFTER_AUTHENTICATION
1348 * - FR_NOTIFICATION_VALUE_TEMPORARILY_DENIED - User has been
1349 * temporarily denied access to the requested service.
1350 * - FR_NOTIFICATION_VALUE_NOT_SUBSCRIBED
1351 * User has not subscribed to the requested service.
1352 */
1353 notification_vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_notification);
1354
1355 /*
1356 * Keep Notification, but remove everything else...
1357 */
1358 if (notification_vp) fr_pair_remove(&request->reply_pairs, notification_vp);
1359 fr_pair_list_free(&request->reply_pairs);
1360 if (notification_vp) fr_pair_append(&request->reply_pairs, notification_vp);
1361
1362 /*
1363 * Change the failure notification depending where
1364 * we are in the eap_aka_state machine.
1365 */
1367 if (!notification_vp) {
1368 MEM(pair_append_reply(&notification_vp, attr_eap_aka_sim_notification) >= 0);
1369 notification_vp->vp_uint16 = eap_aka_sim_session->failure_type; /* Default will be zero */
1370 }
1371
1372 notification_vp->vp_uint16 &= ~0x4000; /* Unset phase bit */
1373
1374 /*
1375 * Include the counter attribute if we're failing
1376 * after a reauthentication success.
1377 *
1378 * RFC 4187 Section #9.10
1379 *
1380 * If EAP-Request/AKA-Notification is used on
1381 * a fast re-authentication exchange, and if
1382 * the P bit in AT_NOTIFICATION is set to zero,
1383 * then AT_COUNTER is used for replay protection.
1384 * In this case, the AT_ENCR_DATA and AT_IV
1385 * attributes MUST be included, and the
1386 * encapsulated plaintext attributes MUST include
1387 * the AT_COUNTER attribute. The counter value
1388 * included in AT_COUNTER MUST be the same
1389 * as in the EAP-Request/AKA-Reauthentication
1390 * packet on the same fast re-authentication
1391 * exchange.
1392 *
1393 * If the counter is used it should never be zero,
1394 * as it's incremented on first reauthentication
1395 * request.
1396 */
1398 MEM(pair_update_reply(&notification_vp, attr_eap_aka_sim_counter) >= 0);
1399 notification_vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
1400 }
1401
1402 /*
1403 * If we're after the challenge phase
1404 * then we need to include a MAC to
1405 * protect notifications.
1406 */
1408 fr_pair_value_memdup(vp, NULL, 0, false);
1409 } else {
1410 /*
1411 * Only valid code is general failure
1412 */
1413 if (!notification_vp) {
1414 MEM(pair_append_reply(&notification_vp, attr_eap_aka_sim_notification) >= 0);
1415 notification_vp->vp_uint16 = FR_NOTIFICATION_VALUE_GENERAL_FAILURE;
1416 /*
1417 * User supplied failure code
1418 */
1419 } else {
1420 notification_vp->vp_uint16 |= 0x4000; /* Set phase bit */
1421 }
1422 }
1423 notification_vp->vp_uint16 &= ~0x8000; /* In both cases success bit should be low */
1424
1425 /*
1426 * Send a response
1427 */
1428 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION);
1429
1431}
1432
1433/** Enter the FAILURE-NOTIFICATION state
1434 *
1435 */
1437{
1438 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1439 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1440
1441 /*
1442 * If we're failing, then any identities
1443 * we sent are now invalid.
1444 */
1446 return session_and_pseudonym_clear(p_result, mctx, request, eap_aka_sim_session,
1447 guard_common_failure_notification); /* come back when we're done */
1448 }
1449
1450 /*
1451 * We've already sent a failure notification
1452 * Now we just fail as it means something
1453 * went wrong processing the ACK or we got
1454 * garbage from the supplicant.
1455 */
1456 if (eap_aka_sim_session->state == state_common_failure_notification) {
1458 }
1459
1460 /*
1461 * Otherwise just transition as normal...
1462 */
1464
1465 return CALL_SECTION(send_common_failure_notification);
1466}
1467
1468/** SUCCESS state - State machine exit point after sending EAP-Success
1469 *
1470 * Should never actually be called. Is just a placeholder function to represent the SUCCESS
1471 * termination state. Could equally be a NULL pointer, but then on a logic error
1472 * we'd get a SEGV instead of a more friendly assert/failure rcode.
1473 */
1475{
1476 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1477
1478 if (!fr_cond_assert(request && mctx && eap_aka_sim_session)) RETURN_UNLANG_FAIL; /* unused args */
1479
1480 fr_assert(0); /* Should never actually be called */
1481
1483}
1484
1485/** Resume after 'send EAP-Success { ... }'
1486 *
1487 * Add MPPE keys to the request being sent to the supplicant
1488 *
1489 * The only work to be done is the add the appropriate SEND/RECV
1490 * attributes derived from the MSK.
1491 */
1492RESUME(send_eap_success)
1493{
1494 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1495 uint8_t *p;
1496
1497 RDEBUG2("Sending EAP-Success");
1498
1499 /*
1500 * If this is true we're entering this state
1501 * after sending a AKA-Success-Notification
1502 *
1503 * Is seems like a really bad idea to allow the
1504 * user to send a protected success to the
1505 * supplicant and then force a failure using
1506 * the send EAP-Success { ... } section.
1507 */
1509 switch (eap_aka_sim_session->result.rcode) {
1511 RWDEBUG("Ignoring rcode (%s) from send EAP-Success { ... } "
1512 "as we already sent a Success-Notification",
1514 RWDEBUG("If you need to force a failure, return an error code from "
1515 "send Success-Notification { ... }");
1516 break;
1517
1518 default:
1519 break;
1520 }
1521
1522 /*
1523 * But... if we're not working with protected
1524 * success indication, this is the only
1525 * opportunity the user has to force a failure at
1526 * the end of authentication.
1527 */
1528 } else {
1530 }
1531
1532 RDEBUG2("Adding attributes for MSK");
1537
1539}
1540
1541/** Enter EAP-SUCCESS state
1542 *
1543 */
1545{
1546 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1547 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1548
1550
1551 return CALL_SECTION(send_eap_success);
1552}
1553
1554/** Resume after 'recv Success-Notification-Ack { ... }'
1555 *
1556 * - Enter the EAP-SUCCESS state.
1557 */
1558RESUME(recv_common_success_notification_ack)
1559{
1560 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1561
1563
1564 /*
1565 * RFC 4187 says we ignore the contents of the
1566 * next packet after we send our success notification
1567 * and always send a success.
1568 */
1570}
1571
1572/** SUCCESS-NOTIFICATION state - Continue the state machine after receiving a response to our EAP-Request/(AKA|SIM)-Notification
1573 *
1574 * - Call 'recv Success-Notification-Ack { ... }'
1575 */
1577{
1578 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1579 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx,
1581 /*
1582 * Because the server uses the AT_NOTIFICATION code "Success" (32768) to
1583 * indicate that the EAP exchange has completed successfully, the EAP
1584 * exchange cannot fail when the server processes the EAP-AKA response
1585 * to this notification. Hence, the server MUST ignore the contents of
1586 * the EAP-AKA response it receives to the EAP-Request/AKA-Notification
1587 * with this code. Regardless of the contents of the EAP-AKA response,
1588 * the server MUST send EAP-Success as the next packet.
1589 */
1590 return CALL_SECTION(recv_common_success_notification_ack);
1591}
1592
1593/** Resume after 'send Success-Notification { ... }'
1594 *
1595 */
1596RESUME(send_common_success_notification)
1597{
1598 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1599 fr_pair_t *vp;
1600
1602
1604
1605 /*
1606 * If we're in this state success bit is
1607 * high phase bit is low.
1608 */
1610 vp->vp_uint16 = FR_NOTIFICATION_VALUE_SUCCESS;
1611
1612 /*
1613 * RFC 4187 section #9.10
1614 *
1615 * If EAP-Request/AKA-Notification is used on
1616 * a fast re-authentication exchange, and if
1617 * the P bit in AT_NOTIFICATION is set to zero,
1618 * then AT_COUNTER is used for replay protection.
1619 * In this case, the AT_ENCR_DATA and AT_IV
1620 * attributes MUST be included, and the
1621 * encapsulated plaintext attributes MUST include
1622 * the AT_COUNTER attribute. The counter value
1623 * included in AT_COUNTER MUST be the same
1624 * as in the EAP-Request/AKA-Reauthentication
1625 * packet on the same fast re-authentication
1626 * exchange.
1627 *
1628 * If the counter is used it should never be zero,
1629 * as it's incremented on first reauthentication
1630 * request.
1631 */
1632 if (eap_aka_sim_session->keys.reauth.counter > 0) {
1634 vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
1635 }
1636
1637 /*
1638 * Need to include an AT_MAC attribute so that
1639 * it will get calculated.
1640 */
1642 fr_pair_value_memdup(vp, NULL, 0, false);
1643
1644 /*
1645 * Return reply attributes
1646 */
1647 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION);
1648
1650}
1651
1652/** Enter the SUCCESS-NOTIFICATION state
1653 *
1654 */
1656{
1657 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1658 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx,
1661
1662 return CALL_SECTION(send_common_success_notification);
1663}
1664
1665/** Resume after 'recv Client-Error { ... }'
1666 *
1667 * - Enter the EAP-FAILURE state.
1668 */
1669RESUME(recv_common_client_error)
1670{
1671 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1672
1674
1676}
1677
1678/** Resume after 'recv Reauthentication-Response { ... }'
1679 *
1680 * - If 'recv Reauthentication-Response { ... }' returned a failure
1681 * rcode, enter the FAILURE-NOTIFICATION state.
1682 * - ...or call the EAP-Request/Reauthentication-Response function to act on the
1683 * contents of the response.
1684 */
1685RESUME(recv_common_reauthentication_response)
1686{
1687 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1688
1690
1691 /*
1692 * Validate mac
1693 */
1694 if (mac_validate(request) < 0) {
1695 failure:
1697 }
1698
1699 /*
1700 * Validate the checkcode
1701 */
1702 if (checkcode_validate(request) < 0) goto failure;
1703
1704 /*
1705 * Check to see if the supplicant sent
1706 * AT_COUNTER_TOO_SMALL, if they did then we
1707 * clear out reauth information and enter the
1708 * challenge state.
1709 */
1710 if (fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_eap_aka_sim_counter_too_small)) {
1711 RWDEBUG("Peer sent AT_COUNTER_TOO_SMALL (indicating our AT_COUNTER value (%u) wasn't fresh)",
1712 eap_aka_sim_session->keys.reauth.counter);
1713
1716
1718 }
1719
1720 /*
1721 * If the peer wants a Success notification, and
1722 * we included AT_RESULT_IND then send a success
1723 * notification, otherwise send a normal EAP-Success.
1724 *
1725 * RFC 4187 Section #6.2. Result Indications
1726 */
1728 if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
1729 RDEBUG("We wanted to use protected result indications, but peer does not");
1731 } else {
1733 }
1734 } else if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
1735 RDEBUG("Peer wanted to use protected result indications, but we do not");
1736 }
1737
1739
1741}
1742
1743/** REAUTHENTICATION state - Continue the state machine after receiving a response to our EAP-Request/SIM-Start
1744 *
1745 * - Continue based on received AT_SUBTYPE value:
1746 * - EAP-Response/(SIM|AKA)-Reauthentication - call 'recv Reauthentication-Response { ... }'
1747 * - EAP-Response/(SIM|AKA)-Client-Error - call 'recv Client-Error { ... }' and after that
1748 * send a EAP-Request/(SIM|AKA)-Notification indicating a General Failure.
1749 * - Anything else, enter the FAILURE-NOTIFICATION state.
1750 */
1752{
1753 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1754 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1755 fr_pair_t *subtype_vp = NULL;
1756
1757 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
1759 REDEBUG("Missing AT_SUBTYPE");
1760 goto fail;
1761 }
1762
1763 /*
1764 * These aren't allowed in Reauthentication responses as they don't apply:
1765 *
1766 * EAP_AKA_AUTHENTICATION_REJECT - We didn't provide an AUTN value
1767 * EAP_AKA_SYNCHRONIZATION_FAILURE - We didn't use new vectors.
1768 */
1769 switch (subtype_vp->vp_uint16) {
1770 case FR_SUBTYPE_VALUE_AKA_SIM_REAUTHENTICATION:
1771 /*
1772 * AT_COUNTER_TOO_SMALL is handled
1773 * in common_reauthentication_response_process.
1774 */
1775 return CALL_SECTION(recv_common_reauthentication_response);
1776
1777 /*
1778 * Case 1 where we're allowed to send an EAP-Failure
1779 */
1780 case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
1781 client_error_debug(request);
1782
1784
1785 return CALL_SECTION(recv_common_client_error);
1786 /*
1787 * RFC 4187 says we *MUST* notify, not just
1788 * send an EAP-Failure in this case.
1789 */
1790 default:
1791 REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
1792 fail:
1794
1796 }
1797}
1798
1799
1800/** Send a EAP-Request/(AKA|SIM)-Reauthenticate message to the supplicant
1801 *
1802 */
1804 module_ctx_t const *mctx,
1805 request_t *request,
1807{
1808 fr_pair_t *vp;
1809 fr_pair_t *kdf_id;
1810
1811 /*
1812 * Allow override of KDF Identity
1813 *
1814 * Because certain handset manufacturers don't
1815 * implement RFC 4187 correctly and use the
1816 * wrong identity as input the the PRF/KDF.
1817 *
1818 * Not seen any doing this for re-authentication
1819 * but you never know...
1820 */
1821 kdf_id = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_kdf_identity);
1822 if (kdf_id) {
1824 (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
1825 fr_pair_delete_by_da(&request->control_pairs, attr_eap_aka_sim_kdf_identity);
1826 }
1827
1828 RDEBUG2("Generating new session keys");
1829
1830 switch (eap_aka_sim_session->type) {
1831 /*
1832 * The GSM and UMTS KDF_0 mutate their keys using
1833 * and identical algorithm.
1834 */
1835 case FR_EAP_METHOD_SIM:
1836 case FR_EAP_METHOD_AKA:
1837 if (fr_aka_sim_vector_gsm_umts_kdf_0_reauth_from_attrs(request, &request->session_state_pairs,
1838 &eap_aka_sim_session->keys) != 0) {
1839 request_new_id:
1841 /*
1842 * Got here processing EAP-Identity-Response
1843 * If this is the *true* reauth ID, then
1844 * there's no point in setting AKA_SIM_ANY_ID_REQ.
1845 */
1847 case AKA_SIM_NO_ID_REQ:
1848 case AKA_SIM_ANY_ID_REQ:
1849 RDEBUG2("Composing EAP-Request/Reauthentication failed. Clearing reply attributes and "
1850 "requesting additional Identity");
1851 fr_pair_list_free(&request->reply_pairs);
1853 return STATE_TRANSITION(common_identity);
1854
1857 REDEBUG("Last requested fullauth or permanent ID, "
1858 "but received, or were told we received (by policy), "
1859 "a fastauth ID. Cannot continue");
1861 }
1862 }
1863 if (fr_aka_sim_crypto_kdf_0_reauth(&eap_aka_sim_session->keys) < 0) goto request_new_id;
1864 break;
1865
1868 if (fr_aka_sim_vector_umts_kdf_1_reauth_from_attrs(request, &request->session_state_pairs,
1869 &eap_aka_sim_session->keys) != 0) {
1870 goto request_new_id;
1871 }
1872 if (fr_aka_sim_crypto_umts_kdf_1_reauth(&eap_aka_sim_session->keys) < 0) goto request_new_id;
1873 } else {
1874 fr_assert(0);
1875 }
1876 break;
1877
1878 default:
1879 fr_assert(0);
1880 break;
1881 }
1882
1884
1885 /*
1886 * Indicate we'd like to use protected success messages
1887 * with AT_RESULT_IND
1888 *
1889 * Use our default, but allow user override too.
1890 */
1891 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind);
1892 if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
1893
1894 /*
1895 * RFC 5448 says AT_BIDDING is only sent in the challenge
1896 * not in reauthentication, so don't add that here.
1897 */
1898
1899 /*
1900 * Add AT_NONCE_S
1901 */
1904 sizeof(eap_aka_sim_session->keys.reauth.nonce_s), false);
1905
1906 /*
1907 * Add AT_COUNTER
1908 */
1910 vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
1911
1912 /*
1913 * need to include an empty AT_MAC attribute so that
1914 * the mac will get calculated.
1915 */
1917 fr_pair_value_memdup(vp, NULL, 0, false);
1918
1919 /*
1920 * We've sent the challenge so the peer should now be able
1921 * to accept encrypted attributes.
1922 */
1924
1925 return session_and_pseudonym_store(p_result, mctx, request, eap_aka_sim_session,
1927}
1928
1929/** Resume after 'send Reauthentication-Request { ... }'
1930 *
1931 */
1932RESUME(send_common_reauthentication_request)
1933{
1934 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1935
1936 switch (eap_aka_sim_session->result.rcode) {
1937 /*
1938 * Failed getting the values we need for resumption
1939 * Request a different identity.
1940 */
1941 default:
1943 /*
1944 * Got here processing EAP-Identity-Response
1945 * If this is the *true* reauth ID, then
1946 * there's no point in setting AKA_SIM_ANY_ID_REQ.
1947 */
1949 case AKA_SIM_NO_ID_REQ:
1950 case AKA_SIM_ANY_ID_REQ:
1951 RDEBUG2("Previous section returned (%s), clearing reply attributes and "
1952 "requesting additional identity",
1954 fr_pair_list_free(&request->reply_pairs);
1956
1957 return STATE_TRANSITION(common_identity);
1958
1961 default:
1962 break;
1963 }
1964 REDEBUG("Last requested Full-Auth-Id or Permanent-Identity, "
1965 "but received a Fast-Auth-Id. Cannot continue");
1966 failure:
1968
1969 /*
1970 * Policy rejected the user
1971 */
1972 case RLM_MODULE_REJECT:
1974 goto failure;
1975
1976 /*
1977 * Everything looks ok, send the EAP-Request/reauthentication message
1978 * After storing any new pseudonyms or session information.
1979 */
1980 case RLM_MODULE_NOOP:
1981 case RLM_MODULE_OK:
1982 case RLM_MODULE_UPDATED:
1983 return common_reauthentication_request_compose(p_result, mctx, request, eap_aka_sim_session);
1984 }
1985}
1986
1987/** Resume after 'load pseudonym { ... }'
1988 *
1989 */
1990RESUME(load_pseudonym)
1991{
1992 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1993 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1994
1996
1997 /*
1998 * Control attributes required could have been specified
1999 * in another section.
2000 */
2001 if (!inst->actions.load_pseudonym) {
2002 next_state:
2003 return eap_aka_sim_session->next(p_result, mctx, request);
2004 }
2005
2006 switch (eap_aka_sim_session->result.rcode) {
2007 /*
2008 * Failed resolving the pseudonym
2009 * request a different identity.
2010 */
2011 default:
2014 case AKA_SIM_NO_ID_REQ:
2015 case AKA_SIM_ANY_ID_REQ:
2017 RDEBUG2("Previous section returned (%s), clearing reply attributes and "
2018 "requesting additional identity",
2020 fr_pair_list_free(&request->reply_pairs);
2022 return STATE_TRANSITION(common_identity);
2023
2025 REDEBUG("Last requested a Permanent-Identity, but received a Pseudonym. Cannot continue");
2026 failure:
2028 }
2029 break;
2030
2031 /*
2032 * Policy rejected the user
2033 */
2034 case RLM_MODULE_REJECT:
2036 goto failure;
2037
2038 /*
2039 * Everything OK
2040 */
2041 case RLM_MODULE_OK:
2042 case RLM_MODULE_UPDATED:
2043 goto next_state;
2044 }
2045
2046 goto failure;
2047}
2048
2049/** Resume after 'load session { ... }'
2050 *
2051 */
2052RESUME(load_session)
2053{
2054 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2055 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2056
2058
2059 /*
2060 * Control attributes required could have been specified
2061 * in another section.
2062 */
2063 if (!inst->actions.load_session) goto reauthenticate;
2064
2065 switch (eap_aka_sim_session->result.rcode) {
2066 /*
2067 * Failed getting the values we need for resumption
2068 * Request a different identity.
2069 */
2070 default:
2072 /*
2073 * Got here processing EAP-Identity-Response
2074 * If this is the *true* reauth ID, then
2075 * there's no point in setting AKA_SIM_ANY_ID_REQ.
2076 */
2078 case AKA_SIM_NO_ID_REQ:
2079 case AKA_SIM_ANY_ID_REQ:
2080 RDEBUG2("Previous section returned (%s), clearing reply attributes and "
2081 "requesting additional identity",
2083 fr_pair_list_free(&request->reply_pairs);
2085 return STATE_TRANSITION(common_identity);
2086
2089 REDEBUG("Last requested Full-Auth-Id or Permanent-Identity, "
2090 "but received a Fast-Auth-Id. Cannot continue");
2092 }
2093 break;
2094
2095 /*
2096 * Policy rejected the user
2097 */
2098 case RLM_MODULE_REJECT:
2100 reject:
2102
2103 /*
2104 * Everything OK
2105 */
2106 case RLM_MODULE_OK:
2107 case RLM_MODULE_UPDATED:
2108 reauthenticate:
2109 return CALL_SECTION(send_common_reauthentication_request);
2110 }
2111
2112 goto reject;
2113}
2114
2115/** Enter the REAUTHENTICATION state
2116 *
2117 */
2119{
2120 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2121 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2122 fr_pair_t *vp = NULL;
2123
2125
2126 /*
2127 * Add the current identity as session_id
2128 * to make it easier to load/store things from
2129 * the cache module.
2130 */
2133
2134 return CALL_SECTION(load_session);
2135}
2136
2137/** Resume after 'recv Synchronization-Failure { ... }'
2138 *
2139 * - If 'recv Synchronization-Failure { ... }' returned a failure
2140 * rcode, enter the FAILURE-NOTIFICATION state.
2141 * - ...or if no 'recv Synchronization-Failure { ... }' section was
2142 * defined, then enter the FAILURE-NOTIFICATION state.
2143 * - ...or if the user didn't provide a new SQN value in &control.SQN
2144 * then enter the FAILURE-NOTIFICATION state.
2145 * - ...or enter the AKA-CHALLENGE state.
2146 */
2147RESUME(recv_aka_synchronization_failure)
2148{
2149 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2150 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2151 fr_pair_t *vp;
2152
2154
2155 /*
2156 * If there's no section to handle this, then no resynchronisation
2157 * can't have occurred and we just send a reject.
2158 *
2159 * Similarly, if we've already received one synchronisation failure
2160 * then it's highly likely whatever user configured action was
2161 * configured was unsuccessful, and we should just give up.
2162 */
2163 if (!inst->actions.recv_aka_synchronization_failure || eap_aka_sim_session->prev_recv_sync_failure) {
2164 failure:
2166 }
2167
2168 /*
2169 * We couldn't generate an SQN and the user didn't provide one,
2170 * so we need to fail.
2171 */
2172 vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_sim_sqn);
2173 if (!vp) {
2174 REDEBUG("No control.SQN value provided after resynchronisation, cannot continue");
2175 goto failure;
2176 }
2177
2178 /*
2179 * RFC 4187 Section #6.3.1
2180 *
2181 * "if the peer detects that the
2182 * sequence number in AUTN is not correct, the peer responds with
2183 * EAP-Response/AKA-Synchronization-Failure (Section 9.6), and the
2184 * server proceeds with a new EAP-Request/AKA-Challenge."
2185 */
2187}
2188
2189/** Resume after 'recv Authentication-Reject { ... }'
2190 *
2191 * - Enter the FAILURE-NOTIFICATION state.
2192 */
2193RESUME(recv_aka_authentication_reject)
2194{
2195 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2196
2198
2199 /*
2200 * Case 2 where we're allowed to send an EAP-Failure
2201 */
2203}
2204
2205/** Resume after 'recv Challenge-Response { ... }'
2206 *
2207 * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
2208 * - ...or call a function to process the contents of the AKA-Challenge message.
2209 *
2210 * Verify that MAC, and RES match what we expect.
2211 */
2212RESUME(recv_aka_challenge_response)
2213{
2214 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2215 fr_pair_t *vp = NULL;
2216
2218
2219 /*
2220 * Validate mac
2221 */
2222 if (mac_validate(request) < 0) {
2223 failure:
2225 }
2226
2227 /*
2228 * Validate the checkcode
2229 */
2230 if (checkcode_validate(request) < 0) goto failure;
2231
2232 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_res);
2233 if (!vp) {
2234 REDEBUG("AT_RES missing from challenge response");
2235 goto failure;
2236 }
2237
2238 if (vp->vp_length != eap_aka_sim_session->keys.umts.vector.xres_len) {
2239 REDEBUG("Received RES' length (%zu) does not match calculated XRES' length (%zu)",
2240 vp->vp_length, eap_aka_sim_session->keys.umts.vector.xres_len);
2241 goto failure;
2242 }
2243
2244 if (memcmp(vp->vp_octets, eap_aka_sim_session->keys.umts.vector.xres, vp->vp_length)) {
2245 REDEBUG("Received RES does not match calculated XRES");
2246 RHEXDUMP_INLINE2(vp->vp_octets, vp->vp_length, "RES :");
2247 RHEXDUMP_INLINE2(eap_aka_sim_session->keys.umts.vector.xres,
2248 eap_aka_sim_session->keys.umts.vector.xres_len, "XRES :");
2249 goto failure;
2250 }
2251
2252 RDEBUG2("Received RES matches calculated XRES");
2253
2255
2256 /*
2257 * If the peer wants a Success notification, and
2258 * we included AT_RESULT_IND then send a success
2259 * notification, otherwise send a normal EAP-Success.
2260 *
2261 * RFC 4187 Section #6.2. Result Indications
2262 */
2264 if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2265 RDEBUG("We wanted to use protected result indications, but peer does not");
2267 } else {
2269 }
2270 } else if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2271 RDEBUG("Peer wanted to use protected result indications, but we do not");
2272 }
2273
2275}
2276
2277/** AKA-CHALLENGE state - Continue the state machine after receiving a response to our EAP-Request/SIM-Challenge
2278 *
2279 * - Continue based on received AT_SUBTYPE value:
2280 * - EAP-Response/AKA-Challenge - call 'recv Challenge-Response { ... }'.
2281 * - EAP-Response/AKA-Authentication-Reject - call 'recv Authentication-Reject { ... }' and after that
2282 * send a EAP-Request/SIM-Notification indicating a General Failure.
2283 * - EAP-Response/AKA-Synchronization-Failure - call 'recv Synchronization-Failure { ... }'.
2284 * - EAP-Response/AKA-Client-Error - call 'recv Client-Error { ... }' and after that
2285 * send a EAP-Request/AKA-Notification indicating a General Failure.
2286 * - Anything else, enter the FAILURE-NOTIFICATION state.
2287 */
2289{
2290 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2291 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2292 fr_pair_t *subtype_vp = NULL;
2294
2295 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
2296 if (!subtype_vp) {
2297 REDEBUG("Missing AT_SUBTYPE");
2298 goto fail;
2299 }
2300
2301 switch (subtype_vp->vp_uint16) {
2302 case FR_SUBTYPE_VALUE_AKA_CHALLENGE:
2303 return CALL_SECTION(recv_aka_challenge_response);
2304
2305 /*
2306 * Case 2 where we're allowed to send an EAP-Failure
2307 */
2308 case FR_SUBTYPE_VALUE_AKA_AUTHENTICATION_REJECT:
2310 return CALL_SECTION(recv_aka_authentication_reject);
2311
2312 case FR_SUBTYPE_VALUE_AKA_SYNCHRONIZATION_FAILURE:
2313 {
2314 uint64_t new_sqn;
2315
2317
2318 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_auts);
2319 if (!vp) {
2320 REDEBUG("EAP-Response/AKA-Synchronisation-Failure missing AT_AUTS");
2321 failure:
2323 }
2324
2325 switch (fr_aka_sim_umts_resync_from_attrs(&new_sqn,
2326 request, vp, &eap_aka_sim_session->keys)) {
2327 /*
2328 * Add everything back that we'll need in the
2329 * next challenge round.
2330 */
2331 case 0:
2333 vp->vp_uint64 = new_sqn;
2334
2337 sizeof(eap_aka_sim_session->keys.auc.ki), false);
2338
2341 sizeof(eap_aka_sim_session->keys.auc.opc), false);
2342 break;
2343
2344 case 1: /* Don't have Ki or OPc so something else will need to deal with this */
2345 break;
2346
2347 default:
2348 case -1:
2349 goto failure;
2350 }
2351
2352 return CALL_SECTION(recv_aka_synchronization_failure);
2353 }
2354
2355 /*
2356 * Case 1 where we're allowed to send an EAP-Failure
2357 */
2358 case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
2359 client_error_debug(request);
2360
2362
2363 return CALL_SECTION(recv_common_client_error);
2364
2365 /*
2366 * RFC 4187 says we *MUST* notify, not just
2367 * send an EAP-Failure in this case.
2368 */
2369 default:
2370 REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
2371 fail:
2373 goto failure;
2374 }
2375}
2376
2377/** Resume after 'send Challenge-Request { ... }'
2378 *
2379 */
2380RESUME(send_aka_challenge_request)
2381{
2382 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2383 fr_pair_t *vp;
2385
2386 fr_pair_t *kdf_id;
2387
2389
2390 /*
2391 * Allow override of KDF Identity
2392 *
2393 * Because certain handset manufacturers don't
2394 * implement RFC 4187 correctly and use the
2395 * wrong identity as input the the PRF/KDF.
2396 */
2397 kdf_id = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_kdf_identity);
2398 if (kdf_id) {
2400 (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
2401 fr_pair_delete_by_da(&request->control_pairs, attr_eap_aka_sim_kdf_identity);
2402 }
2403
2404 RDEBUG2("Acquiring UMTS vector(s)");
2405
2407 /*
2408 * Copy the network name the user specified for
2409 * key derivation purposes.
2410 */
2411 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_kdf_input);
2412 if (vp) {
2415 (uint8_t const *)vp->vp_strvalue,
2416 vp->vp_length);
2417 eap_aka_sim_session->keys.network_len = vp->vp_length;
2418 } else {
2419 REDEBUG("No network name available, can't set AT_KDF_INPUT");
2420 failure:
2422 }
2423
2424 /*
2425 * We don't allow the user to specify
2426 * the KDF currently.
2427 */
2429 vp->vp_uint16 = eap_aka_sim_session->kdf;
2430 }
2431
2432 /*
2433 * Get vectors from attribute or generate
2434 * them using COMP128-* or Milenage.
2435 */
2436 if (fr_aka_sim_vector_umts_from_attrs(request, &request->control_pairs,
2437 &eap_aka_sim_session->keys, &src) != 0) {
2438 REDEBUG("Failed retrieving UMTS vectors");
2439 goto failure;
2440 }
2441
2442 /*
2443 * Don't leave the AMF hanging around
2444 */
2446
2447 /*
2448 * All set, calculate keys!
2449 */
2450 switch (eap_aka_sim_session->type) {
2451 default:
2452 case FR_EAP_METHOD_SIM:
2453 fr_assert(0); /* EAP-SIM has its own Challenge state */
2454 break;
2455
2456 case FR_EAP_METHOD_AKA:
2458 break;
2459
2463 } else {
2464 fr_assert(0);
2465 }
2466 }
2468
2469 /*
2470 * Indicate we'd like to use protected success messages
2471 * with AT_RESULT_IND
2472 *
2473 * Use our default, but allow user override too.
2474 */
2475 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind);
2476 if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
2477
2478 /*
2479 * These attributes are only allowed with
2480 * EAP-AKA', protect users from themselves.
2481 */
2485 }
2486
2487 /*
2488 * Okay, we got the challenge! Put it into an attribute.
2489 */
2492
2493 /*
2494 * Send the AUTN value to the client, so it can authenticate
2495 * whoever has knowledge of the Ki.
2496 */
2499
2500 /*
2501 * need to include an AT_MAC attribute so that it will get
2502 * calculated.
2503 */
2505 fr_pair_value_memdup(vp, NULL, 0, false);
2506
2507 /*
2508 * We've sent the challenge so the peer should now be able
2509 * to accept encrypted attributes.
2510 */
2512
2514}
2515
2516/** Enter the AKA-CHALLENGE state
2517 *
2518 */
2520{
2521 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2522 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2523 fr_pair_t *vp;
2524
2525 /*
2526 * If we've sent either of these identities it
2527 * means we've come here form a Reauthentication-Request
2528 * that failed.
2529 */
2531 return session_and_pseudonym_clear(p_result, mctx, request,
2532 eap_aka_sim_session, guard_aka_challenge);
2533 /* come back when we're done */
2534 }
2535
2537
2538 /*
2539 * Set some default attributes, giving the user a
2540 * chance to modify them.
2541 */
2542 switch (eap_aka_sim_session->type) {
2544 {
2545 uint8_t amf_buff[2] = { 0x80, 0x00 }; /* Set the AMF separation bit high */
2546
2547 /*
2548 * Toggle the AMF high bit to indicate we're doing AKA'
2549 */
2551 fr_pair_value_memdup(vp, amf_buff, sizeof(amf_buff), false);
2552
2553 /*
2554 * Use the default network name we have configured
2555 * and send it to the peer.
2556 */
2557 if (inst->network_name &&
2558 !fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_kdf_input)) {
2561 }
2562 }
2563 break;
2564
2565 default:
2566 break;
2567
2568 }
2569
2570 /*
2571 * Set the defaults for protected result indicator
2572 */
2574 !fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2576 vp->vp_bool = true;
2577 }
2578
2579 return CALL_SECTION(send_aka_challenge_request);
2580}
2581
2582/** Resume after 'recv Challenge-Response { ... }'
2583 *
2584 * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
2585 * - ...or call a function to process the contents of the SIM-Challenge message.
2586 *
2587 * Verify that MAC, and RES match what we expect.
2588 */
2589RESUME(recv_sim_challenge_response)
2590{
2591 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2593 uint8_t *p = sres_cat;
2594
2596
2597 memcpy(p, eap_aka_sim_session->keys.gsm.vector[0].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
2599 memcpy(p, eap_aka_sim_session->keys.gsm.vector[1].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
2601 memcpy(p, eap_aka_sim_session->keys.gsm.vector[2].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
2602
2603 /*
2604 * Validate mac
2605 */
2607
2609
2610 /*
2611 * If the peer wants a Success notification, and
2612 * we included AT_RESULT_IND then send a success
2613 * notification, otherwise send a normal EAP-Success.
2614 */
2616 if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2617 RDEBUG("We wanted to use protected result indications, but peer does not");
2619 } else {
2621 }
2622 } else if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2623 RDEBUG("Peer wanted to use protected result indications, but we do not");
2624 }
2625
2627}
2628
2629/** SIM-CHALLENGE state - Continue the state machine after receiving a response to our EAP-Request/SIM-Challenge
2630 *
2631 * - Continue based on received AT_SUBTYPE value:
2632 * - EAP-Response/SIM-Challenge - call 'recv Challenge-Response { ... }'.
2633 * - EAP-Response/SIM-Client-Error - call 'recv Client-Error { ... }' and after that
2634 * send a EAP-Request/SIM-Notification indicating a General Failure.
2635 * - Anything else, enter the FAILURE-NOTIFICATION state.
2636 */
2638{
2639 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2640 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2641 fr_pair_t *subtype_vp = NULL;
2642
2643 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
2644 if (!subtype_vp) {
2645 REDEBUG("Missing AT_SUBTYPE");
2646 goto fail;
2647 }
2648
2649 switch (subtype_vp->vp_uint16) {
2650 case FR_SUBTYPE_VALUE_SIM_CHALLENGE:
2651 return CALL_SECTION(recv_sim_challenge_response);
2652
2653 /*
2654 * Case 1 where we're allowed to send an EAP-Failure
2655 */
2656 case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
2657 client_error_debug(request);
2658
2660
2661 return CALL_SECTION(recv_common_client_error);
2662
2663 /*
2664 * RFC 4186 says we *MUST* notify, not just
2665 * send an EAP-Failure in this case.
2666 */
2667 default:
2668 REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
2669 fail:
2671
2673 }
2674}
2675
2676/** Resume after 'send Challenge-Request { ... }'
2677 *
2678 */
2679RESUME(send_sim_challenge_request)
2680{
2681 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2682
2683 fr_pair_t *vp;
2685
2686 fr_pair_t *kdf_id;
2687
2689
2690 /*
2691 * Allow override of KDF Identity
2692 *
2693 * Because certain handset manufacturers don't
2694 * implement RFC 4187 correctly and use the
2695 * wrong identity as input the the PRF/KDF.
2696 */
2697 kdf_id = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_kdf_identity);
2698 if (kdf_id) {
2700 (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
2701 fr_pair_delete_by_da(&request->control_pairs, attr_eap_aka_sim_kdf_identity);
2702 }
2703
2704 RDEBUG2("Acquiring GSM vector(s)");
2705 if ((fr_aka_sim_vector_gsm_from_attrs(request, &request->control_pairs, 0,
2706 &eap_aka_sim_session->keys, &src) != 0) ||
2707 (fr_aka_sim_vector_gsm_from_attrs(request, &request->control_pairs, 1,
2708 &eap_aka_sim_session->keys, &src) != 0) ||
2709 (fr_aka_sim_vector_gsm_from_attrs(request, &request->control_pairs, 2,
2710 &eap_aka_sim_session->keys, &src) != 0)) {
2711 REDEBUG("Failed retrieving SIM vectors");
2713 }
2714
2716
2718
2719 /*
2720 * Indicate we'd like to use protected success messages
2721 * with AT_RESULT_IND
2722 *
2723 * Use our default, but allow user override too.
2724 */
2725 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind);
2726 if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
2727
2728 /*
2729 * Okay, we got the challenges! Put them into attributes.
2730 */
2733
2736
2739
2740 /*
2741 * need to include an AT_MAC attribute so that it will get
2742 * calculated.
2743 */
2745 fr_pair_value_memdup(vp, NULL, 0, false);
2746
2747 /*
2748 * We've sent the challenge so the peer should now be able
2749 * to accept encrypted attributes.
2750 */
2752
2754}
2755
2756/** Enter the SIM-CHALLENGE state
2757 *
2758 */
2760{
2761 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2762 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2763 fr_pair_t *vp;
2764
2765 /*
2766 * If we've sent either of these identities it
2767 * means we've come here form a Reauthentication-Request
2768 * that failed.
2769 */
2771 return session_and_pseudonym_clear(p_result, mctx, request,
2772 eap_aka_sim_session, guard_sim_challenge);
2773 /* come back when we're done */
2774 }
2775
2777
2778 /*
2779 * Set the defaults for protected result indicator
2780 */
2782 !fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2784 vp->vp_bool = true;
2785 }
2786
2787 return CALL_SECTION(send_sim_challenge_request);
2788}
2789
2790/** Enter the SIM-CHALLENGE or AKA-CHALLENGE state
2791 *
2792 * Called by functions which are common to both the EAP-SIM and EAP-AKA state machines
2793 * to enter the correct challenge state.
2794 */
2795STATE_GUARD(common_challenge)
2796{
2797 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2798
2799 switch (eap_aka_sim_session->type) {
2800 case FR_EAP_METHOD_SIM:
2802
2803 case FR_EAP_METHOD_AKA:
2806
2807 default:
2808 break;
2809 }
2810
2811 fr_assert(0);
2813}
2814
2815/** Resume after 'recv Identity-Response { ... }' or 'recv AKA-Identity { ... }'
2816 *
2817 * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
2818 * - ...or call a function to process the contents of the AKA-Identity message, mainly the AT_IDENTITY value.
2819 * - If the message does not contain AT_IDENTITY, then enter the FAILURE-NOTIFICATION state.
2820 * - If the user requested another identity, re-enter the AKA-Identity state.
2821 * - ...or continue based on the value of &Identity-Type which was added by #aka_identity,
2822 * and possibly modified by the user.
2823 * - Fastauth - Enter the REAUTHENTICATION state.
2824 * - Pseudonym - Call 'load pseudonym { ... }'
2825 * - Permanent - Enter the CHALLENGE state.
2826 */
2827RESUME(recv_aka_identity_response)
2828{
2829 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2830 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2831
2832 bool user_set_id_req;
2833 fr_pair_t *identity_type;
2834
2836
2837 /*
2838 * See if the user wants us to request another
2839 * identity.
2840 *
2841 * If they set one themselves don't override
2842 * what they set.
2843 */
2844 user_set_id_req = identity_req_set_by_user(request, eap_aka_sim_session);
2845 if ((eap_aka_sim_session->result.rcode == RLM_MODULE_NOTFOUND) || user_set_id_req) {
2846 if (!user_set_id_req) {
2848 case AKA_SIM_ANY_ID_REQ:
2850 break;
2851
2854 break;
2855
2856 case AKA_SIM_NO_ID_REQ: /* We always request an ID in AKA-Identity unlike SIM-Start */
2857 case AKA_SIM_INIT_ID_REQ: /* Should not happen */
2858 fr_assert(0);
2860
2862 REDEBUG("Peer sent no usable identities");
2864
2865 }
2866 RDEBUG2("Previous section returned (%s), requesting next most permissive identity (%s)",
2869 eap_aka_sim_session->id_req, "<INVALID>"));
2870 }
2872 }
2873
2874 /*
2875 * If the identity looks like a fast re-auth id
2876 * run fast re-auth, otherwise do fullauth.
2877 */
2878 identity_type = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity_type);
2879 if (identity_type) switch (identity_type->vp_uint32) {
2880 case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
2882
2883 /*
2884 * It's a pseudonym, which now needs resolving.
2885 * The resume function here calls aka_challenge_enter
2886 * if pseudonym resolution went ok.
2887 */
2888 case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
2889 eap_aka_sim_session->next = guard_aka_challenge;
2890 return CALL_SECTION(load_pseudonym);
2891
2892 default:
2893 break;
2894 }
2895
2897}
2898
2899/** AKA-IDENTITY state - Continue the state machine after receiving a response to our EAP-Request/AKA-Identity
2900 *
2901 * - Continue based on received AT_SUBTYPE value:
2902 * - EAP-Response/AKA-Identity - call either 'recv Identity-Response { ... }' or if
2903 * provided 'recv AKA-Identity-Response { ... }'. The idea here is that the
2904 * EAP-Identity-Response is really the first round in identity negotiation and
2905 * there's no real value distinguishing between the first round and subsequent
2906 * rounds, but if users do want to run different logic, then give them a way of
2907 * doing that.
2908 * - EAP-Response/AKA-Client-Error - call 'recv Client-Error { ... }' and after that
2909 * send a EAP-Request/SIM-Notification indicating a General Failure.
2910 * - Anything else, enter the FAILURE-NOTIFICATION state.
2911 */
2913{
2914 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2915 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2916 fr_pair_t *subtype_vp = NULL;
2917
2918 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
2919 if (!subtype_vp) {
2920 REDEBUG("Missing AT_SUBTYPE");
2921 goto fail;
2922 }
2923
2924 switch (subtype_vp->vp_uint16) {
2925 /*
2926 * This is the subtype we expect
2927 */
2928 case FR_SUBTYPE_VALUE_AKA_IDENTITY:
2929 {
2930 fr_pair_t *id;
2932
2933 id = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity);
2934 if (!id) {
2935 /*
2936 * 9.2. EAP-Response/Identity
2937 *
2938 * The peer sends EAP-Response/Identity in response to a valid
2939 * EAP-Request/Identity from the server.
2940 * The peer MUST include the AT_IDENTITY attribute. The usage of
2941 * AT_IDENTITY is defined in Section 4.1.
2942 */
2943 REDEBUG("EAP-Response/Identity does not contain AT_IDENTITY");
2945 }
2946
2947 /*
2948 * Add ID hint attributes to the request to help
2949 * the user make policy decisions.
2950 */
2951 identity_hint_pairs_add(&type, NULL, request, id->vp_strvalue);
2956 }
2957
2958 /*
2959 * Update cryptographic identity
2960 */
2962 (uint8_t const *)id->vp_strvalue, id->vp_length);
2963
2965 request,
2966 inst->actions.recv_aka_identity_response ?
2967 inst->actions.recv_aka_identity_response:
2968 inst->actions.recv_common_identity_response,
2970 resume_recv_aka_identity_response,
2971 mod_signal,
2974 }
2975
2976 /*
2977 * Case 1 where we're allowed to send an EAP-Failure
2978 *
2979 * This can happen in the case of a conservative
2980 * peer, where it refuses to provide the permanent
2981 * identity.
2982 */
2983 case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
2984 client_error_debug(request);
2985
2986 return CALL_SECTION(recv_common_client_error);
2987
2988 default:
2989 /*
2990 * RFC 4187 says we *MUST* notify, not just
2991 * send an EAP-Failure in this case.
2992 */
2993 REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
2994 fail:
2996 }
2997}
2998
2999/** Resume after 'send Identity-Request { ... }'
3000 *
3001 * There are three types of user identities that can be implemented
3002 * - Permanent identities such as 0123456789098765@myoperator.com
3003 * Permanent identities can be identified by the leading zero followed by
3004 * by 15 digits (the IMSI number).
3005 * - Ephemeral identities (pseudonyms). These are identities assigned for
3006 * identity privacy so the user can't be tracked. These can identities
3007 * can either be generated as per the 3GPP 'Security aspects of non-3GPP accesses'
3008 * document section 14, where a set of up to 16 encryption keys are used
3009 * to reversibly encrypt the IMSI. Alternatively the pseudonym can be completely
3010 * randomised and stored in a datastore.
3011 * - A fast resumption ID which resolves to data used for fast resumption.
3012 *
3013 * In order to perform full authentication the original IMSI is required for
3014 * forwarding to the HLR. In the case where we can't match/decrypt the pseudonym,
3015 * or can't perform fast resumption, we need to request the full identity from
3016 * the supplicant.
3017 *
3018 */
3019RESUME(send_aka_identity_request)
3020{
3021 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3022
3024
3025 /*
3026 * Update eap_aka_sim_session->id_req in case the the
3027 * user set attributes in `send Identity-Request { ... }`
3028 * Also removes all existing id_req attributes
3029 * from the reply.
3030 */
3032
3033 /*
3034 * Select the right type of identity request attribute
3035 *
3036 * Implement checks on identity request order described
3037 * by RFC4187 section #4.1.5.
3038 *
3039 * The internal state machine should always handle this
3040 * correctly, but the user may have other ideas...
3041 */
3042 if (identity_req_pairs_add(request, eap_aka_sim_session) < 0) {
3044 }
3045 eap_aka_sim_session->last_id_req = eap_aka_sim_session->id_req; /* Record what we last requested */
3046
3047 /*
3048 * Encode the packet
3049 */
3050 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_IDENTITY);
3051
3053}
3054
3055/** Enter the AKA-IDENTITY state
3056 *
3057 */
3059{
3060 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3061 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3062
3064
3065 /*
3066 * If we have an send_aka_identity_request section
3067 * then run that, otherwise just run the normal
3068 * identity request section.
3069 */
3071 request,
3072 inst->actions.send_aka_identity_request ?
3073 inst->actions.send_aka_identity_request:
3076 resume_send_aka_identity_request,
3077 mod_signal,
3078 ~FR_SIGNAL_CANCEL,
3080}
3081
3082/** Resume after 'recv Identity-Response { ... }' or 'recv SIM-Start { ... }'
3083 *
3084 * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
3085 * - ...or call a function to process the contents of the SIM-Start message, mainly the AT_IDENTITY value.
3086 * - If the message does not contain AT_IDENTITY, then enter the FAILURE-NOTIFICATION state.
3087 * - If the user requested another identity, re-enter the SIM-START state.
3088 * - ...or continue based on the value of &Identity-Type which was added by #sim_start,
3089 * and possibly modified by the user.
3090 * - Fastauth
3091 * - If AT_NONCE_MT or AT_SELECTED_VERSION are present, enter the FAILURE-NOTIFICATION state.
3092 * - ...or enter the REAUTHENTICATION state.
3093 * - Pseudonym - Verify selected version and AT_NONCE_MT, then call 'load pseudonym { ... }'
3094 * - Permanent - Verify selected version and AT_NONCE_MT, then enter the CHALLENGE state.
3095 */
3096RESUME(recv_sim_start_response)
3097{
3098 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3099 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3100 bool user_set_id_req;
3101 fr_pair_t *identity_type;
3102
3104
3105 /*
3106 * See if the user wants us to request another
3107 * identity.
3108 *
3109 * If they set one themselves don't override
3110 * what they set.
3111 */
3112 user_set_id_req = identity_req_set_by_user(request, eap_aka_sim_session);
3113 if ((eap_aka_sim_session->result.rcode == RLM_MODULE_NOTFOUND) || user_set_id_req) {
3114 if (!user_set_id_req) {
3116 case AKA_SIM_NO_ID_REQ: /* Should not happen */
3118 break;
3119
3120 case AKA_SIM_ANY_ID_REQ:
3122 break;
3123
3126 break;
3127
3128 case AKA_SIM_INIT_ID_REQ: /* Should not happen */
3129 fr_assert(0);
3131
3133 REDEBUG("Peer sent no usable identities");
3134 failure:
3136 }
3137 RDEBUG2("Previous section returned (%s), requesting next most permissive identity (%s)",
3140 eap_aka_sim_session->id_req, "<INVALID>"));
3141 }
3143 }
3144
3145 /*
3146 * If the identity looks like a fast re-auth id
3147 * run fast re-auth, otherwise do fullauth.
3148 */
3149 identity_type = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity_type);
3150 if (identity_type) switch (identity_type->vp_uint32) {
3151 case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
3152 /*
3153 * RFC 4186 Section #9.2
3154 *
3155 * The AT_NONCE_MT attribute MUST NOT be included if the AT_IDENTITY
3156 * with a fast re-authentication identity is present for fast
3157 * re-authentication
3158 */
3159 if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_nonce_mt)) {
3160 REDEBUG("AT_NONCE_MT is not allowed in EAP-Response/SIM-Reauthentication messages");
3162 }
3163
3164 /*
3165 * RFC 4186 Section #9.2
3166 *
3167 * The AT_SELECTED_VERSION attribute MUST NOT be included if the
3168 * AT_IDENTITY attribute with a fast re-authentication identity is
3169 * present for fast re-authentication.
3170 */
3171 if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_selected_version)) {
3172 REDEBUG("AT_SELECTED_VERSION is not allowed in EAP-Response/SIM-Reauthentication messages");
3174 }
3175
3177
3178 /*
3179 * It's a pseudonym, which now needs resolving.
3180 * The resume function here calls aka_challenge_enter
3181 * if pseudonym resolution went ok.
3182 */
3183 case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
3184 if (sim_start_selected_version_check(request, eap_aka_sim_session) < 0) goto failure;
3185 if (sim_start_nonce_mt_check(request, eap_aka_sim_session) < 0) goto failure;
3186
3187 eap_aka_sim_session->next = guard_sim_challenge;
3188 return CALL_SECTION(load_pseudonym);
3189
3190 /*
3191 * If it's a permanent ID, copy it over to
3192 * the session state list for use in the
3193 * store pseudonym/store session sections
3194 * later.
3195 */
3196 case FR_IDENTITY_TYPE_VALUE_PERMANENT:
3197 if (sim_start_selected_version_check(request, eap_aka_sim_session) < 0) goto failure;
3198 if (sim_start_nonce_mt_check(request, eap_aka_sim_session) < 0) goto failure;
3199
3201 default:
3202 break;
3203 }
3204
3206}
3207
3208/** SIM-START state - Continue the state machine after receiving a response to our EAP-Request/SIM-Start
3209 *
3210 * - Continue based on received AT_SUBTYPE value:
3211 * - EAP-Response/SIM-Start - call either 'recv Identity-Response { ... }' or if
3212 * provided 'recv SIM-Start-Response { ... }'. The idea here is that the
3213 * EAP-Identity-Response is really the first round in identity negotiation and
3214 * there's no real value distinguishing between the first round and subsequent
3215 * rounds, but if users do want to run different logic, then give them a way of
3216 * doing that.
3217 * - EAP-Response/SIM-Client-Error - call 'recv Client-Error { ... }' and after that
3218 * send a EAP-Request/SIM-Notification indicating a General Failure.
3219 * - Anything else, enter the FAILURE-NOTIFICATION state.
3220 */
3222{
3223 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3224 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3225 fr_pair_t *subtype_vp = NULL;
3226
3227 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
3228 if (!subtype_vp) {
3229 REDEBUG("Missing AT_SUBTYPE");
3230 goto fail;
3231 }
3232 switch (subtype_vp->vp_uint16) {
3233 case FR_SUBTYPE_VALUE_SIM_START:
3234 {
3235 eap_session_t *eap_session = eap_session_get(request->parent);
3236 fr_pair_t *id;
3238
3239 id = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity);
3240 if (!id && (eap_aka_sim_session->id_req != AKA_SIM_NO_ID_REQ)) {
3241 /*
3242 * RFC 4186 Section #9.2
3243 *
3244 * The peer sends EAP-Response/SIM/Start in response to a valid
3245 * EAP-Request/SIM/Start from the server.
3246 *
3247 * If and only if the server's EAP-Request/SIM/Start includes one of the
3248 * identity-requesting attributes, then the peer MUST include the
3249 * AT_IDENTITY attribute. The usage of AT_IDENTITY is defined in
3250 * Section 4.2.
3251 * The peer MUST include the AT_IDENTITY attribute. The usage of
3252 * AT_IDENTITY is defined in Section 4.1.
3253 */
3254 REDEBUG("EAP-Response/SIM/Start does not contain AT_IDENTITY");
3256 }
3257
3258 /*
3259 * Add ID hint attributes to the request to help
3260 * the user make policy decisions.
3261 */
3262 if (id) {
3263 identity_hint_pairs_add(&type, NULL, request, id->vp_strvalue);
3268 }
3269
3270 /*
3271 * Update cryptographic identity
3272 *
3273 * We only do this if we received a new identity.
3274 */
3276 (uint8_t const *)id->vp_strvalue, id->vp_length);
3277 /*
3278 * If there's no additional identity provided, just
3279 * use eap_session->identity again...
3280 */
3281 } else {
3282 /*
3283 * Copy the EAP-Identity into our Identity
3284 * attribute to make policies easier.
3285 */
3287 fr_pair_value_bstrdup_buffer(id, eap_session->identity, true);
3288
3289 /*
3290 * Add ID hint attributes to the request to help
3291 * the user make policy decisions.
3292 */
3293 identity_hint_pairs_add(&type, NULL, request, eap_session->identity);
3294
3299 }
3300 }
3301
3303 request,
3304 inst->actions.recv_sim_start_response?
3305 inst->actions.recv_sim_start_response:
3306 inst->actions.recv_common_identity_response,
3308 resume_recv_sim_start_response,
3309 mod_signal,
3312 }
3313
3314 /*
3315 * Case 1 where we're allowed to send an EAP-Failure
3316 *
3317 * This can happen in the case of a conservative
3318 * peer, where it refuses to provide the permanent
3319 * identity.
3320 */
3321 case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
3322 client_error_debug(request);
3323
3324 return CALL_SECTION(recv_common_client_error);
3325
3326 default:
3327 /*
3328 * RFC 4187 says we *MUST* notify, not just
3329 * send an EAP-Failure in this case.
3330 */
3331 REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
3332 fail:
3334 }
3335}
3336
3337/** Resume after 'send Start { ... }'
3338 *
3339 * Send a EAP-Request/SIM-Start message to the supplicant
3340 *
3341 * There are three types of user identities that can be implemented
3342 * - Permanent identities such as 0123456789098765@myoperator.com
3343 * Permanent identities can be identified by the leading zero followed by
3344 * by 15 digits (the IMSI number).
3345 * - Ephemeral identities (pseudonyms). These are identities assigned for
3346 * identity privacy so the user can't be tracked. These can identities
3347 * can either be generated as per the 3GPP 'Security aspects of non-3GPP accesses'
3348 * document section 14, where a set of up to 16 encryption keys are used
3349 * to reversibly encrypt the IMSI. Alternatively the pseudonym can be completely
3350 * randomised and stored in a datastore.
3351 * - A fast resumption ID which resolves to data used for fast resumption.
3352 *
3353 * In order to perform full authentication the original IMSI is required for
3354 * forwarding to the HLR. In the case where we can't match/decrypt the pseudonym,
3355 * or can't perform fast resumption, we need to request the full identity from
3356 * the supplicant.
3357 */
3358RESUME(send_sim_start)
3359{
3360 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3361 fr_pair_t *vp;
3362 uint8_t *p, *end;
3363
3365
3366 p = eap_aka_sim_session->keys.gsm.version_list;
3367 end = p + sizeof(eap_aka_sim_session->keys.gsm.version_list);
3368 eap_aka_sim_session->keys.gsm.version_list_len = 0;
3369
3370 /*
3371 * If the user provided no versions, then
3372 * just add the default (1).
3373 */
3374 if (!(fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_version_list))) {
3376 vp->vp_uint16 = EAP_SIM_VERSION;
3377 }
3378
3379 /*
3380 * Iterate over the the versions adding them
3381 * to the version list we use for keying.
3382 */
3383 for (vp = fr_pair_list_head(&request->reply_pairs);
3384 vp;
3385 vp = fr_pair_list_next(&request->reply_pairs, vp)) {
3386 if (vp->da != attr_eap_aka_sim_version_list) continue;
3387
3388 if ((end - p) < 2) break;
3389
3390 /*
3391 * Store as big endian
3392 */
3393 *p++ = (vp->vp_uint16 & 0xff00) >> 8;
3394 *p++ = (vp->vp_uint16 & 0x00ff);
3395 eap_aka_sim_session->keys.gsm.version_list_len += sizeof(uint16_t);
3396 }
3397
3398 /*
3399 * Update eap_aka_sim_session->id_req in case the the
3400 * user set attributes in `send Identity-Request { ... }`
3401 * Also removes all existing id_req attributes
3402 * from the reply.
3403 */
3405
3406 /*
3407 * Select the right type of identity request attribute
3408 *
3409 * Implement checks on identity request order described
3410 * by RFC4186 section #4.2.5.
3411 *
3412 * The internal state machine should always handle this
3413 * correctly, but the user may have other ideas...
3414 */
3415 if (identity_req_pairs_add(request, eap_aka_sim_session) < 0) {
3417 }
3418 eap_aka_sim_session->last_id_req = eap_aka_sim_session->id_req; /* Record what we last requested */
3419
3420 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_SIM_START);
3421
3423}
3424
3425/** Enter the SIM-START state
3426 *
3427 */
3429{
3430 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3431 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3432
3434
3436 request,
3437 inst->actions.send_sim_start_request ?
3438 inst->actions.send_sim_start_request:
3441 resume_send_sim_start,
3442 mod_signal,
3443 ~FR_SIGNAL_CANCEL,
3445}
3446
3447/** Enter the SIM-START or AKA-IDENTITY state
3448 *
3449 * Called by functions which are common to both the EAP-SIM and EAP-AKA state machines
3450 * to enter the correct Identity-Request state.
3451 */
3452STATE_GUARD(common_identity)
3453{
3454 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3455
3456 switch (eap_aka_sim_session->type) {
3457 case FR_EAP_METHOD_SIM:
3459
3460 case FR_EAP_METHOD_AKA:
3463
3464 default:
3465 break;
3466 }
3467
3468 fr_assert(0);
3470}
3471
3472/** Resume after 'recv Identity-Response { ... }'
3473 *
3474 * - Perform the majority of eap_aka_sim_session_t initialisation.
3475 * - If 'recv Identity-Response { ... }' returned a failure rcode, enter the FAILURE-NOTIFICATION state.
3476 * - ...or continue based on the identity hint byte in the AT_IDENTITY value or EAP-Identity-Response value:
3477 * - If identity is a pseudonym, call load pseudonym { ... }.
3478 * - If identity is a fastauth identity, enter the REAUTHENTICATE state.
3479 * - If identity is a permanent identity, enter the CHALLENGE state.
3480 */
3481RESUME(recv_common_identity_response)
3482{
3483 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3484 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3485 fr_pair_t *eap_type, *method, *identity_type;
3486 fr_aka_sim_method_hint_t running, hinted;
3487
3489
3490 /*
3491 * Ignore attempts to change the EAP-Type
3492 * This must be done before we enter
3493 * the submodule.
3494 */
3495 eap_type = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_type);
3496 if (eap_type) RWDEBUG("Ignoring control.EAP-Type, this must be set *before* the EAP module is called");
3497
3498 method = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_method_hint);
3499
3500 /*
3501 * Set default configuration, we may allow these
3502 * to be toggled by attributes later.
3503 */
3505 eap_aka_sim_session->id_req = AKA_SIM_NO_ID_REQ; /* Set the default */
3506
3507 /*
3508 * Unless AKA-Prime is explicitly disabled,
3509 * use it... It has stronger keying, and
3510 * binds authentication to the network.
3511 */
3512 switch (eap_aka_sim_session->type) {
3513 case FR_EAP_METHOD_SIM:
3514 RDEBUG2("New EAP-SIM session");
3515
3516 running = AKA_SIM_METHOD_HINT_SIM;
3517
3519 eap_aka_sim_session->mac_md = EVP_sha1();
3520 break;
3521
3522 case FR_EAP_METHOD_AKA:
3523 RDEBUG2("New EAP-AKA session");
3524
3525 running = AKA_SIM_METHOD_HINT_AKA;
3526
3528 eap_aka_sim_session->mac_md = EVP_sha1();
3529 break;
3530
3532 RDEBUG2("New EAP-AKA' session");
3533
3535
3538 eap_aka_sim_session->mac_md = EVP_sha256();
3539 break;
3540
3541 default:
3542 fr_assert(0);
3544 }
3545
3546 /*
3547 * Warn the user if the selected identity
3548 * does not match what's hinted.
3549 */
3550 if (method) {
3551 switch (method->vp_uint32) {
3552 case FR_METHOD_HINT_VALUE_AKA_PRIME:
3554 break;
3555
3556 case FR_METHOD_HINT_VALUE_AKA:
3557 hinted = AKA_SIM_METHOD_HINT_AKA;
3558 break;
3559
3560 case FR_METHOD_HINT_VALUE_SIM:
3561 hinted = AKA_SIM_METHOD_HINT_SIM;
3562 break;
3563
3564 default:
3565 hinted = running;
3566 break;
3567 }
3568
3569 if (hinted != running) {
3570 RWDEBUG("EAP-Identity hints that EAP-%s should be started, but we're attempting EAP-%s",
3572 fr_table_str_by_value(fr_aka_sim_id_method_table, running, "<INVALID>"));
3573 }
3574 }
3575
3576 /*
3577 * Unless the user has told us otherwise We always
3578 * start by requesting any ID initially as we can
3579 * always negotiate down.
3580 */
3584 RDEBUG2("Previous section returned (%s), requesting additional identity (%s)",
3587 eap_aka_sim_session->id_req, "<INVALID>"));
3588 } else if (inst->request_identity != AKA_SIM_NO_ID_REQ) {
3590 RDEBUG2("Requesting additional identity (%s)",
3592 eap_aka_sim_session->id_req, "<INVALID>"));
3593 }
3594 }
3595
3596 /*
3597 * For EAP-SIM we _always_ start with a SIM-Start
3598 * for "version negotiation" even if we don't need
3599 * another identity.
3600 */
3602
3603 /*
3604 * User may want us to always request an identity
3605 * initially. The RFCs says this is also the
3606 * better way to operate, as the supplicant
3607 * can 'decorate' the identity in the identity
3608 * response.
3609 *
3610 * For EAP-AKA/EAP-AKA' unless we've been configured
3611 * to always request the identity or it was set
3612 * dynamically, we can save a round of EAP and just
3613 * jump straight into the challenge.
3614 */
3615 if (eap_aka_sim_session->id_req != AKA_SIM_NO_ID_REQ) return STATE_TRANSITION(common_identity);
3616
3617 /*
3618 * If the identity looks like a fast re-auth id
3619 * run fast re-auth, otherwise do a fullauth.
3620 */
3621 identity_type = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity_type);
3622 if (identity_type) switch (identity_type->vp_uint32) {
3623 case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
3625
3626 /*
3627 * It's a pseudonym, which now needs resolving.
3628 * The resume function here calls aka_challenge_enter
3629 * if pseudonym resolution went ok.
3630 */
3631 case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
3632 eap_aka_sim_session->next = guard_common_challenge;
3633 return CALL_SECTION(load_pseudonym);
3634
3635 case FR_IDENTITY_TYPE_VALUE_PERMANENT:
3636 default:
3637 break;
3638 }
3639
3640 return STATE_TRANSITION(common_challenge);
3641}
3642
3643/** Enter the EAP-IDENTITY state
3644 *
3645 * - Process the incoming EAP-Identity-Response
3646 * - Start EAP-SIM/EAP-AKA/EAP-AKA' state machine optionally calling 'recv Identity-Response { ... }'
3647 */
3648STATE(init)
3649{
3650 eap_session_t *eap_session = eap_session_get(request->parent);
3651 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3652 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3653 fr_pair_t *vp;
3655
3656 /*
3657 * Verify we received an EAP-Response/Identity
3658 * message before the supplicant started sending
3659 * EAP-SIM/AKA/AKA' packets.
3660 */
3661 if (!eap_session->identity) {
3662 REDEBUG("All SIM or AKA exchanges must begin with a EAP-Response/Identity message");
3664 }
3665
3666 /*
3667 * Copy the EAP-Identity into our Identity
3668 * attribute to make policies easier.
3669 */
3672
3673 /*
3674 * Add ID hint attributes to the request to help
3675 * the user make policy decisions.
3676 */
3677 identity_hint_pairs_add(&type, NULL, request, eap_session->identity);
3682
3683 /*
3684 * Set the initial crypto identity from
3685 * the EAP-Identity-Response
3686 */
3688 (uint8_t const *)eap_session->identity,
3689 talloc_array_length(eap_session->identity) - 1);
3690
3691 return CALL_SECTION(recv_common_identity_response);
3692}
3693
3694/** Zero out the eap_aka_sim_session when we free it to clear knowledge of secret keys
3695 *
3696 * @param[in] eap_aka_sim_session to free.
3697 * @return 0
3698 */
3700{
3701 memset(eap_aka_sim_session, 0, sizeof(*eap_aka_sim_session));
3702 return 0;
3703}
3704
3705/** Resumes the state machine when receiving a new response packet
3706 *
3707 */
3709{
3710 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3713 0);
3714 module_ctx_t our_mctx = *mctx;
3715
3716 /*
3717 * A new EAP-SIM/AKA/AKA' session!
3718 */
3719 if (!eap_aka_sim_session) {
3720
3721 /*
3722 * Must be allocated in the NULL ctx as this will
3723 * need to persist over multiple rounds of EAP.
3724 */
3725 MEM(eap_aka_sim_session = talloc_zero(NULL, eap_aka_sim_session_t));
3726 talloc_set_destructor(eap_aka_sim_session, _eap_aka_sim_session_free);
3727
3728 /*
3729 * Add new session data to the request
3730 * We only ever need to do this once as it's restored
3731 * during the next round of EAP automatically.
3732 *
3733 * It will also be freed automatically if the request
3734 * is freed and persistable data hasn't been moved
3735 * into the parent.
3736 */
3738 eap_aka_sim_session, true, true, true) < 0)) {
3739 RPEDEBUG("Failed creating new EAP-SIM/AKA/AKA' session");
3741 }
3743
3744 our_mctx.rctx = eap_aka_sim_session;
3745
3746 return state_init(p_result, &our_mctx, request);
3747 }
3748
3749 /*
3750 * This function is called without a resume ctx as it's the
3751 * entry point for each new round of EAP-AKA.
3752 */
3753 our_mctx.rctx = eap_aka_sim_session;
3754
3756
3757 return eap_aka_sim_session->state(p_result, &our_mctx, request);
3758}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define MEM(x)
Definition debug.h:36
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
Definition dict_util.c:2040
static fr_slen_t in
Definition dict.h:841
enum eap_type eap_type_t
eap_type
Definition types.h:44
@ FR_EAP_METHOD_SIM
Definition types.h:63
@ FR_EAP_METHOD_AKA
Definition types.h:68
@ FR_EAP_METHOD_AKA_PRIME
Definition types.h:96
uint8_t * identity
Identity from AT_IDENTITY.
Definition base.h:152
int fr_aka_sim_crypto_umts_kdf_0(fr_aka_sim_keys_t *keys)
Key Derivation Function as described in RFC4187 (EAP-AKA) section 7.
Definition crypto.c:564
int fr_aka_sim_crypto_umts_kdf_1_reauth(fr_aka_sim_keys_t *keys)
Key Derivation Function (Fast-Reauthentication) as described in RFC 5448 (EAP-AKA') section 3....
Definition crypto.c:1139
#define AKA_SIM_VECTOR_UMTS_RAND_SIZE
Definition base.h:73
#define AKA_SIM_VECTOR_GSM_RAND_SIZE
Length of RAND in GSM triplet.
Definition base.h:65
uint8_t * network
Network name (EAP-AKA-Prime only).
Definition base.h:155
size_t mk_len
Definition base.h:212
void fr_aka_sim_crypto_keys_log(request_t *request, fr_aka_sim_keys_t *keys)
Dump the current state of all keys associated with the EAP SIM session.
Definition crypto.c:1226
#define AKA_SIM_VECTOR_GSM_SRES_SIZE
Length of SRES in GSM triplet.
Definition base.h:66
size_t network_len
Length of the network name (EAP-AKA-Prime only).
Definition base.h:156
int fr_aka_sim_crypto_kdf_0_reauth(fr_aka_sim_keys_t *keys)
Key Derivation Function (Fast-Reauthentication) as described in RFC4186/7 (EAP-SIM/AKA) section 7.
Definition crypto.c:990
int fr_aka_sim_vector_gsm_umts_kdf_0_reauth_from_attrs(request_t *request, fr_pair_list_t *vps, fr_aka_sim_keys_t *keys)
Populate a fr_aka_sim_keys_t structure from attributes in the session-state list.
Definition vector.c:824
#define AKA_PRIME_MK_REAUTH_SIZE
The portion of the MK used for re-auth.
Definition base.h:57
void fr_aka_sim_vector_umts_reauth_clear(fr_aka_sim_keys_t *keys)
Clear reauth data if reauthentication failed.
Definition vector.c:917
fr_aka_sim_vector_src_t
Where to get EAP-SIM vectors from.
Definition base.h:99
@ AKA_SIM_VECTOR_SRC_AUTO
Discover where to get Triplets from automatically.
Definition base.h:100
int fr_aka_sim_crypto_gsm_kdf_0(fr_aka_sim_keys_t *keys)
Key Derivation Function as described in RFC4186 (EAP-SIM) section 7.
Definition crypto.c:462
size_t identity_len
Length of the identity.
Definition base.h:153
#define AKA_SIM_MK_SIZE
Definition base.h:54
uint8_t k_aut[32]
Derived authentication key.
Definition base.h:224
size_t k_aut_len
Length of k_aut. 16 for AKA/SIM, 32 for AKA'.
Definition base.h:225
int fr_aka_sim_crypto_umts_kdf_1(fr_aka_sim_keys_t *keys)
Key Derivation Function as described in RFC 5448 (EAP-AKA') section 3.3.
Definition crypto.c:846
int fr_aka_sim_vector_gsm_from_attrs(request_t *request, fr_pair_list_t *vps, int idx, fr_aka_sim_keys_t *keys, fr_aka_sim_vector_src_t *src)
Retrieve GSM triplets from sets of attributes.
Definition vector.c:330
uint8_t k_encr[16]
Derived encryption key.
Definition base.h:226
#define AKA_SIM_VECTOR_UMTS_AUTN_SIZE
Definition base.h:69
int fr_aka_sim_vector_umts_kdf_1_reauth_from_attrs(request_t *request, fr_pair_list_t *vps, fr_aka_sim_keys_t *keys)
Populate a fr_aka_sim_keys_t structure from attributes in the session-state list.
Definition vector.c:873
uint8_t mk[AKA_SIM_MK_MAX_SIZE]
Master key from session attributes.
Definition base.h:211
uint8_t msk[64]
Derived master session key.
Definition base.h:227
int fr_aka_sim_umts_resync_from_attrs(uint64_t *new_sqn, request_t *request, fr_pair_t *auts_vp, fr_aka_sim_keys_t *keys)
Perform milenage AUTS validation and resynchronisation.
Definition vector.c:935
int fr_aka_sim_vector_umts_from_attrs(request_t *request, fr_pair_list_t *vps, fr_aka_sim_keys_t *keys, fr_aka_sim_vector_src_t *src)
Retrieve UMTS quintuplets from sets of attributes.
Definition vector.c:755
#define EAP_SIM_VERSION
Definition base.h:76
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Definition interpret.h:134
HIDDEN fr_dict_attr_t const * attr_ms_mppe_send_key
Definition base.c:101
HIDDEN fr_dict_attr_t const * attr_ms_mppe_recv_key
Definition base.c:102
HIDDEN fr_dict_attr_t const * attr_eap_type
Definition base.c:92
void eap_add_reply(request_t *request, fr_dict_attr_t const *da, uint8_t const *value, int len)
Definition base.c:387
char * identity
NAI (User-Name) from EAP-Identity.
Definition session.h:56
static eap_session_t * eap_session_get(request_t *request)
Definition session.h:83
eap_type_t type
EAP method number.
Definition session.h:50
Tracks the progress of a single session of any EAP method.
Definition session.h:41
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_kdf
Definition base.c:81
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_counter
Definition base.c:67
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_nonce_s
Definition base.c:90
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_permanent_id_req
Definition base.c:92
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_encr_data
Definition base.c:69
HIDDEN fr_dict_attr_t const * attr_session_data
Definition base.c:102
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_next_reauth_id
Definition base.c:88
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_counter_too_small
Definition base.c:68
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_permanent_identity
Definition base.c:93
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_nonce_mt
Definition base.c:89
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_auts
Definition base.c:62
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_kdf_identity
Definition base.c:82
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_k_encr
Definition base.c:78
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_version_list
Definition base.c:100
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_checkcode
Definition base.c:64
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_res
Definition base.c:95
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_k_aut
Definition base.c:77
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_identity
Definition base.c:73
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_client_error_code
Definition base.c:66
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_autn
Definition base.c:61
HIDDEN fr_dict_attr_t const * attr_sim_opc
Definition base.c:114
HIDDEN fr_dict_attr_t const * attr_session_id
Definition base.c:103
HIDDEN fr_dict_attr_t const * attr_sim_ki
Definition base.c:112
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_result_ind
Definition base.c:96
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_next_pseudonym
Definition base.c:87
HIDDEN fr_dict_attr_t const * attr_sim_sqn
Definition base.c:115
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_any_id_req
Definition base.c:60
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_mac
Definition base.c:84
HIDDEN fr_dict_attr_t const * attr_sim_amf
Definition base.c:111
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_method_hint
Definition base.c:85
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_selected_version
Definition base.c:97
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_fullauth_id_req
Definition base.c:70
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_subtype
Definition base.c:99
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_hmac_extra_request
Definition base.c:71
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_notification
Definition base.c:91
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_rand
Definition attrs.h:39
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_identity_type
Definition base.c:74
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_hmac_extra_response
Definition base.c:72
HIDDEN fr_value_box_t const * enum_kdf_prime_with_ck_prime_ik_prime
Definition base.c:189
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_kdf_input
Definition base.c:83
fr_table_num_sorted_t const fr_aka_sim_id_method_table[]
Definition id.c:43
char fr_aka_sim_hint_byte(fr_aka_sim_id_type_t type, fr_aka_sim_method_hint_t method)
Return the expected identity hint for a given type/method combination.
Definition id.c:375
fr_table_num_sorted_t const fr_aka_sim_id_request_table[]
Definition id.c:33
int fr_aka_sim_id_type(fr_aka_sim_id_type_t *type, fr_aka_sim_method_hint_t *hint, char const *id, size_t id_len)
Determine what type of ID was provided in the initial identity response.
Definition id.c:167
@ AKA_SIM_INIT_ID_REQ
We've requested no ID. This is used for last_id_req.
Definition id.h:78
@ AKA_SIM_NO_ID_REQ
We're not requesting any ID.
Definition id.h:79
@ AKA_SIM_ANY_ID_REQ
Request IMSI, Pseudonym or Fast-reauth.
Definition id.h:80
@ AKA_SIM_FULLAUTH_ID_REQ
Request IMSI or Pseudonym.
Definition id.h:81
@ AKA_SIM_PERMANENT_ID_REQ
Request IMSI.
Definition id.h:82
@ ID_TAG_AKA_PRIME_FASTAUTH
Fastuath, continue EAP-AKA-Prime.
Definition id.h:72
@ ID_TAG_AKA_FASTAUTH
Fastauth, continue EAP-AKA.
Definition id.h:68
@ ID_TAG_SIM_PSEUDONYM
Pseudonym, continue EAP-SIM.
Definition id.h:63
@ ID_TAG_AKA_PRIME_PSEUDONYM
Pseudonym, continue EAP-AKA-Prime.
Definition id.h:71
@ ID_TAG_AKA_PSEUDONYM
Pseudonym, continue EAP-AKA.
Definition id.h:67
@ ID_TAG_SIM_FASTAUTH
Fastauth, continue EAP-SIM.
Definition id.h:64
fr_aka_sim_method_hint_t
SIM/AKA method hints.
Definition id.h:39
@ AKA_SIM_METHOD_HINT_AKA
The identity hints the supplicant wants to use EAP-AKA.
Definition id.h:43
@ AKA_SIM_METHOD_HINT_SIM
The identity hints the supplicant wants to use EAP-SIM.
Definition id.h:41
@ AKA_SIM_METHOD_HINT_AKA_PRIME
Definition id.h:45
@ AKA_SIM_METHOD_HINT_UNKNOWN
We don't know what method the identity hints at.
Definition id.h:40
fr_aka_sim_id_type_t
SIM/AKA identity type hints.
Definition id.h:53
@ AKA_SIM_ID_TYPE_UNKNOWN
We don't know what type of identity this is.
Definition id.h:54
@ AKA_SIM_ID_TYPE_PSEUDONYM
This is a custom pseudonym.
Definition id.h:56
@ AKA_SIM_ID_TYPE_PERMANENT
This is a permanent identity (the IMSI of the SIM).
Definition id.h:55
@ AKA_SIM_ID_TYPE_FASTAUTH
This is a fastauth (session-resumption) id.
Definition id.h:57
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:443
#define RWDEBUG(fmt,...)
Definition log.h:361
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition log.h:335
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RHEXDUMP_INLINE2(_data, _len, _fmt,...)
Definition log.h:685
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define RPWDEBUG2(fmt,...)
Definition log.h:367
#define RINDENT()
Indent R* messages by one level.
Definition log.h:430
talloc_free(reap)
unsigned short uint16_t
unsigned char uint8_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
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.
Definition pair.c:2936
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.
Definition pair.c:774
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.
Definition pair.c:697
int fr_pair_cmp(fr_pair_t const *a, fr_pair_t const *b)
Compare two pairs, using the operator from "a".
Definition pair.c:1966
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1342
int fr_pair_delete_by_da(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list.
Definition pair.c:1686
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.
Definition pair.c:2786
int fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition pair.c:1823
int fr_pair_value_copy(fr_pair_t *dst, fr_pair_t *src)
Copy the value from one pair to another.
Definition pair.c:2564
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:38
#define pair_update_request(_attr, _da)
static bool done
Definition radclient.c:81
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RDEBUG(fmt,...)
Definition radclient.h:53
void fr_rand_str(uint8_t *out, size_t len, char class)
Generate a random string.
Definition rand.c:163
fr_table_num_sorted_t const rcode_table[]
Definition rcode.c:35
#define RLM_MODULE_USER_SECTION_REJECT
Rcodes that translate to a user configurable section failing overall.
Definition rcode.h:74
#define RETURN_UNLANG_HANDLED
Definition rcode.h:59
#define RETURN_UNLANG_REJECT
Definition rcode.h:56
#define RETURN_UNLANG_OK
Definition rcode.h:58
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:43
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:41
@ RLM_MODULE_NOTFOUND
User not found.
Definition rcode.h:47
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:49
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:48
void * request_data_reference(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request without removing it.
void * request_data_get(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request.
#define request_data_add(_request, _unique_ptr, _unique_int, _opaque, _free_on_replace, _free_on_parent, _persist)
Add opaque data to a request_t.
void * data
Module's instance data.
Definition module.h:291
unlang_action_t(* module_method_t)(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Module section callback.
Definition module.h:69
#define pair_append_control(_attr, _da)
Allocate and append a fr_pair_t to the control list.
Definition pair.h:57
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition pair.h:129
#define pair_append_session_state(_attr, _da)
Allocate and append a fr_pair_t to session-state list.
Definition pair.h:67
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
Definition pair.h:37
#define pair_delete_request(_pair_or_da)
Delete a fr_pair_t in the request list.
Definition pair.h:172
#define pair_update_session_state(_attr, _da)
Return or allocate a fr_pair_t in the session_state list.
Definition pair.h:151
#define pair_delete_reply(_pair_or_da)
Delete a fr_pair_t in the reply list.
Definition pair.h:181
#define pair_append_reply(_attr, _da)
Allocate and append a fr_pair_t to reply list.
Definition pair.h:47
#define pair_delete_control(_pair_or_da)
Delete a fr_pair_t in the control list.
Definition pair.h:190
#define pair_update_control(_attr, _da)
Return or allocate a fr_pair_t in the control list.
Definition pair.h:140
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
unlang_action_t unlang_module_yield_to_section(unlang_result_t *p_result, request_t *request, CONF_SECTION *subcs, rlm_rcode_t default_rcode, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Definition module.c:249
static bool identity_req_set_by_user(request_t *request, eap_aka_sim_session_t *eap_aka_sim_session)
Sync up what identity we're requesting with attributes in the reply.
aka_challenge
AKA-CHALLENGE state - Continue the state machine after receiving a response to our EAP-Request/SIM-Ch...
#define STATE_NO_RESULT(_x)
static int checkcode_validate(request_t *request)
Check &control.checkcode matches &reply.checkcode.
eap_aka_sim_session_t * eap_aka_sim_session
static int sim_start_selected_version_check(request_t *request, eap_aka_sim_session_t *eap_aka_sim_session)
Helper function to check for the presence and length of AT_SELECTED_VERSION and copy its value into t...
common_success_notification
static int identity_req_pairs_add(request_t *request, eap_aka_sim_session_t *eap_aka_sim_session)
Add an Identity Request attribute to the reply.
static void mod_signal(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
Cancel a call to a submodule.
static unlang_action_t common_reauthentication_request_compose(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request, eap_aka_sim_session_t *eap_aka_sim_session)
Send a EAP-Request/(AKA|SIM)-Reauthenticate message to the supplicant.
static int sim_start_nonce_mt_check(request_t *request, eap_aka_sim_session_t *eap_aka_sim_session)
Helper function to check for the presence and length of AT_NONCE_MT and copy its value into the keys ...
static void state_set(request_t *request, eap_aka_sim_session_t *eap_aka_sim_session, module_method_t new_state)
Print debugging information, and write new state to eap_aka_sim_session->state.
common_failure_notification
FAILURE-NOTIFICATION state - Continue the state machine after receiving a response to our EAP-Request...
static int mac_validate(request_t *request)
Check &control.mac matches &reply.mac.
static void common_crypto_export(request_t *request, eap_aka_sim_session_t *eap_aka_sim_session, uint8_t const *hmac_extra_request, size_t hmac_extra_request_len, uint8_t const *hmac_extra_response, size_t hmac_extra_response_len)
static int identity_to_permanent_identity(request_t *request, fr_pair_t *in, eap_type_t eap_type, bool strip_hint)
Copy the incoming identity to the permanent identity attribute.
static size_t aka_sim_state_table_len
static unlang_action_t session_and_pseudonym_store(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request, eap_aka_sim_session_t *eap_aka_sim_session, module_method_t next)
Implements a set of states for storing pseudonym and fastauth identities.
#define STATE_GUARD(_x)
unlang_action_t eap_aka_sim_state_machine_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Resumes the state machine when receiving a new response packet.
fr_pair_t * subtype_vp
#define CALL_SECTION(_x)
aka_identity
AKA-IDENTITY state - Continue the state machine after receiving a response to our EAP-Request/AKA-Ide...
static void identity_hint_pairs_add(fr_aka_sim_id_type_t *type_p, fr_aka_sim_method_hint_t *method_p, request_t *request, char const *identity)
Based on the hint byte in the identity, add &Identity-Type and &Method-Hint attributes.
#define STATE_SET(_new_state)
static unlang_action_t common_reauthentication_request_send(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Called after 'store session { ... }' and 'store pseudonym { ... }'.
static void client_error_debug(request_t *request)
Print out the error the client returned.
static bool after_authentication(eap_aka_sim_session_t *eap_aka_sim_session)
Determine if we're after authentication.
init
Enter the EAP-IDENTITY state.
eap_aka_sim_process_conf_t * inst
fr_pair_value_bstrdup_buffer(vp, eap_session->identity, true)
#define RESUME(_x)
#define EAP_TLS_MPPE_KEY_LEN
static fr_table_ptr_ordered_t const aka_sim_state_table[]
#define SECTION_RCODE_IGNORED
Warn the user that the rcode they provided is being ignored in this section.
static unlang_action_t aka_challenge_request_send(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Called after 'store session { ... }' and 'store pseudonym { ... }'.
static unlang_action_t session_and_pseudonym_clear(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request, eap_aka_sim_session_t *eap_aka_sim_session, module_method_t next)
Implements a set of states for clearing out pseudonym and fastauth identities.
static unlang_action_t sim_challenge_request_send(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Called after 'store session { ... }' and 'store pseudonym { ... }'.
#define STATE_GUARD_NO_RESULT(_x)
eap_success
SUCCESS state - State machine exit point after sending EAP-Success.
static void common_reply(request_t *request, eap_aka_sim_session_t *eap_aka_sim_session, uint16_t subtype)
Export EAP-SIM/AKA['] attributes.
static int _eap_aka_sim_session_free(eap_aka_sim_session_t *eap_aka_sim_session)
Zero out the eap_aka_sim_session when we free it to clear knowledge of secret keys.
common_reauthentication
REAUTHENTICATION state - Continue the state machine after receiving a response to our EAP-Request/SIM...
static void crypto_identity_set(request_t *request, eap_aka_sim_session_t *eap_aka_sim_session, uint8_t const *identity, size_t len)
Set the crypto identity from a received identity.
#define SECTION_RCODE_PROCESS
Trigger a state transition to FAILURE-NOTIFICATION if the section returned a failure code.
#define STATE(_x)
sim_start
SIM-START state - Continue the state machine after receiving a response to our EAP-Request/SIM-Start.
#define STATE_TRANSITION(_x)
RETURN_UNLANG_FAIL
fr_aka_sim_id_type_t type
fr_pair_t * vp
sim_challenge
SIM-CHALLENGE state - Continue the state machine after receiving a response to our EAP-Request/SIM-Ch...
eap_failure
FAILURE state - State machine exit point after sending EAP-Failure.
Declarations for EAP-AKA.
unlang_result_t result
The result of the last unlang section we evaluted.
bool protected_success
Send a success notification as well as and EAP-Success packet.
EVP_MD const * mac_md
HMAC-MD we use to generate the MAC.
eap_aka_sim_actions_t actions
Pre-compiled virtual server sections.
fr_aka_sim_id_req_type_t id_req
The type of identity we're requesting.
CONF_SECTION * load_session
Load cached authentication vectors.
bool challenge_success
Whether we received the correct challenge response.
size_t ephemeral_id_length
The length of any identities we're generating.
eap_type_t type
The preferred EAP-Type of this instance of the EAP-SIM/AKA/AKA' state machine.
fr_aka_sim_keys_t keys
Various EAP-AKA/AKA'/SIMkeys.
fr_aka_sim_id_req_type_t last_id_req
The last identity request we sent.
module_method_t state
The process function to run when we receive the next round of EAP-SIM/AKA/AKA'.
module_method_t next
Resumption function to call after executing common code.
uint16_t failure_type
One of the following values:
char const * network_name
Network ID as described by RFC 5448.
bool allow_encrypted
Whether we can send encrypted attributes at this phase of the attempt.
bool send_result_ind
Say that we would like to use protected result indications (AKA-Notification-Success).
char * pseudonym_sent
Pseudonym value we sent.
bool strip_permanent_identity_hint
Control whether the hint byte is stripped when populating Permanent-Identity.
bool reauthentication_success
Whether we got a valid reauthentication response.
char * fastauth_sent
Fastauth value we sent.
bool prev_recv_sync_failure
We only allow one sync failure per session for sanity.
eap_type_t type
Either FR_TYPE_AKA, or FR_TYPE_AKA_PRIME.
uint16_t kdf
The key derivation function used to derive session keys.
fr_aka_sim_id_req_type_t request_identity
Whether we always request the identity of the subscriber.
CONF_SECTION * load_pseudonym
Resolve a pseudonym to a permanent ID.
CONF_SECTION * send_common_identity_request
Called when we're about to request a different identity.
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
An element in an arbitrarily ordered array of name to ptr mappings.
Definition table.h:73
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:586
Master include file to access all functions and structures in the library.
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.
Definition pair_inline.c:69
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
Definition pair_inline.c:93
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition pair.h:261
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.
Definition pair_inline.c:42
int fr_value_box_bstrdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated talloced buffer to a fr_value_box_t.
Definition value.c:4439
int fr_value_box_bstrdup_buffer_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a talloced buffer containing a nul terminated string to a box, but don't copy it.
Definition value.c:4484
int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Copy a buffer to a fr_value_box_t.
Definition value.c:4620
#define fr_box_strvalue_len(_val, _len)
Definition value.h:305
int nonnull(2, 5))