LCOV - code coverage report
Current view: top level - eap_server - eap_server_pwd.c (source / functions) Hit Total Coverage
Test: hostapd hwsim test run 1412854115 Lines: 408 569 71.7 %
Date: 2014-10-09 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          36 : static const char * eap_pwd_state_txt(int state)
      55             : {
      56          36 :         switch (state) {
      57             :         case PWD_ID_Req:
      58           6 :                 return "PWD-ID-Req";
      59             :         case PWD_Commit_Req:
      60          12 :                 return "PWD-Commit-Req";
      61             :         case PWD_Confirm_Req:
      62          12 :                 return "PWD-Confirm-Req";
      63             :         case SUCCESS:
      64           6 :                 return "SUCCESS";
      65             :         case FAILURE:
      66           0 :                 return "FAILURE";
      67             :         default:
      68           0 :                 return "PWD-Unk";
      69             :         }
      70             : }
      71             : 
      72             : 
      73          18 : static void eap_pwd_state(struct eap_pwd_data *data, int state)
      74             : {
      75          36 :         wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s",
      76          18 :                    eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
      77          18 :         data->state = state;
      78          18 : }
      79             : 
      80             : 
      81           7 : static void * eap_pwd_init(struct eap_sm *sm)
      82             : {
      83             :         struct eap_pwd_data *data;
      84             : 
      85          14 :         if (sm->user == NULL || sm->user->password == NULL ||
      86           7 :             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           7 :         data = os_zalloc(sizeof(*data));
      93           7 :         if (data == NULL)
      94           0 :                 return NULL;
      95             : 
      96           7 :         data->group_num = sm->pwd_group;
      97           7 :         wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
      98           7 :                    data->group_num);
      99           7 :         data->state = PWD_ID_Req;
     100             : 
     101           7 :         data->id_server = (u8 *) os_strdup("server");
     102           7 :         if (data->id_server)
     103           7 :                 data->id_server_len = os_strlen((char *) data->id_server);
     104             : 
     105           7 :         data->password = os_malloc(sm->user->password_len);
     106           7 :         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           7 :         data->password_len = sm->user->password_len;
     114           7 :         os_memcpy(data->password, sm->user->password, data->password_len);
     115             : 
     116           7 :         data->bnctx = BN_CTX_new();
     117           7 :         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           7 :         data->in_frag_pos = data->out_frag_pos = 0;
     126           7 :         data->inbuf = data->outbuf = NULL;
     127             :         /* use default MTU from RFC 5931 if not configured otherwise */
     128           7 :         data->mtu = sm->fragment_size > 0 ? sm->fragment_size : 1020;
     129             : 
     130           7 :         return data;
     131             : }
     132             : 
     133             : 
     134           7 : static void eap_pwd_reset(struct eap_sm *sm, void *priv)
     135             : {
     136           7 :         struct eap_pwd_data *data = priv;
     137             : 
     138           7 :         BN_clear_free(data->private_value);
     139           7 :         BN_clear_free(data->peer_scalar);
     140           7 :         BN_clear_free(data->my_scalar);
     141           7 :         BN_clear_free(data->k);
     142           7 :         BN_CTX_free(data->bnctx);
     143           7 :         EC_POINT_clear_free(data->my_element);
     144           7 :         EC_POINT_clear_free(data->peer_element);
     145           7 :         bin_clear_free(data->id_peer, data->id_peer_len);
     146           7 :         bin_clear_free(data->id_server, data->id_server_len);
     147           7 :         bin_clear_free(data->password, data->password_len);
     148           7 :         if (data->grp) {
     149           6 :                 EC_GROUP_free(data->grp->group);
     150           6 :                 EC_POINT_clear_free(data->grp->pwe);
     151           6 :                 BN_clear_free(data->grp->order);
     152           6 :                 BN_clear_free(data->grp->prime);
     153           6 :                 os_free(data->grp);
     154             :         }
     155           7 :         wpabuf_free(data->inbuf);
     156           7 :         wpabuf_free(data->outbuf);
     157           7 :         bin_clear_free(data, sizeof(*data));
     158           7 : }
     159             : 
     160             : 
     161           7 : static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
     162             :                                  u8 id)
     163             : {
     164           7 :         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           7 :         if (data->out_frag_pos)
     169           0 :                 return;
     170             : 
     171           7 :         data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
     172           7 :                                     data->id_server_len);
     173           7 :         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           7 :         data->token = os_random();
     180           7 :         wpabuf_put_be16(data->outbuf, data->group_num);
     181           7 :         wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
     182           7 :         wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
     183           7 :         wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
     184           7 :         wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE);
     185           7 :         wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
     186             : }
     187             : 
     188             : 
     189           8 : static void eap_pwd_build_commit_req(struct eap_sm *sm,
     190             :                                      struct eap_pwd_data *data, u8 id)
     191             : {
     192           8 :         BIGNUM *mask = NULL, *x = NULL, *y = NULL;
     193           8 :         u8 *scalar = NULL, *element = NULL;
     194             :         u16 offset;
     195             : 
     196           8 :         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           8 :         if (data->out_frag_pos)
     202          10 :                 return;
     203             : 
     204          12 :         if (((data->private_value = BN_new()) == NULL) ||
     205          12 :             ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
     206          12 :             ((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          12 :         if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
     214          12 :             BN_rand_range(mask, data->grp->order) != 1 ||
     215          12 :             BN_add(data->my_scalar, data->private_value, mask) != 1 ||
     216           6 :             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          12 :         if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
     224           6 :                           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           6 :         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           6 :         BN_clear_free(mask);
     238             : 
     239           6 :         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          12 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
     246           6 :                                                  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          12 :         if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
     254           6 :             ((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           6 :         os_memset(scalar, 0, BN_num_bytes(data->grp->order));
     266           6 :         os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
     267          12 :         offset = BN_num_bytes(data->grp->order) -
     268           6 :                 BN_num_bytes(data->my_scalar);
     269           6 :         BN_bn2bin(data->my_scalar, scalar + offset);
     270             : 
     271           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
     272           6 :         BN_bn2bin(x, element + offset);
     273           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
     274           6 :         BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
     275             : 
     276          12 :         data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) +
     277           6 :                                     BN_num_bytes(data->grp->order));
     278           6 :         if (data->outbuf == NULL)
     279           0 :                 goto fin;
     280             : 
     281             :         /* We send the element as (x,y) followed by the scalar */
     282           6 :         wpabuf_put_data(data->outbuf, element,
     283           6 :                         2 * BN_num_bytes(data->grp->prime));
     284           6 :         wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
     285             : 
     286             : fin:
     287           6 :         os_free(scalar);
     288           6 :         os_free(element);
     289           6 :         BN_clear_free(x);
     290           6 :         BN_clear_free(y);
     291           6 :         if (data->outbuf == NULL)
     292           0 :                 eap_pwd_state(data, FAILURE);
     293             : }
     294             : 
     295             : 
     296           6 : static void eap_pwd_build_confirm_req(struct eap_sm *sm,
     297             :                                       struct eap_pwd_data *data, u8 id)
     298             : {
     299           6 :         BIGNUM *x = NULL, *y = NULL;
     300             :         struct crypto_hash *hash;
     301           6 :         u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
     302             :         u16 grp;
     303             :         int offset;
     304             : 
     305           6 :         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           6 :         if (data->out_frag_pos)
     311           6 :                 return;
     312             : 
     313             :         /* Each component of the cruft will be at most as big as the prime */
     314           6 :         if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
     315           6 :             ((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           6 :         hash = eap_pwd_h_init();
     326           6 :         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           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     336           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
     337           6 :         BN_bn2bin(data->k, cruft + offset);
     338           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     339             : 
     340             :         /* server element: x, y */
     341          12 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
     342           6 :                                                  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           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     350           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
     351           6 :         BN_bn2bin(x, cruft + offset);
     352           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     353           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     354           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
     355           6 :         BN_bn2bin(y, cruft + offset);
     356           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     357             : 
     358             :         /* server scalar */
     359           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     360          12 :         offset = BN_num_bytes(data->grp->order) -
     361           6 :                 BN_num_bytes(data->my_scalar);
     362           6 :         BN_bn2bin(data->my_scalar, cruft + offset);
     363           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
     364             : 
     365             :         /* peer element: x, y */
     366          12 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
     367           6 :                                                  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           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     375           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
     376           6 :         BN_bn2bin(x, cruft + offset);
     377           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     378           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     379           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
     380           6 :         BN_bn2bin(y, cruft + offset);
     381           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     382             : 
     383             :         /* peer scalar */
     384           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     385          12 :         offset = BN_num_bytes(data->grp->order) -
     386           6 :                 BN_num_bytes(data->peer_scalar);
     387           6 :         BN_bn2bin(data->peer_scalar, cruft + offset);
     388           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
     389             : 
     390             :         /* ciphersuite */
     391           6 :         grp = htons(data->group_num);
     392           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     393           6 :         ptr = cruft;
     394           6 :         os_memcpy(ptr, &grp, sizeof(u16));
     395           6 :         ptr += sizeof(u16);
     396           6 :         *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
     397           6 :         ptr += sizeof(u8);
     398           6 :         *ptr = EAP_PWD_DEFAULT_PRF;
     399           6 :         ptr += sizeof(u8);
     400           6 :         eap_pwd_h_update(hash, cruft, ptr - cruft);
     401             : 
     402             :         /* all done with the random function */
     403           6 :         eap_pwd_h_final(hash, conf);
     404           6 :         os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
     405             : 
     406           6 :         data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
     407           6 :         if (data->outbuf == NULL)
     408           0 :                 goto fin;
     409             : 
     410           6 :         wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
     411             : 
     412             : fin:
     413           6 :         bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
     414           6 :         BN_clear_free(x);
     415           6 :         BN_clear_free(y);
     416           6 :         if (data->outbuf == NULL)
     417           0 :                 eap_pwd_state(data, FAILURE);
     418             : }
     419             : 
     420             : 
     421             : static struct wpabuf *
     422          21 : eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
     423             : {
     424          21 :         struct eap_pwd_data *data = priv;
     425             :         struct wpabuf *req;
     426             :         u8 lm_exch;
     427             :         const u8 *buf;
     428          21 :         u16 totlen = 0;
     429             :         size_t len;
     430             : 
     431             :         /*
     432             :          * if we're buffering response fragments then just ACK
     433             :          */
     434          21 :         if (data->in_frag_pos) {
     435           0 :                 wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a fragment!!");
     436           0 :                 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
     437             :                                     EAP_PWD_HDR_SIZE, EAP_CODE_REQUEST, id);
     438           0 :                 if (req == NULL) {
     439           0 :                         eap_pwd_state(data, FAILURE);
     440           0 :                         return NULL;
     441             :                 }
     442           0 :                 switch (data->state) {
     443             :                 case PWD_ID_Req:
     444           0 :                         wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH);
     445           0 :                         break;
     446             :                 case PWD_Commit_Req:
     447           0 :                         wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH);
     448           0 :                         break;
     449             :                 case PWD_Confirm_Req:
     450           0 :                         wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH);
     451           0 :                         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           0 :                 return req;
     458             :         }
     459             : 
     460             :         /*
     461             :          * build the data portion of a request
     462             :          */
     463          21 :         switch (data->state) {
     464             :         case PWD_ID_Req:
     465           7 :                 eap_pwd_build_id_req(sm, data, id);
     466           7 :                 lm_exch = EAP_PWD_OPCODE_ID_EXCH;
     467           7 :                 break;
     468             :         case PWD_Commit_Req:
     469           8 :                 eap_pwd_build_commit_req(sm, data, id);
     470           8 :                 lm_exch = EAP_PWD_OPCODE_COMMIT_EXCH;
     471           8 :                 break;
     472             :         case PWD_Confirm_Req:
     473           6 :                 eap_pwd_build_confirm_req(sm, data, id);
     474           6 :                 lm_exch = EAP_PWD_OPCODE_CONFIRM_EXCH;
     475           6 :                 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          21 :         if (data->state == FAILURE)
     485           0 :                 return NULL;
     486             : 
     487             :         /*
     488             :          * determine whether that data needs to be fragmented
     489             :          */
     490          21 :         len = wpabuf_len(data->outbuf) - data->out_frag_pos;
     491          21 :         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          42 :         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
     514          21 :                             EAP_PWD_HDR_SIZE + len +
     515          21 :                             (totlen ? sizeof(u16) : 0),
     516             :                             EAP_CODE_REQUEST, id);
     517          21 :         if (req == NULL) {
     518           0 :                 eap_pwd_state(data, FAILURE);
     519           0 :                 return NULL;
     520             :         }
     521             : 
     522          21 :         wpabuf_put_u8(req, lm_exch);
     523          21 :         if (EAP_PWD_GET_LENGTH_BIT(lm_exch))
     524           1 :                 wpabuf_put_be16(req, totlen);
     525             : 
     526          21 :         buf = wpabuf_head_u8(data->outbuf);
     527          21 :         wpabuf_put_data(req, buf + data->out_frag_pos, len);
     528          21 :         data->out_frag_pos += len;
     529             :         /*
     530             :          * either not fragged or last fragment, either way free up the data
     531             :          */
     532          21 :         if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
     533          19 :                 wpabuf_free(data->outbuf);
     534          19 :                 data->outbuf = NULL;
     535          19 :                 data->out_frag_pos = 0;
     536             :         }
     537             : 
     538          21 :         return req;
     539             : }
     540             : 
     541             : 
     542          20 : static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
     543             :                              struct wpabuf *respData)
     544             : {
     545          20 :         struct eap_pwd_data *data = priv;
     546             :         const u8 *pos;
     547             :         size_t len;
     548             : 
     549          20 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
     550          20 :         if (pos == NULL || len < 1) {
     551           0 :                 wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
     552           0 :                 return TRUE;
     553             :         }
     554             : 
     555          40 :         wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: exch = %d, len = %d",
     556          20 :                    EAP_PWD_GET_EXCHANGE(*pos), (int) len);
     557             : 
     558          26 :         if (data->state == PWD_ID_Req &&
     559           6 :             ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH))
     560           6 :                 return FALSE;
     561             : 
     562          22 :         if (data->state == PWD_Commit_Req &&
     563           8 :             ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH))
     564           8 :                 return FALSE;
     565             : 
     566          12 :         if (data->state == PWD_Confirm_Req &&
     567           6 :             ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH))
     568           6 :                 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           6 : 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           6 :         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           6 :         id = (struct eap_pwd_id *) payload;
     589          12 :         if ((data->group_num != be_to_host16(id->group_num)) ||
     590          12 :             (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
     591          12 :             (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
     592           6 :             (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           6 :         data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
     598           6 :         if (data->id_peer == NULL) {
     599           0 :                 wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
     600           0 :                 return;
     601             :         }
     602           6 :         data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
     603           6 :         os_memcpy(data->id_peer, id->identity, data->id_peer_len);
     604          12 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
     605           6 :                           data->id_peer, data->id_peer_len);
     606             : 
     607           6 :         data->grp = os_zalloc(sizeof(EAP_PWD_group));
     608           6 :         if (data->grp == NULL) {
     609           0 :                 wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
     610             :                            "group");
     611           0 :                 return;
     612             :         }
     613          18 :         if (compute_password_element(data->grp, data->group_num,
     614           6 :                                      data->password, data->password_len,
     615           6 :                                      data->id_server, data->id_server_len,
     616           6 :                                      data->id_peer, data->id_peer_len,
     617           6 :                                      (u8 *) &data->token)) {
     618           0 :                 wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
     619             :                            "PWE");
     620           0 :                 return;
     621             :         }
     622           6 :         wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
     623           6 :                    BN_num_bits(data->grp->prime));
     624             : 
     625           6 :         eap_pwd_state(data, PWD_Commit_Req);
     626             : }
     627             : 
     628             : 
     629             : static void
     630           6 : 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           6 :         BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
     635           6 :         EC_POINT *K = NULL, *point = NULL;
     636           6 :         int res = 0;
     637             : 
     638           6 :         wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
     639             : 
     640          12 :         if (((data->peer_scalar = BN_new()) == NULL) ||
     641          12 :             ((data->k = BN_new()) == NULL) ||
     642           6 :             ((cofactor = BN_new()) == NULL) ||
     643           6 :             ((x = BN_new()) == NULL) ||
     644           6 :             ((y = BN_new()) == NULL) ||
     645          12 :             ((point = EC_POINT_new(data->grp->group)) == NULL) ||
     646          12 :             ((K = EC_POINT_new(data->grp->group)) == NULL) ||
     647           6 :             ((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           6 :         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           6 :         ptr = (u8 *) payload;
     661           6 :         BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
     662           6 :         ptr += BN_num_bytes(data->grp->prime);
     663           6 :         BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
     664           6 :         ptr += BN_num_bytes(data->grp->prime);
     665           6 :         BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
     666           6 :         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           6 :         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          12 :         if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
     691          12 :                            data->peer_scalar, data->bnctx)) ||
     692           6 :             (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
     693           6 :                            data->bnctx)) ||
     694           6 :             (!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           6 :         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           6 :         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           6 :         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           6 :         res = 1;
     729             : 
     730             : fin:
     731           6 :         EC_POINT_clear_free(K);
     732           6 :         EC_POINT_clear_free(point);
     733           6 :         BN_clear_free(cofactor);
     734           6 :         BN_clear_free(x);
     735           6 :         BN_clear_free(y);
     736             : 
     737           6 :         if (res)
     738           6 :                 eap_pwd_state(data, PWD_Confirm_Req);
     739             :         else
     740           0 :                 eap_pwd_state(data, FAILURE);
     741           6 : }
     742             : 
     743             : 
     744             : static void
     745           6 : eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
     746             :                              const u8 *payload, size_t payload_len)
     747             : {
     748           6 :         BIGNUM *x = NULL, *y = NULL;
     749             :         struct crypto_hash *hash;
     750             :         u32 cs;
     751             :         u16 grp;
     752           6 :         u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
     753             :         int offset;
     754             : 
     755             :         /* build up the ciphersuite: group | random_function | prf */
     756           6 :         grp = htons(data->group_num);
     757           6 :         ptr = (u8 *) &cs;
     758           6 :         os_memcpy(ptr, &grp, sizeof(u16));
     759           6 :         ptr += sizeof(u16);
     760           6 :         *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
     761           6 :         ptr += sizeof(u8);
     762           6 :         *ptr = EAP_PWD_DEFAULT_PRF;
     763             : 
     764             :         /* each component of the cruft will be at most as big as the prime */
     765           6 :         if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
     766           6 :             ((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           6 :         hash = eap_pwd_h_init();
     776           6 :         if (hash == NULL)
     777           0 :                 goto fin;
     778             : 
     779             :         /* k */
     780           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     781           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
     782           6 :         BN_bn2bin(data->k, cruft + offset);
     783           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     784             : 
     785             :         /* peer element: x, y */
     786          12 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
     787           6 :                                                  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           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     794           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
     795           6 :         BN_bn2bin(x, cruft + offset);
     796           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     797           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     798           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
     799           6 :         BN_bn2bin(y, cruft + offset);
     800           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     801             : 
     802             :         /* peer scalar */
     803           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     804          12 :         offset = BN_num_bytes(data->grp->order) -
     805           6 :                 BN_num_bytes(data->peer_scalar);
     806           6 :         BN_bn2bin(data->peer_scalar, cruft + offset);
     807           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
     808             : 
     809             :         /* server element: x, y */
     810          12 :         if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
     811           6 :                                                  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           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     819           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
     820           6 :         BN_bn2bin(x, cruft + offset);
     821           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     822           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     823           6 :         offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
     824           6 :         BN_bn2bin(y, cruft + offset);
     825           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
     826             : 
     827             :         /* server scalar */
     828           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     829          12 :         offset = BN_num_bytes(data->grp->order) -
     830           6 :                 BN_num_bytes(data->my_scalar);
     831           6 :         BN_bn2bin(data->my_scalar, cruft + offset);
     832           6 :         eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
     833             : 
     834             :         /* ciphersuite */
     835           6 :         os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
     836           6 :         eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
     837             : 
     838             :         /* all done */
     839           6 :         eap_pwd_h_final(hash, conf);
     840             : 
     841           6 :         ptr = (u8 *) payload;
     842           6 :         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           6 :         wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
     849           6 :         if (compute_keys(data->grp, data->bnctx, data->k,
     850             :                          data->peer_scalar, data->my_scalar, conf,
     851           6 :                          data->my_confirm, &cs, data->msk, data->emsk,
     852           6 :                          data->session_id) < 0)
     853           0 :                 eap_pwd_state(data, FAILURE);
     854             :         else
     855           6 :                 eap_pwd_state(data, SUCCESS);
     856             : 
     857             : fin:
     858           6 :         bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
     859           6 :         BN_clear_free(x);
     860           6 :         BN_clear_free(y);
     861           6 : }
     862             : 
     863             : 
     864          20 : static void eap_pwd_process(struct eap_sm *sm, void *priv,
     865             :                             struct wpabuf *respData)
     866             : {
     867          20 :         struct eap_pwd_data *data = priv;
     868             :         const u8 *pos;
     869             :         size_t len;
     870             :         u8 lm_exch;
     871             :         u16 tot_len;
     872             : 
     873          20 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
     874          20 :         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          20 :         lm_exch = *pos;
     882          20 :         pos++;            /* skip over the bits and the exch */
     883          20 :         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          20 :         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          18 :         if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
     904           0 :                 tot_len = WPA_GET_BE16(pos);
     905           0 :                 wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total "
     906             :                            "length = %d", tot_len);
     907           0 :                 if (tot_len > 15000)
     908           0 :                         return;
     909           0 :                 data->inbuf = wpabuf_alloc(tot_len);
     910           0 :                 if (data->inbuf == NULL) {
     911           0 :                         wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to "
     912             :                                    "buffer fragments!");
     913           0 :                         return;
     914             :                 }
     915           0 :                 pos += sizeof(u16);
     916           0 :                 len -= sizeof(u16);
     917             :         }
     918             :         /*
     919             :          * the first and all intermediate fragments have the M bit set
     920             :          */
     921          18 :         if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
     922           0 :                 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           0 :                 wpabuf_put_data(data->inbuf, pos, len);
     931           0 :                 data->in_frag_pos += len;
     932           0 :                 wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment",
     933             :                            (int) len);
     934           0 :                 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          18 :         if (data->in_frag_pos) {
     941           0 :                 wpabuf_put_data(data->inbuf, pos, len);
     942           0 :                 data->in_frag_pos += len;
     943           0 :                 pos = wpabuf_head_u8(data->inbuf);
     944           0 :                 len = data->in_frag_pos;
     945           0 :                 wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
     946             :                            (int) len);
     947             :         }
     948          18 :         switch (EAP_PWD_GET_EXCHANGE(lm_exch)) {
     949             :         case EAP_PWD_OPCODE_ID_EXCH:
     950           6 :                 eap_pwd_process_id_resp(sm, data, pos, len);
     951           6 :                 break;
     952             :         case EAP_PWD_OPCODE_COMMIT_EXCH:
     953           6 :                 eap_pwd_process_commit_resp(sm, data, pos, len);
     954           6 :                 break;
     955             :         case EAP_PWD_OPCODE_CONFIRM_EXCH:
     956           6 :                 eap_pwd_process_confirm_resp(sm, data, pos, len);
     957           6 :                 break;
     958             :         }
     959             :         /*
     960             :          * if we had been buffering fragments, here's a great place
     961             :          * to clean up
     962             :          */
     963          18 :         if (data->in_frag_pos) {
     964           0 :                 wpabuf_free(data->inbuf);
     965           0 :                 data->inbuf = NULL;
     966           0 :                 data->in_frag_pos = 0;
     967             :         }
     968             : }
     969             : 
     970             : 
     971           6 : static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
     972             : {
     973           6 :         struct eap_pwd_data *data = priv;
     974             :         u8 *key;
     975             : 
     976           6 :         if (data->state != SUCCESS)
     977           0 :                 return NULL;
     978             : 
     979           6 :         key = os_malloc(EAP_MSK_LEN);
     980           6 :         if (key == NULL)
     981           0 :                 return NULL;
     982             : 
     983           6 :         os_memcpy(key, data->msk, EAP_MSK_LEN);
     984           6 :         *len = EAP_MSK_LEN;
     985             : 
     986           6 :         return key;
     987             : }
     988             : 
     989             : 
     990           0 : static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
     991             : {
     992           0 :         struct eap_pwd_data *data = priv;
     993             :         u8 *key;
     994             : 
     995           0 :         if (data->state != SUCCESS)
     996           0 :                 return NULL;
     997             : 
     998           0 :         key = os_malloc(EAP_EMSK_LEN);
     999           0 :         if (key == NULL)
    1000           0 :                 return NULL;
    1001             : 
    1002           0 :         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
    1003           0 :         *len = EAP_EMSK_LEN;
    1004             : 
    1005           0 :         return key;
    1006             : }
    1007             : 
    1008             : 
    1009           6 : static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
    1010             : {
    1011           6 :         struct eap_pwd_data *data = priv;
    1012           6 :         return data->state == SUCCESS;
    1013             : }
    1014             : 
    1015             : 
    1016          20 : static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
    1017             : {
    1018          20 :         struct eap_pwd_data *data = priv;
    1019          20 :         return (data->state == SUCCESS) || (data->state == FAILURE);
    1020             : }
    1021             : 
    1022             : 
    1023           1 : int eap_server_pwd_register(void)
    1024             : {
    1025             :         struct eap_method *eap;
    1026             :         int ret;
    1027             :         struct timeval tp;
    1028             :         struct timezone tz;
    1029             :         u32 sr;
    1030             : 
    1031           1 :         EVP_add_digest(EVP_sha256());
    1032             : 
    1033           1 :         sr = 0xdeaddada;
    1034           1 :         (void) gettimeofday(&tp, &tz);
    1035           1 :         sr ^= (tp.tv_sec ^ tp.tv_usec);
    1036           1 :         srandom(sr);
    1037             : 
    1038           1 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    1039             :                                       EAP_VENDOR_IETF, EAP_TYPE_PWD,
    1040             :                                       "PWD");
    1041           1 :         if (eap == NULL)
    1042           0 :                 return -1;
    1043             : 
    1044           1 :         eap->init = eap_pwd_init;
    1045           1 :         eap->reset = eap_pwd_reset;
    1046           1 :         eap->buildReq = eap_pwd_build_req;
    1047           1 :         eap->check = eap_pwd_check;
    1048           1 :         eap->process = eap_pwd_process;
    1049           1 :         eap->isDone = eap_pwd_is_done;
    1050           1 :         eap->getKey = eap_pwd_getkey;
    1051           1 :         eap->get_emsk = eap_pwd_get_emsk;
    1052           1 :         eap->isSuccess = eap_pwd_is_success;
    1053             : 
    1054           1 :         ret = eap_server_method_register(eap);
    1055           1 :         if (ret)
    1056           0 :                 eap_server_method_free(eap);
    1057           1 :         return ret;
    1058             : }
    1059             : 

Generated by: LCOV version 1.10