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: ff5f140c7c14138348a23ea0978775d0dd6c4efe $")
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  fr_pair_t *vp, *prev;
230  bool set_by_user = false;
231 
232  /*
233  * Check if the user included any of the
234  * ID req attributes. If they did, use
235  * them to inform what we do next, and
236  * then delete them so they don't screw
237  * up any of the other code.
238  */
239  for (vp = fr_pair_list_head(&request->reply_pairs);
240  vp;
241  vp = fr_pair_list_next(&request->reply_pairs, vp)) {
244  found:
245  set_by_user = true;
246  RDEBUG2("Previous section added &reply.%pP, will request additional identity", vp);
247  prev = fr_pair_delete(&request->reply_pairs, vp);
248  vp = prev;
249  }
250  else if (vp->da == attr_eap_aka_sim_fullauth_id_req) {
252  goto found;
253  }
254  else if (vp->da == attr_eap_aka_sim_any_id_req) {
256  goto found;
257  }
258  }
259 
260  return set_by_user;
261 }
262 
263 /** Based on the hint byte in the identity, add &Identity-Type and &Method-Hint attributes
264  *
265  */
267  request_t *request, char const *identity)
268 {
271 
272  /*
273  * Process the identity that we received.
274  */
275  if (fr_aka_sim_id_type(&type, &method,
276  identity, talloc_array_length(identity) - 1) < 0) {
277  RPWDEBUG2("Failed parsing identity, continuing anyway");
278  }
279 
280  /*
281  * Map the output from the generic ID parser
282  * function to specific EAP-AKA internal
283  * attributes in the subrequest.
284  */
285  if (type != AKA_SIM_ID_TYPE_UNKNOWN) {
286  fr_pair_t *vp = NULL;
287 
289  switch (type) {
291  vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_PERMANENT;
292  break;
293 
295  vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_PSEUDONYM;
296  break;
297 
299  vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_FASTAUTH;
300  break;
301 
302  default:
303  fr_assert(0);
304  }
305  }
306 
307  /*
308  * Map the output from the generic ID parser
309  * function to specific EAP-AKA internal
310  * attributes in the subrequest.
311  */
312  if (method != AKA_SIM_METHOD_HINT_UNKNOWN) {
313  fr_pair_t *vp = NULL;
314 
316  switch (method) {
318  vp->vp_uint32 = FR_METHOD_HINT_VALUE_AKA_PRIME;
319  break;
320 
322  vp->vp_uint32 = FR_METHOD_HINT_VALUE_AKA;
323  break;
324 
326  vp->vp_uint32 = FR_METHOD_HINT_VALUE_SIM;
327  break;
328 
329  default:
330  fr_assert(0);
331  }
332  }
333 
334  if (type_p) *type_p = type;
335  if (method_p) *method_p = method;
336 }
337 
338 /** Add an Identity Request attribute to the reply
339  *
340  * Verify the progression of identity requests is valid.
341  *
342  * @param[in] request The current request.
343  * @param[in] eap_aka_sim_session The current eap_aka_sim_session.
344  * @return
345  * - 0 on success.
346  * - -1 on failure (progression of identities was not valid).
347  */
349 {
350  fr_pair_t *vp;
351 
352  switch (eap_aka_sim_session->id_req) {
353  /*
354  * This is allowed for EAP-SIM.
355  *
356  * The EAP-SIM-Start packet gets used both for "version negotiation" and
357  * for request identities, so for EAP-SIM it's perfectly acceptable
358  * to send four Sim-Start packets:
359  *
360  * - No ID
361  * - Any ID
362  * - Fullauth ID
363  * - Permanent ID
364  *
365  * We need to represent the starting state as separate from no id req,
366  * so that we can catch potential loops in the identity statate machine
367  */
368  case AKA_SIM_NO_ID_REQ:
370  id_out_of_order:
371  REDEBUG("Cannot send %s, already sent %s",
373  eap_aka_sim_session->id_req, "<INVALID>"),
375  eap_aka_sim_session->last_id_req, "<INVALID>"));
376  return -1;
377  }
378  break;
379 
380  case AKA_SIM_ANY_ID_REQ:
381  switch (eap_aka_sim_session->last_id_req) {
382  case AKA_SIM_INIT_ID_REQ:
383  case AKA_SIM_NO_ID_REQ:
384  break;
385 
386  default:
387  goto id_out_of_order;
388  }
390  vp->vp_bool = true;
391  break;
392 
394  switch (eap_aka_sim_session->last_id_req) {
395  case AKA_SIM_INIT_ID_REQ:
396  case AKA_SIM_NO_ID_REQ: /* Not sent anything before */
397  case AKA_SIM_ANY_ID_REQ: /* Last request was for any ID, but the re-auth ID was bad */
398  break;
399 
400  default:
401  goto id_out_of_order;
402  }
404  vp->vp_bool = true;
405  break;
406 
408  switch (eap_aka_sim_session->last_id_req) {
409  case AKA_SIM_INIT_ID_REQ:
410  case AKA_SIM_NO_ID_REQ: /* Not sent anything before */
411  case AKA_SIM_ANY_ID_REQ: /* Last request was for any ID, but the re-auth ID was bad */
412  case AKA_SIM_FULLAUTH_ID_REQ: /* ...didn't understand the pseudonym either */
413  break;
414 
415  default:
416  goto id_out_of_order;
417  }
419  vp->vp_bool = true;
420  break;
421 
422  default:
423  fr_assert(0);
424  }
425 
426  return 0;
427 }
428 
429 /** Copy the incoming identity to the permanent identity attribute
430  *
431  * If the incoming ID really looks like a permanent ID, and we were
432  * told it was a permanent ID, then (optionally) trim the first byte
433  * to form the real permanent ID.
434  *
435  * Otherwise copy the entire incoming Identity to the
436  * &session-state.Permanent-Identity attribute.
437  *
438  * @param[in] request The current request.
439  * @param[in] in current identity.
440  * @param[in] eap_type The current eap_type.
441  * @param[in] strip_hint Whether to strip the hint byte off the permanent identity
442  */
443 static int identity_to_permanent_identity(request_t *request, fr_pair_t *in, eap_type_t eap_type, bool strip_hint)
444 {
445  fr_aka_sim_id_type_t our_type;
446  fr_aka_sim_method_hint_t our_method, expected_method;
447  fr_pair_t *vp;
448 
449  if (in->vp_length == 0) {
450  RDEBUG2("Not processing zero length identity");
451  return -1;
452  }
453 
454  /*
455  * Not requested to strip hint, don't do anything
456  * fancy, just copy Identity -> Permanent-Identity.
457  */
458  if (!strip_hint) {
460  fr_pair_value_bstrndup(vp, in->vp_strvalue, in->vp_length, true);
461  return 0;
462  }
463 
464  switch (eap_type) {
465  case FR_EAP_METHOD_SIM:
466  expected_method = AKA_SIM_METHOD_HINT_SIM;
467  break;
468 
469  case FR_EAP_METHOD_AKA:
470  expected_method = AKA_SIM_METHOD_HINT_AKA;
471  break;
472 
474  expected_method = AKA_SIM_METHOD_HINT_AKA_PRIME;
475  break;
476 
477  default:
478  return -1;
479  }
480 
481  /*
482  * First, lets see if this looks like an identity
483  * we can process.
484  *
485  * For now we allow all permanent identities no
486  * matter what EAP method.
487  *
488  * This is because we could be starting a different
489  * EAP method to the one the identity hinted,
490  * but we still want to strip the first byte.
491  */
492  if ((fr_aka_sim_id_type(&our_type, &our_method, in->vp_strvalue, in->vp_length) < 0) ||
493  (our_type != AKA_SIM_ID_TYPE_PERMANENT)) {
495  fr_pair_value_bstrndup(vp, in->vp_strvalue, in->vp_length, true);
496 
497  RDEBUG2("%s has incorrect hint byte, expected '%c', got '%c'. "
498  "'hint' byte not stripped",
501  fr_aka_sim_hint_byte(our_type, our_method));
502  RINDENT();
503  RDEBUG2("&session-state.%pP", vp);
504  REXDENT();
505  } else {
506  /*
507  * To get here the identity must be >= 1 and must have
508  * had the expected hint byte.
509  *
510  * Strip off the hint byte, and then add the permanent
511  * identity to the output list.
512  */
514  fr_pair_value_bstrndup(vp, in->vp_strvalue + 1, in->vp_length - 1, true);
515 
516  RDEBUG2("Stripping 'hint' byte from %s", attr_eap_aka_sim_permanent_identity->name);
517  RINDENT();
518  RDEBUG2("&session-state.%pP", vp);
519  REXDENT();
520  }
521 
522  return 0;
523 }
524 
525 /** Check &control.checkcode matches &reply.checkcode
526  *
527  * @param[in] request The current request.
528  * @return
529  * - 1 if the check was skipped.
530  * - 0 if the check was successful.
531  * - -1 if the check failed.
532  */
533 static int checkcode_validate(request_t *request)
534 {
535  fr_pair_t *peer_checkcode, *our_checkcode;
536  /*
537  * Checkcode validation
538  *
539  * The actual cryptographic calculations are
540  * done by the calling module, we just check
541  * the result.
542  */
543  our_checkcode = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_checkcode);
544  if (our_checkcode) {
545  /*
546  * If the peer doesn't include a checkcode then that
547  * means they don't support it, and we can't validate
548  * their view of the identity packets.
549  */
550  peer_checkcode = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_checkcode);
551  if (peer_checkcode) {
552  if (fr_pair_cmp(peer_checkcode, our_checkcode) == 0) {
553  RDEBUG2("Received AT_CHECKCODE matches calculated AT_CHECKCODE");
554  return 0;
555  } else {
556  REDEBUG("Received AT_CHECKCODE does not match calculated AT_CHECKCODE");
557  RHEXDUMP_INLINE2(peer_checkcode->vp_octets, peer_checkcode->vp_length, "Received");
558  RHEXDUMP_INLINE2(our_checkcode->vp_octets, our_checkcode->vp_length, "Expected");
559  return -1;
560  }
561  /*
562  * Only print something if we calculated a checkcode
563  */
564  } else {
565  RDEBUG2("Peer didn't include AT_CHECKCODE, skipping checkcode validation");
566  }
567  }
568  return 1;
569 }
570 
571 /** Check &control.mac matches &reply.mac
572  *
573  * @param[in] request The current request.
574  * @return
575  * - 0 if the check was successful.
576  * - -1 if the check failed.
577  */
578 static int mac_validate(request_t *request)
579 {
580  fr_pair_t *peer_mac, *our_mac;
581  /*
582  * mac validation
583  *
584  * The actual cryptographic calculations are
585  * done by the calling module, we just check
586  * the result.
587  */
588  our_mac = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_mac);
589  if (!our_mac) {
590  REDEBUG("Missing &control.%s", attr_eap_aka_sim_mac->name);
591  return -1;
592 
593  }
594 
595  /*
596  * If the peer doesn't include a mac then that
597  * means they don't support it, and we can't validate
598  * their view of the identity packets.
599  */
600  peer_mac = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_mac);
601  if (!peer_mac) {
602  REDEBUG("Peer didn't include AT_MAC");
603  return -1;
604  }
605 
606  if (fr_pair_cmp(peer_mac, our_mac) != 0) {
607  REDEBUG("Received AT_MAC does not match calculated AT_MAC");
608  RHEXDUMP_INLINE2(peer_mac->vp_octets, peer_mac->vp_length, "Received");
609  RHEXDUMP_INLINE2(our_mac->vp_octets, our_mac->vp_length, "Expected");
610  return -1;
611  }
612 
613  RDEBUG2("Received AT_MAC matches calculated AT_MAC");
614  return 0;
615 }
616 
617 /** Set the crypto identity from a received identity
618  *
619  */
621  uint8_t const *identity, size_t len)
622 {
623  RDEBUG3("Setting cryptographic identity to \"%pV\"", fr_box_strvalue_len((char const *)identity, len));
624 
627  MEM(eap_aka_sim_session->keys.identity = talloc_memdup(eap_aka_sim_session, identity, len));
628 
629 }
630 
631 /** Resume after 'store session { ... }'
632  *
633  */
634 RESUME(store_session)
635 {
636  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
637 
638  switch (unlang_interpret_stack_result(request)) {
639  /*
640  * Store failed. Don't send fastauth id
641  */
644  break;
645 
646  default:
647  break;
648  }
649 
651 
652  return eap_aka_sim_session->next(p_result, mctx, request);
653 }
654 
655 /** Resume after 'store pseudonym { ... }'
656  *
657  * Stores session data if required.
658  */
659 RESUME(store_pseudonym)
660 {
661  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
662  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
663  fr_pair_t *vp;
664  fr_pair_t *new;
665 
666  switch (unlang_interpret_stack_result(request)) {
667  /*
668  * Store failed. Don't send pseudonym
669  */
672  break;
673 
674  default:
675  break;
676  }
677 
678  unlang_interpret_stack_result_set(request, RLM_MODULE_NOOP); /* Needed because we may call resume functions directly */
679 
681 
682  /*
683  * Generate fast-reauth data if we
684  * find a next_reauth_id pair in the
685  * reply list.
686  */
687  vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_eap_aka_sim_next_reauth_id);
688  if (vp) {
689  /*
690  * Generate a random fastauth string
691  */
692  if (vp->vp_length == 0) {
693  char *identity;
694 
695  if (!inst->ephemeral_id_length) {
696  RWDEBUG("Found empty Next-Reauth-Id, and told not to generate one. "
697  "Skipping store session { ... } section");
698 
699  goto done;
700  }
701 
702  MEM(identity = talloc_array(vp, char, inst->ephemeral_id_length + 2));
703  switch (eap_aka_sim_session->type) {
704  case FR_EAP_METHOD_SIM:
705  identity[0] = (char)ID_TAG_SIM_FASTAUTH;
706  break;
707 
708  case FR_EAP_METHOD_AKA:
709  identity[0] = (char)ID_TAG_AKA_FASTAUTH;
710  break;
711 
713  identity[0] = (char)ID_TAG_AKA_PRIME_FASTAUTH;
714  break;
715 
716  default:
717  break;
718  }
719  fr_rand_str((uint8_t *)identity + 1, inst->ephemeral_id_length, 'a');
720  identity[talloc_array_length(identity) - 1] = '\0';
721 
722  fr_value_box_bstrdup_buffer_shallow(NULL, &vp->data, NULL, identity, false);
723  }
725  fr_pair_value_memdup(new, (uint8_t const *)vp->vp_strvalue, vp->vp_length, vp->vp_tainted);
726 
728  vp->vp_strvalue, vp->vp_length));
729 
730  switch (eap_aka_sim_session->type) {
731  /*
732  * AKA and SIM use the original MK for session resumption.
733  */
734  case FR_EAP_METHOD_SIM:
735  case FR_EAP_METHOD_AKA:
737 
741  false);
742  break;
743  /*
744  * AKA' KDF 1 generates an additional key k_re
745  * which is used for reauthentication instead
746  * of the MK.
747  */
750 
754  false); /* truncates */
755  break;
756 
757  default:
758  fr_assert(0);
759  break;
760  }
761 
762  /*
763  * If the counter already exists in session
764  * state increment by 1, otherwise, add the
765  * attribute and set to zero.
766  */
767  vp = fr_pair_find_by_da_nested(&request->session_state_pairs, NULL, attr_eap_aka_sim_counter);
768  if (vp) {
769  vp->vp_uint16++;
770  /*
771  * Will get incremented by 1 in
772  * reauthentication_send, so when
773  * used, it'll be 1 (as per the standard).
774  */
775  } else {
777  vp->vp_uint16 = 0;
778  }
779 
780  return CALL_SECTION(store_session);
781  }
782 
783  /*
784  * We didn't store any fast-reauth data
785  */
786 done:
787  return eap_aka_sim_session->next(p_result, mctx, request);
788 }
789 
790 /** Implements a set of states for storing pseudonym and fastauth identities
791  *
792  * At the end of challenge or reauthentication rounds, the user may have specified
793  * a pseudonym and fastauth identity to return to the supplicant.
794  *
795  * Call the appropriate sections to persist those values.
796  *
797  * @param[out] p_result Result of calling the module.
798  * @param[in] mctx Module calling ctx.
799  * @param[in] request the current request.
800  * @param[in] eap_aka_sim_session the EAP session
801  * @param[in] next function to call after storing sessions and pseudonyms.
802  */
804  request_t *request,
806  module_method_t next)
807 {
808  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
809  fr_pair_t *vp;
810  fr_pair_t *new;
811 
813 
814  eap_aka_sim_session->next = next;
815 
816  unlang_interpret_stack_result_set(request, RLM_MODULE_NOOP); /* Needed because we may call resume functions directly */
817 
818  vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_eap_aka_sim_next_pseudonym);
819  if (vp) {
820  /*
821  * Generate a random pseudonym string
822  */
823  if (vp->vp_length == 0) {
824  char *identity;
825 
826  if (!inst->ephemeral_id_length) {
827  RWDEBUG("Found empty Pseudonym-Id, and told not to generate one. "
828  "Skipping store pseudonym { ... } section");
829 
830  return resume_store_pseudonym(p_result, mctx, request);
831  }
832 
833  MEM(identity = talloc_array(vp, char, inst->ephemeral_id_length + 2));
834  fr_rand_str((uint8_t *)identity + 1, inst->ephemeral_id_length, 'a');
835  switch (eap_aka_sim_session->type) {
836  case FR_EAP_METHOD_SIM:
837  identity[0] = (char)ID_TAG_SIM_PSEUDONYM;
838  break;
839 
840  case FR_EAP_METHOD_AKA:
841  identity[0] = (char)ID_TAG_AKA_PSEUDONYM;
842  break;
843 
845  identity[0] = (char)ID_TAG_AKA_PRIME_PSEUDONYM;
846  break;
847 
848  default:
849  break;
850  }
851  identity[talloc_array_length(identity) - 1] = '\0';
852  fr_value_box_bstrdup_buffer_shallow(NULL, &vp->data, NULL, identity, false);
853  }
855  fr_pair_value_copy(new, vp);
856 
858  vp->vp_strvalue, vp->vp_length));
859  return CALL_SECTION(store_pseudonym);
860  }
861 
862  return resume_store_pseudonym(p_result, mctx, request);
863 }
864 
865 /** Resume after 'clear session { ... }'
866  *
867  */
868 RESUME(clear_session)
869 {
870  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
871 
873 
874  return eap_aka_sim_session->next(p_result, mctx, request);
875 }
876 
877 /** Resume after 'clear pseudonym { ... }'
878  *
879  */
880 RESUME(clear_pseudonym)
881 {
882  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
883  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
884 
886 
887  /*
888  * Clear session (if one was stored)
889  */
891  fr_pair_t *vp;
892 
894 
896  fr_value_box_memdup(vp, &vp->data, NULL,
898  talloc_array_length(eap_aka_sim_session->fastauth_sent) - 1, true);
899  TALLOC_FREE(eap_aka_sim_session->fastauth_sent);
900 
901  return CALL_SECTION(clear_session);
902  }
903 
904  return eap_aka_sim_session->next(p_result, mctx, request);
905 }
906 
907 /** Implements a set of states for clearing out pseudonym and fastauth identities
908  *
909  * If either a Challenge round or Reauthentication round fail, we need to clear
910  * any identities that were provided during those rounds, as the supplicant
911  * will have discarded them.
912  *
913  * @param[out] p_result Result of calling the module.
914  * @param[in] mctx module calling ctx.
915  * @param[in] request the current request.
916  * @param[in] eap_aka_sim_session the current EAP session
917  * @param[in] next function to call after clearing sessions and pseudonyms.
918  */
920  request_t *request,
922  module_method_t next)
923 {
924  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
925 
927 
928  eap_aka_sim_session->next = next;
929 
930  unlang_interpret_stack_result_set(request, RLM_MODULE_NOOP); /* Needed because we may call resume functions directly */
931 
932  /*
933  * Clear out pseudonyms (if we sent one)
934  */
936  fr_pair_t *vp;
937 
940  TALLOC_FREE(eap_aka_sim_session->pseudonym_sent);
941 
942  return CALL_SECTION(clear_pseudonym);
943  }
944 
945  return resume_clear_pseudonym(p_result, mctx, request);
946 }
947 
948 /** Export EAP-SIM/AKA['] attributes
949  *
950  * Makes any internal data available as attributes in the response.
951  * This allows test frameworks and the encoder to access any data they need without
952  * needing to look at the eap_aka_session_t.
953  */
955 {
956  fr_pair_t *vp = NULL, *subtype_vp;
957 
958  /*
959  * Set the subtype to identity request
960  */
962  subtype_vp->vp_uint16 = subtype;
963 
965  while ((vp = fr_pair_list_next(&request->reply_pairs, vp))) {
967  RWDEBUG("Silently discarding &reply.%pP: Encrypted attributes not "
968  "allowed in this round", vp);
969  vp = fr_pair_delete(&request->reply_pairs, vp);
970  continue;
971  }
972  }
973  }
974 }
975 
976 static void CC_HINT(nonnull(1,2))
978  uint8_t const *hmac_extra_request, size_t hmac_extra_request_len,
979  uint8_t const *hmac_extra_response, size_t hmac_extra_response_len)
980 {
981  fr_pair_t *vp;
982 
983  /*
984  * Export keying material necessary for
985  * the encoder to encrypt and sign
986  * packets.
987  */
988  if (hmac_extra_request && hmac_extra_request_len) {
990  MEM(fr_pair_value_memdup(vp, hmac_extra_request, hmac_extra_request_len, true) == 0);
991  }
992 
993  if (hmac_extra_response && hmac_extra_response_len) {
995  MEM(fr_pair_value_memdup(vp, hmac_extra_response, hmac_extra_response_len, true) == 0);
996  }
997 
1002  true) == 0);
1003 
1007  sizeof(eap_aka_sim_session->keys.k_encr),
1008  true) == 0);
1009 }
1010 
1011 /** Called after 'store session { ... }' and 'store pseudonym { ... }'
1012  *
1013  */
1015  module_ctx_t const *mctx, request_t *request)
1016 {
1017  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1018 
1019  /*
1020  * Return reply attributes - AT_IV is handled automatically by the encoder
1021  */
1022  common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_SIM_REAUTHENTICATION);
1023 
1024  /*
1025  * 9.5. EAP-Request/SIM/Re-authentication
1026  *
1027  * AT_MAC MUST be included. No message-specific data is included in the
1028  * MAC calculation. See Section 10.14.
1029  *
1030  * 9.6. EAP-Response/SIM/Re-authentication
1031  *
1032  * The AT_MAC attribute MUST be included. For
1033  * EAP-Response/SIM/Re-authentication, the MAC code is calculated over
1034  * the following data: EAP packet| NONCE_S
1035  *
1036  * 9.7. EAP-Request/AKA-Reauthentication
1037  *
1038  * The AT_MAC attribute MUST be included. No message-specific data is
1039  * included in the MAC calculation, see Section 10.15.
1040  *
1041  * 9.8. EAP-Response/AKA-Reauthentication
1042  *
1043  * The AT_MAC attribute MUST be included. For
1044  * EAP-Response/AKA-Reauthentication, the MAC code is calculated over
1045  * the following data: EAP packet| NONCE_S.
1046  */
1048  NULL, 0,
1049  eap_aka_sim_session->keys.reauth.nonce_s,
1050  sizeof(eap_aka_sim_session->keys.reauth.nonce_s));
1051 
1053 }
1054 
1055 /** Called after 'store session { ... }' and 'store pseudonym { ... }'
1056  *
1057  */
1059 {
1060  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1061 
1062  /*
1063  * Encode the packet - AT_IV is handled automatically
1064  * by the encoder.
1065  */
1066  common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_CHALLENGE);
1067 
1068  /*
1069  * 9.3. EAP-Request/AKA-Challenge
1070  *
1071  * AT_MAC MUST be included. In EAP-Request/AKA-Challenge, there is no
1072  * message-specific data covered by the MAC, see Section 10.15.
1073  *
1074  * 9.4. EAP-Response/AKA-Challenge
1075  *
1076  * The AT_MAC attribute MUST be included. In
1077  * EAP-Response/AKA-Challenge, there is no message-specific data covered
1078  * by the MAC, see Section 10.15.
1079  */
1080  common_crypto_export(request, eap_aka_sim_session, NULL, 0, NULL, 0);
1081 
1083 }
1084 
1085 /** Called after 'store session { ... }' and 'store pseudonym { ... }'
1086  *
1087  */
1089 {
1090  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1091  uint8_t sres_cat[AKA_SIM_VECTOR_GSM_SRES_SIZE * 3];
1092  uint8_t *p = sres_cat;
1093 
1094  /*
1095  * Encode the packet - AT_IV is handled automatically
1096  * by the encoder.
1097  */
1098  common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_SIM_CHALLENGE);
1099 
1100  memcpy(p, eap_aka_sim_session->keys.gsm.vector[0].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
1102  memcpy(p, eap_aka_sim_session->keys.gsm.vector[1].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
1104  memcpy(p, eap_aka_sim_session->keys.gsm.vector[2].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
1105 
1106  /*
1107  * 9.3. EAP-Request/SIM/Challenge
1108  *
1109  * The AT_MAC attribute MUST be included. For
1110  * EAP-Request/SIM/Challenge, the MAC code is calculated over the
1111  * following data: EAP packet| NONCE_MT
1112  *
1113  * 9.4. EAP-Response/SIM/Challenge
1114  *
1115  * The AT_MAC attribute MUST be included. For EAP-
1116  * Response/SIM/Challenge, the MAC code is calculated over the following
1117  * data: EAP packet| n*SRES
1118  */
1120  eap_aka_sim_session->keys.gsm.nonce_mt, sizeof(eap_aka_sim_session->keys.gsm.nonce_mt),
1121  sres_cat, sizeof(sres_cat));
1122 
1124 }
1125 
1126 /** Helper function to check for the presence and length of AT_SELECTED_VERSION and copy its value into the keys structure
1127  *
1128  * Also checks the version matches one of the ones we advertised in our version list,
1129  * which is a bit redundant seeing as there's only one version of EAP-SIM.
1130  */
1132 {
1133  fr_pair_t *selected_version_vp;
1134 
1135  /*
1136  * Check that we got an AT_SELECTED_VERSION
1137  */
1138  selected_version_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_selected_version);
1139  if (!selected_version_vp) {
1140  REDEBUG("EAP-Response/SIM/Start does not contain AT_SELECTED_VERSION");
1141  return -1;
1142  }
1143 
1144  /*
1145  * See if the selected version was in our list
1146  */
1147  {
1148  uint8_t selected_version[2];
1149  uint8_t *p, *end;
1150  bool found = false;
1151 
1152  p = eap_aka_sim_session->keys.gsm.version_list;
1153  end = p + eap_aka_sim_session->keys.gsm.version_list_len;
1154 
1155  selected_version[0] = (selected_version_vp->vp_uint16 & 0xff00) >> 8;
1156  selected_version[1] = (selected_version_vp->vp_uint16 & 0x00ff);
1157 
1158  while (p < end) {
1159  if ((p[0] == selected_version[0]) && (p[1] == selected_version[1])) {
1160  found = true;
1161  /*
1162  * Update our keying material
1163  */
1164  eap_aka_sim_session->keys.gsm.version_select[0] = selected_version[0];
1165  eap_aka_sim_session->keys.gsm.version_select[1] = selected_version[1];
1166  break;
1167  }
1168  }
1169 
1170  if (!found) {
1171  REDEBUG("AT_SELECTED_VERSION (%u) does not match a value in our version list",
1172  selected_version_vp->vp_uint16);
1173  return -1;
1174  }
1175  }
1176 
1177  return 0;
1178 }
1179 
1180 /** Helper function to check for the presence and length of AT_NONCE_MT and copy its value into the keys structure
1181  *
1182  * Does not actually perform cryptographic validation of AT_NONCE_MT, this is done later.
1183  */
1185 {
1186  fr_pair_t *nonce_mt_vp;
1187 
1188  /*
1189  * Copy nonce_mt to the keying material
1190  */
1191  nonce_mt_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_nonce_mt);
1192  if (!nonce_mt_vp) {
1193  REDEBUG("EAP-Response/SIM/Start does not contain AT_NONCE_MT");
1194  return -1;
1195  }
1196 
1197  if (nonce_mt_vp->vp_length != sizeof(eap_aka_sim_session->keys.gsm.nonce_mt)) {
1198  REDEBUG("AT_NONCE_MT must be exactly %zu bytes, not %zu bytes",
1199  sizeof(eap_aka_sim_session->keys.gsm.nonce_mt), nonce_mt_vp->vp_length);
1200  return -1;
1201  }
1202  memcpy(eap_aka_sim_session->keys.gsm.nonce_mt, nonce_mt_vp->vp_octets,
1203  sizeof(eap_aka_sim_session->keys.gsm.nonce_mt));
1204 
1205  return 0;
1206 }
1207 
1208 /** FAILURE state - State machine exit point after sending EAP-Failure
1209  *
1210  * Should never actually be called. Is just a placeholder function to represent the FAILURE
1211  * termination state. Could equally be a NULL pointer, but then on a logic error
1212  * we'd get a SEGV instead of a more friendly assert/failure rcode.
1213  */
1215 {
1216  if (!fr_cond_assert(request && mctx && mctx->rctx)) RETURN_MODULE_FAIL; /* unused args */
1217 
1218  fr_assert(0); /* Should never actually be called */
1219 
1221 }
1222 
1223 /** Resume after 'send EAP-Failure { ... }'
1224  *
1225  */
1226 RESUME(send_eap_failure)
1227 {
1228  if (!fr_cond_assert(mctx && mctx->rctx)) RETURN_MODULE_FAIL; /* unused args */
1229 
1231 
1232  RDEBUG2("Sending EAP-Failure");
1233 
1235 }
1236 
1237 /** Enter EAP-FAILURE state
1238  *
1239  */
1241 {
1242  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1243  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1244 
1245  /*
1246  * Free anything we were going to send out...
1247  */
1248  fr_pair_list_free(&request->reply_pairs);
1249 
1250  /*
1251  * If we're failing, then any identities
1252  * we sent are now invalid.
1253  */
1255  return session_and_pseudonym_clear(p_result, mctx,
1256  request, eap_aka_sim_session, guard_eap_failure);
1257  /* come back when we're done */
1258  }
1259 
1261 
1262  return CALL_SECTION(send_eap_failure);
1263 }
1264 
1265 /** Resume after 'recv Failure-Notification-Ack { ... }'
1266  *
1267  * - Enter the EAP-FAILURE state.
1268  */
1269 RESUME(recv_common_failure_notification_ack)
1270 {
1272 
1273  /*
1274  * Case 2 where we're allowed to send an EAP-Failure
1275  */
1276  return STATE_TRANSITION(eap_failure);
1277 }
1278 
1279 /** FAILURE-NOTIFICATION state - Continue the state machine after receiving a response to our EAP-Request/(AKA|SIM)-Notification
1280  *
1281  * - Continue based on received AT_SUBTYPE value:
1282  * - EAP-Response/SIM-Client-Error - Call 'recv Failure-Notification-Ack { ... }'
1283  * - Anything else, enter the FAILURE-NOTIFICATION state.
1284  */
1286 {
1287  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1289 
1290  subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
1291  if (!subtype_vp) goto fail;
1292 
1293  switch (subtype_vp->vp_uint16) {
1294  case FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION:
1295  RDEBUG2("Failure-Notification ACKed, sending EAP-Failure");
1296  return CALL_SECTION(recv_common_failure_notification_ack);
1297 
1298  default:
1299  fail:
1300  RWDEBUG("Failure-Notification not ACKed correctly, sending EAP-Failure anyway");
1301  return STATE_TRANSITION(eap_failure);
1302  }
1303 }
1304 
1305 /** Resume after 'send Failure-Notification { ... }'
1306  *
1307  * Ignores return code from send Failure-Notification { ... } section.
1308  */
1309 RESUME(send_common_failure_notification)
1310 {
1311  fr_pair_t *vp, *notification_vp;
1312  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx,
1314 
1315  if (!fr_cond_assert(mctx)) RETURN_MODULE_FAIL; /* quiet unused warning */
1316 
1318 
1319  /*
1320  * Allow the user to specify specific failure notification
1321  * types. We assume the user knows what they're doing and
1322  * only toggle success and phase bits.
1323  *
1324  * This allows custom notification schemes to be implemented.
1325  *
1326  * If this is prior to authentication, valid values are:
1327  * - FR_NOTIFICATION_VALUE_GENERAL_FAILURE
1328  *
1329  * If this is after authentication, valid values are:
1330  * - FR_NOTIFICATION_VALUE_GENERAL_FAILURE_AFTER_AUTHENTICATION
1331  * - FR_NOTIFICATION_VALUE_TEMPORARILY_DENIED - User has been
1332  * temporarily denied access to the requested service.
1333  * - FR_NOTIFICATION_VALUE_NOT_SUBSCRIBED
1334  * User has not subscribed to the requested service.
1335  */
1336  notification_vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_notification);
1337 
1338  /*
1339  * Keep Notification, but remove everything else...
1340  */
1341  if (notification_vp) fr_pair_remove(&request->reply_pairs, notification_vp);
1342  fr_pair_list_free(&request->reply_pairs);
1343  if (notification_vp) fr_pair_append(&request->reply_pairs, notification_vp);
1344 
1345  /*
1346  * Change the failure notification depending where
1347  * we are in the eap_aka_state machine.
1348  */
1350  if (!notification_vp) {
1351  MEM(pair_append_reply(&notification_vp, attr_eap_aka_sim_notification) >= 0);
1352  notification_vp->vp_uint16 = eap_aka_sim_session->failure_type; /* Default will be zero */
1353  }
1354 
1355  notification_vp->vp_uint16 &= ~0x4000; /* Unset phase bit */
1356 
1357  /*
1358  * Include the counter attribute if we're failing
1359  * after a reauthentication success.
1360  *
1361  * RFC 4187 Section #9.10
1362  *
1363  * If EAP-Request/AKA-Notification is used on
1364  * a fast re-authentication exchange, and if
1365  * the P bit in AT_NOTIFICATION is set to zero,
1366  * then AT_COUNTER is used for replay protection.
1367  * In this case, the AT_ENCR_DATA and AT_IV
1368  * attributes MUST be included, and the
1369  * encapsulated plaintext attributes MUST include
1370  * the AT_COUNTER attribute. The counter value
1371  * included in AT_COUNTER MUST be the same
1372  * as in the EAP-Request/AKA-Reauthentication
1373  * packet on the same fast re-authentication
1374  * exchange.
1375  *
1376  * If the counter is used it should never be zero,
1377  * as it's incremented on first reauthentication
1378  * request.
1379  */
1381  MEM(pair_update_reply(&notification_vp, attr_eap_aka_sim_counter) >= 0);
1382  notification_vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
1383  }
1384 
1385  /*
1386  * If we're after the challenge phase
1387  * then we need to include a MAC to
1388  * protect notifications.
1389  */
1391  fr_pair_value_memdup(vp, NULL, 0, false);
1392  } else {
1393  /*
1394  * Only valid code is general failure
1395  */
1396  if (!notification_vp) {
1397  MEM(pair_append_reply(&notification_vp, attr_eap_aka_sim_notification) >= 0);
1398  notification_vp->vp_uint16 = FR_NOTIFICATION_VALUE_GENERAL_FAILURE;
1399  /*
1400  * User supplied failure code
1401  */
1402  } else {
1403  notification_vp->vp_uint16 |= 0x4000; /* Set phase bit */
1404  }
1405  }
1406  notification_vp->vp_uint16 &= ~0x8000; /* In both cases success bit should be low */
1407 
1408  /*
1409  * Send a response
1410  */
1411  common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION);
1412 
1414 }
1415 
1416 /** Enter the FAILURE-NOTIFICATION state
1417  *
1418  */
1420 {
1421  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1422  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1423 
1424  /*
1425  * If we're failing, then any identities
1426  * we sent are now invalid.
1427  */
1429  return session_and_pseudonym_clear(p_result, mctx, request, eap_aka_sim_session,
1430  guard_common_failure_notification); /* come back when we're done */
1431  }
1432 
1433  /*
1434  * We've already sent a failure notification
1435  * Now we just fail as it means something
1436  * went wrong processing the ACK or we got
1437  * garbage from the supplicant.
1438  */
1439  if (eap_aka_sim_session->state == state_common_failure_notification) {
1440  return STATE_TRANSITION(eap_failure);
1441  }
1442 
1443  /*
1444  * Otherwise just transition as normal...
1445  */
1447 
1448  return CALL_SECTION(send_common_failure_notification);
1449 }
1450 
1451 /** SUCCESS state - State machine exit point after sending EAP-Success
1452  *
1453  * Should never actually be called. Is just a placeholder function to represent the SUCCESS
1454  * termination state. Could equally be a NULL pointer, but then on a logic error
1455  * we'd get a SEGV instead of a more friendly assert/failure rcode.
1456  */
1458 {
1459  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1460 
1461  if (!fr_cond_assert(request && mctx && eap_aka_sim_session)) RETURN_MODULE_FAIL; /* unused args */
1462 
1463  fr_assert(0); /* Should never actually be called */
1464 
1466 }
1467 
1468 /** Resume after 'send EAP-Success { ... }'
1469  *
1470  * Add MPPE keys to the request being sent to the supplicant
1471  *
1472  * The only work to be done is the add the appropriate SEND/RECV
1473  * attributes derived from the MSK.
1474  */
1475 RESUME(send_eap_success)
1476 {
1477  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1478  uint8_t *p;
1479 
1480  RDEBUG2("Sending EAP-Success");
1481 
1482  /*
1483  * If this is true we're entering this state
1484  * after sending a AKA-Success-Notification
1485  *
1486  * Is seems like a really bad idea to allow the
1487  * user to send a protected success to the
1488  * supplicant and then force a failure using
1489  * the send EAP-Success { ... } section.
1490  */
1492  switch (unlang_interpret_stack_result(request)) {
1494  RWDEBUG("Ignoring rcode (%s) from send EAP-Success { ... } "
1495  "as we already sent a Success-Notification",
1497  RWDEBUG("If you need to force a failure, return an error code from "
1498  "send Success-Notification { ... }");
1499  break;
1500 
1501  default:
1502  break;
1503  }
1504 
1505  /*
1506  * But... if we're not working with protected
1507  * success indication, this is the only
1508  * opportunity the user has to force a failure at
1509  * the end of authentication.
1510  */
1511  } else {
1513  }
1514 
1515  RDEBUG2("Adding attributes for MSK");
1518  p += EAP_TLS_MPPE_KEY_LEN;
1520 
1522 }
1523 
1524 /** Enter EAP-SUCCESS state
1525  *
1526  */
1528 {
1529  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1530 
1532 
1533  return CALL_SECTION(send_eap_success);
1534 }
1535 
1536 /** Resume after 'recv Success-Notification-Ack { ... }'
1537  *
1538  * - Enter the EAP-SUCCESS state.
1539  */
1540 RESUME(recv_common_success_notification_ack)
1541 {
1543 
1544  /*
1545  * RFC 4187 says we ignore the contents of the
1546  * next packet after we send our success notification
1547  * and always send a success.
1548  */
1549  return STATE_TRANSITION(eap_success);
1550 }
1551 
1552 /** SUCCESS-NOTIFICATION state - Continue the state machine after receiving a response to our EAP-Request/(AKA|SIM)-Notification
1553  *
1554  * - Call 'recv Success-Notification-Ack { ... }'
1555  */
1557 {
1558  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1559 
1560  /*
1561  * Because the server uses the AT_NOTIFICATION code "Success" (32768) to
1562  * indicate that the EAP exchange has completed successfully, the EAP
1563  * exchange cannot fail when the server processes the EAP-AKA response
1564  * to this notification. Hence, the server MUST ignore the contents of
1565  * the EAP-AKA response it receives to the EAP-Request/AKA-Notification
1566  * with this code. Regardless of the contents of the EAP-AKA response,
1567  * the server MUST send EAP-Success as the next packet.
1568  */
1569  return CALL_SECTION(recv_common_success_notification_ack);
1570 }
1571 
1572 /** Resume after 'send Success-Notification { ... }'
1573  *
1574  */
1575 RESUME(send_common_success_notification)
1576 {
1577  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1578  fr_pair_t *vp;
1579 
1581 
1583 
1584  /*
1585  * If we're in this state success bit is
1586  * high phase bit is low.
1587  */
1589  vp->vp_uint16 = FR_NOTIFICATION_VALUE_SUCCESS;
1590 
1591  /*
1592  * RFC 4187 section #9.10
1593  *
1594  * If EAP-Request/AKA-Notification is used on
1595  * a fast re-authentication exchange, and if
1596  * the P bit in AT_NOTIFICATION is set to zero,
1597  * then AT_COUNTER is used for replay protection.
1598  * In this case, the AT_ENCR_DATA and AT_IV
1599  * attributes MUST be included, and the
1600  * encapsulated plaintext attributes MUST include
1601  * the AT_COUNTER attribute. The counter value
1602  * included in AT_COUNTER MUST be the same
1603  * as in the EAP-Request/AKA-Reauthentication
1604  * packet on the same fast re-authentication
1605  * exchange.
1606  *
1607  * If the counter is used it should never be zero,
1608  * as it's incremented on first reauthentication
1609  * request.
1610  */
1611  if (eap_aka_sim_session->keys.reauth.counter > 0) {
1613  vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
1614  }
1615 
1616  /*
1617  * Need to include an AT_MAC attribute so that
1618  * it will get calculated.
1619  */
1621  fr_pair_value_memdup(vp, NULL, 0, false);
1622 
1623  /*
1624  * Return reply attributes
1625  */
1626  common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION);
1627 
1629 }
1630 
1631 /** Enter the SUCCESS-NOTIFICATION state
1632  *
1633  */
1635 {
1636  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1637 
1639 
1640  return CALL_SECTION(send_common_success_notification);
1641 }
1642 
1643 /** Resume after 'recv Client-Error { ... }'
1644  *
1645  * - Enter the EAP-FAILURE state.
1646  */
1647 RESUME(recv_common_client_error)
1648 {
1650 
1651  return STATE_TRANSITION(eap_failure);
1652 }
1653 
1654 /** Resume after 'recv Reauthentication-Response { ... }'
1655  *
1656  * - If 'recv Reauthentication-Response { ... }' returned a failure
1657  * rcode, enter the FAILURE-NOTIFICATION state.
1658  * - ...or call the EAP-Request/Reauthentication-Response function to act on the
1659  * contents of the response.
1660  */
1661 RESUME(recv_common_reauthentication_response)
1662 {
1663  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1664 
1666 
1667  /*
1668  * Validate mac
1669  */
1670  if (mac_validate(request) < 0) {
1671  failure:
1673  }
1674 
1675  /*
1676  * Validate the checkcode
1677  */
1678  if (checkcode_validate(request) < 0) goto failure;
1679 
1680  /*
1681  * Check to see if the supplicant sent
1682  * AT_COUNTER_TOO_SMALL, if they did then we
1683  * clear out reauth information and enter the
1684  * challenge state.
1685  */
1686  if (fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_eap_aka_sim_counter_too_small)) {
1687  RWDEBUG("Peer sent AT_COUNTER_TOO_SMALL (indicating our AT_COUNTER value (%u) wasn't fresh)",
1688  eap_aka_sim_session->keys.reauth.counter);
1689 
1692 
1694  }
1695 
1696  /*
1697  * If the peer wants a Success notification, and
1698  * we included AT_RESULT_IND then send a success
1699  * notification, otherwise send a normal EAP-Success.
1700  *
1701  * RFC 4187 Section #6.2. Result Indications
1702  */
1704  if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
1705  RDEBUG("We wanted to use protected result indications, but peer does not");
1707  } else {
1709  }
1710  } else if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
1711  RDEBUG("Peer wanted to use protected result indications, but we do not");
1712  }
1713 
1715 
1716  return STATE_TRANSITION(eap_success);
1717 }
1718 
1719 /** REAUTHENTICATION state - Continue the state machine after receiving a response to our EAP-Request/SIM-Start
1720  *
1721  * - Continue based on received AT_SUBTYPE value:
1722  * - EAP-Response/(SIM|AKA)-Reauthentication - call 'recv Reauthentication-Response { ... }'
1723  * - EAP-Response/(SIM|AKA)-Client-Error - call 'recv Client-Error { ... }' and after that
1724  * send a EAP-Request/(SIM|AKA)-Notification indicating a General Failure.
1725  * - Anything else, enter the FAILURE-NOTIFICATION state.
1726  */
1728 {
1729  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1730  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1731  fr_pair_t *subtype_vp = NULL;
1732 
1733  subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
1734  if (!subtype_vp) {
1735  REDEBUG("Missing AT_SUBTYPE");
1736  goto fail;
1737  }
1738 
1739  /*
1740  * These aren't allowed in Reauthentication responses as they don't apply:
1741  *
1742  * EAP_AKA_AUTHENTICATION_REJECT - We didn't provide an AUTN value
1743  * EAP_AKA_SYNCHRONIZATION_FAILURE - We didn't use new vectors.
1744  */
1745  switch (subtype_vp->vp_uint16) {
1746  case FR_SUBTYPE_VALUE_AKA_SIM_REAUTHENTICATION:
1747  /*
1748  * AT_COUNTER_TOO_SMALL is handled
1749  * in common_reauthentication_response_process.
1750  */
1751  return CALL_SECTION(recv_common_reauthentication_response);
1752 
1753  /*
1754  * Case 1 where we're allowed to send an EAP-Failure
1755  */
1756  case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
1757  client_error_debug(request);
1758 
1760 
1761  return CALL_SECTION(recv_common_client_error);
1762  /*
1763  * RFC 4187 says we *MUST* notify, not just
1764  * send an EAP-Failure in this case.
1765  */
1766  default:
1767  REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
1768  fail:
1770 
1772  }
1773 }
1774 
1775 
1776 /** Send a EAP-Request/(AKA|SIM)-Reauthenticate message to the supplicant
1777  *
1778  */
1780  module_ctx_t const *mctx,
1781  request_t *request,
1783 {
1784  fr_pair_t *vp;
1785  fr_pair_t *kdf_id;
1786 
1787  /*
1788  * Allow override of KDF Identity
1789  *
1790  * Because certain handset manufacturers don't
1791  * implement RFC 4187 correctly and use the
1792  * wrong identity as input the the PRF/KDF.
1793  *
1794  * Not seen any doing this for re-authentication
1795  * but you never know...
1796  */
1797  kdf_id = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_kdf_identity);
1798  if (kdf_id) {
1800  (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
1801  fr_pair_delete_by_da(&request->control_pairs, attr_eap_aka_sim_kdf_identity);
1802  }
1803 
1804  RDEBUG2("Generating new session keys");
1805 
1806  switch (eap_aka_sim_session->type) {
1807  /*
1808  * The GSM and UMTS KDF_0 mutate their keys using
1809  * and identical algorithm.
1810  */
1811  case FR_EAP_METHOD_SIM:
1812  case FR_EAP_METHOD_AKA:
1813  if (fr_aka_sim_vector_gsm_umts_kdf_0_reauth_from_attrs(request, &request->session_state_pairs,
1814  &eap_aka_sim_session->keys) != 0) {
1815  request_new_id:
1816  switch (eap_aka_sim_session->last_id_req) {
1817  /*
1818  * Got here processing EAP-Identity-Response
1819  * If this is the *true* reauth ID, then
1820  * there's no point in setting AKA_SIM_ANY_ID_REQ.
1821  */
1822  case AKA_SIM_INIT_ID_REQ:
1823  case AKA_SIM_NO_ID_REQ:
1824  case AKA_SIM_ANY_ID_REQ:
1825  RDEBUG2("Composing EAP-Request/Reauthentication failed. Clearing reply attributes and "
1826  "requesting additional Identity");
1827  fr_pair_list_free(&request->reply_pairs);
1829  return STATE_TRANSITION(common_identity);
1830 
1833  REDEBUG("Last requested fullauth or permanent ID, "
1834  "but received, or were told we received (by policy), "
1835  "a fastauth ID. Cannot continue");
1837  }
1838  }
1839  if (fr_aka_sim_crypto_kdf_0_reauth(&eap_aka_sim_session->keys) < 0) goto request_new_id;
1840  break;
1841 
1843  switch (eap_aka_sim_session->kdf) {
1844  case FR_KDF_VALUE_PRIME_WITH_CK_PRIME_IK_PRIME:
1845  if (fr_aka_sim_vector_umts_kdf_1_reauth_from_attrs(request, &request->session_state_pairs,
1846  &eap_aka_sim_session->keys) != 0) {
1847  goto request_new_id;
1848  }
1849  if (fr_aka_sim_crypto_umts_kdf_1_reauth(&eap_aka_sim_session->keys) < 0) goto request_new_id;
1850  break;
1851 
1852  default:
1853  fr_assert(0);
1854  break;
1855  }
1856  break;
1857 
1858  default:
1859  fr_assert(0);
1860  break;
1861  }
1862 
1864 
1865  /*
1866  * Indicate we'd like to use protected success messages
1867  * with AT_RESULT_IND
1868  *
1869  * Use our default, but allow user override too.
1870  */
1871  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind);
1872  if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
1873 
1874  /*
1875  * RFC 5448 says AT_BIDDING is only sent in the challenge
1876  * not in reauthentication, so don't add that here.
1877  */
1878 
1879  /*
1880  * Add AT_NONCE_S
1881  */
1884  sizeof(eap_aka_sim_session->keys.reauth.nonce_s), false);
1885 
1886  /*
1887  * Add AT_COUNTER
1888  */
1890  vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
1891 
1892  /*
1893  * need to include an empty AT_MAC attribute so that
1894  * the mac will get calculated.
1895  */
1897  fr_pair_value_memdup(vp, NULL, 0, false);
1898 
1899  /*
1900  * We've sent the challenge so the peer should now be able
1901  * to accept encrypted attributes.
1902  */
1904 
1905  return session_and_pseudonym_store(p_result, mctx, request, eap_aka_sim_session,
1907 }
1908 
1909 /** Resume after 'send Reauthentication-Request { ... }'
1910  *
1911  */
1912 RESUME(send_common_reauthentication_request)
1913 {
1914  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1915 
1916  switch (unlang_interpret_stack_result(request)) {
1917  /*
1918  * Failed getting the values we need for resumption
1919  * Request a different identity.
1920  */
1921  default:
1922  switch (eap_aka_sim_session->last_id_req) {
1923  /*
1924  * Got here processing EAP-Identity-Response
1925  * If this is the *true* reauth ID, then
1926  * there's no point in setting AKA_SIM_ANY_ID_REQ.
1927  */
1928  case AKA_SIM_INIT_ID_REQ:
1929  case AKA_SIM_NO_ID_REQ:
1930  case AKA_SIM_ANY_ID_REQ:
1931  RDEBUG2("Previous section returned (%s), clearing reply attributes and "
1932  "requesting additional identity",
1934  fr_pair_list_free(&request->reply_pairs);
1936 
1937  return STATE_TRANSITION(common_identity);
1938 
1941  default:
1942  break;
1943  }
1944  REDEBUG("Last requested Full-Auth-Id or Permanent-Identity, "
1945  "but received a Fast-Auth-Id. Cannot continue");
1946  failure:
1948 
1949  /*
1950  * Policy rejected the user
1951  */
1952  case RLM_MODULE_REJECT:
1953  case RLM_MODULE_DISALLOW:
1954  goto failure;
1955 
1956  /*
1957  * Everything looks ok, send the EAP-Request/reauthentication message
1958  * After storing any new pseudonyms or session information.
1959  */
1960  case RLM_MODULE_NOOP:
1961  case RLM_MODULE_OK:
1962  case RLM_MODULE_UPDATED:
1963  return common_reauthentication_request_compose(p_result, mctx, request, eap_aka_sim_session);
1964  }
1965 }
1966 
1967 /** Resume after 'load pseudonym { ... }'
1968  *
1969  */
1970 RESUME(load_pseudonym)
1971 {
1972  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
1973  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
1974 
1976 
1977  /*
1978  * Control attributes required could have been specified
1979  * in another section.
1980  */
1981  if (!inst->actions.load_pseudonym) {
1982  next_state:
1983  return eap_aka_sim_session->next(p_result, mctx, request);
1984  }
1985 
1986  switch (unlang_interpret_stack_result(request)) {
1987  /*
1988  * Failed resolving the pseudonym
1989  * request a different identity.
1990  */
1991  default:
1992  switch (eap_aka_sim_session->last_id_req) {
1993  case AKA_SIM_INIT_ID_REQ:
1994  case AKA_SIM_NO_ID_REQ:
1995  case AKA_SIM_ANY_ID_REQ:
1997  RDEBUG2("Previous section returned (%s), clearing reply attributes and "
1998  "requesting additional identity",
2000  fr_pair_list_free(&request->reply_pairs);
2002  return STATE_TRANSITION(common_identity);
2003 
2005  REDEBUG("Last requested a Permanent-Identity, but received a Pseudonym. Cannot continue");
2006  failure:
2008  }
2009  break;
2010 
2011  /*
2012  * Policy rejected the user
2013  */
2014  case RLM_MODULE_REJECT:
2015  case RLM_MODULE_DISALLOW:
2016  goto failure;
2017 
2018  /*
2019  * Everything OK
2020  */
2021  case RLM_MODULE_OK:
2022  case RLM_MODULE_UPDATED:
2023  goto next_state;
2024  }
2025 
2026  goto failure;
2027 }
2028 
2029 /** Resume after 'load session { ... }'
2030  *
2031  */
2032 RESUME(load_session)
2033 {
2034  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2035  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2036 
2038 
2039  /*
2040  * Control attributes required could have been specified
2041  * in another section.
2042  */
2043  if (!inst->actions.load_session) goto reauthenticate;
2044 
2045  switch (unlang_interpret_stack_result(request)) {
2046  /*
2047  * Failed getting the values we need for resumption
2048  * Request a different identity.
2049  */
2050  default:
2051  switch (eap_aka_sim_session->last_id_req) {
2052  /*
2053  * Got here processing EAP-Identity-Response
2054  * If this is the *true* reauth ID, then
2055  * there's no point in setting AKA_SIM_ANY_ID_REQ.
2056  */
2057  case AKA_SIM_INIT_ID_REQ:
2058  case AKA_SIM_NO_ID_REQ:
2059  case AKA_SIM_ANY_ID_REQ:
2060  RDEBUG2("Previous section returned (%s), clearing reply attributes and "
2061  "requesting additional identity",
2063  fr_pair_list_free(&request->reply_pairs);
2065  return STATE_TRANSITION(common_identity);
2066 
2069  REDEBUG("Last requested Full-Auth-Id or Permanent-Identity, "
2070  "but received a Fast-Auth-Id. Cannot continue");
2072  }
2073  break;
2074 
2075  /*
2076  * Policy rejected the user
2077  */
2078  case RLM_MODULE_REJECT:
2079  case RLM_MODULE_DISALLOW:
2080  reject:
2082 
2083  /*
2084  * Everything OK
2085  */
2086  case RLM_MODULE_OK:
2087  case RLM_MODULE_UPDATED:
2088  reauthenticate:
2089  return CALL_SECTION(send_common_reauthentication_request);
2090  }
2091 
2092  goto reject;
2093 }
2094 
2095 /** Enter the REAUTHENTICATION state
2096  *
2097  */
2099 {
2100  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2101  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2102  fr_pair_t *vp = NULL;
2103 
2105 
2106  /*
2107  * Add the current identity as session_id
2108  * to make it easier to load/store things from
2109  * the cache module.
2110  */
2113 
2114  return CALL_SECTION(load_session);
2115 }
2116 
2117 /** Resume after 'recv Synchronization-Failure { ... }'
2118  *
2119  * - If 'recv Synchronization-Failure { ... }' returned a failure
2120  * rcode, enter the FAILURE-NOTIFICATION state.
2121  * - ...or if no 'recv Synchronization-Failure { ... }' section was
2122  * defined, then enter the FAILURE-NOTIFICATION state.
2123  * - ...or if the user didn't provide a new SQN value in &control.SQN
2124  * then enter the FAILURE-NOTIFICATION state.
2125  * - ...or enter the AKA-CHALLENGE state.
2126  */
2127 RESUME(recv_aka_synchronization_failure)
2128 {
2129  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2130  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2131  fr_pair_t *vp;
2132 
2134 
2135  /*
2136  * If there's no section to handle this, then no resynchronisation
2137  * can't have occurred and we just send a reject.
2138  *
2139  * Similarly, if we've already received one synchronisation failure
2140  * then it's highly likely whatever user configured action was
2141  * configured was unsuccessful, and we should just give up.
2142  */
2143  if (!inst->actions.recv_aka_synchronization_failure || eap_aka_sim_session->prev_recv_sync_failure) {
2144  failure:
2146  }
2147 
2148  /*
2149  * We couldn't generate an SQN and the user didn't provide one,
2150  * so we need to fail.
2151  */
2152  vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_sim_sqn);
2153  if (!vp) {
2154  REDEBUG("No &control.SQN value provided after resynchronisation, cannot continue");
2155  goto failure;
2156  }
2157 
2158  /*
2159  * RFC 4187 Section #6.3.1
2160  *
2161  * "if the peer detects that the
2162  * sequence number in AUTN is not correct, the peer responds with
2163  * EAP-Response/AKA-Synchronization-Failure (Section 9.6), and the
2164  * server proceeds with a new EAP-Request/AKA-Challenge."
2165  */
2167 }
2168 
2169 /** Resume after 'recv Authentication-Reject { ... }'
2170  *
2171  * - Enter the FAILURE-NOTIFICATION state.
2172  */
2173 RESUME(recv_aka_authentication_reject)
2174 {
2176 
2177  /*
2178  * Case 2 where we're allowed to send an EAP-Failure
2179  */
2180  return STATE_TRANSITION(eap_failure);
2181 }
2182 
2183 /** Resume after 'recv Challenge-Response { ... }'
2184  *
2185  * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
2186  * - ...or call a function to process the contents of the AKA-Challenge message.
2187  *
2188  * Verify that MAC, and RES match what we expect.
2189  */
2190 RESUME(recv_aka_challenge_response)
2191 {
2192  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2193  fr_pair_t *vp = NULL;
2194 
2196 
2197  /*
2198  * Validate mac
2199  */
2200  if (mac_validate(request) < 0) {
2201  failure:
2203  }
2204 
2205  /*
2206  * Validate the checkcode
2207  */
2208  if (checkcode_validate(request) < 0) goto failure;
2209 
2210  vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_res);
2211  if (!vp) {
2212  REDEBUG("AT_RES missing from challenge response");
2213  goto failure;
2214  }
2215 
2216  if (vp->vp_length != eap_aka_sim_session->keys.umts.vector.xres_len) {
2217  REDEBUG("Received RES' length (%zu) does not match calculated XRES' length (%zu)",
2218  vp->vp_length, eap_aka_sim_session->keys.umts.vector.xres_len);
2219  goto failure;
2220  }
2221 
2222  if (memcmp(vp->vp_octets, eap_aka_sim_session->keys.umts.vector.xres, vp->vp_length)) {
2223  REDEBUG("Received RES does not match calculated XRES");
2224  RHEXDUMP_INLINE2(vp->vp_octets, vp->vp_length, "RES :");
2225  RHEXDUMP_INLINE2(eap_aka_sim_session->keys.umts.vector.xres,
2226  eap_aka_sim_session->keys.umts.vector.xres_len, "XRES :");
2227  goto failure;
2228  }
2229 
2230  RDEBUG2("Received RES matches calculated XRES");
2231 
2233 
2234  /*
2235  * If the peer wants a Success notification, and
2236  * we included AT_RESULT_IND then send a success
2237  * notification, otherwise send a normal EAP-Success.
2238  *
2239  * RFC 4187 Section #6.2. Result Indications
2240  */
2242  if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2243  RDEBUG("We wanted to use protected result indications, but peer does not");
2245  } else {
2247  }
2248  } else if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2249  RDEBUG("Peer wanted to use protected result indications, but we do not");
2250  }
2251 
2252  return STATE_TRANSITION(eap_success);
2253 }
2254 
2255 /** AKA-CHALLENGE state - Continue the state machine after receiving a response to our EAP-Request/SIM-Challenge
2256  *
2257  * - Continue based on received AT_SUBTYPE value:
2258  * - EAP-Response/AKA-Challenge - call 'recv Challenge-Response { ... }'.
2259  * - EAP-Response/AKA-Authentication-Reject - call 'recv Authentication-Reject { ... }' and after that
2260  * send a EAP-Request/SIM-Notification indicating a General Failure.
2261  * - EAP-Response/AKA-Synchronization-Failure - call 'recv Synchronization-Failure { ... }'.
2262  * - EAP-Response/AKA-Client-Error - call 'recv Client-Error { ... }' and after that
2263  * send a EAP-Request/AKA-Notification indicating a General Failure.
2264  * - Anything else, enter the FAILURE-NOTIFICATION state.
2265  */
2267 {
2268  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2269  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2270  fr_pair_t *subtype_vp = NULL;
2272 
2273  subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
2274  if (!subtype_vp) {
2275  REDEBUG("Missing AT_SUBTYPE");
2276  goto fail;
2277  }
2278 
2279  switch (subtype_vp->vp_uint16) {
2280  case FR_SUBTYPE_VALUE_AKA_CHALLENGE:
2281  return CALL_SECTION(recv_aka_challenge_response);
2282 
2283  /*
2284  * Case 2 where we're allowed to send an EAP-Failure
2285  */
2286  case FR_SUBTYPE_VALUE_AKA_AUTHENTICATION_REJECT:
2288  return CALL_SECTION(recv_aka_authentication_reject);
2289 
2290  case FR_SUBTYPE_VALUE_AKA_SYNCHRONIZATION_FAILURE:
2291  {
2292  uint64_t new_sqn;
2293 
2295 
2296  vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_auts);
2297  if (!vp) {
2298  REDEBUG("EAP-Response/AKA-Synchronisation-Failure missing AT_AUTS");
2299  failure:
2301  }
2302 
2303  switch (fr_aka_sim_umts_resync_from_attrs(&new_sqn,
2304  request, vp, &eap_aka_sim_session->keys)) {
2305  /*
2306  * Add everything back that we'll need in the
2307  * next challenge round.
2308  */
2309  case 0:
2311  vp->vp_uint64 = new_sqn;
2312 
2315  sizeof(eap_aka_sim_session->keys.auc.ki), false);
2316 
2319  sizeof(eap_aka_sim_session->keys.auc.opc), false);
2320  break;
2321 
2322  case 1: /* Don't have Ki or OPc so something else will need to deal with this */
2323  break;
2324 
2325  default:
2326  case -1:
2327  goto failure;
2328  }
2329 
2330  return CALL_SECTION(recv_aka_synchronization_failure);
2331  }
2332 
2333  /*
2334  * Case 1 where we're allowed to send an EAP-Failure
2335  */
2336  case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
2337  client_error_debug(request);
2338 
2340 
2341  return CALL_SECTION(recv_common_client_error);
2342 
2343  /*
2344  * RFC 4187 says we *MUST* notify, not just
2345  * send an EAP-Failure in this case.
2346  */
2347  default:
2348  REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
2349  fail:
2351  goto failure;
2352  }
2353 }
2354 
2355 /** Resume after 'send Challenge-Request { ... }'
2356  *
2357  */
2358 RESUME(send_aka_challenge_request)
2359 {
2360  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2361  fr_pair_t *vp;
2363 
2364  fr_pair_t *kdf_id;
2365 
2367 
2368  /*
2369  * Allow override of KDF Identity
2370  *
2371  * Because certain handset manufacturers don't
2372  * implement RFC 4187 correctly and use the
2373  * wrong identity as input the the PRF/KDF.
2374  */
2375  kdf_id = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_kdf_identity);
2376  if (kdf_id) {
2378  (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
2379  fr_pair_delete_by_da(&request->control_pairs, attr_eap_aka_sim_kdf_identity);
2380  }
2381 
2382  RDEBUG2("Acquiring UMTS vector(s)");
2383 
2385  /*
2386  * Copy the network name the user specified for
2387  * key derivation purposes.
2388  */
2389  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_kdf_input);
2390  if (vp) {
2393  (uint8_t const *)vp->vp_strvalue,
2394  vp->vp_length);
2395  eap_aka_sim_session->keys.network_len = vp->vp_length;
2396  } else {
2397  REDEBUG("No network name available, can't set AT_KDF_INPUT");
2398  failure:
2400  }
2401 
2402  /*
2403  * We don't allow the user to specify
2404  * the KDF currently.
2405  */
2407  vp->vp_uint16 = eap_aka_sim_session->kdf;
2408  }
2409 
2410  /*
2411  * Get vectors from attribute or generate
2412  * them using COMP128-* or Milenage.
2413  */
2414  if (fr_aka_sim_vector_umts_from_attrs(request, &request->control_pairs,
2415  &eap_aka_sim_session->keys, &src) != 0) {
2416  REDEBUG("Failed retrieving UMTS vectors");
2417  goto failure;
2418  }
2419 
2420  /*
2421  * Don't leave the AMF hanging around
2422  */
2424 
2425  /*
2426  * All set, calculate keys!
2427  */
2428  switch (eap_aka_sim_session->type) {
2429  default:
2430  case FR_EAP_METHOD_SIM:
2431  fr_assert(0); /* EAP-SIM has its own Challenge state */
2432  break;
2433 
2434  case FR_EAP_METHOD_AKA:
2436  break;
2437 
2439  switch (eap_aka_sim_session->kdf) {
2440  case FR_KDF_VALUE_PRIME_WITH_CK_PRIME_IK_PRIME:
2442  break;
2443 
2444  default:
2445  fr_assert(0);
2446  break;
2447  }
2448  }
2450 
2451  /*
2452  * Indicate we'd like to use protected success messages
2453  * with AT_RESULT_IND
2454  *
2455  * Use our default, but allow user override too.
2456  */
2457  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind);
2458  if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
2459 
2460  /*
2461  * These attributes are only allowed with
2462  * EAP-AKA', protect users from themselves.
2463  */
2467  }
2468 
2469  /*
2470  * Okay, we got the challenge! Put it into an attribute.
2471  */
2474 
2475  /*
2476  * Send the AUTN value to the client, so it can authenticate
2477  * whoever has knowledge of the Ki.
2478  */
2481 
2482  /*
2483  * need to include an AT_MAC attribute so that it will get
2484  * calculated.
2485  */
2487  fr_pair_value_memdup(vp, NULL, 0, false);
2488 
2489  /*
2490  * We've sent the challenge so the peer should now be able
2491  * to accept encrypted attributes.
2492  */
2494 
2496 }
2497 
2498 /** Enter the AKA-CHALLENGE state
2499  *
2500  */
2502 {
2503  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2504  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2505  fr_pair_t *vp;
2506 
2507  /*
2508  * If we've sent either of these identities it
2509  * means we've come here form a Reauthentication-Request
2510  * that failed.
2511  */
2513  return session_and_pseudonym_clear(p_result, mctx, request,
2514  eap_aka_sim_session, guard_aka_challenge);
2515  /* come back when we're done */
2516  }
2517 
2519 
2520  /*
2521  * Set some default attributes, giving the user a
2522  * chance to modify them.
2523  */
2524  switch (eap_aka_sim_session->type) {
2526  {
2527  uint8_t amf_buff[2] = { 0x80, 0x00 }; /* Set the AMF separation bit high */
2528 
2529  /*
2530  * Toggle the AMF high bit to indicate we're doing AKA'
2531  */
2533  fr_pair_value_memdup(vp, amf_buff, sizeof(amf_buff), false);
2534 
2535  /*
2536  * Use the default network name we have configured
2537  * and send it to the peer.
2538  */
2539  if (inst->network_name &&
2540  !fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_kdf_input)) {
2543  }
2544  }
2545  break;
2546 
2547  default:
2548  break;
2549 
2550  }
2551 
2552  /*
2553  * Set the defaults for protected result indicator
2554  */
2556  !fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2558  vp->vp_bool = true;
2559  }
2560 
2561  return CALL_SECTION(send_aka_challenge_request);
2562 }
2563 
2564 /** Resume after 'recv Challenge-Response { ... }'
2565  *
2566  * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
2567  * - ...or call a function to process the contents of the SIM-Challenge message.
2568  *
2569  * Verify that MAC, and RES match what we expect.
2570  */
2571 RESUME(recv_sim_challenge_response)
2572 {
2573  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2574  uint8_t sres_cat[AKA_SIM_VECTOR_GSM_SRES_SIZE * 3];
2575  uint8_t *p = sres_cat;
2576 
2578 
2579  memcpy(p, eap_aka_sim_session->keys.gsm.vector[0].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
2581  memcpy(p, eap_aka_sim_session->keys.gsm.vector[1].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
2583  memcpy(p, eap_aka_sim_session->keys.gsm.vector[2].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
2584 
2585  /*
2586  * Validate mac
2587  */
2588  if (mac_validate(request) < 0) return STATE_TRANSITION(common_failure_notification);
2589 
2591 
2592  /*
2593  * If the peer wants a Success notification, and
2594  * we included AT_RESULT_IND then send a success
2595  * notification, otherwise send a normal EAP-Success.
2596  */
2598  if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2599  RDEBUG("We wanted to use protected result indications, but peer does not");
2601  } else {
2603  }
2604  } else if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2605  RDEBUG("Peer wanted to use protected result indications, but we do not");
2606  }
2607 
2608  return STATE_TRANSITION(eap_success);
2609 }
2610 
2611 /** SIM-CHALLENGE state - Continue the state machine after receiving a response to our EAP-Request/SIM-Challenge
2612  *
2613  * - Continue based on received AT_SUBTYPE value:
2614  * - EAP-Response/SIM-Challenge - call 'recv Challenge-Response { ... }'.
2615  * - EAP-Response/SIM-Client-Error - call 'recv Client-Error { ... }' and after that
2616  * send a EAP-Request/SIM-Notification indicating a General Failure.
2617  * - Anything else, enter the FAILURE-NOTIFICATION state.
2618  */
2620 {
2621  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2622  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2623  fr_pair_t *subtype_vp = NULL;
2624 
2625  subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
2626  if (!subtype_vp) {
2627  REDEBUG("Missing AT_SUBTYPE");
2628  goto fail;
2629  }
2630 
2631  switch (subtype_vp->vp_uint16) {
2632  case FR_SUBTYPE_VALUE_SIM_CHALLENGE:
2633  return CALL_SECTION(recv_sim_challenge_response);
2634 
2635  /*
2636  * Case 1 where we're allowed to send an EAP-Failure
2637  */
2638  case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
2639  client_error_debug(request);
2640 
2642 
2643  return CALL_SECTION(recv_common_client_error);
2644 
2645  /*
2646  * RFC 4186 says we *MUST* notify, not just
2647  * send an EAP-Failure in this case.
2648  */
2649  default:
2650  REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
2651  fail:
2653 
2655  }
2656 }
2657 
2658 /** Resume after 'send Challenge-Request { ... }'
2659  *
2660  */
2661 RESUME(send_sim_challenge_request)
2662 {
2663  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2664 
2665  fr_pair_t *vp;
2667 
2668  fr_pair_t *kdf_id;
2669 
2671 
2672  /*
2673  * Allow override of KDF Identity
2674  *
2675  * Because certain handset manufacturers don't
2676  * implement RFC 4187 correctly and use the
2677  * wrong identity as input the the PRF/KDF.
2678  */
2679  kdf_id = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_aka_sim_kdf_identity);
2680  if (kdf_id) {
2682  (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
2683  fr_pair_delete_by_da(&request->control_pairs, attr_eap_aka_sim_kdf_identity);
2684  }
2685 
2686  RDEBUG2("Acquiring GSM vector(s)");
2687  if ((fr_aka_sim_vector_gsm_from_attrs(request, &request->control_pairs, 0,
2688  &eap_aka_sim_session->keys, &src) != 0) ||
2689  (fr_aka_sim_vector_gsm_from_attrs(request, &request->control_pairs, 1,
2690  &eap_aka_sim_session->keys, &src) != 0) ||
2691  (fr_aka_sim_vector_gsm_from_attrs(request, &request->control_pairs, 2,
2692  &eap_aka_sim_session->keys, &src) != 0)) {
2693  REDEBUG("Failed retrieving SIM vectors");
2695  }
2696 
2698 
2700 
2701  /*
2702  * Indicate we'd like to use protected success messages
2703  * with AT_RESULT_IND
2704  *
2705  * Use our default, but allow user override too.
2706  */
2707  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind);
2708  if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
2709 
2710  /*
2711  * Okay, we got the challenges! Put them into attributes.
2712  */
2715 
2718 
2721 
2722  /*
2723  * need to include an AT_MAC attribute so that it will get
2724  * calculated.
2725  */
2727  fr_pair_value_memdup(vp, NULL, 0, false);
2728 
2729  /*
2730  * We've sent the challenge so the peer should now be able
2731  * to accept encrypted attributes.
2732  */
2734 
2736 }
2737 
2738 /** Enter the SIM-CHALLENGE state
2739  *
2740  */
2742 {
2743  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2744  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2745  fr_pair_t *vp;
2746 
2747  /*
2748  * If we've sent either of these identities it
2749  * means we've come here form a Reauthentication-Request
2750  * that failed.
2751  */
2753  return session_and_pseudonym_clear(p_result, mctx, request,
2754  eap_aka_sim_session, guard_sim_challenge);
2755  /* come back when we're done */
2756  }
2757 
2759 
2760  /*
2761  * Set the defaults for protected result indicator
2762  */
2764  !fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_result_ind)) {
2766  vp->vp_bool = true;
2767  }
2768 
2769  return CALL_SECTION(send_sim_challenge_request);
2770 }
2771 
2772 /** Enter the SIM-CHALLENGE or AKA-CHALLENGE state
2773  *
2774  * Called by functions which are common to both the EAP-SIM and EAP-AKA state machines
2775  * to enter the correct challenge state.
2776  */
2777 STATE_GUARD(common_challenge)
2778 {
2779  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2780 
2781  switch (eap_aka_sim_session->type) {
2782  case FR_EAP_METHOD_SIM:
2784 
2785  case FR_EAP_METHOD_AKA:
2788 
2789  default:
2790  break;
2791  }
2792 
2793  fr_assert(0);
2795 }
2796 
2797 /** Resume after 'recv Identity-Response { ... }' or 'recv AKA-Identity { ... }'
2798  *
2799  * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
2800  * - ...or call a function to process the contents of the AKA-Identity message, mainly the AT_IDENTITY value.
2801  * - If the message does not contain AT_IDENTITY, then enter the FAILURE-NOTIFICATION state.
2802  * - If the user requested another identity, re-enter the AKA-Identity state.
2803  * - ...or continue based on the value of &Identity-Type which was added by #aka_identity,
2804  * and possibly modified by the user.
2805  * - Fastauth - Enter the REAUTHENTICATION state.
2806  * - Pseudonym - Call 'load pseudonym { ... }'
2807  * - Permanent - Enter the CHALLENGE state.
2808  */
2809 RESUME(recv_aka_identity_response)
2810 {
2811  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2812  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2813 
2814  bool user_set_id_req;
2815  fr_pair_t *identity_type;
2816 
2818 
2819  /*
2820  * See if the user wants us to request another
2821  * identity.
2822  *
2823  * If they set one themselves don't override
2824  * what they set.
2825  */
2826  user_set_id_req = identity_req_set_by_user(request, eap_aka_sim_session);
2827  if ((unlang_interpret_stack_result(request) == RLM_MODULE_NOTFOUND) || user_set_id_req) {
2828  if (!user_set_id_req) {
2829  switch (eap_aka_sim_session->last_id_req) {
2830  case AKA_SIM_ANY_ID_REQ:
2832  break;
2833 
2836  break;
2837 
2838  case AKA_SIM_NO_ID_REQ: /* We always request an ID in AKA-Identity unlike SIM-Start */
2839  case AKA_SIM_INIT_ID_REQ: /* Should not happen */
2840  fr_assert(0);
2841  FALL_THROUGH;
2842 
2844  REDEBUG("Peer sent no usable identities");
2846 
2847  }
2848  RDEBUG2("Previous section returned (%s), requesting next most permissive identity (%s)",
2851  eap_aka_sim_session->id_req, "<INVALID>"));
2852  }
2854  }
2855 
2856  /*
2857  * If the identity looks like a fast re-auth id
2858  * run fast re-auth, otherwise do fullauth.
2859  */
2860  identity_type = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity_type);
2861  if (identity_type) switch (identity_type->vp_uint32) {
2862  case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
2864 
2865  /*
2866  * It's a pseudonym, which now needs resolving.
2867  * The resume function here calls aka_challenge_enter
2868  * if pseudonym resolution went ok.
2869  */
2870  case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
2871  eap_aka_sim_session->next = guard_aka_challenge;
2872  return CALL_SECTION(load_pseudonym);
2873 
2874  default:
2875  break;
2876  }
2877 
2879 }
2880 
2881 /** AKA-IDENTITY state - Continue the state machine after receiving a response to our EAP-Request/AKA-Identity
2882  *
2883  * - Continue based on received AT_SUBTYPE value:
2884  * - EAP-Response/AKA-Identity - call either 'recv Identity-Response { ... }' or if
2885  * provided 'recv AKA-Identity-Response { ... }'. The idea here is that the
2886  * EAP-Identity-Response is really the first round in identity negotiation and
2887  * there's no real value distinguishing between the first round and subsequent
2888  * rounds, but if users do want to run different logic, then give them a way of
2889  * doing that.
2890  * - EAP-Response/AKA-Client-Error - call 'recv Client-Error { ... }' and after that
2891  * send a EAP-Request/SIM-Notification indicating a General Failure.
2892  * - Anything else, enter the FAILURE-NOTIFICATION state.
2893  */
2895 {
2896  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
2897  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
2898  fr_pair_t *subtype_vp = NULL;
2899 
2900  subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
2901  if (!subtype_vp) {
2902  REDEBUG("Missing AT_SUBTYPE");
2903  goto fail;
2904  }
2905 
2906  switch (subtype_vp->vp_uint16) {
2907  /*
2908  * This is the subtype we expect
2909  */
2910  case FR_SUBTYPE_VALUE_AKA_IDENTITY:
2911  {
2912  fr_pair_t *id;
2914 
2915  id = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity);
2916  if (!id) {
2917  /*
2918  * 9.2. EAP-Response/Identity
2919  *
2920  * The peer sends EAP-Response/Identity in response to a valid
2921  * EAP-Request/Identity from the server.
2922  * The peer MUST include the AT_IDENTITY attribute. The usage of
2923  * AT_IDENTITY is defined in Section 4.1.
2924  */
2925  REDEBUG("EAP-Response/Identity does not contain AT_IDENTITY");
2927  }
2928 
2929  /*
2930  * Add ID hint attributes to the request to help
2931  * the user make policy decisions.
2932  */
2933  identity_hint_pairs_add(&type, NULL, request, id->vp_strvalue);
2935  identity_to_permanent_identity(request, id,
2938  }
2939 
2940  /*
2941  * Update cryptographic identity
2942  */
2944  (uint8_t const *)id->vp_strvalue, id->vp_length);
2945 
2946  return unlang_module_yield_to_section(p_result,
2947  request,
2948  inst->actions.recv_aka_identity_response ?
2949  inst->actions.recv_aka_identity_response:
2952  resume_recv_aka_identity_response,
2953  mod_signal,
2954  ~FR_SIGNAL_CANCEL,
2956  }
2957 
2958  /*
2959  * Case 1 where we're allowed to send an EAP-Failure
2960  *
2961  * This can happen in the case of a conservative
2962  * peer, where it refuses to provide the permanent
2963  * identity.
2964  */
2965  case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
2966  client_error_debug(request);
2967 
2968  return CALL_SECTION(recv_common_client_error);
2969 
2970  default:
2971  /*
2972  * RFC 4187 says we *MUST* notify, not just
2973  * send an EAP-Failure in this case.
2974  */
2975  REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
2976  fail:
2978  }
2979 }
2980 
2981 /** Resume after 'send Identity-Request { ... }'
2982  *
2983  * There are three types of user identities that can be implemented
2984  * - Permanent identities such as 0123456789098765@myoperator.com
2985  * Permanent identities can be identified by the leading zero followed by
2986  * by 15 digits (the IMSI number).
2987  * - Ephemeral identities (pseudonyms). These are identities assigned for
2988  * identity privacy so the user can't be tracked. These can identities
2989  * can either be generated as per the 3GPP 'Security aspects of non-3GPP accesses'
2990  * document section 14, where a set of up to 16 encryption keys are used
2991  * to reversibly encrypt the IMSI. Alternatively the pseudonym can be completely
2992  * randomised and stored in a datastore.
2993  * - A fast resumption ID which resolves to data used for fast resumption.
2994  *
2995  * In order to perform full authentication the original IMSI is required for
2996  * forwarding to the HLR. In the case where we can't match/decrypt the pseudonym,
2997  * or can't perform fast resumption, we need to request the full identity from
2998  * the supplicant.
2999  *
3000  */
3001 RESUME(send_aka_identity_request)
3002 {
3003  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3004 
3006 
3007  /*
3008  * Update eap_aka_sim_session->id_req in case the the
3009  * user set attributes in `send Identity-Request { ... }`
3010  * Also removes all existing id_req attributes
3011  * from the reply.
3012  */
3014 
3015  /*
3016  * Select the right type of identity request attribute
3017  *
3018  * Implement checks on identity request order described
3019  * by RFC4187 section #4.1.5.
3020  *
3021  * The internal state machine should always handle this
3022  * correctly, but the user may have other ideas...
3023  */
3024  if (identity_req_pairs_add(request, eap_aka_sim_session) < 0) {
3026  }
3027  eap_aka_sim_session->last_id_req = eap_aka_sim_session->id_req; /* Record what we last requested */
3028 
3029  /*
3030  * Encode the packet
3031  */
3032  common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_IDENTITY);
3033 
3035 }
3036 
3037 /** Enter the AKA-IDENTITY state
3038  *
3039  */
3041 {
3042  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3043  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3044 
3046 
3047  /*
3048  * If we have an send_aka_identity_request section
3049  * then run that, otherwise just run the normal
3050  * identity request section.
3051  */
3052  return unlang_module_yield_to_section(p_result,
3053  request,
3054  inst->actions.send_aka_identity_request ?
3055  inst->actions.send_aka_identity_request:
3058  resume_send_aka_identity_request,
3059  mod_signal,
3060  ~FR_SIGNAL_CANCEL,
3062 }
3063 
3064 /** Resume after 'recv Identity-Response { ... }' or 'recv SIM-Start { ... }'
3065  *
3066  * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
3067  * - ...or call a function to process the contents of the SIM-Start message, mainly the AT_IDENTITY value.
3068  * - If the message does not contain AT_IDENTITY, then enter the FAILURE-NOTIFICATION state.
3069  * - If the user requested another identity, re-enter the SIM-START state.
3070  * - ...or continue based on the value of &Identity-Type which was added by #sim_start,
3071  * and possibly modified by the user.
3072  * - Fastauth
3073  * - If AT_NONCE_MT or AT_SELECTED_VERSION are present, enter the FAILURE-NOTIFICATION state.
3074  * - ...or enter the REAUTHENTICATION state.
3075  * - Pseudonym - Verify selected version and AT_NONCE_MT, then call 'load pseudonym { ... }'
3076  * - Permanent - Verify selected version and AT_NONCE_MT, then enter the CHALLENGE state.
3077  */
3078 RESUME(recv_sim_start_response)
3079 {
3080  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3081  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3082  bool user_set_id_req;
3083  fr_pair_t *identity_type;
3084 
3086 
3087  /*
3088  * See if the user wants us to request another
3089  * identity.
3090  *
3091  * If they set one themselves don't override
3092  * what they set.
3093  */
3094  user_set_id_req = identity_req_set_by_user(request, eap_aka_sim_session);
3095  if ((unlang_interpret_stack_result(request) == RLM_MODULE_NOTFOUND) || user_set_id_req) {
3096  if (!user_set_id_req) {
3097  switch (eap_aka_sim_session->last_id_req) {
3098  case AKA_SIM_NO_ID_REQ: /* Should not happen */
3100  break;
3101 
3102  case AKA_SIM_ANY_ID_REQ:
3104  break;
3105 
3108  break;
3109 
3110  case AKA_SIM_INIT_ID_REQ: /* Should not happen */
3111  fr_assert(0);
3112  FALL_THROUGH;
3113 
3115  REDEBUG("Peer sent no usable identities");
3116  failure:
3118  }
3119  RDEBUG2("Previous section returned (%s), requesting next most permissive identity (%s)",
3122  eap_aka_sim_session->id_req, "<INVALID>"));
3123  }
3124  return STATE_TRANSITION(sim_start);
3125  }
3126 
3127  /*
3128  * If the identity looks like a fast re-auth id
3129  * run fast re-auth, otherwise do fullauth.
3130  */
3131  identity_type = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity_type);
3132  if (identity_type) switch (identity_type->vp_uint32) {
3133  case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
3134  /*
3135  * RFC 4186 Section #9.2
3136  *
3137  * The AT_NONCE_MT attribute MUST NOT be included if the AT_IDENTITY
3138  * with a fast re-authentication identity is present for fast
3139  * re-authentication
3140  */
3141  if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_nonce_mt)) {
3142  REDEBUG("AT_NONCE_MT is not allowed in EAP-Response/SIM-Reauthentication messages");
3144  }
3145 
3146  /*
3147  * RFC 4186 Section #9.2
3148  *
3149  * The AT_SELECTED_VERSION attribute MUST NOT be included if the
3150  * AT_IDENTITY attribute with a fast re-authentication identity is
3151  * present for fast re-authentication.
3152  */
3153  if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_selected_version)) {
3154  REDEBUG("AT_SELECTED_VERSION is not allowed in EAP-Response/SIM-Reauthentication messages");
3156  }
3157 
3159 
3160  /*
3161  * It's a pseudonym, which now needs resolving.
3162  * The resume function here calls aka_challenge_enter
3163  * if pseudonym resolution went ok.
3164  */
3165  case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
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  eap_aka_sim_session->next = guard_sim_challenge;
3170  return CALL_SECTION(load_pseudonym);
3171 
3172  /*
3173  * If it's a permanent ID, copy it over to
3174  * the session state list for use in the
3175  * store pseudonym/store session sections
3176  * later.
3177  */
3178  case FR_IDENTITY_TYPE_VALUE_PERMANENT:
3179  if (sim_start_selected_version_check(request, eap_aka_sim_session) < 0) goto failure;
3180  if (sim_start_nonce_mt_check(request, eap_aka_sim_session) < 0) goto failure;
3181 
3182  FALL_THROUGH;
3183  default:
3184  break;
3185  }
3186 
3188 }
3189 
3190 /** SIM-START state - Continue the state machine after receiving a response to our EAP-Request/SIM-Start
3191  *
3192  * - Continue based on received AT_SUBTYPE value:
3193  * - EAP-Response/SIM-Start - call either 'recv Identity-Response { ... }' or if
3194  * provided 'recv SIM-Start-Response { ... }'. The idea here is that the
3195  * EAP-Identity-Response is really the first round in identity negotiation and
3196  * there's no real value distinguishing between the first round and subsequent
3197  * rounds, but if users do want to run different logic, then give them a way of
3198  * doing that.
3199  * - EAP-Response/SIM-Client-Error - call 'recv Client-Error { ... }' and after that
3200  * send a EAP-Request/SIM-Notification indicating a General Failure.
3201  * - Anything else, enter the FAILURE-NOTIFICATION state.
3202  */
3204 {
3205  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3206  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3207  fr_pair_t *subtype_vp = NULL;
3208 
3209  subtype_vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_subtype);
3210  if (!subtype_vp) {
3211  REDEBUG("Missing AT_SUBTYPE");
3212  goto fail;
3213  }
3214  switch (subtype_vp->vp_uint16) {
3215  case FR_SUBTYPE_VALUE_SIM_START:
3216  {
3217  eap_session_t *eap_session = eap_session_get(request->parent);
3218  fr_pair_t *id;
3220 
3221  id = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity);
3222  if (!id && (eap_aka_sim_session->id_req != AKA_SIM_NO_ID_REQ)) {
3223  /*
3224  * RFC 4186 Section #9.2
3225  *
3226  * The peer sends EAP-Response/SIM/Start in response to a valid
3227  * EAP-Request/SIM/Start from the server.
3228  *
3229  * If and only if the server's EAP-Request/SIM/Start includes one of the
3230  * identity-requesting attributes, then the peer MUST include the
3231  * AT_IDENTITY attribute. The usage of AT_IDENTITY is defined in
3232  * Section 4.2.
3233  * The peer MUST include the AT_IDENTITY attribute. The usage of
3234  * AT_IDENTITY is defined in Section 4.1.
3235  */
3236  REDEBUG("EAP-Response/SIM/Start does not contain AT_IDENTITY");
3238  }
3239 
3240  /*
3241  * Add ID hint attributes to the request to help
3242  * the user make policy decisions.
3243  */
3244  if (id) {
3245  identity_hint_pairs_add(&type, NULL, request, id->vp_strvalue);
3247  identity_to_permanent_identity(request, id,
3250  }
3251 
3252  /*
3253  * Update cryptographic identity
3254  *
3255  * We only do this if we received a new identity.
3256  */
3258  (uint8_t const *)id->vp_strvalue, id->vp_length);
3259  /*
3260  * If there's no additional identity provided, just
3261  * use eap_session->identity again...
3262  */
3263  } else {
3264  /*
3265  * Copy the EAP-Identity into our Identity
3266  * attribute to make policies easier.
3267  */
3269  fr_pair_value_bstrdup_buffer(id, eap_session->identity, true);
3270 
3271  /*
3272  * Add ID hint attributes to the request to help
3273  * the user make policy decisions.
3274  */
3275  identity_hint_pairs_add(&type, NULL, request, eap_session->identity);
3276 
3278  identity_to_permanent_identity(request, id,
3281  }
3282  }
3283 
3284  return unlang_module_yield_to_section(p_result,
3285  request,
3286  inst->actions.recv_sim_start_response?
3287  inst->actions.recv_sim_start_response:
3290  resume_recv_sim_start_response,
3291  mod_signal,
3292  ~FR_SIGNAL_CANCEL,
3294  }
3295 
3296  /*
3297  * Case 1 where we're allowed to send an EAP-Failure
3298  *
3299  * This can happen in the case of a conservative
3300  * peer, where it refuses to provide the permanent
3301  * identity.
3302  */
3303  case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
3304  client_error_debug(request);
3305 
3306  return CALL_SECTION(recv_common_client_error);
3307 
3308  default:
3309  /*
3310  * RFC 4187 says we *MUST* notify, not just
3311  * send an EAP-Failure in this case.
3312  */
3313  REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
3314  fail:
3316  }
3317 }
3318 
3319 /** Resume after 'send Start { ... }'
3320  *
3321  * Send a EAP-Request/SIM-Start message to the supplicant
3322  *
3323  * There are three types of user identities that can be implemented
3324  * - Permanent identities such as 0123456789098765@myoperator.com
3325  * Permanent identities can be identified by the leading zero followed by
3326  * by 15 digits (the IMSI number).
3327  * - Ephemeral identities (pseudonyms). These are identities assigned for
3328  * identity privacy so the user can't be tracked. These can identities
3329  * can either be generated as per the 3GPP 'Security aspects of non-3GPP accesses'
3330  * document section 14, where a set of up to 16 encryption keys are used
3331  * to reversibly encrypt the IMSI. Alternatively the pseudonym can be completely
3332  * randomised and stored in a datastore.
3333  * - A fast resumption ID which resolves to data used for fast resumption.
3334  *
3335  * In order to perform full authentication the original IMSI is required for
3336  * forwarding to the HLR. In the case where we can't match/decrypt the pseudonym,
3337  * or can't perform fast resumption, we need to request the full identity from
3338  * the supplicant.
3339  */
3340 RESUME(send_sim_start)
3341 {
3342  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3343  fr_pair_t *vp;
3344  uint8_t *p, *end;
3345 
3347 
3348  p = eap_aka_sim_session->keys.gsm.version_list;
3349  end = p + sizeof(eap_aka_sim_session->keys.gsm.version_list);
3350  eap_aka_sim_session->keys.gsm.version_list_len = 0;
3351 
3352  /*
3353  * If the user provided no versions, then
3354  * just add the default (1).
3355  */
3356  if (!(fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_aka_sim_version_list))) {
3358  vp->vp_uint16 = EAP_SIM_VERSION;
3359  }
3360 
3361  /*
3362  * Iterate over the the versions adding them
3363  * to the version list we use for keying.
3364  */
3365  for (vp = fr_pair_list_head(&request->reply_pairs);
3366  vp;
3367  vp = fr_pair_list_next(&request->reply_pairs, vp)) {
3368  if (vp->da != attr_eap_aka_sim_version_list) continue;
3369 
3370  if ((end - p) < 2) break;
3371 
3372  /*
3373  * Store as big endian
3374  */
3375  *p++ = (vp->vp_uint16 & 0xff00) >> 8;
3376  *p++ = (vp->vp_uint16 & 0x00ff);
3377  eap_aka_sim_session->keys.gsm.version_list_len += sizeof(uint16_t);
3378  }
3379 
3380  /*
3381  * Update eap_aka_sim_session->id_req in case the the
3382  * user set attributes in `send Identity-Request { ... }`
3383  * Also removes all existing id_req attributes
3384  * from the reply.
3385  */
3387 
3388  /*
3389  * Select the right type of identity request attribute
3390  *
3391  * Implement checks on identity request order described
3392  * by RFC4186 section #4.2.5.
3393  *
3394  * The internal state machine should always handle this
3395  * correctly, but the user may have other ideas...
3396  */
3397  if (identity_req_pairs_add(request, eap_aka_sim_session) < 0) {
3399  }
3400  eap_aka_sim_session->last_id_req = eap_aka_sim_session->id_req; /* Record what we last requested */
3401 
3402  common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_SIM_START);
3403 
3405 }
3406 
3407 /** Enter the SIM-START state
3408  *
3409  */
3411 {
3412  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3413  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3414 
3416 
3417  return unlang_module_yield_to_section(p_result,
3418  request,
3419  inst->actions.send_sim_start_request ?
3420  inst->actions.send_sim_start_request:
3423  resume_send_sim_start,
3424  mod_signal,
3425  ~FR_SIGNAL_CANCEL,
3427 }
3428 
3429 /** Enter the SIM-START or AKA-IDENTITY state
3430  *
3431  * Called by functions which are common to both the EAP-SIM and EAP-AKA state machines
3432  * to enter the correct Identity-Request state.
3433  */
3434 STATE_GUARD(common_identity)
3435 {
3436  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3437 
3438  switch (eap_aka_sim_session->type) {
3439  case FR_EAP_METHOD_SIM:
3440  return STATE_TRANSITION(sim_start);
3441 
3442  case FR_EAP_METHOD_AKA:
3445 
3446  default:
3447  break;
3448  }
3449 
3450  fr_assert(0);
3452 }
3453 
3454 /** Resume after 'recv Identity-Response { ... }'
3455  *
3456  * - Perform the majority of eap_aka_sim_session_t initialisation.
3457  * - If 'recv Identity-Response { ... }' returned a failure rcode, enter the FAILURE-NOTIFICATION state.
3458  * - ...or continue based on the identity hint byte in the AT_IDENTITY value or EAP-Identity-Response value:
3459  * - If identity is a pseudonym, call load pseudonym { ... }.
3460  * - If identity is a fastauth identity, enter the REAUTHENTICATE state.
3461  * - If identity is a permanent identity, enter the CHALLENGE state.
3462  */
3463 RESUME(recv_common_identity_response)
3464 {
3465  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3466  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3467  fr_pair_t *eap_type, *method, *identity_type;
3468  fr_aka_sim_method_hint_t running, hinted;
3469 
3471 
3472  /*
3473  * Ignore attempts to change the EAP-Type
3474  * This must be done before we enter
3475  * the submodule.
3476  */
3477  eap_type = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_type);
3478  if (eap_type) RWDEBUG("Ignoring &control.EAP-Type, this must be set *before* the EAP module is called");
3479 
3480  method = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_method_hint);
3481 
3482  /*
3483  * Set default configuration, we may allow these
3484  * to be toggled by attributes later.
3485  */
3487  eap_aka_sim_session->id_req = AKA_SIM_NO_ID_REQ; /* Set the default */
3488 
3489  /*
3490  * Unless AKA-Prime is explicitly disabled,
3491  * use it... It has stronger keying, and
3492  * binds authentication to the network.
3493  */
3494  switch (eap_aka_sim_session->type) {
3495  case FR_EAP_METHOD_SIM:
3496  RDEBUG2("New EAP-SIM session");
3497 
3498  running = AKA_SIM_METHOD_HINT_SIM;
3499 
3501  eap_aka_sim_session->mac_md = EVP_sha1();
3502  break;
3503 
3504  case FR_EAP_METHOD_AKA:
3505  RDEBUG2("New EAP-AKA session");
3506 
3507  running = AKA_SIM_METHOD_HINT_AKA;
3508 
3510  eap_aka_sim_session->mac_md = EVP_sha1();
3511  break;
3512 
3514  RDEBUG2("New EAP-AKA' session");
3515 
3517 
3519  eap_aka_sim_session->kdf = FR_KDF_VALUE_PRIME_WITH_CK_PRIME_IK_PRIME;
3520  eap_aka_sim_session->mac_md = EVP_sha256();
3521  break;
3522 
3523  default:
3524  fr_assert(0);
3526  }
3527 
3528  /*
3529  * Warn the user if the selected identity
3530  * does not match what's hinted.
3531  */
3532  if (method) {
3533  switch (method->vp_uint32) {
3534  case FR_METHOD_HINT_VALUE_AKA_PRIME:
3536  break;
3537 
3538  case FR_METHOD_HINT_VALUE_AKA:
3539  hinted = AKA_SIM_METHOD_HINT_AKA;
3540  break;
3541 
3542  case FR_METHOD_HINT_VALUE_SIM:
3543  hinted = AKA_SIM_METHOD_HINT_SIM;
3544  break;
3545 
3546  default:
3547  hinted = running;
3548  break;
3549  }
3550 
3551  if (hinted != running) {
3552  RWDEBUG("EAP-Identity hints that EAP-%s should be started, but we're attempting EAP-%s",
3553  fr_table_str_by_value(fr_aka_sim_id_method_table, hinted, "<INVALID>"),
3554  fr_table_str_by_value(fr_aka_sim_id_method_table, running, "<INVALID>"));
3555  }
3556  }
3557 
3558  /*
3559  * Unless the user has told us otherwise We always
3560  * start by requesting any ID initially as we can
3561  * always negotiate down.
3562  */
3566  RDEBUG2("Previous section returned (%s), requesting additional identity (%s)",
3569  eap_aka_sim_session->id_req, "<INVALID>"));
3570  } else if (inst->request_identity != AKA_SIM_NO_ID_REQ) {
3572  RDEBUG2("Requesting additional identity (%s)",
3574  eap_aka_sim_session->id_req, "<INVALID>"));
3575  }
3576  }
3577 
3578  /*
3579  * For EAP-SIM we _always_ start with a SIM-Start
3580  * for "version negotiation" even if we don't need
3581  * another identity.
3582  */
3584 
3585  /*
3586  * User may want us to always request an identity
3587  * initially. The RFCs says this is also the
3588  * better way to operate, as the supplicant
3589  * can 'decorate' the identity in the identity
3590  * response.
3591  *
3592  * For EAP-AKA/EAP-AKA' unless we've been configured
3593  * to always request the identity or it was set
3594  * dynamically, we can save a round of EAP and just
3595  * jump straight into the challenge.
3596  */
3597  if (eap_aka_sim_session->id_req != AKA_SIM_NO_ID_REQ) return STATE_TRANSITION(common_identity);
3598 
3599  /*
3600  * If the identity looks like a fast re-auth id
3601  * run fast re-auth, otherwise do a fullauth.
3602  */
3603  identity_type = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_aka_sim_identity_type);
3604  if (identity_type) switch (identity_type->vp_uint32) {
3605  case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
3607 
3608  /*
3609  * It's a pseudonym, which now needs resolving.
3610  * The resume function here calls aka_challenge_enter
3611  * if pseudonym resolution went ok.
3612  */
3613  case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
3614  eap_aka_sim_session->next = guard_common_challenge;
3615  return CALL_SECTION(load_pseudonym);
3616 
3617  case FR_IDENTITY_TYPE_VALUE_PERMANENT:
3618  default:
3619  break;
3620  }
3621 
3622  return STATE_TRANSITION(common_challenge);
3623 }
3624 
3625 /** Enter the EAP-IDENTITY state
3626  *
3627  * - Process the incoming EAP-Identity-Response
3628  * - Start EAP-SIM/EAP-AKA/EAP-AKA' state machine optionally calling 'recv Identity-Response { ... }'
3629  */
3630 STATE(init)
3631 {
3632  eap_session_t *eap_session = eap_session_get(request->parent);
3633  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3634  eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(mctx->rctx, eap_aka_sim_session_t);
3635  fr_pair_t *vp;
3637 
3638  /*
3639  * Verify we received an EAP-Response/Identity
3640  * message before the supplicant started sending
3641  * EAP-SIM/AKA/AKA' packets.
3642  */
3643  if (!eap_session->identity) {
3644  REDEBUG("All SIM or AKA exchanges must begin with a EAP-Response/Identity message");
3646  }
3647 
3648  /*
3649  * Copy the EAP-Identity into our Identity
3650  * attribute to make policies easier.
3651  */
3654 
3655  /*
3656  * Add ID hint attributes to the request to help
3657  * the user make policy decisions.
3658  */
3659  identity_hint_pairs_add(&type, NULL, request, eap_session->identity);
3661  identity_to_permanent_identity(request, vp, eap_session->type,
3663  }
3664 
3665  /*
3666  * Set the initial crypto identity from
3667  * the EAP-Identity-Response
3668  */
3670  (uint8_t const *)eap_session->identity,
3671  talloc_array_length(eap_session->identity) - 1);
3672 
3673  return CALL_SECTION(recv_common_identity_response);
3674 }
3675 
3676 /** Zero out the eap_aka_sim_session when we free it to clear knowledge of secret keys
3677  *
3678  * @param[in] eap_aka_sim_session to free.
3679  * @return 0
3680  */
3682 {
3683  memset(eap_aka_sim_session, 0, sizeof(*eap_aka_sim_session));
3684  return 0;
3685 }
3686 
3687 /** Resumes the state machine when receiving a new response packet
3688  *
3689  */
3691 {
3692  eap_aka_sim_process_conf_t *inst = talloc_get_type_abort(mctx->mi->data, eap_aka_sim_process_conf_t);
3695  0);
3696  module_ctx_t our_mctx = *mctx;
3697 
3698  /*
3699  * A new EAP-SIM/AKA/AKA' session!
3700  */
3701  if (!eap_aka_sim_session) {
3702 
3703  /*
3704  * Must be allocated in the NULL ctx as this will
3705  * need to persist over multiple rounds of EAP.
3706  */
3707  MEM(eap_aka_sim_session = talloc_zero(NULL, eap_aka_sim_session_t));
3708  talloc_set_destructor(eap_aka_sim_session, _eap_aka_sim_session_free);
3709 
3710  /*
3711  * Add new session data to the request
3712  * We only ever need to do this once as it's restored
3713  * during the next round of EAP automatically.
3714  *
3715  * It will also be freed automatically if the request
3716  * is freed and persistable data hasn't been moved
3717  * into the parent.
3718  */
3720  eap_aka_sim_session, true, true, true) < 0)) {
3721  RPEDEBUG("Failed creating new EAP-SIM/AKA/AKA' session");
3723  }
3725 
3726  our_mctx.rctx = eap_aka_sim_session;
3727 
3728  return state_init(p_result, &our_mctx, request);
3729  }
3730 
3731  /*
3732  * This function is called without a resume ctx as it's the
3733  * entry point for each new round of EAP-AKA.
3734  */
3735  our_mctx.rctx = eap_aka_sim_session;
3736 
3738 
3739  return eap_aka_sim_session->state(p_result, &our_mctx, request);
3740 }
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:444
#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:378
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#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:1631
static fr_slen_t in
Definition: dict.h:645
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:1280
void unlang_interpret_stack_result_set(request_t *request, rlm_rcode_t rcode)
Overwrite the current stack rcode.
Definition: interpret.c:1292
HIDDEN fr_dict_attr_t const * attr_ms_mppe_send_key
Definition: base.c:94
HIDDEN fr_dict_attr_t const * attr_ms_mppe_recv_key
Definition: base.c:95
HIDDEN fr_dict_attr_t const * attr_eap_type
Definition: base.c:86
void eap_add_reply(request_t *request, fr_dict_attr_t const *da, uint8_t const *value, int len)
Definition: base.c:375
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_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:688
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:2978
int fr_pair_cmp(fr_pair_t const *a, fr_pair_t const *b)
Compare two pairs, using the operator from "a".
Definition: pair.c:1966
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1340
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:1684
fr_pair_t * fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition: pair.c:1819
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:2781
int fr_pair_value_copy(fr_pair_t *dst, fr_pair_t *src)
Copy the value from one pair to another.
Definition: pair.c:2560
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:765
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:234
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:70
#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:516
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:253
An element in an arbitrarily ordered array of name to ptr mappings.
Definition: table.h:69
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
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:4157
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:4202
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:4417
#define fr_box_strvalue_len(_val, _len)
Definition: value.h:279
int nonnull(2, 5))