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