diff options
Diffstat (limited to 'contrib/wpa_supplicant/eap_psk.c')
-rw-r--r-- | contrib/wpa_supplicant/eap_psk.c | 262 |
1 files changed, 69 insertions, 193 deletions
diff --git a/contrib/wpa_supplicant/eap_psk.c b/contrib/wpa_supplicant/eap_psk.c index 3b325b5..853c79a 100644 --- a/contrib/wpa_supplicant/eap_psk.c +++ b/contrib/wpa_supplicant/eap_psk.c @@ -1,5 +1,5 @@ /* - * WPA Supplicant / EAP-PSK (draft-bersani-eap-psk-05.txt) + * WPA Supplicant / EAP-PSK (draft-bersani-eap-psk-09.txt) * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> * * This program is free software; you can redistribute it and/or modify @@ -10,6 +10,9 @@ * license. * * See README and COPYING for more details. + * + * Note: EAP-PSK is an EAP authentication method and as such, completely + * different from WPA-PSK. This file is not needed for WPA-PSK functionality. */ #include <stdlib.h> @@ -22,128 +25,19 @@ #include "config_ssid.h" #include "md5.h" #include "aes_wrap.h" - - -/* draft-bersani-eap-psk-03.txt mode. This is retained for interop testing and - * will be removed once an AS that supports draft5 becomes available. */ -#define EAP_PSK_DRAFT3 - -#define EAP_PSK_RAND_LEN 16 -#define EAP_PSK_MAC_LEN 16 -#define EAP_PSK_TEK_LEN 16 -#define EAP_PSK_MSK_LEN 64 - -#define EAP_PSK_R_FLAG_CONT 1 -#define EAP_PSK_R_FLAG_DONE_SUCCESS 2 -#define EAP_PSK_R_FLAG_DONE_FAILURE 3 - -/* EAP-PSK First Message (AS -> Supplicant) */ -struct eap_psk_hdr_1 { - u8 code; - u8 identifier; - u16 length; /* including code, identifier, and length */ - u8 type; /* EAP_TYPE_PSK */ -#ifndef EAP_PSK_DRAFT3 - u8 flags; -#endif /* EAP_PSK_DRAFT3 */ - u8 rand_s[EAP_PSK_RAND_LEN]; -#ifndef EAP_PSK_DRAFT3 - /* Followed by variable length ID_S */ -#endif /* EAP_PSK_DRAFT3 */ -} __attribute__ ((packed)); - -/* EAP-PSK Second Message (Supplicant -> AS) */ -struct eap_psk_hdr_2 { - u8 code; - u8 identifier; - u16 length; /* including code, identifier, and length */ - u8 type; /* EAP_TYPE_PSK */ -#ifndef EAP_PSK_DRAFT3 - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; -#endif /* EAP_PSK_DRAFT3 */ - u8 rand_p[EAP_PSK_RAND_LEN]; - u8 mac_p[EAP_PSK_MAC_LEN]; - /* Followed by variable length ID_P */ -} __attribute__ ((packed)); - -/* EAP-PSK Third Message (AS -> Supplicant) */ -struct eap_psk_hdr_3 { - u8 code; - u8 identifier; - u16 length; /* including code, identifier, and length */ - u8 type; /* EAP_TYPE_PSK */ -#ifndef EAP_PSK_DRAFT3 - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; -#endif /* EAP_PSK_DRAFT3 */ - u8 mac_s[EAP_PSK_MAC_LEN]; - /* Followed by variable length PCHANNEL */ -} __attribute__ ((packed)); - -/* EAP-PSK Fourth Message (Supplicant -> AS) */ -struct eap_psk_hdr_4 { - u8 code; - u8 identifier; - u16 length; /* including code, identifier, and length */ - u8 type; /* EAP_TYPE_PSK */ -#ifndef EAP_PSK_DRAFT3 - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; -#endif /* EAP_PSK_DRAFT3 */ - /* Followed by variable length PCHANNEL */ -} __attribute__ ((packed)); - +#include "eap_psk_common.h" struct eap_psk_data { enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state; - u8 rand_s[EAP_PSK_RAND_LEN]; u8 rand_p[EAP_PSK_RAND_LEN]; - u8 ak[16], kdk[16], tek[EAP_PSK_TEK_LEN]; + u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN]; u8 *id_s, *id_p; size_t id_s_len, id_p_len; u8 key_data[EAP_PSK_MSK_LEN]; }; -#define aes_block_size 16 - - -static void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk) -{ - memset(ak, 0, aes_block_size); - aes_128_encrypt_block(psk, ak, ak); - memcpy(kdk, ak, aes_block_size); - ak[aes_block_size - 1] ^= 0x01; - kdk[aes_block_size - 1] ^= 0x02; - aes_128_encrypt_block(psk, ak, ak); - aes_128_encrypt_block(psk, kdk, kdk); -} - - -static void eap_psk_derive_keys(const u8 *kdk, const u8 *rb, u8 *tek, u8 *msk) -{ - u8 hash[aes_block_size]; - u8 counter = 1; - int i; - - aes_128_encrypt_block(kdk, rb, hash); - - hash[aes_block_size - 1] ^= counter; - aes_128_encrypt_block(kdk, hash, tek); - hash[aes_block_size - 1] ^= counter; - counter++; - - for (i = 0; i < EAP_PSK_MSK_LEN / aes_block_size; i++) { - hash[aes_block_size - 1] ^= counter; - aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]); - hash[aes_block_size - 1] ^= counter; - counter++; - } -} - - static void * eap_psk_init(struct eap_sm *sm) { struct wpa_ssid *config = eap_get_config(sm); @@ -159,8 +53,8 @@ static void * eap_psk_init(struct eap_sm *sm) return NULL; memset(data, 0, sizeof(*data)); eap_psk_key_setup(config->eappsk, data->ak, data->kdk); - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, 16); - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, 16); + wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); + wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); data->state = PSK_INIT; if (config->nai) { @@ -175,22 +69,6 @@ static void * eap_psk_init(struct eap_sm *sm) return NULL; } -#ifdef EAP_PSK_DRAFT3 - if (config->server_nai) { - data->id_s = malloc(config->server_nai_len); - if (data->id_s) - memcpy(data->id_s, config->server_nai, - config->server_nai_len); - data->id_s_len = config->server_nai_len; - } - if (data->id_s == NULL) { - wpa_printf(MSG_INFO, "EAP-PSK: could not get server identity"); - free(data->id_p); - free(data); - return NULL; - } -#endif /* EAP_PSK_DRAFT3 */ - return data; } @@ -206,17 +84,17 @@ static void eap_psk_deinit(struct eap_sm *sm, void *priv) static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data, struct eap_method_ret *ret, - u8 *reqData, size_t reqDataLen, + const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { - struct eap_psk_hdr_1 *hdr1; + const struct eap_psk_hdr_1 *hdr1; struct eap_psk_hdr_2 *hdr2; u8 *resp, *buf, *pos; size_t buflen; wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state"); - hdr1 = (struct eap_psk_hdr_1 *) reqData; + hdr1 = (const struct eap_psk_hdr_1 *) reqData; if (reqDataLen < sizeof(*hdr1) || be_to_host16(hdr1->length) < sizeof(*hdr1) || be_to_host16(hdr1->length) > reqDataLen) { @@ -228,7 +106,6 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data, ret->ignore = TRUE; return NULL; } -#ifndef EAP_PSK_DRAFT3 wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags); if ((hdr1->flags & 0x03) != 0) { wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)", @@ -237,24 +114,20 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data, ret->decision = DECISION_FAIL; return NULL; } -#endif /* EAP_PSK_DRAFT3 */ wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s, EAP_PSK_RAND_LEN); - memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); -#ifndef EAP_PSK_DRAFT3 free(data->id_s); data->id_s_len = be_to_host16(hdr1->length) - sizeof(*hdr1); data->id_s = malloc(data->id_s_len); if (data->id_s == NULL) { wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for " - "ID_S (len=%d)", data->id_s_len); + "ID_S (len=%lu)", (unsigned long) data->id_s_len); ret->ignore = TRUE; return NULL; } memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len); wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S", data->id_s, data->id_s_len); -#endif /* EAP_PSK_DRAFT3 */ if (hostapd_get_rand(data->rand_p, EAP_PSK_RAND_LEN)) { wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); @@ -271,10 +144,8 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data, hdr2->identifier = hdr1->identifier; hdr2->length = host_to_be16(*respDataLen); hdr2->type = EAP_TYPE_PSK; -#ifndef EAP_PSK_DRAFT3 hdr2->flags = 1; /* T=1 */ memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); -#endif /* EAP_PSK_DRAFT3 */ memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN); memcpy((u8 *) (hdr2 + 1), data->id_p, data->id_p_len); /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ @@ -288,7 +159,7 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data, pos = buf + data->id_p_len; memcpy(pos, data->id_s, data->id_s_len); pos += data->id_s_len; - memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN); + memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN); pos += EAP_PSK_RAND_LEN; memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p); @@ -307,19 +178,20 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data, static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data, struct eap_method_ret *ret, - u8 *reqData, size_t reqDataLen, + const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { - struct eap_psk_hdr_3 *hdr3; + const struct eap_psk_hdr_3 *hdr3; struct eap_psk_hdr_4 *hdr4; - u8 *resp, *buf, *pchannel, *tag, *msg, nonce[16]; + u8 *resp, *buf, *rpchannel, nonce[16], *decrypted; + const u8 *pchannel, *tag, *msg; u8 mac[EAP_PSK_MAC_LEN]; - size_t buflen, left; + size_t buflen, left, data_len; int failed = 0; wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state"); - hdr3 = (struct eap_psk_hdr_3 *) reqData; + hdr3 = (const struct eap_psk_hdr_3 *) reqData; left = be_to_host16(hdr3->length); if (left < sizeof(*hdr3) || reqDataLen < left) { wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message " @@ -331,8 +203,7 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data, return NULL; } left -= sizeof(*hdr3); - pchannel = (u8 *) (hdr3 + 1); -#ifndef EAP_PSK_DRAFT3 + pchannel = (const u8 *) (hdr3 + 1); wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags); if ((hdr3->flags & 0x03) != 2) { wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)", @@ -343,16 +214,6 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data, } wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s, EAP_PSK_RAND_LEN); - /* TODO: would not need to store RAND_S since it is available in this - * message. For now, since we store this anyway, verify that it matches - * with whatever the server is sending. */ - if (memcmp(hdr3->rand_s, data->rand_s, EAP_PSK_RAND_LEN) != 0) { - wpa_printf(MSG_ERROR, "EAP-PSK: RAND_S did not match"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return NULL; - } -#endif /* EAP_PSK_DRAFT3 */ wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN); wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left); @@ -404,25 +265,29 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data, wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", reqData, 5); wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left); -#ifdef EAP_PSK_DRAFT3 - if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), - reqData, 5, msg, left, tag)) -#else /* EAP_PSK_DRAFT3 */ + decrypted = malloc(left); + if (decrypted == NULL) { + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + return NULL; + } + memcpy(decrypted, msg, left); + if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), - reqData, 22, msg, left, tag)) -#endif /* EAP_PSK_DRAFT3 */ - { + reqData, 22, decrypted, left, tag)) { wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); + free(decrypted); return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", - msg, left); + decrypted, left); /* Verify R flag */ - switch (msg[0] >> 6) { + switch (decrypted[0] >> 6) { case EAP_PSK_R_FLAG_CONT: wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); - return NULL; + failed = 1; + break; case EAP_PSK_R_FLAG_DONE_SUCCESS: wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); break; @@ -435,37 +300,48 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data, } *respDataLen = sizeof(*hdr4) + 4 + 16 + 1; - resp = malloc(*respDataLen); - if (resp == NULL) + resp = malloc(*respDataLen + 1); + if (resp == NULL) { + free(decrypted); return NULL; + } hdr4 = (struct eap_psk_hdr_4 *) resp; hdr4->code = EAP_CODE_RESPONSE; hdr4->identifier = hdr3->identifier; hdr4->length = host_to_be16(*respDataLen); hdr4->type = EAP_TYPE_PSK; -#ifndef EAP_PSK_DRAFT3 hdr4->flags = 3; /* T=3 */ memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN); -#endif /* EAP_PSK_DRAFT3 */ - pchannel = (u8 *) (hdr4 + 1); + rpchannel = (u8 *) (hdr4 + 1); /* nonce++ */ inc_byte_array(nonce, sizeof(nonce)); - memcpy(pchannel, nonce + 12, 4); + memcpy(rpchannel, nonce + 12, 4); - pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; + data_len = 1; + if (decrypted[0] & EAP_PSK_E_FLAG) { + wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag"); + failed = 1; + rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) | + EAP_PSK_E_FLAG; + if (left > 1) { + /* Add empty EXT_Payload with same EXT_Type */ + (*respDataLen)++; + hdr4->length = host_to_be16(*respDataLen); + rpchannel[4 + 16 + 1] = decrypted[1]; + data_len++; + } + } else if (failed) + rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6; + else + rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)", - pchannel + 4 + 16, 1); -#ifdef EAP_PSK_DRAFT3 - aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 5, - pchannel + 4 + 16, 1, pchannel + 4); -#else /* EAP_PSK_DRAFT3 */ + rpchannel + 4 + 16, data_len); aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 22, - pchannel + 4 + 16, 1, pchannel + 4); -#endif /* EAP_PSK_DRAFT3 */ + rpchannel + 4 + 16, data_len, rpchannel + 4); wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)", - pchannel, 4 + 16 + 1); + rpchannel, 4 + 16 + data_len); wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully", failed ? "un" : ""); @@ -473,31 +349,31 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data, ret->methodState = METHOD_DONE; ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC; + free(decrypted); + return resp; } static u8 * eap_psk_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, - u8 *reqData, size_t reqDataLen, + const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { struct eap_psk_data *data = priv; - struct eap_hdr *req; - u8 *pos, *resp = NULL; + const u8 *pos; + u8 *resp = NULL; size_t len; - req = (struct eap_hdr *) reqData; - pos = (u8 *) (req + 1); - if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_PSK || - (len = be_to_host16(req->length)) > reqDataLen) { - wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame"); + pos = eap_hdr_validate(EAP_TYPE_PSK, reqData, reqDataLen, &len); + if (pos == NULL) { ret->ignore = TRUE; return NULL; } + len += sizeof(struct eap_hdr) + 1; ret->ignore = FALSE; - ret->methodState = METHOD_CONT; + ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = TRUE; |