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 1393793999 Lines: 418 559 74.8 %
Date: 2014-03-02 Functions: 17 18 94.4 %
Branches: 117 230 50.9 %

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

Generated by: LCOV version 1.9