Add support for IMSI privacy in the EAP-SIM/AKA server implementation.
If the new hostapd configuration parameter imsi_privacy_key is used to
specify an RSA private key, that key will be used to decrypt encrypted
permanent identity.
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
bss->eap_sim_aka_result_ind = atoi(pos);
} else if (os_strcmp(buf, "eap_sim_id") == 0) {
bss->eap_sim_id = atoi(pos);
+ } else if (os_strcmp(buf, "imsi_privacy_key") == 0) {
+ os_free(bss->imsi_privacy_key);
+ bss->imsi_privacy_key = os_strdup(pos);
#endif /* EAP_SERVER_SIM */
#ifdef EAP_SERVER_TNC
} else if (os_strcmp(buf, "tnc") == 0) {
# 3 = use pseudonyms and use fast reauthentication (default)
#eap_sim_id=3
+# IMSI privacy key (PEM encoded RSA 2048-bit private key) for decrypting
+# permanent identity when using EAP-SIM/AKA/AKA'.
+#imsi_privacy_key=imsi-privacy-key.pem
+
# Trusted Network Connect (TNC)
# If enabled, TNC validation will be required before the peer is allowed to
# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
os_free(conf->eap_sim_db);
+ os_free(conf->imsi_privacy_key);
os_free(conf->radius_server_clients);
os_free(conf->radius);
os_free(conf->radius_das_shared_secret);
int eap_teap_id;
int eap_sim_aka_result_ind;
int eap_sim_id;
+ char *imsi_privacy_key;
int tnc;
int fragment_size;
u16 pwd_group;
#include "utils/includes.h"
#include "utils/common.h"
+#include "crypto/crypto.h"
#include "crypto/tls.h"
#include "eap_server/eap.h"
#include "eap_server/eap_sim_db.h"
cfg->eap_teap_id = hapd->conf->eap_teap_id;
cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
cfg->eap_sim_id = hapd->conf->eap_sim_id;
+ cfg->imsi_privacy_key = hapd->imsi_privacy_key;
cfg->tnc = hapd->conf->tnc;
cfg->wps = hapd->wps;
cfg->fragment_size = hapd->conf->fragment_size;
}
#endif /* EAP_TLS_FUNCS */
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(hapd->imsi_privacy_key);
+ hapd->imsi_privacy_key = NULL;
+ if (hapd->conf->imsi_privacy_key) {
+ hapd->imsi_privacy_key = crypto_rsa_key_read(
+ hapd->conf->imsi_privacy_key, true);
+ if (!hapd->imsi_privacy_key) {
+ wpa_printf(MSG_ERROR,
+ "Failed to read/parse IMSI privacy key %s",
+ hapd->conf->imsi_privacy_key);
+ authsrv_deinit(hapd);
+ return -1;
+ }
+ }
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
#ifdef EAP_SIM_DB
if (hapd->conf->eap_sim_db) {
hapd->eap_sim_db_priv =
hapd->radius_srv = NULL;
#endif /* RADIUS_SERVER */
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(hapd->imsi_privacy_key);
+ hapd->imsi_privacy_key = NULL;
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
#ifdef EAP_TLS_FUNCS
if (hapd->ssl_ctx) {
tls_deinit(hapd->ssl_ctx);
void *ssl_ctx;
void *eap_sim_db_priv;
+ struct crypto_rsa_key *imsi_privacy_key;
struct radius_server_data *radius_srv;
struct dl_list erp_keys; /* struct eap_server_erp_key */
* callback context.
*/
void *eap_sim_db_priv;
+
+ struct crypto_rsa_key *imsi_privacy_key;
+
bool backend_auth;
int eap_server;
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
#include "crypto/sha256.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
sm->identity, sm->identity_len);
username = sim_get_username(sm->identity, sm->identity_len);
- if (username == NULL) {
- data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
- eap_aka_state(data, NOTIFICATION);
- return;
- }
+ if (!username)
+ goto fail;
if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
os_free(username);
username);
os_strlcpy(data->permanent, username, sizeof(data->permanent));
os_free(username);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ } else if (sm->identity_len > 1 && sm->identity[0] == '\0') {
+ char *enc_id, *pos, *end;
+ size_t enc_id_len;
+ u8 *decoded_id;
+ size_t decoded_id_len;
+ struct wpabuf *enc, *dec;
+ u8 *new_id;
+
+ os_free(username);
+ if (!sm->cfg->imsi_privacy_key) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-AKA: Received encrypted identity, but no IMSI privacy key configured to decrypt it");
+ goto fail;
+ }
+
+ enc_id = (char *) &sm->identity[1];
+ end = (char *) &sm->identity[sm->identity_len];
+ for (pos = enc_id; pos < end; pos++) {
+ if (*pos == ',')
+ break;
+ }
+ enc_id_len = pos - enc_id;
+
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-AKA: Encrypted permanent identity",
+ enc_id, enc_id_len);
+ decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len);
+ if (!decoded_id) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-AKA: Could not base64 decode encrypted identity");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-AKA: Decoded encrypted permanent identity",
+ decoded_id, decoded_id_len);
+ enc = wpabuf_alloc_copy(decoded_id, decoded_id_len);
+ os_free(decoded_id);
+ if (!enc)
+ goto fail;
+ dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key,
+ enc);
+ wpabuf_free(enc);
+ if (!dec) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-AKA: Failed to decrypt encrypted identity");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Decrypted permanent identity",
+ wpabuf_head(dec), wpabuf_len(dec));
+ username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec));
+ if (!username) {
+ wpabuf_free(dec);
+ goto fail;
+ }
+ new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec));
+ if (!new_id) {
+ wpabuf_free(dec);
+ goto fail;
+ }
+ os_free(sm->identity);
+ sm->identity = new_id;
+ sm->identity_len = wpabuf_len(dec);
+ wpabuf_free(dec);
+ os_strlcpy(data->permanent, username, sizeof(data->permanent));
+ os_free(username);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
} else {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
username);
os_free(username);
- data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
- eap_aka_state(data, NOTIFICATION);
+ goto fail;
return;
}
eap_aka_fullauth(sm, data);
+ return;
+
+fail:
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
}
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
+#include "crypto/crypto.h"
#include "crypto/random.h"
#include "eap_server/eap_i.h"
#include "eap_common/eap_sim_common.h"
username);
os_strlcpy(data->permanent, username, sizeof(data->permanent));
os_free(username);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ } else if (sm->identity_len > 1 && sm->identity[0] == '\0') {
+ char *enc_id, *pos, *end;
+ size_t enc_id_len;
+ u8 *decoded_id;
+ size_t decoded_id_len;
+ struct wpabuf *enc, *dec;
+ u8 *new_id;
+
+ os_free(username);
+ if (!sm->cfg->imsi_privacy_key) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Received encrypted identity, but no IMSI privacy key configured to decrypt it");
+ goto failed;
+ }
+
+ enc_id = (char *) &sm->identity[1];
+ end = (char *) &sm->identity[sm->identity_len];
+ for (pos = enc_id; pos < end; pos++) {
+ if (*pos == ',')
+ break;
+ }
+ enc_id_len = pos - enc_id;
+
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-SIM: Encrypted permanent identity",
+ enc_id, enc_id_len);
+ decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len);
+ if (!decoded_id) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Could not base64 decode encrypted identity");
+ goto failed;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-SIM: Decoded encrypted permanent identity",
+ decoded_id, decoded_id_len);
+ enc = wpabuf_alloc_copy(decoded_id, decoded_id_len);
+ os_free(decoded_id);
+ if (!enc)
+ goto failed;
+ dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key,
+ enc);
+ wpabuf_free(enc);
+ if (!dec) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Failed to decrypt encrypted identity");
+ goto failed;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Decrypted permanent identity",
+ wpabuf_head(dec), wpabuf_len(dec));
+ username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec));
+ if (!username) {
+ wpabuf_free(dec);
+ goto failed;
+ }
+ new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec));
+ if (!new_id) {
+ wpabuf_free(dec);
+ goto failed;
+ }
+ os_free(sm->identity);
+ sm->identity = new_id;
+ sm->identity_len = wpabuf_len(dec);
+ wpabuf_free(dec);
+ os_strlcpy(data->permanent, username, sizeof(data->permanent));
+ os_free(username);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
} else {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
username);