1 /*
2  * EAP-TEAP common helper functions (RFC 7170)
3  * Copyright (c) 2008-2019, 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 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "crypto/sha1.h"
13 #include "crypto/sha256.h"
14 #include "crypto/sha384.h"
15 #include "crypto/tls.h"
16 #include "eap_defs.h"
17 #include "eap_teap_common.h"
18 
19 
20 static int tls_cipher_suite_mac_sha384(u16 cs);
21 
22 
eap_teap_put_tlv_hdr(struct wpabuf * buf,u16 type,u16 len)23 void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
24 {
25 	struct teap_tlv_hdr hdr;
26 
27 	hdr.tlv_type = host_to_be16(type);
28 	hdr.length = host_to_be16(len);
29 	wpabuf_put_data(buf, &hdr, sizeof(hdr));
30 }
31 
32 
eap_teap_put_tlv(struct wpabuf * buf,u16 type,const void * data,u16 len)33 void eap_teap_put_tlv(struct wpabuf *buf, u16 type, const void *data, u16 len)
34 {
35 	eap_teap_put_tlv_hdr(buf, type, len);
36 	wpabuf_put_data(buf, data, len);
37 }
38 
39 
eap_teap_put_tlv_buf(struct wpabuf * buf,u16 type,const struct wpabuf * data)40 void eap_teap_put_tlv_buf(struct wpabuf *buf, u16 type,
41 			  const struct wpabuf *data)
42 {
43 	eap_teap_put_tlv_hdr(buf, type, wpabuf_len(data));
44 	wpabuf_put_buf(buf, data);
45 }
46 
47 
eap_teap_tlv_eap_payload(struct wpabuf * buf)48 struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf)
49 {
50 	struct wpabuf *e;
51 
52 	if (!buf)
53 		return NULL;
54 
55 	/* Encapsulate EAP packet in EAP-Payload TLV */
56 	wpa_printf(MSG_DEBUG, "EAP-TEAP: Add EAP-Payload TLV");
57 	e = wpabuf_alloc(sizeof(struct teap_tlv_hdr) + wpabuf_len(buf));
58 	if (!e) {
59 		wpa_printf(MSG_ERROR,
60 			   "EAP-TEAP: Failed to allocate memory for TLV encapsulation");
61 		wpabuf_free(buf);
62 		return NULL;
63 	}
64 	eap_teap_put_tlv_buf(e, TEAP_TLV_MANDATORY | TEAP_TLV_EAP_PAYLOAD, buf);
65 	wpabuf_free(buf);
66 
67 	/* TODO: followed by optional TLVs associated with the EAP packet */
68 
69 	return e;
70 }
71 
72 
eap_teap_tls_prf(u16 tls_cs,const u8 * secret,size_t secret_len,const char * label,const u8 * seed,size_t seed_len,u8 * out,size_t outlen)73 static int eap_teap_tls_prf(u16 tls_cs, const u8 *secret, size_t secret_len,
74 			    const char *label, const u8 *seed, size_t seed_len,
75 			    u8 *out, size_t outlen)
76 {
77 	/* TODO: TLS-PRF for TLSv1.3 */
78 	if (tls_cipher_suite_mac_sha384(tls_cs))
79 		return tls_prf_sha384(secret, secret_len, label, seed, seed_len,
80 				      out, outlen);
81 	return tls_prf_sha256(secret, secret_len, label, seed, seed_len,
82 			      out, outlen);
83 }
84 
85 
eap_teap_derive_eap_msk(u16 tls_cs,const u8 * simck,u8 * msk)86 int eap_teap_derive_eap_msk(u16 tls_cs, const u8 *simck, u8 *msk)
87 {
88 	/*
89 	 * RFC 7170, Section 5.4: EAP Master Session Key Generation
90 	 * MSK = TLS-PRF(S-IMCK[j], "Session Key Generating Function", 64)
91 	 */
92 
93 	if (eap_teap_tls_prf(tls_cs, simck, EAP_TEAP_SIMCK_LEN,
94 			     "Session Key Generating Function", (u8 *) "", 0,
95 			     msk, EAP_TEAP_KEY_LEN) < 0)
96 		return -1;
97 	wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Derived key (MSK)",
98 			msk, EAP_TEAP_KEY_LEN);
99 	return 0;
100 }
101 
102 
eap_teap_derive_eap_emsk(u16 tls_cs,const u8 * simck,u8 * emsk)103 int eap_teap_derive_eap_emsk(u16 tls_cs, const u8 *simck, u8 *emsk)
104 {
105 	/*
106 	 * RFC 7170, Section 5.4: EAP Master Session Key Generation
107 	 * EMSK = TLS-PRF(S-IMCK[j],
108 	 *        "Extended Session Key Generating Function", 64)
109 	 */
110 
111 	if (eap_teap_tls_prf(tls_cs, simck, EAP_TEAP_SIMCK_LEN,
112 			     "Extended Session Key Generating Function",
113 			     (u8 *) "", 0, emsk, EAP_EMSK_LEN) < 0)
114 		return -1;
115 	wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Derived key (EMSK)",
116 			emsk, EAP_EMSK_LEN);
117 	return 0;
118 }
119 
120 
eap_teap_derive_imck(u16 tls_cs,const u8 * prev_s_imck,const u8 * msk,size_t msk_len,const u8 * emsk,size_t emsk_len,u8 * s_imck_msk,u8 * cmk_msk,u8 * s_imck_emsk,u8 * cmk_emsk)121 int eap_teap_derive_imck(u16 tls_cs, const u8 *prev_s_imck,
122 			 const u8 *msk, size_t msk_len,
123 			 const u8 *emsk, size_t emsk_len,
124 			 u8 *s_imck_msk, u8 *cmk_msk,
125 			 u8 *s_imck_emsk, u8 *cmk_emsk)
126 {
127 	u8 imsk[64], imck[EAP_TEAP_IMCK_LEN];
128 	int res;
129 
130 	/*
131 	 * RFC 7170, Section 5.2:
132 	 * IMSK = First 32 octets of TLS-PRF(EMSK, "TEAPbindkey@ietf.org" |
133 	 *                                   "\0" | 64)
134 	 * (if EMSK is not available, MSK is used instead; if neither is
135 	 * available, IMSK is 32 octets of zeros; MSK is truncated to 32 octets
136 	 * or padded to 32 octets, if needed)
137 	 * (64 is encoded as a 2-octet field in network byte order)
138 	 *
139 	 * S-IMCK[0] = session_key_seed
140 	 * IMCK[j] = TLS-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
141 	 *                   IMSK[j], 60)
142 	 * S-IMCK[j] = first 40 octets of IMCK[j]
143 	 * CMK[j] = last 20 octets of IMCK[j]
144 	 */
145 
146 	wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK[j]", msk, msk_len);
147 	wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK[j]", emsk, emsk_len);
148 
149 	if (emsk && emsk_len > 0) {
150 		u8 context[3];
151 
152 		context[0] = 0;
153 		context[1] = 0;
154 		context[2] = 64;
155 		if (eap_teap_tls_prf(tls_cs, emsk, emsk_len,
156 				     "TEAPbindkey@ietf.org",
157 				     context, sizeof(context), imsk, 64) < 0)
158 			return -1;
159 
160 		wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from EMSK",
161 				imsk, 32);
162 
163 		res = eap_teap_tls_prf(tls_cs,
164 				       prev_s_imck, EAP_TEAP_SIMCK_LEN,
165 				       "Inner Methods Compound Keys",
166 				       imsk, 32, imck, EAP_TEAP_IMCK_LEN);
167 		forced_memzero(imsk, sizeof(imsk));
168 		if (res < 0)
169 			return -1;
170 
171 		os_memcpy(s_imck_emsk, imck, EAP_TEAP_SIMCK_LEN);
172 		wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK S-IMCK[j]",
173 				s_imck_emsk, EAP_TEAP_SIMCK_LEN);
174 		os_memcpy(cmk_emsk, &imck[EAP_TEAP_SIMCK_LEN],
175 			  EAP_TEAP_CMK_LEN);
176 		wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK CMK[j]",
177 				cmk_emsk, EAP_TEAP_CMK_LEN);
178 		forced_memzero(imck, EAP_TEAP_IMCK_LEN);
179 	}
180 
181 	if (msk && msk_len > 0) {
182 		size_t copy_len = msk_len;
183 
184 		os_memset(imsk, 0, 32); /* zero pad, if needed */
185 		if (copy_len > 32)
186 			copy_len = 32;
187 		os_memcpy(imsk, msk, copy_len);
188 		wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from MSK", imsk, 32);
189 	} else {
190 		os_memset(imsk, 0, 32);
191 		wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Zero IMSK", imsk, 32);
192 	}
193 
194 	res = eap_teap_tls_prf(tls_cs, prev_s_imck, EAP_TEAP_SIMCK_LEN,
195 			       "Inner Methods Compound Keys",
196 			       imsk, 32, imck, EAP_TEAP_IMCK_LEN);
197 	forced_memzero(imsk, sizeof(imsk));
198 	if (res < 0)
199 		return -1;
200 
201 	os_memcpy(s_imck_msk, imck, EAP_TEAP_SIMCK_LEN);
202 	wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK S-IMCK[j]",
203 			s_imck_msk, EAP_TEAP_SIMCK_LEN);
204 	os_memcpy(cmk_msk, &imck[EAP_TEAP_SIMCK_LEN], EAP_TEAP_CMK_LEN);
205 	wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK CMK[j]",
206 			cmk_msk, EAP_TEAP_CMK_LEN);
207 	forced_memzero(imck, EAP_TEAP_IMCK_LEN);
208 
209 	return 0;
210 }
211 
212 
tls_cipher_suite_match(const u16 * list,size_t count,u16 cs)213 static int tls_cipher_suite_match(const u16 *list, size_t count, u16 cs)
214 {
215 	size_t i;
216 
217 	for (i = 0; i < count; i++) {
218 		if (list[i] == cs)
219 			return 1;
220 	}
221 
222 	return 0;
223 }
224 
225 
tls_cipher_suite_mac_sha1(u16 cs)226 static int tls_cipher_suite_mac_sha1(u16 cs)
227 {
228 	static const u16 sha1_cs[] = {
229 		0x0005, 0x0007, 0x000a, 0x000d, 0x0010, 0x0013, 0x0016, 0x001b,
230 		0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036,
231 		0x0037, 0x0038, 0x0039, 0x003a, 0x0041, 0x0042, 0x0043, 0x0044,
232 		0x0045, 0x0046, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089,
233 		0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091,
234 		0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099,
235 		0x009a, 0x009b,
236 		0xc002, 0xc003, 0xc004, 0xc005, 0xc007, 0xc008, 0xc009, 0xc009,
237 		0xc00a, 0xc00c, 0xc00d, 0xc00e, 0xc00f, 0xc011, 0xc012, 0xc013,
238 		0xc014, 0xc016, 0xc017, 0xc018, 0xc019, 0xc01a, 0xc01b, 0xc01c,
239 		0xc014, 0xc01e, 0xc01f, 0xc020, 0xc021, 0xc022, 0xc033, 0xc034,
240 		0xc035, 0xc036
241 	};
242 
243 	return tls_cipher_suite_match(sha1_cs, ARRAY_SIZE(sha1_cs), cs);
244 }
245 
246 
tls_cipher_suite_mac_sha256(u16 cs)247 static int tls_cipher_suite_mac_sha256(u16 cs)
248 {
249 	static const u16 sha256_cs[] = {
250 		0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0067, 0x0068, 0x0069,
251 		0x006a, 0x006b, 0x006c, 0x006d, 0x009c, 0x009e, 0x00a0, 0x00a2,
252 		0x00a4, 0x00a6, 0x00a8, 0x00aa, 0x00ac, 0x00ae, 0x00b2, 0x00b6,
253 		0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bd, 0x00be, 0x00be,
254 		0x00bf, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5,
255 		0x1301, 0x1303, 0x1304, 0x1305,
256 		0xc023, 0xc025, 0xc027, 0xc029, 0xc02b, 0xc02d, 0xc02f, 0xc031,
257 		0xc037, 0xc03c, 0xc03e, 0xc040, 0xc040, 0xc042, 0xc044, 0xc046,
258 		0xc048, 0xc04a, 0xc04c, 0xc04e, 0xc050, 0xc052, 0xc054, 0xc056,
259 		0xc058, 0xc05a, 0xc05c, 0xc05e, 0xc060, 0xc062, 0xc064, 0xc066,
260 		0xc068, 0xc06a, 0xc06c, 0xc06e, 0xc070, 0xc072, 0xc074, 0xc076,
261 		0xc078, 0xc07a, 0xc07c, 0xc07e, 0xc080, 0xc082, 0xc084, 0xc086,
262 		0xc088, 0xc08a, 0xc08c, 0xc08e, 0xc090, 0xc092, 0xc094, 0xc096,
263 		0xc098, 0xc09a, 0xc0b0, 0xc0b2, 0xc0b4,
264 		0xcca8, 0xcca9, 0xccaa, 0xccab, 0xccac, 0xccad, 0xccae,
265 		0xd001, 0xd003, 0xd005
266 	};
267 
268 	return tls_cipher_suite_match(sha256_cs, ARRAY_SIZE(sha256_cs), cs);
269 }
270 
271 
tls_cipher_suite_mac_sha384(u16 cs)272 static int tls_cipher_suite_mac_sha384(u16 cs)
273 {
274 	static const u16 sha384_cs[] = {
275 		0x009d, 0x009f, 0x00a1, 0x00a3, 0x00a5, 0x00a7, 0x00a9, 0x00ab,
276 		0x00ad, 0x00af, 0x00b3, 0x00b7, 0x1302,
277 		0xc024, 0xc026, 0xc028, 0xc02a, 0xc02c, 0xc02e, 0xc030, 0xc032,
278 		0xc038, 0xc03d, 0xc03f, 0xc041, 0xc043, 0xc045, 0xc047, 0xc049,
279 		0xc04b, 0xc04d, 0xc04f, 0xc051, 0xc053, 0xc055, 0xc057, 0xc059,
280 		0xc05b, 0xc05d, 0xc05f, 0xc061, 0xc063, 0xc065, 0xc067, 0xc069,
281 		0xc06b, 0xc06d, 0xc06f, 0xc071, 0xc073, 0xc075, 0xc077, 0xc079,
282 		0xc07b, 0xc07d, 0xc07f, 0xc081, 0xc083, 0xc085, 0xc087, 0xc089,
283 		0xc08b, 0xc08d, 0xc08f, 0xc091, 0xc093, 0xc095, 0xc097, 0xc099,
284 		0xc09b, 0xc0b1, 0xc0b3, 0xc0b5,
285 		0xd002
286 	};
287 
288 	return tls_cipher_suite_match(sha384_cs, ARRAY_SIZE(sha384_cs), cs);
289 }
290 
291 
eap_teap_tls_mac(u16 tls_cs,const u8 * cmk,size_t cmk_len,const u8 * buffer,size_t buffer_len,u8 * mac,size_t mac_len)292 static int eap_teap_tls_mac(u16 tls_cs, const u8 *cmk, size_t cmk_len,
293 			    const u8 *buffer, size_t buffer_len,
294 			    u8 *mac, size_t mac_len)
295 {
296 	int res;
297 	u8 tmp[48];
298 
299 	os_memset(tmp, 0, sizeof(tmp));
300 	os_memset(mac, 0, mac_len);
301 
302 	if (tls_cipher_suite_mac_sha1(tls_cs)) {
303 		wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA1");
304 		res = hmac_sha1(cmk, cmk_len, buffer, buffer_len, tmp);
305 	} else if (tls_cipher_suite_mac_sha256(tls_cs)) {
306 		wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA256");
307 		res = hmac_sha256(cmk, cmk_len, buffer, buffer_len, tmp);
308 	} else if (tls_cipher_suite_mac_sha384(tls_cs)) {
309 		wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA384");
310 		res = hmac_sha384(cmk, cmk_len, buffer, buffer_len, tmp);
311 	} else {
312 		wpa_printf(MSG_INFO,
313 			   "EAP-TEAP: Unsupported TLS cipher suite 0x%04x",
314 			   tls_cs);
315 		res = -1;
316 	}
317 	if (res < 0)
318 		return res;
319 
320 	if (mac_len > sizeof(tmp))
321 		mac_len = sizeof(tmp);
322 	os_memcpy(mac, tmp, mac_len);
323 	return 0;
324 }
325 
326 
eap_teap_compound_mac(u16 tls_cs,const struct teap_tlv_crypto_binding * cb,const struct wpabuf * server_outer_tlvs,const struct wpabuf * peer_outer_tlvs,const u8 * cmk,u8 * compound_mac)327 int eap_teap_compound_mac(u16 tls_cs, const struct teap_tlv_crypto_binding *cb,
328 			  const struct wpabuf *server_outer_tlvs,
329 			  const struct wpabuf *peer_outer_tlvs,
330 			  const u8 *cmk, u8 *compound_mac)
331 {
332 	u8 *pos, *buffer;
333 	size_t bind_len, buffer_len;
334 	struct teap_tlv_crypto_binding *tmp_cb;
335 	int res;
336 
337 	/* RFC 7170, Section 5.3 */
338 	bind_len = sizeof(struct teap_tlv_hdr) + be_to_host16(cb->length);
339 	buffer_len = bind_len + 1;
340 	if (server_outer_tlvs)
341 		buffer_len += wpabuf_len(server_outer_tlvs);
342 	if (peer_outer_tlvs)
343 		buffer_len += wpabuf_len(peer_outer_tlvs);
344 	buffer = os_malloc(buffer_len);
345 	if (!buffer)
346 		return -1;
347 
348 	pos = buffer;
349 	/* 1. The entire Crypto-Binding TLV attribute with both the EMSK and MSK
350 	 * Compound MAC fields zeroed out. */
351 	os_memcpy(pos, cb, bind_len);
352 	pos += bind_len;
353 	tmp_cb = (struct teap_tlv_crypto_binding *) buffer;
354 	os_memset(tmp_cb->emsk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
355 	os_memset(tmp_cb->msk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
356 
357 	/* 2. The EAP Type sent by the other party in the first TEAP message. */
358 	/* This is supposed to be the EAP Type sent by the other party in the
359 	 * first TEAP message, but since we cannot get here without having
360 	 * successfully negotiated use of TEAP, this can only be the fixed EAP
361 	 * Type of TEAP. */
362 	*pos++ = EAP_TYPE_TEAP;
363 
364 	/* 3. All the Outer TLVs from the first TEAP message sent by EAP server
365 	 * to peer. */
366 	if (server_outer_tlvs) {
367 		os_memcpy(pos, wpabuf_head(server_outer_tlvs),
368 			  wpabuf_len(server_outer_tlvs));
369 		pos += wpabuf_len(server_outer_tlvs);
370 	}
371 
372 	/* 4. All the Outer TLVs from the first TEAP message sent by the peer to
373 	 * the EAP server. */
374 	if (peer_outer_tlvs) {
375 		os_memcpy(pos, wpabuf_head(peer_outer_tlvs),
376 			  wpabuf_len(peer_outer_tlvs));
377 		pos += wpabuf_len(peer_outer_tlvs);
378 	}
379 
380 	buffer_len = pos - buffer;
381 
382 	wpa_hexdump_key(MSG_MSGDUMP,
383 			"EAP-TEAP: CMK for Compound MAC calculation",
384 			cmk, EAP_TEAP_CMK_LEN);
385 	wpa_hexdump(MSG_MSGDUMP,
386 		    "EAP-TEAP: BUFFER for Compound MAC calculation",
387 		    buffer, buffer_len);
388 	res = eap_teap_tls_mac(tls_cs, cmk, EAP_TEAP_CMK_LEN,
389 			       buffer, buffer_len,
390 			       compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
391 	os_free(buffer);
392 
393 	return res;
394 }
395 
396 
eap_teap_parse_tlv(struct eap_teap_tlv_parse * tlv,int tlv_type,u8 * pos,size_t len)397 int eap_teap_parse_tlv(struct eap_teap_tlv_parse *tlv,
398 		       int tlv_type, u8 *pos, size_t len)
399 {
400 	switch (tlv_type) {
401 	case TEAP_TLV_IDENTITY_TYPE:
402 		if (len < 2) {
403 			wpa_printf(MSG_INFO,
404 				   "EAP-TEAP: Too short Identity-Type TLV");
405 			tlv->result = TEAP_STATUS_FAILURE;
406 			break;
407 		}
408 		tlv->identity_type = WPA_GET_BE16(pos);
409 		wpa_printf(MSG_DEBUG, "EAP-TEAP: Identity-Type: %u",
410 			   tlv->identity_type);
411 		break;
412 	case TEAP_TLV_RESULT:
413 		wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Result TLV", pos, len);
414 		if (tlv->result) {
415 			wpa_printf(MSG_INFO,
416 				   "EAP-TEAP: More than one Result TLV in the message");
417 			tlv->result = TEAP_STATUS_FAILURE;
418 			return -2;
419 		}
420 		if (len < 2) {
421 			wpa_printf(MSG_INFO, "EAP-TEAP: Too short Result TLV");
422 			tlv->result = TEAP_STATUS_FAILURE;
423 			break;
424 		}
425 		tlv->result = WPA_GET_BE16(pos);
426 		if (tlv->result != TEAP_STATUS_SUCCESS &&
427 		    tlv->result != TEAP_STATUS_FAILURE) {
428 			wpa_printf(MSG_INFO, "EAP-TEAP: Unknown Result %d",
429 				   tlv->result);
430 			tlv->result = TEAP_STATUS_FAILURE;
431 		}
432 		wpa_printf(MSG_DEBUG, "EAP-TEAP: Result: %s",
433 			   tlv->result == TEAP_STATUS_SUCCESS ?
434 			   "Success" : "Failure");
435 		break;
436 	case TEAP_TLV_NAK:
437 		wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: NAK TLV", pos, len);
438 		if (len < 6) {
439 			wpa_printf(MSG_INFO, "EAP-TEAP: Too short NAK TLV");
440 			tlv->result = TEAP_STATUS_FAILURE;
441 			break;
442 		}
443 		tlv->nak = pos;
444 		tlv->nak_len = len;
445 		break;
446 	case TEAP_TLV_ERROR:
447 		if (len < 4) {
448 			wpa_printf(MSG_INFO, "EAP-TEAP: Too short Error TLV");
449 			tlv->result = TEAP_STATUS_FAILURE;
450 			break;
451 		}
452 		tlv->error_code = WPA_GET_BE32(pos);
453 		wpa_printf(MSG_DEBUG, "EAP-TEAP: Error: %u", tlv->error_code);
454 		break;
455 	case TEAP_TLV_REQUEST_ACTION:
456 		wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Request-Action TLV",
457 			    pos, len);
458 		if (tlv->request_action) {
459 			wpa_printf(MSG_INFO,
460 				   "EAP-TEAP: More than one Request-Action TLV in the message");
461 			tlv->iresult = TEAP_STATUS_FAILURE;
462 			return -2;
463 		}
464 		if (len < 2) {
465 			wpa_printf(MSG_INFO,
466 				   "EAP-TEAP: Too short Request-Action TLV");
467 			tlv->iresult = TEAP_STATUS_FAILURE;
468 			break;
469 		}
470 		tlv->request_action_status = pos[0];
471 		tlv->request_action = pos[1];
472 		wpa_printf(MSG_DEBUG,
473 			   "EAP-TEAP: Request-Action: Status=%u Action=%u",
474 			   tlv->request_action_status, tlv->request_action);
475 		break;
476 	case TEAP_TLV_EAP_PAYLOAD:
477 		wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EAP-Payload TLV",
478 			    pos, len);
479 		if (tlv->eap_payload_tlv) {
480 			wpa_printf(MSG_INFO,
481 				   "EAP-TEAP: More than one EAP-Payload TLV in the message");
482 			tlv->iresult = TEAP_STATUS_FAILURE;
483 			return -2;
484 		}
485 		tlv->eap_payload_tlv = pos;
486 		tlv->eap_payload_tlv_len = len;
487 		break;
488 	case TEAP_TLV_INTERMEDIATE_RESULT:
489 		wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Intermediate-Result TLV",
490 			    pos, len);
491 		if (len < 2) {
492 			wpa_printf(MSG_INFO,
493 				   "EAP-TEAP: Too short Intermediate-Result TLV");
494 			tlv->iresult = TEAP_STATUS_FAILURE;
495 			break;
496 		}
497 		if (tlv->iresult) {
498 			wpa_printf(MSG_INFO,
499 				   "EAP-TEAP: More than one Intermediate-Result TLV in the message");
500 			tlv->iresult = TEAP_STATUS_FAILURE;
501 			return -2;
502 		}
503 		tlv->iresult = WPA_GET_BE16(pos);
504 		if (tlv->iresult != TEAP_STATUS_SUCCESS &&
505 		    tlv->iresult != TEAP_STATUS_FAILURE) {
506 			wpa_printf(MSG_INFO,
507 				   "EAP-TEAP: Unknown Intermediate Result %d",
508 				   tlv->iresult);
509 			tlv->iresult = TEAP_STATUS_FAILURE;
510 		}
511 		wpa_printf(MSG_DEBUG, "EAP-TEAP: Intermediate Result: %s",
512 			   tlv->iresult == TEAP_STATUS_SUCCESS ?
513 			   "Success" : "Failure");
514 		break;
515 	case TEAP_TLV_PAC:
516 		wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: PAC TLV", pos, len);
517 		if (tlv->pac) {
518 			wpa_printf(MSG_INFO,
519 				   "EAP-TEAP: More than one PAC TLV in the message");
520 			tlv->iresult = TEAP_STATUS_FAILURE;
521 			return -2;
522 		}
523 		tlv->pac = pos;
524 		tlv->pac_len = len;
525 		break;
526 	case TEAP_TLV_CRYPTO_BINDING:
527 		wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Crypto-Binding TLV",
528 			    pos, len);
529 		if (tlv->crypto_binding) {
530 			wpa_printf(MSG_INFO,
531 				   "EAP-TEAP: More than one Crypto-Binding TLV in the message");
532 			tlv->iresult = TEAP_STATUS_FAILURE;
533 			return -2;
534 		}
535 		tlv->crypto_binding_len = sizeof(struct teap_tlv_hdr) + len;
536 		if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
537 			wpa_printf(MSG_INFO,
538 				   "EAP-TEAP: Too short Crypto-Binding TLV");
539 			tlv->iresult = TEAP_STATUS_FAILURE;
540 			return -2;
541 		}
542 		tlv->crypto_binding = (struct teap_tlv_crypto_binding *)
543 			(pos - sizeof(struct teap_tlv_hdr));
544 		break;
545 	case TEAP_TLV_BASIC_PASSWORD_AUTH_REQ:
546 		wpa_hexdump_ascii(MSG_MSGDUMP,
547 				  "EAP-TEAP: Basic-Password-Auth-Req TLV",
548 				  pos, len);
549 		if (tlv->basic_auth_req) {
550 			wpa_printf(MSG_INFO,
551 				   "EAP-TEAP: More than one Basic-Password-Auth-Req TLV in the message");
552 			tlv->iresult = TEAP_STATUS_FAILURE;
553 			return -2;
554 		}
555 		tlv->basic_auth_req = pos;
556 		tlv->basic_auth_req_len = len;
557 		break;
558 	case TEAP_TLV_BASIC_PASSWORD_AUTH_RESP:
559 		wpa_hexdump_ascii(MSG_MSGDUMP,
560 				  "EAP-TEAP: Basic-Password-Auth-Resp TLV",
561 				  pos, len);
562 		if (tlv->basic_auth_resp) {
563 			wpa_printf(MSG_INFO,
564 				   "EAP-TEAP: More than one Basic-Password-Auth-Resp TLV in the message");
565 			tlv->iresult = TEAP_STATUS_FAILURE;
566 			return -2;
567 		}
568 		tlv->basic_auth_resp = pos;
569 		tlv->basic_auth_resp_len = len;
570 		break;
571 	default:
572 		/* Unknown TLV */
573 		return -1;
574 	}
575 
576 	return 0;
577 }
578 
579 
eap_teap_tlv_type_str(enum teap_tlv_types type)580 const char * eap_teap_tlv_type_str(enum teap_tlv_types type)
581 {
582 	switch (type) {
583 	case TEAP_TLV_AUTHORITY_ID:
584 		return "Authority-ID";
585 	case TEAP_TLV_IDENTITY_TYPE:
586 		return "Identity-Type";
587 	case TEAP_TLV_RESULT:
588 		return "Result";
589 	case TEAP_TLV_NAK:
590 		return "NAK";
591 	case TEAP_TLV_ERROR:
592 		return "Error";
593 	case TEAP_TLV_CHANNEL_BINDING:
594 		return "Channel-Binding";
595 	case TEAP_TLV_VENDOR_SPECIFIC:
596 		return "Vendor-Specific";
597 	case TEAP_TLV_REQUEST_ACTION:
598 		return "Request-Action";
599 	case TEAP_TLV_EAP_PAYLOAD:
600 		return "EAP-Payload";
601 	case TEAP_TLV_INTERMEDIATE_RESULT:
602 		return "Intermediate-Result";
603 	case TEAP_TLV_PAC:
604 		return "PAC";
605 	case TEAP_TLV_CRYPTO_BINDING:
606 		return "Crypto-Binding";
607 	case TEAP_TLV_BASIC_PASSWORD_AUTH_REQ:
608 		return "Basic-Password-Auth-Req";
609 	case TEAP_TLV_BASIC_PASSWORD_AUTH_RESP:
610 		return "Basic-Password-Auth-Resp";
611 	case TEAP_TLV_PKCS7:
612 		return "PKCS#7";
613 	case TEAP_TLV_PKCS10:
614 		return "PKCS#10";
615 	case TEAP_TLV_TRUSTED_SERVER_ROOT:
616 		return "Trusted-Server-Root";
617 	}
618 
619 	return "?";
620 }
621 
622 
eap_teap_tlv_result(int status,int intermediate)623 struct wpabuf * eap_teap_tlv_result(int status, int intermediate)
624 {
625 	struct wpabuf *buf;
626 	struct teap_tlv_result *result;
627 
628 	if (status != TEAP_STATUS_FAILURE && status != TEAP_STATUS_SUCCESS)
629 		return NULL;
630 
631 	buf = wpabuf_alloc(sizeof(*result));
632 	if (!buf)
633 		return NULL;
634 	wpa_printf(MSG_DEBUG, "EAP-TEAP: Add %sResult TLV(status=%s)",
635 		   intermediate ? "Intermediate-" : "",
636 		   status == TEAP_STATUS_SUCCESS ? "Success" : "Failure");
637 	result = wpabuf_put(buf, sizeof(*result));
638 	result->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
639 					(intermediate ?
640 					 TEAP_TLV_INTERMEDIATE_RESULT :
641 					 TEAP_TLV_RESULT));
642 	result->length = host_to_be16(2);
643 	result->status = host_to_be16(status);
644 	return buf;
645 }
646 
647 
eap_teap_tlv_error(enum teap_error_codes error)648 struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error)
649 {
650 	struct wpabuf *buf;
651 
652 	buf = wpabuf_alloc(4 + 4);
653 	if (!buf)
654 		return NULL;
655 	wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Error TLV(Error Code=%d)",
656 		   error);
657 	wpabuf_put_be16(buf, TEAP_TLV_MANDATORY | TEAP_TLV_ERROR);
658 	wpabuf_put_be16(buf, 4);
659 	wpabuf_put_be32(buf, error);
660 	return buf;
661 }
662 
663 
eap_teap_tlv_identity_type(enum teap_identity_types id)664 struct wpabuf * eap_teap_tlv_identity_type(enum teap_identity_types id)
665 {
666 	struct wpabuf *buf;
667 
668 	buf = wpabuf_alloc(4 + 2);
669 	if (!buf)
670 		return NULL;
671 	wpa_printf(MSG_DEBUG,
672 		   "EAP-TEAP: Add Identity-Type TLV(Identity-Type=%d)", id);
673 	wpabuf_put_be16(buf, TEAP_TLV_IDENTITY_TYPE);
674 	wpabuf_put_be16(buf, 2);
675 	wpabuf_put_be16(buf, id);
676 	return buf;
677 }
678