]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
EAP-SIM/AKA peer: Simplify identity selection for MK derivation
authorJouni Malinen <quic_jouni@quicinc.com>
Thu, 21 Sep 2023 07:46:38 +0000 (10:46 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 21 Sep 2023 08:55:49 +0000 (11:55 +0300)
Redesign the identity selection for MK derivation to be done explicitly
based on the last indicated identity (whether it is from
EAP-Response/Identity or method specific AT_IDENTITY) during the current
exchange. This makes the implementation cleaner and avoids cases were
more or less duplicated selection steps ended up being slightly
different. This is not as clean as it could otherwise be due to the
exception needed for the IMSI privacy case where the identity used in MK
derivation is actually not the one exchanged in the EAP messages.

Furthermore, this moves the somewhat confusing EAP method specific
tracking of the lasgt EAP-Response/Identity value from EAP-SIM/AKA into
the main EAP peer implementation.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/eap_peer/eap.c
src/eap_peer/eap_aka.c
src/eap_peer/eap_i.h
src/eap_peer/eap_sim.c

index d0706021312244fc23da97cceb096c6f87733181..c8e514ab8fa1855913639fff715d4895b43848e5 100644 (file)
@@ -1759,6 +1759,10 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
        wpabuf_put_data(resp, identity, identity_len);
        wpabuf_free(privacy_identity);
 
+       os_free(sm->identity);
+       sm->identity = os_memdup(identity, identity_len);
+       sm->identity_len = identity_len;
+
        return resp;
 }
 
@@ -2262,6 +2266,7 @@ void eap_peer_sm_deinit(struct eap_sm *sm)
                tls_deinit(sm->ssl_ctx2);
        tls_deinit(sm->ssl_ctx);
        eap_peer_erp_free_keys(sm);
+       os_free(sm->identity);
        os_free(sm);
 }
 
index 6fe939b5c20010c9d5202d53ed654ad9598849cf..72d4ee50571060447ea07f8fafa7b397b6873a80 100644 (file)
@@ -41,8 +41,8 @@ struct eap_aka_data {
        size_t reauth_id_len;
        int reauth;
        unsigned int counter, counter_too_small;
-       u8 *last_eap_identity;
-       size_t last_eap_identity_len;
+       u8 *mk_identity;
+       size_t mk_identity_len;
        enum {
                CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
        } state;
@@ -140,6 +140,13 @@ static void * eap_aka_init(struct eap_sm *sm)
                }
        }
 
+       if (sm->identity) {
+               /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY
+                * is not used. */
+               data->mk_identity = os_memdup(sm->identity, sm->identity_len);
+               data->mk_identity_len = sm->identity_len;
+       }
+
        return data;
 }
 
@@ -177,7 +184,7 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv)
        if (data) {
                os_free(data->pseudonym);
                os_free(data->reauth_id);
-               os_free(data->last_eap_identity);
+               os_free(data->mk_identity);
                wpabuf_free(data->id_msgs);
                os_free(data->network_name);
                eap_aka_clear_keys(data, 0);
@@ -373,7 +380,6 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
 
 #define CLEAR_PSEUDONYM        0x01
 #define CLEAR_REAUTH_ID        0x02
-#define CLEAR_EAP_ID   0x04
 
 static void eap_aka_clear_identities(struct eap_sm *sm,
                                     struct eap_aka_data *data, int id)
@@ -392,12 +398,6 @@ static void eap_aka_clear_identities(struct eap_sm *sm,
                data->reauth_id = NULL;
                data->reauth_id_len = 0;
        }
-       if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
-               wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
-               os_free(data->last_eap_identity);
-               data->last_eap_identity = NULL;
-               data->last_eap_identity_len = 0;
-       }
 }
 
 
@@ -699,6 +699,8 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
        size_t identity_len = 0;
        struct eap_sim_msg *msg;
        struct wpabuf *enc_identity = NULL;
+       struct eap_peer_config *config = NULL;
+       bool use_imsi_identity = false;
 
        data->reauth = 0;
        if (id_req == ANY_ID && data->reauth_id) {
@@ -722,10 +724,13 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
                                                       data->pseudonym_len))
                                ids &= ~CLEAR_PSEUDONYM;
                        eap_aka_clear_identities(sm, data, ids);
+
+                       config = eap_get_config(sm);
+                       if (config && config->imsi_identity)
+                               use_imsi_identity = true;
                }
 #ifdef CRYPTO_RSA_OAEP_SHA256
                if (identity && data->imsi_privacy_key) {
-                       struct eap_peer_config *config;
                        const char *attr = NULL;
 
                        config = eap_get_config(sm);
@@ -741,13 +746,16 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
                                        data, id,
                                        EAP_AKA_UNABLE_TO_PROCESS_PACKET);
                        }
