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

Generated by: LCOV version 1.10