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