aboutsummaryrefslogtreecommitdiff
path: root/src/eap_peer/eap_sim.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/eap_peer/eap_sim.c')
-rw-r--r--src/eap_peer/eap_sim.c132
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);