struct wpabuf *resp;
const u8 *identity;
size_t identity_len;
+ struct wpabuf *privacy_identity = NULL;
if (config == NULL) {
wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
identity_len = config->machine_identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
identity, identity_len);
+ } else if (config->imsi_privacy_key && config->identity &&
+ config->identity_len > 0) {
+ const u8 *pos = config->identity;
+ const u8 *end = config->identity + config->identity_len;
+
+ privacy_identity = wpabuf_alloc(9 + config->identity_len);
+ if (!privacy_identity)
+ return NULL;
+
+ /* Include method prefix */
+ if (*pos == '0' || *pos == '1' || *pos == '6')
+ wpabuf_put_u8(privacy_identity, *pos);
+ wpabuf_put_str(privacy_identity, "anonymous");
+
+ /* Include realm */
+ while (pos < end && *pos != '@')
+ pos++;
+ wpabuf_put_data(privacy_identity, pos, end - pos);
+
+ identity = wpabuf_head(privacy_identity);
+ identity_len = wpabuf_len(privacy_identity);
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP: using IMSI privacy anonymous identity",
+ identity, identity_len);
} else {
identity = config->identity;
identity_len = config->identity_len;
return NULL;
wpabuf_put_data(resp, identity, identity_len);
+ wpabuf_free(privacy_identity);
return resp;
}
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
#include "pcsc_funcs.h"
#include "crypto/crypto.h"
#include "crypto/sha1.h"
u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX];
size_t last_kdf_count;
int error_code;
+ struct crypto_rsa_key *imsi_privacy_key;
};
data->eap_method = EAP_TYPE_AKA;
+ if (config && config->imsi_privacy_key) {
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ data->imsi_privacy_key = crypto_rsa_key_read(
+ config->imsi_privacy_key, false);
+ if (!data->imsi_privacy_key) {
+ wpa_printf(MSG_ERROR,
+ "EAP-AKA: Failed to read/parse IMSI privacy key %s",
+ config->imsi_privacy_key);
+ os_free(data);
+ return NULL;
+ }
+#else /* CRYPTO_RSA_OAEP_SHA256 */
+ wpa_printf(MSG_ERROR,
+ "EAP-AKA: No support for imsi_privacy_key in the build");
+ os_free(data);
+ return NULL;
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+ }
+
/* Zero is a valid error code, so we need to initialize */
data->error_code = NO_EAP_METHOD_ERROR;
wpabuf_free(data->id_msgs);
os_free(data->network_name);
eap_aka_clear_keys(data, 0);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(data->imsi_privacy_key);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
os_free(data);
}
}
}
+#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)
+{
+ struct wpabuf *imsi_buf, *enc;
+ char *b64;
+ size_t b64_len;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypt permanent identity",
+ identity, identity_len);
+
+ imsi_buf = wpabuf_alloc_copy(identity, identity_len);
+ if (!imsi_buf)
+ return NULL;
+ enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf);
+ wpabuf_free(imsi_buf);
+ if (!enc)
+ return NULL;
+
+ b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len);
+ wpabuf_free(enc);
+ if (!b64)
+ return NULL;
+
+ enc = wpabuf_alloc(1 + b64_len);
+ if (!enc) {
+ os_free(b64);
+ return NULL;
+ }
+ wpabuf_put_u8(enc, '\0');
+ wpabuf_put_data(enc, b64, b64_len);
+ os_free(b64);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypted permanent identity",
+ wpabuf_head(enc), wpabuf_len(enc));
+
+ return enc;
+}
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
+
static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
struct eap_aka_data *data,
u8 id,
const u8 *identity = NULL;
size_t identity_len = 0;
struct eap_sim_msg *msg;
+ struct wpabuf *enc_identity = NULL;
data->reauth = 0;
if (id_req == ANY_ID && data->reauth_id) {
ids &= ~CLEAR_PSEUDONYM;
eap_aka_clear_identities(sm, data, ids);
}
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ if (identity && data->imsi_privacy_key) {
+ enc_identity = eap_aka_encrypt_identity(
+ data->imsi_privacy_key,
+ identity, identity_len);
+ if (!enc_identity) {
+ wpa_printf(MSG_INFO,
+ "EAP-AKA: Failed to encrypt permanent identity");
+ return eap_aka_client_error(
+ data, id,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+ 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);
eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
identity, identity_len);
}
+ wpabuf_free(enc_identity);
return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
u8 *imsi_identity;
size_t imsi_identity_len;
+ /**
+ * imsi_privacy_key - IMSI privacy key (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.
+ */
+ char *imsi_privacy_key;
+
/**
* machine_identity - EAP Identity for machine credential
*
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
#include "pcsc_funcs.h"
+#include "crypto/crypto.h"
#include "crypto/milenage.h"
#include "crypto/random.h"
#include "eap_peer/eap_i.h"
int result_ind, use_result_ind;
int use_pseudonym;
int error_code;
+ struct crypto_rsa_key *imsi_privacy_key;
};
return NULL;
}
+ if (config && config->imsi_privacy_key) {
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ data->imsi_privacy_key = crypto_rsa_key_read(
+ config->imsi_privacy_key, false);
+ if (!data->imsi_privacy_key) {
+ wpa_printf(MSG_ERROR,
+ "EAP-SIM: Failed to read/parse IMSI privacy key %s",
+ config->imsi_privacy_key);
+ os_free(data);
+ return NULL;
+ }
+#else /* CRYPTO_RSA_OAEP_SHA256 */
+ wpa_printf(MSG_ERROR,
+ "EAP-SIM: No support for imsi_privacy_key in the build");
+ os_free(data);
+ return NULL;
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+ }
+
/* Zero is a valid error code, so we need to initialize */
data->error_code = NO_EAP_METHOD_ERROR;
os_free(data->reauth_id);
os_free(data->last_eap_identity);
eap_sim_clear_keys(data, 0);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(data->imsi_privacy_key);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
os_free(data);
}
}
}
+#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)
+{
+ struct wpabuf *imsi_buf, *enc;
+ char *b64;
+ size_t b64_len;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypt permanent identity",
+ identity, identity_len);
+
+ imsi_buf = wpabuf_alloc_copy(identity, identity_len);
+ if (!imsi_buf)
+ return NULL;
+ enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf);
+ wpabuf_free(imsi_buf);
+ if (!enc)
+ return NULL;
+
+ b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len);
+ wpabuf_free(enc);
+ if (!b64)
+ return NULL;
+
+ enc = wpabuf_alloc(1 + b64_len);
+ if (!enc) {
+ os_free(b64);
+ return NULL;
+ }
+ wpabuf_put_u8(enc, '\0');
+ wpabuf_put_data(enc, b64, b64_len);
+ os_free(b64);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypted permanent identity",
+ wpabuf_head(enc), wpabuf_len(enc));
+
+ return enc;
+}
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
+
static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
struct eap_sim_data *data, u8 id,
enum eap_sim_id_req id_req)
size_t identity_len = 0;
struct eap_sim_msg *msg;
struct wpabuf *resp;
+ struct wpabuf *enc_identity = NULL;
data->reauth = 0;
if (id_req == ANY_ID && data->reauth_id) {
ids &= ~CLEAR_PSEUDONYM;
eap_sim_clear_identities(sm, data, ids);
}
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ if (identity && data->imsi_privacy_key) {
+ enc_identity = eap_sim_encrypt_identity(
+ data->imsi_privacy_key,
+ identity, identity_len);
+ if (!enc_identity) {
+ wpa_printf(MSG_INFO,
+ "EAP-SIM: Failed to encrypt permanent identity");
+ return eap_sim_client_error(
+ data, id,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+ 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);
eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
identity, identity_len);
}
+ wpabuf_free(enc_identity);
if (!data->reauth) {
wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT",
data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
# format
#
+# imsi_privacy_key: IMSI privacy key (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.
+#
# domain_suffix_match: Constraint for server domain name
# If set, this FQDN is used as a suffix match requirement for the AAA
# server certificate in SubjectAltName dNSName element(s). If a
{ INTe(machine_ocsp, machine_cert.ocsp) },
{ INT(eapol_flags) },
{ INTe(sim_num, sim_num) },
+ { STRe(imsi_privacy_key, imsi_privacy_key) },
{ STRe(openssl_ciphers, openssl_ciphers) },
{ INTe(erp, erp) },
#endif /* IEEE8021X_EAPOL */
bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
os_free(eap->imsi_identity);
+ os_free(eap->imsi_privacy_key);
os_free(eap->machine_identity);
bin_clear_free(eap->password, eap->password_len);
bin_clear_free(eap->machine_password, eap->machine_password_len);
os_free(cred->req_conn_capab_port[i]);
os_free(cred->req_conn_capab_port);
os_free(cred->req_conn_capab_proto);
+ os_free(cred->imsi_privacy_key);
os_free(cred);
}
return 0;
}
+ if (os_strcmp(var, "imsi_privacy_key") == 0) {
+ os_free(cred->imsi_privacy_key);
+ cred->imsi_privacy_key = val;
+ return 0;
+ }
+
if (line) {
wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
line, var);
if (os_strcmp(var, "imsi") == 0)
return alloc_strdup(cred->imsi);
+ if (os_strcmp(var, "imsi_privacy_key") == 0)
+ return alloc_strdup(cred->imsi_privacy_key);
+
if (os_strcmp(var, "milenage") == 0) {
if (!(cred->milenage))
return NULL;
*/
char *milenage;
+ /**
+ * imsi_privacy_key - IMSI privacy key (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.
+ */
+ char *imsi_privacy_key;
+
/**
* engine - Use an engine for private key operations
*/
goto fail;
}
+ if (cred->imsi_privacy_key && cred->imsi_privacy_key[0]) {
+ if (wpa_config_set_quoted(ssid, "imsi_privacy_key",
+ cred->imsi_privacy_key) < 0)
+ goto fail;
+ }
+
wpa_s->next_ssid = ssid;
wpa_config_update_prio_list(wpa_s->conf);
if (!only_add)