eap_common.c 7.3 KB

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