Home | History | Annotate | Download | only in eap_common
      1 /*
      2  * EAP common peer/server definitions
      3  * Copyright (c) 2004-2012, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 
     11 #include "common.h"
     12 #include "eap_defs.h"
     13 #include "eap_common.h"
     14 
     15 /**
     16  * eap_hdr_len_valid - Validate EAP header length field
     17  * @msg: EAP frame (starting with EAP header)
     18  * @min_payload: Minimum payload length needed
     19  * Returns: 1 for valid header, 0 for invalid
     20  *
     21  * This is a helper function that does minimal validation of EAP messages. The
     22  * length field is verified to be large enough to include the header and not
     23  * too large to go beyond the end of the buffer.
     24  */
     25 int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)
     26 {
     27 	const struct eap_hdr *hdr;
     28 	size_t len;
     29 
     30 	if (msg == NULL)
     31 		return 0;
     32 
     33 	hdr = wpabuf_head(msg);
     34 
     35 	if (wpabuf_len(msg) < sizeof(*hdr)) {
     36 		wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
     37 		return 0;
     38 	}
     39 
     40 	len = be_to_host16(hdr->length);
     41 	if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) {
     42 		wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
     43 		return 0;
     44 	}
     45 
     46 	return 1;
     47 }
     48 
     49 
     50 /**
     51  * eap_hdr_validate - Validate EAP header
     52  * @vendor: Expected EAP Vendor-Id (0 = IETF)
     53  * @eap_type: Expected EAP type number
     54  * @msg: EAP frame (starting with EAP header)
     55  * @plen: Pointer to variable to contain the returned payload length
     56  * Returns: Pointer to EAP payload (after type field), or %NULL on failure
     57  *
     58  * This is a helper function for EAP method implementations. This is usually
     59  * called in the beginning of struct eap_method::process() function to verify
     60  * that the received EAP request packet has a valid header. This function is
     61  * able to process both legacy and expanded EAP headers and in most cases, the
     62  * caller can just use the returned payload pointer (into *plen) for processing
     63  * the payload regardless of whether the packet used the expanded EAP header or
     64  * not.
     65  */
     66 const u8 * eap_hdr_validate(int vendor, EapType eap_type,
     67 			    const struct wpabuf *msg, size_t *plen)
     68 {
     69 	const struct eap_hdr *hdr;
     70 	const u8 *pos;
     71 	size_t len;
     72 
     73 	if (!eap_hdr_len_valid(msg, 1))
     74 		return NULL;
     75 
     76 	hdr = wpabuf_head(msg);
     77 	len = be_to_host16(hdr->length);
     78 	pos = (const u8 *) (hdr + 1);
     79 
     80 	if (*pos == EAP_TYPE_EXPANDED) {
     81 		int exp_vendor;
     82 		u32 exp_type;
     83 		if (len < sizeof(*hdr) + 8) {
     84 			wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
     85 				   "length");
     86 			return NULL;
     87 		}
     88 		pos++;
     89 		exp_vendor = WPA_GET_BE24(pos);
     90 		pos += 3;
     91 		exp_type = WPA_GET_BE32(pos);
     92 		pos += 4;
     93 		if (exp_vendor != vendor || exp_type != (u32) eap_type) {
     94 			wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
     95 				   "type");
     96 			return NULL;
     97 		}
     98 
     99 		*plen = len - sizeof(*hdr) - 8;
    100 		return pos;
    101 	} else {
    102 		if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
    103 			wpa_printf(MSG_INFO, "EAP: Invalid frame type");
    104 			return NULL;
    105 		}
    106 		*plen = len - sizeof(*hdr) - 1;
    107 		return pos + 1;
    108 	}
    109 }
    110 
    111 
    112 /**
    113  * eap_msg_alloc - Allocate a buffer for an EAP message
    114  * @vendor: Vendor-Id (0 = IETF)
    115  * @type: EAP type
    116  * @payload_len: Payload length in bytes (data after Type)
    117  * @code: Message Code (EAP_CODE_*)
    118  * @identifier: Identifier
    119  * Returns: Pointer to the allocated message buffer or %NULL on error
    120  *
    121  * This function can be used to allocate a buffer for an EAP message and fill
    122  * in the EAP header. This function is automatically using expanded EAP header
    123  * if the selected Vendor-Id is not IETF. In other words, most EAP methods do
    124  * not need to separately select which header type to use when using this
    125  * function to allocate the message buffers. The returned buffer has room for
    126  * payload_len bytes and has the EAP header and Type field already filled in.
    127  */
    128 struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
    129 			      u8 code, u8 identifier)
    130 {
    131 	struct wpabuf *buf;
    132 	struct eap_hdr *hdr;
    133 	size_t len;
    134 
    135 	len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
    136 		payload_len;
    137 	buf = wpabuf_alloc(len);
    138 	if (buf == NULL)
    139 		return NULL;
    140 
    141 	hdr = wpabuf_put(buf, sizeof(*hdr));
    142 	hdr->code = code;
    143 	hdr->identifier = identifier;
    144 	hdr->length = host_to_be16(len);
    145 
    146 	if (vendor == EAP_VENDOR_IETF) {
    147 		wpabuf_put_u8(buf, type);
    148 	} else {
    149 		wpabuf_put_u8(buf, EAP_TYPE_EXPANDED);
    150 		wpabuf_put_be24(buf, vendor);
    151 		wpabuf_put_be32(buf, type);
    152 	}
    153 
    154 	return buf;
    155 }
    156 
    157 
    158 /**
    159  * eap_update_len - Update EAP header length
    160  * @msg: EAP message from eap_msg_alloc
    161  *
    162  * This function updates the length field in the EAP header to match with the
    163  * current length for the buffer. This allows eap_msg_alloc() to be used to
    164  * allocate a larger buffer than the exact message length (e.g., if exact
    165  * message length is not yet known).
    166  */
    167 void eap_update_len(struct wpabuf *msg)
    168 {
    169 	struct eap_hdr *hdr;
    170 	hdr = wpabuf_mhead(msg);
    171 	if (wpabuf_len(msg) < sizeof(*hdr))
    172 		return;
    173 	hdr->length = host_to_be16(wpabuf_len(msg));
    174 }
    175 
    176 
    177 /**
    178  * eap_get_id - Get EAP Identifier from wpabuf
    179  * @msg: Buffer starting with an EAP header
    180  * Returns: The Identifier field from the EAP header
    181  */
    182 u8 eap_get_id(const struct wpabuf *msg)
    183 {
    184 	const struct eap_hdr *eap;
    185 
    186 	if (wpabuf_len(msg) < sizeof(*eap))
    187 		return 0;
    188 
    189 	eap = wpabuf_head(msg);
    190 	return eap->identifier;
    191 }
    192 
    193 
    194 /**
    195  * eap_get_id - Get EAP Type from wpabuf
    196  * @msg: Buffer starting with an EAP header
    197  * Returns: The EAP Type after the EAP header
    198  */
    199 EapType eap_get_type(const struct wpabuf *msg)
    200 {
    201 	if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
    202 		return EAP_TYPE_NONE;
    203 
    204 	return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)];
    205 }
    206