LCOV - code coverage report
Current view: top level - src/eap_server - eap_server_pwd.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 472 605 78.0 %
Date: 2015-09-27 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / EAP-pwd (RFC 5931) server
       3             :  * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
       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/sha256.h"
      13             : #include "crypto/ms_funcs.h"
      14             : #include "eap_server/eap_i.h"
      15             : #include "eap_common/eap_pwd_common.h"
      16             : 
      17             : 
      18             : struct eap_pwd_data {
      19             :         enum {
      20             :                 PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
      21             :         } state;
      22             :         u8 *id_peer;
      23             :         size_t id_peer_len;
      24             :         u8 *id_server;
      25             :         size_t id_server_len;
      26             :         u8 *password;
      27             :         size_t password_len;
      28             :         int password_hash;
      29             :         u32 token;
      30             :         u16 group_num;
      31             :         EAP_PWD_group *grp;
      32             : 
      33             :         struct wpabuf *inbuf;
      34             :         size_t in_frag_pos;
      35             :         struct wpabuf *outbuf;
      36             :         size_t out_frag_pos;
      37             :         size_t mtu;
      38             : 
      39             :         BIGNUM *k;
      40             :         BIGNUM *private_value;
      41             :         BIGNUM *peer_scalar;
      42             :         BIGNUM *my_scalar;
      43             :         EC_POINT *my_element;
      44             :         EC_POINT *peer_element;
      45             : 
      46             :         u8 my_confirm[SHA256_MAC_LEN];
      47             : 
      48             :         u8 msk[EAP_MSK_LEN];
      49             :         u8 emsk[EAP_EMSK_LEN];
      50             :         u8 session_id[1 + SHA256_MAC_LEN];
      51             : 
      52             :         BN_CTX *bnctx;
      53             : };
      54             : 
      55             : 
      56          82 : static const char * eap_pwd_state_txt(int state)
      57             : {
      58          82 :         switch (state) {
      59             :         case PWD_ID_Req:
      60          14 :                 return "PWD-ID-Req";
      61             :         case PWD_Commit_Req:
      62          28 :                 return "PWD-Commit-Req";
      63             :         case PWD_Confirm_Req:
      64          27 :                 return "PWD-Confirm-Req";
      65             :         case SUCCESS:
      66          13 :                 return "SUCCESS";
      67             :         case FAILURE:
      68           0 :                 return "FAILURE";
      69             :         default:
      70           0 :                 return "PWD-Unk";
      71             :         }
      72             : }
      73             : 
      74             : 
      75          41 : static void eap_pwd_state(struct eap_pwd_data *data, int state)
      76             : {
      77          82 :         wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s",
      78          41 :                    eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
      79          41 :         data->state = state;
      80          41 : }
      81             : 
      82             : 
      83          16 : static void * eap_pwd_init(struct eap_sm *sm)
      84             : {
      85             :         struct eap_pwd_data *data;
      86             : 
      87          32 :         if (sm->user == NULL || sm->user->password == NULL ||
      88          16 :             sm->user->password_len == 0) {
      89           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not "
      90             :                            "configured");
      91           0 :                 return NULL;
      92             :         }
      93             : 
      94          16 :         data = os_zalloc(sizeof(*data));
      95          16 :         if (data == NULL)
      96           0 :                 return NULL;
      97             : 
      98          16 :         data->group_num = sm->pwd_group;
      99          16 :         wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
     100          16 :                    data->group_num);
     101          16 :         data->state = PWD_ID_Req;
     102             : 
     103          16 :         data->id_server = (u8 *) os_strdup("server");
     104          16 :         if (data->id_server)
     105          16 :                 data->id_server_len = os_strlen((char *) data->id_server);
     106             : 
     107          16 :         data->password = os_malloc(sm->user->password_len);
     108          16 :         if (data->password == NULL) {
     109           0 :                 wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
     110             :                            "fail");
     111           0 :                 bin_clear_free(data->id_server, data->id_server_len);
     112           0 :                 os_free(data);
     113           0 :                 return NULL;
     114             :         }
     115          16 :         data->password_len = sm->user->password_len;
     116          16 :         os_memcpy(data->password, sm->user->password, data->password_len);
     117          16 :         data->password_hash = sm->user->password_hash;
     118             : 
     119          16 :         data->bnctx = BN_CTX_new();
     120          16 :         if (data->bnctx == NULL) {
     121           0 :                 wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
     122           0 :                 bin_clear_free(data->password, data->password_len);
     123           0 :                 bin_clear_free(data->id_server, data->id_server_len);
     124           0 :                 os_free(data);
     125           0 :                 return NULL;
     126             :         }
     127             : 
     128          16 :         data->in_frag_pos = data->out_frag_pos = 0;
     129          16 :         data->inbuf = data->outbuf = NULL;
     130             :         /* use default MTU from RFC 5931 if not configured otherwise */
     131          16 :         data->mtu = sm->fragment_size > 0 ? sm->fragment_size : 1020;
     132             : 
     133          16 :         return data;
     134             : }
     135             : 
     136             : 
     137          16 : static void eap_pwd_reset(struct eap_sm *sm, void *priv)
     138             : {
     139          16 :         struct eap_pwd_data *data = priv;
     140             : 
     141          16 :         BN_clear_free(data->private_value);
     142          16 :         BN_clear_free(data->peer_scalar);
     143          16 :         BN_clear_free(data->my_scalar);
     144          16 :         BN_clear_free(data->k);
     145          16 :         BN_CTX_free(data->bnctx);
     146          16 :         EC_POINT_clear_free(data->my_element);
     147          16 :         EC_POINT_clear_free(data->peer_element);
     148          16 :         bin_clear_free(data->id_peer, data->id_peer_len);
     149          16 :         bin_clear_free(data->id_server, data->id_server_len);
     150          16 :         bin_clear_free(data->password, data->password_len);
     151          16 :         if (data->grp) {
     152          14 :                 EC_GROUP_free(data->grp->group);
     153          14 :                 EC_POINT_clear_free(data->grp->pwe);
     154          14 :                 BN_clear_free(data->grp->order);
     155          14 :                 BN_clear_free(data->grp->prime);
     156          14 :                 os_free(data->grp);
     157             :         }
     158          16 :         wpabuf_free(data->inbuf);
     159          16 :         wpabuf_free(data->outbuf);
     160          16 :         bin_clear_free(data, sizeof(*data));
     161          16 : }
     162             : 
     163             : 
     164          16 : static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
     165             :                                  u8 id)
     166             : {
     167          16 :         wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
     168             :         /*
     169             :          * if we're fragmenting then we already have an id request, just return
     170             :          */
     171          16 :         if (data->out_frag_pos)
     172           0 :                 return;
     173             : 
     174          16 :         data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
     175          16 :                                     data->id_server_len);
     176          16 :         if (data->outbuf == NULL) {
     177           0 :                 eap_pwd_state(data, FAILURE);
     178           0 :                 return;
     179             :         }
     180             : 
     181             :         /* an lfsr is good enough to generate unpredictable tokens */
     182          16 :         data->token = os_random();
     183          16 :         wpabuf_put_be16(data->outbuf, data->group_num);
     184          16 :         wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
     185          16 :         wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
     186          16 :         wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
     187          16 :         wpabuf_put_u8(data->outbuf, data->password_hash ? EAP_PWD_PREP_MS :
     188             :                       EAP_PWD_PREP_NONE);
     189          16 :         wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
     190             : }
     191             : 
     192             : 
     193          16 : static void eap_pwd_build_commit_req(struct eap_sm *sm,
     194             :                                      struct eap_pwd_data *data, u8 id)
     195             : {
     196          16 :         BIGNUM *mask = NULL, *x = NULL, *y = NULL;
     197          16 :         u8 *scalar = NULL, *element = NULL;
     198             :         u16 offset;
     199             : 
     200          16 :         wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
     201             :         /*
     202             :          * if we're fragmenting then we already have an commit request, just
     203             :          * return
     204             :          */
     205          16 :         if (data->out_frag_pos)
     206          18 :                 return;
     207             : 
     208          28 :         if (((data->private_value = BN_new()) == NULL) ||
     209          28 :             ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
     210          28 :             ((data->my_scalar = BN_new()) == NULL) ||
     211             :             ((mask = BN_new()) == NULL)) {
     212           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
     213             :                            "fail");
     214           0 :                 goto fin;
     215             :         }
     216             : 
     217          28 :         if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
     218          28 :             BN_rand_range(mask, data->grp->order) != 1 ||
     219          28 :             BN_add(data->my_scalar, data->private_value, mask) != 1 ||
     220          14 :             BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
     221             :                    data->bnctx) != 1) {
     222           0 :                 wpa_printf(MSG_INFO,
     223             :                            "EAP-pwd (server): unable to get randomness");
     224           0 :                 goto fin;
     225             :         }
     226             : 
     227          28 :         if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
     228          14 :                           data->grp->pwe, mask, data->bnctx)) {
     229           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
     230             :                            "fail");
     231           0 :                 eap_pwd_state(data, FAILURE);
     232           0 :                 goto fin;
     233             :         }
     234             : 
     235          14 :         if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
     236             :         {
     237           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
     238             :                            "fail");
     239           0 :                 goto fin;
     240             :         }
     241          14 :         BN_clear_free(mask);
     242             : 
     243          14 :         if (((x = BN_new()) == NULL) ||
     244             :             ((y = BN_new()) == NULL)) {
     245           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation "
     246             :                            "fail");
     247           0 :                 goto fin;
     248             :         }
     249          28 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
     250          14 :                                                  data->my_element, x, y,
     251             :                                                  data->bnctx)) {
     252           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
     253             :                            "fail");
     254           0 :                 goto fin;
     255             :         }
     256             : 
     257          28 :         if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
     258          14 :             ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
     259             :              NULL)) {
     260           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
     261           0 :                 goto fin;
     262             :         }
     263             : 
     264             :         /*
     265             :          * bignums occupy as little memory as possible so one that is
     266             :          * sufficiently smaller than the prime or order might need pre-pending
     267             :          * with zeros.
     268             :          */
     269          14 :         os_memset(scalar, 0, BN_num_bytes(data->grp->order));
     270          14 :         os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
     271          28 :         offset = BN_num_bytes(data->grp->order) -
     272          14 :                 BN_num_bytes(data->my_scalar);
     273          14 :         BN_bn2bin(data->my_scalar, scalar + offset);
     274             : 
     275          14 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
     276          14 :         BN_bn2bin(x, element + offset);
     277          14 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
     278          14 :         BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
     279             : 
     280          28 :         data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) +
     281          14 :                                     BN_num_bytes(data->grp->order));
     282          14 :         if (data->outbuf == NULL)
     283           0 :                 goto fin;
     284             : 
     285             :         /* We send the element as (x,y) followed by the scalar */
     286          14 :         wpabuf_put_data(data->outbuf, element,
     287          14 :                         2 * BN_num_bytes(data->grp->prime));
     288          14 :         wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
     289             : 
     290             : fin:
     291          14 :         os_free(scalar);
     292          14 :         os_free(element);
     293          14 :         BN_clear_free(x);
     294          14 :         BN_clear_free(y);
     295          14 :         if (data->outbuf == NULL)
     296           0 :                 eap_pwd_state(data, FAILURE);
     297             : }
     298             : 
     299             : 
     300          14 : static void eap_pwd_build_confirm_req(struct eap_sm *sm,
     301             :                                       struct eap_pwd_data *data, u8 id)
     302             : {
     303          14 :         BIGNUM *x = NULL, *y = NULL;
     304             :         struct crypto_hash *hash;
     305          14 :         u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
     306             :         u16 grp;
     307             :         int offset;
     308             : 
     309          14 :         wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
     310             :         /*
     311             :          * if we're fragmenting then we already have an confirm request, just
     312             :          * return
     313             :          */
     314          14 :         if (data->out_frag_pos)
     315          14 :                 return;
     316             : 
     317             :         /* Each component of the cruft will be at most as big as the prime */
     318          14 :         if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
     319          14 :             ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
     320           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
     321             :                            "fail");
     322           0 :                 goto fin;
     323             :         }
     324             : 
     325             :         /*
     326             :          * commit is H(k | server_element | server_scalar | peer_element |
     327             :          *             peer_scalar | ciphersuite)
     328             :          */
     329          14 :         hash = eap_pwd_h_init();
     330          14 :         if (hash == NULL)
     331           0 :                 goto fin;
     332             : 
     333             :         /*
     334             :          * Zero the memory each time because this is mod prime math and some
     335             :          * value may start with a few zeros and the previous one did not.
     336             :          *
     337             :          * First is k
     338             :          */
     339          14 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     340          14 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
     341          14 :         BN_bn2bin(data->k, cruft + offset);
     342          14 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     343             : 
     344             :         /* server element: x, y */
     345          28 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
     346          14 :                                                  data->my_element, x, y,
     347             :                                                  data->bnctx)) {
     348           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
     349             :                            "assignment fail");
     350           0 :                 goto fin;
     351             :         }
     352             : 
     353          14 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     354          14 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
     355          14 :         BN_bn2bin(x, cruft + offset);
     356          14 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     357          14 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     358          14 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
     359          14 :         BN_bn2bin(y, cruft + offset);
     360          14 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     361             : 
     362             :         /* server scalar */
     363          14 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     364          28 :         offset = BN_num_bytes(data->grp->order) -
     365          14 :                 BN_num_bytes(data->my_scalar);
     366          14 :         BN_bn2bin(data->my_scalar, cruft + offset);
     367          14 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
     368             : 
     369             :         /* peer element: x, y */
     370          28 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
     371          14 :                                                  data->peer_element, x, y,
     372             :                                                  data->bnctx)) {
     373           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
     374             :                            "assignment fail");
     375           0 :                 goto fin;
     376             :         }
     377             : 
     378          14 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     379          14 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
     380          14 :         BN_bn2bin(x, cruft + offset);
     381          14 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     382          14 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     383          14 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
     384          14 :         BN_bn2bin(y, cruft + offset);
     385          14 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     386             : 
     387             :         /* peer scalar */
     388          14 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     389          28 :         offset = BN_num_bytes(data->grp->order) -
     390          14 :                 BN_num_bytes(data->peer_scalar);
     391          14 :         BN_bn2bin(data->peer_scalar, cruft + offset);
     392          14 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
     393             : 
     394             :         /* ciphersuite */
     395          14 :         grp = htons(data->group_num);
     396          14 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     397          14 :         ptr = cruft;
     398          14 :         os_memcpy(ptr, &grp, sizeof(u16));
     399          14 :         ptr += sizeof(u16);
     400          14 :         *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
     401          14 :         ptr += sizeof(u8);
     402          14 :         *ptr = EAP_PWD_DEFAULT_PRF;
     403          14 :         ptr += sizeof(u8);
     404          14 :         eap_pwd_h_update(hash, cruft, ptr - cruft);
     405             : 
     406             :         /* all done with the random function */
     407          14 :         eap_pwd_h_final(hash, conf);
     408          14 :         os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
     409             : 
     410          14 :         data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
     411          14 :         if (data->outbuf == NULL)
     412           0 :                 goto fin;
     413             : 
     414          14 :         wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
     415             : 
     416             : fin:
     417          14 :         bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
     418          14 :         BN_clear_free(x);
     419          14 :         BN_clear_free(y);
     420          14 :         if (data->outbuf == NULL)
     421           0 :                 eap_pwd_state(data, FAILURE);
     422             : }
     423             : 
     424             : 
     425             : static struct wpabuf *
     426          56 : eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
     427             : {
     428          56 :         struct eap_pwd_data *data = priv;
     429             :         struct wpabuf *req;
     430             :         u8 lm_exch;
     431             :         const u8 *buf;
     432          56 :         u16 totlen = 0;
     433             :         size_t len;
     434             : 
     435             :         /*
     436             :          * if we're buffering response fragments then just ACK
     437             :          */
     438          56 :         if (data->in_frag_pos) {
     439          10 :                 wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a fragment!!");
     440          10 :                 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
     441             :                                     EAP_PWD_HDR_SIZE, EAP_CODE_REQUEST, id);
     442          10 :                 if (req == NULL) {
     443           0 :                         eap_pwd_state(data, FAILURE);
     444           0 :                         return NULL;
     445             :                 }
     446          10 :                 switch (data->state) {
     447             :                 case PWD_ID_Req:
     448           5 :                         wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH);
     449           5 :                         break;
     450             :                 case PWD_Commit_Req:
     451           4 :                         wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH);
     452           4 :                         break;
     453             :                 case PWD_Confirm_Req:
     454           1 :                         wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH);
     455           1 :                         break;
     456             :                 default:
     457           0 :                         eap_pwd_state(data, FAILURE);   /* just to be sure */
     458           0 :                         wpabuf_free(req);
     459           0 :                         return NULL;
     460             :                 }
     461          10 :                 return req;
     462             :         }
     463             : 
     464             :         /*
     465             :          * build the data portion of a request
     466             :          */
     467          46 :         switch (data->state) {
     468             :         case PWD_ID_Req:
     469          16 :                 eap_pwd_build_id_req(sm, data, id);
     470          16 :                 lm_exch = EAP_PWD_OPCODE_ID_EXCH;
     471          16 :                 break;
     472             :         case PWD_Commit_Req:
     473          16 :                 eap_pwd_build_commit_req(sm, data, id);
     474          16 :                 lm_exch = EAP_PWD_OPCODE_COMMIT_EXCH;
     475          16 :                 break;
     476             :         case PWD_Confirm_Req:
     477          14 :                 eap_pwd_build_confirm_req(sm, data, id);
     478          14 :                 lm_exch = EAP_PWD_OPCODE_CONFIRM_EXCH;
     479          14 :                 break;
     480             :         default:
     481           0 :                 wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req",
     482           0 :                            data->state);
     483           0 :                 eap_pwd_state(data, FAILURE);
     484           0 :                 lm_exch = 0;    /* hush now, sweet compiler */
     485           0 :                 break;
     486             :         }
     487             : 
     488          46 :         if (data->state == FAILURE)
     489           0 :                 return NULL;
     490             : 
     491             :         /*
     492             :          * determine whether that data needs to be fragmented
     493             :          */
     494          46 :         len = wpabuf_len(data->outbuf) - data->out_frag_pos;
     495          46 :         if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
     496           2 :                 len = data->mtu - EAP_PWD_HDR_SIZE;
     497           2 :                 EAP_PWD_SET_MORE_BIT(lm_exch);
     498             :                 /*
     499             :                  * if this is the first fragment, need to set the M bit
     500             :                  * and add the total length to the eap_pwd_hdr
     501             :                  */
     502           2 :                 if (data->out_frag_pos == 0) {
     503           1 :                         EAP_PWD_SET_LENGTH_BIT(lm_exch);
     504           1 :                         totlen = wpabuf_len(data->outbuf) +
     505             :                                 EAP_PWD_HDR_SIZE + sizeof(u16);
     506           1 :                         len -= sizeof(u16);
     507           1 :                         wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, "
     508             :                                    "total length = %d", totlen);
     509             :                 }
     510           2 :                 wpa_printf(MSG_DEBUG, "EAP-pwd: Send a %d byte fragment",
     511             :                            (int) len);
     512             :         }
     513             : 
     514             :         /*
     515             :          * alloc an eap request and populate it with the data
     516             :          */
     517          92 :         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
     518          46 :                             EAP_PWD_HDR_SIZE + len +
     519          46 :                             (totlen ? sizeof(u16) : 0),
     520             :                             EAP_CODE_REQUEST, id);
     521          46 :         if (req == NULL) {
     522           0 :                 eap_pwd_state(data, FAILURE);
     523           0 :                 return NULL;
     524             :         }
     525             : 
     526          46 :         wpabuf_put_u8(req, lm_exch);
     527          46 :         if (EAP_PWD_GET_LENGTH_BIT(lm_exch))
     528           1 :                 wpabuf_put_be16(req, totlen);
     529             : 
     530          46 :         buf = wpabuf_head_u8(data->outbuf);
     531          46 :         wpabuf_put_data(req, buf + data->out_frag_pos, len);
     532          46 :         data->out_frag_pos += len;
     533             :         /*
     534             :          * either not fragged or last fragment, either way free up the data
     535             :          */
     536          46 :         if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
     537          44 :                 wpabuf_free(data->outbuf);
     538          44 :                 data->outbuf = NULL;
     539          44 :                 data->out_frag_pos = 0;
     540             :         }
     541             : 
     542          46 :         return req;
     543             : }
     544             : 
     545             : 
     546          53 : static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
     547             :                              struct wpabuf *respData)
     548             : {
     549          53 :         struct eap_pwd_data *data = priv;
     550             :         const u8 *pos;
     551             :         size_t len;
     552             : 
     553          53 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
     554          53 :         if (pos == NULL || len < 1) {
     555           0 :                 wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
     556           0 :                 return TRUE;
     557             :         }
     558             : 
     559         106 :         wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: exch = %d, len = %d",
     560          53 :                    EAP_PWD_GET_EXCHANGE(*pos), (int) len);
     561             : 
     562          72 :         if (data->state == PWD_ID_Req &&
     563          19 :             ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH))
     564          19 :                 return FALSE;
     565             : 
     566          54 :         if (data->state == PWD_Commit_Req &&
     567          20 :             ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH))
     568          20 :                 return FALSE;
     569             : 
     570          28 :         if (data->state == PWD_Confirm_Req &&
     571          14 :             ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH))
     572          14 :                 return FALSE;
     573             : 
     574           0 :         wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
     575           0 :                    *pos, data->state);
     576             : 
     577           0 :         return TRUE;
     578             : }
     579             : 
     580             : 
     581          14 : static void eap_pwd_process_id_resp(struct eap_sm *sm,
     582             :                                     struct eap_pwd_data *data,
     583             :                                     const u8 *payload, size_t payload_len)
     584             : {
     585             :         struct eap_pwd_id *id;
     586             :         const u8 *password;
     587             :         size_t password_len;
     588             :         u8 pwhashhash[16];
     589             :         int res;
     590             : 
     591          14 :         if (payload_len < sizeof(struct eap_pwd_id)) {
     592           0 :                 wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
     593           0 :                 return;
     594             :         }
     595             : 
     596          14 :         id = (struct eap_pwd_id *) payload;
     597          28 :         if ((data->group_num != be_to_host16(id->group_num)) ||
     598          28 :             (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
     599          28 :             (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
     600          14 :             (id->prf != EAP_PWD_DEFAULT_PRF)) {
     601           0 :                 wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
     602           0 :                 eap_pwd_state(data, FAILURE);
     603           0 :                 return;
     604             :         }
     605          14 :         data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
     606          14 :         if (data->id_peer == NULL) {
     607           0 :                 wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
     608           0 :                 return;
     609             :         }
     610          14 :         data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
     611          14 :         os_memcpy(data->id_peer, id->identity, data->id_peer_len);
     612          28 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
     613          14 :                           data->id_peer, data->id_peer_len);
     614             : 
     615          14 :         data->grp = os_zalloc(sizeof(EAP_PWD_group));
     616          14 :         if (data->grp == NULL) {
     617           0 :                 wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
     618             :                            "group");
     619           0 :                 return;
     620             :         }
     621             : 
     622          14 :         if (data->password_hash) {
     623           2 :                 res = hash_nt_password_hash(data->password, pwhashhash);
     624           2 :                 if (res)
     625           0 :                         return;
     626           2 :                 password = pwhashhash;
     627           2 :                 password_len = sizeof(pwhashhash);
     628             :         } else {
     629          12 :                 password = data->password;
     630          12 :                 password_len = data->password_len;
     631             :         }
     632             : 
     633          42 :         res = compute_password_element(data->grp, data->group_num,
     634             :                                        password, password_len,
     635          14 :                                        data->id_server, data->id_server_len,
     636          14 :                                        data->id_peer, data->id_peer_len,
     637          14 :                                        (u8 *) &data->token);
     638          14 :         os_memset(pwhashhash, 0, sizeof(pwhashhash));
     639          14 :         if (res) {
     640           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
     641             :                            "PWE");
     642           0 :                 return;
     643             :         }
     644          14 :         wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
     645          14 :                    BN_num_bits(data->grp->prime));
     646             : 
     647          14 :         eap_pwd_state(data, PWD_Commit_Req);
     648             : }
     649             : 
     650             : 
     651             : static void
     652          14 : eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
     653             :                             const u8 *payload, size_t payload_len)
     654             : {
     655             :         u8 *ptr;
     656          14 :         BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
     657          14 :         EC_POINT *K = NULL, *point = NULL;
     658          14 :         int res = 0;
     659             :         size_t prime_len, order_len;
     660             : 
     661          14 :         wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
     662             : 
     663          14 :         prime_len = BN_num_bytes(data->grp->prime);
     664          14 :         order_len = BN_num_bytes(data->grp->order);
     665             : 
     666          14 :         if (payload_len != 2 * prime_len + order_len) {
     667           0 :                 wpa_printf(MSG_INFO,
     668             :                            "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
     669             :                            (unsigned int) payload_len,
     670             :                            (unsigned int) (2 * prime_len + order_len));
     671           0 :                 goto fin;
     672             :         }
     673             : 
     674          28 :         if (((data->peer_scalar = BN_new()) == NULL) ||
     675          28 :             ((data->k = BN_new()) == NULL) ||
     676          14 :             ((cofactor = BN_new()) == NULL) ||
     677          14 :             ((x = BN_new()) == NULL) ||
     678          14 :             ((y = BN_new()) == NULL) ||
     679          28 :             ((point = EC_POINT_new(data->grp->group)) == NULL) ||
     680          28 :             ((K = EC_POINT_new(data->grp->group)) == NULL) ||
     681          14 :             ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
     682           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
     683             :                            "fail");
     684           0 :                 goto fin;
     685             :         }
     686             : 
     687          14 :         if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
     688           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
     689             :                            "cofactor for curve");
     690           0 :                 goto fin;
     691             :         }
     692             : 
     693             :         /* element, x then y, followed by scalar */
     694          14 :         ptr = (u8 *) payload;
     695          14 :         BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
     696          14 :         ptr += BN_num_bytes(data->grp->prime);
     697          14 :         BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
     698          14 :         ptr += BN_num_bytes(data->grp->prime);
     699          14 :         BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
     700          14 :         if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
     701             :                                                  data->peer_element, x, y,
     702             :                                                  data->bnctx)) {
     703           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
     704             :                            "fail");
     705           0 :                 goto fin;
     706             :         }
     707             : 
     708             :         /* check to ensure peer's element is not in a small sub-group */
     709          14 :         if (BN_cmp(cofactor, BN_value_one())) {
     710           0 :                 if (!EC_POINT_mul(data->grp->group, point, NULL,
     711           0 :                                   data->peer_element, cofactor, NULL)) {
     712           0 :                         wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
     713             :                                    "multiply peer element by order");
     714           0 :                         goto fin;
     715             :                 }
     716           0 :                 if (EC_POINT_is_at_infinity(data->grp->group, point)) {
     717           0 :                         wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
     718             :                                    "is at infinity!\n");
     719           0 :                         goto fin;
     720             :                 }
     721             :         }
     722             : 
     723             :         /* compute the shared key, k */
     724          28 :         if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
     725          28 :                            data->peer_scalar, data->bnctx)) ||
     726          14 :             (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
     727          14 :                            data->bnctx)) ||
     728          14 :             (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
     729             :                            data->bnctx))) {
     730           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
     731             :                            "fail");
     732           0 :                 goto fin;
     733             :         }
     734             : 
     735             :         /* ensure that the shared key isn't in a small sub-group */
     736          14 :         if (BN_cmp(cofactor, BN_value_one())) {
     737           0 :                 if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
     738             :                                   NULL)) {
     739           0 :                         wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
     740             :                                    "multiply shared key point by order!\n");
     741           0 :                         goto fin;
     742             :                 }
     743             :         }
     744             : 
     745             :         /*
     746             :          * This check is strictly speaking just for the case above where
     747             :          * co-factor > 1 but it was suggested that even though this is probably
     748             :          * never going to happen it is a simple and safe check "just to be
     749             :          * sure" so let's be safe.
     750             :          */
     751          14 :         if (EC_POINT_is_at_infinity(data->grp->group, K)) {
     752           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
     753             :                            "at infinity");
     754           0 :                 goto fin;
     755             :         }
     756          14 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
     757             :                                                  NULL, data->bnctx)) {
     758           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
     759             :                            "shared secret from secret point");
     760           0 :                 goto fin;
     761             :         }
     762          14 :         res = 1;
     763             : 
     764             : fin:
     765          14 :         EC_POINT_clear_free(K);
     766          14 :         EC_POINT_clear_free(point);
     767          14 :         BN_clear_free(cofactor);
     768          14 :         BN_clear_free(x);
     769          14 :         BN_clear_free(y);
     770             : 
     771          14 :         if (res)
     772          14 :                 eap_pwd_state(data, PWD_Confirm_Req);
     773             :         else
     774           0 :                 eap_pwd_state(data, FAILURE);
     775          14 : }
     776             : 
     777             : 
     778             : static void
     779          13 : eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
     780             :                              const u8 *payload, size_t payload_len)
     781             : {
     782          13 :         BIGNUM *x = NULL, *y = NULL;
     783             :         struct crypto_hash *hash;
     784             :         u32 cs;
     785             :         u16 grp;
     786          13 :         u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
     787             :         int offset;
     788             : 
     789          13 :         if (payload_len != SHA256_MAC_LEN) {
     790           0 :                 wpa_printf(MSG_INFO,
     791             :                            "EAP-pwd: Unexpected Confirm payload length %u (expected %u)",
     792             :                            (unsigned int) payload_len, SHA256_MAC_LEN);
     793           0 :                 goto fin;
     794             :         }
     795             : 
     796             :         /* build up the ciphersuite: group | random_function | prf */
     797          13 :         grp = htons(data->group_num);
     798          13 :         ptr = (u8 *) &cs;
     799          13 :         os_memcpy(ptr, &grp, sizeof(u16));
     800          13 :         ptr += sizeof(u16);
     801          13 :         *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
     802          13 :         ptr += sizeof(u8);
     803          13 :         *ptr = EAP_PWD_DEFAULT_PRF;
     804             : 
     805             :         /* each component of the cruft will be at most as big as the prime */
     806          13 :         if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
     807          13 :             ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
     808           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
     809           0 :                 goto fin;
     810             :         }
     811             : 
     812             :         /*
     813             :          * commit is H(k | peer_element | peer_scalar | server_element |
     814             :          *             server_scalar | ciphersuite)
     815             :          */
     816          13 :         hash = eap_pwd_h_init();
     817          13 :         if (hash == NULL)
     818           0 :                 goto fin;
     819             : 
     820             :         /* k */
     821          13 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     822          13 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
     823          13 :         BN_bn2bin(data->k, cruft + offset);
     824          13 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     825             : 
     826             :         /* peer element: x, y */
     827          26 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
     828          13 :                                                  data->peer_element, x, y,
     829             :                                                  data->bnctx)) {
     830           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
     831             :                            "assignment fail");
     832           0 :                 goto fin;
     833             :         }
     834          13 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     835          13 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
     836          13 :         BN_bn2bin(x, cruft + offset);
     837          13 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     838          13 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     839          13 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
     840          13 :         BN_bn2bin(y, cruft + offset);
     841          13 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     842             : 
     843             :         /* peer scalar */
     844          13 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     845          26 :         offset = BN_num_bytes(data->grp->order) -
     846          13 :                 BN_num_bytes(data->peer_scalar);
     847          13 :         BN_bn2bin(data->peer_scalar, cruft + offset);
     848          13 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
     849             : 
     850             :         /* server element: x, y */
     851          26 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
     852          13 :                                                  data->my_element, x, y,
     853             :                                                  data->bnctx)) {
     854           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
     855             :                            "assignment fail");
     856           0 :                 goto fin;
     857             :         }
     858             : 
     859          13 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     860          13 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
     861          13 :         BN_bn2bin(x, cruft + offset);
     862          13 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     863          13 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     864          13 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
     865          13 :         BN_bn2bin(y, cruft + offset);
     866          13 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     867             : 
     868             :         /* server scalar */
     869          13 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     870          26 :         offset = BN_num_bytes(data->grp->order) -
     871          13 :                 BN_num_bytes(data->my_scalar);
     872          13 :         BN_bn2bin(data->my_scalar, cruft + offset);
     873          13 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
     874             : 
     875             :         /* ciphersuite */
     876          13 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     877          13 :         eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
     878             : 
     879             :         /* all done */
     880          13 :         eap_pwd_h_final(hash, conf);
     881             : 
     882          13 :         ptr = (u8 *) payload;
     883          13 :         if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
     884           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
     885             :                            "verify");
     886           0 :                 goto fin;
     887             :         }
     888             : 
     889          13 :         wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
     890          13 :         if (compute_keys(data->grp, data->bnctx, data->k,
     891          13 :                          data->peer_scalar, data->my_scalar, conf,
     892          13 :                          data->my_confirm, &cs, data->msk, data->emsk,
     893          13 :                          data->session_id) < 0)
     894           0 :                 eap_pwd_state(data, FAILURE);
     895             :         else
     896          13 :                 eap_pwd_state(data, SUCCESS);
     897             : 
     898             : fin:
     899          13 :         bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
     900          13 :         BN_clear_free(x);
     901          13 :         BN_clear_free(y);
     902          13 : }
     903             : 
     904             : 
     905          53 : static void eap_pwd_process(struct eap_sm *sm, void *priv,
     906             :                             struct wpabuf *respData)
     907             : {
     908          53 :         struct eap_pwd_data *data = priv;
     909             :         const u8 *pos;
     910             :         size_t len;
     911             :         u8 lm_exch;
     912             :         u16 tot_len;
     913             : 
     914          53 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
     915          53 :         if ((pos == NULL) || (len < 1)) {
     916           0 :                 wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d",
     917             :                            (pos == NULL) ? "is NULL" : "is not NULL",
     918             :                            (int) len);
     919           0 :                 return;
     920             :         }
     921             : 
     922          53 :         lm_exch = *pos;
     923          53 :         pos++;            /* skip over the bits and the exch */
     924          53 :         len--;
     925             : 
     926             :         /*
     927             :          * if we're fragmenting then this should be an ACK with no data,
     928             :          * just return and continue fragmenting in the "build" section above
     929             :          */
     930          53 :         if (data->out_frag_pos) {
     931           2 :                 if (len > 1)
     932           0 :                         wpa_printf(MSG_INFO, "EAP-pwd: Bad response! "
     933             :                                    "Fragmenting but not an ACK");
     934             :                 else
     935           2 :                         wpa_printf(MSG_DEBUG, "EAP-pwd: received ACK from "
     936             :                                    "peer");
     937           2 :                 return;
     938             :         }
     939             :         /*
     940             :          * if we're receiving fragmented packets then we need to buffer...
     941             :          *
     942             :          * the first fragment has a total length
     943             :          */
     944          51 :         if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
     945           5 :                 if (len < 2) {
     946           0 :                         wpa_printf(MSG_DEBUG,
     947             :                                    "EAP-pwd: Frame too short to contain Total-Length field");
     948           0 :                         return;
     949             :                 }
     950           5 :                 tot_len = WPA_GET_BE16(pos);
     951           5 :                 wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total "
     952             :                            "length = %d", tot_len);
     953           5 :                 if (tot_len > 15000)
     954           0 :                         return;
     955           5 :                 if (data->inbuf) {
     956           0 :                         wpa_printf(MSG_DEBUG,
     957             :                                    "EAP-pwd: Unexpected new fragment start when previous fragment is still in use");
     958           0 :                         return;
     959             :                 }
     960           5 :                 data->inbuf = wpabuf_alloc(tot_len);
     961           5 :                 if (data->inbuf == NULL) {
     962           0 :                         wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to "
     963             :                                    "buffer fragments!");
     964           0 :                         return;
     965             :                 }
     966           5 :                 data->in_frag_pos = 0;
     967           5 :                 pos += sizeof(u16);
     968           5 :                 len -= sizeof(u16);
     969             :         }
     970             :         /*
     971             :          * the first and all intermediate fragments have the M bit set
     972             :          */
     973          51 :         if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
     974          10 :                 if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) {
     975           0 :                         wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow "
     976             :                                    "attack detected! (%d+%d > %d)",
     977           0 :                                    (int) data->in_frag_pos, (int) len,
     978           0 :                                    (int) wpabuf_size(data->inbuf));
     979           0 :                         eap_pwd_state(data, FAILURE);
     980           0 :                         return;
     981             :                 }
     982          10 :                 wpabuf_put_data(data->inbuf, pos, len);
     983          10 :                 data->in_frag_pos += len;
     984          10 :                 wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment",
     985             :                            (int) len);
     986          10 :                 return;
     987             :         }
     988             :         /*
     989             :          * last fragment won't have the M bit set (but we're obviously
     990             :          * buffering fragments so that's how we know it's the last)
     991             :          */
     992          41 :         if (data->in_frag_pos) {
     993           5 :                 wpabuf_put_data(data->inbuf, pos, len);
     994           5 :                 data->in_frag_pos += len;
     995           5 :                 pos = wpabuf_head_u8(data->inbuf);
     996           5 :                 len = data->in_frag_pos;
     997           5 :                 wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
     998             :                            (int) len);
     999             :         }
    1000          41 :         switch (EAP_PWD_GET_EXCHANGE(lm_exch)) {
    1001             :         case EAP_PWD_OPCODE_ID_EXCH:
    1002          14 :                 eap_pwd_process_id_resp(sm, data, pos, len);
    1003          14 :                 break;
    1004             :         case EAP_PWD_OPCODE_COMMIT_EXCH:
    1005          14 :                 eap_pwd_process_commit_resp(sm, data, pos, len);
    1006          14 :                 break;
    1007             :         case EAP_PWD_OPCODE_CONFIRM_EXCH:
    1008          13 :                 eap_pwd_process_confirm_resp(sm, data, pos, len);
    1009          13 :                 break;
    1010             :         }
    1011             :         /*
    1012             :          * if we had been buffering fragments, here's a great place
    1013             :          * to clean up
    1014             :          */
    1015          41 :         if (data->in_frag_pos) {
    1016           5 :                 wpabuf_free(data->inbuf);
    1017           5 :                 data->inbuf = NULL;
    1018           5 :                 data->in_frag_pos = 0;
    1019             :         }
    1020             : }
    1021             : 
    1022             : 
    1023          13 : static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
    1024             : {
    1025          13 :         struct eap_pwd_data *data = priv;
    1026             :         u8 *key;
    1027             : 
    1028          13 :         if (data->state != SUCCESS)
    1029           0 :                 return NULL;
    1030             : 
    1031          13 :         key = os_malloc(EAP_MSK_LEN);
    1032          13 :         if (key == NULL)
    1033           0 :                 return NULL;
    1034             : 
    1035          13 :         os_memcpy(key, data->msk, EAP_MSK_LEN);
    1036          13 :         *len = EAP_MSK_LEN;
    1037             : 
    1038          13 :         return key;
    1039             : }
    1040             : 
    1041             : 
    1042           1 : static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
    1043             : {
    1044           1 :         struct eap_pwd_data *data = priv;
    1045             :         u8 *key;
    1046             : 
    1047           1 :         if (data->state != SUCCESS)
    1048           0 :                 return NULL;
    1049             : 
    1050           1 :         key = os_malloc(EAP_EMSK_LEN);
    1051           1 :         if (key == NULL)
    1052           0 :                 return NULL;
    1053             : 
    1054           1 :         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
    1055           1 :         *len = EAP_EMSK_LEN;
    1056             : 
    1057           1 :         return key;
    1058             : }
    1059             : 
    1060             : 
    1061          13 : static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
    1062             : {
    1063          13 :         struct eap_pwd_data *data = priv;
    1064          13 :         return data->state == SUCCESS;
    1065             : }
    1066             : 
    1067             : 
    1068          53 : static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
    1069             : {
    1070          53 :         struct eap_pwd_data *data = priv;
    1071          53 :         return (data->state == SUCCESS) || (data->state == FAILURE);
    1072             : }
    1073             : 
    1074             : 
    1075          13 : static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
    1076             : {
    1077          13 :         struct eap_pwd_data *data = priv;
    1078             :         u8 *id;
    1079             : 
    1080          13 :         if (data->state != SUCCESS)
    1081           0 :                 return NULL;
    1082             : 
    1083          13 :         id = os_malloc(1 + SHA256_MAC_LEN);
    1084          13 :         if (id == NULL)
    1085           0 :                 return NULL;
    1086             : 
    1087          13 :         os_memcpy(id, data->session_id, 1 + SHA256_MAC_LEN);
    1088          13 :         *len = 1 + SHA256_MAC_LEN;
    1089             : 
    1090          13 :         return id;
    1091             : }
    1092             : 
    1093             : 
    1094          25 : int eap_server_pwd_register(void)
    1095             : {
    1096             :         struct eap_method *eap;
    1097             :         int ret;
    1098             :         struct timeval tp;
    1099             :         struct timezone tz;
    1100             :         u32 sr;
    1101             : 
    1102          25 :         sr = 0xdeaddada;
    1103          25 :         (void) gettimeofday(&tp, &tz);
    1104          25 :         sr ^= (tp.tv_sec ^ tp.tv_usec);
    1105          25 :         srandom(sr);
    1106             : 
    1107          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    1108             :                                       EAP_VENDOR_IETF, EAP_TYPE_PWD,
    1109             :                                       "PWD");
    1110          25 :         if (eap == NULL)
    1111           0 :                 return -1;
    1112             : 
    1113          25 :         eap->init = eap_pwd_init;
    1114          25 :         eap->reset = eap_pwd_reset;
    1115          25 :         eap->buildReq = eap_pwd_build_req;
    1116          25 :         eap->check = eap_pwd_check;
    1117          25 :         eap->process = eap_pwd_process;
    1118          25 :         eap->isDone = eap_pwd_is_done;
    1119          25 :         eap->getKey = eap_pwd_getkey;
    1120          25 :         eap->get_emsk = eap_pwd_get_emsk;
    1121          25 :         eap->isSuccess = eap_pwd_is_success;
    1122          25 :         eap->getSessionId = eap_pwd_get_session_id;
    1123             : 
    1124          25 :         ret = eap_server_method_register(eap);
    1125          25 :         if (ret)
    1126           0 :                 eap_server_method_free(eap);
    1127          25 :         return ret;
    1128             : }
    1129             : 

Generated by: LCOV version 1.10