xref: /freebsd-src/contrib/wpa/src/eap_common/eap_fast_common.c (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
1*39beb93cSSam Leffler /*
2*39beb93cSSam Leffler  * EAP-FAST common helper functions (RFC 4851)
3*39beb93cSSam Leffler  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
4*39beb93cSSam Leffler  *
5*39beb93cSSam Leffler  * This program is free software; you can redistribute it and/or modify
6*39beb93cSSam Leffler  * it under the terms of the GNU General Public License version 2 as
7*39beb93cSSam Leffler  * published by the Free Software Foundation.
8*39beb93cSSam Leffler  *
9*39beb93cSSam Leffler  * Alternatively, this software may be distributed under the terms of BSD
10*39beb93cSSam Leffler  * license.
11*39beb93cSSam Leffler  *
12*39beb93cSSam Leffler  * See README and COPYING for more details.
13*39beb93cSSam Leffler  */
14*39beb93cSSam Leffler 
15*39beb93cSSam Leffler #include "includes.h"
16*39beb93cSSam Leffler 
17*39beb93cSSam Leffler #include "common.h"
18*39beb93cSSam Leffler #include "sha1.h"
19*39beb93cSSam Leffler #include "tls.h"
20*39beb93cSSam Leffler #include "eap_defs.h"
21*39beb93cSSam Leffler #include "eap_tlv_common.h"
22*39beb93cSSam Leffler #include "eap_fast_common.h"
23*39beb93cSSam Leffler 
24*39beb93cSSam Leffler 
25*39beb93cSSam Leffler void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
26*39beb93cSSam Leffler {
27*39beb93cSSam Leffler 	struct pac_tlv_hdr hdr;
28*39beb93cSSam Leffler 	hdr.type = host_to_be16(type);
29*39beb93cSSam Leffler 	hdr.len = host_to_be16(len);
30*39beb93cSSam Leffler 	wpabuf_put_data(buf, &hdr, sizeof(hdr));
31*39beb93cSSam Leffler }
32*39beb93cSSam Leffler 
33*39beb93cSSam Leffler 
34*39beb93cSSam Leffler void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
35*39beb93cSSam Leffler 			     u16 len)
36*39beb93cSSam Leffler {
37*39beb93cSSam Leffler 	eap_fast_put_tlv_hdr(buf, type, len);
38*39beb93cSSam Leffler 	wpabuf_put_data(buf, data, len);
39*39beb93cSSam Leffler }
40*39beb93cSSam Leffler 
41*39beb93cSSam Leffler 
42*39beb93cSSam Leffler void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
43*39beb93cSSam Leffler 				 const struct wpabuf *data)
44*39beb93cSSam Leffler {
45*39beb93cSSam Leffler 	eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data));
46*39beb93cSSam Leffler 	wpabuf_put_buf(buf, data);
47*39beb93cSSam Leffler }
48*39beb93cSSam Leffler 
49*39beb93cSSam Leffler 
50*39beb93cSSam Leffler struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
51*39beb93cSSam Leffler {
52*39beb93cSSam Leffler 	struct wpabuf *e;
53*39beb93cSSam Leffler 
54*39beb93cSSam Leffler 	if (buf == NULL)
55*39beb93cSSam Leffler 		return NULL;
56*39beb93cSSam Leffler 
57*39beb93cSSam Leffler 	/* Encapsulate EAP packet in EAP-Payload TLV */
58*39beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
59*39beb93cSSam Leffler 	e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf));
60*39beb93cSSam Leffler 	if (e == NULL) {
61*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
62*39beb93cSSam Leffler 			   "for TLV encapsulation");
63*39beb93cSSam Leffler 		wpabuf_free(buf);
64*39beb93cSSam Leffler 		return NULL;
65*39beb93cSSam Leffler 	}
66*39beb93cSSam Leffler 	eap_fast_put_tlv_buf(e,
67*39beb93cSSam Leffler 			     EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV,
68*39beb93cSSam Leffler 			     buf);
69*39beb93cSSam Leffler 	wpabuf_free(buf);
70*39beb93cSSam Leffler 	return e;
71*39beb93cSSam Leffler }
72*39beb93cSSam Leffler 
73*39beb93cSSam Leffler 
74*39beb93cSSam Leffler void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
75*39beb93cSSam Leffler 				   const u8 *client_random, u8 *master_secret)
76*39beb93cSSam Leffler {
77*39beb93cSSam Leffler #define TLS_RANDOM_LEN 32
78*39beb93cSSam Leffler #define TLS_MASTER_SECRET_LEN 48
79*39beb93cSSam Leffler 	u8 seed[2 * TLS_RANDOM_LEN];
80*39beb93cSSam Leffler 
81*39beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
82*39beb93cSSam Leffler 		    client_random, TLS_RANDOM_LEN);
83*39beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
84*39beb93cSSam Leffler 		    server_random, TLS_RANDOM_LEN);
85*39beb93cSSam Leffler 
86*39beb93cSSam Leffler 	/*
87*39beb93cSSam Leffler 	 * RFC 4851, Section 5.1:
88*39beb93cSSam Leffler 	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
89*39beb93cSSam Leffler 	 *                       server_random + client_random, 48)
90*39beb93cSSam Leffler 	 */
91*39beb93cSSam Leffler 	os_memcpy(seed, server_random, TLS_RANDOM_LEN);
92*39beb93cSSam Leffler 	os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
93*39beb93cSSam Leffler 	sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
94*39beb93cSSam Leffler 		   "PAC to master secret label hash",
95*39beb93cSSam Leffler 		   seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
96*39beb93cSSam Leffler 
97*39beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
98*39beb93cSSam Leffler 			master_secret, TLS_MASTER_SECRET_LEN);
99*39beb93cSSam Leffler }
100*39beb93cSSam Leffler 
101*39beb93cSSam Leffler 
102*39beb93cSSam Leffler u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
103*39beb93cSSam Leffler 			 const char *label, size_t len)
104*39beb93cSSam Leffler {
105*39beb93cSSam Leffler 	struct tls_keys keys;
106*39beb93cSSam Leffler 	u8 *rnd = NULL, *out;
107*39beb93cSSam Leffler 	int block_size;
108*39beb93cSSam Leffler 
109*39beb93cSSam Leffler 	block_size = tls_connection_get_keyblock_size(ssl_ctx, conn);
110*39beb93cSSam Leffler 	if (block_size < 0)
111*39beb93cSSam Leffler 		return NULL;
112*39beb93cSSam Leffler 
113*39beb93cSSam Leffler 	out = os_malloc(block_size + len);
114*39beb93cSSam Leffler 	if (out == NULL)
115*39beb93cSSam Leffler 		return NULL;
116*39beb93cSSam Leffler 
117*39beb93cSSam Leffler 	if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len)
118*39beb93cSSam Leffler 	    == 0) {
119*39beb93cSSam Leffler 		os_memmove(out, out + block_size, len);
120*39beb93cSSam Leffler 		return out;
121*39beb93cSSam Leffler 	}
122*39beb93cSSam Leffler 
123*39beb93cSSam Leffler 	if (tls_connection_get_keys(ssl_ctx, conn, &keys))
124*39beb93cSSam Leffler 		goto fail;
125*39beb93cSSam Leffler 
126*39beb93cSSam Leffler 	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
127*39beb93cSSam Leffler 	if (rnd == NULL)
128*39beb93cSSam Leffler 		goto fail;
129*39beb93cSSam Leffler 
130*39beb93cSSam Leffler 	os_memcpy(rnd, keys.server_random, keys.server_random_len);
131*39beb93cSSam Leffler 	os_memcpy(rnd + keys.server_random_len, keys.client_random,
132*39beb93cSSam Leffler 		  keys.client_random_len);
133*39beb93cSSam Leffler 
134*39beb93cSSam Leffler 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
135*39beb93cSSam Leffler 			"expansion", keys.master_key, keys.master_key_len);
136*39beb93cSSam Leffler 	if (tls_prf(keys.master_key, keys.master_key_len,
137*39beb93cSSam Leffler 		    label, rnd, keys.client_random_len +
138*39beb93cSSam Leffler 		    keys.server_random_len, out, block_size + len))
139*39beb93cSSam Leffler 		goto fail;
140*39beb93cSSam Leffler 	os_free(rnd);
141*39beb93cSSam Leffler 	os_memmove(out, out + block_size, len);
142*39beb93cSSam Leffler 	return out;
143*39beb93cSSam Leffler 
144*39beb93cSSam Leffler fail:
145*39beb93cSSam Leffler 	os_free(rnd);
146*39beb93cSSam Leffler 	os_free(out);
147*39beb93cSSam Leffler 	return NULL;
148*39beb93cSSam Leffler }
149*39beb93cSSam Leffler 
150*39beb93cSSam Leffler 
151*39beb93cSSam Leffler void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
152*39beb93cSSam Leffler {
153*39beb93cSSam Leffler 	/*
154*39beb93cSSam Leffler 	 * RFC 4851, Section 5.4: EAP Master Session Key Generation
155*39beb93cSSam Leffler 	 * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
156*39beb93cSSam Leffler 	 */
157*39beb93cSSam Leffler 
158*39beb93cSSam Leffler 	sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
159*39beb93cSSam Leffler 		   "Session Key Generating Function", (u8 *) "", 0,
160*39beb93cSSam Leffler 		   msk, EAP_FAST_KEY_LEN);
161*39beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
162*39beb93cSSam Leffler 			msk, EAP_FAST_KEY_LEN);
163*39beb93cSSam Leffler }
164*39beb93cSSam Leffler 
165*39beb93cSSam Leffler 
166*39beb93cSSam Leffler void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
167*39beb93cSSam Leffler {
168*39beb93cSSam Leffler 	/*
169*39beb93cSSam Leffler 	 * RFC 4851, Section 5.4: EAP Master Session Key Genreration
170*39beb93cSSam Leffler 	 * EMSK = T-PRF(S-IMCK[j],
171*39beb93cSSam Leffler 	 *        "Extended Session Key Generating Function", 64)
172*39beb93cSSam Leffler 	 */
173*39beb93cSSam Leffler 
174*39beb93cSSam Leffler 	sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
175*39beb93cSSam Leffler 		   "Extended Session Key Generating Function", (u8 *) "", 0,
176*39beb93cSSam Leffler 		   emsk, EAP_EMSK_LEN);
177*39beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
178*39beb93cSSam Leffler 			emsk, EAP_EMSK_LEN);
179*39beb93cSSam Leffler }
180*39beb93cSSam Leffler 
181*39beb93cSSam Leffler 
182*39beb93cSSam Leffler int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
183*39beb93cSSam Leffler 		       int tlv_type, u8 *pos, int len)
184*39beb93cSSam Leffler {
185*39beb93cSSam Leffler 	switch (tlv_type) {
186*39beb93cSSam Leffler 	case EAP_TLV_EAP_PAYLOAD_TLV:
187*39beb93cSSam Leffler 		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
188*39beb93cSSam Leffler 			    pos, len);
189*39beb93cSSam Leffler 		if (tlv->eap_payload_tlv) {
190*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
191*39beb93cSSam Leffler 				   "EAP-Payload TLV in the message");
192*39beb93cSSam Leffler 			tlv->iresult = EAP_TLV_RESULT_FAILURE;
193*39beb93cSSam Leffler 			return -2;
194*39beb93cSSam Leffler 		}
195*39beb93cSSam Leffler 		tlv->eap_payload_tlv = pos;
196*39beb93cSSam Leffler 		tlv->eap_payload_tlv_len = len;
197*39beb93cSSam Leffler 		break;
198*39beb93cSSam Leffler 	case EAP_TLV_RESULT_TLV:
199*39beb93cSSam Leffler 		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
200*39beb93cSSam Leffler 		if (tlv->result) {
201*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
202*39beb93cSSam Leffler 				   "Result TLV in the message");
203*39beb93cSSam Leffler 			tlv->result = EAP_TLV_RESULT_FAILURE;
204*39beb93cSSam Leffler 			return -2;
205*39beb93cSSam Leffler 		}
206*39beb93cSSam Leffler 		if (len < 2) {
207*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
208*39beb93cSSam Leffler 				   "Result TLV");
209*39beb93cSSam Leffler 			tlv->result = EAP_TLV_RESULT_FAILURE;
210*39beb93cSSam Leffler 			break;
211*39beb93cSSam Leffler 		}
212*39beb93cSSam Leffler 		tlv->result = WPA_GET_BE16(pos);
213*39beb93cSSam Leffler 		if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
214*39beb93cSSam Leffler 		    tlv->result != EAP_TLV_RESULT_FAILURE) {
215*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
216*39beb93cSSam Leffler 				   tlv->result);
217*39beb93cSSam Leffler 			tlv->result = EAP_TLV_RESULT_FAILURE;
218*39beb93cSSam Leffler 		}
219*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
220*39beb93cSSam Leffler 			   tlv->result == EAP_TLV_RESULT_SUCCESS ?
221*39beb93cSSam Leffler 			   "Success" : "Failure");
222*39beb93cSSam Leffler 		break;
223*39beb93cSSam Leffler 	case EAP_TLV_INTERMEDIATE_RESULT_TLV:
224*39beb93cSSam Leffler 		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
225*39beb93cSSam Leffler 			    pos, len);
226*39beb93cSSam Leffler 		if (len < 2) {
227*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
228*39beb93cSSam Leffler 				   "Intermediate-Result TLV");
229*39beb93cSSam Leffler 			tlv->iresult = EAP_TLV_RESULT_FAILURE;
230*39beb93cSSam Leffler 			break;
231*39beb93cSSam Leffler 		}
232*39beb93cSSam Leffler 		if (tlv->iresult) {
233*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
234*39beb93cSSam Leffler 				   "Intermediate-Result TLV in the message");
235*39beb93cSSam Leffler 			tlv->iresult = EAP_TLV_RESULT_FAILURE;
236*39beb93cSSam Leffler 			return -2;
237*39beb93cSSam Leffler 		}
238*39beb93cSSam Leffler 		tlv->iresult = WPA_GET_BE16(pos);
239*39beb93cSSam Leffler 		if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
240*39beb93cSSam Leffler 		    tlv->iresult != EAP_TLV_RESULT_FAILURE) {
241*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
242*39beb93cSSam Leffler 				   "Result %d", tlv->iresult);
243*39beb93cSSam Leffler 			tlv->iresult = EAP_TLV_RESULT_FAILURE;
244*39beb93cSSam Leffler 		}
245*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
246*39beb93cSSam Leffler 			   tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
247*39beb93cSSam Leffler 			   "Success" : "Failure");
248*39beb93cSSam Leffler 		break;
249*39beb93cSSam Leffler 	case EAP_TLV_CRYPTO_BINDING_TLV:
250*39beb93cSSam Leffler 		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
251*39beb93cSSam Leffler 			    pos, len);
252*39beb93cSSam Leffler 		if (tlv->crypto_binding) {
253*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
254*39beb93cSSam Leffler 				   "Crypto-Binding TLV in the message");
255*39beb93cSSam Leffler 			tlv->iresult = EAP_TLV_RESULT_FAILURE;
256*39beb93cSSam Leffler 			return -2;
257*39beb93cSSam Leffler 		}
258*39beb93cSSam Leffler 		tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
259*39beb93cSSam Leffler 		if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
260*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
261*39beb93cSSam Leffler 				   "Crypto-Binding TLV");
262*39beb93cSSam Leffler 			tlv->iresult = EAP_TLV_RESULT_FAILURE;
263*39beb93cSSam Leffler 			return -2;
264*39beb93cSSam Leffler 		}
265*39beb93cSSam Leffler 		tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *)
266*39beb93cSSam Leffler 			(pos - sizeof(struct eap_tlv_hdr));
267*39beb93cSSam Leffler 		break;
268*39beb93cSSam Leffler 	case EAP_TLV_REQUEST_ACTION_TLV:
269*39beb93cSSam Leffler 		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
270*39beb93cSSam Leffler 			    pos, len);
271*39beb93cSSam Leffler 		if (tlv->request_action) {
272*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
273*39beb93cSSam Leffler 				   "Request-Action TLV in the message");
274*39beb93cSSam Leffler 			tlv->iresult = EAP_TLV_RESULT_FAILURE;
275*39beb93cSSam Leffler 			return -2;
276*39beb93cSSam Leffler 		}
277*39beb93cSSam Leffler 		if (len < 2) {
278*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
279*39beb93cSSam Leffler 				   "Request-Action TLV");
280*39beb93cSSam Leffler 			tlv->iresult = EAP_TLV_RESULT_FAILURE;
281*39beb93cSSam Leffler 			break;
282*39beb93cSSam Leffler 		}
283*39beb93cSSam Leffler 		tlv->request_action = WPA_GET_BE16(pos);
284*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
285*39beb93cSSam Leffler 			   tlv->request_action);
286*39beb93cSSam Leffler 		break;
287*39beb93cSSam Leffler 	case EAP_TLV_PAC_TLV:
288*39beb93cSSam Leffler 		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
289*39beb93cSSam Leffler 		if (tlv->pac) {
290*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
291*39beb93cSSam Leffler 				   "PAC TLV in the message");
292*39beb93cSSam Leffler 			tlv->iresult = EAP_TLV_RESULT_FAILURE;
293*39beb93cSSam Leffler 			return -2;
294*39beb93cSSam Leffler 		}
295*39beb93cSSam Leffler 		tlv->pac = pos;
296*39beb93cSSam Leffler 		tlv->pac_len = len;
297*39beb93cSSam Leffler 		break;
298*39beb93cSSam Leffler 	default:
299*39beb93cSSam Leffler 		/* Unknown TLV */
300*39beb93cSSam Leffler 		return -1;
301*39beb93cSSam Leffler 	}
302*39beb93cSSam Leffler 
303*39beb93cSSam Leffler 	return 0;
304*39beb93cSSam Leffler }
305