]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
EAP-SIM/AKA peer: IMSI privacy attribute
authorJouni Malinen <quic_jouni@quicinc.com>
Wed, 25 May 2022 17:18:40 +0000 (20:18 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 25 May 2022 17:18:40 +0000 (20:18 +0300)
Extend IMSI privacy functionality to allow an attribute (in name=value
format) to be added using the new imsi_privacy_attr parameter.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/eap_peer/eap_aka.c
src/eap_peer/eap_config.h
src/eap_peer/eap_sim.c
wpa_supplicant/README-HS20
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/interworking.c

index 0c9b4b3a9608c98844245139429cc1c1b546f08c..5c9a8c73924a92507fbe89a77dd1cd03e5d99c1e 100644 (file)
@@ -644,11 +644,12 @@ static struct wpabuf * eap_aka_synchronization_failure(
 #ifdef CRYPTO_RSA_OAEP_SHA256
 static struct wpabuf *
 eap_aka_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
-                        const u8 *identity, size_t identity_len)
+                        const u8 *identity, size_t identity_len,
+                        const char *attr)
 {
        struct wpabuf *imsi_buf, *enc;
        char *b64;
-       size_t b64_len;
+       size_t b64_len, len;
 
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypt permanent identity",
                          identity, identity_len);
@@ -666,7 +667,10 @@ eap_aka_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
        if (!b64)
                return NULL;
 
-       enc = wpabuf_alloc(1 + b64_len);
+       len = 1 + b64_len;
+       if (attr)
+               len += 1 + os_strlen(attr);
+       enc = wpabuf_alloc(len);
        if (!enc) {
                os_free(b64);
                return NULL;
@@ -674,6 +678,10 @@ eap_aka_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
        wpabuf_put_u8(enc, '\0');
        wpabuf_put_data(enc, b64, b64_len);
        os_free(b64);
+       if (attr) {
+               wpabuf_put_u8(enc, ',');
+               wpabuf_put_str(enc, attr);
+       }
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypted permanent identity",
                          wpabuf_head(enc), wpabuf_len(enc));
 
@@ -717,9 +725,15 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
                }
 #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);
+                       if (config)
+                               attr = config->imsi_privacy_attr;
                        enc_identity = eap_aka_encrypt_identity(
                                data->imsi_privacy_key,
-                               identity, identity_len);
+                               identity, identity_len, attr);
                        if (!enc_identity) {
                                wpa_printf(MSG_INFO,
                                           "EAP-AKA: Failed to encrypt permanent identity");
index b52007263a5b297ae8c7114d1557135fb16df6da..26744ab6840d9fb20279afe4127af0511ad1ff48 100644 (file)
@@ -327,6 +327,16 @@ struct eap_peer_config {
         */
        char *imsi_privacy_cert;
 
+       /**
+        * imsi_privacy_attr - IMSI privacy attribute
+        *
+        * This field is used to help the EAP-SIM/AKA/AKA' server to identify
+        * the used certificate (and as such, the matching private key). This
+        * is set to an attribute in name=value format if the operator needs
+        * this information.
+        */
+       char *imsi_privacy_attr;
+
        /**
         * machine_identity - EAP Identity for machine credential
         *
index b23222eecaa169577ef28060da8003b7c32f5431..c5a7d0174ebb42abea3319ff19132055cf793a5f 100644 (file)
@@ -512,11 +512,12 @@ static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
 #ifdef CRYPTO_RSA_OAEP_SHA256
 static struct wpabuf *
 eap_sim_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
-                        const u8 *identity, size_t identity_len)
+                        const u8 *identity, size_t identity_len,
+                        const char *attr)
 {
        struct wpabuf *imsi_buf, *enc;
        char *b64;
-       size_t b64_len;
+       size_t b64_len, len;
 
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypt permanent identity",
                          identity, identity_len);
@@ -534,7 +535,10 @@ eap_sim_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
        if (!b64)
                return NULL;
 
-       enc = wpabuf_alloc(1 + b64_len);
+       len = 1 + b64_len;
+       if (attr)
+               len += 1 + os_strlen(attr);
+       enc = wpabuf_alloc(len);
        if (!enc) {
                os_free(b64);
                return NULL;
@@ -542,6 +546,10 @@ eap_sim_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
        wpabuf_put_u8(enc, '\0');
        wpabuf_put_data(enc, b64, b64_len);
        os_free(b64);
+       if (attr) {
+               wpabuf_put_u8(enc, ',');
+               wpabuf_put_str(enc, attr);
+       }
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypted permanent identity",
                          wpabuf_head(enc), wpabuf_len(enc));
 
@@ -585,9 +593,15 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
                }
 #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);
+                       if (config)
+                               attr = config->imsi_privacy_attr;
                        enc_identity = eap_sim_encrypt_identity(
                                data->imsi_privacy_key,
-                               identity, identity_len);
+                               identity, identity_len, attr);
                        if (!enc_identity) {
                                wpa_printf(MSG_INFO,
                                           "EAP-SIM: Failed to encrypt permanent identity");
index a099a85b4c98cc4714162ed8457164aa31b73e40..0cc5f3949147a7a4f44742f2700944ffda743bc0 100644 (file)
@@ -168,11 +168,16 @@ Credentials can be pre-configured for automatic network selection:
 # milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
 #      format
 #
-# imsi_privacy_key: IMSI privacy key (PEM encoded X.509v3 certificate)
+# imsi_privacy_cert: IMSI privacy certificate (PEM encoded X.509v3 certificate)
 #      This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
 #      identity (IMSI) to improve privacy. The X.509v3 certificate needs to
 #      include a 2048-bit RSA public key and this is from the operator who
 #      authenticates the SIM/USIM.
+# imsi_privacy_attr: IMSI privacy attribute
+#      This field is used to help the EAP-SIM/AKA/AKA' server to identify
+#      the used certificate (and as such, the matching private key). This
+#      is set to an attribute in name=value format if the operator needs
+#      this information.
 #
 # domain_suffix_match: Constraint for server domain name
 #      If set, this FQDN is used as a suffix match requirement for the AAA
index 49d3244f6114080a5582e74733863afa7847b0be..bfbc460002c25427e84b16f2267a3fbe6f6336eb 100644 (file)
@@ -2504,6 +2504,7 @@ static const struct parse_data ssid_fields[] = {
        { INT(eapol_flags) },
        { INTe(sim_num, sim_num) },
        { STRe(imsi_privacy_cert, imsi_privacy_cert) },
+       { STRe(imsi_privacy_attr, imsi_privacy_attr) },
        { STRe(openssl_ciphers, openssl_ciphers) },
        { INTe(erp, erp) },
 #endif /* IEEE8021X_EAPOL */
@@ -2772,6 +2773,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
        os_free(eap->anonymous_identity);
        os_free(eap->imsi_identity);
        os_free(eap->imsi_privacy_cert);
+       os_free(eap->imsi_privacy_attr);
        os_free(eap->machine_identity);
        bin_clear_free(eap->password, eap->password_len);
        bin_clear_free(eap->machine_password, eap->machine_password_len);
@@ -2876,6 +2878,7 @@ void wpa_config_free_cred(struct wpa_cred *cred)
        os_free(cred->req_conn_capab_port);
        os_free(cred->req_conn_capab_proto);
        os_free(cred->imsi_privacy_cert);
+       os_free(cred->imsi_privacy_attr);
        os_free(cred);
 }
 
@@ -3917,6 +3920,12 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
                return 0;
        }
 
