LCOV - code coverage report
Current view: top level - src/eap_server - eap_server_peap.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1422976643 Lines: 482 641 75.2 %
Date: 2015-02-03 Functions: 29 29 100.0 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
       3             :  * Copyright (c) 2004-2008, 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 "crypto/random.h"
      15             : #include "eap_i.h"
      16             : #include "eap_tls_common.h"
      17             : #include "eap_common/eap_tlv_common.h"
      18             : #include "eap_common/eap_peap_common.h"
      19             : #include "tncs.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_reset(struct eap_sm *sm, void *priv);
      30             : 
      31             : 
      32             : struct eap_peap_data {
      33             :         struct eap_ssl_data ssl;
      34             :         enum {
      35             :                 START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,
      36             :                 PHASE2_METHOD, PHASE2_SOH,
      37             :                 PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
      38             :         } state;
      39             : 
      40             :         int peap_version;
      41             :         int recv_version;
      42             :         const struct eap_method *phase2_method;
      43             :         void *phase2_priv;
      44             :         int force_version;
      45             :         struct wpabuf *pending_phase2_resp;
      46             :         enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
      47             :         int crypto_binding_sent;
      48             :         int crypto_binding_used;
      49             :         enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
      50             :         u8 binding_nonce[32];
      51             :         u8 ipmk[40];
      52             :         u8 cmk[20];
      53             :         u8 *phase2_key;
      54             :         size_t phase2_key_len;
      55             :         struct wpabuf *soh_response;
      56             : };
      57             : 
      58             : 
      59         424 : static const char * eap_peap_state_txt(int state)
      60             : {
      61         424 :         switch (state) {
      62             :         case START:
      63          35 :                 return "START";
      64             :         case PHASE1:
      65          70 :                 return "PHASE1";
      66             :         case PHASE1_ID2:
      67           0 :                 return "PHASE1_ID2";
      68             :         case PHASE2_START:
      69          70 :                 return "PHASE2_START";
      70             :         case PHASE2_ID:
      71          70 :                 return "PHASE2_ID";
      72             :         case PHASE2_METHOD:
      73          70 :                 return "PHASE2_METHOD";
      74             :         case PHASE2_SOH:
      75           6 :                 return "PHASE2_SOH";
      76             :         case PHASE2_TLV:
      77          17 :                 return "PHASE2_TLV";
      78             :         case SUCCESS_REQ:
      79          48 :                 return "SUCCESS_REQ";
      80             :         case FAILURE_REQ:
      81           4 :                 return "FAILURE_REQ";
      82             :         case SUCCESS:
      83          31 :                 return "SUCCESS";
      84             :         case FAILURE:
      85           3 :                 return "FAILURE";
      86             :         default:
      87           0 :                 return "Unknown?!";
      88             :         }
      89             : }
      90             : 
      91             : 
      92         212 : static void eap_peap_state(struct eap_peap_data *data, int state)
      93             : {
      94         424 :         wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
      95         212 :                    eap_peap_state_txt(data->state),
      96             :                    eap_peap_state_txt(state));
      97         212 :         data->state = state;
      98         212 : }
      99             : 
     100             : 
     101          32 : static void eap_peap_req_success(struct eap_sm *sm,
     102             :                                  struct eap_peap_data *data)
     103             : {
     104          32 :         if (data->state == FAILURE || data->state == FAILURE_REQ) {
     105           0 :                 eap_peap_state(data, FAILURE);
     106          32 :                 return;
     107             :         }
     108             : 
     109          32 :         if (data->peap_version == 0) {
     110           8 :                 data->tlv_request = TLV_REQ_SUCCESS;
     111           8 :                 eap_peap_state(data, PHASE2_TLV);
     112             :         } else {
     113          24 :                 eap_peap_state(data, SUCCESS_REQ);
     114             :         }
     115             : }
     116             : 
     117             : 
     118           3 : static void eap_peap_req_failure(struct eap_sm *sm,
     119             :                                  struct eap_peap_data *data)
     120             : {
     121           6 :         if (data->state == FAILURE || data->state == FAILURE_REQ ||
     122           6 :             data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
     123           0 :                 eap_peap_state(data, FAILURE);
     124           3 :                 return;
     125             :         }
     126             : 
     127           3 :         if (data->peap_version == 0) {
     128           1 :                 data->tlv_request = TLV_REQ_FAILURE;
     129           1 :                 eap_peap_state(data, PHASE2_TLV);
     130             :         } else {
     131           2 :                 eap_peap_state(data, FAILURE_REQ);
     132             :         }
     133             : }
     134             : 
     135             : 
     136          35 : static void * eap_peap_init(struct eap_sm *sm)
     137             : {
     138             :         struct eap_peap_data *data;
     139             : 
     140          35 :         data = os_zalloc(sizeof(*data));
     141          35 :         if (data == NULL)
     142           0 :                 return NULL;
     143          35 :         data->peap_version = EAP_PEAP_VERSION;
     144          35 :         data->force_version = -1;
     145          35 :         if (sm->user && sm->user->force_version >= 0) {
     146           0 :                 data->force_version = sm->user->force_version;
     147           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",
     148             :                            data->force_version);
     149           0 :                 data->peap_version = data->force_version;
     150             :         }
     151          35 :         data->state = START;
     152          35 :         data->crypto_binding = OPTIONAL_BINDING;
     153             : 
     154          35 :         if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
     155           0 :                 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
     156           0 :                 eap_peap_reset(sm, data);
     157           0 :                 return NULL;
     158             :         }
     159             : 
     160          35 :         return data;
     161             : }
     162             : 
     163             : 
     164          35 : static void eap_peap_reset(struct eap_sm *sm, void *priv)
     165             : {
     166          35 :         struct eap_peap_data *data = priv;
     167          35 :         if (data == NULL)
     168          35 :                 return;
     169          35 :         if (data->phase2_priv && data->phase2_method)
     170           0 :                 data->phase2_method->reset(sm, data->phase2_priv);
     171          35 :         eap_server_tls_ssl_deinit(sm, &data->ssl);
     172          35 :         wpabuf_free(data->pending_phase2_resp);
     173          35 :         os_free(data->phase2_key);
     174          35 :         wpabuf_free(data->soh_response);
     175          35 :         bin_clear_free(data, sizeof(*data));
     176             : }
     177             : 
     178             : 
     179          35 : static struct wpabuf * eap_peap_build_start(struct eap_sm *sm,
     180             :                                             struct eap_peap_data *data, u8 id)
     181             : {
     182             :         struct wpabuf *req;
     183             : 
     184          35 :         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,
     185             :                             EAP_CODE_REQUEST, id);
     186          35 :         if (req == NULL) {
     187           0 :                 wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"
     188             :                            " request");
     189           0 :                 eap_peap_state(data, FAILURE);
     190           0 :                 return NULL;
     191             :         }
     192             : 
     193          35 :         wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);
     194             : 
     195          35 :         eap_peap_state(data, PHASE1);
     196             : 
     197          35 :         return req;
     198             : }
     199             : 
     200             : 
     201         111 : static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
     202             :                                                  struct eap_peap_data *data,
     203             :                                                  u8 id)
     204             : {
     205             :         struct wpabuf *buf, *encr_req, msgbuf;
     206             :         const u8 *req;
     207             :         size_t req_len;
     208             : 
     209         111 :         if (data->phase2_method == NULL || data->phase2_priv == NULL) {
     210           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
     211           0 :                 return NULL;
     212             :         }
     213         111 :         buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
     214         111 :         if (buf == NULL)
     215           0 :                 return NULL;
     216             : 
     217         111 :         req = wpabuf_head(buf);
     218         111 :         req_len = wpabuf_len(buf);
     219         111 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
     220             :                         req, req_len);
     221             : 
     222         138 :         if (data->peap_version == 0 &&
     223          27 :             data->phase2_method->method != EAP_TYPE_TLV) {
     224          27 :                 req += sizeof(struct eap_hdr);
     225          27 :                 req_len -= sizeof(struct eap_hdr);
     226             :         }
     227             : 
     228         111 :         wpabuf_set(&msgbuf, req, req_len);
     229         111 :         encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
     230         111 :         wpabuf_free(buf);
     231             : 
     232         111 :         return encr_req;
     233             : }
     234             : 
     235             : 
     236             : #ifdef EAP_SERVER_TNC
     237           3 : static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
     238             :                                                  struct eap_peap_data *data,
     239             :                                                  u8 id)
     240             : {
     241             :         struct wpabuf *buf1, *buf, *encr_req, msgbuf;
     242             :         const u8 *req;
     243             :         size_t req_len;
     244             : 
     245           3 :         buf1 = tncs_build_soh_request();
     246           3 :         if (buf1 == NULL)
     247           0 :                 return NULL;
     248             : 
     249           3 :         buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
     250             :                             EAP_CODE_REQUEST, id);
     251           3 :         if (buf == NULL) {
     252           0 :                 wpabuf_free(buf1);
     253           0 :                 return NULL;
     254             :         }
     255           3 :         wpabuf_put_buf(buf, buf1);
     256           3 :         wpabuf_free(buf1);
     257             : 
     258           3 :         req = wpabuf_head(buf);
     259           3 :         req_len = wpabuf_len(buf);
     260             : 
     261           3 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
     262             :                         req, req_len);
     263             : 
     264           3 :         req += sizeof(struct eap_hdr);
     265           3 :         req_len -= sizeof(struct eap_hdr);
     266           3 :         wpabuf_set(&msgbuf, req, req_len);
     267             : 
     268           3 :         encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
     269           3 :         wpabuf_free(buf);
     270             : 
     271           3 :         return encr_req;
     272             : }
     273             : #endif /* EAP_SERVER_TNC */
     274             : 
     275             : 
     276           8 : static void eap_peap_get_isk(struct eap_peap_data *data,
     277             :                              u8 *isk, size_t isk_len)
     278             : {
     279             :         size_t key_len;
     280             : 
     281           8 :         os_memset(isk, 0, isk_len);
     282           8 :         if (data->phase2_key == NULL)
     283           8 :                 return;
     284             : 
     285           8 :         key_len = data->phase2_key_len;
     286           8 :         if (key_len > isk_len)
     287           0 :                 key_len = isk_len;
     288           8 :         os_memcpy(isk, data->phase2_key, key_len);
     289             : }
     290             : 
     291             : 
     292           8 : static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
     293             : {
     294             :         u8 *tk;
     295             :         u8 isk[32], imck[60];
     296             : 
     297             :         /*
     298             :          * Tunnel key (TK) is the first 60 octets of the key generated by
     299             :          * phase 1 of PEAP (based on TLS).
     300             :          */
     301           8 :         tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
     302             :                                        EAP_TLS_KEY_LEN);
     303           8 :         if (tk == NULL)
     304           0 :                 return -1;
     305           8 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
     306             : 
     307           8 :         eap_peap_get_isk(data, isk, sizeof(isk));
     308           8 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
     309             : 
     310             :         /*
     311             :          * IPMK Seed = "Inner Methods Compound Keys" | ISK
     312             :          * TempKey = First 40 octets of TK
     313             :          * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
     314             :          * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
     315             :          * in the end of the label just before ISK; is that just a typo?)
     316             :          */
     317           8 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
     318           8 :         if (peap_prfplus(data->peap_version, tk, 40,
     319             :                          "Inner Methods Compound Keys",
     320             :                          isk, sizeof(isk), imck, sizeof(imck)) < 0) {
     321           0 :                 os_free(tk);
     322           0 :                 return -1;
     323             :         }
     324           8 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
     325             :                         imck, sizeof(imck));
     326             : 
     327           8 :         os_free(tk);
     328             : 
     329             :         /* TODO: fast-connect: IPMK|CMK = TK */
     330           8 :         os_memcpy(data->ipmk, imck, 40);
     331           8 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
     332           8 :         os_memcpy(data->cmk, imck + 40, 20);
     333           8 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
     334             : 
     335           8 :         return 0;
     336             : }
     337             : 
     338             : 
     339           9 : static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
     340             :                                                  struct eap_peap_data *data,
     341             :                                                  u8 id)
     342             : {
     343             :         struct wpabuf *buf, *encr_req;
     344             :         size_t mlen;
     345             : 
     346           9 :         mlen = 6; /* Result TLV */
     347          17 :         if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
     348           8 :             data->crypto_binding != NO_BINDING) {
     349           8 :                 mlen += 60; /* Cryptobinding TLV */
     350             : #ifdef EAP_SERVER_TNC
     351           8 :                 if (data->soh_response)
     352           0 :                         mlen += wpabuf_len(data->soh_response);
     353             : #endif /* EAP_SERVER_TNC */
     354             :         }
     355             : 
     356           9 :         buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
     357             :                             EAP_CODE_REQUEST, id);
     358           9 :         if (buf == NULL)
     359           0 :                 return NULL;
     360             : 
     361           9 :         wpabuf_put_u8(buf, 0x80); /* Mandatory */
     362           9 :         wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
     363             :         /* Length */
     364           9 :         wpabuf_put_be16(buf, 2);
     365             :         /* Status */
     366           9 :         wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
     367             :                         EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
     368             : 
     369          17 :         if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
     370           8 :             data->crypto_binding != NO_BINDING) {
     371             :                 u8 *mac;
     372           8 :                 u8 eap_type = EAP_TYPE_PEAP;
     373             :                 const u8 *addr[2];
     374             :                 size_t len[2];
     375             :                 u16 tlv_type;
     376             : 
     377             : #ifdef EAP_SERVER_TNC
     378           8 :                 if (data->soh_response) {
     379           0 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "
     380             :                                    "Response TLV");
     381           0 :                         wpabuf_put_buf(buf, data->soh_response);
     382           0 :                         wpabuf_free(data->soh_response);
     383           0 :                         data->soh_response = NULL;
     384             :                 }
     385             : #endif /* EAP_SERVER_TNC */
     386             : 
     387          16 :                 if (eap_peap_derive_cmk(sm, data) < 0 ||
     388           8 :                     random_get_bytes(data->binding_nonce, 32)) {
     389           0 :                         wpabuf_free(buf);
     390           0 :                         return NULL;
     391             :                 }
     392             : 
     393             :                 /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
     394           8 :                 addr[0] = wpabuf_put(buf, 0);
     395           8 :                 len[0] = 60;
     396           8 :                 addr[1] = &eap_type;
     397           8 :                 len[1] = 1;
     398             : 
     399           8 :                 tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
     400           8 :                 wpabuf_put_be16(buf, tlv_type);
     401           8 :                 wpabuf_put_be16(buf, 56);
     402             : 
     403           8 :                 wpabuf_put_u8(buf, 0); /* Reserved */
     404           8 :                 wpabuf_put_u8(buf, data->peap_version); /* Version */
     405           8 :                 wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
     406           8 :                 wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
     407           8 :                 wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
     408           8 :                 mac = wpabuf_put(buf, 20); /* Compound_MAC */
     409           8 :                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
     410           8 :                             data->cmk, 20);
     411          16 :                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
     412           8 :                             addr[0], len[0]);
     413          16 :                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
     414           8 :                             addr[1], len[1]);
     415           8 :                 hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
     416           8 :                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
     417             :                             mac, SHA1_MAC_LEN);
     418           8 :                 data->crypto_binding_sent = 1;
     419             :         }
     420             : 
     421           9 :         wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
     422             :                             buf);
     423             : 
     424           9 :         encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
     425           9 :         wpabuf_free(buf);
     426             : 
     427           9 :         return encr_req;
     428             : }
     429             : 
     430             : 
     431          26 : static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
     432             :                                                   struct eap_peap_data *data,
     433             :                                                   u8 id, int success)
     434             : {
     435             :         struct wpabuf *encr_req, msgbuf;
     436             :         size_t req_len;
     437             :         struct eap_hdr *hdr;
     438             : 
     439          26 :         req_len = sizeof(*hdr);
     440          26 :         hdr = os_zalloc(req_len);
     441          26 :         if (hdr == NULL)
     442           0 :                 return NULL;
     443             : 
     444          26 :         hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
     445          26 :         hdr->identifier = id;
     446          26 :         hdr->length = host_to_be16(req_len);
     447             : 
     448          26 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
     449             :                         (u8 *) hdr, req_len);
     450             : 
     451          26 :         wpabuf_set(&msgbuf, hdr, req_len);
     452          26 :         encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
     453          26 :         os_free(hdr);
     454             : 
     455          26 :         return encr_req;
     456             : }
     457             : 
     458             : 
     459         286 : static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
     460             : {
     461         286 :         struct eap_peap_data *data = priv;
     462             : 
     463         286 :         if (data->ssl.state == FRAG_ACK) {
     464           1 :                 return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
     465             :                                                 data->peap_version);
     466             :         }
     467             : 
     468         285 :         if (data->ssl.state == WAIT_FRAG_ACK) {
     469          31 :                 return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
     470             :                                                 data->peap_version, id);
     471             :         }
     472             : 
     473         254 :         switch (data->state) {
     474             :         case START:
     475          35 :                 return eap_peap_build_start(sm, data, id);
     476             :         case PHASE1:
     477             :         case PHASE1_ID2:
     478          70 :                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
     479          35 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
     480             :                                    "starting Phase2");
     481          35 :                         eap_peap_state(data, PHASE2_START);
     482             :                 }
     483          70 :                 break;
     484             :         case PHASE2_ID:
     485             :         case PHASE2_METHOD:
     486         111 :                 wpabuf_free(data->ssl.tls_out);
     487         111 :                 data->ssl.tls_out_pos = 0;
     488         111 :                 data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
     489         111 :                 break;
     490             : #ifdef EAP_SERVER_TNC
     491             :         case PHASE2_SOH:
     492           3 :                 wpabuf_free(data->ssl.tls_out);
     493           3 :                 data->ssl.tls_out_pos = 0;
     494           3 :                 data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id);
     495           3 :                 break;
     496             : #endif /* EAP_SERVER_TNC */
     497             :         case PHASE2_TLV:
     498           9 :                 wpabuf_free(data->ssl.tls_out);
     499           9 :                 data->ssl.tls_out_pos = 0;
     500           9 :                 data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
     501           9 :                 break;
     502             :         case SUCCESS_REQ:
     503          24 :                 wpabuf_free(data->ssl.tls_out);
     504          24 :                 data->ssl.tls_out_pos = 0;
     505          24 :                 data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
     506             :                                                                1);
     507          24 :                 break;
     508             :         case FAILURE_REQ:
     509           2 :                 wpabuf_free(data->ssl.tls_out);
     510           2 :                 data->ssl.tls_out_pos = 0;
     511           2 :                 data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
     512             :                                                                0);
     513           2 :                 break;
     514             :         default:
     515           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
     516           0 :                            __func__, data->state);
     517           0 :                 return NULL;
     518             :         }
     519             : 
     520         219 :         return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
     521             :                                         data->peap_version, id);
     522             : }
     523             : 
     524             : 
     525         285 : static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
     526             :                               struct wpabuf *respData)
     527             : {
     528             :         const u8 *pos;
     529             :         size_t len;
     530             : 
     531         285 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
     532         285 :         if (pos == NULL || len < 1) {
     533           0 :                 wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
     534           0 :                 return TRUE;
     535             :         }
     536             : 
     537         285 :         return FALSE;
     538             : }
     539             : 
     540             : 
     541         110 : static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
     542             :                                 EapType eap_type)
     543             : {
     544         110 :         if (data->phase2_priv && data->phase2_method) {
     545          72 :                 data->phase2_method->reset(sm, data->phase2_priv);
     546          72 :                 data->phase2_method = NULL;
     547          72 :                 data->phase2_priv = NULL;
     548             :         }
     549         110 :         data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
     550             :                                                         eap_type);
     551         110 :         if (!data->phase2_method)
     552          38 :                 return -1;
     553             : 
     554          72 :         sm->init_phase2 = 1;
     555          72 :         data->phase2_priv = data->phase2_method->init(sm);
     556          72 :         sm->init_phase2 = 0;
     557          72 :         return 0;
     558             : }
     559             : 
     560             : 
     561           6 : static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
     562             :                                           struct eap_peap_data *data,
     563             :                                           const u8 *crypto_tlv,
     564             :                                           size_t crypto_tlv_len)
     565             : {
     566             :         u8 buf[61], mac[SHA1_MAC_LEN];
     567             :         const u8 *pos;
     568             : 
     569           6 :         if (crypto_tlv_len != 4 + 56) {
     570           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
     571             :                            "length %d", (int) crypto_tlv_len);
     572           0 :                 return -1;
     573             :         }
     574             : 
     575           6 :         pos = crypto_tlv;
     576           6 :         pos += 4; /* TLV header */
     577           6 :         if (pos[1] != data->peap_version) {
     578           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
     579             :                            "mismatch (was %d; expected %d)",
     580           0 :                            pos[1], data->peap_version);
     581           0 :                 return -1;
     582             :         }
     583             : 
     584           6 :         if (pos[3] != 1) {
     585           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
     586           0 :                            "SubType %d", pos[3]);
     587           0 :                 return -1;
     588             :         }
     589           6 :         pos += 4;
     590           6 :         pos += 32; /* Nonce */
     591             : 
     592             :         /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
     593           6 :         os_memcpy(buf, crypto_tlv, 60);
     594           6 :         os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
     595           6 :         buf[60] = EAP_TYPE_PEAP;
     596           6 :         hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
     597             : 
     598           6 :         if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
     599           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
     600             :                            "cryptobinding TLV");
     601           0 :                 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
     602           0 :                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
     603             :                             buf, 61);
     604           0 :                 return -1;
     605             :         }
     606             : 
     607           6 :         wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
     608             : 
     609           6 :         return 0;
     610             : }
     611             : 
     612             : 
     613           8 : static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
     614             :                                         struct eap_peap_data *data,
     615             :                                         struct wpabuf *in_data)
     616             : {
     617             :         const u8 *pos;
     618             :         size_t left;
     619           8 :         const u8 *result_tlv = NULL, *crypto_tlv = NULL;
     620           8 :         size_t result_tlv_len = 0, crypto_tlv_len = 0;
     621             :         int tlv_type, mandatory, tlv_len;
     622             : 
     623           8 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
     624           8 :         if (pos == NULL) {
     625           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
     626           0 :                 return;
     627             :         }
     628             : 
     629             :         /* Parse TLVs */
     630           8 :         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
     631          30 :         while (left >= 4) {
     632          14 :                 mandatory = !!(pos[0] & 0x80);
     633          14 :                 tlv_type = pos[0] & 0x3f;
     634          14 :                 tlv_type = (tlv_type << 8) | pos[1];
     635          14 :                 tlv_len = ((int) pos[2] << 8) | pos[3];
     636          14 :                 pos += 4;
     637          14 :                 left -= 4;
     638          14 :                 if ((size_t) tlv_len > left) {
     639           0 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
     640             :                                    "(tlv_len=%d left=%lu)", tlv_len,
     641             :                                    (unsigned long) left);
     642           0 :                         eap_peap_state(data, FAILURE);
     643           0 :                         return;
     644             :                 }
     645          14 :                 switch (tlv_type) {
     646             :                 case EAP_TLV_RESULT_TLV:
     647           8 :                         result_tlv = pos;
     648           8 :                         result_tlv_len = tlv_len;
     649           8 :                         break;
     650             :                 case EAP_TLV_CRYPTO_BINDING_TLV:
     651           6 :                         crypto_tlv = pos;
     652           6 :                         crypto_tlv_len = tlv_len;
     653           6 :                         break;
     654             :                 default:
     655           0 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
     656             :                                    "%d%s", tlv_type,
     657             :                                    mandatory ? " (mandatory)" : "");
     658           0 :                         if (mandatory) {
     659           0 :                                 eap_peap_state(data, FAILURE);
     660           0 :                                 return;
     661             :                         }
     662             :                         /* Ignore this TLV, but process other TLVs */
     663           0 :                         break;
     664             :                 }
     665             : 
     666          14 :                 pos += tlv_len;
     667          14 :                 left -= tlv_len;
     668             :         }
     669           8 :         if (left) {
     670           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
     671             :                            "Request (left=%lu)", (unsigned long) left);
     672           0 :                 eap_peap_state(data, FAILURE);
     673           0 :                 return;
     674             :         }
     675             : 
     676             :         /* Process supported TLVs */
     677           8 :         if (crypto_tlv && data->crypto_binding_sent) {
     678           6 :                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
     679             :                             crypto_tlv, crypto_tlv_len);
     680           6 :                 if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
     681             :                                                    crypto_tlv_len + 4) < 0) {
     682           0 :                         eap_peap_state(data, FAILURE);
     683           0 :                         return;
     684             :                 }
     685           6 :                 data->crypto_binding_used = 1;
     686           4 :         } else if (!crypto_tlv && data->crypto_binding_sent &&
     687           2 :                    data->crypto_binding == REQUIRE_BINDING) {
     688           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
     689           0 :                 eap_peap_state(data, FAILURE);
     690           0 :                 return;
     691             :         }
     692             : 
     693           8 :         if (result_tlv) {
     694             :                 int status;
     695             :                 const char *requested;
     696             : 
     697           8 :                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
     698             :                             result_tlv, result_tlv_len);
     699           8 :                 if (result_tlv_len < 2) {
     700           0 :                         wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
     701             :                                    "(len=%lu)",
     702             :                                    (unsigned long) result_tlv_len);
     703           0 :                         eap_peap_state(data, FAILURE);
     704           0 :                         return;
     705             :                 }
     706           8 :                 requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
     707             :                         "Failure";
     708           8 :                 status = WPA_GET_BE16(result_tlv);
     709           8 :                 if (status == EAP_TLV_RESULT_SUCCESS) {
     710           7 :                         wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
     711             :                                    "- requested %s", requested);
     712           7 :                         if (data->tlv_request == TLV_REQ_SUCCESS)
     713           7 :                                 eap_peap_state(data, SUCCESS);
     714             :                         else
     715           0 :                                 eap_peap_state(data, FAILURE);
     716             :                         
     717           1 :                 } else if (status == EAP_TLV_RESULT_FAILURE) {
     718           1 :                         wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
     719             :                                    "- requested %s", requested);
     720           1 :                         eap_peap_state(data, FAILURE);
     721             :                 } else {
     722           0 :                         wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
     723             :                                    "Status %d", status);
     724           0 :                         eap_peap_state(data, FAILURE);
     725             :                 }
     726             :         }
     727             : }
     728             : 
     729             : 
     730             : #ifdef EAP_SERVER_TNC
     731           3 : static void eap_peap_process_phase2_soh(struct eap_sm *sm,
     732             :                                         struct eap_peap_data *data,
     733             :                                         struct wpabuf *in_data)
     734             : {
     735             :         const u8 *pos, *vpos;
     736             :         size_t left;
     737           3 :         const u8 *soh_tlv = NULL;
     738           3 :         size_t soh_tlv_len = 0;
     739             :         int tlv_type, mandatory, tlv_len, vtlv_len;
     740             :         u8 next_type;
     741             :         u32 vendor_id;
     742             : 
     743           3 :         pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
     744           3 :         if (pos == NULL) {
     745           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
     746             :                            "Extensions Method header - skip TNC");
     747           0 :                 goto auth_method;
     748             :         }
     749             : 
     750             :         /* Parse TLVs */
     751           3 :         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
     752           9 :         while (left >= 4) {
     753           3 :                 mandatory = !!(pos[0] & 0x80);
     754           3 :                 tlv_type = pos[0] & 0x3f;
     755           3 :                 tlv_type = (tlv_type << 8) | pos[1];
     756           3 :                 tlv_len = ((int) pos[2] << 8) | pos[3];
     757           3 :                 pos += 4;
     758           3 :                 left -= 4;
     759           3 :                 if ((size_t) tlv_len > left) {
     760           0 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
     761             :                                    "(tlv_len=%d left=%lu)", tlv_len,
     762             :                                    (unsigned long) left);
     763           0 :                         eap_peap_state(data, FAILURE);
     764           0 :                         return;
     765             :                 }
     766           3 :                 switch (tlv_type) {
     767             :                 case EAP_TLV_VENDOR_SPECIFIC_TLV:
     768           3 :                         if (tlv_len < 4) {
     769           0 :                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
     770             :                                            "vendor specific TLV (len=%d)",
     771             :                                            (int) tlv_len);
     772           0 :                                 eap_peap_state(data, FAILURE);
     773           0 :                                 return;
     774             :                         }
     775             : 
     776           3 :                         vendor_id = WPA_GET_BE32(pos);
     777           3 :                         if (vendor_id != EAP_VENDOR_MICROSOFT) {
     778           0 :                                 if (mandatory) {
     779           0 :                                         eap_peap_state(data, FAILURE);
     780           0 :                                         return;
     781             :                                 }
     782           0 :                                 break;
     783             :                         }
     784             : 
     785           3 :                         vpos = pos + 4;
     786           3 :                         mandatory = !!(vpos[0] & 0x80);
     787           3 :                         tlv_type = vpos[0] & 0x3f;
     788           3 :                         tlv_type = (tlv_type << 8) | vpos[1];
     789           3 :                         vtlv_len = ((int) vpos[2] << 8) | vpos[3];
     790           3 :                         vpos += 4;
     791           3 :                         if (vpos + vtlv_len > pos + left) {
     792           0 :                                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
     793             :                                            "underrun");
     794           0 :                                 eap_peap_state(data, FAILURE);
     795           0 :                                 return;
     796             :                         }
     797             : 
     798           3 :                         if (tlv_type == 1) {
     799           3 :                                 soh_tlv = vpos;
     800           3 :                                 soh_tlv_len = vtlv_len;
     801           3 :                                 break;
     802             :                         }
     803             : 
     804           0 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
     805             :                                    "Type %d%s", tlv_type,
     806             :                                    mandatory ? " (mandatory)" : "");
     807           0 :                         if (mandatory) {
     808           0 :                                 eap_peap_state(data, FAILURE);
     809           0 :                                 return;
     810             :                         }
     811             :                         /* Ignore this TLV, but process other TLVs */
     812           0 :                         break;
     813             :                 default:
     814           0 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
     815             :                                    "%d%s", tlv_type,
     816             :                                    mandatory ? " (mandatory)" : "");
     817           0 :                         if (mandatory) {
     818           0 :                                 eap_peap_state(data, FAILURE);
     819           0 :                                 return;
     820             :                         }
     821             :                         /* Ignore this TLV, but process other TLVs */
     822           0 :                         break;
     823             :                 }
     824             : 
     825           3 :                 pos += tlv_len;
     826           3 :                 left -= tlv_len;
     827             :         }
     828           3 :         if (left) {
     829           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
     830             :                            "Request (left=%lu)", (unsigned long) left);
     831           0 :                 eap_peap_state(data, FAILURE);
     832           0 :                 return;
     833             :         }
     834             : 
     835             :         /* Process supported TLVs */
     836           3 :         if (soh_tlv) {
     837           3 :                 int failure = 0;
     838           3 :                 wpabuf_free(data->soh_response);
     839           3 :                 data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
     840             :                                                       &failure);
     841           3 :                 if (failure) {
     842           0 :                         eap_peap_state(data, FAILURE);
     843           0 :                         return;
     844             :                 }
     845             :         } else {
     846           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
     847           0 :                 eap_peap_state(data, FAILURE);
     848           0 :                 return;
     849             :         }
     850             : 
     851             : auth_method:
     852           3 :         eap_peap_state(data, PHASE2_METHOD);
     853           3 :         next_type = sm->user->methods[0].method;
     854           3 :         sm->user_eap_method_index = 1;
     855           3 :         wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
     856           3 :         eap_peap_phase2_init(sm, data, next_type);
     857             : }
     858             : #endif /* EAP_SERVER_TNC */
     859             : 
     860             : 
     861         123 : static void eap_peap_process_phase2_response(struct eap_sm *sm,
     862             :                                              struct eap_peap_data *data,
     863             :                                              struct wpabuf *in_data)
     864             : {
     865         123 :         u8 next_type = EAP_TYPE_NONE;
     866             :         const struct eap_hdr *hdr;
     867             :         const u8 *pos;
     868             :         size_t left;
     869             : 
     870         123 :         if (data->state == PHASE2_TLV) {
     871           8 :                 eap_peap_process_phase2_tlv(sm, data, in_data);
     872           8 :                 return;
     873             :         }
     874             : 
     875             : #ifdef EAP_SERVER_TNC
     876         115 :         if (data->state == PHASE2_SOH) {
     877           3 :                 eap_peap_process_phase2_soh(sm, data, in_data);
     878           3 :                 return;
     879             :         }
     880             : #endif /* EAP_SERVER_TNC */
     881             : 
     882         112 :         if (data->phase2_priv == NULL) {
     883           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
     884             :                            "initialized?!", __func__);
     885           0 :                 return;
     886             :         }
     887             : 
     888         112 :         hdr = wpabuf_head(in_data);
     889         112 :         pos = (const u8 *) (hdr + 1);
     890             : 
     891         112 :         if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
     892           2 :                 left = wpabuf_len(in_data) - sizeof(*hdr);
     893           2 :                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
     894             :                             "allowed types", pos + 1, left - 1);
     895           2 :                 eap_sm_process_nak(sm, pos + 1, left - 1);
     896           4 :                 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
     897           2 :                     sm->user->methods[sm->user_eap_method_index].method !=
     898             :                     EAP_TYPE_NONE) {
     899           4 :                         next_type = sm->user->methods[
     900           2 :                                 sm->user_eap_method_index++].method;
     901           2 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
     902             :                                    next_type);
     903             :                 } else {
     904           0 :                         eap_peap_req_failure(sm, data);
     905           0 :                         next_type = EAP_TYPE_NONE;
     906             :                 }
     907           2 :                 eap_peap_phase2_init(sm, data, next_type);
     908           2 :                 return;
     909             :         }
     910             : 
     911         110 :         if (data->phase2_method->check(sm, data->phase2_priv, in_data)) {
     912           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
     913             :                            "ignore the packet");
     914           0 :                 return;
     915             :         }
     916             : 
     917         110 :         data->phase2_method->process(sm, data->phase2_priv, in_data);
     918             : 
     919         110 :         if (sm->method_pending == METHOD_PENDING_WAIT) {
     920           1 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
     921             :                            "pending wait state - save decrypted response");
     922           1 :                 wpabuf_free(data->pending_phase2_resp);
     923           1 :                 data->pending_phase2_resp = wpabuf_dup(in_data);
     924             :         }
     925             : 
     926         110 :         if (!data->phase2_method->isDone(sm, data->phase2_priv))
     927          40 :                 return;
     928             : 
     929          70 :         if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
     930           2 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
     931           2 :                 eap_peap_req_failure(sm, data);
     932           2 :                 next_type = EAP_TYPE_NONE;
     933           2 :                 eap_peap_phase2_init(sm, data, next_type);
     934           2 :                 return;
     935             :         }
     936             : 
     937          68 :         os_free(data->phase2_key);
     938          68 :         if (data->phase2_method->getKey) {
     939          31 :                 data->phase2_key = data->phase2_method->getKey(
     940             :                         sm, data->phase2_priv, &data->phase2_key_len);
     941          31 :                 if (data->phase2_key == NULL) {
     942           1 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
     943             :                                    "failed");
     944           1 :                         eap_peap_req_failure(sm, data);
     945           1 :                         eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
     946           1 :                         return;
     947             :                 }
     948             :         }
     949             : 
     950          67 :         switch (data->state) {
     951             :         case PHASE1_ID2:
     952             :         case PHASE2_ID:
     953             :         case PHASE2_SOH:
     954          35 :                 if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
     955           0 :                         wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
     956             :                                           "Identity not found in the user "
     957             :                                           "database",
     958           0 :                                           sm->identity, sm->identity_len);
     959           0 :                         eap_peap_req_failure(sm, data);
     960           0 :                         next_type = EAP_TYPE_NONE;
     961           0 :                         break;
     962             :                 }
     963             : 
     964             : #ifdef EAP_SERVER_TNC
     965          38 :                 if (data->state != PHASE2_SOH && sm->tnc &&
     966           3 :                     data->peap_version == 0) {
     967           3 :                         eap_peap_state(data, PHASE2_SOH);
     968           3 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
     969             :                                    "TNC (NAP SOH)");
     970           3 :                         next_type = EAP_TYPE_NONE;
     971           3 :                         break;
     972             :                 }
     973             : #endif /* EAP_SERVER_TNC */
     974             : 
     975          32 :                 eap_peap_state(data, PHASE2_METHOD);
     976          32 :                 next_type = sm->user->methods[0].method;
     977          32 :                 sm->user_eap_method_index = 1;
     978          32 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
     979          32 :                 break;
     980             :         case PHASE2_METHOD:
     981          32 :                 eap_peap_req_success(sm, data);
     982          32 :                 next_type = EAP_TYPE_NONE;
     983          32 :                 break;
     984             :         case FAILURE:
     985           0 :                 break;
     986             :         default:
     987           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
     988           0 :                            __func__, data->state);
     989           0 :                 break;
     990             :         }
     991             : 
     992          67 :         eap_peap_phase2_init(sm, data, next_type);
     993             : }
     994             : 
     995             : 
     996         123 : static void eap_peap_process_phase2(struct eap_sm *sm,
     997             :                                     struct eap_peap_data *data,
     998             :                                     const struct wpabuf *respData,
     999             :                                     struct wpabuf *in_buf)
    1000             : {
    1001             :         struct wpabuf *in_decrypted;
    1002             :         const struct eap_hdr *hdr;
    1003             :         size_t len;
    1004             : 
    1005         123 :         wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
    1006             :                    " Phase 2", (unsigned long) wpabuf_len(in_buf));
    1007             : 
    1008         123 :         if (data->pending_phase2_resp) {
    1009           1 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
    1010             :                            "skip decryption and use old data");
    1011           1 :                 eap_peap_process_phase2_response(sm, data,
    1012             :                                                  data->pending_phase2_resp);
    1013           1 :                 wpabuf_free(data->pending_phase2_resp);
    1014           1 :                 data->pending_phase2_resp = NULL;
    1015           1 :                 return;
    1016             :         }
    1017             : 
    1018         122 :         in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
    1019             :                                               in_buf);
    1020         122 :         if (in_decrypted == NULL) {
    1021           0 :                 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
    1022             :                            "data");
    1023           0 :                 eap_peap_state(data, FAILURE);
    1024           0 :                 return;
    1025             :         }
    1026             : 
    1027         122 :         wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
    1028             :                             in_decrypted);
    1029             : 
    1030         122 :         if (data->peap_version == 0 && data->state != PHASE2_TLV) {
    1031             :                 const struct eap_hdr *resp;
    1032             :                 struct eap_hdr *nhdr;
    1033          30 :                 struct wpabuf *nbuf =
    1034          30 :                         wpabuf_alloc(sizeof(struct eap_hdr) +
    1035          30 :                                      wpabuf_len(in_decrypted));
    1036          30 :                 if (nbuf == NULL) {
    1037           0 :                         wpabuf_free(in_decrypted);
    1038           0 :                         return;
    1039             :                 }
    1040             : 
    1041          30 :                 resp = wpabuf_head(respData);
    1042          30 :                 nhdr = wpabuf_put(nbuf, sizeof(*nhdr));
    1043          30 :                 nhdr->code = resp->code;
    1044          30 :                 nhdr->identifier = resp->identifier;
    1045          30 :                 nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
    1046             :                                             wpabuf_len(in_decrypted));
    1047          30 :                 wpabuf_put_buf(nbuf, in_decrypted);
    1048          30 :                 wpabuf_free(in_decrypted);
    1049             : 
    1050          30 :                 in_decrypted = nbuf;
    1051             :         }
    1052             : 
    1053         122 :         hdr = wpabuf_head(in_decrypted);
    1054         122 :         if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) {
    1055           0 :                 wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
    1056             :                            "EAP frame (len=%lu)",
    1057             :                            (unsigned long) wpabuf_len(in_decrypted));
    1058           0 :                 wpabuf_free(in_decrypted);
    1059           0 :                 eap_peap_req_failure(sm, data);
    1060           0 :                 return;
    1061             :         }
    1062         122 :         len = be_to_host16(hdr->length);
    1063         122 :         if (len > wpabuf_len(in_decrypted)) {
    1064           0 :                 wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
    1065             :                            "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
    1066             :                            (unsigned long) wpabuf_len(in_decrypted),
    1067             :                            (unsigned long) len);
    1068           0 :                 wpabuf_free(in_decrypted);
    1069           0 :                 eap_peap_req_failure(sm, data);
    1070           0 :                 return;
    1071             :         }
    1072         244 :         wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
    1073         244 :                    "identifier=%d length=%lu", hdr->code, hdr->identifier,
    1074             :                    (unsigned long) len);
    1075         122 :         switch (hdr->code) {
    1076             :         case EAP_CODE_RESPONSE:
    1077         122 :                 eap_peap_process_phase2_response(sm, data, in_decrypted);
    1078         122 :                 break;
    1079             :         case EAP_CODE_SUCCESS:
    1080           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
    1081           0 :                 if (data->state == SUCCESS_REQ) {
    1082           0 :                         eap_peap_state(data, SUCCESS);
    1083             :                 }
    1084           0 :                 break;
    1085             :         case EAP_CODE_FAILURE:
    1086           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
    1087           0 :                 eap_peap_state(data, FAILURE);
    1088           0 :                 break;
    1089             :         default:
    1090           0 :                 wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
    1091           0 :                            "Phase 2 EAP header", hdr->code);
    1092           0 :                 break;
    1093             :         }
    1094             : 
    1095         122 :         wpabuf_free(in_decrypted);
    1096             : }
    1097             : 
    1098             : 
    1099         286 : static int eap_peap_process_version(struct eap_sm *sm, void *priv,
    1100             :                                     int peer_version)
    1101             : {
    1102         286 :         struct eap_peap_data *data = priv;
    1103             : 
    1104         286 :         data->recv_version = peer_version;
    1105         286 :         if (data->force_version >= 0 && peer_version != data->force_version) {
    1106           0 :                 wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
    1107             :                            " version (forced=%d peer=%d) - reject",
    1108             :                            data->force_version, peer_version);
    1109           0 :                 return -1;
    1110             :         }
    1111         286 :         if (peer_version < data->peap_version) {
    1112           9 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
    1113             :                            "use version %d",
    1114             :                            peer_version, data->peap_version, peer_version);
    1115           9 :                 data->peap_version = peer_version;
    1116             :         }
    1117             : 
    1118         286 :         return 0;
    1119             : }
    1120             : 
    1121             : 
    1122         254 : static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
    1123             :                                  const struct wpabuf *respData)
    1124             : {
    1125         254 :         struct eap_peap_data *data = priv;
    1126             : 
    1127         254 :         switch (data->state) {
    1128             :         case PHASE1:
    1129          70 :                 if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
    1130           0 :                         eap_peap_state(data, FAILURE);
    1131           0 :                         break;
    1132             :                 }
    1133          70 :                 break;
    1134             :         case PHASE2_START:
    1135          35 :                 eap_peap_state(data, PHASE2_ID);
    1136          35 :                 eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
    1137          35 :                 break;
    1138             :         case PHASE1_ID2:
    1139             :         case PHASE2_ID:
    1140             :         case PHASE2_METHOD:
    1141             :         case PHASE2_SOH:
    1142             :         case PHASE2_TLV:
    1143         123 :                 eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in);
    1144         123 :                 break;
    1145             :         case SUCCESS_REQ:
    1146          24 :                 eap_peap_state(data, SUCCESS);
    1147          24 :                 break;
    1148             :         case FAILURE_REQ:
    1149           2 :                 eap_peap_state(data, FAILURE);
    1150           2 :                 break;
    1151             :         default:
    1152           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
    1153           0 :                            data->state, __func__);
    1154           0 :                 break;
    1155             :         }
    1156         254 : }
    1157             : 
    1158             : 
    1159         286 : static void eap_peap_process(struct eap_sm *sm, void *priv,
    1160             :                              struct wpabuf *respData)
    1161             : {
    1162         286 :         struct eap_peap_data *data = priv;
    1163         286 :         if (eap_server_tls_process(sm, &data->ssl, respData, data,
    1164             :                                    EAP_TYPE_PEAP, eap_peap_process_version,
    1165             :                                    eap_peap_process_msg) < 0)
    1166           0 :                 eap_peap_state(data, FAILURE);
    1167         286 : }
    1168             : 
    1169             : 
    1170         289 : static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
    1171             : {
    1172         289 :         struct eap_peap_data *data = priv;
    1173         289 :         return data->state == SUCCESS || data->state == FAILURE;
    1174             : }
    1175             : 
    1176             : 
    1177          34 : static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
    1178             : {
    1179          34 :         struct eap_peap_data *data = priv;
    1180             :         u8 *eapKeyData;
    1181             : 
    1182          34 :         if (data->state != SUCCESS)
    1183           3 :                 return NULL;
    1184             : 
    1185          31 :         if (data->crypto_binding_used) {
    1186             :                 u8 csk[128];
    1187             :                 /*
    1188             :                  * Note: It looks like Microsoft implementation requires null
    1189             :                  * termination for this label while the one used for deriving
    1190             :                  * IPMK|CMK did not use null termination.
    1191             :                  */
    1192           6 :                 if (peap_prfplus(data->peap_version, data->ipmk, 40,
    1193             :                                  "Session Key Generating Function",
    1194             :                                  (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
    1195           0 :                         return NULL;
    1196           6 :                 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
    1197           6 :                 eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
    1198           6 :                 if (eapKeyData) {
    1199           6 :                         os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
    1200           6 :                         *len = EAP_TLS_KEY_LEN;
    1201           6 :                         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
    1202             :                                     eapKeyData, EAP_TLS_KEY_LEN);
    1203             :                 } else {
    1204           0 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
    1205             :                                    "key");
    1206             :                 }
    1207             : 
    1208           6 :                 return eapKeyData;
    1209             :         }
    1210             : 
    1211             :         /* TODO: PEAPv1 - different label in some cases */
    1212          25 :         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
    1213             :                                                "client EAP encryption",
    1214             :                                                EAP_TLS_KEY_LEN);
    1215          25 :         if (eapKeyData) {
    1216          25 :                 *len = EAP_TLS_KEY_LEN;
    1217          25 :                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
    1218             :                             eapKeyData, EAP_TLS_KEY_LEN);
    1219             :         } else {
    1220           0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key");
    1221             :         }
    1222             : 
    1223          25 :         return eapKeyData;
    1224             : }
    1225             : 
    1226             : 
    1227          37 : static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
    1228             : {
    1229          37 :         struct eap_peap_data *data = priv;
    1230          37 :         return data->state == SUCCESS;
    1231             : }
    1232             : 
    1233             : 
    1234          34 : static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
    1235             : {
    1236          34 :         struct eap_peap_data *data = priv;
    1237             : 
    1238          34 :         if (data->state != SUCCESS)
    1239           3 :                 return NULL;
    1240             : 
    1241          31 :         return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP,
    1242             :                                                 len);
    1243             : }
    1244             : 
    1245             : 
    1246          10 : int eap_server_peap_register(void)
    1247             : {
    1248             :         struct eap_method *eap;
    1249             :         int ret;
    1250             : 
    1251          10 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    1252             :                                       EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
    1253          10 :         if (eap == NULL)
    1254           0 :                 return -1;
    1255             : 
    1256          10 :         eap->init = eap_peap_init;
    1257          10 :         eap->reset = eap_peap_reset;
    1258          10 :         eap->buildReq = eap_peap_buildReq;
    1259          10 :         eap->check = eap_peap_check;
    1260          10 :         eap->process = eap_peap_process;
    1261          10 :         eap->isDone = eap_peap_isDone;
    1262          10 :         eap->getKey = eap_peap_getKey;
    1263          10 :         eap->isSuccess = eap_peap_isSuccess;
    1264          10 :         eap->getSessionId = eap_peap_get_session_id;
    1265             : 
    1266          10 :         ret = eap_server_method_register(eap);
    1267          10 :         if (ret)
    1268           0 :                 eap_server_method_free(eap);
    1269          10 :         return ret;
    1270             : }

Generated by: LCOV version 1.10