Line data Source code
1 : /*
2 : * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
3 : * Copyright (c) 2004-2008, 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/tls.h"
14 : #include "crypto/random.h"
15 : #include "eap_i.h"
16 : #include "eap_tls_common.h"
17 : #include "eap_common/eap_tlv_common.h"
18 : #include "eap_common/eap_peap_common.h"
19 : #include "tncs.h"
20 :
21 :
22 : /* Maximum supported PEAP version
23 : * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
24 : * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
25 : */
26 : #define EAP_PEAP_VERSION 1
27 :
28 :
29 : static void eap_peap_reset(struct eap_sm *sm, void *priv);
30 :
31 :
32 : struct eap_peap_data {
33 : struct eap_ssl_data ssl;
34 : enum {
35 : START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,
36 : PHASE2_METHOD, PHASE2_SOH,
37 : PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
38 : } state;
39 :
40 : int peap_version;
41 : int recv_version;
42 : const struct eap_method *phase2_method;
43 : void *phase2_priv;
44 : int force_version;
45 : struct wpabuf *pending_phase2_resp;
46 : enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
47 : int crypto_binding_sent;
48 : int crypto_binding_used;
49 : enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
50 : u8 binding_nonce[32];
51 : u8 ipmk[40];
52 : u8 cmk[20];
53 : u8 *phase2_key;
54 : size_t phase2_key_len;
55 : struct wpabuf *soh_response;
56 : };
57 :
58 :
59 424 : static const char * eap_peap_state_txt(int state)
60 : {
61 424 : switch (state) {
62 : case START:
63 35 : return "START";
64 : case PHASE1:
65 70 : return "PHASE1";
66 : case PHASE1_ID2:
67 0 : return "PHASE1_ID2";
68 : case PHASE2_START:
69 70 : return "PHASE2_START";
70 : case PHASE2_ID:
71 70 : return "PHASE2_ID";
72 : case PHASE2_METHOD:
73 70 : return "PHASE2_METHOD";
74 : case PHASE2_SOH:
75 6 : return "PHASE2_SOH";
76 : case PHASE2_TLV:
77 17 : return "PHASE2_TLV";
78 : case SUCCESS_REQ:
79 48 : return "SUCCESS_REQ";
80 : case FAILURE_REQ:
81 4 : return "FAILURE_REQ";
82 : case SUCCESS:
83 31 : return "SUCCESS";
84 : case FAILURE:
85 3 : return "FAILURE";
86 : default:
87 0 : return "Unknown?!";
88 : }
89 : }
90 :
91 :
92 212 : static void eap_peap_state(struct eap_peap_data *data, int state)
93 : {
94 424 : wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
95 212 : eap_peap_state_txt(data->state),
96 : eap_peap_state_txt(state));
97 212 : data->state = state;
98 212 : }
99 :
100 :
101 32 : static void eap_peap_req_success(struct eap_sm *sm,
102 : struct eap_peap_data *data)
103 : {
104 32 : if (data->state == FAILURE || data->state == FAILURE_REQ) {
105 0 : eap_peap_state(data, FAILURE);
106 32 : return;
107 : }
108 :
109 32 : if (data->peap_version == 0) {
110 8 : data->tlv_request = TLV_REQ_SUCCESS;
111 8 : eap_peap_state(data, PHASE2_TLV);
112 : } else {
113 24 : eap_peap_state(data, SUCCESS_REQ);
114 : }
115 : }
116 :
117 :
118 3 : static void eap_peap_req_failure(struct eap_sm *sm,
119 : struct eap_peap_data *data)
120 : {
121 6 : if (data->state == FAILURE || data->state == FAILURE_REQ ||
122 6 : data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
123 0 : eap_peap_state(data, FAILURE);
124 3 : return;
125 : }
126 :
127 3 : if (data->peap_version == 0) {
128 1 : data->tlv_request = TLV_REQ_FAILURE;
129 1 : eap_peap_state(data, PHASE2_TLV);
130 : } else {
131 2 : eap_peap_state(data, FAILURE_REQ);
132 : }
133 : }
134 :
135 :
136 35 : static void * eap_peap_init(struct eap_sm *sm)
137 : {
138 : struct eap_peap_data *data;
139 :
140 35 : data = os_zalloc(sizeof(*data));
141 35 : if (data == NULL)
142 0 : return NULL;
143 35 : data->peap_version = EAP_PEAP_VERSION;
144 35 : data->force_version = -1;
145 35 : if (sm->user && sm->user->force_version >= 0) {
146 0 : data->force_version = sm->user->force_version;
147 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",
148 : data->force_version);
149 0 : data->peap_version = data->force_version;
150 : }
151 35 : data->state = START;
152 35 : data->crypto_binding = OPTIONAL_BINDING;
153 :
154 35 : if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
155 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
156 0 : eap_peap_reset(sm, data);
157 0 : return NULL;
158 : }
159 :
160 35 : return data;
161 : }
162 :
163 :
164 35 : static void eap_peap_reset(struct eap_sm *sm, void *priv)
165 : {
166 35 : struct eap_peap_data *data = priv;
167 35 : if (data == NULL)
168 35 : return;
169 35 : if (data->phase2_priv && data->phase2_method)
170 0 : data->phase2_method->reset(sm, data->phase2_priv);
171 35 : eap_server_tls_ssl_deinit(sm, &data->ssl);
172 35 : wpabuf_free(data->pending_phase2_resp);
173 35 : os_free(data->phase2_key);
174 35 : wpabuf_free(data->soh_response);
175 35 : bin_clear_free(data, sizeof(*data));
176 : }
177 :
178 :
179 35 : static struct wpabuf * eap_peap_build_start(struct eap_sm *sm,
180 : struct eap_peap_data *data, u8 id)
181 : {
182 : struct wpabuf *req;
183 :
184 35 : req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,
185 : EAP_CODE_REQUEST, id);
186 35 : if (req == NULL) {
187 0 : wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"
188 : " request");
189 0 : eap_peap_state(data, FAILURE);
190 0 : return NULL;
191 : }
192 :
193 35 : wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);
194 :
195 35 : eap_peap_state(data, PHASE1);
196 :
197 35 : return req;
198 : }
199 :
200 :
201 111 : static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
202 : struct eap_peap_data *data,
203 : u8 id)
204 : {
205 : struct wpabuf *buf, *encr_req, msgbuf;
206 : const u8 *req;
207 : size_t req_len;
208 :
209 111 : if (data->phase2_method == NULL || data->phase2_priv == NULL) {
210 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
211 0 : return NULL;
212 : }
213 111 : buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
214 111 : if (buf == NULL)
215 0 : return NULL;
216 :
217 111 : req = wpabuf_head(buf);
218 111 : req_len = wpabuf_len(buf);
219 111 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
220 : req, req_len);
221 :
222 138 : if (data->peap_version == 0 &&
223 27 : data->phase2_method->method != EAP_TYPE_TLV) {
224 27 : req += sizeof(struct eap_hdr);
225 27 : req_len -= sizeof(struct eap_hdr);
226 : }
227 :
228 111 : wpabuf_set(&msgbuf, req, req_len);
229 111 : encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
230 111 : wpabuf_free(buf);
231 :
232 111 : return encr_req;
233 : }
234 :
235 :
236 : #ifdef EAP_SERVER_TNC
237 3 : static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
238 : struct eap_peap_data *data,
239 : u8 id)
240 : {
241 : struct wpabuf *buf1, *buf, *encr_req, msgbuf;
242 : const u8 *req;
243 : size_t req_len;
244 :
245 3 : buf1 = tncs_build_soh_request();
246 3 : if (buf1 == NULL)
247 0 : return NULL;
248 :
249 3 : buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
250 : EAP_CODE_REQUEST, id);
251 3 : if (buf == NULL) {
252 0 : wpabuf_free(buf1);
253 0 : return NULL;
254 : }
255 3 : wpabuf_put_buf(buf, buf1);
256 3 : wpabuf_free(buf1);
257 :
258 3 : req = wpabuf_head(buf);
259 3 : req_len = wpabuf_len(buf);
260 :
261 3 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
262 : req, req_len);
263 :
264 3 : req += sizeof(struct eap_hdr);
265 3 : req_len -= sizeof(struct eap_hdr);
266 3 : wpabuf_set(&msgbuf, req, req_len);
267 :
268 3 : encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
269 3 : wpabuf_free(buf);
270 :
271 3 : return encr_req;
272 : }
273 : #endif /* EAP_SERVER_TNC */
274 :
275 :
276 8 : static void eap_peap_get_isk(struct eap_peap_data *data,
277 : u8 *isk, size_t isk_len)
278 : {
279 : size_t key_len;
280 :
281 8 : os_memset(isk, 0, isk_len);
282 8 : if (data->phase2_key == NULL)
283 8 : return;
284 :
285 8 : key_len = data->phase2_key_len;
286 8 : if (key_len > isk_len)
287 0 : key_len = isk_len;
288 8 : os_memcpy(isk, data->phase2_key, key_len);
289 : }
290 :
291 :
292 8 : static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
293 : {
294 : u8 *tk;
295 : u8 isk[32], imck[60];
296 :
297 : /*
298 : * Tunnel key (TK) is the first 60 octets of the key generated by
299 : * phase 1 of PEAP (based on TLS).
300 : */
301 8 : tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
302 : EAP_TLS_KEY_LEN);
303 8 : if (tk == NULL)
304 0 : return -1;
305 8 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
306 :
307 8 : eap_peap_get_isk(data, isk, sizeof(isk));
308 8 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
309 :
310 : /*
311 : * IPMK Seed = "Inner Methods Compound Keys" | ISK
312 : * TempKey = First 40 octets of TK
313 : * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
314 : * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
315 : * in the end of the label just before ISK; is that just a typo?)
316 : */
317 8 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
318 8 : if (peap_prfplus(data->peap_version, tk, 40,
319 : "Inner Methods Compound Keys",
320 : isk, sizeof(isk), imck, sizeof(imck)) < 0) {
321 0 : os_free(tk);
322 0 : return -1;
323 : }
324 8 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
325 : imck, sizeof(imck));
326 :
327 8 : os_free(tk);
328 :
329 : /* TODO: fast-connect: IPMK|CMK = TK */
330 8 : os_memcpy(data->ipmk, imck, 40);
331 8 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
332 8 : os_memcpy(data->cmk, imck + 40, 20);
333 8 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
334 :
335 8 : return 0;
336 : }
337 :
338 :
339 9 : static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
340 : struct eap_peap_data *data,
341 : u8 id)
342 : {
343 : struct wpabuf *buf, *encr_req;
344 : size_t mlen;
345 :
346 9 : mlen = 6; /* Result TLV */
347 17 : if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
348 8 : data->crypto_binding != NO_BINDING) {
349 8 : mlen += 60; /* Cryptobinding TLV */
350 : #ifdef EAP_SERVER_TNC
351 8 : if (data->soh_response)
352 0 : mlen += wpabuf_len(data->soh_response);
353 : #endif /* EAP_SERVER_TNC */
354 : }
355 :
356 9 : buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
357 : EAP_CODE_REQUEST, id);
358 9 : if (buf == NULL)
359 0 : return NULL;
360 :
361 9 : wpabuf_put_u8(buf, 0x80); /* Mandatory */
362 9 : wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
363 : /* Length */
364 9 : wpabuf_put_be16(buf, 2);
365 : /* Status */
366 9 : wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
367 : EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
368 :
369 17 : if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
370 8 : data->crypto_binding != NO_BINDING) {
371 : u8 *mac;
372 8 : u8 eap_type = EAP_TYPE_PEAP;
373 : const u8 *addr[2];
374 : size_t len[2];
375 : u16 tlv_type;
376 :
377 : #ifdef EAP_SERVER_TNC
378 8 : if (data->soh_response) {
379 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "
380 : "Response TLV");
381 0 : wpabuf_put_buf(buf, data->soh_response);
382 0 : wpabuf_free(data->soh_response);
383 0 : data->soh_response = NULL;
384 : }
385 : #endif /* EAP_SERVER_TNC */
386 :
387 16 : if (eap_peap_derive_cmk(sm, data) < 0 ||
388 8 : random_get_bytes(data->binding_nonce, 32)) {
389 0 : wpabuf_free(buf);
390 0 : return NULL;
391 : }
392 :
393 : /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
394 8 : addr[0] = wpabuf_put(buf, 0);
395 8 : len[0] = 60;
396 8 : addr[1] = &eap_type;
397 8 : len[1] = 1;
398 :
399 8 : tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
400 8 : wpabuf_put_be16(buf, tlv_type);
401 8 : wpabuf_put_be16(buf, 56);
402 :
403 8 : wpabuf_put_u8(buf, 0); /* Reserved */
404 8 : wpabuf_put_u8(buf, data->peap_version); /* Version */
405 8 : wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
406 8 : wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
407 8 : wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
408 8 : mac = wpabuf_put(buf, 20); /* Compound_MAC */
409 8 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
410 8 : data->cmk, 20);
411 16 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
412 8 : addr[0], len[0]);
413 16 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
414 8 : addr[1], len[1]);
415 8 : hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
416 8 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
417 : mac, SHA1_MAC_LEN);
418 8 : data->crypto_binding_sent = 1;
419 : }
420 :
421 9 : wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
422 : buf);
423 :
424 9 : encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
425 9 : wpabuf_free(buf);
426 :
427 9 : return encr_req;
428 : }
429 :
430 :
431 26 : static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
432 : struct eap_peap_data *data,
433 : u8 id, int success)
434 : {
435 : struct wpabuf *encr_req, msgbuf;
436 : size_t req_len;
437 : struct eap_hdr *hdr;
438 :
439 26 : req_len = sizeof(*hdr);
440 26 : hdr = os_zalloc(req_len);
441 26 : if (hdr == NULL)
442 0 : return NULL;
443 :
444 26 : hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
445 26 : hdr->identifier = id;
446 26 : hdr->length = host_to_be16(req_len);
447 :
448 26 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
449 : (u8 *) hdr, req_len);
450 :
451 26 : wpabuf_set(&msgbuf, hdr, req_len);
452 26 : encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
453 26 : os_free(hdr);
454 :
455 26 : return encr_req;
456 : }
457 :
458 :
459 286 : static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
460 : {
461 286 : struct eap_peap_data *data = priv;
462 :
463 286 : if (data->ssl.state == FRAG_ACK) {
464 1 : return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
465 : data->peap_version);
466 : }
467 :
468 285 : if (data->ssl.state == WAIT_FRAG_ACK) {
469 31 : return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
470 : data->peap_version, id);
471 : }
472 :
473 254 : switch (data->state) {
474 : case START:
475 35 : return eap_peap_build_start(sm, data, id);
476 : case PHASE1:
477 : case PHASE1_ID2:
478 70 : if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
479 35 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
480 : "starting Phase2");
481 35 : eap_peap_state(data, PHASE2_START);
482 : }
483 70 : break;
484 : case PHASE2_ID:
485 : case PHASE2_METHOD:
486 111 : wpabuf_free(data->ssl.tls_out);
487 111 : data->ssl.tls_out_pos = 0;
488 111 : data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
489 111 : break;
490 : #ifdef EAP_SERVER_TNC
491 : case PHASE2_SOH:
492 3 : wpabuf_free(data->ssl.tls_out);
493 3 : data->ssl.tls_out_pos = 0;
494 3 : data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id);
495 3 : break;
496 : #endif /* EAP_SERVER_TNC */
497 : case PHASE2_TLV:
498 9 : wpabuf_free(data->ssl.tls_out);
499 9 : data->ssl.tls_out_pos = 0;
500 9 : data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
501 9 : break;
502 : case SUCCESS_REQ:
503 24 : wpabuf_free(data->ssl.tls_out);
504 24 : data->ssl.tls_out_pos = 0;
505 24 : data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
506 : 1);
507 24 : break;
508 : case FAILURE_REQ:
509 2 : wpabuf_free(data->ssl.tls_out);
510 2 : data->ssl.tls_out_pos = 0;
511 2 : data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
512 : 0);
513 2 : break;
514 : default:
515 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
516 0 : __func__, data->state);
517 0 : return NULL;
518 : }
519 :
520 219 : return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
521 : data->peap_version, id);
522 : }
523 :
524 :
525 285 : static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
526 : struct wpabuf *respData)
527 : {
528 : const u8 *pos;
529 : size_t len;
530 :
531 285 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
532 285 : if (pos == NULL || len < 1) {
533 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
534 0 : return TRUE;
535 : }
536 :
537 285 : return FALSE;
538 : }
539 :
540 :
541 110 : static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
542 : EapType eap_type)
543 : {
544 110 : if (data->phase2_priv && data->phase2_method) {
545 72 : data->phase2_method->reset(sm, data->phase2_priv);
546 72 : data->phase2_method = NULL;
547 72 : data->phase2_priv = NULL;
548 : }
549 110 : data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
550 : eap_type);
551 110 : if (!data->phase2_method)
552 38 : return -1;
553 :
554 72 : sm->init_phase2 = 1;
555 72 : data->phase2_priv = data->phase2_method->init(sm);
556 72 : sm->init_phase2 = 0;
557 72 : return 0;
558 : }
559 :
560 :
561 6 : static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
562 : struct eap_peap_data *data,
563 : const u8 *crypto_tlv,
564 : size_t crypto_tlv_len)
565 : {
566 : u8 buf[61], mac[SHA1_MAC_LEN];
567 : const u8 *pos;
568 :
569 6 : if (crypto_tlv_len != 4 + 56) {
570 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
571 : "length %d", (int) crypto_tlv_len);
572 0 : return -1;
573 : }
574 :
575 6 : pos = crypto_tlv;
576 6 : pos += 4; /* TLV header */
577 6 : if (pos[1] != data->peap_version) {
578 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
579 : "mismatch (was %d; expected %d)",
580 0 : pos[1], data->peap_version);
581 0 : return -1;
582 : }
583 :
584 6 : if (pos[3] != 1) {
585 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
586 0 : "SubType %d", pos[3]);
587 0 : return -1;
588 : }
589 6 : pos += 4;
590 6 : pos += 32; /* Nonce */
591 :
592 : /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
593 6 : os_memcpy(buf, crypto_tlv, 60);
594 6 : os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
595 6 : buf[60] = EAP_TYPE_PEAP;
596 6 : hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
597 :
598 6 : if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
599 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
600 : "cryptobinding TLV");
601 0 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
602 0 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
603 : buf, 61);
604 0 : return -1;
605 : }
606 :
607 6 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
608 :
609 6 : return 0;
610 : }
611 :
612 :
613 8 : static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
614 : struct eap_peap_data *data,
615 : struct wpabuf *in_data)
616 : {
617 : const u8 *pos;
618 : size_t left;
619 8 : const u8 *result_tlv = NULL, *crypto_tlv = NULL;
620 8 : size_t result_tlv_len = 0, crypto_tlv_len = 0;
621 : int tlv_type, mandatory, tlv_len;
622 :
623 8 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
624 8 : if (pos == NULL) {
625 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
626 0 : return;
627 : }
628 :
629 : /* Parse TLVs */
630 8 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
631 30 : while (left >= 4) {
632 14 : mandatory = !!(pos[0] & 0x80);
633 14 : tlv_type = pos[0] & 0x3f;
634 14 : tlv_type = (tlv_type << 8) | pos[1];
635 14 : tlv_len = ((int) pos[2] << 8) | pos[3];
636 14 : pos += 4;
637 14 : left -= 4;
638 14 : if ((size_t) tlv_len > left) {
639 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
640 : "(tlv_len=%d left=%lu)", tlv_len,
641 : (unsigned long) left);
642 0 : eap_peap_state(data, FAILURE);
643 0 : return;
644 : }
645 14 : switch (tlv_type) {
646 : case EAP_TLV_RESULT_TLV:
647 8 : result_tlv = pos;
648 8 : result_tlv_len = tlv_len;
649 8 : break;
650 : case EAP_TLV_CRYPTO_BINDING_TLV:
651 6 : crypto_tlv = pos;
652 6 : crypto_tlv_len = tlv_len;
653 6 : break;
654 : default:
655 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
656 : "%d%s", tlv_type,
657 : mandatory ? " (mandatory)" : "");
658 0 : if (mandatory) {
659 0 : eap_peap_state(data, FAILURE);
660 0 : return;
661 : }
662 : /* Ignore this TLV, but process other TLVs */
663 0 : break;
664 : }
665 :
666 14 : pos += tlv_len;
667 14 : left -= tlv_len;
668 : }
669 8 : if (left) {
670 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
671 : "Request (left=%lu)", (unsigned long) left);
672 0 : eap_peap_state(data, FAILURE);
673 0 : return;
674 : }
675 :
676 : /* Process supported TLVs */
677 8 : if (crypto_tlv && data->crypto_binding_sent) {
678 6 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
679 : crypto_tlv, crypto_tlv_len);
680 6 : if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
681 : crypto_tlv_len + 4) < 0) {
682 0 : eap_peap_state(data, FAILURE);
683 0 : return;
684 : }
685 6 : data->crypto_binding_used = 1;
686 4 : } else if (!crypto_tlv && data->crypto_binding_sent &&
687 2 : data->crypto_binding == REQUIRE_BINDING) {
688 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
689 0 : eap_peap_state(data, FAILURE);
690 0 : return;
691 : }
692 :
693 8 : if (result_tlv) {
694 : int status;
695 : const char *requested;
696 :
697 8 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
698 : result_tlv, result_tlv_len);
699 8 : if (result_tlv_len < 2) {
700 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
701 : "(len=%lu)",
702 : (unsigned long) result_tlv_len);
703 0 : eap_peap_state(data, FAILURE);
704 0 : return;
705 : }
706 8 : requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
707 : "Failure";
708 8 : status = WPA_GET_BE16(result_tlv);
709 8 : if (status == EAP_TLV_RESULT_SUCCESS) {
710 7 : wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
711 : "- requested %s", requested);
712 7 : if (data->tlv_request == TLV_REQ_SUCCESS)
713 7 : eap_peap_state(data, SUCCESS);
714 : else
715 0 : eap_peap_state(data, FAILURE);
716 :
717 1 : } else if (status == EAP_TLV_RESULT_FAILURE) {
718 1 : wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
719 : "- requested %s", requested);
720 1 : eap_peap_state(data, FAILURE);
721 : } else {
722 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
723 : "Status %d", status);
724 0 : eap_peap_state(data, FAILURE);
725 : }
726 : }
727 : }
728 :
729 :
730 : #ifdef EAP_SERVER_TNC
731 3 : static void eap_peap_process_phase2_soh(struct eap_sm *sm,
732 : struct eap_peap_data *data,
733 : struct wpabuf *in_data)
734 : {
735 : const u8 *pos, *vpos;
736 : size_t left;
737 3 : const u8 *soh_tlv = NULL;
738 3 : size_t soh_tlv_len = 0;
739 : int tlv_type, mandatory, tlv_len, vtlv_len;
740 : u8 next_type;
741 : u32 vendor_id;
742 :
743 3 : pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
744 3 : if (pos == NULL) {
745 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
746 : "Extensions Method header - skip TNC");
747 0 : goto auth_method;
748 : }
749 :
750 : /* Parse TLVs */
751 3 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
752 9 : while (left >= 4) {
753 3 : mandatory = !!(pos[0] & 0x80);
754 3 : tlv_type = pos[0] & 0x3f;
755 3 : tlv_type = (tlv_type << 8) | pos[1];
756 3 : tlv_len = ((int) pos[2] << 8) | pos[3];
757 3 : pos += 4;
758 3 : left -= 4;
759 3 : if ((size_t) tlv_len > left) {
760 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
761 : "(tlv_len=%d left=%lu)", tlv_len,
762 : (unsigned long) left);
763 0 : eap_peap_state(data, FAILURE);
764 0 : return;
765 : }
766 3 : switch (tlv_type) {
767 : case EAP_TLV_VENDOR_SPECIFIC_TLV:
768 3 : if (tlv_len < 4) {
769 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
770 : "vendor specific TLV (len=%d)",
771 : (int) tlv_len);
772 0 : eap_peap_state(data, FAILURE);
773 0 : return;
774 : }
775 :
776 3 : vendor_id = WPA_GET_BE32(pos);
777 3 : if (vendor_id != EAP_VENDOR_MICROSOFT) {
778 0 : if (mandatory) {
779 0 : eap_peap_state(data, FAILURE);
780 0 : return;
781 : }
782 0 : break;
783 : }
784 :
785 3 : vpos = pos + 4;
786 3 : mandatory = !!(vpos[0] & 0x80);
787 3 : tlv_type = vpos[0] & 0x3f;
788 3 : tlv_type = (tlv_type << 8) | vpos[1];
789 3 : vtlv_len = ((int) vpos[2] << 8) | vpos[3];
790 3 : vpos += 4;
791 3 : if (vpos + vtlv_len > pos + left) {
792 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
793 : "underrun");
794 0 : eap_peap_state(data, FAILURE);
795 0 : return;
796 : }
797 :
798 3 : if (tlv_type == 1) {
799 3 : soh_tlv = vpos;
800 3 : soh_tlv_len = vtlv_len;
801 3 : break;
802 : }
803 :
804 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
805 : "Type %d%s", tlv_type,
806 : mandatory ? " (mandatory)" : "");
807 0 : if (mandatory) {
808 0 : eap_peap_state(data, FAILURE);
809 0 : return;
810 : }
811 : /* Ignore this TLV, but process other TLVs */
812 0 : break;
813 : default:
814 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
815 : "%d%s", tlv_type,
816 : mandatory ? " (mandatory)" : "");
817 0 : if (mandatory) {
818 0 : eap_peap_state(data, FAILURE);
819 0 : return;
820 : }
821 : /* Ignore this TLV, but process other TLVs */
822 0 : break;
823 : }
824 :
825 3 : pos += tlv_len;
826 3 : left -= tlv_len;
827 : }
828 3 : if (left) {
829 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
830 : "Request (left=%lu)", (unsigned long) left);
831 0 : eap_peap_state(data, FAILURE);
832 0 : return;
833 : }
834 :
835 : /* Process supported TLVs */
836 3 : if (soh_tlv) {
837 3 : int failure = 0;
838 3 : wpabuf_free(data->soh_response);
839 3 : data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
840 : &failure);
841 3 : if (failure) {
842 0 : eap_peap_state(data, FAILURE);
843 0 : return;
844 : }
845 : } else {
846 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
847 0 : eap_peap_state(data, FAILURE);
848 0 : return;
849 : }
850 :
851 : auth_method:
852 3 : eap_peap_state(data, PHASE2_METHOD);
853 3 : next_type = sm->user->methods[0].method;
854 3 : sm->user_eap_method_index = 1;
855 3 : wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
856 3 : eap_peap_phase2_init(sm, data, next_type);
857 : }
858 : #endif /* EAP_SERVER_TNC */
859 :
860 :
861 123 : static void eap_peap_process_phase2_response(struct eap_sm *sm,
862 : struct eap_peap_data *data,
863 : struct wpabuf *in_data)
864 : {
865 123 : u8 next_type = EAP_TYPE_NONE;
866 : const struct eap_hdr *hdr;
867 : const u8 *pos;
868 : size_t left;
869 :
870 123 : if (data->state == PHASE2_TLV) {
871 8 : eap_peap_process_phase2_tlv(sm, data, in_data);
872 8 : return;
873 : }
874 :
875 : #ifdef EAP_SERVER_TNC
876 115 : if (data->state == PHASE2_SOH) {
877 3 : eap_peap_process_phase2_soh(sm, data, in_data);
878 3 : return;
879 : }
880 : #endif /* EAP_SERVER_TNC */
881 :
882 112 : if (data->phase2_priv == NULL) {
883 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
884 : "initialized?!", __func__);
885 0 : return;
886 : }
887 :
888 112 : hdr = wpabuf_head(in_data);
889 112 : pos = (const u8 *) (hdr + 1);
890 :
891 112 : if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
892 2 : left = wpabuf_len(in_data) - sizeof(*hdr);
893 2 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
894 : "allowed types", pos + 1, left - 1);
895 2 : eap_sm_process_nak(sm, pos + 1, left - 1);
896 4 : if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
897 2 : sm->user->methods[sm->user_eap_method_index].method !=
898 : EAP_TYPE_NONE) {
899 4 : next_type = sm->user->methods[
900 2 : sm->user_eap_method_index++].method;
901 2 : wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
902 : next_type);
903 : } else {
904 0 : eap_peap_req_failure(sm, data);
905 0 : next_type = EAP_TYPE_NONE;
906 : }
907 2 : eap_peap_phase2_init(sm, data, next_type);
908 2 : return;
909 : }
910 :
911 110 : if (data->phase2_method->check(sm, data->phase2_priv, in_data)) {
912 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
913 : "ignore the packet");
914 0 : return;
915 : }
916 :
917 110 : data->phase2_method->process(sm, data->phase2_priv, in_data);
918 :
919 110 : if (sm->method_pending == METHOD_PENDING_WAIT) {
920 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
921 : "pending wait state - save decrypted response");
922 1 : wpabuf_free(data->pending_phase2_resp);
923 1 : data->pending_phase2_resp = wpabuf_dup(in_data);
924 : }
925 :
926 110 : if (!data->phase2_method->isDone(sm, data->phase2_priv))
927 40 : return;
928 :
929 70 : if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
930 2 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
931 2 : eap_peap_req_failure(sm, data);
932 2 : next_type = EAP_TYPE_NONE;
933 2 : eap_peap_phase2_init(sm, data, next_type);
934 2 : return;
935 : }
936 :
937 68 : os_free(data->phase2_key);
938 68 : if (data->phase2_method->getKey) {
939 31 : data->phase2_key = data->phase2_method->getKey(
940 : sm, data->phase2_priv, &data->phase2_key_len);
941 31 : if (data->phase2_key == NULL) {
942 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
943 : "failed");
944 1 : eap_peap_req_failure(sm, data);
945 1 : eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
946 1 : return;
947 : }
948 : }
949 :
950 67 : switch (data->state) {
951 : case PHASE1_ID2:
952 : case PHASE2_ID:
953 : case PHASE2_SOH:
954 35 : if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
955 0 : wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
956 : "Identity not found in the user "
957 : "database",
958 0 : sm->identity, sm->identity_len);
959 0 : eap_peap_req_failure(sm, data);
960 0 : next_type = EAP_TYPE_NONE;
961 0 : break;
962 : }
963 :
964 : #ifdef EAP_SERVER_TNC
965 38 : if (data->state != PHASE2_SOH && sm->tnc &&
966 3 : data->peap_version == 0) {
967 3 : eap_peap_state(data, PHASE2_SOH);
968 3 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
969 : "TNC (NAP SOH)");
970 3 : next_type = EAP_TYPE_NONE;
971 3 : break;
972 : }
973 : #endif /* EAP_SERVER_TNC */
974 :
975 32 : eap_peap_state(data, PHASE2_METHOD);
976 32 : next_type = sm->user->methods[0].method;
977 32 : sm->user_eap_method_index = 1;
978 32 : wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
979 32 : break;
980 : case PHASE2_METHOD:
981 32 : eap_peap_req_success(sm, data);
982 32 : next_type = EAP_TYPE_NONE;
983 32 : break;
984 : case FAILURE:
985 0 : break;
986 : default:
987 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
988 0 : __func__, data->state);
989 0 : break;
990 : }
991 :
992 67 : eap_peap_phase2_init(sm, data, next_type);
993 : }
994 :
995 :
996 123 : static void eap_peap_process_phase2(struct eap_sm *sm,
997 : struct eap_peap_data *data,
998 : const struct wpabuf *respData,
999 : struct wpabuf *in_buf)
1000 : {
1001 : struct wpabuf *in_decrypted;
1002 : const struct eap_hdr *hdr;
1003 : size_t len;
1004 :
1005 123 : wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
1006 : " Phase 2", (unsigned long) wpabuf_len(in_buf));
1007 :
1008 123 : if (data->pending_phase2_resp) {
1009 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
1010 : "skip decryption and use old data");
1011 1 : eap_peap_process_phase2_response(sm, data,
1012 : data->pending_phase2_resp);
1013 1 : wpabuf_free(data->pending_phase2_resp);
1014 1 : data->pending_phase2_resp = NULL;
1015 1 : return;
1016 : }
1017 :
1018 122 : in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
1019 : in_buf);
1020 122 : if (in_decrypted == NULL) {
1021 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
1022 : "data");
1023 0 : eap_peap_state(data, FAILURE);
1024 0 : return;
1025 : }
1026 :
1027 122 : wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
1028 : in_decrypted);
1029 :
1030 122 : if (data->peap_version == 0 && data->state != PHASE2_TLV) {
1031 : const struct eap_hdr *resp;
1032 : struct eap_hdr *nhdr;
1033 30 : struct wpabuf *nbuf =
1034 30 : wpabuf_alloc(sizeof(struct eap_hdr) +
1035 30 : wpabuf_len(in_decrypted));
1036 30 : if (nbuf == NULL) {
1037 0 : wpabuf_free(in_decrypted);
1038 0 : return;
1039 : }
1040 :
1041 30 : resp = wpabuf_head(respData);
1042 30 : nhdr = wpabuf_put(nbuf, sizeof(*nhdr));
1043 30 : nhdr->code = resp->code;
1044 30 : nhdr->identifier = resp->identifier;
1045 30 : nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
1046 : wpabuf_len(in_decrypted));
1047 30 : wpabuf_put_buf(nbuf, in_decrypted);
1048 30 : wpabuf_free(in_decrypted);
1049 :
1050 30 : in_decrypted = nbuf;
1051 : }
1052 :
1053 122 : hdr = wpabuf_head(in_decrypted);
1054 122 : if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) {
1055 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
1056 : "EAP frame (len=%lu)",
1057 : (unsigned long) wpabuf_len(in_decrypted));
1058 0 : wpabuf_free(in_decrypted);
1059 0 : eap_peap_req_failure(sm, data);
1060 0 : return;
1061 : }
1062 122 : len = be_to_host16(hdr->length);
1063 122 : if (len > wpabuf_len(in_decrypted)) {
1064 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
1065 : "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
1066 : (unsigned long) wpabuf_len(in_decrypted),
1067 : (unsigned long) len);
1068 0 : wpabuf_free(in_decrypted);
1069 0 : eap_peap_req_failure(sm, data);
1070 0 : return;
1071 : }
1072 244 : wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
1073 244 : "identifier=%d length=%lu", hdr->code, hdr->identifier,
1074 : (unsigned long) len);
1075 122 : switch (hdr->code) {
1076 : case EAP_CODE_RESPONSE:
1077 122 : eap_peap_process_phase2_response(sm, data, in_decrypted);
1078 122 : break;
1079 : case EAP_CODE_SUCCESS:
1080 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
1081 0 : if (data->state == SUCCESS_REQ) {
1082 0 : eap_peap_state(data, SUCCESS);
1083 : }
1084 0 : break;
1085 : case EAP_CODE_FAILURE:
1086 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
1087 0 : eap_peap_state(data, FAILURE);
1088 0 : break;
1089 : default:
1090 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
1091 0 : "Phase 2 EAP header", hdr->code);
1092 0 : break;
1093 : }
1094 :
1095 122 : wpabuf_free(in_decrypted);
1096 : }
1097 :
1098 :
1099 286 : static int eap_peap_process_version(struct eap_sm *sm, void *priv,
1100 : int peer_version)
1101 : {
1102 286 : struct eap_peap_data *data = priv;
1103 :
1104 286 : data->recv_version = peer_version;
1105 286 : if (data->force_version >= 0 && peer_version != data->force_version) {
1106 0 : wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
1107 : " version (forced=%d peer=%d) - reject",
1108 : data->force_version, peer_version);
1109 0 : return -1;
1110 : }
1111 286 : if (peer_version < data->peap_version) {
1112 9 : wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
1113 : "use version %d",
1114 : peer_version, data->peap_version, peer_version);
1115 9 : data->peap_version = peer_version;
1116 : }
1117 :
1118 286 : return 0;
1119 : }
1120 :
1121 :
1122 254 : static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
1123 : const struct wpabuf *respData)
1124 : {
1125 254 : struct eap_peap_data *data = priv;
1126 :
1127 254 : switch (data->state) {
1128 : case PHASE1:
1129 70 : if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
1130 0 : eap_peap_state(data, FAILURE);
1131 0 : break;
1132 : }
1133 70 : break;
1134 : case PHASE2_START:
1135 35 : eap_peap_state(data, PHASE2_ID);
1136 35 : eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
1137 35 : break;
1138 : case PHASE1_ID2:
1139 : case PHASE2_ID:
1140 : case PHASE2_METHOD:
1141 : case PHASE2_SOH:
1142 : case PHASE2_TLV:
1143 123 : eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in);
1144 123 : break;
1145 : case SUCCESS_REQ:
1146 24 : eap_peap_state(data, SUCCESS);
1147 24 : break;
1148 : case FAILURE_REQ:
1149 2 : eap_peap_state(data, FAILURE);
1150 2 : break;
1151 : default:
1152 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
1153 0 : data->state, __func__);
1154 0 : break;
1155 : }
1156 254 : }
1157 :
1158 :
1159 286 : static void eap_peap_process(struct eap_sm *sm, void *priv,
1160 : struct wpabuf *respData)
1161 : {
1162 286 : struct eap_peap_data *data = priv;
1163 286 : if (eap_server_tls_process(sm, &data->ssl, respData, data,
1164 : EAP_TYPE_PEAP, eap_peap_process_version,
1165 : eap_peap_process_msg) < 0)
1166 0 : eap_peap_state(data, FAILURE);
1167 286 : }
1168 :
1169 :
1170 289 : static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
1171 : {
1172 289 : struct eap_peap_data *data = priv;
1173 289 : return data->state == SUCCESS || data->state == FAILURE;
1174 : }
1175 :
1176 :
1177 34 : static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
1178 : {
1179 34 : struct eap_peap_data *data = priv;
1180 : u8 *eapKeyData;
1181 :
1182 34 : if (data->state != SUCCESS)
1183 3 : return NULL;
1184 :
1185 31 : if (data->crypto_binding_used) {
1186 : u8 csk[128];
1187 : /*
1188 : * Note: It looks like Microsoft implementation requires null
1189 : * termination for this label while the one used for deriving
1190 : * IPMK|CMK did not use null termination.
1191 : */
1192 6 : if (peap_prfplus(data->peap_version, data->ipmk, 40,
1193 : "Session Key Generating Function",
1194 : (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
1195 0 : return NULL;
1196 6 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
1197 6 : eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
1198 6 : if (eapKeyData) {
1199 6 : os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
1200 6 : *len = EAP_TLS_KEY_LEN;
1201 6 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
1202 : eapKeyData, EAP_TLS_KEY_LEN);
1203 : } else {
1204 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
1205 : "key");
1206 : }
1207 :
1208 6 : return eapKeyData;
1209 : }
1210 :
1211 : /* TODO: PEAPv1 - different label in some cases */
1212 25 : eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
1213 : "client EAP encryption",
1214 : EAP_TLS_KEY_LEN);
1215 25 : if (eapKeyData) {
1216 25 : *len = EAP_TLS_KEY_LEN;
1217 25 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
1218 : eapKeyData, EAP_TLS_KEY_LEN);
1219 : } else {
1220 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key");
1221 : }
1222 :
1223 25 : return eapKeyData;
1224 : }
1225 :
1226 :
1227 37 : static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
1228 : {
1229 37 : struct eap_peap_data *data = priv;
1230 37 : return data->state == SUCCESS;
1231 : }
1232 :
1233 :
1234 34 : static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1235 : {
1236 34 : struct eap_peap_data *data = priv;
1237 :
1238 34 : if (data->state != SUCCESS)
1239 3 : return NULL;
1240 :
1241 31 : return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP,
1242 : len);
1243 : }
1244 :
1245 :
1246 10 : int eap_server_peap_register(void)
1247 : {
1248 : struct eap_method *eap;
1249 : int ret;
1250 :
1251 10 : eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1252 : EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
1253 10 : if (eap == NULL)
1254 0 : return -1;
1255 :
1256 10 : eap->init = eap_peap_init;
1257 10 : eap->reset = eap_peap_reset;
1258 10 : eap->buildReq = eap_peap_buildReq;
1259 10 : eap->check = eap_peap_check;
1260 10 : eap->process = eap_peap_process;
1261 10 : eap->isDone = eap_peap_isDone;
1262 10 : eap->getKey = eap_peap_getKey;
1263 10 : eap->isSuccess = eap_peap_isSuccess;
1264 10 : eap->getSessionId = eap_peap_get_session_id;
1265 :
1266 10 : ret = eap_server_method_register(eap);
1267 10 : if (ret)
1268 0 : eap_server_method_free(eap);
1269 10 : return ret;
1270 : }
|