Merge from vendor branch BIND:
[dragonfly.git] / contrib / hostapd-0.4.9 / eap_peap.c
1 /*
2  * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
3  * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
4  *
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.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <netinet/in.h>
19
20 #include "hostapd.h"
21 #include "common.h"
22 #include "eap_i.h"
23 #include "eap_tls_common.h"
24 #include "tls.h"
25
26
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
31  */
32 #define EAP_PEAP_VERSION 1
33
34
35 static void eap_peap_reset(struct eap_sm *sm, void *priv);
36
37
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;
44
45         int peap_version;
46         const struct eap_method *phase2_method;
47         void *phase2_priv;
48         int force_version;
49 };
50
51
52 static const char * eap_peap_state_txt(int state)
53 {
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?!";
77         }
78 }
79
80
81 static void eap_peap_state(struct eap_peap_data *data, int state)
82 {
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;
87 }
88
89
90 static EapType eap_peap_req_success(struct eap_sm *sm,
91                                     struct eap_peap_data *data)
92 {
93         if (data->state == FAILURE || data->state == FAILURE_REQ) {
94                 eap_peap_state(data, FAILURE);
95                 return EAP_TYPE_NONE;
96         }
97
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;
105         }
106 }
107
108
109 static EapType eap_peap_req_failure(struct eap_sm *sm,
110                                     struct eap_peap_data *data)
111 {
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;
118         }
119
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;
127         }
128 }
129
130
131 static void * eap_peap_init(struct eap_sm *sm)
132 {
133         struct eap_peap_data *data;
134
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;
146         }
147         data->state = START;
148
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;
153         }
154
155         return data;
156 }
157
158
159 static void eap_peap_reset(struct eap_sm *sm, void *priv)
160 {
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);
168 }
169
170
171 static u8 * eap_peap_build_start(struct eap_sm *sm, struct eap_peap_data *data,
172                                  int id, size_t *reqDataLen)
173 {
174         struct eap_hdr *req;
175         u8 *pos;
176
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;
184         }
185
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;
192
193         eap_peap_state(data, PHASE1);
194
195         return (u8 *) req;
196 }
197
198
199 static u8 * eap_peap_build_req(struct eap_sm *sm, struct eap_peap_data *data,
200                                int id, size_t *reqDataLen)
201 {
202         int res;
203         u8 *req;
204
205         res = eap_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_PEAP,
206                                       data->peap_version, id, &req,
207                                       reqDataLen);
208
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);
213         }
214
215         if (res == 1)
216                 return eap_tls_build_ack(reqDataLen, id, EAP_TYPE_PEAP,
217                                          data->peap_version);
218         return req;
219 }
220
221
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)
225 {
226         int res;
227         u8 *pos;
228         struct eap_hdr *req;
229
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;
235
236         req->code = EAP_CODE_REQUEST;
237         req->identifier = id;
238
239         pos = (u8 *) (req + 1);
240         *pos++ = EAP_TYPE_PEAP;
241         *pos++ = data->peap_version;
242
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;
251         }
252
253         *out_len = sizeof(struct eap_hdr) + 2 + res;
254         req->length = host_to_be16(*out_len);
255         return (u8 *) req;
256 }
257
258
259 static u8 * eap_peap_build_phase2_req(struct eap_sm *sm,
260                                       struct eap_peap_data *data,
261                                       int id, size_t *reqDataLen)
262 {
263         u8 *req, *buf, *encr_req;
264         size_t req_len;
265
266         buf = req = data->phase2_method->buildReq(sm, data->phase2_priv, id,
267                                                   &req_len);
268         if (req == NULL)
269                 return NULL;
270
271         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
272                         req, req_len);
273
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);
278         }
279
280         encr_req = eap_peap_encrypt(sm, data, id, req, req_len, reqDataLen);
281         free(buf);
282
283         return encr_req;
284 }
285
286
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)
290 {
291         u8 *encr_req;
292         size_t req_len;
293         struct eap_hdr *hdr;
294
295         req_len = sizeof(*hdr);
296         hdr = malloc(req_len);
297         if (hdr == NULL) {
298                 return NULL;
299         }
300
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);
305
306         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
307                         (u8 *) hdr, req_len);
308
309         encr_req = eap_peap_encrypt(sm, data, id, (u8 *) hdr, req_len,
310                                     reqDataLen);
311         free(hdr);
312
313         return encr_req;
314 }
315
316
317 static u8 * eap_peap_buildReq(struct eap_sm *sm, void *priv, int id,
318                               size_t *reqDataLen)
319 {
320         struct eap_peap_data *data = priv;
321
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;
339         }
340 }
341
342
343 static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
344                               u8 *respData, size_t respDataLen)
345 {
346         struct eap_hdr *resp;
347         u8 *pos;
348         size_t len;
349
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;
356         }
357
358         return FALSE;
359 }
360
361
362 static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
363                                 u8 eap_type)
364 {
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;
369         }
370         data->phase2_method = eap_sm_get_eap_methods(eap_type);
371         if (!data->phase2_method)
372                 return -1;
373
374         sm->init_phase2 = 1;
375         data->phase2_priv = data->phase2_method->init(sm);
376         sm->init_phase2 = 0;
377         return 0;
378 }
379
380
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)
384 {
385         u8 next_type = EAP_TYPE_NONE;
386         struct eap_hdr *hdr;
387         u8 *pos;
388         size_t left;
389
390         if (data->phase2_priv == NULL) {
391                 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
392                            "initialized?!", __func__);
393                 return;
394         }
395
396         hdr = (struct eap_hdr *) in_data;
397         pos = (u8 *) (hdr + 1);
398         left = in_len - sizeof(*hdr);
399
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);
413                 }
414                 eap_peap_phase2_init(sm, data, next_type);
415                 return;
416         }
417
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;
423         }
424
425         data->phase2_method->process(sm, data->phase2_priv, in_data, in_len);
426
427         if (!data->phase2_method->isDone(sm, data->phase2_priv))
428                 return;
429
430
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;
436         }
437
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;
447                 }
448
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);
463                 }
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;
471         }
472
473         eap_peap_phase2_init(sm, data, next_type);
474 }
475
476
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)
481 {
482         u8 *in_decrypted;
483         int buf_len, len_decrypted, len, res;
484         struct eap_hdr *hdr;
485
486         wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
487                    " Phase 2", (unsigned long) in_len);
488
489         res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
490         if (res < 0 || res == 1)
491                 return;
492
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;
504         }
505
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;
518         }
519
520         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
521                         in_decrypted, len_decrypted);
522
523         hdr = (struct eap_hdr *) in_decrypted;
524
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;
531                 }
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);
538
539                 len_decrypted += sizeof(struct eap_hdr);
540                 in_decrypted = (u8 *) nhdr;
541         }
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;
549         }
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;
558         }
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);
569                 }
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;
579         }
580
581         free(in_decrypted);
582  }
583
584
585 static void eap_peap_process(struct eap_sm *sm, void *priv,
586                              u8 *respData, size_t respDataLen)
587 {
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;
594
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;
609         }
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;
615                            
616         }
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;
623                 }
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;
634                 }
635                 pos += 4;
636                 left -= 4;
637         }
638
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);
645                 }
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;
666         }
667
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);
672         }
673 }
674
675
676 static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
677 {
678         struct eap_peap_data *data = priv;
679         return data->state == SUCCESS || data->state == FAILURE;
680 }
681
682
683 static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
684 {
685         struct eap_peap_data *data = priv;
686         u8 *eapKeyData;
687
688         if (data->state != SUCCESS)
689                 return NULL;
690
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");
701         }
702
703         return eapKeyData;
704 }
705
706
707 static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
708 {
709         struct eap_peap_data *data = priv;
710         return data->state == SUCCESS;
711 }
712
713
714 const struct eap_method eap_method_peap =
715 {
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,
726 };