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