+       if (os_strcmp(var, "imsi_privacy_attr") == 0) {
+               os_free(cred->imsi_privacy_attr);
+               cred->imsi_privacy_attr = val;
+               return 0;
+       }
+
        if (line) {
                wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
                           line, var);
@@ -4070,6 +4079,9 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var)
        if (os_strcmp(var, "imsi_privacy_cert") == 0)
                return alloc_strdup(cred->imsi_privacy_cert);
 
+       if (os_strcmp(var, "imsi_privacy_attr") == 0)
+               return alloc_strdup(cred->imsi_privacy_attr);
+
        if (os_strcmp(var, "milenage") == 0) {
                if (!(cred->milenage))
                        return NULL;
index 9e6ee87cfa43e62f8ec3a4fba2a42ee684fdcc3f..ba9f2ed8b952fc11f11203f0be2d08d6e65cabc5 100644 (file)
@@ -190,6 +190,16 @@ struct wpa_cred {
         */
        char *imsi_privacy_cert;
 
+       /**
+        * imsi_privacy_attr - IMSI privacy attribute
+        *
+        * This field is used to help the EAP-SIM/AKA/AKA' server to identify
+        * the used certificate (and as such, the matching private key). This
+        * is set to an attribute in name=value format if the operator needs
+        * this information.
+        */
+       char *imsi_privacy_attr;
+
        /**
         * engine - Use an engine for private key operations
         */
index 163b480731108d560528b9ebaccade1090a41628..c0763253fe56bdb9eef93b30170dfa609241de8a 100644 (file)
@@ -1036,6 +1036,13 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
                fprintf(f, "\tcert_id=\"%s\"\n", cred->cert_id);
        if (cred->ca_cert_id)
                fprintf(f, "\tca_cert_id=\"%s\"\n", cred->ca_cert_id);
+
+       if (cred->imsi_privacy_cert)
+               fprintf(f, "\timsi_privacy_cert=\"%s\"\n",
+                       cred->imsi_privacy_cert);
+       if (cred->imsi_privacy_attr)
+               fprintf(f, "\timsi_privacy_attr=\"%s\"\n",
+                       cred->imsi_privacy_attr);
 }
 
 
index 78e3087de2b2a8eec65e49285bf2206e4e363011..bc81728ad208385ce88e78cfa2e06683c50d47cc 100644 (file)
@@ -1071,6 +1071,12 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
                        goto fail;
        }
 
+       if (cred->imsi_privacy_attr && cred->imsi_privacy_attr[0]) {
+               if (wpa_config_set_quoted(ssid, "imsi_privacy_attr",
+                                         cred->imsi_privacy_attr) < 0)
+                       goto fail;
+       }
+
        wpa_s->next_ssid = ssid;
        wpa_config_update_prio_list(wpa_s->conf);
        if (!only_add)