18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP-FAST common helper functions (RFC 4851)
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha1.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/tls.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_defs.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_tlv_common.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_fast_common.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct pac_tlv_hdr hdr;
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr.type = host_to_be16(type);
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr.len = host_to_be16(len);
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(buf, &hdr, sizeof(hdr));
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     u16 len)
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_fast_put_tlv_hdr(buf, type, len);
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(buf, data, len);
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 const struct wpabuf *data)
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data));
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_buf(buf, data);
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *e;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Encapsulate EAP packet in EAP-Payload TLV */
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf));
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e == NULL) {
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "for TLV encapsulation");
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(buf);
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_fast_put_tlv_buf(e,
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV,
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     buf);
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(buf);
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return e;
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   const u8 *client_random, u8 *master_secret)
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define TLS_RANDOM_LEN 32
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define TLS_MASTER_SECRET_LEN 48
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 seed[2 * TLS_RANDOM_LEN];
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    client_random, TLS_RANDOM_LEN);
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    server_random, TLS_RANDOM_LEN);
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * RFC 4851, Section 5.1:
82293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                       server_random + client_random, 48)
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(seed, server_random, TLS_RANDOM_LEN);
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "PAC to master secret label hash",
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			master_secret, TLS_MASTER_SECRET_LEN);
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtu8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, size_t len)
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
98af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt	u8 *out;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
100af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt	out = os_malloc(len);
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (out == NULL)
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
104849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	if (tls_connection_get_eap_fast_key(ssl_ctx, conn, out, len)) {
105af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt		os_free(out);
106af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt		return NULL;
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return out;
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1131b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidtint eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * RFC 4851, Section 5.4: EAP Master Session Key Generation
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1201b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt	if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
1211b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt		       "Session Key Generating Function", (u8 *) "", 0,
1221b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt		       msk, EAP_FAST_KEY_LEN) < 0)
1231b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt		return -1;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			msk, EAP_FAST_KEY_LEN);
1261b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt	return 0;
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1301b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidtint eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * RFC 4851, Section 5.4: EAP Master Session Key Genreration
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * EMSK = T-PRF(S-IMCK[j],
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *        "Extended Session Key Generating Function", 64)
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1381b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt	if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
1391b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt		       "Extended Session Key Generating Function", (u8 *) "", 0,
1401b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt		       emsk, EAP_EMSK_LEN) < 0)
1411b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt		return -1;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			emsk, EAP_EMSK_LEN);
1441b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt	return 0;
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
1490c08fdcf5231617f2340cb18e45769a8ed3a1dc4Dmitry Shmidt		       int tlv_type, u8 *pos, size_t len)
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (tlv_type) {
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_TLV_EAP_PAYLOAD_TLV:
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    pos, len);
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tlv->eap_payload_tlv) {
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "EAP-Payload TLV in the message");
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->iresult = EAP_TLV_RESULT_FAILURE;
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -2;
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tlv->eap_payload_tlv = pos;
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tlv->eap_payload_tlv_len = len;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_TLV_RESULT_TLV:
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tlv->result) {
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Result TLV in the message");
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->result = EAP_TLV_RESULT_FAILURE;
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -2;
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 2) {
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Result TLV");
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->result = EAP_TLV_RESULT_FAILURE;
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tlv->result = WPA_GET_BE16(pos);
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    tlv->result != EAP_TLV_RESULT_FAILURE) {
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   tlv->result);
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->result = EAP_TLV_RESULT_FAILURE;
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   tlv->result == EAP_TLV_RESULT_SUCCESS ?
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Success" : "Failure");
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_TLV_INTERMEDIATE_RESULT_TLV:
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    pos, len);
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 2) {
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Intermediate-Result TLV");
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->iresult = EAP_TLV_RESULT_FAILURE;
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tlv->iresult) {
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Intermediate-Result TLV in the message");
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->iresult = EAP_TLV_RESULT_FAILURE;
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -2;
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tlv->iresult = WPA_GET_BE16(pos);
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    tlv->iresult != EAP_TLV_RESULT_FAILURE) {
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Result %d", tlv->iresult);
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->iresult = EAP_TLV_RESULT_FAILURE;
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Success" : "Failure");
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_TLV_CRYPTO_BINDING_TLV:
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    pos, len);
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tlv->crypto_binding) {
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Crypto-Binding TLV in the message");
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->iresult = EAP_TLV_RESULT_FAILURE;
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -2;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Crypto-Binding TLV");
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->iresult = EAP_TLV_RESULT_FAILURE;
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -2;
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *)
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			(pos - sizeof(struct eap_tlv_hdr));
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_TLV_REQUEST_ACTION_TLV:
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    pos, len);
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tlv->request_action) {
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Request-Action TLV in the message");
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->iresult = EAP_TLV_RESULT_FAILURE;
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -2;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 2) {
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Request-Action TLV");
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->iresult = EAP_TLV_RESULT_FAILURE;
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tlv->request_action = WPA_GET_BE16(pos);
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   tlv->request_action);
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAP_TLV_PAC_TLV:
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tlv->pac) {
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "PAC TLV in the message");
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tlv->iresult = EAP_TLV_RESULT_FAILURE;
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -2;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tlv->pac = pos;
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tlv->pac_len = len;
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Unknown TLV */
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
271