]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
EAP-SIM/AKA server: IMSI privacy
authorJouni Malinen <quic_jouni@quicinc.com>
Sat, 30 Apr 2022 13:56:10 +0000 (16:56 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 1 May 2022 13:25:16 +0000 (16:25 +0300)
Add support for IMSI privacy in the EAP-SIM/AKA server implementation.
If the new hostapd configuration parameter imsi_privacy_key is used to
specify an RSA private key, that key will be used to decrypt encrypted
permanent identity.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/authsrv.c
src/ap/hostapd.h
src/eap_server/eap.h
src/eap_server/eap_server_aka.c
src/eap_server/eap_server_sim.c

index 97eea8eda23aa8b3ee0cc697e7772c072791c248..8a86ce08bae4914616b0d6e277656d72300adf88 100644 (file)
@@ -2589,6 +2589,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                bss->eap_sim_aka_result_ind = atoi(pos);
        } else if (os_strcmp(buf, "eap_sim_id") == 0) {
                bss->eap_sim_id = atoi(pos);
+       } else if (os_strcmp(buf, "imsi_privacy_key") == 0) {
+               os_free(bss->imsi_privacy_key);
+               bss->imsi_privacy_key = os_strdup(pos);
 #endif /* EAP_SERVER_SIM */
 #ifdef EAP_SERVER_TNC
        } else if (os_strcmp(buf, "tnc") == 0) {
index 6ccb61115f8535e7418a07a0aa99fa92452bf94d..f37d5634b1b5c63d80a5e3ca364f1dd15bde923d 100644 (file)
@@ -1423,6 +1423,10 @@ eap_server=0
 # 3 = use pseudonyms and use fast reauthentication (default)
 #eap_sim_id=3
 
+# IMSI privacy key (PEM encoded RSA 2048-bit private key) for decrypting
+# permanent identity when using EAP-SIM/AKA/AKA'.
+#imsi_privacy_key=imsi-privacy-key.pem
+
 # Trusted Network Connect (TNC)
 # If enabled, TNC validation will be required before the peer is allowed to
 # connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
index ac0617e3f8fe6fbabaaccc54acac2a751846d400..e208788d11242a6d9ef41a6d98902f549e6afe5e 100644 (file)
@@ -809,6 +809,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->eap_fast_a_id);
        os_free(conf->eap_fast_a_id_info);
        os_free(conf->eap_sim_db);
+       os_free(conf->imsi_privacy_key);
        os_free(conf->radius_server_clients);
        os_free(conf->radius);
        os_free(conf->radius_das_shared_secret);
index 5b7e574a5220c2aaaaf21391969ebf869bef4479..274b6f3097a49f917ae6a2665f771d17f08d8da0 100644 (file)
@@ -443,6 +443,7 @@ struct hostapd_bss_config {
        int eap_teap_id;
        int eap_sim_aka_result_ind;
        int eap_sim_id;
+       char *imsi_privacy_key;
        int tnc;
        int fragment_size;
        u16 pwd_group;
index 35df5980370334ade723390f94a3465376b7abc7..516c1da74081fed70ce264a82d612b2505761da5 100644 (file)
@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "crypto/crypto.h"
 #include "crypto/tls.h"
 #include "eap_server/eap.h"
 #include "eap_server/eap_sim_db.h"
@@ -209,6 +210,7 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
        cfg->eap_teap_id = hapd->conf->eap_teap_id;
        cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
        cfg->eap_sim_id = hapd->conf->eap_sim_id;
+       cfg->imsi_privacy_key = hapd->imsi_privacy_key;
        cfg->tnc = hapd->conf->tnc;
        cfg->wps = hapd->wps;
        cfg->fragment_size = hapd->conf->fragment_size;
@@ -295,6 +297,22 @@ int authsrv_init(struct hostapd_data *hapd)
        }
 #endif /* EAP_TLS_FUNCS */
 
