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