diff options
Diffstat (limited to 'src/eap_peer/eap_sim.c')
-rw-r--r-- | src/eap_peer/eap_sim.c | 132 |
1 files changed, 111 insertions, 21 deletions
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c index de423e8b..6f18ebfe 100644 --- a/src/eap_peer/eap_sim.c +++ b/src/eap_peer/eap_sim.c @@ -9,7 +9,9 @@ #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" @@ -49,6 +51,7 @@ struct eap_sim_data { int result_ind, use_result_ind; int use_pseudonym; int error_code; + struct crypto_rsa_key *imsi_privacy_key; }; @@ -98,6 +101,25 @@ static void * eap_sim_init(struct eap_sm *sm) return NULL; } + if (config && config->imsi_privacy_cert) { +#ifdef CRYPTO_RSA_OAEP_SHA256 + data->imsi_privacy_key = crypto_rsa_key_read( + config->imsi_privacy_cert, false); + if (!data->imsi_privacy_key) { + wpa_printf(MSG_ERROR, + "EAP-SIM: Failed to read/parse IMSI privacy certificate %s", + config->imsi_privacy_cert); + os_free(data); + return NULL; + } +#else /* CRYPTO_RSA_OAEP_SHA256 */ + wpa_printf(MSG_ERROR, + "EAP-SIM: No support for imsi_privacy_cert 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; @@ -111,6 +133,9 @@ static void * eap_sim_init(struct eap_sm *sm) "sim_min_num_chal configuration " "(%lu, expected 2 or 3)", (unsigned long) data->min_num_chal); +#ifdef CRYPTO_RSA_OAEP_SHA256 + crypto_rsa_key_free(data->imsi_privacy_key); +#endif /* CRYPTO_RSA_OAEP_SHA256 */ os_free(data); return NULL; } @@ -162,6 +187,9 @@ static void eap_sim_deinit(struct eap_sm *sm, void *priv) 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); } } @@ -407,33 +435,16 @@ static int eap_sim_learn_ids(struct eap_sm *sm, struct eap_sim_data *data, size_t identity_len = 0; const u8 *realm = NULL; size_t realm_len = 0; - struct eap_peer_config *config = eap_get_config(sm); wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: (encr) AT_NEXT_PSEUDONYM", attr->next_pseudonym, attr->next_pseudonym_len); os_free(data->pseudonym); - /* Look for the realm of the permanent identity */ - identity = eap_get_config_identity(sm, &identity_len); - if (identity) { - for (realm = identity, realm_len = identity_len; - realm_len > 0; realm_len--, realm++) { - if (*realm == '@') - break; - } - } - // If no realm from the permanent identity, look for the - // realm of the anonymous identity. - if (realm_len == 0 && config && config->anonymous_identity - && config->anonymous_identity_len > 0) { - for (realm = config->anonymous_identity, - realm_len = config->anonymous_identity_len; - realm_len > 0; realm_len--, realm++) { - if (*realm == '@') - break; - } - } + + /* Get realm from identities to decorate pseudonym. */ + realm = eap_get_config_realm(sm, &realm_len); + data->pseudonym = os_malloc(attr->next_pseudonym_len + realm_len); if (data->pseudonym == NULL) { @@ -493,6 +504,55 @@ 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 char *attr) +{ + struct wpabuf *imsi_buf, *enc; + char *b64; + size_t b64_len, 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; + + len = 1 + b64_len; + if (attr) + len += 1 + os_strlen(attr); + enc = wpabuf_alloc(len); + if (!enc) { + os_free(b64); + return NULL; + } + 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)); + + 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) @@ -501,6 +561,7 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, 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) { @@ -515,6 +576,12 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, identity_len = data->pseudonym_len; eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID); } else if (id_req != NO_ID_REQ) { + if (id_req == PERMANENT_ID && eap_get_config_strict_conservative_peer_mode(sm)) { + wpa_printf(MSG_INFO, "EAP-SIM: permanent_id_req is denied in " + "the strict conservative peer mode"); + eap_notify_permanent_id_req_denied(sm); + return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); + } identity = eap_get_config_identity(sm, &identity_len); if (identity) { int ids = CLEAR_PSEUDONYM | CLEAR_REAUTH_ID; @@ -525,6 +592,28 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, ids &= ~CLEAR_PSEUDONYM; eap_sim_clear_identities(sm, data, ids); } +#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, attr); + 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); @@ -538,6 +627,7 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, 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); |