+#ifdef CRYPTO_RSA_OAEP_SHA256
+       crypto_rsa_key_free(hapd->imsi_privacy_key);
+       hapd->imsi_privacy_key = NULL;
+       if (hapd->conf->imsi_privacy_key) {
+               hapd->imsi_privacy_key = crypto_rsa_key_read(
+                       hapd->conf->imsi_privacy_key, true);
+               if (!hapd->imsi_privacy_key) {
+                       wpa_printf(MSG_ERROR,
+                                  "Failed to read/parse IMSI privacy key %s",
+                                  hapd->conf->imsi_privacy_key);
+                       authsrv_deinit(hapd);
+                       return -1;
+               }
+       }
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
 #ifdef EAP_SIM_DB
        if (hapd->conf->eap_sim_db) {
                hapd->eap_sim_db_priv =
@@ -335,6 +353,11 @@ void authsrv_deinit(struct hostapd_data *hapd)
        hapd->radius_srv = NULL;
 #endif /* RADIUS_SERVER */
 
+#ifdef CRYPTO_RSA_OAEP_SHA256
+       crypto_rsa_key_free(hapd->imsi_privacy_key);
+       hapd->imsi_privacy_key = NULL;
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
 #ifdef EAP_TLS_FUNCS
        if (hapd->ssl_ctx) {
                tls_deinit(hapd->ssl_ctx);
index a1ac45f8998caf0c862ccd6ab78692655719aaef..297faaf1409c4bfa57c3034414284de7b76a9f00 100644 (file)
@@ -208,6 +208,7 @@ struct hostapd_data {
 
        void *ssl_ctx;
        void *eap_sim_db_priv;
+       struct crypto_rsa_key *imsi_privacy_key;
        struct radius_server_data *radius_srv;
        struct dl_list erp_keys; /* struct eap_server_erp_key */
 
index f1d3a9c9922d122c62d5f7db8d2774d28e6f21c7..2894cfbfeefbaab6a584e00b6d2b295d1aaeb3a9 100644 (file)
@@ -124,6 +124,9 @@ struct eap_config {
         * callback context.
         */
        void *eap_sim_db_priv;
+
+       struct crypto_rsa_key *imsi_privacy_key;
+
        bool backend_auth;
        int eap_server;
 
index e9bf0300c16f967b255f84d40ae2307312ff31cb..5fb19e976a7138d5353a4d872c881d22131c96bc 100644 (file)
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "utils/base64.h"
 #include "crypto/sha256.h"
 #include "crypto/crypto.h"
 #include "crypto/random.h"
@@ -737,11 +738,8 @@ static void eap_aka_determine_identity(struct eap_sm *sm,
                          sm->identity, sm->identity_len);
 
        username = sim_get_username(sm->identity, sm->identity_len);
-       if (username == NULL) {
-               data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-               eap_aka_state(data, NOTIFICATION);
-               return;
-       }
+       if (!username)
+               goto fail;
 
        if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
                os_free(username);
@@ -785,16 +783,87 @@ static void eap_aka_determine_identity(struct eap_sm *sm,
                           username);
                os_strlcpy(data->permanent, username, sizeof(data->permanent));
                os_free(username);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+       } else if (sm->identity_len > 1 && sm->identity[0] == '\0') {
+               char *enc_id, *pos, *end;
+               size_t enc_id_len;
+               u8 *decoded_id;
+               size_t decoded_id_len;
+               struct wpabuf *enc, *dec;
+               u8 *new_id;
+
+               os_free(username);
+               if (!sm->cfg->imsi_privacy_key) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-AKA: Received encrypted identity, but no IMSI privacy key configured to decrypt it");
+                       goto fail;
+               }
+
+               enc_id = (char *) &sm->identity[1];
+               end = (char *) &sm->identity[sm->identity_len];
+               for (pos = enc_id; pos < end; pos++) {
+                       if (*pos == ',')
+                               break;
+               }
+               enc_id_len = pos - enc_id;
+
+               wpa_hexdump_ascii(MSG_DEBUG,
+                                 "EAP-AKA: Encrypted permanent identity",
+                                 enc_id, enc_id_len);
+               decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len);
+               if (!decoded_id) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-AKA: Could not base64 decode encrypted identity");
+                       goto fail;
+               }
+               wpa_hexdump(MSG_DEBUG,
+                           "EAP-AKA: Decoded encrypted permanent identity",
+                           decoded_id, decoded_id_len);
+               enc = wpabuf_alloc_copy(decoded_id, decoded_id_len);
+               os_free(decoded_id);
+               if (!enc)
+                       goto fail;
+               dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key,
+                                                    enc);
+               wpabuf_free(enc);
+               if (!dec) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-AKA: Failed to decrypt encrypted identity");
+                       goto fail;
+               }
+               wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Decrypted permanent identity",
+                                 wpabuf_head(dec), wpabuf_len(dec));
+               username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec));
+               if (!username) {
+                       wpabuf_free(dec);
+                       goto fail;
+               }
+               new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec));
+               if (!new_id) {
+                       wpabuf_free(dec);
+                       goto fail;
+               }
+               os_free(sm->identity);
+               sm->identity = new_id;
+               sm->identity_len = wpabuf_len(dec);
+               wpabuf_free(dec);
+               os_strlcpy(data->permanent, username, sizeof(data->permanent));
+               os_free(username);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
        } else {
                wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
                           username);
                os_free(username);
