From d1f89dd732ab5f579d2f362c0523912f756c2b2d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 29 Nov 2014 23:46:45 +0200 Subject: [PATCH] EAP server: Add getSessionId This extends EAP server implementation to derive Session-Id similarly to the existing EAP peer implementation. Signed-off-by: Jouni Malinen --- src/eap_server/eap.h | 2 ++ src/eap_server/eap_i.h | 13 ++++++++ src/eap_server/eap_server.c | 14 +++++++++ src/eap_server/eap_server_aka.c | 24 +++++++++++++++ src/eap_server/eap_server_fast.c | 13 ++++++++ src/eap_server/eap_server_gpsk.c | 36 ++++++++++++++++++++++ src/eap_server/eap_server_ikev2.c | 31 +++++++++++++++++++ src/eap_server/eap_server_peap.c | 13 ++++++++ src/eap_server/eap_server_psk.c | 23 +++++++++++++++ src/eap_server/eap_server_pwd.c | 20 +++++++++++++ src/eap_server/eap_server_sake.c | 23 +++++++++++++++ src/eap_server/eap_server_sim.c | 24 +++++++++++++++ src/eap_server/eap_server_tls.c | 13 ++++++++ src/eap_server/eap_server_tls_common.c | 41 ++++++++++++++++++++++++++ src/eap_server/eap_server_ttls.c | 13 ++++++++ src/eap_server/eap_tls_common.h | 3 ++ 16 files changed, 306 insertions(+) diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h index 1253bd6e4..3fdc0668e 100644 --- a/src/eap_server/eap.h +++ b/src/eap_server/eap.h @@ -58,6 +58,8 @@ struct eap_eapol_interface { struct wpabuf *eapReqData; u8 *eapKeyData; size_t eapKeyDataLen; + u8 *eapSessionId; + size_t eapSessionIdLen; Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */ /* AAA interface to full authenticator variables */ diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h index 3a6802b7a..0ec71abd4 100644 --- a/src/eap_server/eap_i.h +++ b/src/eap_server/eap_i.h @@ -88,6 +88,19 @@ struct eap_method { * private data or this function may derive the key. */ u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len); + + /** + * getSessionId - Get EAP method specific Session-Id + * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * @len: Pointer to a variable to store Session-Id length + * Returns: Session-Id or %NULL if not available + * + * This function can be used to get the Session-Id from the EAP method. + * The Session-Id may already be stored in the method-specific private + * data or this function may derive the Session-Id. + */ + u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len); }; /** diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c index c1bb6b83b..ff98acce8 100644 --- a/src/eap_server/eap_server.c +++ b/src/eap_server/eap_server.c @@ -171,6 +171,9 @@ SM_STATE(EAP, INITIALIZE) bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); sm->eap_if.eapKeyData = NULL; sm->eap_if.eapKeyDataLen = 0; + os_free(sm->eap_if.eapSessionId); + sm->eap_if.eapSessionId = NULL; + sm->eap_if.eapSessionIdLen = 0; sm->eap_if.eapKeyAvailable = FALSE; sm->eap_if.eapRestart = FALSE; @@ -355,6 +358,16 @@ SM_STATE(EAP, METHOD_RESPONSE) sm->eap_if.eapKeyData = NULL; sm->eap_if.eapKeyDataLen = 0; } + os_free(sm->eap_if.eapSessionId); + sm->eap_if.eapSessionId = NULL; + if (sm->m->getSessionId) { + sm->eap_if.eapSessionId = sm->m->getSessionId( + sm, sm->eap_method_priv, + &sm->eap_if.eapSessionIdLen); + wpa_hexdump(MSG_DEBUG, "EAP: Session-Id", + sm->eap_if.eapSessionId, + sm->eap_if.eapSessionIdLen); + } sm->methodState = METHOD_END; } else { sm->methodState = METHOD_CONTINUE; @@ -1353,6 +1366,7 @@ void eap_server_sm_deinit(struct eap_sm *sm) sm->m->reset(sm, sm->eap_method_priv); wpabuf_free(sm->eap_if.eapReqData); bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); + os_free(sm->eap_if.eapSessionId); wpabuf_free(sm->lastReqData); wpabuf_free(sm->eap_if.eapRespData); os_free(sm->identity); diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c index 09b976e64..db9b6aa2d 100644 --- a/src/eap_server/eap_server_aka.c +++ b/src/eap_server/eap_server_aka.c @@ -1294,6 +1294,28 @@ static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv) } +static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_aka_data *data = priv; + u8 *id; + + if (data->state != SUCCESS) + return NULL; + + *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN; + id = os_malloc(*len); + if (id == NULL) + return NULL; + + id[0] = data->eap_method; + os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN); + os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN); + wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len); + + return id; +} + + int eap_server_aka_register(void) { struct eap_method *eap; @@ -1313,6 +1335,7 @@ int eap_server_aka_register(void) eap->getKey = eap_aka_getKey; eap->isSuccess = eap_aka_isSuccess; eap->get_emsk = eap_aka_get_emsk; + eap->getSessionId = eap_aka_get_session_id; ret = eap_server_method_register(eap); if (ret) @@ -1342,6 +1365,7 @@ int eap_server_aka_prime_register(void) eap->getKey = eap_aka_getKey; eap->isSuccess = eap_aka_isSuccess; eap->get_emsk = eap_aka_get_emsk; + eap->getSessionId = eap_aka_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c index c6bf6de8f..56ac7f43d 100644 --- a/src/eap_server/eap_server_fast.c +++ b/src/eap_server/eap_server_fast.c @@ -1589,6 +1589,18 @@ static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv) } +static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_fast_data *data = priv; + + if (data->state != SUCCESS) + return NULL; + + return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_FAST, + len); +} + + int eap_server_fast_register(void) { struct eap_method *eap; @@ -1608,6 +1620,7 @@ int eap_server_fast_register(void) eap->getKey = eap_fast_getKey; eap->get_emsk = eap_fast_get_emsk; eap->isSuccess = eap_fast_isSuccess; + eap->getSessionId = eap_fast_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c index cb369e449..50f15c31d 100644 --- a/src/eap_server/eap_server_gpsk.c +++ b/src/eap_server/eap_server_gpsk.c @@ -24,6 +24,8 @@ struct eap_gpsk_data { size_t sk_len; u8 pk[EAP_GPSK_MAX_PK_LEN]; size_t pk_len; + u8 session_id[128]; + size_t id_len; u8 *id_peer; size_t id_peer_len; #define MAX_NUM_CSUITES 2 @@ -417,6 +419,21 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm, return; } + if (eap_gpsk_derive_session_id(sm->user->password, + sm->user->password_len, + data->vendor, data->specifier, + data->rand_peer, data->rand_server, + data->id_peer, data->id_peer_len, + sm->server_id, sm->server_id_len, + EAP_TYPE_GPSK, + data->session_id, &data->id_len) < 0) { + wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id"); + eap_gpsk_state(data, FAILURE); + return; + } + wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id", + data->session_id, data->id_len); + miclen = eap_gpsk_mic_len(data->vendor, data->specifier); if (end - pos < (int) miclen) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " @@ -593,6 +610,24 @@ static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv) } +static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_gpsk_data *data = priv; + u8 *sid; + + if (data->state != SUCCESS) + return NULL; + + sid = os_malloc(data->id_len); + if (sid == NULL) + return NULL; + os_memcpy(sid, data->session_id, data->id_len); + *len = data->id_len; + + return sid; +} + + int eap_server_gpsk_register(void) { struct eap_method *eap; @@ -612,6 +647,7 @@ int eap_server_gpsk_register(void) eap->getKey = eap_gpsk_getKey; eap->isSuccess = eap_gpsk_isSuccess; eap->get_emsk = eap_gpsk_get_emsk; + eap->getSessionId = eap_gpsk_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c index 65b2ef699..804f78540 100644 --- a/src/eap_server/eap_server_ikev2.c +++ b/src/eap_server/eap_server_ikev2.c @@ -511,6 +511,36 @@ static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) } +static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_ikev2_data *data = priv; + u8 *sid; + size_t sid_len; + size_t offset; + + if (data->state != DONE || !data->keymat_ok) + return NULL; + + sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len; + sid = os_malloc(sid_len); + if (sid) { + offset = 0; + sid[offset] = EAP_TYPE_IKEV2; + offset++; + os_memcpy(sid + offset, data->ikev2.i_nonce, + data->ikev2.i_nonce_len); + offset += data->ikev2.i_nonce_len; + os_memcpy(sid + offset, data->ikev2.r_nonce, + data->ikev2.r_nonce_len); + *len = sid_len; + wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id", + sid, sid_len); + } + + return sid; +} + + int eap_server_ikev2_register(void) { struct eap_method *eap; @@ -531,6 +561,7 @@ int eap_server_ikev2_register(void) eap->getKey = eap_ikev2_getKey; eap->isSuccess = eap_ikev2_isSuccess; eap->get_emsk = eap_ikev2_get_emsk; + eap->getSessionId = eap_ikev2_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c index 594e02dd4..98d608bfa 100644 --- a/src/eap_server/eap_server_peap.c +++ b/src/eap_server/eap_server_peap.c @@ -1229,6 +1229,18 @@ static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv) } +static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_peap_data *data = priv; + + if (data->state != SUCCESS) + return NULL; + + return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP, + len); +} + + int eap_server_peap_register(void) { struct eap_method *eap; @@ -1247,6 +1259,7 @@ int eap_server_peap_register(void) eap->isDone = eap_peap_isDone; eap->getKey = eap_peap_getKey; eap->isSuccess = eap_peap_isSuccess; + eap->getSessionId = eap_peap_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c index db394e983..12b5d25d6 100644 --- a/src/eap_server/eap_server_psk.c +++ b/src/eap_server/eap_server_psk.c @@ -485,6 +485,28 @@ static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv) } +static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_psk_data *data = priv; + u8 *id; + + if (data->state != SUCCESS) + return NULL; + + *len = 1 + 2 * EAP_PSK_RAND_LEN; + id = os_malloc(*len); + if (id == NULL) + return NULL; + + id[0] = EAP_TYPE_PSK; + os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN); + os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN); + wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len); + + return id; +} + + int eap_server_psk_register(void) { struct eap_method *eap; @@ -504,6 +526,7 @@ int eap_server_psk_register(void) eap->getKey = eap_psk_getKey; eap->isSuccess = eap_psk_isSuccess; eap->get_emsk = eap_psk_get_emsk; + eap->getSessionId = eap_psk_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c index 3102e9324..943af0d15 100644 --- a/src/eap_server/eap_server_pwd.c +++ b/src/eap_server/eap_server_pwd.c @@ -1020,6 +1020,25 @@ static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv) } +static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_pwd_data *data = priv; + u8 *id; + + if (data->state != SUCCESS) + return NULL; + + id = os_malloc(1 + SHA256_MAC_LEN); + if (id == NULL) + return NULL; + + os_memcpy(id, data->session_id, 1 + SHA256_MAC_LEN); + *len = 1 + SHA256_MAC_LEN; + + return id; +} + + int eap_server_pwd_register(void) { struct eap_method *eap; @@ -1048,6 +1067,7 @@ int eap_server_pwd_register(void) eap->getKey = eap_pwd_getkey; eap->get_emsk = eap_pwd_get_emsk; eap->isSuccess = eap_pwd_is_success; + eap->getSessionId = eap_pwd_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c index 1937621c9..de7077731 100644 --- a/src/eap_server/eap_server_sake.c +++ b/src/eap_server/eap_server_sake.c @@ -495,6 +495,28 @@ static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv) } +static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_sake_data *data = priv; + u8 *id; + + if (data->state != SUCCESS) + return NULL; + + *len = 1 + 2 * EAP_SAKE_RAND_LEN; + id = os_malloc(*len); + if (id == NULL) + return NULL; + + id[0] = EAP_TYPE_SAKE; + os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN); + os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN); + wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len); + + return id; +} + + int eap_server_sake_register(void) { struct eap_method *eap; @@ -514,6 +536,7 @@ int eap_server_sake_register(void) eap->getKey = eap_sake_getKey; eap->isSuccess = eap_sake_isSuccess; eap->get_emsk = eap_sake_get_emsk; + eap->getSessionId = eap_sake_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c index 23ee2b60e..ddfb71cf4 100644 --- a/src/eap_server/eap_server_sim.c +++ b/src/eap_server/eap_server_sim.c @@ -820,6 +820,29 @@ static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv) } +static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_sim_data *data = priv; + u8 *id; + + if (data->state != SUCCESS) + return NULL; + + *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN; + id = os_malloc(*len); + if (id == NULL) + return NULL; + + id[0] = EAP_TYPE_SIM; + os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN); + os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt, + EAP_SIM_NONCE_MT_LEN); + wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len); + + return id; +} + + int eap_server_sim_register(void) { struct eap_method *eap; @@ -839,6 +862,7 @@ int eap_server_sim_register(void) eap->getKey = eap_sim_getKey; eap->isSuccess = eap_sim_isSuccess; eap->get_emsk = eap_sim_get_emsk; + eap->getSessionId = eap_sim_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c index 6bed62f8c..0c9e856d5 100644 --- a/src/eap_server/eap_server_tls.c +++ b/src/eap_server/eap_server_tls.c @@ -310,6 +310,18 @@ static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv) } +static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_tls_data *data = priv; + + if (data->state != SUCCESS) + return NULL; + + return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS, + len); +} + + int eap_server_tls_register(void) { struct eap_method *eap; @@ -329,6 +341,7 @@ int eap_server_tls_register(void) eap->getKey = eap_tls_getKey; eap->isSuccess = eap_tls_isSuccess; eap->get_emsk = eap_tls_get_emsk; + eap->getSessionId = eap_tls_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c index 01853e689..56916c45a 100644 --- a/src/eap_server/eap_server_tls_common.c +++ b/src/eap_server/eap_server_tls_common.c @@ -140,6 +140,47 @@ fail: } +/** + * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) + * @len: Pointer to length of the session ID generated + * Returns: Pointer to allocated Session-Id on success or %NULL on failure + * + * This function derive the Session-Id based on the TLS session data + * (client/server random and method type). + * + * The caller is responsible for freeing the returned buffer. + */ +u8 * eap_server_tls_derive_session_id(struct eap_sm *sm, + struct eap_ssl_data *data, u8 eap_type, + size_t *len) +{ + struct tls_keys keys; + u8 *out; + + if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) + return NULL; + + if (keys.client_random == NULL || keys.server_random == NULL) + return NULL; + + *len = 1 + keys.client_random_len + keys.server_random_len; + out = os_malloc(*len); + if (out == NULL) + return NULL; + + /* Session-Id = EAP type || client.random || server.random */ + out[0] = eap_type; + os_memcpy(out + 1, keys.client_random, keys.client_random_len); + os_memcpy(out + 1 + keys.client_random_len, keys.server_random, + keys.server_random_len); + + return out; +} + + struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, int eap_type, int version, u8 id) { diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c index 31e3871de..f2b0e55aa 100644 --- a/src/eap_server/eap_server_ttls.c +++ b/src/eap_server/eap_server_ttls.c @@ -1181,6 +1181,18 @@ static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv) } +static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_ttls_data *data = priv; + + if (data->state != SUCCESS) + return NULL; + + return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TTLS, + len); +} + + int eap_server_ttls_register(void) { struct eap_method *eap; @@ -1199,6 +1211,7 @@ int eap_server_ttls_register(void) eap->isDone = eap_ttls_isDone; eap->getKey = eap_ttls_getKey; eap->isSuccess = eap_ttls_isSuccess; + eap->getSessionId = eap_ttls_get_session_id; ret = eap_server_method_register(eap); if (ret) diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h index 91449afd7..ddf90b859 100644 --- a/src/eap_server/eap_tls_common.h +++ b/src/eap_server/eap_tls_common.h @@ -74,6 +74,9 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, char *label, size_t len); +u8 * eap_server_tls_derive_session_id(struct eap_sm *sm, + struct eap_ssl_data *data, u8 eap_type, + size_t *len); struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, int eap_type, int version, u8 id); struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version);