From 8c11fdabccc2b7d3e821206ea510d555249ec695 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 3 May 2019 11:59:49 -0700 Subject: [PATCH] erp: remove 'complete' callback Since ERP is only used for FILS and not behaving in the 'normal' ERP fashion (dealing with actual EAP data, timeouts etc.) we can structure ERP as a more synchronous protocol, removing the need for a complete callback. Now, erp_rx_packet returns a status, so FILS can decide how to handle any failures. The complete callback was also removed in favor of a getter for the RMSK (erp_get_rmsk). This allows FILS to syncronously handle ERP, and potentially fail directly in fils_rx_authenticate. --- src/erp.c | 26 ++++++++++++++------------ src/erp.h | 8 ++++---- src/fils.c | 25 +++++++++++++------------ 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/erp.c b/src/erp.c index 7cc21cc2..c0eb38a6 100644 --- a/src/erp.c +++ b/src/erp.c @@ -26,6 +26,7 @@ #include #include +#include #include @@ -50,11 +51,11 @@ struct erp_cache_entry { struct erp_state { erp_tx_packet_func_t tx_packet; - erp_complete_func_t complete; void *user_data; struct erp_cache_entry *cache; + uint8_t rmsk[64]; uint8_t r_rk[64]; uint8_t r_ik[64]; char keyname_nai[254]; @@ -330,7 +331,7 @@ static bool erp_derive_reauth_keys(const uint8_t *emsk, size_t emsk_len, struct erp_state *erp_new(struct erp_cache_entry *cache, erp_tx_packet_func_t tx_packet, - erp_complete_func_t complete, void *user_data) + void *user_data) { struct erp_state *erp; @@ -340,7 +341,6 @@ struct erp_state *erp_new(struct erp_cache_entry *cache, erp = l_new(struct erp_state, 1); erp->tx_packet = tx_packet; - erp->complete = complete; erp->user_data = user_data; erp->cache = cache; @@ -398,12 +398,11 @@ bool erp_start(struct erp_state *erp) return true; } -void erp_rx_packet(struct erp_state *erp, const uint8_t *pkt, size_t len) +int erp_rx_packet(struct erp_state *erp, const uint8_t *pkt, size_t len) { struct erp_tlv_iter iter; enum eap_erp_cryptosuite cs; uint8_t hash[16]; - uint8_t rmsk[64]; char info[256]; char *ptr = info; const uint8_t *nai = NULL; @@ -425,7 +424,7 @@ void erp_rx_packet(struct erp_state *erp, const uint8_t *pkt, size_t len) type = pkt[4]; if (type != ERP_TYPE_REAUTH) - return; + goto eap_failed; r = util_is_bit_set(pkt[5], 0); if (r) @@ -505,15 +504,18 @@ void erp_rx_packet(struct erp_state *erp, const uint8_t *pkt, size_t len) ptr += 2; hkdf_expand(L_CHECKSUM_SHA256, erp->r_rk, erp->cache->emsk_len, - info, ptr - info, rmsk, erp->cache->emsk_len); + info, ptr - info, erp->rmsk, erp->cache->emsk_len); - erp->complete(ERP_RESULT_SUCCESS, rmsk, erp->cache->emsk_len, - erp->user_data); - - return; + return 0; eap_failed: - erp->complete(ERP_RESULT_FAIL, NULL, 0, erp->user_data); + return -EINVAL; +} + +void erp_get_rmsk(struct erp_state *erp, void **rmsk, size_t *rmsk_len) +{ + *rmsk = erp->rmsk; + *rmsk_len = erp->cache->emsk_len; } void erp_init(void) diff --git a/src/erp.h b/src/erp.h index ebf6bc1c..517ae911 100644 --- a/src/erp.h +++ b/src/erp.h @@ -30,16 +30,16 @@ enum erp_result { typedef void (*erp_tx_packet_func_t)(const uint8_t *erp_data, size_t len, void *user_data); -typedef void (*erp_complete_func_t)(enum erp_result result, const void *rmsk, - size_t rmsk_len, void *user_data); struct erp_state *erp_new(struct erp_cache_entry *cache, erp_tx_packet_func_t tx_packet, - erp_complete_func_t complete, void *user_data); + void *user_data); void erp_free(struct erp_state *erp); bool erp_start(struct erp_state *erp); -void erp_rx_packet(struct erp_state *erp, const uint8_t *erp_data, size_t len); +int erp_rx_packet(struct erp_state *erp, const uint8_t *erp_data, size_t len); + +void erp_get_rmsk(struct erp_state *erp, void **rmsk, size_t *rmsk_len); void erp_cache_add(const char *id, const void *session_id, size_t session_len, const void *emsk, size_t emsk_len, diff --git a/src/fils.c b/src/fils.c index 75577cc2..58a13111 100644 --- a/src/fils.c +++ b/src/fils.c @@ -119,10 +119,9 @@ static void fils_erp_tx_func(const uint8_t *eap_data, size_t len, fils->auth(data, ptr - data + tlv_len, fils->user_data); } -static void fils_erp_complete(enum erp_result result, const void *rmsk, - size_t rmsk_len, void *user_data) +static int fils_derive_key_data(struct fils_sm *fils, const void *rmsk, + size_t rmsk_len) { - struct fils_sm *fils = user_data; struct ie_tlv_builder builder; uint8_t key[FILS_NONCE_LEN * 2]; uint8_t key_data[64 + 48 + 16]; /* largest ICK, KEK, TK */ @@ -134,11 +133,6 @@ static void fils_erp_complete(enum erp_result result, const void *rmsk, bool sha384; unsigned int ie_len; - if (result != ERP_RESULT_SUCCESS) { - fils_failed(fils, MMPDU_STATUS_CODE_UNSPECIFIED, false); - return; - } - /* * IEEE 802.11ai - Section 12.12.2.5.3 */ @@ -241,6 +235,8 @@ static void fils_erp_complete(enum erp_result result, const void *rmsk, FILS_NONCE_LEN * 2, fils->user_data); fils->in_auth = false; + + return 0; } struct fils_sm *fils_sm_new(struct handshake_state *hs, @@ -259,8 +255,7 @@ struct fils_sm *fils_sm_new(struct handshake_state *hs, fils->hs = hs; fils->in_auth = true; - fils->erp = erp_new(hs->erp_cache, fils_erp_tx_func, - fils_erp_complete, fils); + fils->erp = erp_new(hs->erp_cache, fils_erp_tx_func, fils); return fils; } @@ -294,6 +289,8 @@ void fils_rx_authenticate(struct fils_sm *fils, const uint8_t *frame, const uint8_t *session = NULL; const uint8_t *wrapped = NULL; size_t wrapped_len = 0; + void *rmsk; + size_t rmsk_len; if (!hdr) { l_debug("Auth frame header did not validate"); @@ -353,9 +350,13 @@ void fils_rx_authenticate(struct fils_sm *fils, const uint8_t *frame, memcpy(fils->anonce, anonce, FILS_NONCE_LEN); - erp_rx_packet(fils->erp, wrapped, wrapped_len); + if (erp_rx_packet(fils->erp, wrapped, wrapped_len) < 0) + goto auth_failed; + + erp_get_rmsk(fils->erp, &rmsk, &rmsk_len); + + fils_derive_key_data(fils, rmsk, rmsk_len); - /* EAP should now call the key materials callback, giving us the rMSK */ return; auth_failed: