aboutsummaryrefslogtreecommitdiff
path: root/src/eap_peer/eap_aka.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/eap_peer/eap_aka.c')
-rw-r--r--src/eap_peer/eap_aka.c128
1 files changed, 107 insertions, 21 deletions
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index ee7010d4..49338cf7 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
#include "pcsc_funcs.h"
#include "crypto/crypto.h"
#include "crypto/sha1.h"
@@ -58,6 +59,7 @@ struct eap_aka_data {
u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX];
size_t last_kdf_count;
int error_code;
+ struct crypto_rsa_key *imsi_privacy_key;
};
@@ -101,6 +103,25 @@ static void * eap_aka_init(struct eap_sm *sm)
data->eap_method = EAP_TYPE_AKA;
+ 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-AKA: 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-AKA: 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;
@@ -160,6 +181,9 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv)
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);
}
}
@@ -385,33 +409,16 @@ static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_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-AKA: (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) {
@@ -629,6 +636,55 @@ 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 char *attr)
+{
+ struct wpabuf *imsi_buf, *enc;
+ char *b64;
+ size_t b64_len, 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;
+
+ 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-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,
@@ -637,6 +693,7 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
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) {
@@ -651,6 +708,12 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
identity_len = data->pseudonym_len;
eap_aka_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-AKA: permanent_id_req is denied in "
+ "the strict conservative peer mode");
+ eap_notify_permanent_id_req_denied(sm);
+ return eap_aka_client_error(data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
identity = eap_get_config_identity(sm, &identity_len);
if (identity) {
int ids = CLEAR_PSEUDONYM | CLEAR_REAUTH_ID;
@@ -661,6 +724,28 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
ids &= ~CLEAR_PSEUDONYM;
eap_aka_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_aka_encrypt_identity(
+ data->imsi_privacy_key,
+ identity, identity_len, attr);
+ 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);
@@ -675,6 +760,7 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
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);
}