+                       /* Use the real identity, not the encrypted one, in MK
+                        * derivation. */
+                       os_free(data->mk_identity);
+                       data->mk_identity = os_memdup(identity, identity_len);
+                       data->mk_identity_len = identity_len;
                        identity = wpabuf_head(enc_identity);
                        identity_len = wpabuf_len(enc_identity);
                }
 #endif /* CRYPTO_RSA_OAEP_SHA256 */
        }
-       if (id_req != NO_ID_REQ)
-               eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
 
        wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
        msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
@@ -758,6 +766,22 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
                                  identity, identity_len);
                eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
                                identity, identity_len);
+               if (use_imsi_identity && config && config->imsi_identity) {
+                       /* Use the IMSI identity override, i.e., the not
+                        * encrypted one, in MK derivation, when using
+                        * externally encrypted identity in configuration. */
+                       os_free(data->mk_identity);
+                       data->mk_identity = os_memdup(
+                               config->imsi_identity,
+                               config->imsi_identity_len);
+                       data->mk_identity_len = config->imsi_identity_len;
+               } else if (!enc_identity) {
+                       /* Use the last AT_IDENTITY value as the identity in
+                        * MK derivation. */
+                       os_free(data->mk_identity);
+                       data->mk_identity = os_memdup(identity, identity_len);
+                       data->mk_identity_len = identity_len;
+               }
        }
        wpabuf_free(enc_identity);
 
@@ -1147,28 +1171,9 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
                                                 data->network_name_len);
        }
 #endif /* EAP_AKA_PRIME */
