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 1393793999 Lines: 388 634 61.2 %
Date: 2014-03-02 Functions: 26 28 92.9 %
Branches: 144 288 50.0 %

           Branch data     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                 :        252 : static const char * eap_peap_state_txt(int state)
      60                 :            : {
      61   [ +  +  -  +  :        252 :         switch (state) {
          +  +  -  +  +  
             +  +  +  - ]
      62                 :            :         case START:
      63                 :         21 :                 return "START";
      64                 :            :         case PHASE1:
      65                 :         42 :                 return "PHASE1";
      66                 :            :         case PHASE1_ID2:
      67                 :          0 :                 return "PHASE1_ID2";
      68                 :            :         case PHASE2_START:
      69                 :         42 :                 return "PHASE2_START";
      70                 :            :         case PHASE2_ID:
      71                 :         42 :                 return "PHASE2_ID";
      72                 :            :         case PHASE2_METHOD:
      73                 :         42 :                 return "PHASE2_METHOD";
      74                 :            :         case PHASE2_SOH:
      75                 :          0 :                 return "PHASE2_SOH";
      76                 :            :         case PHASE2_TLV:
      77                 :          4 :                 return "PHASE2_TLV";
      78                 :            :         case SUCCESS_REQ:
      79                 :         36 :                 return "SUCCESS_REQ";
      80                 :            :         case FAILURE_REQ:
      81                 :          2 :                 return "FAILURE_REQ";
      82                 :            :         case SUCCESS:
      83                 :         20 :                 return "SUCCESS";
      84                 :            :         case FAILURE:
      85                 :          1 :                 return "FAILURE";
      86                 :            :         default:
      87                 :        252 :                 return "Unknown?!";
      88                 :            :         }
      89                 :            : }
      90                 :            : 
      91                 :            : 
      92                 :        126 : static void eap_peap_state(struct eap_peap_data *data, int state)
      93                 :            : {
      94                 :        126 :         wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
      95                 :        126 :                    eap_peap_state_txt(data->state),
      96                 :            :                    eap_peap_state_txt(state));
      97                 :        126 :         data->state = state;
      98                 :        126 : }
      99                 :            : 
     100                 :            : 
     101                 :         20 : static void eap_peap_req_success(struct eap_sm *sm,
     102                 :            :                                  struct eap_peap_data *data)
     103                 :            : {
     104 [ +  - ][ -  + ]:         20 :         if (data->state == FAILURE || data->state == FAILURE_REQ) {
     105                 :          0 :                 eap_peap_state(data, FAILURE);
     106                 :         20 :                 return;
     107                 :            :         }
     108                 :            : 
     109         [ +  + ]:         20 :         if (data->peap_version == 0) {
     110                 :          2 :                 data->tlv_request = TLV_REQ_SUCCESS;
     111                 :          2 :                 eap_peap_state(data, PHASE2_TLV);
     112                 :            :         } else {
     113                 :         18 :                 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 [ +  - ][ +  - ]:          1 :         if (data->state == FAILURE || data->state == FAILURE_REQ ||
                 [ +  - ]
     122         [ -  + ]:          1 :             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                 :         21 : static void * eap_peap_init(struct eap_sm *sm)
     137                 :            : {
     138                 :            :         struct eap_peap_data *data;
     139                 :            : 
     140                 :         21 :         data = os_zalloc(sizeof(*data));
     141         [ -  + ]:         21 :         if (data == NULL)
     142                 :          0 :                 return NULL;
     143                 :         21 :         data->peap_version = EAP_PEAP_VERSION;
     144                 :         21 :         data->force_version = -1;
     145 [ +  - ][ -  + ]:         21 :         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                 :         21 :         data->state = START;
     152                 :         21 :         data->crypto_binding = OPTIONAL_BINDING;
     153                 :            : 
     154         [ -  + ]:         21 :         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                 :         21 :         return data;
     161                 :            : }
     162                 :            : 
     163                 :            : 
     164                 :         21 : static void eap_peap_reset(struct eap_sm *sm, void *priv)
     165                 :            : {
     166                 :         21 :         struct eap_peap_data *data = priv;
     167         [ -  + ]:         21 :         if (data == NULL)
     168                 :         21 :                 return;
     169 [ -  + ][ #  # ]:         21 :         if (data->phase2_priv && data->phase2_method)
     170                 :          0 :                 data->phase2_method->reset(sm, data->phase2_priv);
     171                 :         21 :         eap_server_tls_ssl_deinit(sm, &data->ssl);
     172                 :         21 :         wpabuf_free(data->pending_phase2_resp);
     173                 :         21 :         os_free(data->phase2_key);
     174                 :         21 :         wpabuf_free(data->soh_response);
     175                 :         21 :         os_free(data);
     176                 :            : }
     177                 :            : 
     178                 :            : 
     179                 :         21 : 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                 :         21 :         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,
     185                 :            :                             EAP_CODE_REQUEST, id);
     186         [ -  + ]:         21 :         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                 :         21 :         wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);
     194                 :            : 
     195                 :         21 :         eap_peap_state(data, PHASE1);
     196                 :            : 
     197                 :         21 :         return req;
     198                 :            : }
     199                 :            : 
     200                 :            : 
     201                 :         69 : 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 [ +  - ][ -  + ]:         69 :         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                 :         69 :         buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
     214         [ -  + ]:         69 :         if (buf == NULL)
     215                 :          0 :                 return NULL;
     216                 :            : 
     217                 :         69 :         req = wpabuf_head(buf);
     218                 :         69 :         req_len = wpabuf_len(buf);
     219                 :         69 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
     220                 :            :                         req, req_len);
     221                 :            : 
     222 [ +  - ][ +  + ]:         69 :         if (data->peap_version == 0 &&
     223                 :          6 :             data->phase2_method->method != EAP_TYPE_TLV) {
     224                 :          6 :                 req += sizeof(struct eap_hdr);
     225                 :          6 :                 req_len -= sizeof(struct eap_hdr);
     226                 :            :         }
     227                 :            : 
     228                 :         69 :         wpabuf_set(&msgbuf, req, req_len);
     229                 :         69 :         encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
     230                 :         69 :         wpabuf_free(buf);
     231                 :            : 
     232                 :         69 :         return encr_req;
     233                 :            : }
     234                 :            : 
     235                 :            : 
     236                 :            : #ifdef EAP_SERVER_TNC
     237                 :          0 : 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                 :          0 :         buf1 = tncs_build_soh_request();
     246         [ #  # ]:          0 :         if (buf1 == NULL)
     247                 :          0 :                 return NULL;
     248                 :            : 
     249                 :          0 :         buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
     250                 :            :                             EAP_CODE_REQUEST, id);
     251         [ #  # ]:          0 :         if (buf == NULL) {
     252                 :          0 :                 wpabuf_free(buf1);
     253                 :          0 :                 return NULL;
     254                 :            :         }
     255                 :          0 :         wpabuf_put_buf(buf, buf1);
     256                 :          0 :         wpabuf_free(buf1);
     257                 :            : 
     258                 :          0 :         req = wpabuf_head(buf);
     259                 :          0 :         req_len = wpabuf_len(buf);
     260                 :            : 
     261                 :          0 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
     262                 :            :                         req, req_len);
     263                 :            : 
     264                 :          0 :         req += sizeof(struct eap_hdr);
     265                 :          0 :         req_len -= sizeof(struct eap_hdr);
     266                 :          0 :         wpabuf_set(&msgbuf, req, req_len);
     267                 :            : 
     268                 :          0 :         encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
     269                 :          0 :         wpabuf_free(buf);
     270                 :            : 
     271                 :          0 :         return encr_req;
     272                 :            : }
     273                 :            : #endif /* EAP_SERVER_TNC */
     274                 :            : 
     275                 :            : 
     276                 :          2 : 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                 :          2 :         os_memset(isk, 0, isk_len);
     282         [ -  + ]:          2 :         if (data->phase2_key == NULL)
     283                 :          2 :                 return;
     284                 :            : 
     285                 :          2 :         key_len = data->phase2_key_len;
     286         [ -  + ]:          2 :         if (key_len > isk_len)
     287                 :          0 :                 key_len = isk_len;
     288                 :          2 :         os_memcpy(isk, data->phase2_key, key_len);
     289                 :            : }
     290                 :            : 
     291                 :            : 
     292                 :          2 : 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                 :          2 :         tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
     302                 :            :                                        EAP_TLS_KEY_LEN);
     303         [ -  + ]:          2 :         if (tk == NULL)
     304                 :          0 :                 return -1;
     305                 :          2 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
     306                 :            : 
     307                 :          2 :         eap_peap_get_isk(data, isk, sizeof(isk));
     308                 :          2 :         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                 :          2 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
     318         [ -  + ]:          2 :         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                 :          2 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
     325                 :            :                         imck, sizeof(imck));
     326                 :            : 
     327                 :          2 :         os_free(tk);
     328                 :            : 
     329                 :            :         /* TODO: fast-connect: IPMK|CMK = TK */
     330                 :          2 :         os_memcpy(data->ipmk, imck, 40);
     331                 :          2 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
     332                 :          2 :         os_memcpy(data->cmk, imck + 40, 20);
     333                 :          2 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
     334                 :            : 
     335                 :          2 :         return 0;
     336                 :            : }
     337                 :            : 
     338                 :            : 
     339                 :          2 : 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                 :          2 :         mlen = 6; /* Result TLV */
     347         [ +  - ]:          2 :         if (data->crypto_binding != NO_BINDING)
     348                 :          2 :                 mlen += 60; /* Cryptobinding TLV */
     349                 :            : #ifdef EAP_SERVER_TNC
     350         [ -  + ]:          2 :         if (data->soh_response)
     351                 :          0 :                 mlen += wpabuf_len(data->soh_response);
     352                 :            : #endif /* EAP_SERVER_TNC */
     353                 :            : 
     354                 :          2 :         buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
     355                 :            :                             EAP_CODE_REQUEST, id);
     356         [ -  + ]:          2 :         if (buf == NULL)
     357                 :          0 :                 return NULL;
     358                 :            : 
     359                 :          2 :         wpabuf_put_u8(buf, 0x80); /* Mandatory */
     360                 :          2 :         wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
     361                 :            :         /* Length */
     362                 :          2 :         wpabuf_put_be16(buf, 2);
     363                 :            :         /* Status */
     364         [ +  - ]:          2 :         wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
     365                 :            :                         EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
     366                 :            : 
     367 [ +  - ][ +  - ]:          2 :         if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
                 [ +  - ]
     368                 :          2 :             data->crypto_binding != NO_BINDING) {
     369                 :            :                 u8 *mac;
     370                 :          2 :                 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         [ -  + ]:          2 :                 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   [ +  -  -  + ]:          4 :                 if (eap_peap_derive_cmk(sm, data) < 0 ||
     386                 :          2 :                     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                 :          2 :                 addr[0] = wpabuf_put(buf, 0);
     393                 :          2 :                 len[0] = 60;
     394                 :          2 :                 addr[1] = &eap_type;
     395                 :          2 :                 len[1] = 1;
     396                 :            : 
     397                 :          2 :                 tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
     398                 :          2 :                 wpabuf_put_be16(buf, tlv_type);
     399                 :          2 :                 wpabuf_put_be16(buf, 56);
     400                 :            : 
     401                 :          2 :                 wpabuf_put_u8(buf, 0); /* Reserved */
     402                 :          2 :                 wpabuf_put_u8(buf, data->peap_version); /* Version */
     403                 :          2 :                 wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
     404                 :          2 :                 wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
     405                 :          2 :                 wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
     406                 :          2 :                 mac = wpabuf_put(buf, 20); /* Compound_MAC */
     407                 :          2 :                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
     408                 :          2 :                             data->cmk, 20);
     409                 :          2 :                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
     410                 :          2 :                             addr[0], len[0]);
     411                 :          2 :                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
     412                 :          2 :                             addr[1], len[1]);
     413                 :          2 :                 hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
     414                 :          2 :                 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
     415                 :            :                             mac, SHA1_MAC_LEN);
     416                 :          2 :                 data->crypto_binding_sent = 1;
     417                 :            :         }
     418                 :            : 
     419                 :          2 :         wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
     420                 :            :                             buf);
     421                 :            : 
     422                 :          2 :         encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
     423                 :          2 :         wpabuf_free(buf);
     424                 :            : 
     425                 :          2 :         return encr_req;
     426                 :            : }
     427                 :            : 
     428                 :            : 
     429                 :         19 : 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                 :         19 :         req_len = sizeof(*hdr);
     438                 :         19 :         hdr = os_zalloc(req_len);
     439         [ -  + ]:         19 :         if (hdr == NULL)
     440                 :          0 :                 return NULL;
     441                 :            : 
     442         [ +  + ]:         19 :         hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
     443                 :         19 :         hdr->identifier = id;
     444                 :         19 :         hdr->length = host_to_be16(req_len);
     445                 :            : 
     446                 :         19 :         wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
     447                 :            :                         (u8 *) hdr, req_len);
     448                 :            : 
     449                 :         19 :         wpabuf_set(&msgbuf, hdr, req_len);
     450                 :         19 :         encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
     451                 :         19 :         os_free(hdr);
     452                 :            : 
     453                 :         19 :         return encr_req;
     454                 :            : }
     455                 :            : 
     456                 :            : 
     457                 :        175 : static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
     458                 :            : {
     459                 :        175 :         struct eap_peap_data *data = priv;
     460                 :            : 
     461         [ +  + ]:        175 :         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         [ +  + ]:        174 :         if (data->ssl.state == WAIT_FRAG_ACK) {
     467                 :         21 :                 return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
     468                 :            :                                                 data->peap_version, id);
     469                 :            :         }
     470                 :            : 
     471   [ +  +  +  -  :        153 :         switch (data->state) {
             +  +  +  - ]
     472                 :            :         case START:
     473                 :         21 :                 return eap_peap_build_start(sm, data, id);
     474                 :            :         case PHASE1:
     475                 :            :         case PHASE1_ID2:
     476         [ +  + ]:         42 :                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
     477                 :         21 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
     478                 :            :                                    "starting Phase2");
     479                 :         21 :                         eap_peap_state(data, PHASE2_START);
     480                 :            :                 }
     481                 :         42 :                 break;
     482                 :            :         case PHASE2_ID:
     483                 :            :         case PHASE2_METHOD:
     484                 :         69 :                 wpabuf_free(data->ssl.tls_out);
     485                 :         69 :                 data->ssl.tls_out_pos = 0;
     486                 :         69 :                 data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
     487                 :         69 :                 break;
     488                 :            : #ifdef EAP_SERVER_TNC
     489                 :            :         case PHASE2_SOH:
     490                 :          0 :                 wpabuf_free(data->ssl.tls_out);
     491                 :          0 :                 data->ssl.tls_out_pos = 0;
     492                 :          0 :                 data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id);
     493                 :          0 :                 break;
     494                 :            : #endif /* EAP_SERVER_TNC */
     495                 :            :         case PHASE2_TLV:
     496                 :          2 :                 wpabuf_free(data->ssl.tls_out);
     497                 :          2 :                 data->ssl.tls_out_pos = 0;
     498                 :          2 :                 data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
     499                 :          2 :                 break;
     500                 :            :         case SUCCESS_REQ:
     501                 :         18 :                 wpabuf_free(data->ssl.tls_out);
     502                 :         18 :                 data->ssl.tls_out_pos = 0;
     503                 :         18 :                 data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
     504                 :            :                                                                1);
     505                 :         18 :                 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                 :        175 :         return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
     519                 :            :                                         data->peap_version, id);
     520                 :            : }
     521                 :            : 
     522                 :            : 
     523                 :        175 : 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                 :        175 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
     530 [ -  + ][ +  - ]:        175 :         if (pos == NULL || len < 1) {
     531                 :          0 :                 wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
     532                 :          0 :                 return TRUE;
     533                 :            :         }
     534                 :            : 
     535                 :        175 :         return FALSE;
     536                 :            : }
     537                 :            : 
     538                 :            : 
     539                 :         65 : static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
     540                 :            :                                 EapType eap_type)
     541                 :            : {
     542 [ +  + ][ +  - ]:         65 :         if (data->phase2_priv && data->phase2_method) {
     543                 :         44 :                 data->phase2_method->reset(sm, data->phase2_priv);
     544                 :         44 :                 data->phase2_method = NULL;
     545                 :         44 :                 data->phase2_priv = NULL;
     546                 :            :         }
     547                 :         65 :         data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
     548                 :            :                                                         eap_type);
     549         [ +  + ]:         65 :         if (!data->phase2_method)
     550                 :         21 :                 return -1;
     551                 :            : 
     552                 :         44 :         sm->init_phase2 = 1;
     553                 :         44 :         data->phase2_priv = data->phase2_method->init(sm);
     554                 :         44 :         sm->init_phase2 = 0;
     555                 :         65 :         return 0;
     556                 :            : }
     557                 :            : 
     558                 :            : 
     559                 :          2 : 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         [ -  + ]:          2 :         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                 :          2 :         pos = crypto_tlv;
     574                 :          2 :         pos += 4; /* TLV header */
     575         [ -  + ]:          2 :         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         [ -  + ]:          2 :         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                 :          2 :         pos += 4;
     588                 :          2 :         pos += 32; /* Nonce */
     589                 :            : 
     590                 :            :         /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
     591                 :          2 :         os_memcpy(buf, crypto_tlv, 60);
     592                 :          2 :         os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
     593                 :          2 :         buf[60] = EAP_TYPE_PEAP;
     594                 :          2 :         hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
     595                 :            : 
     596         [ -  + ]:          2 :         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                 :          2 :         wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
     606                 :            : 
     607                 :          2 :         return 0;
     608                 :            : }
     609                 :            : 
     610                 :            : 
     611                 :          2 : 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                 :          2 :         const u8 *result_tlv = NULL, *crypto_tlv = NULL;
     618                 :          2 :         size_t result_tlv_len = 0, crypto_tlv_len = 0;
     619                 :            :         int tlv_type, mandatory, tlv_len;
     620                 :            : 
     621                 :          2 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
     622         [ -  + ]:          2 :         if (pos == NULL) {
     623                 :          0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
     624                 :          0 :                 return;
     625                 :            :         }
     626                 :            : 
     627                 :            :         /* Parse TLVs */
     628                 :          2 :         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
     629         [ +  + ]:          6 :         while (left >= 4) {
     630                 :          4 :                 mandatory = !!(pos[0] & 0x80);
     631                 :          4 :                 tlv_type = pos[0] & 0x3f;
     632                 :          4 :                 tlv_type = (tlv_type << 8) | pos[1];
     633                 :          4 :                 tlv_len = ((int) pos[2] << 8) | pos[3];
     634                 :          4 :                 pos += 4;
     635                 :          4 :                 left -= 4;
     636         [ -  + ]:          4 :                 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      [ +  +  - ]:          4 :                 switch (tlv_type) {
     644                 :            :                 case EAP_TLV_RESULT_TLV:
     645                 :          2 :                         result_tlv = pos;
     646                 :          2 :                         result_tlv_len = tlv_len;
     647                 :          2 :                         break;
     648                 :            :                 case EAP_TLV_CRYPTO_BINDING_TLV:
     649                 :          2 :                         crypto_tlv = pos;
     650                 :          2 :                         crypto_tlv_len = tlv_len;
     651                 :          2 :                         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                 :          4 :                 pos += tlv_len;
     665                 :          4 :                 left -= tlv_len;
     666                 :            :         }
     667         [ -  + ]:          2 :         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 [ +  - ][ +  - ]:          2 :         if (crypto_tlv && data->crypto_binding_sent) {
     676                 :          2 :                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
     677                 :            :                             crypto_tlv, crypto_tlv_len);
     678         [ -  + ]:          2 :                 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                 :          2 :                 data->crypto_binding_used = 1;
     684 [ #  # ][ #  # ]:          0 :         } else if (!crypto_tlv && data->crypto_binding_sent &&
                 [ #  # ]
     685                 :          0 :                    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         [ +  - ]:          2 :         if (result_tlv) {
     692                 :            :                 int status;
     693                 :            :                 const char *requested;
     694                 :            : 
     695                 :          2 :                 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
     696                 :            :                             result_tlv, result_tlv_len);
     697         [ -  + ]:          2 :                 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         [ +  - ]:          2 :                 requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
     705                 :            :                         "Failure";
     706                 :          2 :                 status = WPA_GET_BE16(result_tlv);
     707         [ +  - ]:          2 :                 if (status == EAP_TLV_RESULT_SUCCESS) {
     708                 :          2 :                         wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
     709                 :            :                                    "- requested %s", requested);
     710         [ +  - ]:          2 :                         if (data->tlv_request == TLV_REQ_SUCCESS)
     711                 :          2 :                                 eap_peap_state(data, SUCCESS);
     712                 :            :                         else
     713                 :          0 :                                 eap_peap_state(data, FAILURE);
     714                 :            :                         
     715         [ #  # ]:          0 :                 } else if (status == EAP_TLV_RESULT_FAILURE) {
     716                 :          0 :                         wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
     717                 :            :                                    "- requested %s", requested);
     718                 :          0 :                         eap_peap_state(data, FAILURE);
     719                 :            :                 } else {
     720                 :          0 :                         wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
     721                 :            :                                    "Status %d", status);
     722                 :          2 :                         eap_peap_state(data, FAILURE);
     723                 :            :                 }
     724                 :            :         }
     725                 :            : }
     726                 :            : 
     727                 :            : 
     728                 :            : #ifdef EAP_SERVER_TNC
     729                 :          0 : 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                 :          0 :         const u8 *soh_tlv = NULL;
     736                 :          0 :         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                 :          0 :         pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
     742         [ #  # ]:          0 :         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                 :          0 :         wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
     750         [ #  # ]:          0 :         while (left >= 4) {
     751                 :          0 :                 mandatory = !!(pos[0] & 0x80);
     752                 :          0 :                 tlv_type = pos[0] & 0x3f;
     753                 :          0 :                 tlv_type = (tlv_type << 8) | pos[1];
     754                 :          0 :                 tlv_len = ((int) pos[2] << 8) | pos[3];
     755                 :          0 :                 pos += 4;
     756                 :          0 :                 left -= 4;
     757         [ #  # ]:          0 :                 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         [ #  # ]:          0 :                 switch (tlv_type) {
     765                 :            :                 case EAP_TLV_VENDOR_SPECIFIC_TLV:
     766         [ #  # ]:          0 :                         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                 :          0 :                         vendor_id = WPA_GET_BE32(pos);
     775         [ #  # ]:          0 :                         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                 :          0 :                         vpos = pos + 4;
     784                 :          0 :                         mandatory = !!(vpos[0] & 0x80);
     785                 :          0 :                         tlv_type = vpos[0] & 0x3f;
     786                 :          0 :                         tlv_type = (tlv_type << 8) | vpos[1];
     787                 :          0 :                         vtlv_len = ((int) vpos[2] << 8) | vpos[3];
     788                 :          0 :                         vpos += 4;
     789         [ #  # ]:          0 :                         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         [ #  # ]:          0 :                         if (tlv_type == 1) {
     797                 :          0 :                                 soh_tlv = vpos;
     798                 :          0 :                                 soh_tlv_len = vtlv_len;
     799                 :          0 :                                 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                 :          0 :                 pos += tlv_len;
     824                 :          0 :                 left -= tlv_len;
     825                 :            :         }
     826         [ #  # ]:          0 :         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         [ #  # ]:          0 :         if (soh_tlv) {
     835                 :          0 :                 int failure = 0;
     836                 :          0 :                 wpabuf_free(data->soh_response);
     837                 :          0 :                 data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
     838                 :            :                                                       &failure);
     839         [ #  # ]:          0 :                 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                 :          0 :         eap_peap_state(data, PHASE2_METHOD);
     851                 :          0 :         next_type = sm->user->methods[0].method;
     852                 :          0 :         sm->user_eap_method_index = 1;
     853                 :          0 :         wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
     854                 :          0 :         eap_peap_phase2_init(sm, data, next_type);
     855                 :            : }
     856                 :            : #endif /* EAP_SERVER_TNC */
     857                 :            : 
     858                 :            : 
     859                 :         71 : static void eap_peap_process_phase2_response(struct eap_sm *sm,
     860                 :            :                                              struct eap_peap_data *data,
     861                 :            :                                              struct wpabuf *in_data)
     862                 :            : {
     863                 :         71 :         u8 next_type = EAP_TYPE_NONE;
     864                 :            :         const struct eap_hdr *hdr;
     865                 :            :         const u8 *pos;
     866                 :            :         size_t left;
     867                 :            : 
     868         [ +  + ]:         71 :         if (data->state == PHASE2_TLV) {
     869                 :          2 :                 eap_peap_process_phase2_tlv(sm, data, in_data);
     870                 :          2 :                 return;
     871                 :            :         }
     872                 :            : 
     873                 :            : #ifdef EAP_SERVER_TNC
     874         [ -  + ]:         69 :         if (data->state == PHASE2_SOH) {
     875                 :          0 :                 eap_peap_process_phase2_soh(sm, data, in_data);
     876                 :          0 :                 return;
     877                 :            :         }
     878                 :            : #endif /* EAP_SERVER_TNC */
     879                 :            : 
     880         [ -  + ]:         69 :         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                 :         69 :         hdr = wpabuf_head(in_data);
     887                 :         69 :         pos = (const u8 *) (hdr + 1);
     888                 :            : 
     889 [ +  + ][ +  - ]:         69 :         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 [ +  - ][ +  - ]:          2 :                 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                 :          4 :                                 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         [ -  + ]:         67 :         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                 :         67 :         data->phase2_method->process(sm, data->phase2_priv, in_data);
     916                 :            : 
     917         [ -  + ]:         67 :         if (sm->method_pending == METHOD_PENDING_WAIT) {
     918                 :          0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
     919                 :            :                            "pending wait state - save decrypted response");
     920                 :          0 :                 wpabuf_free(data->pending_phase2_resp);
     921                 :          0 :                 data->pending_phase2_resp = wpabuf_dup(in_data);
     922                 :            :         }
     923                 :            : 
     924         [ +  + ]:         67 :         if (!data->phase2_method->isDone(sm, data->phase2_priv))
     925                 :         25 :                 return;
     926                 :            : 
     927         [ +  + ]:         42 :         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                 :         41 :         os_free(data->phase2_key);
     936         [ +  + ]:         41 :         if (data->phase2_method->getKey) {
     937                 :         18 :                 data->phase2_key = data->phase2_method->getKey(
     938                 :            :                         sm, data->phase2_priv, &data->phase2_key_len);
     939         [ -  + ]:         18 :                 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   [ +  +  -  - ]:         41 :         switch (data->state) {
     949                 :            :         case PHASE1_ID2:
     950                 :            :         case PHASE2_ID:
     951                 :            :         case PHASE2_SOH:
     952         [ -  + ]:         21 :                 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 [ +  - ][ -  + ]:         21 :                 if (data->state != PHASE2_SOH && sm->tnc &&
                 [ #  # ]
     964                 :          0 :                     data->peap_version == 0) {
     965                 :          0 :                         eap_peap_state(data, PHASE2_SOH);
     966                 :          0 :                         wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
     967                 :            :                                    "TNC (NAP SOH)");
     968                 :          0 :                         next_type = EAP_TYPE_NONE;
     969                 :          0 :                         break;
     970                 :            :                 }
     971                 :            : #endif /* EAP_SERVER_TNC */
     972                 :            : 
     973                 :         21 :                 eap_peap_state(data, PHASE2_METHOD);
     974                 :         21 :                 next_type = sm->user->methods[0].method;
     975                 :         21 :                 sm->user_eap_method_index = 1;
     976                 :         21 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
     977                 :         21 :                 break;
     978                 :            :         case PHASE2_METHOD:
     979                 :         20 :                 eap_peap_req_success(sm, data);
     980                 :         20 :                 next_type = EAP_TYPE_NONE;
     981                 :         20 :                 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                 :         71 :         eap_peap_phase2_init(sm, data, next_type);
     991                 :            : }
     992                 :            : 
     993                 :            : 
     994                 :         71 : 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                 :         71 :         wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
    1004                 :            :                    " Phase 2", (unsigned long) wpabuf_len(in_buf));
    1005                 :            : 
    1006         [ -  + ]:         71 :         if (data->pending_phase2_resp) {
    1007                 :          0 :                 wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
    1008                 :            :                            "skip decryption and use old data");
    1009                 :          0 :                 eap_peap_process_phase2_response(sm, data,
    1010                 :            :                                                  data->pending_phase2_resp);
    1011                 :          0 :                 wpabuf_free(data->pending_phase2_resp);
    1012                 :          0 :                 data->pending_phase2_resp = NULL;
    1013                 :          0 :                 return;
    1014                 :            :         }
    1015                 :            : 
    1016                 :         71 :         in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
    1017                 :            :                                               in_buf);
    1018         [ -  + ]:         71 :         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                 :         71 :         wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
    1026                 :            :                             in_decrypted);
    1027                 :            : 
    1028 [ +  + ][ +  + ]:         71 :         if (data->peap_version == 0 && data->state != PHASE2_TLV) {
    1029                 :            :                 const struct eap_hdr *resp;
    1030                 :            :                 struct eap_hdr *nhdr;
    1031                 :          6 :                 struct wpabuf *nbuf =
    1032                 :          6 :                         wpabuf_alloc(sizeof(struct eap_hdr) +
    1033                 :          6 :                                      wpabuf_len(in_decrypted));
    1034         [ -  + ]:          6 :                 if (nbuf == NULL) {
    1035                 :          0 :                         wpabuf_free(in_decrypted);
    1036                 :          0 :                         return;
    1037                 :            :                 }
    1038                 :            : 
    1039                 :          6 :                 resp = wpabuf_head(respData);
    1040                 :          6 :                 nhdr = wpabuf_put(nbuf, sizeof(*nhdr));
    1041                 :          6 :                 nhdr->code = resp->code;
    1042                 :          6 :                 nhdr->identifier = resp->identifier;
    1043                 :          6 :                 nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
    1044                 :            :                                             wpabuf_len(in_decrypted));
    1045                 :          6 :                 wpabuf_put_buf(nbuf, in_decrypted);
    1046                 :          6 :                 wpabuf_free(in_decrypted);
    1047                 :            : 
    1048                 :          6 :                 in_decrypted = nbuf;
    1049                 :            :         }
    1050                 :            : 
    1051                 :         71 :         hdr = wpabuf_head(in_decrypted);
    1052         [ -  + ]:         71 :         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                 :         71 :         len = be_to_host16(hdr->length);
    1061         [ -  + ]:         71 :         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                 :         71 :         wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
    1071                 :        142 :                    "identifier=%d length=%lu", hdr->code, hdr->identifier,
    1072                 :            :                    (unsigned long) len);
    1073   [ +  -  -  - ]:         71 :         switch (hdr->code) {
    1074                 :            :         case EAP_CODE_RESPONSE:
    1075                 :         71 :                 eap_peap_process_phase2_response(sm, data, in_decrypted);
    1076                 :         71 :                 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                 :         71 :         wpabuf_free(in_decrypted);
    1094                 :            : }
    1095                 :            : 
    1096                 :            : 
    1097                 :        175 : static int eap_peap_process_version(struct eap_sm *sm, void *priv,
    1098                 :            :                                     int peer_version)
    1099                 :            : {
    1100                 :        175 :         struct eap_peap_data *data = priv;
    1101                 :            : 
    1102                 :        175 :         data->recv_version = peer_version;
    1103 [ -  + ][ #  # ]:        175 :         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         [ +  + ]:        175 :         if (peer_version < data->peap_version) {
    1110                 :          2 :                 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                 :          2 :                 data->peap_version = peer_version;
    1114                 :            :         }
    1115                 :            : 
    1116                 :        175 :         return 0;
    1117                 :            : }
    1118                 :            : 
    1119                 :            : 
    1120                 :        153 : static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
    1121                 :            :                                  const struct wpabuf *respData)
    1122                 :            : {
    1123                 :        153 :         struct eap_peap_data *data = priv;
    1124                 :            : 
    1125   [ +  +  +  +  :        153 :         switch (data->state) {
                   +  - ]
    1126                 :            :         case PHASE1:
    1127         [ -  + ]:         42 :                 if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
    1128                 :          0 :                         eap_peap_state(data, FAILURE);
    1129                 :          0 :                         break;
    1130                 :            :                 }
    1131                 :         42 :                 break;
    1132                 :            :         case PHASE2_START:
    1133                 :         21 :                 eap_peap_state(data, PHASE2_ID);
    1134                 :         21 :                 eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
    1135                 :         21 :                 break;
    1136                 :            :         case PHASE1_ID2:
    1137                 :            :         case PHASE2_ID:
    1138                 :            :         case PHASE2_METHOD:
    1139                 :            :         case PHASE2_SOH:
    1140                 :            :         case PHASE2_TLV:
    1141                 :         71 :                 eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in);
    1142                 :         71 :                 break;
    1143                 :            :         case SUCCESS_REQ:
    1144                 :         18 :                 eap_peap_state(data, SUCCESS);
    1145                 :         18 :                 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                 :        153 : }
    1155                 :            : 
    1156                 :            : 
    1157                 :        175 : static void eap_peap_process(struct eap_sm *sm, void *priv,
    1158                 :            :                              struct wpabuf *respData)
    1159                 :            : {
    1160                 :        175 :         struct eap_peap_data *data = priv;
    1161         [ -  + ]:        175 :         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                 :        175 : }
    1166                 :            : 
    1167                 :            : 
    1168                 :        176 : static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
    1169                 :            : {
    1170                 :        176 :         struct eap_peap_data *data = priv;
    1171 [ +  + ][ +  + ]:        176 :         return data->state == SUCCESS || data->state == FAILURE;
    1172                 :            : }
    1173                 :            : 
    1174                 :            : 
    1175                 :         21 : static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
    1176                 :            : {
    1177                 :         21 :         struct eap_peap_data *data = priv;
    1178                 :            :         u8 *eapKeyData;
    1179                 :            : 
    1180         [ +  + ]:         21 :         if (data->state != SUCCESS)
    1181                 :          1 :                 return NULL;
    1182                 :            : 
    1183         [ +  + ]:         20 :         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         [ -  + ]:          2 :                 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                 :          2 :                 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
    1195                 :          2 :                 eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
    1196         [ +  - ]:          2 :                 if (eapKeyData) {
    1197                 :          2 :                         os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
    1198                 :          2 :                         *len = EAP_TLS_KEY_LEN;
    1199                 :          2 :                         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                 :          2 :                 return eapKeyData;
    1207                 :            :         }
    1208                 :            : 
    1209                 :            :         /* TODO: PEAPv1 - different label in some cases */
    1210                 :         18 :         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
    1211                 :            :                                                "client EAP encryption",
    1212                 :            :                                                EAP_TLS_KEY_LEN);
    1213         [ +  - ]:         18 :         if (eapKeyData) {
    1214                 :         18 :                 *len = EAP_TLS_KEY_LEN;
    1215                 :         18 :                 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                 :         21 :         return eapKeyData;
    1222                 :            : }
    1223                 :            : 
    1224                 :            : 
    1225                 :         22 : static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
    1226                 :            : {
    1227                 :         22 :         struct eap_peap_data *data = priv;
    1228                 :         22 :         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.9