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

Generated by: LCOV version 1.10