GC wpa_supplicant 0.4.9
[dragonfly/port-amd64.git] / contrib / hostapd-0.4.9 / eap_peap.c
blob9eb61a6b132f31dbbbfe5c6c9f51932474ba339c
1 /*
2 * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <netinet/in.h>
20 #include "hostapd.h"
21 #include "common.h"
22 #include "eap_i.h"
23 #include "eap_tls_common.h"
24 #include "tls.h"
27 /* Maximum supported PEAP version
28 * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
29 * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
30 * 2 = draft-josefsson-ppext-eap-tls-eap-07.txt
32 #define EAP_PEAP_VERSION 1
35 static void eap_peap_reset(struct eap_sm *sm, void *priv);
38 struct eap_peap_data {
39 struct eap_ssl_data ssl;
40 enum {
41 START, PHASE1, PHASE2_START, PHASE2_ID, PHASE2_METHOD,
42 PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
43 } state;
45 int peap_version;
46 const struct eap_method *phase2_method;
47 void *phase2_priv;
48 int force_version;
52 static const char * eap_peap_state_txt(int state)
54 switch (state) {
55 case START:
56 return "START";
57 case PHASE1:
58 return "PHASE1";
59 case PHASE2_START:
60 return "PHASE2_START";
61 case PHASE2_ID:
62 return "PHASE2_ID";
63 case PHASE2_METHOD:
64 return "PHASE2_METHOD";
65 case PHASE2_TLV:
66 return "PHASE2_TLV";
67 case SUCCESS_REQ:
68 return "SUCCESS_REQ";
69 case FAILURE_REQ:
70 return "FAILURE_REQ";
71 case SUCCESS:
72 return "SUCCESS";
73 case FAILURE:
74 return "FAILURE";
75 default:
76 return "Unknown?!";
81 static void eap_peap_state(struct eap_peap_data *data, int state)
83 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
84 eap_peap_state_txt(data->state),
85 eap_peap_state_txt(state));
86 data->state = state;
90 static EapType eap_peap_req_success(struct eap_sm *sm,
91 struct eap_peap_data *data)
93 if (data->state == FAILURE || data->state == FAILURE_REQ) {
94 eap_peap_state(data, FAILURE);
95 return EAP_TYPE_NONE;
98 if (data->peap_version == 0) {
99 sm->tlv_request = TLV_REQ_SUCCESS;
100 eap_peap_state(data, PHASE2_TLV);
101 return EAP_TYPE_TLV;
102 } else {
103 eap_peap_state(data, SUCCESS_REQ);
104 return EAP_TYPE_NONE;
109 static EapType eap_peap_req_failure(struct eap_sm *sm,
110 struct eap_peap_data *data)
112 if (data->state == FAILURE || data->state == FAILURE_REQ ||
113 data->state == SUCCESS_REQ ||
114 (data->phase2_method &&
115 data->phase2_method->method == EAP_TYPE_TLV)) {
116 eap_peap_state(data, FAILURE);
117 return EAP_TYPE_NONE;
120 if (data->peap_version == 0) {
121 sm->tlv_request = TLV_REQ_FAILURE;
122 eap_peap_state(data, PHASE2_TLV);
123 return EAP_TYPE_TLV;
124 } else {
125 eap_peap_state(data, FAILURE_REQ);
126 return EAP_TYPE_NONE;
131 static void * eap_peap_init(struct eap_sm *sm)
133 struct eap_peap_data *data;
135 data = malloc(sizeof(*data));
136 if (data == NULL)
137 return data;
138 memset(data, 0, sizeof(*data));
139 data->peap_version = EAP_PEAP_VERSION;
140 data->force_version = -1;
141 if (sm->user && sm->user->force_version >= 0) {
142 data->force_version = sm->user->force_version;
143 wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",
144 data->force_version);
145 data->peap_version = data->force_version;
147 data->state = START;
149 if (eap_tls_ssl_init(sm, &data->ssl, 0)) {
150 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
151 eap_peap_reset(sm, data);
152 return NULL;
155 return data;
159 static void eap_peap_reset(struct eap_sm *sm, void *priv)
161 struct eap_peap_data *data = priv;
162 if (data == NULL)
163 return;
164 if (data->phase2_priv && data->phase2_method)
165 data->phase2_method->reset(sm, data->phase2_priv);
166 eap_tls_ssl_deinit(sm, &data->ssl);
167 free(data);
171 static u8 * eap_peap_build_start(struct eap_sm *sm, struct eap_peap_data *data,
172 int id, size_t *reqDataLen)
174 struct eap_hdr *req;
175 u8 *pos;
177 *reqDataLen = sizeof(*req) + 2;
178 req = malloc(*reqDataLen);
179 if (req == NULL) {
180 wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"
181 " request");
182 eap_peap_state(data, FAILURE);
183 return NULL;
186 req->code = EAP_CODE_REQUEST;
187 req->identifier = id;
188 req->length = htons(*reqDataLen);
189 pos = (u8 *) (req + 1);
190 *pos++ = EAP_TYPE_PEAP;
191 *pos = EAP_TLS_FLAGS_START | data->peap_version;
193 eap_peap_state(data, PHASE1);
195 return (u8 *) req;
199 static u8 * eap_peap_build_req(struct eap_sm *sm, struct eap_peap_data *data,
200 int id, size_t *reqDataLen)
202 int res;
203 u8 *req;
205 res = eap_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_PEAP,
206 data->peap_version, id, &req,
207 reqDataLen);
209 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
210 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, starting "
211 "Phase2");
212 eap_peap_state(data, PHASE2_START);
215 if (res == 1)
216 return eap_tls_build_ack(reqDataLen, id, EAP_TYPE_PEAP,
217 data->peap_version);
218 return req;
222 static u8 * eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
223 int id, u8 *plain, size_t plain_len,
224 size_t *out_len)
226 int res;
227 u8 *pos;
228 struct eap_hdr *req;
230 /* TODO: add support for fragmentation, if needed. This will need to
231 * add TLS Message Length field, if the frame is fragmented. */
232 req = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
233 if (req == NULL)
234 return NULL;
236 req->code = EAP_CODE_REQUEST;
237 req->identifier = id;
239 pos = (u8 *) (req + 1);
240 *pos++ = EAP_TYPE_PEAP;
241 *pos++ = data->peap_version;
243 res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
244 plain, plain_len,
245 pos, data->ssl.tls_out_limit);
246 if (res < 0) {
247 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
248 "data");
249 free(req);
250 return NULL;
253 *out_len = sizeof(struct eap_hdr) + 2 + res;
254 req->length = host_to_be16(*out_len);
255 return (u8 *) req;
259 static u8 * eap_peap_build_phase2_req(struct eap_sm *sm,
260 struct eap_peap_data *data,
261 int id, size_t *reqDataLen)
263 u8 *req, *buf, *encr_req;
264 size_t req_len;
266 buf = req = data->phase2_method->buildReq(sm, data->phase2_priv, id,
267 &req_len);
268 if (req == NULL)
269 return NULL;
271 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
272 req, req_len);
274 if (data->peap_version == 0 &&
275 data->phase2_method->method != EAP_TYPE_TLV) {
276 req += sizeof(struct eap_hdr);
277 req_len -= sizeof(struct eap_hdr);
280 encr_req = eap_peap_encrypt(sm, data, id, req, req_len, reqDataLen);
281 free(buf);
283 return encr_req;
287 static u8 * eap_peap_build_phase2_term(struct eap_sm *sm,
288 struct eap_peap_data *data,
289 int id, size_t *reqDataLen, int success)
291 u8 *encr_req;
292 size_t req_len;
293 struct eap_hdr *hdr;
295 req_len = sizeof(*hdr);
296 hdr = malloc(req_len);
297 if (hdr == NULL) {
298 return NULL;
301 memset(hdr, 0, req_len);
302 hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
303 hdr->identifier = id;
304 hdr->length = htons(req_len);
306 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
307 (u8 *) hdr, req_len);
309 encr_req = eap_peap_encrypt(sm, data, id, (u8 *) hdr, req_len,
310 reqDataLen);
311 free(hdr);
313 return encr_req;
317 static u8 * eap_peap_buildReq(struct eap_sm *sm, void *priv, int id,
318 size_t *reqDataLen)
320 struct eap_peap_data *data = priv;
322 switch (data->state) {
323 case START:
324 return eap_peap_build_start(sm, data, id, reqDataLen);
325 case PHASE1:
326 return eap_peap_build_req(sm, data, id, reqDataLen);
327 case PHASE2_ID:
328 case PHASE2_METHOD:
329 case PHASE2_TLV:
330 return eap_peap_build_phase2_req(sm, data, id, reqDataLen);
331 case SUCCESS_REQ:
332 return eap_peap_build_phase2_term(sm, data, id, reqDataLen, 1);
333 case FAILURE_REQ:
334 return eap_peap_build_phase2_term(sm, data, id, reqDataLen, 0);
335 default:
336 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
337 __func__, data->state);
338 return NULL;
343 static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
344 u8 *respData, size_t respDataLen)
346 struct eap_hdr *resp;
347 u8 *pos;
348 size_t len;
350 resp = (struct eap_hdr *) respData;
351 pos = (u8 *) (resp + 1);
352 if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_PEAP ||
353 (len = ntohs(resp->length)) > respDataLen) {
354 wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
355 return TRUE;
358 return FALSE;
362 static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
363 u8 eap_type)
365 if (data->phase2_priv && data->phase2_method) {
366 data->phase2_method->reset(sm, data->phase2_priv);
367 data->phase2_method = NULL;
368 data->phase2_priv = NULL;
370 data->phase2_method = eap_sm_get_eap_methods(eap_type);
371 if (!data->phase2_method)
372 return -1;
374 sm->init_phase2 = 1;
375 data->phase2_priv = data->phase2_method->init(sm);
376 sm->init_phase2 = 0;
377 return 0;
381 static void eap_peap_process_phase2_response(struct eap_sm *sm,
382 struct eap_peap_data *data,
383 u8 *in_data, size_t in_len)
385 u8 next_type = EAP_TYPE_NONE;
386 struct eap_hdr *hdr;
387 u8 *pos;
388 size_t left;
390 if (data->phase2_priv == NULL) {
391 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
392 "initialized?!", __func__);
393 return;
396 hdr = (struct eap_hdr *) in_data;
397 pos = (u8 *) (hdr + 1);
398 left = in_len - sizeof(*hdr);
400 if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
401 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
402 "allowed types", pos + 1, left - 1);
403 eap_sm_process_nak(sm, pos + 1, left - 1);
404 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
405 sm->user->methods[sm->user_eap_method_index] !=
406 EAP_TYPE_NONE) {
407 next_type =
408 sm->user->methods[sm->user_eap_method_index++];
409 wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
410 next_type);
411 } else {
412 next_type = eap_peap_req_failure(sm, data);
414 eap_peap_phase2_init(sm, data, next_type);
415 return;
418 if (data->phase2_method->check(sm, data->phase2_priv, in_data,
419 in_len)) {
420 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
421 "ignore the packet");
422 return;
425 data->phase2_method->process(sm, data->phase2_priv, in_data, in_len);
427 if (!data->phase2_method->isDone(sm, data->phase2_priv))
428 return;
431 if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
432 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
433 next_type = eap_peap_req_failure(sm, data);
434 eap_peap_phase2_init(sm, data, next_type);
435 return;
438 switch (data->state) {
439 case PHASE2_ID:
440 if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
441 wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
442 "Identity not found in the user "
443 "database",
444 sm->identity, sm->identity_len);
445 next_type = eap_peap_req_failure(sm, data);
446 break;
449 eap_peap_state(data, PHASE2_METHOD);
450 next_type = sm->user->methods[0];
451 sm->user_eap_method_index = 1;
452 wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
453 break;
454 case PHASE2_METHOD:
455 next_type = eap_peap_req_success(sm, data);
456 break;
457 case PHASE2_TLV:
458 if (sm->tlv_request == TLV_REQ_SUCCESS ||
459 data->state == SUCCESS_REQ) {
460 eap_peap_state(data, SUCCESS);
461 } else {
462 eap_peap_state(data, FAILURE);
464 break;
465 case FAILURE:
466 break;
467 default:
468 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
469 __func__, data->state);
470 break;
473 eap_peap_phase2_init(sm, data, next_type);
477 static void eap_peap_process_phase2(struct eap_sm *sm,
478 struct eap_peap_data *data,
479 struct eap_hdr *resp,
480 u8 *in_data, size_t in_len)
482 u8 *in_decrypted;
483 int buf_len, len_decrypted, len, res;
484 struct eap_hdr *hdr;
486 wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
487 " Phase 2", (unsigned long) in_len);
489 res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
490 if (res < 0 || res == 1)
491 return;
493 buf_len = in_len;
494 if (data->ssl.tls_in_total > buf_len)
495 buf_len = data->ssl.tls_in_total;
496 in_decrypted = malloc(buf_len);
497 if (in_decrypted == NULL) {
498 free(data->ssl.tls_in);
499 data->ssl.tls_in = NULL;
500 data->ssl.tls_in_len = 0;
501 wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
502 "for decryption");
503 return;
506 len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
507 in_data, in_len,
508 in_decrypted, buf_len);
509 free(data->ssl.tls_in);
510 data->ssl.tls_in = NULL;
511 data->ssl.tls_in_len = 0;
512 if (len_decrypted < 0) {
513 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
514 "data");
515 free(in_decrypted);
516 eap_peap_state(data, FAILURE);
517 return;
520 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
521 in_decrypted, len_decrypted);
523 hdr = (struct eap_hdr *) in_decrypted;
525 if (data->peap_version == 0 && data->state != PHASE2_TLV) {
526 struct eap_hdr *nhdr = malloc(sizeof(struct eap_hdr) +
527 len_decrypted);
528 if (nhdr == NULL) {
529 free(in_decrypted);
530 return;
532 memcpy((u8 *) (nhdr + 1), in_decrypted, len_decrypted);
533 free(in_decrypted);
534 nhdr->code = resp->code;
535 nhdr->identifier = resp->identifier;
536 nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
537 len_decrypted);
539 len_decrypted += sizeof(struct eap_hdr);
540 in_decrypted = (u8 *) nhdr;
542 hdr = (struct eap_hdr *) in_decrypted;
543 if (len_decrypted < sizeof(*hdr)) {
544 free(in_decrypted);
545 wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
546 "EAP frame (len=%d)", len_decrypted);
547 eap_peap_req_failure(sm, data);
548 return;
550 len = be_to_host16(hdr->length);
551 if (len > len_decrypted) {
552 free(in_decrypted);
553 wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
554 "Phase 2 EAP frame (len=%d hdr->length=%d)",
555 len_decrypted, len);
556 eap_peap_req_failure(sm, data);
557 return;
559 wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
560 "identifier=%d length=%d", hdr->code, hdr->identifier, len);
561 switch (hdr->code) {
562 case EAP_CODE_RESPONSE:
563 eap_peap_process_phase2_response(sm, data, (u8 *) hdr, len);
564 break;
565 case EAP_CODE_SUCCESS:
566 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
567 if (data->state == SUCCESS_REQ) {
568 eap_peap_state(data, SUCCESS);
570 break;
571 case EAP_CODE_FAILURE:
572 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
573 eap_peap_state(data, FAILURE);
574 break;
575 default:
576 wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
577 "Phase 2 EAP header", hdr->code);
578 break;
581 free(in_decrypted);
585 static void eap_peap_process(struct eap_sm *sm, void *priv,
586 u8 *respData, size_t respDataLen)
588 struct eap_peap_data *data = priv;
589 struct eap_hdr *resp;
590 u8 *pos, flags;
591 int left;
592 unsigned int tls_msg_len;
593 int peer_version;
595 resp = (struct eap_hdr *) respData;
596 pos = (u8 *) (resp + 1);
597 pos++;
598 flags = *pos++;
599 left = htons(resp->length) - sizeof(struct eap_hdr) - 2;
600 wpa_printf(MSG_DEBUG, "EAP-PEAP: Received packet(len=%lu) - "
601 "Flags 0x%02x", (unsigned long) respDataLen, flags);
602 peer_version = flags & EAP_PEAP_VERSION_MASK;
603 if (data->force_version >= 0 && peer_version != data->force_version) {
604 wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
605 " version (forced=%d peer=%d) - reject",
606 data->force_version, peer_version);
607 eap_peap_state(data, FAILURE);
608 return;
610 if (peer_version < data->peap_version) {
611 wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
612 "use version %d",
613 peer_version, data->peap_version, peer_version);
614 data->peap_version = peer_version;
617 if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
618 if (left < 4) {
619 wpa_printf(MSG_INFO, "EAP-PEAP: Short frame with TLS "
620 "length");
621 eap_peap_state(data, FAILURE);
622 return;
624 tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
625 pos[3];
626 wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS Message Length: %d",
627 tls_msg_len);
628 if (data->ssl.tls_in_left == 0) {
629 data->ssl.tls_in_total = tls_msg_len;
630 data->ssl.tls_in_left = tls_msg_len;
631 free(data->ssl.tls_in);
632 data->ssl.tls_in = NULL;
633 data->ssl.tls_in_len = 0;
635 pos += 4;
636 left -= 4;
639 switch (data->state) {
640 case PHASE1:
641 if (eap_tls_process_helper(sm, &data->ssl, pos, left) < 0) {
642 wpa_printf(MSG_INFO, "EAP-PEAP: TLS processing "
643 "failed");
644 eap_peap_state(data, FAILURE);
646 break;
647 case PHASE2_START:
648 eap_peap_state(data, PHASE2_ID);
649 eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
650 break;
651 case PHASE2_ID:
652 case PHASE2_METHOD:
653 case PHASE2_TLV:
654 eap_peap_process_phase2(sm, data, resp, pos, left);
655 break;
656 case SUCCESS_REQ:
657 eap_peap_state(data, SUCCESS);
658 break;
659 case FAILURE_REQ:
660 eap_peap_state(data, FAILURE);
661 break;
662 default:
663 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
664 data->state, __func__);
665 break;
668 if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
669 wpa_printf(MSG_INFO, "EAP-PEAP: Locally detected fatal error "
670 "in TLS processing");
671 eap_peap_state(data, FAILURE);
676 static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
678 struct eap_peap_data *data = priv;
679 return data->state == SUCCESS || data->state == FAILURE;
683 static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
685 struct eap_peap_data *data = priv;
686 u8 *eapKeyData;
688 if (data->state != SUCCESS)
689 return NULL;
691 /* TODO: PEAPv1 - different label in some cases */
692 eapKeyData = eap_tls_derive_key(sm, &data->ssl,
693 "client EAP encryption",
694 EAP_TLS_KEY_LEN);
695 if (eapKeyData) {
696 *len = EAP_TLS_KEY_LEN;
697 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
698 eapKeyData, EAP_TLS_KEY_LEN);
699 } else {
700 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key");
703 return eapKeyData;
707 static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
709 struct eap_peap_data *data = priv;
710 return data->state == SUCCESS;
714 const struct eap_method eap_method_peap =
716 .method = EAP_TYPE_PEAP,
717 .name = "PEAP",
718 .init = eap_peap_init,
719 .reset = eap_peap_reset,
720 .buildReq = eap_peap_buildReq,
721 .check = eap_peap_check,
722 .process = eap_peap_process,
723 .isDone = eap_peap_isDone,
724 .getKey = eap_peap_getKey,
725 .isSuccess = eap_peap_isSuccess,