EAP-PEAP: Added preliminary code for PEAPv0 and PEAPv2 cryptobinding
[wpasupplicant] / src / eap_peer / eap_peap.c
1 /*
2  * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
3  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.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 "includes.h"
16
17 #include "common.h"
18 #include "crypto/sha1.h"
19 #include "eap_i.h"
20 #include "eap_tls_common.h"
21 #include "eap_config.h"
22 #include "tls.h"
23 #include "eap_common/eap_tlv_common.h"
24
25
26 /* Maximum supported PEAP version
27  * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
28  * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
29  * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
30  */
31 #define EAP_PEAP_VERSION 1
32
33
34 static void eap_peap_deinit(struct eap_sm *sm, void *priv);
35
36
37 struct eap_peap_data {
38         struct eap_ssl_data ssl;
39
40         int peap_version, force_peap_version, force_new_label;
41
42         const struct eap_method *phase2_method;
43         void *phase2_priv;
44         int phase2_success;
45         int phase2_eap_success;
46         int phase2_eap_started;
47
48         struct eap_method_type phase2_type;
49         struct eap_method_type *phase2_types;
50         size_t num_phase2_types;
51
52         int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
53                                  * EAP-Success
54                                  * 1 = reply with tunneled EAP-Success to inner
55                                  * EAP-Success and expect AS to send outer
56                                  * (unencrypted) EAP-Success after this
57                                  * 2 = reply with PEAP/TLS ACK to inner
58                                  * EAP-Success and expect AS to send outer
59                                  * (unencrypted) EAP-Success after this */
60         int resuming; /* starting a resumed session */
61         u8 *key_data;
62
63         struct wpabuf *pending_phase2_req;
64         enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
65         int crypto_binding_used;
66         u8 ipmk[40];
67         u8 cmk[20];
68 };
69
70
71 static int eap_peap_parse_phase1(struct eap_peap_data *data,
72                                  const char *phase1)
73 {
74         const char *pos;
75
76         pos = os_strstr(phase1, "peapver=");
77         if (pos) {
78                 data->force_peap_version = atoi(pos + 8);
79                 data->peap_version = data->force_peap_version;
80                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d",
81                            data->force_peap_version);
82         }
83
84         if (os_strstr(phase1, "peaplabel=1")) {
85                 data->force_new_label = 1;
86                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key "
87                            "derivation");
88         }
89
90         if (os_strstr(phase1, "peap_outer_success=0")) {
91                 data->peap_outer_success = 0;
92                 wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on "
93                            "tunneled EAP-Success");
94         } else if (os_strstr(phase1, "peap_outer_success=1")) {
95                 data->peap_outer_success = 1;
96                 wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success "
97                            "after receiving tunneled EAP-Success");
98         } else if (os_strstr(phase1, "peap_outer_success=2")) {
99                 data->peap_outer_success = 2;
100                 wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after "
101                            "receiving tunneled EAP-Success");
102         }
103
104         return 0;
105 }
106
107
108 static void * eap_peap_init(struct eap_sm *sm)
109 {
110         struct eap_peap_data *data;
111         struct eap_peer_config *config = eap_get_config(sm);
112
113         data = os_zalloc(sizeof(*data));
114         if (data == NULL)
115                 return NULL;
116         sm->peap_done = FALSE;
117         data->peap_version = EAP_PEAP_VERSION;
118         data->force_peap_version = -1;
119         data->peap_outer_success = 2;
120         data->crypto_binding = NO_BINDING;
121
122         if (config && config->phase1 &&
123             eap_peap_parse_phase1(data, config->phase1) < 0) {
124                 eap_peap_deinit(sm, data);
125                 return NULL;
126         }
127
128         if (eap_peer_select_phase2_methods(config, "auth=",
129                                            &data->phase2_types,
130                                            &data->num_phase2_types) < 0) {
131                 eap_peap_deinit(sm, data);
132                 return NULL;
133         }
134
135         data->phase2_type.vendor = EAP_VENDOR_IETF;
136         data->phase2_type.method = EAP_TYPE_NONE;
137
138         if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
139                 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
140                 eap_peap_deinit(sm, data);
141                 return NULL;
142         }
143
144         return data;
145 }
146
147
148 static void eap_peap_deinit(struct eap_sm *sm, void *priv)
149 {
150         struct eap_peap_data *data = priv;
151         if (data == NULL)
152                 return;
153         if (data->phase2_priv && data->phase2_method)
154                 data->phase2_method->deinit(sm, data->phase2_priv);
155         os_free(data->phase2_types);
156         eap_peer_tls_ssl_deinit(sm, &data->ssl);
157         os_free(data->key_data);
158         wpabuf_free(data->pending_phase2_req);
159         os_free(data);
160 }
161
162
163 /**
164  * eap_tlv_build_nak - Build EAP-TLV NAK message
165  * @id: EAP identifier for the header
166  * @nak_type: TLV type (EAP_TLV_*)
167  * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
168  *
169  * This funtion builds an EAP-TLV NAK message. The caller is responsible for
170  * freeing the returned buffer.
171  */
172 static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
173 {
174         struct wpabuf *msg;
175
176         msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10,
177                             EAP_CODE_RESPONSE, id);
178         if (msg == NULL)
179                 return NULL;
180
181         wpabuf_put_u8(msg, 0x80); /* Mandatory */
182         wpabuf_put_u8(msg, EAP_TLV_NAK_TLV);
183         wpabuf_put_be16(msg, 6); /* Length */
184         wpabuf_put_be32(msg, 0); /* Vendor-Id */
185         wpabuf_put_be16(msg, nak_type); /* NAK-Type */
186
187         return msg;
188 }
189
190
191 static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
192                             u8 *isk, size_t isk_len)
193 {
194         u8 *key;
195         size_t key_len;
196
197         os_memset(isk, 0, isk_len);
198         if (data->phase2_method == NULL || data->phase2_priv == NULL ||
199             data->phase2_method->isKeyAvailable == NULL ||
200             data->phase2_method->getKey == NULL)
201                 return 0;
202
203         if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
204             (key = data->phase2_method->getKey(sm, data->phase2_priv,
205                                                &key_len)) == NULL) {
206                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material "
207                            "from Phase 2");
208                 return -1;
209         }
210
211         if (key_len > isk_len)
212                 key_len = isk_len;
213         os_memcpy(isk, key, key_len);
214         os_free(key);
215
216         return 0;
217 }
218
219
220 void peap_prfplus(int version, const u8 *key, size_t key_len,
221                   const char *label, const u8 *seed, size_t seed_len,
222                   u8 *buf, size_t buf_len)
223 {
224         unsigned char counter = 0;
225         size_t pos, plen;
226         u8 hash[SHA1_MAC_LEN];
227         size_t label_len = os_strlen(label);
228         u8 extra[2];
229         const unsigned char *addr[5];
230         size_t len[5];
231
232         addr[0] = hash;
233         len[0] = 0;
234         addr[1] = (unsigned char *) label;
235         len[1] = label_len;
236         addr[2] = seed;
237         len[2] = seed_len;
238
239         if (version == 0) {
240                 /*
241                  * PRF+(K, S, LEN) = T1 | T2 | ... | Tn
242                  * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00)
243                  * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00)
244                  * ...
245                  * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00)
246                  */
247
248                 extra[0] = 0;
249                 extra[1] = 0;
250
251                 addr[3] = &counter;
252                 len[3] = 1;
253                 addr[4] = extra;
254                 len[4] = 2;
255         } else {
256                 /*
257                  * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where:
258                  * T1 = HMAC-SHA1(K, S | LEN | 0x01)
259                  * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02)
260                  * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03)
261                  * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04)
262                  *   ...
263                  */
264
265                 extra[0] = buf_len & 0xff;
266
267                 addr[3] = extra;
268                 len[3] = 1;
269                 addr[4] = &counter;
270                 len[4] = 1;
271         }
272
273         pos = 0;
274         while (pos < buf_len) {
275                 counter++;
276                 plen = buf_len - pos;
277                 hmac_sha1_vector(key, key_len, 5, addr, len, hash);
278                 if (plen >= SHA1_MAC_LEN) {
279                         os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
280                         pos += SHA1_MAC_LEN;
281                 } else {
282                         os_memcpy(&buf[pos], hash, plen);
283                         break;
284                 }
285                 len[0] = SHA1_MAC_LEN;
286         }
287 }
288
289
290 static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
291 {
292         u8 *tk;
293         u8 isk[32], imck[60];
294
295         /*
296          * Tunnel key (TK) is the first 60 octets of the key generated by
297          * phase 1 of PEAP (based on TLS).
298          */
299         tk = data->key_data;
300         if (tk == NULL)
301                 return -1;
302         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
303
304         if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
305                 return -1;
306         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
307
308         /*
309          * IPMK Seed = "Inner Methods Compound Keys" | ISK
310          * TempKey = First 40 octets of TK
311          * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
312          * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
313          * in the end of the label just before ISK; is that just a typo?)
314          */
315         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
316         peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
317                      isk, sizeof(isk), imck, sizeof(imck));
318         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
319                         imck, sizeof(imck));
320
321         /* TODO: fast-connect: IPMK|CMK = TK */
322         os_memcpy(data->ipmk, imck, 40);
323         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
324         os_memcpy(data->cmk, imck + 40, 20);
325         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
326
327         return 0;
328 }
329
330
331 static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
332                                      struct eap_peap_data *data,
333                                      struct wpabuf *buf)
334 {
335         u8 *mac;
336         u8 eap_type = EAP_TYPE_PEAP;
337         const u8 *addr[2];
338         size_t len[2];
339         u16 tlv_type;
340         u8 binding_nonce[32];
341
342         /* FIX: should binding_nonce be copied from request? */
343         if (os_get_random(binding_nonce, 32))
344                 return -1;
345
346         /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
347         addr[0] = wpabuf_put(buf, 0);
348         len[0] = 60;
349         addr[1] = &eap_type;
350         len[1] = 1;
351
352         tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
353         if (data->peap_version >= 2)
354                 tlv_type |= EAP_TLV_TYPE_MANDATORY;
355         wpabuf_put_be16(buf, tlv_type);
356         wpabuf_put_be16(buf, 56);
357
358         wpabuf_put_u8(buf, 0); /* Reserved */
359         wpabuf_put_u8(buf, data->peap_version); /* Version */
360         wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
361         wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
362         wpabuf_put_data(buf, binding_nonce, 32); /* Nonce */
363         mac = wpabuf_put(buf, 20); /* Compound_MAC */
364         wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
365         wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
366                     addr[0], len[0]);
367         wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
368                     addr[1], len[1]);
369         hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
370         wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
371         data->crypto_binding_used = 1;
372
373         return 0;
374 }
375
376
377 /**
378  * eap_tlv_build_result - Build EAP-TLV Result message
379  * @id: EAP identifier for the header
380  * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
381  * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
382  *
383  * This funtion builds an EAP-TLV Result message. The caller is responsible for
384  * freeing the returned buffer.
385  */
386 static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
387                                             struct eap_peap_data *data,
388                                             int crypto_tlv_used,
389                                             int id, u16 status)
390 {
391         struct wpabuf *msg;
392         size_t len;
393
394         if (data->crypto_binding == NO_BINDING)
395                 crypto_tlv_used = 0;
396
397         len = 6;
398         if (crypto_tlv_used)
399                 len += 60; /* Cryptobinding TLV */
400         msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
401                             EAP_CODE_RESPONSE, id);
402         if (msg == NULL)
403                 return NULL;
404
405         wpabuf_put_u8(msg, 0x80); /* Mandatory */
406         wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
407         wpabuf_put_be16(msg, 2); /* Length */
408         wpabuf_put_be16(msg, status); /* Status */
409
410         if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
411                 wpabuf_free(msg);
412                 return NULL;
413         }
414
415         return msg;
416 }
417
418
419 static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
420                                           struct eap_peap_data *data,
421                                           const u8 *crypto_tlv,
422                                           size_t crypto_tlv_len)
423 {
424         u8 buf[61], mac[SHA1_MAC_LEN];
425         const u8 *pos;
426
427         if (eap_peap_derive_cmk(sm, data) < 0) {
428                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
429                 return -1;
430         }
431
432         if (crypto_tlv_len != 4 + 56) {
433                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
434                            "length %d", (int) crypto_tlv_len);
435                 return -1;
436         }
437
438         pos = crypto_tlv;
439         pos += 4; /* TLV header */
440         if (pos[1] != data->peap_version) {
441                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
442                            "mismatch (was %d; expected %d)",
443                            pos[1], data->peap_version);
444                 return -1;
445         }
446
447         if (pos[3] != 0) {
448                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
449                            "SubType %d", pos[3]);
450                 return -1;
451         }
452         pos += 4;
453         pos += 32; /* Nonce */
454
455         /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
456         os_memcpy(buf, crypto_tlv, 60);
457         os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
458         buf[60] = EAP_TYPE_PEAP;
459         hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
460
461         if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
462                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
463                            "cryptobinding TLV");
464                 return -1;
465         }
466
467         wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
468
469         return 0;
470 }
471
472
473 /**
474  * eap_tlv_process - Process a received EAP-TLV message and generate a response
475  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
476  * @ret: Return values from EAP request validation and processing
477  * @req: EAP-TLV request to be processed. The caller must have validated that
478  * the buffer is large enough to contain full request (hdr->length bytes) and
479  * that the EAP type is EAP_TYPE_TLV.
480  * @resp: Buffer to return a pointer to the allocated response message. This
481  * field should be initialized to %NULL before the call. The value will be
482  * updated if a response message is generated. The caller is responsible for
483  * freeing the allocated message.
484  * @force_failure: Force negotiation to fail
485  * Returns: 0 on success, -1 on failure
486  */
487 static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
488                            struct eap_method_ret *ret,
489                            const struct wpabuf *req, struct wpabuf **resp,
490                            int force_failure)
491 {
492         size_t left, tlv_len;
493         const u8 *pos;
494         const u8 *result_tlv = NULL, *crypto_tlv = NULL;
495         size_t result_tlv_len = 0, crypto_tlv_len = 0;
496         int tlv_type, mandatory;
497
498         /* Parse TLVs */
499         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
500         if (pos == NULL)
501                 return -1;
502         wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
503         while (left >= 4) {
504                 mandatory = !!(pos[0] & 0x80);
505                 tlv_type = WPA_GET_BE16(pos) & 0x3fff;
506                 pos += 2;
507                 tlv_len = WPA_GET_BE16(pos);
508                 pos += 2;
509                 left -= 4;
510                 if (tlv_len > left) {
511                         wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
512                                    "(tlv_len=%lu left=%lu)",
513                                    (unsigned long) tlv_len,
514                                    (unsigned long) left);
515                         return -1;
516                 }
517                 switch (tlv_type) {
518                 case EAP_TLV_RESULT_TLV:
519                         result_tlv = pos;
520                         result_tlv_len = tlv_len;
521                         break;
522                 case EAP_TLV_CRYPTO_BINDING_TLV:
523                         crypto_tlv = pos;
524                         crypto_tlv_len = tlv_len;
525                         break;
526                 default:
527                         wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
528                                    "%d%s", tlv_type,
529                                    mandatory ? " (mandatory)" : "");
530                         if (mandatory) {
531                                 /* NAK TLV and ignore all TLVs in this packet.
532                                  */
533                                 *resp = eap_tlv_build_nak(eap_get_id(req),
534                                                           tlv_type);
535                                 return *resp == NULL ? -1 : 0;
536                         }
537                         /* Ignore this TLV, but process other TLVs */
538                         break;
539                 }
540
541                 pos += tlv_len;
542                 left -= tlv_len;
543         }
544         if (left) {
545                 wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
546                            "Request (left=%lu)", (unsigned long) left);
547                 return -1;
548         }
549
550         /* Process supported TLVs */
551         if (crypto_tlv && data->crypto_binding != NO_BINDING) {
552                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
553                             crypto_tlv, crypto_tlv_len);
554                 if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
555                                                    crypto_tlv_len + 4) < 0) {
556                         if (result_tlv == NULL)
557                                 return -1;
558                         force_failure = 1;
559                 }
560         } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
561                 wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
562                 return -1;
563         }
564
565         if (result_tlv) {
566                 int status, resp_status;
567                 wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
568                             result_tlv, result_tlv_len);
569                 if (result_tlv_len < 2) {
570                         wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
571                                    "(len=%lu)",
572                                    (unsigned long) result_tlv_len);
573                         return -1;
574                 }
575                 status = WPA_GET_BE16(result_tlv);
576                 if (status == EAP_TLV_RESULT_SUCCESS) {
577                         wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
578                                    "- EAP-TLV/Phase2 Completed");
579                         if (force_failure) {
580                                 wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
581                                            " - force failed Phase 2");
582                                 resp_status = EAP_TLV_RESULT_FAILURE;
583                                 ret->decision = DECISION_FAIL;
584                         } else {
585                                 resp_status = EAP_TLV_RESULT_SUCCESS;
586                                 ret->decision = DECISION_UNCOND_SUCC;
587                         }
588                 } else if (status == EAP_TLV_RESULT_FAILURE) {
589                         wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
590                         resp_status = EAP_TLV_RESULT_FAILURE;
591                         ret->decision = DECISION_FAIL;
592                 } else {
593                         wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
594                                    "Status %d", status);
595                         resp_status = EAP_TLV_RESULT_FAILURE;
596                         ret->decision = DECISION_FAIL;
597                 }
598                 ret->methodState = METHOD_DONE;
599
600                 *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
601                                              eap_get_id(req), resp_status);
602         }
603
604         return 0;
605 }
606
607
608 static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
609 {
610         struct wpabuf *e;
611         struct eap_tlv_hdr *tlv;
612
613         if (buf == NULL)
614                 return NULL;
615
616         /* Encapsulate EAP packet in EAP-Payload TLV */
617         wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
618         e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
619         if (e == NULL) {
620                 wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
621                            "for TLV encapsulation");
622                 wpabuf_free(buf);
623                 return NULL;
624         }
625         tlv = wpabuf_put(e, sizeof(*tlv));
626         tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
627                                      EAP_TLV_EAP_PAYLOAD_TLV);
628         tlv->length = host_to_be16(wpabuf_len(buf));
629         wpabuf_put_buf(e, buf);
630         wpabuf_free(buf);
631         return e;
632 }
633
634
635 static int eap_peap_phase2_request(struct eap_sm *sm,
636                                    struct eap_peap_data *data,
637                                    struct eap_method_ret *ret,
638                                    struct wpabuf *req,
639                                    struct wpabuf **resp)
640 {
641         struct eap_hdr *hdr = wpabuf_mhead(req);
642         size_t len = be_to_host16(hdr->length);
643         u8 *pos;
644         struct eap_method_ret iret;
645         struct eap_peer_config *config = eap_get_config(sm);
646
647         if (len <= sizeof(struct eap_hdr)) {
648                 wpa_printf(MSG_INFO, "EAP-PEAP: too short "
649                            "Phase 2 request (len=%lu)", (unsigned long) len);
650                 return -1;
651         }
652         pos = (u8 *) (hdr + 1);
653         wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
654         switch (*pos) {
655         case EAP_TYPE_IDENTITY:
656                 *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
657                 break;
658         case EAP_TYPE_TLV:
659                 os_memset(&iret, 0, sizeof(iret));
660                 if (eap_tlv_process(sm, data, &iret, req, resp,
661                                     data->phase2_eap_started &&
662                                     !data->phase2_eap_success)) {
663                         ret->methodState = METHOD_DONE;
664                         ret->decision = DECISION_FAIL;
665                         return -1;
666                 }
667                 if (iret.methodState == METHOD_DONE ||
668                     iret.methodState == METHOD_MAY_CONT) {
669                         ret->methodState = iret.methodState;
670                         ret->decision = iret.decision;
671                         data->phase2_success = 1;
672                 }
673                 break;
674         default:
675                 if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
676                     data->phase2_type.method == EAP_TYPE_NONE) {
677                         size_t i;
678                         for (i = 0; i < data->num_phase2_types; i++) {
679                                 if (data->phase2_types[i].vendor !=
680                                     EAP_VENDOR_IETF ||
681                                     data->phase2_types[i].method != *pos)
682                                         continue;
683
684                                 data->phase2_type.vendor =
685                                         data->phase2_types[i].vendor;
686                                 data->phase2_type.method =
687                                         data->phase2_types[i].method;
688                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
689                                            "Phase 2 EAP vendor %d method %d",
690                                            data->phase2_type.vendor,
691                                            data->phase2_type.method);
692                                 break;
693                         }
694                 }
695                 if (*pos != data->phase2_type.method ||
696                     *pos == EAP_TYPE_NONE) {
697                         if (eap_peer_tls_phase2_nak(data->phase2_types,
698                                                     data->num_phase2_types,
699                                                     hdr, resp))
700                                 return -1;
701                         return 0;
702                 }
703
704                 if (data->phase2_priv == NULL) {
705                         data->phase2_method = eap_peer_get_eap_method(
706                                 data->phase2_type.vendor,
707                                 data->phase2_type.method);
708                         if (data->phase2_method) {
709                                 sm->init_phase2 = 1;
710                                 sm->mschapv2_full_key = 1;
711                                 data->phase2_priv =
712                                         data->phase2_method->init(sm);
713                                 sm->init_phase2 = 0;
714                                 sm->mschapv2_full_key = 0;
715                         }
716                 }
717                 if (data->phase2_priv == NULL || data->phase2_method == NULL) {
718                         wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
719                                    "Phase 2 EAP method %d", *pos);
720                         ret->methodState = METHOD_DONE;
721                         ret->decision = DECISION_FAIL;
722                         return -1;
723                 }
724                 data->phase2_eap_started = 1;
725                 os_memset(&iret, 0, sizeof(iret));
726                 *resp = data->phase2_method->process(sm, data->phase2_priv,
727                                                      &iret, req);
728                 if ((iret.methodState == METHOD_DONE ||
729                      iret.methodState == METHOD_MAY_CONT) &&
730                     (iret.decision == DECISION_UNCOND_SUCC ||
731                      iret.decision == DECISION_COND_SUCC)) {
732                         data->phase2_eap_success = 1;
733                         data->phase2_success = 1;
734                 }
735                 break;
736         }
737
738         if (*resp == NULL &&
739             (config->pending_req_identity || config->pending_req_password ||
740              config->pending_req_otp || config->pending_req_new_password)) {
741                 wpabuf_free(data->pending_phase2_req);
742                 data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
743         }
744
745         return 0;
746 }
747
748
749 static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
750                             struct eap_method_ret *ret,
751                             const struct eap_hdr *req,
752                             const struct wpabuf *in_data,
753                             struct wpabuf **out_data)
754 {
755         struct wpabuf *in_decrypted = NULL;
756         int res, skip_change = 0;
757         struct eap_hdr *hdr, *rhdr;
758         struct wpabuf *resp = NULL;
759         size_t len;
760
761         wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
762                    " Phase 2", (unsigned long) wpabuf_len(in_data));
763
764         if (data->pending_phase2_req) {
765                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
766                            "skip decryption and use old data");
767                 /* Clear TLS reassembly state. */
768                 eap_peer_tls_reset_input(&data->ssl);
769                 in_decrypted = data->pending_phase2_req;
770                 data->pending_phase2_req = NULL;
771                 skip_change = 1;
772                 goto continue_req;
773         }
774
775         if (wpabuf_len(in_data) == 0 && sm->workaround &&
776             data->phase2_success) {
777                 /*
778                  * Cisco ACS seems to be using TLS ACK to terminate
779                  * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
780                  */
781                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
782                            "expected data - acknowledge with TLS ACK since "
783                            "Phase 2 has been completed");
784                 ret->decision = DECISION_COND_SUCC;
785                 ret->methodState = METHOD_DONE;
786                 return 1;
787         } else if (wpabuf_len(in_data) == 0) {
788                 /* Received TLS ACK - requesting more fragments */
789                 return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
790                                             data->peap_version,
791                                             req->identifier, NULL, out_data);
792         }
793
794         res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
795         if (res)
796                 return res;
797
798 continue_req:
799         wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
800                         in_decrypted);
801
802         hdr = wpabuf_mhead(in_decrypted);
803         if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST &&
804             be_to_host16(hdr->length) == 5 &&
805             eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) {
806                 /* At least FreeRADIUS seems to send full EAP header with
807                  * EAP Request Identity */
808                 skip_change = 1;
809         }
810         if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST &&
811             eap_get_type(in_decrypted) == EAP_TYPE_TLV) {
812                 skip_change = 1;
813         }
814
815         if (data->peap_version == 0 && !skip_change) {
816                 struct eap_hdr *nhdr;
817                 struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
818                                                    wpabuf_len(in_decrypted));
819                 if (nmsg == NULL) {
820                         wpabuf_free(in_decrypted);
821                         return 0;
822                 }
823                 nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
824                 wpabuf_put_buf(nmsg, in_decrypted);
825                 nhdr->code = req->code;
826                 nhdr->identifier = req->identifier;
827                 nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
828                                             wpabuf_len(in_decrypted));
829
830                 wpabuf_free(in_decrypted);
831                 in_decrypted = nmsg;
832         }
833
834         if (data->peap_version >= 2) {
835                 struct eap_tlv_hdr *tlv;
836                 struct wpabuf *nmsg;
837
838                 if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
839                         wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
840                                    "EAP TLV");
841                         wpabuf_free(in_decrypted);
842                         return 0;
843                 }
844                 tlv = wpabuf_mhead(in_decrypted);
845                 if ((be_to_host16(tlv->tlv_type) & 0x3fff) !=
846                     EAP_TLV_EAP_PAYLOAD_TLV) {
847                         wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
848                         wpabuf_free(in_decrypted);
849                         return 0;
850                 }
851                 if (sizeof(*tlv) + be_to_host16(tlv->length) >
852                     wpabuf_len(in_decrypted)) {
853                         wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
854                                    "length");
855                         wpabuf_free(in_decrypted);
856                         return 0;
857                 }
858                 hdr = (struct eap_hdr *) (tlv + 1);
859                 if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
860                         wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
861                                    "EAP packet in EAP TLV");
862                         wpabuf_free(in_decrypted);
863                         return 0;
864                 }
865
866                 nmsg = wpabuf_alloc(be_to_host16(hdr->length));
867                 if (nmsg == NULL) {
868                         wpabuf_free(in_decrypted);
869                         return 0;
870                 }
871
872                 wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
873                 wpabuf_free(in_decrypted);
874                 in_decrypted = nmsg;
875         }
876
877         hdr = wpabuf_mhead(in_decrypted);
878         if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
879                 wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
880                            "EAP frame (len=%lu)",
881                            (unsigned long) wpabuf_len(in_decrypted));
882                 wpabuf_free(in_decrypted);
883                 return 0;
884         }
885         len = be_to_host16(hdr->length);
886         if (len > wpabuf_len(in_decrypted)) {
887                 wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
888                            "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
889                            (unsigned long) wpabuf_len(in_decrypted),
890                            (unsigned long) len);
891                 wpabuf_free(in_decrypted);
892                 return 0;
893         }
894         if (len < wpabuf_len(in_decrypted)) {
895                 wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
896                            "shorter length than full decrypted data "
897                            "(%lu < %lu)",
898                            (unsigned long) len,
899                            (unsigned long) wpabuf_len(in_decrypted));
900         }
901         wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
902                    "identifier=%d length=%lu", hdr->code, hdr->identifier,
903                    (unsigned long) len);
904         switch (hdr->code) {
905         case EAP_CODE_REQUEST:
906                 if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
907                                             &resp)) {
908                         wpabuf_free(in_decrypted);
909                         wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
910                                    "processing failed");
911                         return 0;
912                 }
913                 break;
914         case EAP_CODE_SUCCESS:
915                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
916                 if (data->peap_version == 1) {
917                         /* EAP-Success within TLS tunnel is used to indicate
918                          * shutdown of the TLS channel. The authentication has
919                          * been completed. */
920                         if (data->phase2_eap_started &&
921                             !data->phase2_eap_success) {
922                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
923                                            "Success used to indicate success, "
924                                            "but Phase 2 EAP was not yet "
925                                            "completed successfully");
926                                 ret->methodState = METHOD_DONE;
927                                 ret->decision = DECISION_FAIL;
928                                 wpabuf_free(in_decrypted);
929                                 return 0;
930                         }
931                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
932                                    "EAP-Success within TLS tunnel - "
933                                    "authentication completed");
934                         ret->decision = DECISION_UNCOND_SUCC;
935                         ret->methodState = METHOD_DONE;
936                         data->phase2_success = 1;
937                         if (data->peap_outer_success == 2) {
938                                 wpabuf_free(in_decrypted);
939                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
940                                            "to finish authentication");
941                                 return 1;
942                         } else if (data->peap_outer_success == 1) {
943                                 /* Reply with EAP-Success within the TLS
944                                  * channel to complete the authentication. */
945                                 resp = wpabuf_alloc(sizeof(struct eap_hdr));
946                                 if (resp) {
947                                         rhdr = wpabuf_put(resp, sizeof(*rhdr));
948                                         rhdr->code = EAP_CODE_SUCCESS;
949                                         rhdr->identifier = hdr->identifier;
950                                         rhdr->length =
951                                                 host_to_be16(sizeof(*rhdr));
952                                 }
953                         } else {
954                                 /* No EAP-Success expected for Phase 1 (outer,
955                                  * unencrypted auth), so force EAP state
956                                  * machine to SUCCESS state. */
957                                 sm->peap_done = TRUE;
958                         }
959                 } else {
960                         /* FIX: ? */
961                 }
962                 break;
963         case EAP_CODE_FAILURE:
964                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
965                 ret->decision = DECISION_FAIL;
966                 ret->methodState = METHOD_MAY_CONT;
967                 ret->allowNotifications = FALSE;
968                 /* Reply with EAP-Failure within the TLS channel to complete
969                  * failure reporting. */
970                 resp = wpabuf_alloc(sizeof(struct eap_hdr));
971                 if (resp) {
972                         rhdr = wpabuf_put(resp, sizeof(*rhdr));
973                         rhdr->code = EAP_CODE_FAILURE;
974                         rhdr->identifier = hdr->identifier;
975                         rhdr->length = host_to_be16(sizeof(*rhdr));
976                 }
977                 break;
978         default:
979                 wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
980                            "Phase 2 EAP header", hdr->code);
981                 break;
982         }
983
984         wpabuf_free(in_decrypted);
985
986         if (resp) {
987                 int skip_change2 = 0;
988                 struct wpabuf *rmsg, buf;
989
990                 wpa_hexdump_buf_key(MSG_DEBUG,
991                                     "EAP-PEAP: Encrypting Phase 2 data", resp);
992                 /* PEAP version changes */
993                 if (data->peap_version >= 2) {
994                         resp = eap_peapv2_tlv_eap_payload(resp);
995                         if (resp == NULL)
996                                 return -1;
997                 }
998                 if (wpabuf_len(resp) >= 5 &&
999                     wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
1000                     eap_get_type(resp) == EAP_TYPE_TLV)
1001                         skip_change2 = 1;
1002                 rmsg = resp;
1003                 if (data->peap_version == 0 && !skip_change2) {
1004                         wpabuf_set(&buf, wpabuf_head_u8(resp) +
1005                                    sizeof(struct eap_hdr),
1006                                    wpabuf_len(resp) - sizeof(struct eap_hdr));
1007                         rmsg = &buf;
1008                 }
1009
1010                 if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
1011                                          data->peap_version, req->identifier,
1012                                          rmsg, out_data)) {
1013                         wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
1014                                    "a Phase 2 frame");
1015                 }
1016                 wpabuf_free(resp);
1017         }
1018
1019         return 0;
1020 }
1021
1022
1023 static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
1024                                         struct eap_method_ret *ret,
1025                                         const struct wpabuf *reqData)
1026 {
1027         const struct eap_hdr *req;
1028         size_t left;
1029         int res;
1030         u8 flags, id;
1031         struct wpabuf *resp;
1032         const u8 *pos;
1033         struct eap_peap_data *data = priv;
1034
1035         pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
1036                                         reqData, &left, &flags);
1037         if (pos == NULL)
1038                 return NULL;
1039         req = wpabuf_head(reqData);
1040         id = req->identifier;
1041
1042         if (flags & EAP_TLS_FLAGS_START) {
1043                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
1044                            "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
1045                         data->peap_version);
1046                 if ((flags & EAP_PEAP_VERSION_MASK) < data->peap_version)
1047                         data->peap_version = flags & EAP_PEAP_VERSION_MASK;
1048                 if (data->force_peap_version >= 0 &&
1049                     data->force_peap_version != data->peap_version) {
1050                         wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
1051                                    "forced PEAP version %d",
1052                                    data->force_peap_version);
1053                         ret->methodState = METHOD_DONE;
1054                         ret->decision = DECISION_FAIL;
1055                         ret->allowNotifications = FALSE;
1056                         return NULL;
1057                 }
1058                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
1059                            data->peap_version);
1060                 left = 0; /* make sure that this frame is empty, even though it
1061                            * should always be, anyway */
1062         }
1063
1064         resp = NULL;
1065         if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1066             !data->resuming) {
1067                 struct wpabuf msg;
1068                 wpabuf_set(&msg, pos, left);
1069                 res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
1070         } else {
1071                 res = eap_peer_tls_process_helper(sm, &data->ssl,
1072                                                   EAP_TYPE_PEAP,
1073                                                   data->peap_version, id, pos,
1074                                                   left, &resp);
1075
1076                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
1077                         char *label;
1078                         wpa_printf(MSG_DEBUG,
1079                                    "EAP-PEAP: TLS done, proceed to Phase 2");
1080                         os_free(data->key_data);
1081                         /* draft-josefsson-ppext-eap-tls-eap-05.txt
1082                          * specifies that PEAPv1 would use "client PEAP
1083                          * encryption" as the label. However, most existing
1084                          * PEAPv1 implementations seem to be using the old
1085                          * label, "client EAP encryption", instead. Use the old
1086                          * label by default, but allow it to be configured with
1087                          * phase1 parameter peaplabel=1. */
1088                         if (data->peap_version > 1 || data->force_new_label)
1089                                 label = "client PEAP encryption";
1090                         else
1091                                 label = "client EAP encryption";
1092                         wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
1093                                    "key derivation", label);
1094                         data->key_data =
1095                                 eap_peer_tls_derive_key(sm, &data->ssl, label,
1096                                                         EAP_TLS_KEY_LEN);
1097                         if (data->key_data) {
1098                                 wpa_hexdump_key(MSG_DEBUG, 
1099                                                 "EAP-PEAP: Derived key",
1100                                                 data->key_data,
1101                                                 EAP_TLS_KEY_LEN);
1102                         } else {
1103                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
1104                                            "derive key");
1105                         }
1106
1107                         if (sm->workaround && data->resuming) {
1108                                 /*
1109                                  * At least few RADIUS servers (Aegis v1.1.6;
1110                                  * but not v1.1.4; and Cisco ACS) seem to be
1111                                  * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
1112                                  * ACS) session resumption with outer
1113                                  * EAP-Success. This does not seem to follow
1114                                  * draft-josefsson-pppext-eap-tls-eap-05.txt
1115                                  * section 4.2, so only allow this if EAP
1116                                  * workarounds are enabled.
1117                                  */
1118                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
1119                                            "allow outer EAP-Success to "
1120                                            "terminate PEAP resumption");
1121                                 ret->decision = DECISION_COND_SUCC;
1122                                 data->phase2_success = 1;
1123                         }
1124
1125                         data->resuming = 0;
1126                 }
1127
1128                 if (res == 2) {
1129                         struct wpabuf msg;
1130                         /*
1131                          * Application data included in the handshake message.
1132                          */
1133                         wpabuf_free(data->pending_phase2_req);
1134                         data->pending_phase2_req = resp;
1135                         resp = NULL;
1136                         wpabuf_set(&msg, pos, left);
1137                         res = eap_peap_decrypt(sm, data, ret, req, &msg,
1138                                                &resp);
1139                 }
1140         }
1141
1142         if (ret->methodState == METHOD_DONE) {
1143                 ret->allowNotifications = FALSE;
1144         }
1145
1146         if (res == 1) {
1147                 wpabuf_free(resp);
1148                 return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
1149                                               data->peap_version);
1150         }
1151
1152         return resp;
1153 }
1154
1155
1156 static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
1157 {
1158         struct eap_peap_data *data = priv;
1159         return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1160                 data->phase2_success;
1161 }
1162
1163
1164 static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
1165 {
1166         struct eap_peap_data *data = priv;
1167         wpabuf_free(data->pending_phase2_req);
1168         data->pending_phase2_req = NULL;
1169         data->crypto_binding_used = 0;
1170 }
1171
1172
1173 static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
1174 {
1175         struct eap_peap_data *data = priv;
1176         os_free(data->key_data);
1177         data->key_data = NULL;
1178         if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
1179                 os_free(data);
1180                 return NULL;
1181         }
1182         if (data->phase2_priv && data->phase2_method &&
1183             data->phase2_method->init_for_reauth)
1184                 data->phase2_method->init_for_reauth(sm, data->phase2_priv);
1185         data->phase2_success = 0;
1186         data->phase2_eap_success = 0;
1187         data->phase2_eap_started = 0;
1188         data->resuming = 1;
1189         sm->peap_done = FALSE;
1190         return priv;
1191 }
1192
1193
1194 static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
1195                                size_t buflen, int verbose)
1196 {
1197         struct eap_peap_data *data = priv;
1198         int len, ret;
1199
1200         len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
1201         if (data->phase2_method) {
1202                 ret = os_snprintf(buf + len, buflen - len,
1203                                   "EAP-PEAPv%d Phase2 method=%s\n",
1204                                   data->peap_version,
1205                                   data->phase2_method->name);
1206                 if (ret < 0 || (size_t) ret >= buflen - len)
1207                         return len;
1208                 len += ret;
1209         }
1210         return len;
1211 }
1212
1213
1214 static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
1215 {
1216         struct eap_peap_data *data = priv;
1217         return data->key_data != NULL && data->phase2_success;
1218 }
1219
1220
1221 static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
1222 {
1223         struct eap_peap_data *data = priv;
1224         u8 *key;
1225
1226         if (data->key_data == NULL || !data->phase2_success)
1227                 return NULL;
1228
1229         key = os_malloc(EAP_TLS_KEY_LEN);
1230         if (key == NULL)
1231                 return NULL;
1232
1233         *len = EAP_TLS_KEY_LEN;
1234
1235         if (data->crypto_binding_used) {
1236                 u8 csk[128];
1237                 peap_prfplus(data->peap_version, data->ipmk, 40,
1238                              "Session Key Generating Function",
1239                              (u8 *) "", 0, csk, sizeof(csk));
1240                 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
1241                 os_memcpy(key, csk, EAP_TLS_KEY_LEN);
1242                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
1243                             key, EAP_TLS_KEY_LEN);
1244         } else
1245                 os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
1246
1247         return key;
1248 }
1249
1250
1251 int eap_peer_peap_register(void)
1252 {
1253         struct eap_method *eap;
1254         int ret;
1255
1256         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1257                                     EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
1258         if (eap == NULL)
1259                 return -1;
1260
1261         eap->init = eap_peap_init;
1262         eap->deinit = eap_peap_deinit;
1263         eap->process = eap_peap_process;
1264         eap->isKeyAvailable = eap_peap_isKeyAvailable;
1265         eap->getKey = eap_peap_getKey;
1266         eap->get_status = eap_peap_get_status;
1267         eap->has_reauth_data = eap_peap_has_reauth_data;
1268         eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
1269         eap->init_for_reauth = eap_peap_init_for_reauth;
1270
1271         ret = eap_peer_method_register(eap);
1272         if (ret)
1273                 eap_peer_method_free(eap);
1274         return ret;
1275 }