139beb93cSSam Leffler /* 239beb93cSSam Leffler * EAP common peer/server definitions 3*f05cddf9SRui Paulo * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 1239beb93cSSam Leffler #include "eap_defs.h" 1339beb93cSSam Leffler #include "eap_common.h" 1439beb93cSSam Leffler 1539beb93cSSam Leffler /** 16*f05cddf9SRui Paulo * eap_hdr_len_valid - Validate EAP header length field 17*f05cddf9SRui Paulo * @msg: EAP frame (starting with EAP header) 18*f05cddf9SRui Paulo * @min_payload: Minimum payload length needed 19*f05cddf9SRui Paulo * Returns: 1 for valid header, 0 for invalid 20*f05cddf9SRui Paulo * 21*f05cddf9SRui Paulo * This is a helper function that does minimal validation of EAP messages. The 22*f05cddf9SRui Paulo * length field is verified to be large enough to include the header and not 23*f05cddf9SRui Paulo * too large to go beyond the end of the buffer. 24*f05cddf9SRui Paulo */ 25*f05cddf9SRui Paulo int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload) 26*f05cddf9SRui Paulo { 27*f05cddf9SRui Paulo const struct eap_hdr *hdr; 28*f05cddf9SRui Paulo size_t len; 29*f05cddf9SRui Paulo 30*f05cddf9SRui Paulo if (msg == NULL) 31*f05cddf9SRui Paulo return 0; 32*f05cddf9SRui Paulo 33*f05cddf9SRui Paulo hdr = wpabuf_head(msg); 34*f05cddf9SRui Paulo 35*f05cddf9SRui Paulo if (wpabuf_len(msg) < sizeof(*hdr)) { 36*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP: Too short EAP frame"); 37*f05cddf9SRui Paulo return 0; 38*f05cddf9SRui Paulo } 39*f05cddf9SRui Paulo 40*f05cddf9SRui Paulo len = be_to_host16(hdr->length); 41*f05cddf9SRui Paulo if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) { 42*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP: Invalid EAP length"); 43*f05cddf9SRui Paulo return 0; 44*f05cddf9SRui Paulo } 45*f05cddf9SRui Paulo 46*f05cddf9SRui Paulo return 1; 47*f05cddf9SRui Paulo } 48*f05cddf9SRui Paulo 49*f05cddf9SRui Paulo 50*f05cddf9SRui Paulo /** 5139beb93cSSam Leffler * eap_hdr_validate - Validate EAP header 5239beb93cSSam Leffler * @vendor: Expected EAP Vendor-Id (0 = IETF) 5339beb93cSSam Leffler * @eap_type: Expected EAP type number 5439beb93cSSam Leffler * @msg: EAP frame (starting with EAP header) 5539beb93cSSam Leffler * @plen: Pointer to variable to contain the returned payload length 5639beb93cSSam Leffler * Returns: Pointer to EAP payload (after type field), or %NULL on failure 5739beb93cSSam Leffler * 5839beb93cSSam Leffler * This is a helper function for EAP method implementations. This is usually 5939beb93cSSam Leffler * called in the beginning of struct eap_method::process() function to verify 6039beb93cSSam Leffler * that the received EAP request packet has a valid header. This function is 6139beb93cSSam Leffler * able to process both legacy and expanded EAP headers and in most cases, the 6239beb93cSSam Leffler * caller can just use the returned payload pointer (into *plen) for processing 6339beb93cSSam Leffler * the payload regardless of whether the packet used the expanded EAP header or 6439beb93cSSam Leffler * not. 6539beb93cSSam Leffler */ 6639beb93cSSam Leffler const u8 * eap_hdr_validate(int vendor, EapType eap_type, 6739beb93cSSam Leffler const struct wpabuf *msg, size_t *plen) 6839beb93cSSam Leffler { 6939beb93cSSam Leffler const struct eap_hdr *hdr; 7039beb93cSSam Leffler const u8 *pos; 7139beb93cSSam Leffler size_t len; 7239beb93cSSam Leffler 73*f05cddf9SRui Paulo if (!eap_hdr_len_valid(msg, 1)) 74*f05cddf9SRui Paulo return NULL; 75*f05cddf9SRui Paulo 7639beb93cSSam Leffler hdr = wpabuf_head(msg); 7739beb93cSSam Leffler len = be_to_host16(hdr->length); 7839beb93cSSam Leffler pos = (const u8 *) (hdr + 1); 7939beb93cSSam Leffler 8039beb93cSSam Leffler if (*pos == EAP_TYPE_EXPANDED) { 8139beb93cSSam Leffler int exp_vendor; 8239beb93cSSam Leffler u32 exp_type; 8339beb93cSSam Leffler if (len < sizeof(*hdr) + 8) { 8439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP " 8539beb93cSSam Leffler "length"); 8639beb93cSSam Leffler return NULL; 8739beb93cSSam Leffler } 8839beb93cSSam Leffler pos++; 8939beb93cSSam Leffler exp_vendor = WPA_GET_BE24(pos); 9039beb93cSSam Leffler pos += 3; 9139beb93cSSam Leffler exp_type = WPA_GET_BE32(pos); 9239beb93cSSam Leffler pos += 4; 9339beb93cSSam Leffler if (exp_vendor != vendor || exp_type != (u32) eap_type) { 9439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP: Invalid expanded frame " 9539beb93cSSam Leffler "type"); 9639beb93cSSam Leffler return NULL; 9739beb93cSSam Leffler } 9839beb93cSSam Leffler 9939beb93cSSam Leffler *plen = len - sizeof(*hdr) - 8; 10039beb93cSSam Leffler return pos; 10139beb93cSSam Leffler } else { 10239beb93cSSam Leffler if (vendor != EAP_VENDOR_IETF || *pos != eap_type) { 10339beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP: Invalid frame type"); 10439beb93cSSam Leffler return NULL; 10539beb93cSSam Leffler } 10639beb93cSSam Leffler *plen = len - sizeof(*hdr) - 1; 10739beb93cSSam Leffler return pos + 1; 10839beb93cSSam Leffler } 10939beb93cSSam Leffler } 11039beb93cSSam Leffler 11139beb93cSSam Leffler 11239beb93cSSam Leffler /** 11339beb93cSSam Leffler * eap_msg_alloc - Allocate a buffer for an EAP message 11439beb93cSSam Leffler * @vendor: Vendor-Id (0 = IETF) 11539beb93cSSam Leffler * @type: EAP type 11639beb93cSSam Leffler * @payload_len: Payload length in bytes (data after Type) 11739beb93cSSam Leffler * @code: Message Code (EAP_CODE_*) 11839beb93cSSam Leffler * @identifier: Identifier 11939beb93cSSam Leffler * Returns: Pointer to the allocated message buffer or %NULL on error 12039beb93cSSam Leffler * 12139beb93cSSam Leffler * This function can be used to allocate a buffer for an EAP message and fill 12239beb93cSSam Leffler * in the EAP header. This function is automatically using expanded EAP header 12339beb93cSSam Leffler * if the selected Vendor-Id is not IETF. In other words, most EAP methods do 12439beb93cSSam Leffler * not need to separately select which header type to use when using this 12539beb93cSSam Leffler * function to allocate the message buffers. The returned buffer has room for 12639beb93cSSam Leffler * payload_len bytes and has the EAP header and Type field already filled in. 12739beb93cSSam Leffler */ 12839beb93cSSam Leffler struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, 12939beb93cSSam Leffler u8 code, u8 identifier) 13039beb93cSSam Leffler { 13139beb93cSSam Leffler struct wpabuf *buf; 13239beb93cSSam Leffler struct eap_hdr *hdr; 13339beb93cSSam Leffler size_t len; 13439beb93cSSam Leffler 13539beb93cSSam Leffler len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) + 13639beb93cSSam Leffler payload_len; 13739beb93cSSam Leffler buf = wpabuf_alloc(len); 13839beb93cSSam Leffler if (buf == NULL) 13939beb93cSSam Leffler return NULL; 14039beb93cSSam Leffler 14139beb93cSSam Leffler hdr = wpabuf_put(buf, sizeof(*hdr)); 14239beb93cSSam Leffler hdr->code = code; 14339beb93cSSam Leffler hdr->identifier = identifier; 14439beb93cSSam Leffler hdr->length = host_to_be16(len); 14539beb93cSSam Leffler 14639beb93cSSam Leffler if (vendor == EAP_VENDOR_IETF) { 14739beb93cSSam Leffler wpabuf_put_u8(buf, type); 14839beb93cSSam Leffler } else { 14939beb93cSSam Leffler wpabuf_put_u8(buf, EAP_TYPE_EXPANDED); 15039beb93cSSam Leffler wpabuf_put_be24(buf, vendor); 15139beb93cSSam Leffler wpabuf_put_be32(buf, type); 15239beb93cSSam Leffler } 15339beb93cSSam Leffler 15439beb93cSSam Leffler return buf; 15539beb93cSSam Leffler } 15639beb93cSSam Leffler 15739beb93cSSam Leffler 15839beb93cSSam Leffler /** 15939beb93cSSam Leffler * eap_update_len - Update EAP header length 16039beb93cSSam Leffler * @msg: EAP message from eap_msg_alloc 16139beb93cSSam Leffler * 16239beb93cSSam Leffler * This function updates the length field in the EAP header to match with the 16339beb93cSSam Leffler * current length for the buffer. This allows eap_msg_alloc() to be used to 16439beb93cSSam Leffler * allocate a larger buffer than the exact message length (e.g., if exact 16539beb93cSSam Leffler * message length is not yet known). 16639beb93cSSam Leffler */ 16739beb93cSSam Leffler void eap_update_len(struct wpabuf *msg) 16839beb93cSSam Leffler { 16939beb93cSSam Leffler struct eap_hdr *hdr; 17039beb93cSSam Leffler hdr = wpabuf_mhead(msg); 17139beb93cSSam Leffler if (wpabuf_len(msg) < sizeof(*hdr)) 17239beb93cSSam Leffler return; 17339beb93cSSam Leffler hdr->length = host_to_be16(wpabuf_len(msg)); 17439beb93cSSam Leffler } 17539beb93cSSam Leffler 17639beb93cSSam Leffler 17739beb93cSSam Leffler /** 17839beb93cSSam Leffler * eap_get_id - Get EAP Identifier from wpabuf 17939beb93cSSam Leffler * @msg: Buffer starting with an EAP header 18039beb93cSSam Leffler * Returns: The Identifier field from the EAP header 18139beb93cSSam Leffler */ 18239beb93cSSam Leffler u8 eap_get_id(const struct wpabuf *msg) 18339beb93cSSam Leffler { 18439beb93cSSam Leffler const struct eap_hdr *eap; 18539beb93cSSam Leffler 18639beb93cSSam Leffler if (wpabuf_len(msg) < sizeof(*eap)) 18739beb93cSSam Leffler return 0; 18839beb93cSSam Leffler 18939beb93cSSam Leffler eap = wpabuf_head(msg); 19039beb93cSSam Leffler return eap->identifier; 19139beb93cSSam Leffler } 19239beb93cSSam Leffler 19339beb93cSSam Leffler 19439beb93cSSam Leffler /** 19539beb93cSSam Leffler * eap_get_id - Get EAP Type from wpabuf 19639beb93cSSam Leffler * @msg: Buffer starting with an EAP header 19739beb93cSSam Leffler * Returns: The EAP Type after the EAP header 19839beb93cSSam Leffler */ 19939beb93cSSam Leffler EapType eap_get_type(const struct wpabuf *msg) 20039beb93cSSam Leffler { 20139beb93cSSam Leffler if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1) 20239beb93cSSam Leffler return EAP_TYPE_NONE; 20339beb93cSSam Leffler 20439beb93cSSam Leffler return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)]; 20539beb93cSSam Leffler } 206