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