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 42 : static const char * eap_peap_state_txt(int state)
60 : {
61 42 : switch (state) {
62 : case START:
63 3 : return "START";
64 : case PHASE1:
65 6 : return "PHASE1";
66 : case PHASE1_ID2:
67 0 : return "PHASE1_ID2";
68 : case PHASE2_START:
69 6 : return "PHASE2_START";
70 : case PHASE2_ID:
71 6 : return "PHASE2_ID";
72 : case PHASE2_METHOD:
73 6 : return "PHASE2_METHOD";
74 : case PHASE2_SOH:
75 6 : return "PHASE2_SOH";
76 : case PHASE2_TLV:
77 6 : return "PHASE2_TLV";
78 : case SUCCESS_REQ:
79 0 : return "SUCCESS_REQ";
80 : case FAILURE_REQ:
81 0 : return "FAILURE_REQ";
82 : case SUCCESS:
83 3 : return "SUCCESS";
84 : case FAILURE:
85 0 : return "FAILURE";
86 : default:
87 0 : return "Unknown?!";
88 : }
89 : }
90 :
91 :
92 21 : static void eap_peap_state(struct eap_peap_data *data, int state)
93 : {
94 42 : wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
95 21 : eap_peap_state_txt(data->state),
96 : eap_peap_state_txt(state));
97 21 : data->state = state;
98 21 : }
99 :
100 :
101 3 : static void eap_peap_req_success(struct eap_sm *sm,
102 : struct eap_peap_data *data)
103 : {
104 3 : if (data->state == FAILURE || data->state == FAILURE_REQ) {
105 0 : eap_peap_state(data, FAILURE);
106 3 : return;
107 : }
108 :
109 3 : if (data->peap_version == 0) {
110 3 : data->tlv_request = TLV_REQ_SUCCESS;
111 3 : eap_peap_state(data, PHASE2_TLV);
112 : } else {
113 0 : eap_peap_state(data, SUCCESS_REQ);
114 : }
115 : }
116 :
117 :
118 0 : static void eap_peap_req_failure(struct eap_sm *sm,
119 : struct eap_peap_data *data)
120 : {
121 0 : if (data->state == FAILURE || data->state == FAILURE_REQ ||
122 0 : data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
123 0 : eap_peap_state(data, FAILURE);
124 0 : return;
125 : }
126 :
127 0 : if (data->peap_version == 0) {
128 0 : data->tlv_request = TLV_REQ_FAILURE;
129 0 : eap_peap_state(data, PHASE2_TLV);
130 : } else {
131 0 : eap_peap_state(data, FAILURE_REQ);
132 : }
133 : }
134 :
135 :
136 3 : static void * eap_peap_init(struct eap_sm *sm)
137 : {
138 : struct eap_peap_data *data;
139 :
140 3 : data = os_zalloc(sizeof(*data));
141 3 : if (data == NULL)
142 0 : return NULL;
143 3 : data->peap_version = EAP_PEAP_VERSION;
144 3 : data->force_version = -1;
145 3 : 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 3 : data->state = START;
152 3 : data->crypto_binding = OPTIONAL_BINDING;
153 :
154 3 : 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 3 : return data;
161 : }
162 :
163 :
164 3 : static void eap_peap_reset(struct eap_sm *sm, void *priv)
165 : {
166 3 : struct eap_peap_data *data = priv;
167 3 : if (data == NULL)
168 3 : return;
169 3 : if (data->phase2_priv && data->phase2_method)
170 0 : data->phase2_method->reset(sm, data->phase2_priv);
171 3 : eap_server_tls_ssl_deinit(sm, &data->ssl);
172 3 : wpabuf_free(data->pending_phase2_resp);
173 3 : os_free(data->phase2_key);
174 3 : wpabuf_free(data->soh_response);
175 3 : os_free(data);
176 : }
177 :
178 :
179 3 : 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 3 : req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,
185 : EAP_CODE_REQUEST, id);
186 3 : 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 3 : wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);
194 :
195 3 : eap_peap_state(data, PHASE1);
196 :
197 3 : return req;
198 : }
199 :
200 :
201 9 : 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 9 : 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 9 : buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
214 9 : if (buf == NULL)
215 0 : return NULL;
216 :
217 9 : req = wpabuf_head(buf);
218 9 : req_len = wpabuf_len(buf);
219 9 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
220 : req, req_len);
221 :
222 18 : if (data->peap_version == 0 &&
223 9 : data->phase2_method->method != EAP_TYPE_TLV) {
224 9 : req += sizeof(struct eap_hdr);
225 9 : req_len -= sizeof(struct eap_hdr);
226 : }
227 :
228 9 : wpabuf_set(&msgbuf, req, req_len);
229 9 : encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
230 9 : wpabuf_free(buf);
231 :
232 9 : 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 3 : 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 3 : os_memset(isk, 0, isk_len);
282 3 : if (data->phase2_key == NULL)
283 3 : return;
284 :
285 3 : key_len = data->phase2_key_len;
286 3 : if (key_len > isk_len)
287 0 : key_len = isk_len;
288 3 : os_memcpy(isk, data->phase2_key, key_len);
289 : }
290 :
291 :
292 3 : 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 3 : tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
302 : EAP_TLS_KEY_LEN);
303 3 : if (tk == NULL)
304 0 : return -1;
305 3 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
306 :
307 3 : eap_peap_get_isk(data, isk, sizeof(isk));
308 3 : 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 3 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
318 3 : 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 3 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
325 : imck, sizeof(imck));
326 :
327 3 : os_free(tk);
328 :
329 : /* TODO: fast-connect: IPMK|CMK = TK */
330 3 : os_memcpy(data->ipmk, imck, 40);
331 3 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
332 3 : os_memcpy(data->cmk, imck + 40, 20);
333 3 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
334 :
335 3 : return 0;
336 : }
337 :
338 :
339 3 : 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 3 : mlen = 6; /* Result TLV */
347 3 : if (data->crypto_binding != NO_BINDING)
348 3 : mlen += 60; /* Cryptobinding TLV */
349 : #ifdef EAP_SERVER_TNC
350 3 : if (data->soh_response)
351 0 : mlen += wpabuf_len(data->soh_response);
352 : #endif /* EAP_SERVER_TNC */
353 :
354 3 : buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
355 : EAP_CODE_REQUEST, id);
356 3 : if (buf == NULL)
357 0 : return NULL;
358 :
359 3 : wpabuf_put_u8(buf, 0x80); /* Mandatory */
360 3 : wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
361 : /* Length */
362 3 : wpabuf_put_be16(buf, 2);
363 : /* Status */
364 3 : wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
365 : EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
366 :
367 6 : if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
368 3 : data->crypto_binding != NO_BINDING) {
369 : u8 *mac;
370 3 : 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 3 : 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 6 : if (eap_peap_derive_cmk(sm, data) < 0 ||
386 3 : 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 3 : addr[0] = wpabuf_put(buf, 0);
393 3 : len[0] = 60;
394 3 : addr[1] = &eap_type;
395 3 : len[1] = 1;
396 :
397 3 : tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
398 3 : wpabuf_put_be16(buf, tlv_type);
399 3 : wpabuf_put_be16(buf, 56);
400 :
401 3 : wpabuf_put_u8(buf, 0); /* Reserved */
402 3 : wpabuf_put_u8(buf, data->peap_version); /* Version */
403 3 : wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
404 3 : wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
405 3 : wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
406 3 : mac = wpabuf_put(buf, 20); /* Compound_MAC */
407 3 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
408 3 : data->cmk, 20);
409 6 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
410 3 : addr[0], len[0]);
411 6 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
412 3 : addr[1], len[1]);
413 3 : hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
414 3 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
415 : mac, SHA1_MAC_LEN);
416 3 : data->crypto_binding_sent = 1;
417 : }
418 :
419 3 : wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
420 : buf);
421 :
422 3 : encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
423 3 : wpabuf_free(buf);
424 :
425 3 : return encr_req;
426 : }
427 :
428 :
429 0 : 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 0 : req_len = sizeof(*hdr);
438 0 : hdr = os_zalloc(req_len);
439 0 : if (hdr == NULL)
440 0 : return NULL;
441 :
442 0 : hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
443 0 : hdr->identifier = id;
444 0 : hdr->length = host_to_be16(req_len);
445 :
446 0 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
447 : (u8 *) hdr, req_len);
448 :
449 0 : wpabuf_set(&msgbuf, hdr, req_len);
450 0 : encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
451 0 : os_free(hdr);
452 :
453 0 : return encr_req;
454 : }
455 :
456 :
457 24 : static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
458 : {
459 24 : struct eap_peap_data *data = priv;
460 :
461 24 : if (data->ssl.state == FRAG_ACK) {
462 0 : return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
463 : data->peap_version);
464 : }
465 :
466 24 : if (data->ssl.state == WAIT_FRAG_ACK) {
467 0 : return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
468 : data->peap_version, id);
469 : }
470 :
471 24 : switch (data->state) {
472 : case START:
473 3 : return eap_peap_build_start(sm, data, id);
474 : case PHASE1:
475 : case PHASE1_ID2:
476 6 : if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
477 3 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
478 : "starting Phase2");
479 3 : eap_peap_state(data, PHASE2_START);
480 : }
481 6 : break;
482 : case PHASE2_ID:
483 : case PHASE2_METHOD:
484 9 : wpabuf_free(data->ssl.tls_out);
485 9 : data->ssl.tls_out_pos = 0;
486 9 : data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
487 9 : 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 3 : wpabuf_free(data->ssl.tls_out);
497 3 : data->ssl.tls_out_pos = 0;
498 3 : data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
499 3 : break;
500 : case SUCCESS_REQ:
501 0 : wpabuf_free(data->ssl.tls_out);
502 0 : data->ssl.tls_out_pos = 0;
503 0 : data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
504 : 1);
505 0 : break;
506 : case FAILURE_REQ:
507 0 : wpabuf_free(data->ssl.tls_out);
508 0 : data->ssl.tls_out_pos = 0;
509 0 : data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
510 : 0);
511 0 : 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 21 : return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
519 : data->peap_version, id);
520 : }
521 :
522 :
523 24 : 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 24 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
530 24 : if (pos == NULL || len < 1) {
531 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
532 0 : return TRUE;
533 : }
534 :
535 24 : return FALSE;
536 : }
537 :
538 :
539 12 : static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
540 : EapType eap_type)
541 : {
542 12 : if (data->phase2_priv && data->phase2_method) {
543 6 : data->phase2_method->reset(sm, data->phase2_priv);
544 6 : data->phase2_method = NULL;
545 6 : data->phase2_priv = NULL;
546 : }
547 12 : data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
548 : eap_type);
549 12 : if (!data->phase2_method)
550 6 : return -1;
551 :
552 6 : sm->init_phase2 = 1;
553 6 : data->phase2_priv = data->phase2_method->init(sm);
554 6 : sm->init_phase2 = 0;
555 6 : return 0;
556 : }
557 :
558 :
559 3 : 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 3 : 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 3 : pos = crypto_tlv;
574 3 : pos += 4; /* TLV header */
575 3 : 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 3 : 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 3 : pos += 4;
588 3 : pos += 32; /* Nonce */
589 :
590 : /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
591 3 : os_memcpy(buf, crypto_tlv, 60);
592 3 : os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
593 3 : buf[60] = EAP_TYPE_PEAP;
594 3 : hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
595 :
596 3 : 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 3 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
606 :
607 3 : return 0;
608 : }
609 :
610 :
611 3 : 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 3 : const u8 *result_tlv = NULL, *crypto_tlv = NULL;
618 3 : size_t result_tlv_len = 0, crypto_tlv_len = 0;
619 : int tlv_type, mandatory, tlv_len;
620 :
621 3 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
622 3 : if (pos == NULL) {
623 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
624 0 : return;
625 : }
626 :
627 : /* Parse TLVs */
628 3 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
629 12 : while (left >= 4) {
630 6 : mandatory = !!(pos[0] & 0x80);
631 6 : tlv_type = pos[0] & 0x3f;
632 6 : tlv_type = (tlv_type << 8) | pos[1];
633 6 : tlv_len = ((int) pos[2] << 8) | pos[3];
634 6 : pos += 4;
635 6 : left -= 4;
636 6 : 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 6 : switch (tlv_type) {
644 : case EAP_TLV_RESULT_TLV:
645 3 : result_tlv = pos;
646 3 : result_tlv_len = tlv_len;
647 3 : break;
648 : case EAP_TLV_CRYPTO_BINDING_TLV:
649 3 : crypto_tlv = pos;
650 3 : crypto_tlv_len = tlv_len;
651 3 : 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 6 : pos += tlv_len;
665 6 : left -= tlv_len;
666 : }
667 3 : 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 3 : if (crypto_tlv && data->crypto_binding_sent) {
676 3 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
677 : crypto_tlv, crypto_tlv_len);
678 3 : 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 3 : data->crypto_binding_used = 1;
684 0 : } else if (!crypto_tlv && data->crypto_binding_sent &&
685 0 : 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 3 : if (result_tlv) {
692 : int status;
693 : const char *requested;
694 :
695 3 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
696 : result_tlv, result_tlv_len);
697 3 : 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 3 : requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
705 : "Failure";
706 3 : status = WPA_GET_BE16(result_tlv);
707 3 : if (status == EAP_TLV_RESULT_SUCCESS) {
708 3 : wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
709 : "- requested %s", requested);
710 3 : if (data->tlv_request == TLV_REQ_SUCCESS)
711 3 : eap_peap_state(data, SUCCESS);
712 : else
713 0 : eap_peap_state(data, FAILURE);
714 :
715 0 : } else if (status == EAP_TLV_RESULT_FAILURE) {
716 0 : wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
717 : "- requested %s", requested);
718 0 : 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 15 : static void eap_peap_process_phase2_response(struct eap_sm *sm,
860 : struct eap_peap_data *data,
861 : struct wpabuf *in_data)
862 : {
863 15 : u8 next_type = EAP_TYPE_NONE;
864 : const struct eap_hdr *hdr;
865 : const u8 *pos;
866 : size_t left;
867 :
868 15 : if (data->state == PHASE2_TLV) {
869 3 : eap_peap_process_phase2_tlv(sm, data, in_data);
870 3 : return;
871 : }
872 :
873 : #ifdef EAP_SERVER_TNC
874 12 : 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 9 : 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 9 : hdr = wpabuf_head(in_data);
887 9 : pos = (const u8 *) (hdr + 1);
888 :
889 9 : if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
890 0 : left = wpabuf_len(in_data) - sizeof(*hdr);
891 0 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
892 : "allowed types", pos + 1, left - 1);
893 0 : eap_sm_process_nak(sm, pos + 1, left - 1);
894 0 : if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
895 0 : sm->user->methods[sm->user_eap_method_index].method !=
896 : EAP_TYPE_NONE) {
897 0 : next_type = sm->user->methods[
898 0 : sm->user_eap_method_index++].method;
899 0 : 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 0 : eap_peap_phase2_init(sm, data, next_type);
906 0 : return;
907 : }
908 :
909 9 : 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 9 : data->phase2_method->process(sm, data->phase2_priv, in_data);
916 :
917 9 : if (sm->method_pending == METHOD_PENDING_WAIT) {
918 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
919 : "pending wait state - save decrypted response");
920 0 : wpabuf_free(data->pending_phase2_resp);
921 0 : data->pending_phase2_resp = wpabuf_dup(in_data);
922 : }
923 :
924 9 : if (!data->phase2_method->isDone(sm, data->phase2_priv))
925 3 : return;
926 :
927 6 : if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
928 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
929 0 : eap_peap_req_failure(sm, data);
930 0 : next_type = EAP_TYPE_NONE;
931 0 : eap_peap_phase2_init(sm, data, next_type);
932 0 : return;
933 : }
934 :
935 6 : os_free(data->phase2_key);
936 6 : if (data->phase2_method->getKey) {
937 3 : data->phase2_key = data->phase2_method->getKey(
938 : sm, data->phase2_priv, &data->phase2_key_len);
939 3 : 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 6 : switch (data->state) {
949 : case PHASE1_ID2:
950 : case PHASE2_ID:
951 : case PHASE2_SOH:
952 3 : 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 6 : 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 0 : eap_peap_state(data, PHASE2_METHOD);
974 0 : next_type = sm->user->methods[0].method;
975 0 : sm->user_eap_method_index = 1;
976 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
977 0 : break;
978 : case PHASE2_METHOD:
979 3 : eap_peap_req_success(sm, data);
980 3 : next_type = EAP_TYPE_NONE;
981 3 : 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 6 : eap_peap_phase2_init(sm, data, next_type);
991 : }
992 :
993 :
994 15 : 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 15 : wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
1004 : " Phase 2", (unsigned long) wpabuf_len(in_buf));
1005 :
1006 15 : if (data->pending_phase2_resp) {
1007 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
1008 : "skip decryption and use old data");
1009 0 : eap_peap_process_phase2_response(sm, data,
1010 : data->pending_phase2_resp);
1011 0 : wpabuf_free(data->pending_phase2_resp);
1012 0 : data->pending_phase2_resp = NULL;
1013 0 : return;
1014 : }
1015 :
1016 15 : in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
1017 : in_buf);
1018 15 : 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 15 : wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
1026 : in_decrypted);
1027 :
1028 15 : if (data->peap_version == 0 && data->state != PHASE2_TLV) {
1029 : const struct eap_hdr *resp;
1030 : struct eap_hdr *nhdr;
1031 12 : struct wpabuf *nbuf =
1032 12 : wpabuf_alloc(sizeof(struct eap_hdr) +
1033 12 : wpabuf_len(in_decrypted));
1034 12 : if (nbuf == NULL) {
1035 0 : wpabuf_free(in_decrypted);
1036 0 : return;
1037 : }
1038 :
1039 12 : resp = wpabuf_head(respData);
1040 12 : nhdr = wpabuf_put(nbuf, sizeof(*nhdr));
1041 12 : nhdr->code = resp->code;
1042 12 : nhdr->identifier = resp->identifier;
1043 12 : nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
1044 : wpabuf_len(in_decrypted));
1045 12 : wpabuf_put_buf(nbuf, in_decrypted);
1046 12 : wpabuf_free(in_decrypted);
1047 :
1048 12 : in_decrypted = nbuf;
1049 : }
1050 :
1051 15 : hdr = wpabuf_head(in_decrypted);
1052 15 : 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 15 : len = be_to_host16(hdr->length);
1061 15 : 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 30 : wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
1071 30 : "identifier=%d length=%lu", hdr->code, hdr->identifier,
1072 : (unsigned long) len);
1073 15 : switch (hdr->code) {
1074 : case EAP_CODE_RESPONSE:
1075 15 : eap_peap_process_phase2_response(sm, data, in_decrypted);
1076 15 : 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 15 : wpabuf_free(in_decrypted);
1094 : }
1095 :
1096 :
1097 24 : static int eap_peap_process_version(struct eap_sm *sm, void *priv,
1098 : int peer_version)
1099 : {
1100 24 : struct eap_peap_data *data = priv;
1101 :
1102 24 : data->recv_version = peer_version;
1103 24 : 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 24 : if (peer_version < data->peap_version) {
1110 3 : 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 3 : data->peap_version = peer_version;
1114 : }
1115 :
1116 24 : return 0;
1117 : }
1118 :
1119 :
1120 24 : static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
1121 : const struct wpabuf *respData)
1122 : {
1123 24 : struct eap_peap_data *data = priv;
1124 :
1125 24 : switch (data->state) {
1126 : case PHASE1:
1127 6 : if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
1128 0 : eap_peap_state(data, FAILURE);
1129 0 : break;
1130 : }
1131 6 : break;
1132 : case PHASE2_START:
1133 3 : eap_peap_state(data, PHASE2_ID);
1134 3 : eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
1135 3 : break;
1136 : case PHASE1_ID2:
1137 : case PHASE2_ID:
1138 : case PHASE2_METHOD:
1139 : case PHASE2_SOH:
1140 : case PHASE2_TLV:
1141 15 : eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in);
1142 15 : break;
1143 : case SUCCESS_REQ:
1144 0 : eap_peap_state(data, SUCCESS);
1145 0 : break;
1146 : case FAILURE_REQ:
1147 0 : eap_peap_state(data, FAILURE);
1148 0 : 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 24 : }
1155 :
1156 :
1157 24 : static void eap_peap_process(struct eap_sm *sm, void *priv,
1158 : struct wpabuf *respData)
1159 : {
1160 24 : struct eap_peap_data *data = priv;
1161 24 : 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 24 : }
1166 :
1167 :
1168 24 : static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
1169 : {
1170 24 : struct eap_peap_data *data = priv;
1171 24 : return data->state == SUCCESS || data->state == FAILURE;
1172 : }
1173 :
1174 :
1175 3 : static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
1176 : {
1177 3 : struct eap_peap_data *data = priv;
1178 : u8 *eapKeyData;
1179 :
1180 3 : if (data->state != SUCCESS)
1181 0 : return NULL;
1182 :
1183 3 : 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 3 : 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 3 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
1195 3 : eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
1196 3 : if (eapKeyData) {
1197 3 : os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
1198 3 : *len = EAP_TLS_KEY_LEN;
1199 3 : 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 3 : return eapKeyData;
1207 : }
1208 :
1209 : /* TODO: PEAPv1 - different label in some cases */
1210 0 : eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
1211 : "client EAP encryption",
1212 : EAP_TLS_KEY_LEN);
1213 0 : if (eapKeyData) {
1214 0 : *len = EAP_TLS_KEY_LEN;
1215 0 : 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 0 : return eapKeyData;
1222 : }
1223 :
1224 :
1225 3 : static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
1226 : {
1227 3 : struct eap_peap_data *data = priv;
1228 3 : return data->state == SUCCESS;
1229 : }
1230 :
1231 :
1232 1 : int eap_server_peap_register(void)
1233 : {
1234 : struct eap_method *eap;
1235 : int ret;
1236 :
1237 1 : eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1238 : EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
1239 1 : if (eap == NULL)
1240 0 : return -1;
1241 :
1242 1 : eap->init = eap_peap_init;
1243 1 : eap->reset = eap_peap_reset;
1244 1 : eap->buildReq = eap_peap_buildReq;
1245 1 : eap->check = eap_peap_check;
1246 1 : eap->process = eap_peap_process;
1247 1 : eap->isDone = eap_peap_isDone;
1248 1 : eap->getKey = eap_peap_getKey;
1249 1 : eap->isSuccess = eap_peap_isSuccess;
1250 :
1251 1 : ret = eap_server_method_register(eap);
1252 1 : if (ret)
1253 0 : eap_server_method_free(eap);
1254 1 : return ret;
1255 : }
|