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