-       if (data->last_eap_identity) {
-               identity = data->last_eap_identity;
-               identity_len = data->last_eap_identity_len;
-       } else if (data->reauth_id) {
-               identity = data->reauth_id;
-               identity_len = data->reauth_id_len;
-       } else if (data->pseudonym &&
-                  !eap_sim_anonymous_username(data->pseudonym,
-                                              data->pseudonym_len)) {
-               identity = data->pseudonym;
-               identity_len = data->pseudonym_len;
-       } else {
-               struct eap_peer_config *config;
-
-               config = eap_get_config(sm);
-               if (config && config->imsi_identity) {
-                       identity = config->imsi_identity;
-                       identity_len = config->imsi_identity_len;
-               } else {
-                       identity = eap_get_config_identity(sm, &identity_len);
-               }
-       }
+
+       identity = data->mk_identity;
+       identity_len = data->mk_identity_len;
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
                          "derivation", identity, identity_len);
        if (data->eap_method == EAP_TYPE_AKA_PRIME) {
@@ -1197,7 +1202,7 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
         * other words, if no new identities are received, full
         * authentication will be used on next reauthentication (using
         * pseudonym identity or permanent identity). */
-       eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+       eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
 
        if (attr->encr_data) {
                u8 *decrypted;
@@ -1407,14 +1412,8 @@ static struct wpabuf * eap_aka_process_reauthentication(
 
                /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
                 * reauth_id must not be used to start a new reauthentication.
-                * However, since it was used in the last EAP-Response-Identity
-                * packet, it has to saved for the following fullauth to be
-                * used in MK derivation. */
-               os_free(data->last_eap_identity);
-               data->last_eap_identity = data->reauth_id;
-               data->last_eap_identity_len = data->reauth_id_len;
-               data->reauth_id = NULL;
-               data->reauth_id_len = 0;
+                */
+               eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
 
                res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s);
                os_free(decrypted);
@@ -1439,7 +1438,7 @@ static struct wpabuf * eap_aka_process_reauthentication(
                                           data->nonce_s, data->mk,
                                           data->msk, data->emsk);
        }
-       eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+       eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
        eap_aka_learn_ids(sm, data, &eattr);
 
        if (data->result_ind && attr->result_ind)
@@ -1455,8 +1454,7 @@ static struct wpabuf * eap_aka_process_reauthentication(
        if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
                wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
                           "fast reauths performed - force fullauth");
-               eap_aka_clear_identities(sm, data,
-                                        CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+               eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
        }
        os_free(decrypted);
        return eap_aka_response_reauth(data, id, 0, data->nonce_s);
@@ -1572,7 +1570,10 @@ static bool eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
 static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
 {
        struct eap_aka_data *data = priv;
-       eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
+
+       os_free(data->mk_identity);
+       data->mk_identity = NULL;
+       data->mk_identity_len = 0;
        data->prev_id = -1;
        wpabuf_free(data->id_msgs);
        data->id_msgs = NULL;
@@ -1585,6 +1586,15 @@ static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
 static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv)
 {
        struct eap_aka_data *data = priv;
+
+       if (sm->identity) {
+               /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY
+                * is not used. */
+               os_free(data->mk_identity);
+               data->mk_identity = os_memdup(sm->identity, sm->identity_len);
+               data->mk_identity_len = sm->identity_len;
+       }
+
        data->num_id_req = 0;
        data->num_notification = 0;
        eap_aka_state(data, CONTINUE);
index 08dd569d6a60d90f5d206033e54cc474927f9eca..21681658d68875b8db4ca500d1d6b0376fe77908 100644 (file)
@@ -390,6 +390,10 @@ struct eap_sm {
        unsigned int use_machine_cred:1;
 
        struct dl_list erp_keys; /* struct eap_erp_key */
+
+       /* Identity used in EAP-Response/Identity */
+       u8 *identity;
+       size_t identity_len;
 };
 
 const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
index 71da424d22aef01ccff8d114c9cfe1f83b4bb02e..b5e3240232727096202fd8721e9c9e9e0d0f0649 100644 (file)
@@ -43,8 +43,8 @@ struct eap_sim_data {
        size_t reauth_id_len;
        int reauth;
        unsigned int counter, counter_too_small;
-       u8 *last_eap_identity;
-       size_t last_eap_identity_len;
+       u8 *mk_identity;
+       size_t mk_identity_len;
        enum {
                CONTINUE, START_DONE, RESULT_SUCCESS, SUCCESS, FAILURE
        } state;
@@ -158,6 +158,13 @@ static void * eap_sim_init(struct eap_sm *sm)
                }
        }
 
+       if (sm->identity) {
+               /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY
+                * is not used. */
+               data->mk_identity = os_memdup(sm->identity, sm->identity_len);
+               data->mk_identity_len = sm->identity_len;
+       }
+
        eap_sim_state(data, CONTINUE);
 
        return data;
@@ -185,7 +192,7 @@ static void eap_sim_deinit(struct eap_sm *sm, void *priv)
                os_free(data->ver_list);
                os_free(data->pseudonym);
                os_free(data->reauth_id);
-               os_free(data->last_eap_identity);
+               os_free(data->mk_identity);
                eap_sim_clear_keys(data, 0);
 #ifdef CRYPTO_RSA_OAEP_SHA256
                crypto_rsa_key_free(data->imsi_privacy_key);
@@ -399,7 +406,6 @@ static int eap_sim_supported_ver(int version)
 
 #define CLEAR_PSEUDONYM        0x01
 #define CLEAR_REAUTH_ID        0x02
-#define CLEAR_EAP_ID   0x04
 
 static void eap_sim_clear_identities(struct eap_sm *sm,
                                     struct eap_sim_data *data, int id)
@@ -418,12 +424,6 @@ static void eap_sim_clear_identities(struct eap_sm *sm,
                data->reauth_id = NULL;
                data->reauth_id_len = 0;
        }
-       if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
-               wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id");
-               os_free(data->last_eap_identity);
-               data->last_eap_identity = NULL;
-               data->last_eap_identity_len = 0;
-       }
 }
 
 
@@ -567,6 +567,8 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
        struct eap_sim_msg *msg;
        struct wpabuf *resp;
        struct wpabuf *enc_identity = NULL;
+       struct eap_peer_config *config = NULL;
+       bool use_imsi_identity = false;
 
        data->reauth = 0;
        if (id_req == ANY_ID && data->reauth_id) {
@@ -590,10 +592,13 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
                                                       data->pseudonym_len))
                                ids &= ~CLEAR_PSEUDONYM;
                        eap_sim_clear_identities(sm, data, ids);
+
+                       config = eap_get_config(sm);
+                       if (config && config->imsi_identity)
+                               use_imsi_identity = true;
                }
 #ifdef CRYPTO_RSA_OAEP_SHA256
                if (identity && data->imsi_privacy_key) {
-                       struct eap_peer_config *config;
                        const char *attr = NULL;
 
                        config = eap_get_config(sm);
@@ -609,13 +614,16 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
                                        data, id,
                                        EAP_SIM_UNABLE_TO_PROCESS_PACKET);
                        }
+                       /* Use the real identity, not the encrypted one, in MK
+                        * derivation. */
+                       os_free(data->mk_identity);
+                       data->mk_identity = os_memdup(identity, identity_len);
+                       data->mk_identity_len = identity_len;
                        identity = wpabuf_head(enc_identity);
                        identity_len = wpabuf_len(enc_identity);
                }
 #endif /* CRYPTO_RSA_OAEP_SHA256 */
        }
