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 1475438200 Lines: 546 715 76.4 %
Date: 2016-10-02 Functions: 30 30 100.0 %

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

Generated by: LCOV version 1.10