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

Generated by: LCOV version 1.10