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: 4b7fbb5d31fbdca0659b3aaab8c27d15f0507630 $")
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(rlm_rcode_t *p_result, \
45 module_ctx_t const *mctx, \
46 request_t *request)
47#define STATE_GUARD(_x) static unlang_action_t guard_ ## _x(rlm_rcode_t *p_result, \
48 module_ctx_t const *mctx, \
49 request_t *request)
50
51#define RESUME(_x) static inline unlang_action_t resume_ ## _x(rlm_rcode_t *p_result, \
52 module_ctx_t const *mctx, \
53 request_t *request)
54
55#define STATE_TRANSITION(_x) guard_ ## _x(p_result, mctx, request)
56
57#define CALL_SECTION(_x) unlang_module_yield_to_section(p_result, \
58 request, \
59 inst->actions._x, \
60 RLM_MODULE_NOOP, \
61 resume_ ## _x, \
62 mod_signal, \
63 ~FR_SIGNAL_CANCEL, \
64 talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t))
65
66/*
67 * Declare all state and guard functions to
68 * avoid ordering issues.
69 */
84STATE_GUARD(common_challenge);
89STATE_GUARD(common_identity);
91
93 { L("INIT"), NULL },
94
95 { L("EAP-IDENTITY"), (void *)state_init },
96 { L("SIM-START"), (void *)state_sim_start },
97 { L("AKA-IDENTITY"), (void *)state_aka_identity },
98
99 { L("SIM-CHALLENGE"), (void *)state_sim_challenge },
100 { L("AKA-CHALLENGE"), (void *)state_aka_challenge },
101
102 { L("SUCCESS-NOTIFICATION"), (void *)state_common_success_notification },
103 { L("FAILURE-NOTIFICATION"), (void *)state_common_failure_notification },
104
105 { L("REAUTHENTICATION"), (void *)state_common_reauthentication },
106
107 { L("EAP-SUCCESS"), (void *)state_eap_success },
108 { L("EAP-FAILURE"), (void *)state_eap_failure }
109};
111
112/** Cancel a call to a submodule
113 *
114 * @param[in] mctx UNUSED.
115 * @param[in] request The current request.
116 * @param[in] action to perform.
117 */
118static void mod_signal(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
119{
120 RDEBUG2("Request cancelled - Destroying session");
121
122 /*
123 * Remove data from the request to
124 * avoid double free.
125 */
126 if (!fr_cond_assert(request_data_get(request, (void *)eap_aka_sim_state_machine_process, 0) == mctx->rctx)) return;
127
128 talloc_free(mctx->rctx);
129}
130
131/** Warn the user that the rcode they provided is being ignored in this section
132 *
133 */
134#define SECTION_RCODE_IGNORED \
135do { \
136 switch (unlang_interpret_stack_result(request)) { \
137 case RLM_MODULE_USER_SECTION_REJECT: \
138 RWDEBUG("Ignoring rcode (%s)", \
139 fr_table_str_by_value(rcode_table, unlang_interpret_stack_result(request), "<invalid>")); \
140 break; \
141 default: \
142 break; \
143 } \
144} while(0)
145
146/** Trigger a state transition to FAILURE-NOTIFICATION if the section returned a failure code
147 *
148 */
149#define SECTION_RCODE_PROCESS \
150do { \
151 if (after_authentication(eap_aka_sim_session)) { \
152 switch (unlang_interpret_stack_result(request)) { \
153 case RLM_MODULE_REJECT: \
154 case RLM_MODULE_DISALLOW: \
155 eap_aka_sim_session->failure_type = FR_NOTIFICATION_VALUE_TEMPORARILY_DENIED; \
156 return STATE_TRANSITION(common_failure_notification); \
157 case RLM_MODULE_NOTFOUND: \
158 eap_aka_sim_session->failure_type = FR_NOTIFICATION_VALUE_NOT_SUBSCRIBED; \
159 return STATE_TRANSITION(common_failure_notification); \
160 case RLM_MODULE_INVALID: \
161 case RLM_MODULE_FAIL: \
162 eap_aka_sim_session->failure_type = FR_NOTIFICATION_VALUE_GENERAL_FAILURE_AFTER_AUTHENTICATION;\
163 return STATE_TRANSITION(common_failure_notification); \
164 default: \
165 break; \
166 } \
167 } else { \
168 switch (unlang_interpret_stack_result(request)) { \
169 case RLM_MODULE_USER_SECTION_REJECT: \
170 REDEBUG("Section rcode (%s) indicates we should reject the user", \
171 fr_table_str_by_value(rcode_table, unlang_interpret_stack_result(request), "<INVALID>")); \
172 return STATE_TRANSITION(common_failure_notification); \
173 default: \
174 break; \
175 } \
176 } \
177} while(0)
178
179/** Print debugging information, and write new state to eap_aka_sim_session->state
180 *
181 */
182static inline CC_HINT(always_inline) void state_set(request_t *request,
184 module_method_t new_state)
185{
187
188 if (new_state != old_state) {
189 RDEBUG2("Changed state %s -> %s",
190 fr_table_str_by_value(aka_sim_state_table, (void *)old_state, "<unknown>"),
191 fr_table_str_by_value(aka_sim_state_table, (void *)new_state, "<unknown>"));
192 } else {
193 RDEBUG2("Reentering state %s",
194 fr_table_str_by_value(aka_sim_state_table, (void *)old_state, "<unknown>"));
195 }
196
197 eap_aka_sim_session->state = new_state;
198}
199#define STATE_SET(_new_state) state_set(request, talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t), state_ ## _new_state)
200
201/** Determine if we're after authentication
202 *
203 */
208
209/** Print out the error the client returned
210 *
211 */
212static inline CC_HINT(always_inline) void client_error_debug(request_t *request)
213{
214 fr_pair_t *vp;
215
216 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_client_error_code);
217 if (!vp) {
218 REDEBUG("Peer has not supplied a AT_ERROR_CODE");
219 } else {
220 REDEBUG("Peer rejected request with error: %i (%pV)", vp->vp_uint16, &vp->data);
221 }
222}
223
224/** Sync up what identity we're requesting with attributes in the reply
225 *
226 */
228{
229 bool set_by_user = false;
230
231 /*
232 * Check if the user included any of the
233 * ID req attributes. If they did, use
234 * them to inform what we do next, and
235 * then delete them so they don't screw
236 * up any of the other code.
237 */
238 fr_pair_list_foreach(&request->reply_pairs, vp) {
241 found:
242 set_by_user = true;
243 RDEBUG2("Previous section added &reply.%pP, will request additional identity", vp);
244 fr_pair_delete(&request->reply_pairs, vp);
245 }
248 goto found;
249 }
250 else if (vp->da == attr_eap_aka_sim_any_id_req) {
252 goto found;
253 }
254 }
255
256 return set_by_user;
257}
258
259/** Based on the hint byte in the identity, add &Identity-Type and &Method-Hint attributes
260 *
261 */
263 request_t *request, char const *identity)
264{
267
268 /*
269 * Process the identity that we received.
270 */
271 if (fr_aka_sim_id_type(&type, &method,
272 identity, talloc_array_length(identity) - 1) < 0) {
273 RPWDEBUG2("Failed parsing identity, continuing anyway");
274 }
275
276 /*
277 * Map the output from the generic ID parser
278 * function to specific EAP-AKA internal
279 * attributes in the subrequest.
280 */
282 fr_pair_t *vp = NULL;
283
285 switch (type) {
287 vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_PERMANENT;
288 break;
289
291 vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_PSEUDONYM;
292 break;
293
295 vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_FASTAUTH;
296 break;
297
298 default:
299 fr_assert(0);
300 }
301 }
302
303 /*
304 * Map the output from the generic ID parser
305 * function to specific EAP-AKA internal
306 * attributes in the subrequest.
307 */
308 if (method != AKA_SIM_METHOD_HINT_UNKNOWN) {
309 fr_pair_t *vp = NULL;
310
312 switch (method) {
314 vp->vp_uint32 = FR_METHOD_HINT_VALUE_AKA_PRIME;
315 break;
316
318 vp->vp_uint32 = FR_METHOD_HINT_VALUE_AKA;
319 break;
320
322 vp->vp_uint32 = FR_METHOD_HINT_VALUE_SIM;
323 break;
324
325 default:
326 fr_assert(0);
327 }
328 }
329
330 if (type_p) *type_p = type;
331 if (method_p) *method_p = method;
332}
333
334/** Add an Identity Request attribute to the reply
335 *
336 * Verify the progression of identity requests is valid.
337 *
338 * @param[in] request The current request.
339 * @param[in] eap_aka_sim_session The current eap_aka_sim_session.
340 * @return
341 * - 0 on success.
342 * - -1 on failure (progression of identities was not valid).
343 */
345{
346 fr_pair_t *vp;
347
348 switch (eap_aka_sim_session->id_req) {
349 /*
350 * This is allowed for EAP-SIM.
351 *
352 * The EAP-SIM-Start packet gets used both for "version negotiation" and
353 * for request identities, so for EAP-SIM it's perfectly acceptable
354 * to send four Sim-Start packets:
355 *
356 * - No ID
357 * - Any ID
358 * - Fullauth ID
359 * - Permanent ID
360 *
361 * We need to represent the starting state as separate from no id req,
362 * so that we can catch potential loops in the identity statate machine
363 */
366 id_out_of_order:
367 REDEBUG("Cannot send %s, already sent %s",
369 eap_aka_sim_session->id_req, "<INVALID>"),
371 eap_aka_sim_session->last_id_req, "<INVALID>"));
372 return -1;
373 }
374 break;
375
380 break;
381
382 default:
383 goto id_out_of_order;
384 }
386 vp->vp_bool = true;
387 break;
388
392 case AKA_SIM_NO_ID_REQ: /* Not sent anything before */
393 case AKA_SIM_ANY_ID_REQ: /* Last request was for any ID, but the re-auth ID was bad */
394 break;
395
396 default:
397 goto id_out_of_order;
398 }
400 vp->vp_bool = true;
401 break;
402
406 case AKA_SIM_NO_ID_REQ: /* Not sent anything before */
407 case AKA_SIM_ANY_ID_REQ: /* Last request was for any ID, but the re-auth ID was bad */
408 case AKA_SIM_FULLAUTH_ID_REQ: /* ...didn't understand the pseudonym either */
409 break;
410
411 default:
412 goto id_out_of_order;
413 }
415 vp->vp_bool = true;
416 break;
417
418 default:
419 fr_assert(0);
420 }
421
422 return 0;
423}
424
425/** Copy the incoming identity to the permanent identity attribute
426 *
427 * If the incoming ID really looks like a permanent ID, and we were
428 * told it was a permanent ID, then (optionally) trim the first byte
429 * to form the real permanent ID.
430 *
431 * Otherwise copy the entire incoming Identity to the
432 * &session-state.Permanent-Identity attribute.
433 *
434 * @param[in] request The current request.
435 * @param[in] in current identity.
436 * @param[in] eap_type The current eap_type.
437 * @param[in] strip_hint Whether to strip the hint byte off the permanent identity
438 */
440{
441 fr_aka_sim_id_type_t our_type;
442 fr_aka_sim_method_hint_t our_method, expected_method;
443 fr_pair_t *vp;
444
445 if (in->vp_length == 0) {
446 RDEBUG2("Not processing zero length identity");
447 return -1;
448 }
449
450 /*
451 * Not requested to strip hint, don't do anything
452 * fancy, just copy Identity -> Permanent-Identity.
453 */
454 if (!strip_hint) {
456 fr_pair_value_bstrndup(vp, in->vp_strvalue, in->vp_length, true);
457 return 0;
458 }
459
460 switch (eap_type) {
462 expected_method = AKA_SIM_METHOD_HINT_SIM;
463 break;
464
466 expected_method = AKA_SIM_METHOD_HINT_AKA;
467 break;
468
470 expected_method = AKA_SIM_METHOD_HINT_AKA_PRIME;
471 break;
472
473 default:
474 return -1;
475 }
476
477 /*
478 * First, lets see if this looks like an identity
479 * we can process.
480 *
481 * For now we allow all permanent identities no
482 * matter what EAP method.
483 *
484 * This is because we could be starting a different
485 * EAP method to the one the identity hinted,
486 * but we still want to strip the first byte.
487 */
488 if ((fr_aka_sim_id_type(&our_type, &our_method, in->vp_strvalue, in->vp_length) < 0) ||
489 (our_type != AKA_SIM_ID_TYPE_PERMANENT)) {
491 fr_pair_value_bstrndup(vp, in->vp_strvalue, in->vp_length, true);
492
493 RDEBUG2("%s has incorrect hint byte, expected '%c', got '%c'. "
494 "'hint' byte not stripped",
497 fr_aka_sim_hint_byte(our_type, our_method));
498 RINDENT();
499 RDEBUG2("&session-state.%pP", vp);
500 REXDENT();
501 } else {
502 /*
503 * To get here the identity must be >= 1 and must have
504 * had the expected hint byte.
505 *
506 * Strip off the hint byte, and then add the permanent
507 * identity to the output list.
508 */
510 fr_pair_value_bstrndup(vp, in->vp_strvalue + 1, in->vp_length - 1, true);
511
512 RDEBUG2("Stripping 'hint' byte from %s", attr_eap_aka_sim_permanent_identity->name);
513 RINDENT();
514 RDEBUG2("&session-state.%pP", vp);
515 REXDENT();
516 }
517
518 return 0;
519}
520
521/** Check &control.checkcode matches &reply.checkcode
522 *
523 * @param[in] request The current request.
524 * @return
525 * - 1 if the check was skipped.
526 * - 0 if the check was successful.
527 * - -1 if the check failed.
528 */
529static int checkcode_validate(request_t *request)
530{
531 fr_pair_t *peer_checkcode, *our_checkcode;
532 /*
533 * Checkcode validation
534 *
535 * The actual cryptographic calculations are
536 * done by the calling module, we just check
537 * the result.
538 */
539 our_checkcode = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_checkcode);
540 if (our_checkcode) {
541 /*
542 * If the peer doesn't include a checkcode then that
543 * means they don't support it, and we can't validate
544 * their view of the identity packets.
545 */
546 peer_checkcode = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_checkcode);
547 if (peer_checkcode) {
548 if (fr_pair_cmp(peer_checkcode, our_checkcode) == 0) {
549 RDEBUG2("Received AT_CHECKCODE matches calculated AT_CHECKCODE");
550 return 0;
551 } else {
552 REDEBUG("Received AT_CHECKCODE does not match calculated AT_CHECKCODE");
553 RHEXDUMP_INLINE2(peer_checkcode->vp_octets, peer_checkcode->vp_length, "Received");
554 RHEXDUMP_INLINE2(our_checkcode->vp_octets, our_checkcode->vp_length, "Expected");
555 return -1;
556 }
557 /*
558 * Only print something if we calculated a checkcode
559 */
560 } else {
561 RDEBUG2("Peer didn't include AT_CHECKCODE, skipping checkcode validation");
562 }
563 }
564 return 1;
565}
566
567/** Check &control.mac matches &reply.mac
568 *
569 * @param[in] request The current request.
570 * @return
571 * - 0 if the check was successful.
572 * - -1 if the check failed.
573 */
574static int mac_validate(request_t *request)
575{
576 fr_pair_t *peer_mac, *our_mac;
577 /*
578 * mac validation
579 *
580 * The actual cryptographic calculations are
581 * done by the calling module, we just check
582 * the result.
583 */
584 our_mac = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_mac);
585 if (!our_mac) {
586 REDEBUG("Missing &control.%s", attr_eap_aka_sim_mac->name);
587 return -1;
588
589 }
590
591 /*
592 * If the peer doesn't include a mac then that
593 * means they don't support it, and we can't validate
594 * their view of the identity packets.
595 */
596 peer_mac = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_mac);
597 if (!peer_mac) {
598 REDEBUG("Peer didn't include AT_MAC");
599 return -1;
600 }
601
602 if (fr_pair_cmp(peer_mac, our_mac) != 0) {
603 REDEBUG("Received AT_MAC does not match calculated AT_MAC");
604 RHEXDUMP_INLINE2(peer_mac->vp_octets, peer_mac->vp_length, "Received");
605 RHEXDUMP_INLINE2(our_mac->vp_octets, our_mac->vp_length, "Expected");
606 return -1;
607 }
608
609 RDEBUG2("Received AT_MAC matches calculated AT_MAC");
610 return 0;
611}
612
613/** Set the crypto identity from a received identity
614 *
615 */
617 uint8_t const *identity, size_t len)
618{
619 RDEBUG3("Setting cryptographic identity to \"%pV\"", fr_box_strvalue_len((char const *)identity, len));
620
623 MEM(eap_aka_sim_session->keys.identity = talloc_memdup(eap_aka_sim_session, identity, len));
624
625}
626
627/** Resume after 'store session { ... }'
628 *
629 */
630RESUME(store_session)
631{
632 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
633
634 switch (unlang_interpret_stack_result(request)) {
635 /*
636 * Store failed. Don't send fastauth id
637 */
640 break;
641
642 default:
643 break;
644 }
645
647
648 return eap_aka_sim_session->next(p_result, mctx, request);
649}
650
651/** Resume after 'store pseudonym { ... }'
652 *
653 * Stores session data if required.
654 */
655RESUME(store_pseudonym)
656{
657 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
658 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
659 fr_pair_t *vp;
660 fr_pair_t *new;
661
662 switch (unlang_interpret_stack_result(request)) {
663 /*
664 * Store failed. Don't send pseudonym
665 */
668 break;
669
670 default:
671 break;
672 }
673
674 unlang_interpret_stack_result_set(request, RLM_MODULE_NOOP); /* Needed because we may call resume functions directly */
675
677
678 /*
679 * Generate fast-reauth data if we
680 * find a next_reauth_id pair in the
681 * reply list.
682 */
683 vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_eap_aka_sim_next_reauth_id);
684 if (vp) {
685 /*
686 * Generate a random fastauth string
687 */
688 if (vp->vp_length == 0) {
689 char *identity;
690
692 RWDEBUG("Found empty Next-Reauth-Id, and told not to generate one. "
693 "Skipping store session { ... } section");
694
695 goto done;
696 }
697
698 MEM(identity = talloc_array(vp, char, inst->ephemeral_id_length + 2));
699 switch (eap_aka_sim_session->type) {
701 identity[0] = (char)ID_TAG_SIM_FASTAUTH;
702 break;
703
705 identity[0] = (char)ID_TAG_AKA_FASTAUTH;
706 break;
707
709 identity[0] = (char)ID_TAG_AKA_PRIME_FASTAUTH;
710 break;
711
712 default:
713 break;
714 }
715 fr_rand_str((uint8_t *)identity + 1, inst->ephemeral_id_length, 'a');
716 identity[talloc_array_length(identity) - 1] = '\0';
717
718 fr_value_box_bstrdup_buffer_shallow(NULL, &vp->data, NULL, identity, false);
719 }
721 fr_pair_value_memdup(new, (uint8_t const *)vp->vp_strvalue, vp->vp_length, vp->vp_tainted);
722
724 vp->vp_strvalue, vp->vp_length));
725
726 switch (eap_aka_sim_session->type) {
727 /*
728 * AKA and SIM use the original MK for session resumption.
729 */
733
737 false);
738 break;
739 /*
740 * AKA' KDF 1 generates an additional key k_re
741 * which is used for reauthentication instead
742 * of the MK.
743 */
746
750 false); /* truncates */
751 break;
752
753 default:
754 fr_assert(0);
755 break;
756 }
757
758 /*
759 * If the counter already exists in session
760 * state increment by 1, otherwise, add the
761 * attribute and set to zero.
762 */
763 vp = fr_pair_find_by_da_nested(&request->session_state_pairs, NULL, attr_eap_aka_sim_counter);
764 if (vp) {
765 vp->vp_uint16++;
766 /*
767 * Will get incremented by 1 in
768 * reauthentication_send, so when
769 * used, it'll be 1 (as per the standard).
770 */
771 } else {
773 vp->vp_uint16 = 0;
774 }
775
776 return CALL_SECTION(store_session);
777 }
778
779 /*
780 * We didn't store any fast-reauth data
781 */
782done:
783 return eap_aka_sim_session->next(p_result, mctx, request);
784}
785
786/** Implements a set of states for storing pseudonym and fastauth identities
787 *
788 * At the end of challenge or reauthentication rounds, the user may have specified
789 * a pseudonym and fastauth identity to return to the supplicant.
790 *
791 * Call the appropriate sections to persist those values.
792 *
793 * @param[out] p_result Result of calling the module.
794 * @param[in] mctx Module calling ctx.
795 * @param[in] request the current request.
796 * @param[in] eap_aka_sim_session the EAP session
797 * @param[in] next function to call after storing sessions and pseudonyms.
798 */
800 request_t *request,
802 module_method_t next)
803{
804 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
805 fr_pair_t *vp;
806 fr_pair_t *new;
807
809
811
812 unlang_interpret_stack_result_set(request, RLM_MODULE_NOOP); /* Needed because we may call resume functions directly */
813
814 vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_eap_aka_sim_next_pseudonym);
815 if (vp) {
816 /*
817 * Generate a random pseudonym string
818 */
819 if (vp->vp_length == 0) {
820 char *identity;
821
823 RWDEBUG("Found empty Pseudonym-Id, and told not to generate one. "
824 "Skipping store pseudonym { ... } section");
825
826 return resume_store_pseudonym(p_result, mctx, request);
827 }
828
829 MEM(identity = talloc_array(vp, char, inst->ephemeral_id_length + 2));
830 fr_rand_str((uint8_t *)identity + 1, inst->ephemeral_id_length, 'a');
831 switch (eap_aka_sim_session->type) {
833 identity[0] = (char)ID_TAG_SIM_PSEUDONYM;
834 break;
835
837 identity[0] = (char)ID_TAG_AKA_PSEUDONYM;
838 break;
839
841 identity[0] = (char)ID_TAG_AKA_PRIME_PSEUDONYM;
842 break;
843
844 default:
845 break;
846 }
847 identity[talloc_array_length(identity) - 1] = '\0';
848 fr_value_box_bstrdup_buffer_shallow(NULL, &vp->data, NULL, identity, false);
849 }
852
854 vp->vp_strvalue, vp->vp_length));
855 return CALL_SECTION(store_pseudonym);
856 }
857
858 return resume_store_pseudonym(p_result, mctx, request);
859}
860
861/** Resume after 'clear session { ... }'
862 *
863 */
864RESUME(clear_session)
865{
866 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
867
869
870 return eap_aka_sim_session->next(p_result, mctx, request);
871}
872
873/** Resume after 'clear pseudonym { ... }'
874 *
875 */
876RESUME(clear_pseudonym)
877{
878 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
879 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
880
882
883 /*
884 * Clear session (if one was stored)
885 */
887 fr_pair_t *vp;
888
890
892 fr_value_box_memdup(vp, &vp->data, NULL,
894 talloc_array_length(eap_aka_sim_session->fastauth_sent) - 1, true);
896
897 return CALL_SECTION(clear_session);
898 }
899
900 return eap_aka_sim_session->next(p_result, mctx, request);
901}
902
903/** Implements a set of states for clearing out pseudonym and fastauth identities
904 *
905 * If either a Challenge round or Reauthentication round fail, we need to clear
906 * any identities that were provided during those rounds, as the supplicant
907 * will have discarded them.
908 *
909 * @param[out] p_result Result of calling the module.
910 * @param[in] mctx module calling ctx.
911 * @param[in] request the current request.
912 * @param[in] eap_aka_sim_session the current EAP session
913 * @param[in] next function to call after clearing sessions and pseudonyms.
914 */
916 request_t *request,
918 module_method_t next)
919{
920 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
921
923
925
926 unlang_interpret_stack_result_set(request, RLM_MODULE_NOOP); /* Needed because we may call resume functions directly */
927
928 /*
929 * Clear out pseudonyms (if we sent one)
930 */
932 fr_pair_t *vp;
933
937
938 return CALL_SECTION(clear_pseudonym);
939 }
940
941 return resume_clear_pseudonym(p_result, mctx, request);
942}
943
944/** Export EAP-SIM/AKA['] attributes
945 *
946 * Makes any internal data available as attributes in the response.
947 * This allows test frameworks and the encoder to access any data they need without
948 * needing to look at the eap_aka_session_t.
949 */
951{
953
954 /*
955 * Set the subtype to identity request
956 */
958 subtype_vp->vp_uint16 = subtype;
959
961 fr_pair_list_foreach(&request->reply_pairs, vp) {
963 RWDEBUG("Silently discarding &reply.%pP: Encrypted attributes not "
964 "allowed in this round", vp);
965 fr_pair_delete(&request->reply_pairs, vp);
966 }
967 }
968 }
969}
970
971static void CC_HINT(nonnull(1,2))
973 uint8_t const *hmac_extra_request, size_t hmac_extra_request_len,
974 uint8_t const *hmac_extra_response, size_t hmac_extra_response_len)
975{
976 fr_pair_t *vp;
977
978 /*
979 * Export keying material necessary for
980 * the encoder to encrypt and sign
981 * packets.
982 */
983 if (hmac_extra_request && hmac_extra_request_len) {
985 MEM(fr_pair_value_memdup(vp, hmac_extra_request, hmac_extra_request_len, true) == 0);
986 }
987
988 if (hmac_extra_response && hmac_extra_response_len) {
990 MEM(fr_pair_value_memdup(vp, hmac_extra_response, hmac_extra_response_len, true) == 0);
991 }
992
997 true) == 0);
998
1003 true) == 0);
1004}
1005
1006/** Called after 'store session { ... }' and 'store pseudonym { ... }'
1007 *
1008 */
1010 module_ctx_t const *mctx, request_t *request)
1011{
1013
1014 /*
1015 * Return reply attributes - AT_IV is handled automatically by the encoder
1016 */
1017 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_SIM_REAUTHENTICATION);
1018
1019 /*
1020 * 9.5. EAP-Request/SIM/Re-authentication
1021 *
1022 * AT_MAC MUST be included. No message-specific data is included in the
1023 * MAC calculation. See Section 10.14.
1024 *
1025 * 9.6. EAP-Response/SIM/Re-authentication
1026 *
1027 * The AT_MAC attribute MUST be included. For
1028 * EAP-Response/SIM/Re-authentication, the MAC code is calculated over
1029 * the following data: EAP packet| NONCE_S
1030 *
1031 * 9.7. EAP-Request/AKA-Reauthentication
1032 *
1033 * The AT_MAC attribute MUST be included. No message-specific data is
1034 * included in the MAC calculation, see Section 10.15.
1035 *
1036 * 9.8. EAP-Response/AKA-Reauthentication
1037 *
1038 * The AT_MAC attribute MUST be included. For
1039 * EAP-Response/AKA-Reauthentication, the MAC code is calculated over
1040 * the following data: EAP packet| NONCE_S.
1041 */
1043 NULL, 0,
1044 eap_aka_sim_session->keys.reauth.nonce_s,
1045 sizeof(eap_aka_sim_session->keys.reauth.nonce_s));
1046
1048}
1049
1050/** Called after 'store session { ... }' and 'store pseudonym { ... }'
1051 *
1052 */
1054{
1056
1057 /*
1058 * Encode the packet - AT_IV is handled automatically
1059 * by the encoder.
1060 */
1061 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_CHALLENGE);
1062
1063 /*
1064 * 9.3. EAP-Request/AKA-Challenge
1065 *
1066 * AT_MAC MUST be included. In EAP-Request/AKA-Challenge, there is no
1067 * message-specific data covered by the MAC, see Section 10.15.
1068 *
1069 * 9.4. EAP-Response/AKA-Challenge
1070 *
1071 * The AT_MAC attribute MUST be included. In
1072 * EAP-Response/AKA-Challenge, there is no message-specific data covered
1073 * by the MAC, see Section 10.15.
1074 */
1075 common_crypto_export(request, eap_aka_sim_session, NULL, 0, NULL, 0);
1076
1078}
1079
1080/** Called after 'store session { ... }' and 'store pseudonym { ... }'
1081 *
1082 */
1084{
1087 uint8_t *p = sres_cat;
1088
1089 /*
1090 * Encode the packet - AT_IV is handled automatically
1091 * by the encoder.
1092 */
1093 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_SIM_CHALLENGE);
1094
1095 memcpy(p, eap_aka_sim_session->keys.gsm.vector[0].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
1097 memcpy(p, eap_aka_sim_session->keys.gsm.vector[1].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
1099 memcpy(p, eap_aka_sim_session->keys.gsm.vector[2].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
1100
1101 /*
1102 * 9.3. EAP-Request/SIM/Challenge
1103 *
1104 * The AT_MAC attribute MUST be included. For
1105 * EAP-Request/SIM/Challenge, the MAC code is calculated over the
1106 * following data: EAP packet| NONCE_MT
1107 *
1108 * 9.4. EAP-Response/SIM/Challenge
1109 *
1110 * The AT_MAC attribute MUST be included. For EAP-
1111 * Response/SIM/Challenge, the MAC code is calculated over the following
1112 * data: EAP packet| n*SRES
1113 */
1115 eap_aka_sim_session->keys.gsm.nonce_mt, sizeof(eap_aka_sim_session->keys.gsm.nonce_mt),
1116 sres_cat, sizeof(sres_cat));
1117
1119}
1120
1121/** Helper function to check for the presence and length of AT_SELECTED_VERSION and copy its value into the keys structure
1122 *
1123 * Also checks the version matches one of the ones we advertised in our version list,
1124 * which is a bit redundant seeing as there's only one version of EAP-SIM.
1125 */
1127{
1128 fr_pair_t *selected_version_vp;
1129
1130 /*
1131 * Check that we got an AT_SELECTED_VERSION
1132 */
1133 selected_version_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_selected_version);
1134 if (!selected_version_vp) {
1135 REDEBUG("EAP-Response/SIM/Start does not contain AT_SELECTED_VERSION");
1136 return -1;
1137 }
1138
1139 /*
1140 * See if the selected version was in our list
1141 */
1142 {
1143 uint8_t selected_version[2];
1144 uint8_t *p, *end;
1145 bool found = false;
1146
1147 p = eap_aka_sim_session->keys.gsm.version_list;
1148 end = p + eap_aka_sim_session->keys.gsm.version_list_len;
1149
1150 selected_version[0] = (selected_version_vp->vp_uint16 & 0xff00) >> 8;
1151 selected_version[1] = (selected_version_vp->vp_uint16 & 0x00ff);
1152
1153 while (p < end) {
1154 if ((p[0] == selected_version[0]) && (p[1] == selected_version[1])) {
1155 found = true;
1156 /*
1157 * Update our keying material
1158 */
1159 eap_aka_sim_session->keys.gsm.version_select[0] = selected_version[0];
1160 eap_aka_sim_session->keys.gsm.version_select[1] = selected_version[1];
1161 break;
1162 }
1163 }
1164
1165 if (!found) {
1166 REDEBUG("AT_SELECTED_VERSION (%u) does not match a value in our version list",
1167 selected_version_vp->vp_uint16);
1168 return -1;
1169 }
1170 }
1171
1172 return 0;
1173}
1174
1175/** Helper function to check for the presence and length of AT_NONCE_MT and copy its value into the keys structure
1176 *
1177 * Does not actually perform cryptographic validation of AT_NONCE_MT, this is done later.
1178 */
1180{
1181 fr_pair_t *nonce_mt_vp;
1182
1183 /*
1184 * Copy nonce_mt to the keying material
1185 */
1186 nonce_mt_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_nonce_mt);
1187 if (!nonce_mt_vp) {
1188 REDEBUG("EAP-Response/SIM/Start does not contain AT_NONCE_MT");
1189 return -1;
1190 }
1191
1192 if (nonce_mt_vp->vp_length != sizeof(eap_aka_sim_session->keys.gsm.nonce_mt)) {
1193 REDEBUG("AT_NONCE_MT must be exactly %zu bytes, not %zu bytes",
1194 sizeof(eap_aka_sim_session->keys.gsm.nonce_mt), nonce_mt_vp->vp_length);
1195 return -1;
1196 }
1197 memcpy(eap_aka_sim_session->keys.gsm.nonce_mt, nonce_mt_vp->vp_octets,
1198 sizeof(eap_aka_sim_session->keys.gsm.nonce_mt));
1199
1200 return 0;
1201}
1202
1203/** FAILURE state - State machine exit point after sending EAP-Failure
1204 *
1205 * Should never actually be called. Is just a placeholder function to represent the FAILURE
1206 * termination state. Could equally be a NULL pointer, but then on a logic error
1207 * we'd get a SEGV instead of a more friendly assert/failure rcode.
1208 */
1210{
1211 if (!fr_cond_assert(request && mctx && mctx->rctx)) RETURN_MODULE_FAIL; /* unused args */
1212
1213 fr_assert(0); /* Should never actually be called */
1214
1216}
1217
1218/** Resume after 'send EAP-Failure { ... }'
1219 *
1220 */
1221RESUME(send_eap_failure)
1222{
1223 if (!fr_cond_assert(mctx && mctx->rctx)) RETURN_MODULE_FAIL; /* unused args */
1224
1226
1227 RDEBUG2("Sending EAP-Failure");
1228
1230}
1231
1232/** Enter EAP-FAILURE state
1233 *
1234 */
1236{
1237 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1238 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1239
1240 /*
1241 * Free anything we were going to send out...
1242 */
1243 fr_pair_list_free(&request->reply_pairs);
1244
1245 /*
1246 * If we're failing, then any identities
1247 * we sent are now invalid.
1248 */
1250 return session_and_pseudonym_clear(p_result, mctx,
1251 request, eap_aka_sim_session, guard_eap_failure);
1252 /* come back when we're done */
1253 }
1254
1256
1257 return CALL_SECTION(send_eap_failure);
1258}
1259
1260/** Resume after 'recv Failure-Notification-Ack { ... }'
1261 *
1262 * - Enter the EAP-FAILURE state.
1263 */
1264RESUME(recv_common_failure_notification_ack)
1265{
1267
1268 /*
1269 * Case 2 where we're allowed to send an EAP-Failure
1270 */
1272}
1273
1274/** FAILURE-NOTIFICATION state - Continue the state machine after receiving a response to our EAP-Request/(AKA|SIM)-Notification
1275 *
1276 * - Continue based on received AT_SUBTYPE value:
1277 * - EAP-Response/SIM-Client-Error - Call 'recv Failure-Notification-Ack { ... }'
1278 * - Anything else, enter the FAILURE-NOTIFICATION state.
1279 */
1281{
1282 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1284
1285 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
1286 if (!subtype_vp) goto fail;
1287
1288 switch (subtype_vp->vp_uint16) {
1289 case FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION:
1290 RDEBUG2("Failure-Notification ACKed, sending EAP-Failure");
1291 return CALL_SECTION(recv_common_failure_notification_ack);
1292
1293 default:
1294 fail:
1295 RWDEBUG("Failure-Notification not ACKed correctly, sending EAP-Failure anyway");
1297 }
1298}
1299
1300/** Resume after 'send Failure-Notification { ... }'
1301 *
1302 * Ignores return code from send Failure-Notification { ... } section.
1303 */
1304RESUME(send_common_failure_notification)
1305{
1306 fr_pair_t *vp, *notification_vp;
1307 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx,
1309
1310 if (!fr_cond_assert(mctx)) RETURN_MODULE_FAIL; /* quiet unused warning */
1311
1313
1314 /*
1315 * Allow the user to specify specific failure notification
1316 * types. We assume the user knows what they're doing and
1317 * only toggle success and phase bits.
1318 *
1319 * This allows custom notification schemes to be implemented.
1320 *
1321 * If this is prior to authentication, valid values are:
1322 * - FR_NOTIFICATION_VALUE_GENERAL_FAILURE
1323 *
1324 * If this is after authentication, valid values are:
1325 * - FR_NOTIFICATION_VALUE_GENERAL_FAILURE_AFTER_AUTHENTICATION
1326 * - FR_NOTIFICATION_VALUE_TEMPORARILY_DENIED - User has been
1327 * temporarily denied access to the requested service.
1328 * - FR_NOTIFICATION_VALUE_NOT_SUBSCRIBED
1329 * User has not subscribed to the requested service.
1330 */
1331 notification_vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_notification);
1332
1333 /*
1334 * Keep Notification, but remove everything else...
1335 */
1336 if (notification_vp) fr_pair_remove(&request->reply_pairs, notification_vp);
1337 fr_pair_list_free(&request->reply_pairs);
1338 if (notification_vp) fr_pair_append(&request->reply_pairs, notification_vp);
1339
1340 /*
1341 * Change the failure notification depending where
1342 * we are in the eap_aka_state machine.
1343 */
1345 if (!notification_vp) {
1346 MEM(pair_append_reply(&notification_vp, attr_eap_aka_sim_notification) >= 0);
1347 notification_vp->vp_uint16 = eap_aka_sim_session->failure_type; /* Default will be zero */
1348 }
1349
1350 notification_vp->vp_uint16 &= ~0x4000; /* Unset phase bit */
1351
1352 /*
1353 * Include the counter attribute if we're failing
1354 * after a reauthentication success.
1355 *
1356 * RFC 4187 Section #9.10
1357 *
1358 * If EAP-Request/AKA-Notification is used on
1359 * a fast re-authentication exchange, and if
1360 * the P bit in AT_NOTIFICATION is set to zero,
1361 * then AT_COUNTER is used for replay protection.
1362 * In this case, the AT_ENCR_DATA and AT_IV
1363 * attributes MUST be included, and the
1364 * encapsulated plaintext attributes MUST include
1365 * the AT_COUNTER attribute. The counter value
1366 * included in AT_COUNTER MUST be the same
1367 * as in the EAP-Request/AKA-Reauthentication
1368 * packet on the same fast re-authentication
1369 * exchange.
1370 *
1371 * If the counter is used it should never be zero,
1372 * as it's incremented on first reauthentication
1373 * request.
1374 */
1376 MEM(pair_update_reply(&notification_vp, attr_eap_aka_sim_counter) >= 0);
1377 notification_vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
1378 }
1379
1380 /*
1381 * If we're after the challenge phase
1382 * then we need to include a MAC to
1383 * protect notifications.
1384 */
1386 fr_pair_value_memdup(vp, NULL, 0, false);
1387 } else {
1388 /*
1389 * Only valid code is general failure
1390 */
1391 if (!notification_vp) {
1392 MEM(pair_append_reply(&notification_vp, attr_eap_aka_sim_notification) >= 0);
1393 notification_vp->vp_uint16 = FR_NOTIFICATION_VALUE_GENERAL_FAILURE;
1394 /*
1395 * User supplied failure code
1396 */
1397 } else {
1398 notification_vp->vp_uint16 |= 0x4000; /* Set phase bit */
1399 }
1400 }
1401 notification_vp->vp_uint16 &= ~0x8000; /* In both cases success bit should be low */
1402
1403 /*
1404 * Send a response
1405 */
1406 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION);
1407
1409}
1410
1411/** Enter the FAILURE-NOTIFICATION state
1412 *
1413 */
1415{
1416 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1417 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1418
1419 /*
1420 * If we're failing, then any identities
1421 * we sent are now invalid.
1422 */
1424 return session_and_pseudonym_clear(p_result, mctx, request, eap_aka_sim_session,
1425 guard_common_failure_notification); /* come back when we're done */
1426 }
1427
1428 /*
1429 * We've already sent a failure notification
1430 * Now we just fail as it means something
1431 * went wrong processing the ACK or we got
1432 * garbage from the supplicant.
1433 */
1434 if (eap_aka_sim_session->state == state_common_failure_notification) {
1436 }
1437
1438 /*
1439 * Otherwise just transition as normal...
1440 */
1442
1443 return CALL_SECTION(send_common_failure_notification);
1444}
1445
1446/** SUCCESS state - State machine exit point after sending EAP-Success
1447 *
1448 * Should never actually be called. Is just a placeholder function to represent the SUCCESS
1449 * termination state. Could equally be a NULL pointer, but then on a logic error
1450 * we'd get a SEGV instead of a more friendly assert/failure rcode.
1451 */
1453{
1454 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1455
1456 if (!fr_cond_assert(request && mctx && eap_aka_sim_session)) RETURN_MODULE_FAIL; /* unused args */
1457
1458 fr_assert(0); /* Should never actually be called */
1459
1461}
1462
1463/** Resume after 'send EAP-Success { ... }'
1464 *
1465 * Add MPPE keys to the request being sent to the supplicant
1466 *
1467 * The only work to be done is the add the appropriate SEND/RECV
1468 * attributes derived from the MSK.
1469 */
1470RESUME(send_eap_success)
1471{
1472 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1473 uint8_t *p;
1474
1475 RDEBUG2("Sending EAP-Success");
1476
1477 /*
1478 * If this is true we're entering this state
1479 * after sending a AKA-Success-Notification
1480 *
1481 * Is seems like a really bad idea to allow the
1482 * user to send a protected success to the
1483 * supplicant and then force a failure using
1484 * the send EAP-Success { ... } section.
1485 */
1487 switch (unlang_interpret_stack_result(request)) {
1489 RWDEBUG("Ignoring rcode (%s) from send EAP-Success { ... } "
1490 "as we already sent a Success-Notification",
1492 RWDEBUG("If you need to force a failure, return an error code from "
1493 "send Success-Notification { ... }");
1494 break;
1495
1496 default:
1497 break;
1498 }
1499
1500 /*
1501 * But... if we're not working with protected
1502 * success indication, this is the only
1503 * opportunity the user has to force a failure at
1504 * the end of authentication.
1505 */
1506 } else {
1508 }
1509
1510 RDEBUG2("Adding attributes for MSK");
1515
1517}
1518
1519/** Enter EAP-SUCCESS state
1520 *
1521 */
1523{
1524 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1525
1527
1528 return CALL_SECTION(send_eap_success);
1529}
1530
1531/** Resume after 'recv Success-Notification-Ack { ... }'
1532 *
1533 * - Enter the EAP-SUCCESS state.
1534 */
1535RESUME(recv_common_success_notification_ack)
1536{
1538
1539 /*
1540 * RFC 4187 says we ignore the contents of the
1541 * next packet after we send our success notification
1542 * and always send a success.
1543 */
1545}
1546
1547/** SUCCESS-NOTIFICATION state - Continue the state machine after receiving a response to our EAP-Request/(AKA|SIM)-Notification
1548 *
1549 * - Call 'recv Success-Notification-Ack { ... }'
1550 */
1552{
1553 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1554
1555 /*
1556 * Because the server uses the AT_NOTIFICATION code "Success" (32768) to
1557 * indicate that the EAP exchange has completed successfully, the EAP
1558 * exchange cannot fail when the server processes the EAP-AKA response
1559 * to this notification. Hence, the server MUST ignore the contents of
1560 * the EAP-AKA response it receives to the EAP-Request/AKA-Notification
1561 * with this code. Regardless of the contents of the EAP-AKA response,
1562 * the server MUST send EAP-Success as the next packet.
1563 */
1564 return CALL_SECTION(recv_common_success_notification_ack);
1565}
1566
1567/** Resume after 'send Success-Notification { ... }'
1568 *
1569 */
1570RESUME(send_common_success_notification)
1571{
1572 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1573 fr_pair_t *vp;
1574
1576
1578
1579 /*
1580 * If we're in this state success bit is
1581 * high phase bit is low.
1582 */
1584 vp->vp_uint16 = FR_NOTIFICATION_VALUE_SUCCESS;
1585
1586 /*
1587 * RFC 4187 section #9.10
1588 *
1589 * If EAP-Request/AKA-Notification is used on
1590 * a fast re-authentication exchange, and if
1591 * the P bit in AT_NOTIFICATION is set to zero,
1592 * then AT_COUNTER is used for replay protection.
1593 * In this case, the AT_ENCR_DATA and AT_IV
1594 * attributes MUST be included, and the
1595 * encapsulated plaintext attributes MUST include
1596 * the AT_COUNTER attribute. The counter value
1597 * included in AT_COUNTER MUST be the same
1598 * as in the EAP-Request/AKA-Reauthentication
1599 * packet on the same fast re-authentication
1600 * exchange.
1601 *
1602 * If the counter is used it should never be zero,
1603 * as it's incremented on first reauthentication
1604 * request.
1605 */
1606 if (eap_aka_sim_session->keys.reauth.counter > 0) {
1608 vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
1609 }
1610
1611 /*
1612 * Need to include an AT_MAC attribute so that
1613 * it will get calculated.
1614 */
1616 fr_pair_value_memdup(vp, NULL, 0, false);
1617
1618 /*
1619 * Return reply attributes
1620 */
1621 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION);
1622
1624}
1625
1626/** Enter the SUCCESS-NOTIFICATION state
1627 *
1628 */
1630{
1631 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1632
1634
1635 return CALL_SECTION(send_common_success_notification);
1636}
1637
1638/** Resume after 'recv Client-Error { ... }'
1639 *
1640 * - Enter the EAP-FAILURE state.
1641 */
1642RESUME(recv_common_client_error)
1643{
1645
1647}
1648
1649/** Resume after 'recv Reauthentication-Response { ... }'
1650 *
1651 * - If 'recv Reauthentication-Response { ... }' returned a failure
1652 * rcode, enter the FAILURE-NOTIFICATION state.
1653 * - ...or call the EAP-Request/Reauthentication-Response function to act on the
1654 * contents of the response.
1655 */
1656RESUME(recv_common_reauthentication_response)
1657{
1658 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1659
1661
1662 /*
1663 * Validate mac
1664 */
1665 if (mac_validate(request) < 0) {
1666 failure:
1668 }
1669
1670 /*
1671 * Validate the checkcode
1672 */
1673 if (checkcode_validate(request) < 0) goto failure;
1674
1675 /*
1676 * Check to see if the supplicant sent
1677 * AT_COUNTER_TOO_SMALL, if they did then we
1678 * clear out reauth information and enter the
1679 * challenge state.
1680 */
1681 if (fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_eap_aka_sim_counter_too_small)) {
1682 RWDEBUG("Peer sent AT_COUNTER_TOO_SMALL (indicating our AT_COUNTER value (%u) wasn't fresh)",
1683 eap_aka_sim_session->keys.reauth.counter);
1684
1687
1689 }
1690
1691 /*
1692 * If the peer wants a Success notification, and
1693 * we included AT_RESULT_IND then send a success
1694 * notification, otherwise send a normal EAP-Success.
1695 *
1696 * RFC 4187 Section #6.2. Result Indications
1697 */
1699 if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
1700 RDEBUG("We wanted to use protected result indications, but peer does not");
1702 } else {
1704 }
1705 } else if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
1706 RDEBUG("Peer wanted to use protected result indications, but we do not");
1707 }
1708
1710
1712}
1713
1714/** REAUTHENTICATION state - Continue the state machine after receiving a response to our EAP-Request/SIM-Start
1715 *
1716 * - Continue based on received AT_SUBTYPE value:
1717 * - EAP-Response/(SIM|AKA)-Reauthentication - call 'recv Reauthentication-Response { ... }'
1718 * - EAP-Response/(SIM|AKA)-Client-Error - call 'recv Client-Error { ... }' and after that
1719 * send a EAP-Request/(SIM|AKA)-Notification indicating a General Failure.
1720 * - Anything else, enter the FAILURE-NOTIFICATION state.
1721 */
1723{
1724 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1726 fr_pair_t *subtype_vp = NULL;
1727
1728 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
1730 REDEBUG("Missing AT_SUBTYPE");
1731 goto fail;
1732 }
1733
1734 /*
1735 * These aren't allowed in Reauthentication responses as they don't apply:
1736 *
1737 * EAP_AKA_AUTHENTICATION_REJECT - We didn't provide an AUTN value
1738 * EAP_AKA_SYNCHRONIZATION_FAILURE - We didn't use new vectors.
1739 */
1740 switch (subtype_vp->vp_uint16) {
1741 case FR_SUBTYPE_VALUE_AKA_SIM_REAUTHENTICATION:
1742 /*
1743 * AT_COUNTER_TOO_SMALL is handled
1744 * in common_reauthentication_response_process.
1745 */
1746 return CALL_SECTION(recv_common_reauthentication_response);
1747
1748 /*
1749 * Case 1 where we're allowed to send an EAP-Failure
1750 */
1751 case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
1752 client_error_debug(request);
1753
1755
1756 return CALL_SECTION(recv_common_client_error);
1757 /*
1758 * RFC 4187 says we *MUST* notify, not just
1759 * send an EAP-Failure in this case.
1760 */
1761 default:
1762 REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
1763 fail:
1765
1767 }
1768}
1769
1770
1771/** Send a EAP-Request/(AKA|SIM)-Reauthenticate message to the supplicant
1772 *
1773 */
1775 module_ctx_t const *mctx,
1776 request_t *request,
1778{
1779 fr_pair_t *vp;
1780 fr_pair_t *kdf_id;
1781
1782 /*
1783 * Allow override of KDF Identity
1784 *
1785 * Because certain handset manufacturers don't
1786 * implement RFC 4187 correctly and use the
1787 * wrong identity as input the the PRF/KDF.
1788 *
1789 * Not seen any doing this for re-authentication
1790 * but you never know...
1791 */
1792 kdf_id = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_kdf_identity);
1793 if (kdf_id) {
1795 (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
1796 fr_pair_delete_by_da(&request->control_pairs, attr_eap_aka_sim_kdf_identity);
1797 }
1798
1799 RDEBUG2("Generating new session keys");
1800
1801 switch (eap_aka_sim_session->type) {
1802 /*
1803 * The GSM and UMTS KDF_0 mutate their keys using
1804 * and identical algorithm.
1805 */
1806 case FR_EAP_METHOD_SIM:
1807 case FR_EAP_METHOD_AKA:
1808 if (fr_aka_sim_vector_gsm_umts_kdf_0_reauth_from_attrs(request, &request->session_state_pairs,
1809 &eap_aka_sim_session->keys) != 0) {
1810 request_new_id:
1812 /*
1813 * Got here processing EAP-Identity-Response
1814 * If this is the *true* reauth ID, then
1815 * there's no point in setting AKA_SIM_ANY_ID_REQ.
1816 */
1818 case AKA_SIM_NO_ID_REQ:
1819 case AKA_SIM_ANY_ID_REQ:
1820 RDEBUG2("Composing EAP-Request/Reauthentication failed. Clearing reply attributes and "
1821 "requesting additional Identity");
1822 fr_pair_list_free(&request->reply_pairs);
1824 return STATE_TRANSITION(common_identity);
1825
1828 REDEBUG("Last requested fullauth or permanent ID, "
1829 "but received, or were told we received (by policy), "
1830 "a fastauth ID. Cannot continue");
1832 }
1833 }
1834 if (fr_aka_sim_crypto_kdf_0_reauth(&eap_aka_sim_session->keys) < 0) goto request_new_id;
1835 break;
1836
1839 if (fr_aka_sim_vector_umts_kdf_1_reauth_from_attrs(request, &request->session_state_pairs,
1840 &eap_aka_sim_session->keys) != 0) {
1841 goto request_new_id;
1842 }
1843 if (fr_aka_sim_crypto_umts_kdf_1_reauth(&eap_aka_sim_session->keys) < 0) goto request_new_id;
1844 } else {
1845 fr_assert(0);
1846 }
1847 break;
1848
1849 default:
1850 fr_assert(0);
1851 break;
1852 }
1853
1855
1856 /*
1857 * Indicate we'd like to use protected success messages
1858 * with AT_RESULT_IND
1859 *
1860 * Use our default, but allow user override too.
1861 */
1862 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind);
1863 if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
1864
1865 /*
1866 * RFC 5448 says AT_BIDDING is only sent in the challenge
1867 * not in reauthentication, so don't add that here.
1868 */
1869
1870 /*
1871 * Add AT_NONCE_S
1872 */
1875 sizeof(eap_aka_sim_session->keys.reauth.nonce_s), false);
1876
1877 /*
1878 * Add AT_COUNTER
1879 */
1881 vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
1882
1883 /*
1884 * need to include an empty AT_MAC attribute so that
1885 * the mac will get calculated.
1886 */
1888 fr_pair_value_memdup(vp, NULL, 0, false);
1889
1890 /*
1891 * We've sent the challenge so the peer should now be able
1892 * to accept encrypted attributes.
1893 */
1895
1896 return session_and_pseudonym_store(p_result, mctx, request, eap_aka_sim_session,
1898}
1899
1900/** Resume after 'send Reauthentication-Request { ... }'
1901 *
1902 */
1903RESUME(send_common_reauthentication_request)
1904{
1905 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1906
1907 switch (unlang_interpret_stack_result(request)) {
1908 /*
1909 * Failed getting the values we need for resumption
1910 * Request a different identity.
1911 */
1912 default:
1914 /*
1915 * Got here processing EAP-Identity-Response
1916 * If this is the *true* reauth ID, then
1917 * there's no point in setting AKA_SIM_ANY_ID_REQ.
1918 */
1920 case AKA_SIM_NO_ID_REQ:
1921 case AKA_SIM_ANY_ID_REQ:
1922 RDEBUG2("Previous section returned (%s), clearing reply attributes and "
1923 "requesting additional identity",
1925 fr_pair_list_free(&request->reply_pairs);
1927
1928 return STATE_TRANSITION(common_identity);
1929
1932 default:
1933 break;
1934 }
1935 REDEBUG("Last requested Full-Auth-Id or Permanent-Identity, "
1936 "but received a Fast-Auth-Id. Cannot continue");
1937 failure:
1939
1940 /*
1941 * Policy rejected the user
1942 */
1943 case RLM_MODULE_REJECT:
1945 goto failure;
1946
1947 /*
1948 * Everything looks ok, send the EAP-Request/reauthentication message
1949 * After storing any new pseudonyms or session information.
1950 */
1951 case RLM_MODULE_NOOP:
1952 case RLM_MODULE_OK:
1953 case RLM_MODULE_UPDATED:
1954 return common_reauthentication_request_compose(p_result, mctx, request, eap_aka_sim_session);
1955 }
1956}
1957
1958/** Resume after 'load pseudonym { ... }'
1959 *
1960 */
1961RESUME(load_pseudonym)
1962{
1963 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1964 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1965
1967
1968 /*
1969 * Control attributes required could have been specified
1970 * in another section.
1971 */
1972 if (!inst->actions.load_pseudonym) {
1973 next_state:
1974 return eap_aka_sim_session->next(p_result, mctx, request);
1975 }
1976
1977 switch (unlang_interpret_stack_result(request)) {
1978 /*
1979 * Failed resolving the pseudonym
1980 * request a different identity.
1981 */
1982 default:
1985 case AKA_SIM_NO_ID_REQ:
1986 case AKA_SIM_ANY_ID_REQ:
1988 RDEBUG2("Previous section returned (%s), clearing reply attributes and "
1989 "requesting additional identity",
1991 fr_pair_list_free(&request->reply_pairs);
1993 return STATE_TRANSITION(common_identity);
1994
1996 REDEBUG("Last requested a Permanent-Identity, but received a Pseudonym. Cannot continue");
1997 failure:
1999 }
2000 break;
2001
2002 /*
2003 * Policy rejected the user
2004 */
2005 case RLM_MODULE_REJECT:
2007 goto failure;
2008
2009 /*
2010 * Everything OK
2011 */
2012 case RLM_MODULE_OK:
2013 case RLM_MODULE_UPDATED:
2014 goto next_state;
2015 }
2016
2017 goto failure;
2018}
2019
2020/** Resume after 'load session { ... }'
2021 *
2022 */
2023RESUME(load_session)
2024{
2025 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2026 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2027
2029
2030 /*
2031 * Control attributes required could have been specified
2032 * in another section.
2033 */
2034 if (!inst->actions.load_session) goto reauthenticate;
2035
2036 switch (unlang_interpret_stack_result(request)) {
2037 /*
2038 * Failed getting the values we need for resumption
2039 * Request a different identity.
2040 */
2041 default:
2043 /*
2044 * Got here processing EAP-Identity-Response
2045 * If this is the *true* reauth ID, then
2046 * there's no point in setting AKA_SIM_ANY_ID_REQ.
2047 */
2049 case AKA_SIM_NO_ID_REQ:
2050 case AKA_SIM_ANY_ID_REQ:
2051 RDEBUG2("Previous section returned (%s), clearing reply attributes and "
2052 "requesting additional identity",
2054 fr_pair_list_free(&request->reply_pairs);
2056 return STATE_TRANSITION(common_identity);
2057
2060 REDEBUG("Last requested Full-Auth-Id or Permanent-Identity, "
2061 "but received a Fast-Auth-Id. Cannot continue");
2063 }
2064 break;
2065
2066 /*
2067 * Policy rejected the user
2068 */
2069 case RLM_MODULE_REJECT:
2071 reject:
2073
2074 /*
2075 * Everything OK
2076 */
2077 case RLM_MODULE_OK:
2078 case RLM_MODULE_UPDATED:
2079 reauthenticate:
2080 return CALL_SECTION(send_common_reauthentication_request);
2081 }
2082
2083 goto reject;
2084}
2085
2086/** Enter the REAUTHENTICATION state
2087 *
2088 */
2090{
2091 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2092 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2093 fr_pair_t *vp = NULL;
2094
2096
2097 /*
2098 * Add the current identity as session_id
2099 * to make it easier to load/store things from
2100 * the cache module.
2101 */
2104
2105 return CALL_SECTION(load_session);
2106}
2107
2108/** Resume after 'recv Synchronization-Failure { ... }'
2109 *
2110 * - If 'recv Synchronization-Failure { ... }' returned a failure
2111 * rcode, enter the FAILURE-NOTIFICATION state.
2112 * - ...or if no 'recv Synchronization-Failure { ... }' section was
2113 * defined, then enter the FAILURE-NOTIFICATION state.
2114 * - ...or if the user didn't provide a new SQN value in &control.SQN
2115 * then enter the FAILURE-NOTIFICATION state.
2116 * - ...or enter the AKA-CHALLENGE state.
2117 */
2118RESUME(recv_aka_synchronization_failure)
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;
2123
2125
2126 /*
2127 * If there's no section to handle this, then no resynchronisation
2128 * can't have occurred and we just send a reject.
2129 *
2130 * Similarly, if we've already received one synchronisation failure
2131 * then it's highly likely whatever user configured action was
2132 * configured was unsuccessful, and we should just give up.
2133 */
2134 if (!inst->actions.recv_aka_synchronization_failure || eap_aka_sim_session->prev_recv_sync_failure) {
2135 failure:
2137 }
2138
2139 /*
2140 * We couldn't generate an SQN and the user didn't provide one,
2141 * so we need to fail.
2142 */
2143 vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_sim_sqn);
2144 if (!vp) {
2145 REDEBUG("No &control.SQN value provided after resynchronisation, cannot continue");
2146 goto failure;
2147 }
2148
2149 /*
2150 * RFC 4187 Section #6.3.1
2151 *
2152 * "if the peer detects that the
2153 * sequence number in AUTN is not correct, the peer responds with
2154 * EAP-Response/AKA-Synchronization-Failure (Section 9.6), and the
2155 * server proceeds with a new EAP-Request/AKA-Challenge."
2156 */
2158}
2159
2160/** Resume after 'recv Authentication-Reject { ... }'
2161 *
2162 * - Enter the FAILURE-NOTIFICATION state.
2163 */
2164RESUME(recv_aka_authentication_reject)
2165{
2167
2168 /*
2169 * Case 2 where we're allowed to send an EAP-Failure
2170 */
2172}
2173
2174/** Resume after 'recv Challenge-Response { ... }'
2175 *
2176 * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
2177 * - ...or call a function to process the contents of the AKA-Challenge message.
2178 *
2179 * Verify that MAC, and RES match what we expect.
2180 */
2181RESUME(recv_aka_challenge_response)
2182{
2183 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2184 fr_pair_t *vp = NULL;
2185
2187
2188 /*
2189 * Validate mac
2190 */
2191 if (mac_validate(request) < 0) {
2192 failure:
2194 }
2195
2196 /*
2197 * Validate the checkcode
2198 */
2199 if (checkcode_validate(request) < 0) goto failure;
2200
2201 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_res);
2202 if (!vp) {
2203 REDEBUG("AT_RES missing from challenge response");
2204 goto failure;
2205 }
2206
2207 if (vp->vp_length != eap_aka_sim_session->keys.umts.vector.xres_len) {
2208 REDEBUG("Received RES' length (%zu) does not match calculated XRES' length (%zu)",
2209 vp->vp_length, eap_aka_sim_session->keys.umts.vector.xres_len);
2210 goto failure;
2211 }
2212
2213 if (memcmp(vp->vp_octets, eap_aka_sim_session->keys.umts.vector.xres, vp->vp_length)) {
2214 REDEBUG("Received RES does not match calculated XRES");
2215 RHEXDUMP_INLINE2(vp->vp_octets, vp->vp_length, "RES :");
2216 RHEXDUMP_INLINE2(eap_aka_sim_session->keys.umts.vector.xres,
2217 eap_aka_sim_session->keys.umts.vector.xres_len, "XRES :");
2218 goto failure;
2219 }
2220
2221 RDEBUG2("Received RES matches calculated XRES");
2222
2224
2225 /*
2226 * If the peer wants a Success notification, and
2227 * we included AT_RESULT_IND then send a success
2228 * notification, otherwise send a normal EAP-Success.
2229 *
2230 * RFC 4187 Section #6.2. Result Indications
2231 */
2233 if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2234 RDEBUG("We wanted to use protected result indications, but peer does not");
2236 } else {
2238 }
2239 } else if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2240 RDEBUG("Peer wanted to use protected result indications, but we do not");
2241 }
2242
2244}
2245
2246/** AKA-CHALLENGE state - Continue the state machine after receiving a response to our EAP-Request/SIM-Challenge
2247 *
2248 * - Continue based on received AT_SUBTYPE value:
2249 * - EAP-Response/AKA-Challenge - call 'recv Challenge-Response { ... }'.
2250 * - EAP-Response/AKA-Authentication-Reject - call 'recv Authentication-Reject { ... }' and after that
2251 * send a EAP-Request/SIM-Notification indicating a General Failure.
2252 * - EAP-Response/AKA-Synchronization-Failure - call 'recv Synchronization-Failure { ... }'.
2253 * - EAP-Response/AKA-Client-Error - call 'recv Client-Error { ... }' and after that
2254 * send a EAP-Request/AKA-Notification indicating a General Failure.
2255 * - Anything else, enter the FAILURE-NOTIFICATION state.
2256 */
2258{
2259 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2260 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2261 fr_pair_t *subtype_vp = NULL;
2263
2264 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
2265 if (!subtype_vp) {
2266 REDEBUG("Missing AT_SUBTYPE");
2267 goto fail;
2268 }
2269
2270 switch (subtype_vp->vp_uint16) {
2271 case FR_SUBTYPE_VALUE_AKA_CHALLENGE:
2272 return CALL_SECTION(recv_aka_challenge_response);
2273
2274 /*
2275 * Case 2 where we're allowed to send an EAP-Failure
2276 */
2277 case FR_SUBTYPE_VALUE_AKA_AUTHENTICATION_REJECT:
2279 return CALL_SECTION(recv_aka_authentication_reject);
2280
2281 case FR_SUBTYPE_VALUE_AKA_SYNCHRONIZATION_FAILURE:
2282 {
2283 uint64_t new_sqn;
2284
2286
2287 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_auts);
2288 if (!vp) {
2289 REDEBUG("EAP-Response/AKA-Synchronisation-Failure missing AT_AUTS");
2290 failure:
2292 }
2293
2294 switch (fr_aka_sim_umts_resync_from_attrs(&new_sqn,
2295 request, vp, &eap_aka_sim_session->keys)) {
2296 /*
2297 * Add everything back that we'll need in the
2298 * next challenge round.
2299 */
2300 case 0:
2302 vp->vp_uint64 = new_sqn;
2303
2306 sizeof(eap_aka_sim_session->keys.auc.ki), false);
2307
2310 sizeof(eap_aka_sim_session->keys.auc.opc), false);
2311 break;
2312
2313 case 1: /* Don't have Ki or OPc so something else will need to deal with this */
2314 break;
2315
2316 default:
2317 case -1:
2318 goto failure;
2319 }
2320
2321 return CALL_SECTION(recv_aka_synchronization_failure);
2322 }
2323
2324 /*
2325 * Case 1 where we're allowed to send an EAP-Failure
2326 */
2327 case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
2328 client_error_debug(request);
2329
2331
2332 return CALL_SECTION(recv_common_client_error);
2333
2334 /*
2335 * RFC 4187 says we *MUST* notify, not just
2336 * send an EAP-Failure in this case.
2337 */
2338 default:
2339 REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
2340 fail:
2342 goto failure;
2343 }
2344}
2345
2346/** Resume after 'send Challenge-Request { ... }'
2347 *
2348 */
2349RESUME(send_aka_challenge_request)
2350{
2351 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2352 fr_pair_t *vp;
2354
2355 fr_pair_t *kdf_id;
2356
2358
2359 /*
2360 * Allow override of KDF Identity
2361 *
2362 * Because certain handset manufacturers don't
2363 * implement RFC 4187 correctly and use the
2364 * wrong identity as input the the PRF/KDF.
2365 */
2366 kdf_id = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_kdf_identity);
2367 if (kdf_id) {
2369 (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
2370 fr_pair_delete_by_da(&request->control_pairs, attr_eap_aka_sim_kdf_identity);
2371 }
2372
2373 RDEBUG2("Acquiring UMTS vector(s)");
2374
2376 /*
2377 * Copy the network name the user specified for
2378 * key derivation purposes.
2379 */
2380 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_kdf_input);
2381 if (vp) {
2384 (uint8_t const *)vp->vp_strvalue,
2385 vp->vp_length);
2386 eap_aka_sim_session->keys.network_len = vp->vp_length;
2387 } else {
2388 REDEBUG("No network name available, can't set AT_KDF_INPUT");
2389 failure:
2391 }
2392
2393 /*
2394 * We don't allow the user to specify
2395 * the KDF currently.
2396 */
2398 vp->vp_uint16 = eap_aka_sim_session->kdf;
2399 }
2400
2401 /*
2402 * Get vectors from attribute or generate
2403 * them using COMP128-* or Milenage.
2404 */
2405 if (fr_aka_sim_vector_umts_from_attrs(request, &request->control_pairs,
2406 &eap_aka_sim_session->keys, &src) != 0) {
2407 REDEBUG("Failed retrieving UMTS vectors");
2408 goto failure;
2409 }
2410
2411 /*
2412 * Don't leave the AMF hanging around
2413 */
2415
2416 /*
2417 * All set, calculate keys!
2418 */
2419 switch (eap_aka_sim_session->type) {
2420 default:
2421 case FR_EAP_METHOD_SIM:
2422 fr_assert(0); /* EAP-SIM has its own Challenge state */
2423 break;
2424
2425 case FR_EAP_METHOD_AKA:
2427 break;
2428
2432 } else {
2433 fr_assert(0);
2434 }
2435 }
2437
2438 /*
2439 * Indicate we'd like to use protected success messages
2440 * with AT_RESULT_IND
2441 *
2442 * Use our default, but allow user override too.
2443 */
2444 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind);
2445 if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
2446
2447 /*
2448 * These attributes are only allowed with
2449 * EAP-AKA', protect users from themselves.
2450 */
2454 }
2455
2456 /*
2457 * Okay, we got the challenge! Put it into an attribute.
2458 */
2461
2462 /*
2463 * Send the AUTN value to the client, so it can authenticate
2464 * whoever has knowledge of the Ki.
2465 */
2468
2469 /*
2470 * need to include an AT_MAC attribute so that it will get
2471 * calculated.
2472 */
2474 fr_pair_value_memdup(vp, NULL, 0, false);
2475
2476 /*
2477 * We've sent the challenge so the peer should now be able
2478 * to accept encrypted attributes.
2479 */
2481
2483}
2484
2485/** Enter the AKA-CHALLENGE state
2486 *
2487 */
2489{
2490 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2491 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2492 fr_pair_t *vp;
2493
2494 /*
2495 * If we've sent either of these identities it
2496 * means we've come here form a Reauthentication-Request
2497 * that failed.
2498 */
2500 return session_and_pseudonym_clear(p_result, mctx, request,
2501 eap_aka_sim_session, guard_aka_challenge);
2502 /* come back when we're done */
2503 }
2504
2506
2507 /*
2508 * Set some default attributes, giving the user a
2509 * chance to modify them.
2510 */
2511 switch (eap_aka_sim_session->type) {
2513 {
2514 uint8_t amf_buff[2] = { 0x80, 0x00 }; /* Set the AMF separation bit high */
2515
2516 /*
2517 * Toggle the AMF high bit to indicate we're doing AKA'
2518 */
2520 fr_pair_value_memdup(vp, amf_buff, sizeof(amf_buff), false);
2521
2522 /*
2523 * Use the default network name we have configured
2524 * and send it to the peer.
2525 */
2526 if (inst->network_name &&
2527 !fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_kdf_input)) {
2530 }
2531 }
2532 break;
2533
2534 default:
2535 break;
2536
2537 }
2538
2539 /*
2540 * Set the defaults for protected result indicator
2541 */
2543 !fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2545 vp->vp_bool = true;
2546 }
2547
2548 return CALL_SECTION(send_aka_challenge_request);
2549}
2550
2551/** Resume after 'recv Challenge-Response { ... }'
2552 *
2553 * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
2554 * - ...or call a function to process the contents of the SIM-Challenge message.
2555 *
2556 * Verify that MAC, and RES match what we expect.
2557 */
2558RESUME(recv_sim_challenge_response)
2559{
2560 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2562 uint8_t *p = sres_cat;
2563
2565
2566 memcpy(p, eap_aka_sim_session->keys.gsm.vector[0].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
2568 memcpy(p, eap_aka_sim_session->keys.gsm.vector[1].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
2570 memcpy(p, eap_aka_sim_session->keys.gsm.vector[2].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
2571
2572 /*
2573 * Validate mac
2574 */
2576
2578
2579 /*
2580 * If the peer wants a Success notification, and
2581 * we included AT_RESULT_IND then send a success
2582 * notification, otherwise send a normal EAP-Success.
2583 */
2585 if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2586 RDEBUG("We wanted to use protected result indications, but peer does not");
2588 } else {
2590 }
2591 } else if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2592 RDEBUG("Peer wanted to use protected result indications, but we do not");
2593 }
2594
2596}
2597
2598/** SIM-CHALLENGE state - Continue the state machine after receiving a response to our EAP-Request/SIM-Challenge
2599 *
2600 * - Continue based on received AT_SUBTYPE value:
2601 * - EAP-Response/SIM-Challenge - call 'recv Challenge-Response { ... }'.
2602 * - EAP-Response/SIM-Client-Error - call 'recv Client-Error { ... }' and after that
2603 * send a EAP-Request/SIM-Notification indicating a General Failure.
2604 * - Anything else, enter the FAILURE-NOTIFICATION state.
2605 */
2607{
2608 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2609 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2610 fr_pair_t *subtype_vp = NULL;
2611
2612 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
2613 if (!subtype_vp) {
2614 REDEBUG("Missing AT_SUBTYPE");
2615 goto fail;
2616 }
2617
2618 switch (subtype_vp->vp_uint16) {
2619 case FR_SUBTYPE_VALUE_SIM_CHALLENGE:
2620 return CALL_SECTION(recv_sim_challenge_response);
2621
2622 /*
2623 * Case 1 where we're allowed to send an EAP-Failure
2624 */
2625 case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
2626 client_error_debug(request);
2627
2629
2630 return CALL_SECTION(recv_common_client_error);
2631
2632 /*
2633 * RFC 4186 says we *MUST* notify, not just
2634 * send an EAP-Failure in this case.
2635 */
2636 default:
2637 REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
2638 fail:
2640
2642 }
2643}
2644
2645/** Resume after 'send Challenge-Request { ... }'
2646 *
2647 */
2648RESUME(send_sim_challenge_request)
2649{
2650 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2651
2652 fr_pair_t *vp;
2654
2655 fr_pair_t *kdf_id;
2656
2658
2659 /*
2660 * Allow override of KDF Identity
2661 *
2662 * Because certain handset manufacturers don't
2663 * implement RFC 4187 correctly and use the
2664 * wrong identity as input the the PRF/KDF.
2665 */
2666 kdf_id = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_kdf_identity);
2667 if (kdf_id) {
2669 (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
2670 fr_pair_delete_by_da(&request->control_pairs, attr_eap_aka_sim_kdf_identity);
2671 }
2672
2673 RDEBUG2("Acquiring GSM vector(s)");
2674 if ((fr_aka_sim_vector_gsm_from_attrs(request, &request->control_pairs, 0,
2675 &eap_aka_sim_session->keys, &src) != 0) ||
2676 (fr_aka_sim_vector_gsm_from_attrs(request, &request->control_pairs, 1,
2677 &eap_aka_sim_session->keys, &src) != 0) ||
2678 (fr_aka_sim_vector_gsm_from_attrs(request, &request->control_pairs, 2,
2679 &eap_aka_sim_session->keys, &src) != 0)) {
2680 REDEBUG("Failed retrieving SIM vectors");
2682 }
2683
2685
2687
2688 /*
2689 * Indicate we'd like to use protected success messages
2690 * with AT_RESULT_IND
2691 *
2692 * Use our default, but allow user override too.
2693 */
2694 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind);
2695 if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
2696
2697 /*
2698 * Okay, we got the challenges! Put them into attributes.
2699 */
2702
2705
2708
2709 /*
2710 * need to include an AT_MAC attribute so that it will get
2711 * calculated.
2712 */
2714 fr_pair_value_memdup(vp, NULL, 0, false);
2715
2716 /*
2717 * We've sent the challenge so the peer should now be able
2718 * to accept encrypted attributes.
2719 */
2721
2723}
2724
2725/** Enter the SIM-CHALLENGE state
2726 *
2727 */
2729{
2730 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2731 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2732 fr_pair_t *vp;
2733
2734 /*
2735 * If we've sent either of these identities it
2736 * means we've come here form a Reauthentication-Request
2737 * that failed.
2738 */
2740 return session_and_pseudonym_clear(p_result, mctx, request,
2741 eap_aka_sim_session, guard_sim_challenge);
2742 /* come back when we're done */
2743 }
2744
2746
2747 /*
2748 * Set the defaults for protected result indicator
2749 */
2751 !fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2753 vp->vp_bool = true;
2754 }
2755
2756 return CALL_SECTION(send_sim_challenge_request);
2757}
2758
2759/** Enter the SIM-CHALLENGE or AKA-CHALLENGE state
2760 *
2761 * Called by functions which are common to both the EAP-SIM and EAP-AKA state machines
2762 * to enter the correct challenge state.
2763 */
2764STATE_GUARD(common_challenge)
2765{
2766 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2767
2768 switch (eap_aka_sim_session->type) {
2769 case FR_EAP_METHOD_SIM:
2771
2772 case FR_EAP_METHOD_AKA:
2775
2776 default:
2777 break;
2778 }
2779
2780 fr_assert(0);
2782}
2783
2784/** Resume after 'recv Identity-Response { ... }' or 'recv AKA-Identity { ... }'
2785 *
2786 * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
2787 * - ...or call a function to process the contents of the AKA-Identity message, mainly the AT_IDENTITY value.
2788 * - If the message does not contain AT_IDENTITY, then enter the FAILURE-NOTIFICATION state.
2789 * - If the user requested another identity, re-enter the AKA-Identity state.
2790 * - ...or continue based on the value of &Identity-Type which was added by #aka_identity,
2791 * and possibly modified by the user.
2792 * - Fastauth - Enter the REAUTHENTICATION state.
2793 * - Pseudonym - Call 'load pseudonym { ... }'
2794 * - Permanent - Enter the CHALLENGE state.
2795 */
2796RESUME(recv_aka_identity_response)
2797{
2798 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2799 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2800
2801 bool user_set_id_req;
2802 fr_pair_t *identity_type;
2803
2805
2806 /*
2807 * See if the user wants us to request another
2808 * identity.
2809 *
2810 * If they set one themselves don't override
2811 * what they set.
2812 */
2813 user_set_id_req = identity_req_set_by_user(request, eap_aka_sim_session);
2814 if ((unlang_interpret_stack_result(request) == RLM_MODULE_NOTFOUND) || user_set_id_req) {
2815 if (!user_set_id_req) {
2817 case AKA_SIM_ANY_ID_REQ:
2819 break;
2820
2823 break;
2824
2825 case AKA_SIM_NO_ID_REQ: /* We always request an ID in AKA-Identity unlike SIM-Start */
2826 case AKA_SIM_INIT_ID_REQ: /* Should not happen */
2827 fr_assert(0);
2829
2831 REDEBUG("Peer sent no usable identities");
2833
2834 }
2835 RDEBUG2("Previous section returned (%s), requesting next most permissive identity (%s)",
2838 eap_aka_sim_session->id_req, "<INVALID>"));
2839 }
2841 }
2842
2843 /*
2844 * If the identity looks like a fast re-auth id
2845 * run fast re-auth, otherwise do fullauth.
2846 */
2847 identity_type = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity_type);
2848 if (identity_type) switch (identity_type->vp_uint32) {
2849 case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
2851
2852 /*
2853 * It's a pseudonym, which now needs resolving.
2854 * The resume function here calls aka_challenge_enter
2855 * if pseudonym resolution went ok.
2856 */
2857 case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
2858 eap_aka_sim_session->next = guard_aka_challenge;
2859 return CALL_SECTION(load_pseudonym);
2860
2861 default:
2862 break;
2863 }
2864
2866}
2867
2868/** AKA-IDENTITY state - Continue the state machine after receiving a response to our EAP-Request/AKA-Identity
2869 *
2870 * - Continue based on received AT_SUBTYPE value:
2871 * - EAP-Response/AKA-Identity - call either 'recv Identity-Response { ... }' or if
2872 * provided 'recv AKA-Identity-Response { ... }'. The idea here is that the
2873 * EAP-Identity-Response is really the first round in identity negotiation and
2874 * there's no real value distinguishing between the first round and subsequent
2875 * rounds, but if users do want to run different logic, then give them a way of
2876 * doing that.
2877 * - EAP-Response/AKA-Client-Error - call 'recv Client-Error { ... }' and after that
2878 * send a EAP-Request/SIM-Notification indicating a General Failure.
2879 * - Anything else, enter the FAILURE-NOTIFICATION state.
2880 */
2882{
2883 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2884 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2885 fr_pair_t *subtype_vp = NULL;
2886
2887 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
2888 if (!subtype_vp) {
2889 REDEBUG("Missing AT_SUBTYPE");
2890 goto fail;
2891 }
2892
2893 switch (subtype_vp->vp_uint16) {
2894 /*
2895 * This is the subtype we expect
2896 */
2897 case FR_SUBTYPE_VALUE_AKA_IDENTITY:
2898 {
2899 fr_pair_t *id;
2901
2902 id = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity);
2903 if (!id) {
2904 /*
2905 * 9.2. EAP-Response/Identity
2906 *
2907 * The peer sends EAP-Response/Identity in response to a valid
2908 * EAP-Request/Identity from the server.
2909 * The peer MUST include the AT_IDENTITY attribute. The usage of
2910 * AT_IDENTITY is defined in Section 4.1.
2911 */
2912 REDEBUG("EAP-Response/Identity does not contain AT_IDENTITY");
2914 }
2915
2916 /*
2917 * Add ID hint attributes to the request to help
2918 * the user make policy decisions.
2919 */
2920 identity_hint_pairs_add(&type, NULL, request, id->vp_strvalue);
2925 }
2926
2927 /*
2928 * Update cryptographic identity
2929 */
2931 (uint8_t const *)id->vp_strvalue, id->vp_length);
2932
2933 return unlang_module_yield_to_section(p_result,
2934 request,
2935 inst->actions.recv_aka_identity_response ?
2936 inst->actions.recv_aka_identity_response:
2937 inst->actions.recv_common_identity_response,
2939 resume_recv_aka_identity_response,
2940 mod_signal,
2943 }
2944
2945 /*
2946 * Case 1 where we're allowed to send an EAP-Failure
2947 *
2948 * This can happen in the case of a conservative
2949 * peer, where it refuses to provide the permanent
2950 * identity.
2951 */
2952 case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
2953 client_error_debug(request);
2954
2955 return CALL_SECTION(recv_common_client_error);
2956
2957 default:
2958 /*
2959 * RFC 4187 says we *MUST* notify, not just
2960 * send an EAP-Failure in this case.
2961 */
2962 REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
2963 fail:
2965 }
2966}
2967
2968/** Resume after 'send Identity-Request { ... }'
2969 *
2970 * There are three types of user identities that can be implemented
2971 * - Permanent identities such as 0123456789098765@myoperator.com
2972 * Permanent identities can be identified by the leading zero followed by
2973 * by 15 digits (the IMSI number).
2974 * - Ephemeral identities (pseudonyms). These are identities assigned for
2975 * identity privacy so the user can't be tracked. These can identities
2976 * can either be generated as per the 3GPP 'Security aspects of non-3GPP accesses'
2977 * document section 14, where a set of up to 16 encryption keys are used
2978 * to reversibly encrypt the IMSI. Alternatively the pseudonym can be completely
2979 * randomised and stored in a datastore.
2980 * - A fast resumption ID which resolves to data used for fast resumption.
2981 *
2982 * In order to perform full authentication the original IMSI is required for
2983 * forwarding to the HLR. In the case where we can't match/decrypt the pseudonym,
2984 * or can't perform fast resumption, we need to request the full identity from
2985 * the supplicant.
2986 *
2987 */
2988RESUME(send_aka_identity_request)
2989{
2990 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2991
2993
2994 /*
2995 * Update eap_aka_sim_session->id_req in case the the
2996 * user set attributes in `send Identity-Request { ... }`
2997 * Also removes all existing id_req attributes
2998 * from the reply.
2999 */
3001
3002 /*
3003 * Select the right type of identity request attribute
3004 *
3005 * Implement checks on identity request order described
3006 * by RFC4187 section #4.1.5.
3007 *
3008 * The internal state machine should always handle this
3009 * correctly, but the user may have other ideas...
3010 */
3011 if (identity_req_pairs_add(request, eap_aka_sim_session) < 0) {
3013 }
3014 eap_aka_sim_session->last_id_req = eap_aka_sim_session->id_req; /* Record what we last requested */
3015
3016 /*
3017 * Encode the packet
3018 */
3019 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_IDENTITY);
3020
3022}
3023
3024/** Enter the AKA-IDENTITY state
3025 *
3026 */
3028{
3029 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3030 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3031
3033
3034 /*
3035 * If we have an send_aka_identity_request section
3036 * then run that, otherwise just run the normal
3037 * identity request section.
3038 */
3039 return unlang_module_yield_to_section(p_result,
3040 request,
3041 inst->actions.send_aka_identity_request ?
3042 inst->actions.send_aka_identity_request:
3045 resume_send_aka_identity_request,
3046 mod_signal,
3047 ~FR_SIGNAL_CANCEL,
3049}
3050
3051/** Resume after 'recv Identity-Response { ... }' or 'recv SIM-Start { ... }'
3052 *
3053 * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
3054 * - ...or call a function to process the contents of the SIM-Start message, mainly the AT_IDENTITY value.
3055 * - If the message does not contain AT_IDENTITY, then enter the FAILURE-NOTIFICATION state.
3056 * - If the user requested another identity, re-enter the SIM-START state.
3057 * - ...or continue based on the value of &Identity-Type which was added by #sim_start,
3058 * and possibly modified by the user.
3059 * - Fastauth
3060 * - If AT_NONCE_MT or AT_SELECTED_VERSION are present, enter the FAILURE-NOTIFICATION state.
3061 * - ...or enter the REAUTHENTICATION state.
3062 * - Pseudonym - Verify selected version and AT_NONCE_MT, then call 'load pseudonym { ... }'
3063 * - Permanent - Verify selected version and AT_NONCE_MT, then enter the CHALLENGE state.
3064 */
3065RESUME(recv_sim_start_response)
3066{
3067 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3068 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3069 bool user_set_id_req;
3070 fr_pair_t *identity_type;
3071
3073
3074 /*
3075 * See if the user wants us to request another
3076 * identity.
3077 *
3078 * If they set one themselves don't override
3079 * what they set.
3080 */
3081 user_set_id_req = identity_req_set_by_user(request, eap_aka_sim_session);
3082 if ((unlang_interpret_stack_result(request) == RLM_MODULE_NOTFOUND) || user_set_id_req) {
3083 if (!user_set_id_req) {
3085 case AKA_SIM_NO_ID_REQ: /* Should not happen */
3087 break;
3088
3089 case AKA_SIM_ANY_ID_REQ:
3091 break;
3092
3095 break;
3096
3097 case AKA_SIM_INIT_ID_REQ: /* Should not happen */
3098 fr_assert(0);
3100
3102 REDEBUG("Peer sent no usable identities");
3103 failure:
3105 }
3106 RDEBUG2("Previous section returned (%s), requesting next most permissive identity (%s)",
3109 eap_aka_sim_session->id_req, "<INVALID>"));
3110 }
3112 }
3113
3114 /*
3115 * If the identity looks like a fast re-auth id
3116 * run fast re-auth, otherwise do fullauth.
3117 */
3118 identity_type = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity_type);
3119 if (identity_type) switch (identity_type->vp_uint32) {
3120 case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
3121 /*
3122 * RFC 4186 Section #9.2
3123 *
3124 * The AT_NONCE_MT attribute MUST NOT be included if the AT_IDENTITY
3125 * with a fast re-authentication identity is present for fast
3126 * re-authentication
3127 */
3128 if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_nonce_mt)) {
3129 REDEBUG("AT_NONCE_MT is not allowed in EAP-Response/SIM-Reauthentication messages");
3131 }
3132
3133 /*
3134 * RFC 4186 Section #9.2
3135 *
3136 * The AT_SELECTED_VERSION attribute MUST NOT be included if the
3137 * AT_IDENTITY attribute with a fast re-authentication identity is
3138 * present for fast re-authentication.
3139 */
3140 if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_selected_version)) {
3141 REDEBUG("AT_SELECTED_VERSION is not allowed in EAP-Response/SIM-Reauthentication messages");
3143 }
3144
3146
3147 /*
3148 * It's a pseudonym, which now needs resolving.
3149 * The resume function here calls aka_challenge_enter
3150 * if pseudonym resolution went ok.
3151 */
3152 case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
3153 if (sim_start_selected_version_check(request, eap_aka_sim_session) < 0) goto failure;
3154 if (sim_start_nonce_mt_check(request, eap_aka_sim_session) < 0) goto failure;
3155
3156 eap_aka_sim_session->next = guard_sim_challenge;
3157 return CALL_SECTION(load_pseudonym);
3158
3159 /*
3160 * If it's a permanent ID, copy it over to
3161 * the session state list for use in the
3162 * store pseudonym/store session sections
3163 * later.
3164 */
3165 case FR_IDENTITY_TYPE_VALUE_PERMANENT:
3166 if (sim_start_selected_version_check(request, eap_aka_sim_session) < 0) goto failure;
3167 if (sim_start_nonce_mt_check(request, eap_aka_sim_session) < 0) goto failure;
3168
3170 default:
3171 break;
3172 }
3173
3175}
3176
3177/** SIM-START state - Continue the state machine after receiving a response to our EAP-Request/SIM-Start
3178 *
3179 * - Continue based on received AT_SUBTYPE value:
3180 * - EAP-Response/SIM-Start - call either 'recv Identity-Response { ... }' or if
3181 * provided 'recv SIM-Start-Response { ... }'. The idea here is that the
3182 * EAP-Identity-Response is really the first round in identity negotiation and
3183 * there's no real value distinguishing between the first round and subsequent
3184 * rounds, but if users do want to run different logic, then give them a way of
3185 * doing that.
3186 * - EAP-Response/SIM-Client-Error - call 'recv Client-Error { ... }' and after that
3187 * send a EAP-Request/SIM-Notification indicating a General Failure.
3188 * - Anything else, enter the FAILURE-NOTIFICATION state.
3189 */
3191{
3192 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3193 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3194 fr_pair_t *subtype_vp = NULL;
3195
3196 subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
3197 if (!subtype_vp) {
3198 REDEBUG("Missing AT_SUBTYPE");
3199 goto fail;
3200 }
3201 switch (subtype_vp->vp_uint16) {
3202 case FR_SUBTYPE_VALUE_SIM_START:
3203 {
3204 eap_session_t *eap_session = eap_session_get(request->parent);
3205 fr_pair_t *id;
3207
3208 id = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity);
3209 if (!id && (eap_aka_sim_session->id_req != AKA_SIM_NO_ID_REQ)) {
3210 /*
3211 * RFC 4186 Section #9.2
3212 *
3213 * The peer sends EAP-Response/SIM/Start in response to a valid
3214 * EAP-Request/SIM/Start from the server.
3215 *
3216 * If and only if the server's EAP-Request/SIM/Start includes one of the
3217 * identity-requesting attributes, then the peer MUST include the
3218 * AT_IDENTITY attribute. The usage of AT_IDENTITY is defined in
3219 * Section 4.2.
3220 * The peer MUST include the AT_IDENTITY attribute. The usage of
3221 * AT_IDENTITY is defined in Section 4.1.
3222 */
3223 REDEBUG("EAP-Response/SIM/Start does not contain AT_IDENTITY");
3225 }
3226
3227 /*
3228 * Add ID hint attributes to the request to help
3229 * the user make policy decisions.
3230 */
3231 if (id) {
3232 identity_hint_pairs_add(&type, NULL, request, id->vp_strvalue);
3237 }
3238
3239 /*
3240 * Update cryptographic identity
3241 *
3242 * We only do this if we received a new identity.
3243 */
3245 (uint8_t const *)id->vp_strvalue, id->vp_length);
3246 /*
3247 * If there's no additional identity provided, just
3248 * use eap_session->identity again...
3249 */
3250 } else {
3251 /*
3252 * Copy the EAP-Identity into our Identity
3253 * attribute to make policies easier.
3254 */
3256 fr_pair_value_bstrdup_buffer(id, eap_session->identity, true);
3257
3258 /*
3259 * Add ID hint attributes to the request to help
3260 * the user make policy decisions.
3261 */
3262 identity_hint_pairs_add(&type, NULL, request, eap_session->identity);
3263
3268 }
3269 }
3270
3271 return unlang_module_yield_to_section(p_result,
3272 request,
3273 inst->actions.recv_sim_start_response?
3274 inst->actions.recv_sim_start_response:
3275 inst->actions.recv_common_identity_response,
3277 resume_recv_sim_start_response,
3278 mod_signal,
3281 }
3282
3283 /*
3284 * Case 1 where we're allowed to send an EAP-Failure
3285 *
3286 * This can happen in the case of a conservative
3287 * peer, where it refuses to provide the permanent
3288 * identity.
3289 */
3290 case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
3291 client_error_debug(request);
3292
3293 return CALL_SECTION(recv_common_client_error);
3294
3295 default:
3296 /*
3297 * RFC 4187 says we *MUST* notify, not just
3298 * send an EAP-Failure in this case.
3299 */
3300 REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
3301 fail:
3303 }
3304}
3305
3306/** Resume after 'send Start { ... }'
3307 *
3308 * Send a EAP-Request/SIM-Start message to the supplicant
3309 *
3310 * There are three types of user identities that can be implemented
3311 * - Permanent identities such as 0123456789098765@myoperator.com
3312 * Permanent identities can be identified by the leading zero followed by
3313 * by 15 digits (the IMSI number).
3314 * - Ephemeral identities (pseudonyms). These are identities assigned for
3315 * identity privacy so the user can't be tracked. These can identities
3316 * can either be generated as per the 3GPP 'Security aspects of non-3GPP accesses'
3317 * document section 14, where a set of up to 16 encryption keys are used
3318 * to reversibly encrypt the IMSI. Alternatively the pseudonym can be completely
3319 * randomised and stored in a datastore.
3320 * - A fast resumption ID which resolves to data used for fast resumption.
3321 *
3322 * In order to perform full authentication the original IMSI is required for
3323 * forwarding to the HLR. In the case where we can't match/decrypt the pseudonym,
3324 * or can't perform fast resumption, we need to request the full identity from
3325 * the supplicant.
3326 */
3327RESUME(send_sim_start)
3328{
3329 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3330 fr_pair_t *vp;
3331 uint8_t *p, *end;
3332
3334
3335 p = eap_aka_sim_session->keys.gsm.version_list;
3336 end = p + sizeof(eap_aka_sim_session->keys.gsm.version_list);
3337 eap_aka_sim_session->keys.gsm.version_list_len = 0;
3338
3339 /*
3340 * If the user provided no versions, then
3341 * just add the default (1).
3342 */
3343 if (!(fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_version_list))) {
3345 vp->vp_uint16 = EAP_SIM_VERSION;
3346 }
3347
3348 /*
3349 * Iterate over the the versions adding them
3350 * to the version list we use for keying.
3351 */
3352 for (vp = fr_pair_list_head(&request->reply_pairs);
3353 vp;
3354 vp = fr_pair_list_next(&request->reply_pairs, vp)) {
3355 if (vp->da != attr_eap_aka_sim_version_list) continue;
3356
3357 if ((end - p) < 2) break;
3358
3359 /*
3360 * Store as big endian
3361 */
3362 *p++ = (vp->vp_uint16 & 0xff00) >> 8;
3363 *p++ = (vp->vp_uint16 & 0x00ff);
3364 eap_aka_sim_session->keys.gsm.version_list_len += sizeof(uint16_t);
3365 }
3366
3367 /*
3368 * Update eap_aka_sim_session->id_req in case the the
3369 * user set attributes in `send Identity-Request { ... }`
3370 * Also removes all existing id_req attributes
3371 * from the reply.
3372 */
3374
3375 /*
3376 * Select the right type of identity request attribute
3377 *
3378 * Implement checks on identity request order described
3379 * by RFC4186 section #4.2.5.
3380 *
3381 * The internal state machine should always handle this
3382 * correctly, but the user may have other ideas...
3383 */
3384 if (identity_req_pairs_add(request, eap_aka_sim_session) < 0) {
3386 }
3387 eap_aka_sim_session->last_id_req = eap_aka_sim_session->id_req; /* Record what we last requested */
3388
3389 common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_SIM_START);
3390
3392}
3393
3394/** Enter the SIM-START state
3395 *
3396 */
3398{
3399 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3400 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3401
3403
3404 return unlang_module_yield_to_section(p_result,
3405 request,
3406 inst->actions.send_sim_start_request ?
3407 inst->actions.send_sim_start_request:
3410 resume_send_sim_start,
3411 mod_signal,
3412 ~FR_SIGNAL_CANCEL,
3414}
3415
3416/** Enter the SIM-START or AKA-IDENTITY state
3417 *
3418 * Called by functions which are common to both the EAP-SIM and EAP-AKA state machines
3419 * to enter the correct Identity-Request state.
3420 */
3421STATE_GUARD(common_identity)
3422{
3423 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3424
3425 switch (eap_aka_sim_session->type) {
3426 case FR_EAP_METHOD_SIM:
3428
3429 case FR_EAP_METHOD_AKA:
3432
3433 default:
3434 break;
3435 }
3436
3437 fr_assert(0);
3439}
3440
3441/** Resume after 'recv Identity-Response { ... }'
3442 *
3443 * - Perform the majority of eap_aka_sim_session_t initialisation.
3444 * - If 'recv Identity-Response { ... }' returned a failure rcode, enter the FAILURE-NOTIFICATION state.
3445 * - ...or continue based on the identity hint byte in the AT_IDENTITY value or EAP-Identity-Response value:
3446 * - If identity is a pseudonym, call load pseudonym { ... }.
3447 * - If identity is a fastauth identity, enter the REAUTHENTICATE state.
3448 * - If identity is a permanent identity, enter the CHALLENGE state.
3449 */
3450RESUME(recv_common_identity_response)
3451{
3452 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3453 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3454 fr_pair_t *eap_type, *method, *identity_type;
3455 fr_aka_sim_method_hint_t running, hinted;
3456
3458
3459 /*
3460 * Ignore attempts to change the EAP-Type
3461 * This must be done before we enter
3462 * the submodule.
3463 */
3464 eap_type = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_type);
3465 if (eap_type) RWDEBUG("Ignoring &control.EAP-Type, this must be set *before* the EAP module is called");
3466
3467 method = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_method_hint);
3468
3469 /*
3470 * Set default configuration, we may allow these
3471 * to be toggled by attributes later.
3472 */
3474 eap_aka_sim_session->id_req = AKA_SIM_NO_ID_REQ; /* Set the default */
3475
3476 /*
3477 * Unless AKA-Prime is explicitly disabled,
3478 * use it... It has stronger keying, and
3479 * binds authentication to the network.
3480 */
3481 switch (eap_aka_sim_session->type) {
3482 case FR_EAP_METHOD_SIM:
3483 RDEBUG2("New EAP-SIM session");
3484
3485 running = AKA_SIM_METHOD_HINT_SIM;
3486
3488 eap_aka_sim_session->mac_md = EVP_sha1();
3489 break;
3490
3491 case FR_EAP_METHOD_AKA:
3492 RDEBUG2("New EAP-AKA session");
3493
3494 running = AKA_SIM_METHOD_HINT_AKA;
3495
3497 eap_aka_sim_session->mac_md = EVP_sha1();
3498 break;
3499
3501 RDEBUG2("New EAP-AKA' session");
3502
3504
3507 eap_aka_sim_session->mac_md = EVP_sha256();
3508 break;
3509
3510 default:
3511 fr_assert(0);
3513 }
3514
3515 /*
3516 * Warn the user if the selected identity
3517 * does not match what's hinted.
3518 */
3519 if (method) {
3520 switch (method->vp_uint32) {
3521 case FR_METHOD_HINT_VALUE_AKA_PRIME:
3523 break;
3524
3525 case FR_METHOD_HINT_VALUE_AKA:
3526 hinted = AKA_SIM_METHOD_HINT_AKA;
3527 break;
3528
3529 case FR_METHOD_HINT_VALUE_SIM:
3530 hinted = AKA_SIM_METHOD_HINT_SIM;
3531 break;
3532
3533 default:
3534 hinted = running;
3535 break;
3536 }
3537
3538 if (hinted != running) {
3539 RWDEBUG("EAP-Identity hints that EAP-%s should be started, but we're attempting EAP-%s",
3541 fr_table_str_by_value(fr_aka_sim_id_method_table, running, "<INVALID>"));
3542 }
3543 }
3544
3545 /*
3546 * Unless the user has told us otherwise We always
3547 * start by requesting any ID initially as we can
3548 * always negotiate down.
3549 */
3553 RDEBUG2("Previous section returned (%s), requesting additional identity (%s)",
3556 eap_aka_sim_session->id_req, "<INVALID>"));
3557 } else if (inst->request_identity != AKA_SIM_NO_ID_REQ) {
3559 RDEBUG2("Requesting additional identity (%s)",
3561 eap_aka_sim_session->id_req, "<INVALID>"));
3562 }
3563 }
3564
3565 /*
3566 * For EAP-SIM we _always_ start with a SIM-Start
3567 * for "version negotiation" even if we don't need
3568 * another identity.
3569 */
3571
3572 /*
3573 * User may want us to always request an identity
3574 * initially. The RFCs says this is also the
3575 * better way to operate, as the supplicant
3576 * can 'decorate' the identity in the identity
3577 * response.
3578 *
3579 * For EAP-AKA/EAP-AKA' unless we've been configured
3580 * to always request the identity or it was set
3581 * dynamically, we can save a round of EAP and just
3582 * jump straight into the challenge.
3583 */
3584 if (eap_aka_sim_session->id_req != AKA_SIM_NO_ID_REQ) return STATE_TRANSITION(common_identity);
3585
3586 /*
3587 * If the identity looks like a fast re-auth id
3588 * run fast re-auth, otherwise do a fullauth.
3589 */
3590 identity_type = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity_type);
3591 if (identity_type) switch (identity_type->vp_uint32) {
3592 case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
3594
3595 /*
3596 * It's a pseudonym, which now needs resolving.
3597 * The resume function here calls aka_challenge_enter
3598 * if pseudonym resolution went ok.
3599 */
3600 case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
3601 eap_aka_sim_session->next = guard_common_challenge;
3602 return CALL_SECTION(load_pseudonym);
3603
3604 case FR_IDENTITY_TYPE_VALUE_PERMANENT:
3605 default:
3606 break;
3607 }
3608
3609 return STATE_TRANSITION(common_challenge);
3610}
3611
3612/** Enter the EAP-IDENTITY state
3613 *
3614 * - Process the incoming EAP-Identity-Response
3615 * - Start EAP-SIM/EAP-AKA/EAP-AKA' state machine optionally calling 'recv Identity-Response { ... }'
3616 */
3617STATE(init)
3618{
3619 eap_session_t *eap_session = eap_session_get(request->parent);
3620 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3621 eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3622 fr_pair_t *vp;
3624
3625 /*
3626 * Verify we received an EAP-Response/Identity
3627 * message before the supplicant started sending
3628 * EAP-SIM/AKA/AKA' packets.
3629 */
3630 if (!eap_session->identity) {
3631 REDEBUG("All SIM or AKA exchanges must begin with a EAP-Response/Identity message");
3633 }
3634
3635 /*
3636 * Copy the EAP-Identity into our Identity
3637 * attribute to make policies easier.
3638 */
3641
3642 /*
3643 * Add ID hint attributes to the request to help
3644 * the user make policy decisions.
3645 */
3646 identity_hint_pairs_add(&type, NULL, request, eap_session->identity);
3651
3652 /*
3653 * Set the initial crypto identity from
3654 * the EAP-Identity-Response
3655 */
3657 (uint8_t const *)eap_session->identity,
3658 talloc_array_length(eap_session->identity) - 1);
3659
3660 return CALL_SECTION(recv_common_identity_response);
3661}
3662
3663/** Zero out the eap_aka_sim_session when we free it to clear knowledge of secret keys
3664 *
3665 * @param[in] eap_aka_sim_session to free.
3666 * @return 0
3667 */
3669{
3670 memset(eap_aka_sim_session, 0, sizeof(*eap_aka_sim_session));
3671 return 0;
3672}
3673
3674/** Resumes the state machine when receiving a new response packet
3675 *
3676 */
3678{
3679 eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3682 0);
3683 module_ctx_t our_mctx = *mctx;
3684
3685 /*
3686 * A new EAP-SIM/AKA/AKA' session!
3687 */
3688 if (!eap_aka_sim_session) {
3689
3690 /*
3691 * Must be allocated in the NULL ctx as this will
3692 * need to persist over multiple rounds of EAP.
3693 */
3694 MEM(eap_aka_sim_session = talloc_zero(NULL, eap_aka_sim_session_t));
3695 talloc_set_destructor(eap_aka_sim_session, _eap_aka_sim_session_free);
3696
3697 /*
3698 * Add new session data to the request
3699 * We only ever need to do this once as it's restored
3700 * during the next round of EAP automatically.
3701 *
3702 * It will also be freed automatically if the request
3703 * is freed and persistable data hasn't been moved
3704 * into the parent.
3705 */
3707 eap_aka_sim_session, true, true, true) < 0)) {
3708 RPEDEBUG("Failed creating new EAP-SIM/AKA/AKA' session");
3710 }
3712
3713 our_mctx.rctx = eap_aka_sim_session;
3714
3715 return state_init(p_result, &our_mctx, request);
3716 }
3717
3718 /*
3719 * This function is called without a resume ctx as it's the
3720 * entry point for each new round of EAP-AKA.
3721 */
3722 our_mctx.rctx = eap_aka_sim_session;
3723
3725
3726 return eap_aka_sim_session->state(p_result, &our_mctx, request);
3727}
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:483
#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:322
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
#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:2037
static fr_slen_t in
Definition dict.h:824
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 unlang_interpret_stack_result(request_t *request)
Get the current rcode for the frame.
Definition interpret.c:1290
void unlang_interpret_stack_result_set(request_t *request, rlm_rcode_t rcode)
Overwrite the current stack rcode.
Definition interpret.c:1302
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:55
static eap_session_t * eap_session_get(request_t *request)
Definition session.h:82
eap_type_t type
EAP method number.
Definition session.h:49
Tracks the progress of a single session of any EAP method.
Definition session.h:40
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:2981
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:770
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:693
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:1969
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:1345
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:1689
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:2784
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:1826
int fr_pair_value_copy(fr_pair_t *dst, fr_pair_t *src)
Copy the value from one pair to another.
Definition pair.c:2563
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:38
#define pair_update_request(_attr, _da)
static bool done
Definition radclient.c:80
#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 RETURN_MODULE_REJECT
Definition rcode.h:55
#define RETURN_MODULE_HANDLED
Definition rcode.h:58
#define RLM_MODULE_USER_SECTION_REJECT
Rcodes that translate to a user configurable section failing overall.
Definition rcode.h:72
#define RETURN_MODULE_OK
Definition rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ 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:271
unlang_action_t(* module_method_t)(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Module section callback.
Definition module.h:68
#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(rlm_rcode_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:248
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...
static int checkcode_validate(request_t *request)
Check &control.checkcode matches &reply.checkcode.
RETURN_MODULE_FAIL
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
SUCCESS-NOTIFICATION state - Continue the state machine after receiving a response to our EAP-Request...
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 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.
static unlang_action_t common_reauthentication_request_compose(rlm_rcode_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 unlang_action_t aka_challenge_request_send(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Called after 'store session { ... }' and 'store pseudonym { ... }'.
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 unlang_action_t session_and_pseudonym_store(rlm_rcode_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.
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
#define STATE_GUARD(_x)
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 void client_error_debug(request_t *request)
Print out the error the client returned.
static unlang_action_t sim_challenge_request_send(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Called after 'store session { ... }' and 'store pseudonym { ... }'.
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
static unlang_action_t common_reauthentication_request_send(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Called after 'store session { ... }' and 'store pseudonym { ... }'.
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.
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.
static unlang_action_t session_and_pseudonym_clear(rlm_rcode_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.
#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)
fr_aka_sim_id_type_t type
fr_pair_t * vp
unlang_action_t eap_aka_sim_state_machine_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Resumes the state machine when receiving a new response packet.
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.
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:564
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:70
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:94
#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:43
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:4208
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:4253
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:4468
#define fr_box_strvalue_len(_val, _len)
Definition value.h:286
int nonnull(2, 5))