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 1401264779 Lines: 438 565 77.5 %
Date: 2014-05-28 Functions: 17 18 94.4 %

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

Generated by: LCOV version 1.10