-       if (id_req != NO_ID_REQ)
-               eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
 
        wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
        msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
@@ -625,6 +633,22 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
                                  identity, identity_len);
                eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
                                identity, identity_len);
+               if (use_imsi_identity && config && config->imsi_identity) {
+                       /* Use the IMSI identity override, i.e., the not
+                        * encrypted one, in MK derivation, when using
+                        * externally encrypted identity in configuration. */
+                       os_free(data->mk_identity);
+                       data->mk_identity = os_memdup(
+                               config->imsi_identity,
+                               config->imsi_identity_len);
+                       data->mk_identity_len = config->imsi_identity_len;
+               } else if (!enc_identity) {
+                       /* Use the last AT_IDENTITY value as the identity in
+                        * MK derivation. */
+                       os_free(data->mk_identity);
+                       data->mk_identity = os_memdup(identity, identity_len);
+                       data->mk_identity_len = identity_len;
+               }
        }
        wpabuf_free(enc_identity);
        if (!data->reauth) {
@@ -886,28 +910,9 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
                return eap_sim_client_error(data, id,
                                            EAP_SIM_UNABLE_TO_PROCESS_PACKET);
        }
-       if (data->last_eap_identity) {
-               identity = data->last_eap_identity;
-               identity_len = data->last_eap_identity_len;
-       } else if (data->reauth_id) {
-               identity = data->reauth_id;
-               identity_len = data->reauth_id_len;
-       } else if (data->pseudonym &&
-                  !eap_sim_anonymous_username(data->pseudonym,
-                                              data->pseudonym_len)) {
-               identity = data->pseudonym;
-               identity_len = data->pseudonym_len;
-       } else {
-               struct eap_peer_config *config;
-
-               config = eap_get_config(sm);
-               if (config && config->imsi_identity) {
-                       identity = config->imsi_identity;
-                       identity_len = config->imsi_identity_len;
-               } else {
-                       identity = eap_get_config_identity(sm, &identity_len);
-               }
-       }
+
+       identity = data->mk_identity;
+       identity_len = data->mk_identity_len;
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
                          "derivation", identity, identity_len);
        eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
@@ -933,7 +938,7 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
         * other words, if no new reauth identity is received, full
         * authentication will be used on next reauthentication (using
         * pseudonym identity or permanent identity). */
-       eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+       eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
 
        if (attr->encr_data) {
                u8 *decrypted;
@@ -1143,14 +1148,8 @@ static struct wpabuf * eap_sim_process_reauthentication(
 
                /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
                 * reauth_id must not be used to start a new reauthentication.
-                * However, since it was used in the last EAP-Response-Identity
-                * packet, it has to saved for the following fullauth to be
-                * used in MK derivation. */
-               os_free(data->last_eap_identity);
-               data->last_eap_identity = data->reauth_id;
-               data->last_eap_identity_len = data->reauth_id_len;
-               data->reauth_id = NULL;
-               data->reauth_id_len = 0;
+                */
+               eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
 
                res = eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
                os_free(decrypted);
@@ -1167,7 +1166,7 @@ static struct wpabuf * eap_sim_process_reauthentication(
                                   data->reauth_id, data->reauth_id_len,
                                   data->nonce_s, data->mk, data->msk,
                                   data->emsk);
-       eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+       eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
        eap_sim_learn_ids(sm, data, &eattr);
 
        if (data->result_ind && attr->result_ind)
@@ -1183,8 +1182,7 @@ static struct wpabuf * eap_sim_process_reauthentication(
        if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
                wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
                           "fast reauths performed - force fullauth");
-               eap_sim_clear_identities(sm, data,
-                                        CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+               eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
        }
        os_free(decrypted);
        return eap_sim_response_reauth(data, id, 0, data->nonce_s);
@@ -1293,7 +1291,10 @@ static bool eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
 static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
 {
        struct eap_sim_data *data = priv;
-       eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
+
+       os_free(data->mk_identity);
+       data->mk_identity = NULL;
+       data->mk_identity_len = 0;
        data->use_result_ind = 0;
        eap_sim_clear_keys(data, 1);
 }
@@ -1308,6 +1309,15 @@ static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
                eap_sim_deinit(sm, data);
                return NULL;
        }
+
+       if (sm->identity) {
+               /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY
+                * is not used. */
+               os_free(data->mk_identity);
+               data->mk_identity = os_memdup(sm->identity, sm->identity_len);
+               data->mk_identity_len = sm->identity_len;
+       }
+
        data->num_id_req = 0;
        data->num_notification = 0;
        eap_sim_state(data, CONTINUE);