xref: /dragonfly/contrib/wpa_supplicant/src/eap_peer/eap_peap.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
1 /*
2  * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
3  * Copyright (c) 2004-2019, 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 
eap_peap_parse_phase1(struct eap_peap_data * data,const char * phase1)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 
eap_peap_init(struct eap_sm * sm)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 
eap_peap_free_key(struct eap_peap_data * data)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 + EAP_EMSK_LEN);
173                     data->key_data = NULL;
174           }
175 }
176 
177 
eap_peap_deinit(struct eap_sm * sm,void * priv)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_clear_free(data->pending_phase2_req);
190           wpabuf_clear_free(data->pending_resp);
191           bin_clear_free(data, sizeof(*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  */
eap_tlv_build_nak(int id,u16 nak_type)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 
eap_peap_get_isk(struct eap_sm * sm,struct eap_peap_data * data,u8 * isk,size_t isk_len)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 
eap_peap_derive_cmk(struct eap_sm * sm,struct eap_peap_data * data)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           int resumed, res;
257 
258           /*
259            * Tunnel key (TK) is the first 60 octets of the key generated by
260            * phase 1 of PEAP (based on TLS).
261            */
262           tk = data->key_data;
263           if (tk == NULL)
264                     return -1;
265           wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
266 
267           resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn);
268           wpa_printf(MSG_DEBUG,
269                        "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d",
270                        data->reauth, resumed, data->phase2_eap_started,
271                        data->phase2_success);
272           if (data->reauth && !data->phase2_eap_started && resumed) {
273                     /* Fast-connect: IPMK|CMK = TK */
274                     os_memcpy(data->ipmk, tk, 40);
275                     wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
276                                         data->ipmk, 40);
277                     os_memcpy(data->cmk, tk + 40, 20);
278                     wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
279                                         data->cmk, 20);
280                     return 0;
281           }
282 
283           if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
284                     return -1;
285           wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
286 
287           /*
288            * IPMK Seed = "Inner Methods Compound Keys" | ISK
289            * TempKey = First 40 octets of TK
290            * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
291            * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
292            * in the end of the label just before ISK; is that just a typo?)
293            */
294           wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
295           res = peap_prfplus(data->peap_version, tk, 40,
296                                  "Inner Methods Compound Keys",
297                                  isk, sizeof(isk), imck, sizeof(imck));
298           forced_memzero(isk, sizeof(isk));
299           if (res < 0)
300                     return -1;
301           wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
302                               imck, sizeof(imck));
303 
304           os_memcpy(data->ipmk, imck, 40);
305           wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
306           os_memcpy(data->cmk, imck + 40, 20);
307           wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
308           forced_memzero(imck, sizeof(imck));
309 
310           return 0;
311 }
312 
313 
eap_tlv_add_cryptobinding(struct eap_sm * sm,struct eap_peap_data * data,struct wpabuf * buf)314 static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
315                                              struct eap_peap_data *data,
316                                              struct wpabuf *buf)
317 {
318           u8 *mac;
319           u8 eap_type = EAP_TYPE_PEAP;
320           const u8 *addr[2];
321           size_t len[2];
322           u16 tlv_type;
323 
324           /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
325           addr[0] = wpabuf_put(buf, 0);
326           len[0] = 60;
327           addr[1] = &eap_type;
328           len[1] = 1;
329 
330           tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
331           wpabuf_put_be16(buf, tlv_type);
332           wpabuf_put_be16(buf, 56);
333 
334           wpabuf_put_u8(buf, 0); /* Reserved */
335           wpabuf_put_u8(buf, data->peap_version); /* Version */
336           wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
337           wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
338           wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
339           mac = wpabuf_put(buf, 20); /* Compound_MAC */
340           wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
341           wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
342                         addr[0], len[0]);
343           wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
344                         addr[1], len[1]);
345           if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0)
346                     return -1;
347           wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
348           data->crypto_binding_used = 1;
349 
350           return 0;
351 }
352 
353 
354 /**
355  * eap_tlv_build_result - Build EAP-TLV Result message
356  * @id: EAP identifier for the header
357  * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
358  * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
359  *
360  * This function builds an EAP-TLV Result message. The caller is responsible
361  * for freeing the returned buffer.
362  */
eap_tlv_build_result(struct eap_sm * sm,struct eap_peap_data * data,int crypto_tlv_used,int id,u16 status)363 static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
364                                                       struct eap_peap_data *data,
365                                                       int crypto_tlv_used,
366                                                       int id, u16 status)
367 {
368           struct wpabuf *msg;
369           size_t len;
370 
371           if (data->crypto_binding == NO_BINDING)
372                     crypto_tlv_used = 0;
373 
374           len = 6;
375           if (crypto_tlv_used)
376                     len += 60; /* Cryptobinding TLV */
377           msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
378                                   EAP_CODE_RESPONSE, id);
379           if (msg == NULL)
380                     return NULL;
381 
382           wpabuf_put_u8(msg, 0x80); /* Mandatory */
383           wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
384           wpabuf_put_be16(msg, 2); /* Length */
385           wpabuf_put_be16(msg, status); /* Status */
386 
387           if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
388                     wpabuf_clear_free(msg);
389                     return NULL;
390           }
391 
392           return msg;
393 }
394 
395 
eap_tlv_validate_cryptobinding(struct eap_sm * sm,struct eap_peap_data * data,const u8 * crypto_tlv,size_t crypto_tlv_len)396 static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
397                                                     struct eap_peap_data *data,
398                                                     const u8 *crypto_tlv,
399                                                     size_t crypto_tlv_len)
400 {
401           u8 buf[61], mac[SHA1_MAC_LEN];
402           const u8 *pos;
403 
404           if (eap_peap_derive_cmk(sm, data) < 0) {
405                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
406                     return -1;
407           }
408 
409           if (crypto_tlv_len != 4 + 56) {
410                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
411                                  "length %d", (int) crypto_tlv_len);
412                     return -1;
413           }
414 
415           pos = crypto_tlv;
416           pos += 4; /* TLV header */
417           if (pos[1] != data->peap_version) {
418                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
419                                  "mismatch (was %d; expected %d)",
420                                  pos[1], data->peap_version);
421                     return -1;
422           }
423 
424           if (pos[3] != 0) {
425                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
426                                  "SubType %d", pos[3]);
427                     return -1;
428           }
429           pos += 4;
430           os_memcpy(data->binding_nonce, pos, 32);
431           pos += 32; /* Nonce */
432 
433           /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
434           os_memcpy(buf, crypto_tlv, 60);
435           os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
436           buf[60] = EAP_TYPE_PEAP;
437           wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data",
438                         buf, sizeof(buf));
439           hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
440 
441           if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
442                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
443                                  "cryptobinding TLV");
444                     wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
445                                   pos, SHA1_MAC_LEN);
446                     wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC",
447                                   mac, SHA1_MAC_LEN);
448                     return -1;
449           }
450 
451           wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
452 
453           return 0;
454 }
455 
456 
457 /**
458  * eap_tlv_process - Process a received EAP-TLV message and generate a response
459  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
460  * @ret: Return values from EAP request validation and processing
461  * @req: EAP-TLV request to be processed. The caller must have validated that
462  * the buffer is large enough to contain full request (hdr->length bytes) and
463  * that the EAP type is EAP_TYPE_TLV.
464  * @resp: Buffer to return a pointer to the allocated response message. This
465  * field should be initialized to %NULL before the call. The value will be
466  * updated if a response message is generated. The caller is responsible for
467  * freeing the allocated message.
468  * @force_failure: Force negotiation to fail
469  * Returns: 0 on success, -1 on failure
470  */
eap_tlv_process(struct eap_sm * sm,struct eap_peap_data * data,struct eap_method_ret * ret,const struct wpabuf * req,struct wpabuf ** resp,int force_failure)471 static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
472                                  struct eap_method_ret *ret,
473                                  const struct wpabuf *req, struct wpabuf **resp,
474                                  int force_failure)
475 {
476           size_t left, tlv_len;
477           const u8 *pos;
478           const u8 *result_tlv = NULL, *crypto_tlv = NULL;
479           size_t result_tlv_len = 0, crypto_tlv_len = 0;
480           int tlv_type, mandatory;
481 
482           /* Parse TLVs */
483           pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
484           if (pos == NULL)
485                     return -1;
486           wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
487           while (left >= 4) {
488                     mandatory = !!(pos[0] & 0x80);
489                     tlv_type = WPA_GET_BE16(pos) & 0x3fff;
490                     pos += 2;
491                     tlv_len = WPA_GET_BE16(pos);
492                     pos += 2;
493                     left -= 4;
494                     if (tlv_len > left) {
495                               wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
496                                            "(tlv_len=%lu left=%lu)",
497                                            (unsigned long) tlv_len,
498                                            (unsigned long) left);
499                               return -1;
500                     }
501                     switch (tlv_type) {
502                     case EAP_TLV_RESULT_TLV:
503                               result_tlv = pos;
504                               result_tlv_len = tlv_len;
505                               break;
506                     case EAP_TLV_CRYPTO_BINDING_TLV:
507                               crypto_tlv = pos;
508                               crypto_tlv_len = tlv_len;
509                               break;
510                     default:
511                               wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
512                                            "%d%s", tlv_type,
513                                            mandatory ? " (mandatory)" : "");
514                               if (mandatory) {
515                                         /* NAK TLV and ignore all TLVs in this packet.
516                                          */
517                                         *resp = eap_tlv_build_nak(eap_get_id(req),
518                                                                         tlv_type);
519                                         return *resp == NULL ? -1 : 0;
520                               }
521                               /* Ignore this TLV, but process other TLVs */
522                               break;
523                     }
524 
525                     pos += tlv_len;
526                     left -= tlv_len;
527           }
528           if (left) {
529                     wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
530                                  "Request (left=%lu)", (unsigned long) left);
531                     return -1;
532           }
533 
534           /* Process supported TLVs */
535           if (crypto_tlv && data->crypto_binding != NO_BINDING) {
536                     wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
537                                   crypto_tlv, crypto_tlv_len);
538                     if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
539                                                                crypto_tlv_len + 4) < 0) {
540                               if (result_tlv == NULL)
541                                         return -1;
542                               force_failure = 1;
543                               crypto_tlv = NULL; /* do not include Cryptobinding TLV
544                                                       * in response, if the received
545                                                       * cryptobinding was invalid. */
546                     }
547           } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
548                     wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
549                     return -1;
550           }
551 
552           if (result_tlv) {
553                     int status, resp_status;
554                     wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
555                                   result_tlv, result_tlv_len);
556                     if (result_tlv_len < 2) {
557                               wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
558                                            "(len=%lu)",
559                                            (unsigned long) result_tlv_len);
560                               return -1;
561                     }
562                     status = WPA_GET_BE16(result_tlv);
563                     if (status == EAP_TLV_RESULT_SUCCESS) {
564                               wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
565                                            "- EAP-TLV/Phase2 Completed");
566                               if (force_failure) {
567                                         wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
568                                                      " - force failed Phase 2");
569                                         resp_status = EAP_TLV_RESULT_FAILURE;
570                                         ret->decision = DECISION_FAIL;
571                               } else {
572                                         resp_status = EAP_TLV_RESULT_SUCCESS;
573                                         ret->decision = DECISION_UNCOND_SUCC;
574                               }
575                     } else if (status == EAP_TLV_RESULT_FAILURE) {
576                               wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
577                               resp_status = EAP_TLV_RESULT_FAILURE;
578                               ret->decision = DECISION_FAIL;
579                     } else {
580                               wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
581                                            "Status %d", status);
582                               resp_status = EAP_TLV_RESULT_FAILURE;
583                               ret->decision = DECISION_FAIL;
584                     }
585                     ret->methodState = METHOD_DONE;
586 
587                     *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
588                                                        eap_get_id(req), resp_status);
589           }
590 
591           return 0;
592 }
593 
594 
eap_peap_phase2_request(struct eap_sm * sm,struct eap_peap_data * data,struct eap_method_ret * ret,struct wpabuf * req,struct wpabuf ** resp)595 static int eap_peap_phase2_request(struct eap_sm *sm,
596                                            struct eap_peap_data *data,
597                                            struct eap_method_ret *ret,
598                                            struct wpabuf *req,
599                                            struct wpabuf **resp)
600 {
601           struct eap_hdr *hdr = wpabuf_mhead(req);
602           size_t len = be_to_host16(hdr->length);
603           u8 *pos;
604           struct eap_method_ret iret;
605           struct eap_peer_config *config = eap_get_config(sm);
606 
607           if (len <= sizeof(struct eap_hdr)) {
608                     wpa_printf(MSG_INFO, "EAP-PEAP: too short "
609                                  "Phase 2 request (len=%lu)", (unsigned long) len);
610                     return -1;
611           }
612           pos = (u8 *) (hdr + 1);
613           wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
614           switch (*pos) {
615           case EAP_TYPE_IDENTITY:
616                     *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
617                     break;
618           case EAP_TYPE_TLV:
619                     os_memset(&iret, 0, sizeof(iret));
620                     if (eap_tlv_process(sm, data, &iret, req, resp,
621                                             data->phase2_eap_started &&
622                                             !data->phase2_eap_success)) {
623                               ret->methodState = METHOD_DONE;
624                               ret->decision = DECISION_FAIL;
625                               return -1;
626                     }
627                     if (iret.methodState == METHOD_DONE ||
628                         iret.methodState == METHOD_MAY_CONT) {
629                               ret->methodState = iret.methodState;
630                               ret->decision = iret.decision;
631                               data->phase2_success = 1;
632                     }
633                     break;
634           case EAP_TYPE_EXPANDED:
635 #ifdef EAP_TNC
636                     if (data->soh) {
637                               const u8 *epos;
638                               size_t eleft;
639 
640                               epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
641                                                             req, &eleft);
642                               if (epos) {
643                                         struct wpabuf *buf;
644                                         wpa_printf(MSG_DEBUG,
645                                                      "EAP-PEAP: SoH EAP Extensions");
646                                         buf = tncc_process_soh_request(data->soh,
647                                                                              epos, eleft);
648                                         if (buf) {
649                                                   *resp = eap_msg_alloc(
650                                                             EAP_VENDOR_MICROSOFT, 0x21,
651                                                             wpabuf_len(buf),
652                                                             EAP_CODE_RESPONSE,
653                                                             hdr->identifier);
654                                                   if (*resp == NULL) {
655                                                             ret->methodState = METHOD_DONE;
656                                                             ret->decision = DECISION_FAIL;
657                                                             wpabuf_clear_free(buf);
658                                                             return -1;
659                                                   }
660                                                   wpabuf_put_buf(*resp, buf);
661                                                   wpabuf_clear_free(buf);
662                                                   break;
663                                         }
664                               }
665                     }
666 #endif /* EAP_TNC */
667                     /* fall through */
668           default:
669                     if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
670                         data->phase2_type.method == EAP_TYPE_NONE) {
671                               size_t i;
672                               for (i = 0; i < data->num_phase2_types; i++) {
673                                         if (data->phase2_types[i].vendor !=
674                                             EAP_VENDOR_IETF ||
675                                             data->phase2_types[i].method != *pos)
676                                                   continue;
677 
678                                         data->phase2_type.vendor =
679                                                   data->phase2_types[i].vendor;
680                                         data->phase2_type.method =
681                                                   data->phase2_types[i].method;
682                                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
683                                                      "Phase 2 EAP vendor %d method %d",
684                                                      data->phase2_type.vendor,
685                                                      data->phase2_type.method);
686                                         break;
687                               }
688                     }
689                     if (*pos != data->phase2_type.method ||
690                         *pos == EAP_TYPE_NONE) {
691                               if (eap_peer_tls_phase2_nak(data->phase2_types,
692                                                                 data->num_phase2_types,
693                                                                 hdr, resp))
694                                         return -1;
695                               return 0;
696                     }
697 
698                     if (data->phase2_priv == NULL) {
699                               data->phase2_method = eap_peer_get_eap_method(
700                                         data->phase2_type.vendor,
701                                         data->phase2_type.method);
702                               if (data->phase2_method) {
703                                         sm->init_phase2 = 1;
704                                         data->phase2_priv =
705                                                   data->phase2_method->init(sm);
706                                         sm->init_phase2 = 0;
707                               }
708                     }
709                     if (data->phase2_priv == NULL || data->phase2_method == NULL) {
710                               wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
711                                            "Phase 2 EAP method %d", *pos);
712                               ret->methodState = METHOD_DONE;
713                               ret->decision = DECISION_FAIL;
714                               return -1;
715                     }
716                     data->phase2_eap_started = 1;
717                     os_memset(&iret, 0, sizeof(iret));
718                     *resp = data->phase2_method->process(sm, data->phase2_priv,
719                                                                  &iret, req);
720                     if ((iret.methodState == METHOD_DONE ||
721                          iret.methodState == METHOD_MAY_CONT) &&
722                         (iret.decision == DECISION_UNCOND_SUCC ||
723                          iret.decision == DECISION_COND_SUCC)) {
724                               data->phase2_eap_success = 1;
725                               data->phase2_success = 1;
726                     }
727                     break;
728           }
729 
730           if (*resp == NULL &&
731               (config->pending_req_identity || config->pending_req_password ||
732                config->pending_req_otp || config->pending_req_new_password ||
733                config->pending_req_sim)) {
734                     wpabuf_clear_free(data->pending_phase2_req);
735                     data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
736           }
737 
738           return 0;
739 }
740 
741 
eap_peap_decrypt(struct eap_sm * sm,struct eap_peap_data * data,struct eap_method_ret * ret,const struct eap_hdr * req,const struct wpabuf * in_data,struct wpabuf ** out_data)742 static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
743                                   struct eap_method_ret *ret,
744                                   const struct eap_hdr *req,
745                                   const struct wpabuf *in_data,
746                                   struct wpabuf **out_data)
747 {
748           struct wpabuf *in_decrypted = NULL;
749           int res, skip_change = 0;
750           struct eap_hdr *hdr, *rhdr;
751           struct wpabuf *resp = NULL;
752           size_t len;
753 
754           wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
755                        " Phase 2", (unsigned long) wpabuf_len(in_data));
756 
757           if (data->pending_phase2_req) {
758                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
759                                  "skip decryption and use old data");
760                     /* Clear TLS reassembly state. */
761                     eap_peer_tls_reset_input(&data->ssl);
762                     in_decrypted = data->pending_phase2_req;
763                     data->pending_phase2_req = NULL;
764                     skip_change = 1;
765                     goto continue_req;
766           }
767 
768           if (wpabuf_len(in_data) == 0 && sm->workaround &&
769               data->phase2_success) {
770                     /*
771                      * Cisco ACS seems to be using TLS ACK to terminate
772                      * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
773                      */
774                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
775                                  "expected data - acknowledge with TLS ACK since "
776                                  "Phase 2 has been completed");
777                     ret->decision = DECISION_COND_SUCC;
778                     ret->methodState = METHOD_DONE;
779                     return 1;
780           } else if (wpabuf_len(in_data) == 0) {
781                     /* Received TLS ACK - requesting more fragments */
782                     return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
783                                                       data->peap_version,
784                                                       req->identifier, NULL, out_data);
785           }
786 
787           res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
788           if (res)
789                     return res;
790 
791 continue_req:
792           wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
793                               in_decrypted);
794 
795           hdr = wpabuf_mhead(in_decrypted);
796           if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST &&
797               be_to_host16(hdr->length) == 5 &&
798               eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) {
799                     /* At least FreeRADIUS seems to send full EAP header with
800                      * EAP Request Identity */
801                     skip_change = 1;
802           }
803           if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST &&
804               eap_get_type(in_decrypted) == EAP_TYPE_TLV) {
805                     skip_change = 1;
806           }
807 
808           if (data->peap_version == 0 && !skip_change) {
809                     struct eap_hdr *nhdr;
810                     struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
811                                                                wpabuf_len(in_decrypted));
812                     if (nmsg == NULL) {
813                               wpabuf_clear_free(in_decrypted);
814                               return 0;
815                     }
816                     nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
817                     wpabuf_put_buf(nmsg, in_decrypted);
818                     nhdr->code = req->code;
819                     nhdr->identifier = req->identifier;
820                     nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
821                                                       wpabuf_len(in_decrypted));
822 
823                     wpabuf_clear_free(in_decrypted);
824                     in_decrypted = nmsg;
825           }
826 
827           hdr = wpabuf_mhead(in_decrypted);
828           if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
829                     wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
830                                  "EAP frame (len=%lu)",
831                                  (unsigned long) wpabuf_len(in_decrypted));
832                     wpabuf_clear_free(in_decrypted);
833                     return 0;
834           }
835           len = be_to_host16(hdr->length);
836           if (len > wpabuf_len(in_decrypted)) {
837                     wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
838                                  "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
839                                  (unsigned long) wpabuf_len(in_decrypted),
840                                  (unsigned long) len);
841                     wpabuf_clear_free(in_decrypted);
842                     return 0;
843           }
844           if (len < wpabuf_len(in_decrypted)) {
845                     wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
846                                  "shorter length than full decrypted data "
847                                  "(%lu < %lu)",
848                                  (unsigned long) len,
849                                  (unsigned long) wpabuf_len(in_decrypted));
850           }
851           wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
852                        "identifier=%d length=%lu", hdr->code, hdr->identifier,
853                        (unsigned long) len);
854           switch (hdr->code) {
855           case EAP_CODE_REQUEST:
856                     if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
857                                                       &resp)) {
858                               wpabuf_clear_free(in_decrypted);
859                               wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
860                                            "processing failed");
861                               return 0;
862                     }
863                     break;
864           case EAP_CODE_SUCCESS:
865                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
866                     if (data->peap_version == 1) {
867                               /* EAP-Success within TLS tunnel is used to indicate
868                                * shutdown of the TLS channel. The authentication has
869                                * been completed. */
870                               if (data->phase2_eap_started &&
871                                   !data->phase2_eap_success) {
872                                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
873                                                      "Success used to indicate success, "
874                                                      "but Phase 2 EAP was not yet "
875                                                      "completed successfully");
876                                         ret->methodState = METHOD_DONE;
877                                         ret->decision = DECISION_FAIL;
878                                         wpabuf_clear_free(in_decrypted);
879                                         return 0;
880                               }
881                               wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
882                                            "EAP-Success within TLS tunnel - "
883                                            "authentication completed");
884                               ret->decision = DECISION_UNCOND_SUCC;
885                               ret->methodState = METHOD_DONE;
886                               data->phase2_success = 1;
887                               if (data->peap_outer_success == 2) {
888                                         wpabuf_clear_free(in_decrypted);
889                                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
890                                                      "to finish authentication");
891                                         return 1;
892                               } else if (data->peap_outer_success == 1) {
893                                         /* Reply with EAP-Success within the TLS
894                                          * channel to complete the authentication. */
895                                         resp = wpabuf_alloc(sizeof(struct eap_hdr));
896                                         if (resp) {
897                                                   rhdr = wpabuf_put(resp, sizeof(*rhdr));
898                                                   rhdr->code = EAP_CODE_SUCCESS;
899                                                   rhdr->identifier = hdr->identifier;
900                                                   rhdr->length =
901                                                             host_to_be16(sizeof(*rhdr));
902                                         }
903                               } else {
904                                         /* No EAP-Success expected for Phase 1 (outer,
905                                          * unencrypted auth), so force EAP state
906                                          * machine to SUCCESS state. */
907                                         sm->peap_done = TRUE;
908                               }
909                     } else {
910                               /* FIX: ? */
911                     }
912                     break;
913           case EAP_CODE_FAILURE:
914                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
915                     ret->decision = DECISION_FAIL;
916                     ret->methodState = METHOD_MAY_CONT;
917                     ret->allowNotifications = FALSE;
918                     /* Reply with EAP-Failure within the TLS channel to complete
919                      * failure reporting. */
920                     resp = wpabuf_alloc(sizeof(struct eap_hdr));
921                     if (resp) {
922                               rhdr = wpabuf_put(resp, sizeof(*rhdr));
923                               rhdr->code = EAP_CODE_FAILURE;
924                               rhdr->identifier = hdr->identifier;
925                               rhdr->length = host_to_be16(sizeof(*rhdr));
926                     }
927                     break;
928           default:
929                     wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
930                                  "Phase 2 EAP header", hdr->code);
931                     break;
932           }
933 
934           wpabuf_clear_free(in_decrypted);
935 
936           if (resp) {
937                     int skip_change2 = 0;
938                     struct wpabuf *rmsg, buf;
939 
940                     wpa_hexdump_buf_key(MSG_DEBUG,
941                                             "EAP-PEAP: Encrypting Phase 2 data", resp);
942                     /* PEAP version changes */
943                     if (wpabuf_len(resp) >= 5 &&
944                         wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
945                         eap_get_type(resp) == EAP_TYPE_TLV)
946                               skip_change2 = 1;
947                     rmsg = resp;
948                     if (data->peap_version == 0 && !skip_change2) {
949                               wpabuf_set(&buf, wpabuf_head_u8(resp) +
950                                            sizeof(struct eap_hdr),
951                                            wpabuf_len(resp) - sizeof(struct eap_hdr));
952                               rmsg = &buf;
953                     }
954 
955                     if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
956                                                    data->peap_version, req->identifier,
957                                                    rmsg, out_data)) {
958                               wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
959                                            "a Phase 2 frame");
960                     }
961                     wpabuf_clear_free(resp);
962           }
963 
964           return 0;
965 }
966 
967 
eap_peap_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)968 static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
969                                                   struct eap_method_ret *ret,
970                                                   const struct wpabuf *reqData)
971 {
972           const struct eap_hdr *req;
973           size_t left;
974           int res;
975           u8 flags, id;
976           struct wpabuf *resp;
977           const u8 *pos;
978           struct eap_peap_data *data = priv;
979           struct wpabuf msg;
980 
981           pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
982                                                   reqData, &left, &flags);
983           if (pos == NULL)
984                     return NULL;
985           req = wpabuf_head(reqData);
986           id = req->identifier;
987 
988           if (flags & EAP_TLS_FLAGS_START) {
989                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
990                                  "ver=%d)", flags & EAP_TLS_VERSION_MASK,
991                               data->peap_version);
992                     if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version)
993                               data->peap_version = flags & EAP_TLS_VERSION_MASK;
994                     if (data->force_peap_version >= 0 &&
995                         data->force_peap_version != data->peap_version) {
996                               wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
997                                            "forced PEAP version %d",
998                                            data->force_peap_version);
999                               ret->methodState = METHOD_DONE;
1000                               ret->decision = DECISION_FAIL;
1001                               ret->allowNotifications = FALSE;
1002                               return NULL;
1003                     }
1004                     wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
1005                                  data->peap_version);
1006                     left = 0; /* make sure that this frame is empty, even though it
1007                                  * should always be, anyway */
1008           }
1009 
1010           wpabuf_set(&msg, pos, left);
1011 
1012           resp = NULL;
1013           if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1014               !data->resuming) {
1015                     res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
1016           } else {
1017                     if (sm->waiting_ext_cert_check && data->pending_resp) {
1018                               struct eap_peer_config *config = eap_get_config(sm);
1019 
1020                               if (config->pending_ext_cert_check ==
1021                                   EXT_CERT_CHECK_GOOD) {
1022                                         wpa_printf(MSG_DEBUG,
1023                                                      "EAP-PEAP: External certificate check succeeded - continue handshake");
1024                                         resp = data->pending_resp;
1025                                         data->pending_resp = NULL;
1026                                         sm->waiting_ext_cert_check = 0;
1027                                         return resp;
1028                               }
1029 
1030                               if (config->pending_ext_cert_check ==
1031                                   EXT_CERT_CHECK_BAD) {
1032                                         wpa_printf(MSG_DEBUG,
1033                                                      "EAP-PEAP: External certificate check failed - force authentication failure");
1034                                         ret->methodState = METHOD_DONE;
1035                                         ret->decision = DECISION_FAIL;
1036                                         sm->waiting_ext_cert_check = 0;
1037                                         return NULL;
1038                               }
1039 
1040                               wpa_printf(MSG_DEBUG,
1041                                            "EAP-PEAP: Continuing to wait external server certificate validation");
1042                               return NULL;
1043                     }
1044 
1045                     res = eap_peer_tls_process_helper(sm, &data->ssl,
1046                                                               EAP_TYPE_PEAP,
1047                                                               data->peap_version, id, &msg,
1048                                                               &resp);
1049 
1050                     if (res < 0) {
1051                               wpa_printf(MSG_DEBUG,
1052                                            "EAP-PEAP: TLS processing failed");
1053                               ret->methodState = METHOD_DONE;
1054                               ret->decision = DECISION_FAIL;
1055                               return resp;
1056                     }
1057 
1058 
1059                     if (sm->waiting_ext_cert_check) {
1060                               wpa_printf(MSG_DEBUG,
1061                                            "EAP-PEAP: Waiting external server certificate validation");
1062                               wpabuf_clear_free(data->pending_resp);
1063                               data->pending_resp = resp;
1064                               return NULL;
1065                     }
1066 
1067                     if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
1068                               char *label;
1069                               wpa_printf(MSG_DEBUG,
1070                                            "EAP-PEAP: TLS done, proceed to Phase 2");
1071                               eap_peap_free_key(data);
1072                               /* draft-josefsson-ppext-eap-tls-eap-05.txt
1073                                * specifies that PEAPv1 would use "client PEAP
1074                                * encryption" as the label. However, most existing
1075                                * PEAPv1 implementations seem to be using the old
1076                                * label, "client EAP encryption", instead. Use the old
1077                                * label by default, but allow it to be configured with
1078                                * phase1 parameter peaplabel=1. */
1079                               if (data->force_new_label)
1080                                         label = "client PEAP encryption";
1081                               else
1082                                         label = "client EAP encryption";
1083                               wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
1084                                            "key derivation", label);
1085                               data->key_data =
1086                                         eap_peer_tls_derive_key(sm, &data->ssl, label,
1087                                                                       NULL, 0,
1088                                                                       EAP_TLS_KEY_LEN +
1089                                                                       EAP_EMSK_LEN);
1090                               if (data->key_data) {
1091                                         wpa_hexdump_key(MSG_DEBUG,
1092                                                             "EAP-PEAP: Derived key",
1093                                                             data->key_data,
1094                                                             EAP_TLS_KEY_LEN);
1095                                         wpa_hexdump_key(MSG_DEBUG,
1096                                                             "EAP-PEAP: Derived EMSK",
1097                                                             data->key_data +
1098                                                             EAP_TLS_KEY_LEN,
1099                                                             EAP_EMSK_LEN);
1100                               } else {
1101                                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
1102                                                      "derive key");
1103                               }
1104 
1105                               os_free(data->session_id);
1106                               data->session_id =
1107                                         eap_peer_tls_derive_session_id(sm, &data->ssl,
1108                                                                              EAP_TYPE_PEAP,
1109                                                                              &data->id_len);
1110                               if (data->session_id) {
1111                                         wpa_hexdump(MSG_DEBUG,
1112                                                       "EAP-PEAP: Derived Session-Id",
1113                                                       data->session_id, data->id_len);
1114                               } else {
1115                                         wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to "
1116                                                      "derive Session-Id");
1117                               }
1118 
1119                               if (sm->workaround && data->resuming) {
1120                                         /*
1121                                          * At least few RADIUS servers (Aegis v1.1.6;
1122                                          * but not v1.1.4; and Cisco ACS) seem to be
1123                                          * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
1124                                          * ACS) session resumption with outer
1125                                          * EAP-Success. This does not seem to follow
1126                                          * draft-josefsson-pppext-eap-tls-eap-05.txt
1127                                          * section 4.2, so only allow this if EAP
1128                                          * workarounds are enabled.
1129                                          */
1130                                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
1131                                                      "allow outer EAP-Success to "
1132                                                      "terminate PEAP resumption");
1133                                         ret->decision = DECISION_COND_SUCC;
1134                                         data->phase2_success = 1;
1135                               }
1136 
1137                               data->resuming = 0;
1138                     }
1139 
1140                     if (res == 2) {
1141                               /*
1142                                * Application data included in the handshake message.
1143                                */
1144                               wpabuf_clear_free(data->pending_phase2_req);
1145                               data->pending_phase2_req = resp;
1146                               resp = NULL;
1147                               res = eap_peap_decrypt(sm, data, ret, req, &msg,
1148                                                          &resp);
1149                     }
1150           }
1151 
1152           if (ret->methodState == METHOD_DONE) {
1153                     ret->allowNotifications = FALSE;
1154           }
1155 
1156           if (res == 1) {
1157                     wpabuf_clear_free(resp);
1158                     return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
1159                                                         data->peap_version);
1160           }
1161 
1162           return resp;
1163 }
1164 
1165 
eap_peap_has_reauth_data(struct eap_sm * sm,void * priv)1166 static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
1167 {
1168           struct eap_peap_data *data = priv;
1169           return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1170                     data->phase2_success;
1171 }
1172 
1173 
eap_peap_deinit_for_reauth(struct eap_sm * sm,void * priv)1174 static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
1175 {
1176           struct eap_peap_data *data = priv;
1177 
1178           if (data->phase2_priv && data->phase2_method &&
1179               data->phase2_method->deinit_for_reauth)
1180                     data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
1181           wpabuf_clear_free(data->pending_phase2_req);
1182           data->pending_phase2_req = NULL;
1183           wpabuf_clear_free(data->pending_resp);
1184           data->pending_resp = NULL;
1185           data->crypto_binding_used = 0;
1186 }
1187 
1188 
eap_peap_init_for_reauth(struct eap_sm * sm,void * priv)1189 static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
1190 {
1191           struct eap_peap_data *data = priv;
1192           eap_peap_free_key(data);
1193           os_free(data->session_id);
1194           data->session_id = 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 
eap_peap_get_status(struct eap_sm * sm,void * priv,char * buf,size_t buflen,int verbose)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 (os_snprintf_error(buflen - len, ret))
1225                               return len;
1226                     len += ret;
1227           }
1228           return len;
1229 }
1230 
1231 
eap_peap_isKeyAvailable(struct eap_sm * sm,void * priv)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 
eap_peap_getKey(struct eap_sm * sm,void * priv,size_t * len)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                     if (peap_prfplus(data->peap_version, data->ipmk, 40,
1261                                          "Session Key Generating Function",
1262                                          (u8 *) "\00", 1, csk, sizeof(csk)) < 0) {
1263                               os_free(key);
1264                               return NULL;
1265                     }
1266                     wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
1267                     os_memcpy(key, csk, EAP_TLS_KEY_LEN);
1268                     wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
1269                                   key, EAP_TLS_KEY_LEN);
1270                     forced_memzero(csk, sizeof(csk));
1271           } else
1272                     os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
1273 
1274           return key;
1275 }
1276 
1277 
eap_peap_get_emsk(struct eap_sm * sm,void * priv,size_t * len)1278 static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1279 {
1280           struct eap_peap_data *data = priv;
1281           u8 *key;
1282 
1283           if (!data->key_data || !data->phase2_success)
1284                     return NULL;
1285 
1286           if (data->crypto_binding_used) {
1287                     /* [MS-PEAP] does not define EMSK derivation */
1288                     return NULL;
1289           }
1290 
1291           key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
1292           if (!key)
1293                     return NULL;
1294 
1295           *len = EAP_EMSK_LEN;
1296 
1297           return key;
1298 }
1299 
1300 
eap_peap_get_session_id(struct eap_sm * sm,void * priv,size_t * len)1301 static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1302 {
1303           struct eap_peap_data *data = priv;
1304           u8 *id;
1305 
1306           if (data->session_id == NULL || !data->phase2_success)
1307                     return NULL;
1308 
1309           id = os_memdup(data->session_id, data->id_len);
1310           if (id == NULL)
1311                     return NULL;
1312 
1313           *len = data->id_len;
1314 
1315           return id;
1316 }
1317 
1318 
eap_peer_peap_register(void)1319 int eap_peer_peap_register(void)
1320 {
1321           struct eap_method *eap;
1322 
1323           eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1324                                             EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
1325           if (eap == NULL)
1326                     return -1;
1327 
1328           eap->init = eap_peap_init;
1329           eap->deinit = eap_peap_deinit;
1330           eap->process = eap_peap_process;
1331           eap->isKeyAvailable = eap_peap_isKeyAvailable;
1332           eap->getKey = eap_peap_getKey;
1333           eap->get_emsk = eap_peap_get_emsk;
1334           eap->get_status = eap_peap_get_status;
1335           eap->has_reauth_data = eap_peap_has_reauth_data;
1336           eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
1337           eap->init_for_reauth = eap_peap_init_for_reauth;
1338           eap->getSessionId = eap_peap_get_session_id;
1339 
1340           return eap_peer_method_register(eap);
1341 }
1342