-               data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-               eap_aka_state(data, NOTIFICATION);
+               goto fail;
                return;
        }
 
        eap_aka_fullauth(sm, data);
+       return;
+
+fail:
+       data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+       eap_aka_state(data, NOTIFICATION);
 }
 
 
index 8a68289620796a85546a455b1d8af0c01858a225..1bcf26c467ca32aa6e7ac28a0610adb9c54790e7 100644 (file)
@@ -9,6 +9,8 @@
 #include "includes.h"
 
 #include "common.h"
+#include "utils/base64.h"
+#include "crypto/crypto.h"
 #include "crypto/random.h"
 #include "eap_server/eap_i.h"
 #include "eap_common/eap_sim_common.h"
@@ -512,6 +514,73 @@ static void eap_sim_process_start(struct eap_sm *sm,
                           username);
                os_strlcpy(data->permanent, username, sizeof(data->permanent));
                os_free(username);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+       } else if (sm->identity_len > 1 && sm->identity[0] == '\0') {
+               char *enc_id, *pos, *end;
+               size_t enc_id_len;
+               u8 *decoded_id;
+               size_t decoded_id_len;
+               struct wpabuf *enc, *dec;
+               u8 *new_id;
+
+               os_free(username);
+               if (!sm->cfg->imsi_privacy_key) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-SIM: Received encrypted identity, but no IMSI privacy key configured to decrypt it");
+                       goto failed;
+               }
+
+               enc_id = (char *) &sm->identity[1];
+               end = (char *) &sm->identity[sm->identity_len];
+               for (pos = enc_id; pos < end; pos++) {
+                       if (*pos == ',')
+                               break;
+               }
+               enc_id_len = pos - enc_id;
+
+               wpa_hexdump_ascii(MSG_DEBUG,
+                                 "EAP-SIM: Encrypted permanent identity",
+                                 enc_id, enc_id_len);
+               decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len);
+               if (!decoded_id) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-SIM: Could not base64 decode encrypted identity");
+                       goto failed;
+               }
+               wpa_hexdump(MSG_DEBUG,
+                           "EAP-SIM: Decoded encrypted permanent identity",
+                           decoded_id, decoded_id_len);
+               enc = wpabuf_alloc_copy(decoded_id, decoded_id_len);
+               os_free(decoded_id);
+               if (!enc)
+                       goto failed;
+               dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key,
+                                                    enc);
+               wpabuf_free(enc);
+               if (!dec) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-SIM: Failed to decrypt encrypted identity");
+                       goto failed;
+               }
+               wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Decrypted permanent identity",
+                                 wpabuf_head(dec), wpabuf_len(dec));
+               username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec));
+               if (!username) {
+                       wpabuf_free(dec);
+                       goto failed;
+               }
+               new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec));
+               if (!new_id) {
+                       wpabuf_free(dec);
+                       goto failed;
+               }
+               os_free(sm->identity);
+               sm->identity = new_id;
+               sm->identity_len = wpabuf_len(dec);
+               wpabuf_free(dec);
+               os_strlcpy(data->permanent, username, sizeof(data->permanent));
+               os_free(username);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
        } else {
                wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
                           username);