]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Allow SIM-Start packets without identity requests
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 11 Feb 2022 17:47:07 +0000 (12:47 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 11 Feb 2022 17:47:07 +0000 (12:47 -0500)
Unsure why/when this would be useful, but it's needed for completeness.

src/lib/eap_aka_sim/id.c
src/lib/eap_aka_sim/id.h
src/lib/eap_aka_sim/state_machine.c
src/process/eap_aka/base.c
src/process/eap_aka_prime/base.c
src/process/eap_sim/base.c

index 25875fa22e14fc868d56e23144f17213ecc9f8b9..3e4cf32598e87342155ca611e4aed39b4a7fced8 100644 (file)
 fr_table_num_sorted_t const fr_aka_sim_id_request_table[] = {
        { L("Any-Id-Req"),              AKA_SIM_ANY_ID_REQ              },
        { L("FullAuth-Id-Req"),         AKA_SIM_FULLAUTH_ID_REQ         },
+       { L("Init"),                    AKA_SIM_INIT_ID_REQ             },
+       { L("Permanent-Id-Req"),        AKA_SIM_PERMANENT_ID_REQ        },
        { L("no"),                      AKA_SIM_NO_ID_REQ               },      /* Used for config parsing */
        { L("none"),                    AKA_SIM_NO_ID_REQ               },
-       { L("Permanent-Id-Req"),        AKA_SIM_PERMANENT_ID_REQ        },
 };
 size_t fr_aka_sim_id_request_table_len = NUM_ELEMENTS(fr_aka_sim_id_request_table);
 
 fr_table_num_sorted_t const fr_aka_sim_id_method_table[] = {
-       { L("AKA'"),                    AKA_SIM_METHOD_HINT_AKA_PRIME   },
        { L("AKA"),                     AKA_SIM_METHOD_HINT_AKA         },
+       { L("AKA'"),                    AKA_SIM_METHOD_HINT_AKA_PRIME   },
        { L("SIM"),                     AKA_SIM_METHOD_HINT_SIM         },
 };
 size_t fr_aka_sim_id_method_table_len = NUM_ELEMENTS(fr_aka_sim_id_method_table);
index 3756c76bd5a1f1847a897ebf1b7dbad2db12febe..f9f605e5f6df0a7d6572ef9d9bd6a186a6001c7a 100644 (file)
@@ -75,7 +75,8 @@ typedef enum {
 /** Identity request types
  */
 typedef enum {
-       AKA_SIM_NO_ID_REQ = 0,                  //!< We're not requesting any ID.
+       AKA_SIM_INIT_ID_REQ = 0,                //!< We've requested no ID.  This is used for last_id_req.
+       AKA_SIM_NO_ID_REQ,                      //!< We're not requesting any ID.
        AKA_SIM_ANY_ID_REQ,                     //!< Request IMSI, Pseudonym or Fast-reauth.
        AKA_SIM_FULLAUTH_ID_REQ,                //!< Request IMSI or Pseudonym.
        AKA_SIM_PERMANENT_ID_REQ,               //!< Request IMSI.
index b2201448aa048f0e974aef2bd368c42af5f39505..a3906e44138c05f276da5777663d5b6ca7905434 100644 (file)
@@ -351,8 +351,23 @@ static int identity_req_pairs_add(request_t *request, eap_aka_sim_session_t *eap
        fr_pair_t *vp;
 
        switch (eap_aka_sim_session->id_req) {
-       case AKA_SIM_ANY_ID_REQ:
-               if (eap_aka_sim_session->last_id_req != AKA_SIM_NO_ID_REQ) {
+       /*
+        *      This is allowed for EAP-SIM.
+        *
+        *      The EAP-SIM-Start packet gets used both for "version negotiation" and
+        *      for request identities, so for EAP-SIM it's perfectly acceptable
+        *      to send four Sim-Start packets:
+        *
+        *      - No ID
+        *      - Any ID
+        *      - Fullauth ID
+        *      - Permanent ID
+        *
+        *      We need to represent the starting state as separate from no id req,
+        *      so that we can catch potential loops in the identity statate machine
+        */
+       case AKA_SIM_NO_ID_REQ:
+               if (eap_aka_sim_session->last_id_req != AKA_SIM_INIT_ID_REQ) {
                id_out_of_order:
                        REDEBUG("Cannot send %s, already sent %s",
                                fr_table_str_by_value(fr_aka_sim_id_request_table,
@@ -361,12 +376,24 @@ static int identity_req_pairs_add(request_t *request, eap_aka_sim_session_t *eap
                                                      eap_aka_sim_session->last_id_req, "<INVALID>"));
                        return -1;
                }
+               break;
+
+       case AKA_SIM_ANY_ID_REQ:
+               switch (eap_aka_sim_session->last_id_req) {
+               case AKA_SIM_INIT_ID_REQ:
+               case AKA_SIM_NO_ID_REQ:
+                       break;
+
+               default:
+                       goto id_out_of_order;
+               }
                MEM(pair_append_reply(&vp, attr_eap_aka_sim_any_id_req) >= 0);
                vp->vp_bool = true;
                break;
 
        case AKA_SIM_FULLAUTH_ID_REQ:
                switch (eap_aka_sim_session->last_id_req) {
+               case AKA_SIM_INIT_ID_REQ:
                case AKA_SIM_NO_ID_REQ:         /* Not sent anything before */
                case AKA_SIM_ANY_ID_REQ:        /* Last request was for any ID, but the re-auth ID was bad */
                        break;
@@ -380,6 +407,7 @@ static int identity_req_pairs_add(request_t *request, eap_aka_sim_session_t *eap
 
        case AKA_SIM_PERMANENT_ID_REQ:
                switch (eap_aka_sim_session->last_id_req) {
+               case AKA_SIM_INIT_ID_REQ:
                case AKA_SIM_NO_ID_REQ:         /* Not sent anything before */
                case AKA_SIM_ANY_ID_REQ:        /* Last request was for any ID, but the re-auth ID was bad */
                case AKA_SIM_FULLAUTH_ID_REQ:   /* ...didn't understand the pseudonym either */
@@ -1792,6 +1820,7 @@ static unlang_action_t common_reauthentication_request_compose(rlm_rcode_t *p_re
                         *      If this is the *true* reauth ID, then
                         *      there's no point in setting AKA_SIM_ANY_ID_REQ.
                         */
+                       case AKA_SIM_INIT_ID_REQ:
                        case AKA_SIM_NO_ID_REQ:
                        case AKA_SIM_ANY_ID_REQ:
                                RDEBUG2("Composing EAP-Request/Reauthentication failed.  Clearing reply attributes and "
@@ -1897,6 +1926,7 @@ RESUME(send_common_reauthentication_request)
                 *      If this is the *true* reauth ID, then
                 *      there's no point in setting AKA_SIM_ANY_ID_REQ.
                 */
+               case AKA_SIM_INIT_ID_REQ:
                case AKA_SIM_NO_ID_REQ:
                case AKA_SIM_ANY_ID_REQ:
                        RDEBUG2("Previous section returned (%s), clearing reply attributes and "
@@ -1961,6 +1991,7 @@ RESUME(load_pseudonym)
         */
        default:
                switch (eap_aka_sim_session->last_id_req) {
+               case AKA_SIM_INIT_ID_REQ:
                case AKA_SIM_NO_ID_REQ:
                case AKA_SIM_ANY_ID_REQ:
                case AKA_SIM_FULLAUTH_ID_REQ:
@@ -2024,6 +2055,7 @@ RESUME(load_session)
                 *      If this is the *true* reauth ID, then
                 *      there's no point in setting AKA_SIM_ANY_ID_REQ.
                 */
+               case AKA_SIM_INIT_ID_REQ:
                case AKA_SIM_NO_ID_REQ:
                case AKA_SIM_ANY_ID_REQ:
                        RDEBUG2("Previous section returned (%s), clearing reply attributes and "
@@ -2804,7 +2836,8 @@ RESUME(recv_aka_identity_response)
                                eap_aka_sim_session->id_req = AKA_SIM_PERMANENT_ID_REQ;
                                break;
 
-                       case AKA_SIM_NO_ID_REQ: /* Should not happen */
+                       case AKA_SIM_NO_ID_REQ:         /* We always request an ID in AKA-Identity unlike SIM-Start */
+                       case AKA_SIM_INIT_ID_REQ:       /* Should not happen */
                                fr_assert(0);
                                FALL_THROUGH;
 
@@ -3061,6 +3094,10 @@ RESUME(recv_sim_start_response)
        if ((unlang_interpret_stack_result(request) == RLM_MODULE_NOTFOUND) || user_set_id_req) {
                if (!user_set_id_req) {
                        switch (eap_aka_sim_session->last_id_req) {
+                       case AKA_SIM_NO_ID_REQ: /* Should not happen */
+                               eap_aka_sim_session->id_req = AKA_SIM_ANY_ID_REQ;
+                               break;
+
                        case AKA_SIM_ANY_ID_REQ:
                                eap_aka_sim_session->id_req = AKA_SIM_FULLAUTH_ID_REQ;
                                break;
@@ -3069,7 +3106,7 @@ RESUME(recv_sim_start_response)
                                eap_aka_sim_session->id_req = AKA_SIM_PERMANENT_ID_REQ;
                                break;
 
-                       case AKA_SIM_NO_ID_REQ: /* Should not happen */
+                       case AKA_SIM_INIT_ID_REQ:       /* Should not happen */
                                fr_assert(0);
                                FALL_THROUGH;
 
@@ -3176,16 +3213,22 @@ STATE(sim_start)
        switch (subtype_vp->vp_uint16) {
        case FR_SUBTYPE_VALUE_SIM_START:
        {
+               eap_session_t           *eap_session = eap_session_get(request->parent);
                fr_pair_t               *id;
                fr_aka_sim_id_type_t    type;
 
                id = fr_pair_find_by_da_idx(&request->request_pairs, attr_eap_aka_sim_identity, 0);
-               if (!id) {
+               if (!id && (eap_aka_sim_session->id_req != AKA_SIM_NO_ID_REQ)) {
                        /*
                         *  RFC 4186 Section #9.2
                         *
                         *  The peer sends EAP-Response/SIM/Start in response to a valid
                         *  EAP-Request/SIM/Start from the server.
+                        *
+                        *  If and only if the server's EAP-Request/SIM/Start includes one of the
+                        *  identity-requesting attributes, then the peer MUST include the
+                        *  AT_IDENTITY attribute.  The usage of AT_IDENTITY is defined in
+                        *  Section 4.2.
                         *  The peer MUST include the AT_IDENTITY attribute.  The usage of
                         *  AT_IDENTITY is defined in Section 4.1.
                         */
@@ -3197,18 +3240,45 @@ STATE(sim_start)
                 *      Add ID hint attributes to the request to help
                 *      the user make policy decisions.
                 */
-               identity_hint_pairs_add(&type, NULL, request, id->vp_strvalue);
-               if (type == AKA_SIM_ID_TYPE_PERMANENT) {
-                       identity_to_permanent_identity(request, id,
-                                                      eap_aka_sim_session->type,
-                                                      inst->strip_permanent_identity_hint);
-               }
+               if (id) {
+                       identity_hint_pairs_add(&type, NULL, request, id->vp_strvalue);
+                       if (type == AKA_SIM_ID_TYPE_PERMANENT) {
+                               identity_to_permanent_identity(request, id,
+                                                              eap_aka_sim_session->type,
+                                                              inst->strip_permanent_identity_hint);
+                       }
 
+                       /*
+                        *      Update cryptographic identity
+                        *
+                        *      We only do this if we received a new identity.
+                        */
+                       crypto_identity_set(request, eap_aka_sim_session,
+                                           (uint8_t const *)id->vp_strvalue, id->vp_length);
                /*
-                *      Update cryptographic identity
+                *      If there's no additional identity provided, just
+                *      use eap_session->identity again...
                 */
-               crypto_identity_set(request, eap_aka_sim_session,
-                                   (uint8_t const *)id->vp_strvalue, id->vp_length);
+               } else {
+                       /*
+                        *      Copy the EAP-Identity into our Identity
+                        *      attribute to make policies easier.
+                        */
+                       MEM(pair_append_request(&id, attr_eap_aka_sim_identity) >= 0);
+                       fr_pair_value_bstrdup_buffer(id, eap_session->identity, true);
+
+                       /*
+                        *      Add ID hint attributes to the request to help
+                        *      the user make policy decisions.
+                        */
+                       identity_hint_pairs_add(&type, NULL, request, eap_session->identity);
+
+                       if (type == AKA_SIM_ID_TYPE_PERMANENT) {
+                               identity_to_permanent_identity(request, id,
+                                                              eap_aka_sim_session->type,
+                                                              inst->strip_permanent_identity_hint);
+                       }
+               }
 
                return unlang_module_yield_to_section(p_result,
                                                      request,
@@ -3503,13 +3573,11 @@ RESUME(recv_common_identity_response)
        }
 
        /*
-        *      For EAP-SIM we _always_ request an identity
-        *      because the state machine requires us to send
-        *      an EAP-SIM-START packet.  EAP-AKA and EAP-AKA'
-        *      don't have this requirement.
+        *      For EAP-SIM we _always_ start with a SIM-Start
+        *      for "version negotiation" even if we don't need
+        *      another identity.
         */
-       if ((eap_aka_sim_session->type == FR_EAP_METHOD_SIM) &&
-           (eap_aka_sim_session->id_req == AKA_SIM_NO_ID_REQ)) eap_aka_sim_session->id_req = AKA_SIM_ANY_ID_REQ;
+       if (eap_aka_sim_session->type == FR_EAP_METHOD_SIM) return STATE_TRANSITION(sim_start);
 
        /*
         *      User may want us to always request an identity
index 0b557eef7416ea6322ce77fdf94ab17eb0170f15..1a4831bc3268ff01ccf801d4b7f945adbcfc6490 100644 (file)
@@ -238,6 +238,12 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
 
        inst->type = FR_EAP_METHOD_AKA;
 
+       /*
+        *      This isn't allowed, so just munge
+        *      it to no id request.
+        */
+       if (inst->request_identity == AKA_SIM_INIT_ID_REQ) inst->request_identity = AKA_SIM_NO_ID_REQ;
+
        return 0;
 }
 
index 2ae6ced4c0c20a3d5f2311762a7a263d7b42c24f..d80c344c632caa9407b9240bf51f43288d1537cb 100644 (file)
@@ -239,6 +239,12 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
 
        inst->type = FR_EAP_METHOD_AKA_PRIME;
 
+       /*
+        *      This isn't allowed, so just munge
+        *      it to no id request.
+        */
+       if (inst->request_identity == AKA_SIM_INIT_ID_REQ) inst->request_identity = AKA_SIM_NO_ID_REQ;
+
        return 0;
 }
 
index 65af2369e5e0358ad34e9be85435ef0a8a70435c..d77042d4e318b05216dddf09027fc4faf8d9dd08 100644 (file)
@@ -226,6 +226,12 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
 
        inst->type = FR_EAP_METHOD_SIM;
 
+       /*
+        *      This isn't allowed, so just munge
+        *      it to no id request.
+        */
+       if (inst->request_identity == AKA_SIM_INIT_ID_REQ) inst->request_identity = AKA_SIM_NO_ID_REQ;
+
        return 0;
 }