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