LCOV - code coverage report
Current view: top level - src/eap_peer - eap_gpsk.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1401264779 Lines: 279 399 69.9 %
Date: 2014-05-28 Functions: 22 23 95.7 %

          Line data    Source code
       1             : /*
       2             :  * EAP peer method: EAP-GPSK (RFC 5433)
       3             :  * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
       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/random.h"
      13             : #include "eap_peer/eap_i.h"
      14             : #include "eap_common/eap_gpsk_common.h"
      15             : 
      16             : struct eap_gpsk_data {
      17             :         enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
      18             :         u8 rand_server[EAP_GPSK_RAND_LEN];
      19             :         u8 rand_peer[EAP_GPSK_RAND_LEN];
      20             :         u8 msk[EAP_MSK_LEN];
      21             :         u8 emsk[EAP_EMSK_LEN];
      22             :         u8 sk[EAP_GPSK_MAX_SK_LEN];
      23             :         size_t sk_len;
      24             :         u8 pk[EAP_GPSK_MAX_PK_LEN];
      25             :         size_t pk_len;
      26             :         u8 session_id[128];
      27             :         size_t id_len;
      28             :         u8 *id_peer;
      29             :         size_t id_peer_len;
      30             :         u8 *id_server;
      31             :         size_t id_server_len;
      32             :         int vendor; /* CSuite/Specifier */
      33             :         int specifier; /* CSuite/Specifier */
      34             :         u8 *psk;
      35             :         size_t psk_len;
      36             :         u16 forced_cipher; /* force cipher or 0 to allow all supported */
      37             : };
      38             : 
      39             : 
      40             : static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
      41             :                                             u8 identifier,
      42             :                                             const u8 *csuite_list,
      43             :                                             size_t csuite_list_len);
      44             : static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
      45             :                                             u8 identifier);
      46             : 
      47             : 
      48             : #ifndef CONFIG_NO_STDOUT_DEBUG
      49          80 : static const char * eap_gpsk_state_txt(int state)
      50             : {
      51          80 :         switch (state) {
      52             :         case GPSK_1:
      53          21 :                 return "GPSK-1";
      54             :         case GPSK_3:
      55          39 :                 return "GPSK-3";
      56             :         case SUCCESS:
      57          19 :                 return "SUCCESS";
      58             :         case FAILURE:
      59           1 :                 return "FAILURE";
      60             :         default:
      61           0 :                 return "?";
      62             :         }
      63             : }
      64             : #endif /* CONFIG_NO_STDOUT_DEBUG */
      65             : 
      66             : 
      67          40 : static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
      68             : {
      69          80 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
      70          40 :                    eap_gpsk_state_txt(data->state),
      71             :                    eap_gpsk_state_txt(state));
      72          40 :         data->state = state;
      73          40 : }
      74             : 
      75             : 
      76             : static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
      77             : 
      78             : 
      79          21 : static void * eap_gpsk_init(struct eap_sm *sm)
      80             : {
      81             :         struct eap_gpsk_data *data;
      82             :         const u8 *identity, *password;
      83             :         size_t identity_len, password_len;
      84             :         const char *phase1;
      85             : 
      86          21 :         password = eap_get_config_password(sm, &password_len);
      87          21 :         if (password == NULL) {
      88           0 :                 wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
      89           0 :                 return NULL;
      90             :         }
      91             : 
      92          21 :         data = os_zalloc(sizeof(*data));
      93          21 :         if (data == NULL)
      94           0 :                 return NULL;
      95          21 :         data->state = GPSK_1;
      96             : 
      97          21 :         identity = eap_get_config_identity(sm, &identity_len);
      98          21 :         if (identity) {
      99          21 :                 data->id_peer = os_malloc(identity_len);
     100          21 :                 if (data->id_peer == NULL) {
     101           0 :                         eap_gpsk_deinit(sm, data);
     102           0 :                         return NULL;
     103             :                 }
     104          21 :                 os_memcpy(data->id_peer, identity, identity_len);
     105          21 :                 data->id_peer_len = identity_len;
     106             :         }
     107             : 
     108          21 :         phase1 = eap_get_config_phase1(sm);
     109          21 :         if (phase1) {
     110             :                 const char *pos;
     111             : 
     112           3 :                 pos = os_strstr(phase1, "cipher=");
     113           3 :                 if (pos) {
     114           3 :                         data->forced_cipher = atoi(pos + 7);
     115           3 :                         wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
     116           3 :                                    data->forced_cipher);
     117             :                 }
     118             :         }
     119             : 
     120          21 :         data->psk = os_malloc(password_len);
     121          21 :         if (data->psk == NULL) {
     122           0 :                 eap_gpsk_deinit(sm, data);
     123           0 :                 return NULL;
     124             :         }
     125          21 :         os_memcpy(data->psk, password, password_len);
     126          21 :         data->psk_len = password_len;
     127             : 
     128          21 :         return data;
     129             : }
     130             : 
     131             : 
     132          21 : static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
     133             : {
     134          21 :         struct eap_gpsk_data *data = priv;
     135          21 :         os_free(data->id_server);
     136          21 :         os_free(data->id_peer);
     137          21 :         os_free(data->psk);
     138          21 :         os_free(data);
     139          21 : }
     140             : 
     141             : 
     142          21 : static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
     143             :                                              const u8 *pos, const u8 *end)
     144             : {
     145             :         u16 alen;
     146             : 
     147          21 :         if (end - pos < 2) {
     148           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
     149           0 :                 return NULL;
     150             :         }
     151          21 :         alen = WPA_GET_BE16(pos);
     152          21 :         pos += 2;
     153          21 :         if (end - pos < alen) {
     154           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
     155           0 :                 return NULL;
     156             :         }
     157          21 :         os_free(data->id_server);
     158          21 :         data->id_server = os_malloc(alen);
     159          21 :         if (data->id_server == NULL) {
     160           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
     161           0 :                 return NULL;
     162             :         }
     163          21 :         os_memcpy(data->id_server, pos, alen);
     164          21 :         data->id_server_len = alen;
     165          42 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
     166          21 :                           data->id_server, data->id_server_len);
     167          21 :         pos += alen;
     168             : 
     169          21 :         return pos;
     170             : }
     171             : 
     172             : 
     173          21 : static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
     174             :                                                const u8 *pos, const u8 *end)
     175             : {
     176          21 :         if (pos == NULL)
     177           0 :                 return NULL;
     178             : 
     179          21 :         if (end - pos < EAP_GPSK_RAND_LEN) {
     180           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
     181           0 :                 return NULL;
     182             :         }
     183          21 :         os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
     184          21 :         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
     185          21 :                     data->rand_server, EAP_GPSK_RAND_LEN);
     186          21 :         pos += EAP_GPSK_RAND_LEN;
     187             : 
     188          21 :         return pos;
     189             : }
     190             : 
     191             : 
     192          21 : static int eap_gpsk_select_csuite(struct eap_sm *sm,
     193             :                                   struct eap_gpsk_data *data,
     194             :                                   const u8 *csuite_list,
     195             :                                   size_t csuite_list_len)
     196             : {
     197             :         struct eap_gpsk_csuite *csuite;
     198             :         int i, count;
     199             : 
     200          21 :         count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
     201          21 :         data->vendor = EAP_GPSK_VENDOR_IETF;
     202          21 :         data->specifier = EAP_GPSK_CIPHER_RESERVED;
     203          21 :         csuite = (struct eap_gpsk_csuite *) csuite_list;
     204          63 :         for (i = 0; i < count; i++) {
     205             :                 int vendor, specifier;
     206          42 :                 vendor = WPA_GET_BE32(csuite->vendor);
     207          42 :                 specifier = WPA_GET_BE16(csuite->specifier);
     208          42 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
     209             :                            i, vendor, specifier);
     210          84 :                 if (data->vendor == EAP_GPSK_VENDOR_IETF &&
     211          65 :                     data->specifier == EAP_GPSK_CIPHER_RESERVED &&
     212          46 :                     eap_gpsk_supported_ciphersuite(vendor, specifier) &&
     213          28 :                     (!data->forced_cipher || data->forced_cipher == specifier))
     214             :                 {
     215          20 :                         data->vendor = vendor;
     216          20 :                         data->specifier = specifier;
     217             :                 }
     218          42 :                 csuite++;
     219             :         }
     220          42 :         if (data->vendor == EAP_GPSK_VENDOR_IETF &&
     221          21 :             data->specifier == EAP_GPSK_CIPHER_RESERVED) {
     222           1 :                 wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
     223             :                         "ciphersuite found");
     224           1 :                 return -1;
     225             :         }
     226          20 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
     227             :                    data->vendor, data->specifier);
     228             : 
     229          20 :         return 0;
     230             : }
     231             : 
     232             : 
     233          21 : static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
     234             :                                                struct eap_gpsk_data *data,
     235             :                                                const u8 **list,
     236             :                                                size_t *list_len,
     237             :                                                const u8 *pos, const u8 *end)
     238             : {
     239          21 :         if (pos == NULL)
     240           0 :                 return NULL;
     241             : 
     242          21 :         if (end - pos < 2) {
     243           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
     244           0 :                 return NULL;
     245             :         }
     246          21 :         *list_len = WPA_GET_BE16(pos);
     247          21 :         pos += 2;
     248          21 :         if (end - pos < (int) *list_len) {
     249           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
     250           0 :                 return NULL;
     251             :         }
     252          21 :         if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) {
     253           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
     254             :                            (unsigned long) *list_len);
     255           0 :                 return NULL;
     256             :         }
     257          21 :         *list = pos;
     258          21 :         pos += *list_len;
     259             : 
     260          21 :         if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0)
     261           1 :                 return NULL;
     262             : 
     263          20 :         return pos;
     264             : }
     265             : 
     266             : 
     267          21 : static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
     268             :                                                struct eap_gpsk_data *data,
     269             :                                                struct eap_method_ret *ret,
     270             :                                                const struct wpabuf *reqData,
     271             :                                                const u8 *payload,
     272             :                                                size_t payload_len)
     273             : {
     274             :         size_t csuite_list_len;
     275             :         const u8 *csuite_list, *pos, *end;
     276             :         struct wpabuf *resp;
     277             : 
     278          21 :         if (data->state != GPSK_1) {
     279           0 :                 ret->ignore = TRUE;
     280           0 :                 return NULL;
     281             :         }
     282             : 
     283          21 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
     284             : 
     285          21 :         end = payload + payload_len;
     286             : 
     287          21 :         pos = eap_gpsk_process_id_server(data, payload, end);
     288          21 :         pos = eap_gpsk_process_rand_server(data, pos, end);
     289          21 :         pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
     290             :                                            &csuite_list_len, pos, end);
     291          21 :         if (pos == NULL) {
     292           1 :                 ret->methodState = METHOD_DONE;
     293           1 :                 eap_gpsk_state(data, FAILURE);
     294           1 :                 return NULL;
     295             :         }
     296             : 
     297          20 :         resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData),
     298             :                                     csuite_list, csuite_list_len);
     299          20 :         if (resp == NULL)
     300           0 :                 return NULL;
     301             : 
     302          20 :         eap_gpsk_state(data, GPSK_3);
     303             : 
     304          20 :         return resp;
     305             : }
     306             : 
     307             : 
     308          20 : static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
     309             :                                             u8 identifier,
     310             :                                             const u8 *csuite_list,
     311             :                                             size_t csuite_list_len)
     312             : {
     313             :         struct wpabuf *resp;
     314             :         size_t len, miclen;
     315             :         u8 *rpos, *start;
     316             :         struct eap_gpsk_csuite *csuite;
     317             : 
     318          20 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
     319             : 
     320          20 :         miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
     321          40 :         len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
     322          20 :                 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
     323          20 :                 sizeof(struct eap_gpsk_csuite) + 2 + miclen;
     324             : 
     325          20 :         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
     326             :                              EAP_CODE_RESPONSE, identifier);
     327          20 :         if (resp == NULL)
     328           0 :                 return NULL;
     329             : 
     330          20 :         wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
     331          20 :         start = wpabuf_put(resp, 0);
     332             : 
     333          40 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
     334          20 :                           data->id_peer, data->id_peer_len);
     335          20 :         wpabuf_put_be16(resp, data->id_peer_len);
     336          20 :         wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
     337             : 
     338          20 :         wpabuf_put_be16(resp, data->id_server_len);
     339          20 :         wpabuf_put_data(resp, data->id_server, data->id_server_len);
     340             : 
     341          20 :         if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
     342           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
     343             :                            "for RAND_Peer");
     344           0 :                 eap_gpsk_state(data, FAILURE);
     345           0 :                 wpabuf_free(resp);
     346           0 :                 return NULL;
     347             :         }
     348          20 :         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
     349          20 :                     data->rand_peer, EAP_GPSK_RAND_LEN);
     350          20 :         wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
     351          20 :         wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
     352             : 
     353          20 :         wpabuf_put_be16(resp, csuite_list_len);
     354          20 :         wpabuf_put_data(resp, csuite_list, csuite_list_len);
     355             : 
     356          20 :         csuite = wpabuf_put(resp, sizeof(*csuite));
     357          20 :         WPA_PUT_BE32(csuite->vendor, data->vendor);
     358          20 :         WPA_PUT_BE16(csuite->specifier, data->specifier);
     359             : 
     360         100 :         if (eap_gpsk_derive_keys(data->psk, data->psk_len,
     361             :                                  data->vendor, data->specifier,
     362          20 :                                  data->rand_peer, data->rand_server,
     363          20 :                                  data->id_peer, data->id_peer_len,
     364          20 :                                  data->id_server, data->id_server_len,
     365          20 :                                  data->msk, data->emsk,
     366          20 :                                  data->sk, &data->sk_len,
     367          20 :                                  data->pk, &data->pk_len) < 0) {
     368           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
     369           0 :                 eap_gpsk_state(data, FAILURE);
     370           0 :                 wpabuf_free(resp);
     371           0 :                 return NULL;
     372             :         }
     373             : 
     374          80 :         if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
     375             :                                        data->vendor, data->specifier,
     376          20 :                                        data->rand_peer, data->rand_server,
     377          20 :                                        data->id_peer, data->id_peer_len,
     378          20 :                                        data->id_server, data->id_server_len,
     379             :                                        EAP_TYPE_GPSK,
     380          20 :                                        data->session_id, &data->id_len) < 0) {
     381           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
     382           0 :                 eap_gpsk_state(data, FAILURE);
     383           0 :                 wpabuf_free(resp);
     384           0 :                 return NULL;
     385             :         }
     386          40 :         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
     387          20 :                     data->session_id, data->id_len);
     388             : 
     389             :         /* No PD_Payload_1 */
     390          20 :         wpabuf_put_be16(resp, 0);
     391             : 
     392          20 :         rpos = wpabuf_put(resp, miclen);
     393          20 :         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
     394          20 :                                  data->specifier, start, rpos - start, rpos) <
     395             :             0) {
     396           0 :                 eap_gpsk_state(data, FAILURE);
     397           0 :                 wpabuf_free(resp);
     398           0 :                 return NULL;
     399             :         }
     400             : 
     401          20 :         return resp;
     402             : }
     403             : 
     404             : 
     405          19 : static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
     406             :                                          const u8 *pos, const u8 *end)
     407             : {
     408          19 :         if (end - pos < EAP_GPSK_RAND_LEN) {
     409           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
     410             :                            "RAND_Peer");
     411           0 :                 return NULL;
     412             :         }
     413          19 :         if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
     414           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
     415             :                            "GPSK-3 did not match");
     416           0 :                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
     417           0 :                             data->rand_peer, EAP_GPSK_RAND_LEN);
     418           0 :                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
     419             :                             pos, EAP_GPSK_RAND_LEN);
     420           0 :                 return NULL;
     421             :         }
     422          19 :         pos += EAP_GPSK_RAND_LEN;
     423             : 
     424          19 :         if (end - pos < EAP_GPSK_RAND_LEN) {
     425           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
     426             :                            "RAND_Server");
     427           0 :                 return NULL;
     428             :         }
     429          19 :         if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
     430           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
     431             :                            "GPSK-3 did not match");
     432           0 :                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
     433           0 :                             data->rand_server, EAP_GPSK_RAND_LEN);
     434           0 :                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
     435             :                             pos, EAP_GPSK_RAND_LEN);
     436           0 :                 return NULL;
     437             :         }
     438          19 :         pos += EAP_GPSK_RAND_LEN;
     439             : 
     440          19 :         return pos;
     441             : }
     442             : 
     443             : 
     444          19 : static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
     445             :                                               const u8 *pos, const u8 *end)
     446             : {
     447             :         size_t len;
     448             : 
     449          19 :         if (pos == NULL)
     450           0 :                 return NULL;
     451             : 
     452          19 :         if (end - pos < (int) 2) {
     453           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
     454             :                            "length(ID_Server)");
     455           0 :                 return NULL;
     456             :         }
     457             : 
     458          19 :         len = WPA_GET_BE16(pos);
     459          19 :         pos += 2;
     460             : 
     461          19 :         if (end - pos < (int) len) {
     462           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
     463             :                            "ID_Server");
     464           0 :                 return NULL;
     465             :         }
     466             : 
     467          38 :         if (len != data->id_server_len ||
     468          19 :             os_memcmp(pos, data->id_server, len) != 0) {
     469           0 :                 wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
     470             :                            "the one used in GPSK-1");
     471           0 :                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
     472           0 :                                   data->id_server, data->id_server_len);
     473           0 :                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
     474             :                                   pos, len);
     475           0 :                 return NULL;
     476             :         }
     477             : 
     478          19 :         pos += len;
     479             : 
     480          19 :         return pos;
     481             : }
     482             : 
     483             : 
     484          19 : static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
     485             :                                            const u8 *pos, const u8 *end)
     486             : {
     487             :         int vendor, specifier;
     488             :         const struct eap_gpsk_csuite *csuite;
     489             : 
     490          19 :         if (pos == NULL)
     491           0 :                 return NULL;
     492             : 
     493          19 :         if (end - pos < (int) sizeof(*csuite)) {
     494           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
     495             :                            "CSuite_Sel");
     496           0 :                 return NULL;
     497             :         }
     498          19 :         csuite = (const struct eap_gpsk_csuite *) pos;
     499          19 :         vendor = WPA_GET_BE32(csuite->vendor);
     500          19 :         specifier = WPA_GET_BE16(csuite->specifier);
     501          19 :         pos += sizeof(*csuite);
     502          19 :         if (vendor != data->vendor || specifier != data->specifier) {
     503           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
     504             :                            "match with the one sent in GPSK-2 (%d:%d)",
     505             :                            vendor, specifier, data->vendor, data->specifier);
     506           0 :                 return NULL;
     507             :         }
     508             : 
     509          19 :         return pos;
     510             : }
     511             : 
     512             : 
     513          19 : static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
     514             :                                                  const u8 *pos, const u8 *end)
     515             : {
     516             :         u16 alen;
     517             : 
     518          19 :         if (pos == NULL)
     519           0 :                 return NULL;
     520             : 
     521          19 :         if (end - pos < 2) {
     522           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
     523             :                            "PD_Payload_2 length");
     524           0 :                 return NULL;
     525             :         }
     526          19 :         alen = WPA_GET_BE16(pos);
     527          19 :         pos += 2;
     528          19 :         if (end - pos < alen) {
     529           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
     530             :                            "%d-octet PD_Payload_2", alen);
     531           0 :                 return NULL;
     532             :         }
     533          19 :         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
     534          19 :         pos += alen;
     535             : 
     536          19 :         return pos;
     537             : }
     538             : 
     539             : 
     540          19 : static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
     541             :                                                const u8 *payload,
     542             :                                                const u8 *pos, const u8 *end)
     543             : {
     544             :         size_t miclen;
     545             :         u8 mic[EAP_GPSK_MAX_MIC_LEN];
     546             : 
     547          19 :         if (pos == NULL)
     548           0 :                 return NULL;
     549             : 
     550          19 :         miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
     551          19 :         if (end - pos < (int) miclen) {
     552           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
     553             :                            "(left=%lu miclen=%lu)",
     554           0 :                            (unsigned long) (end - pos),
     555             :                            (unsigned long) miclen);
     556           0 :                 return NULL;
     557             :         }
     558          19 :         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
     559          19 :                                  data->specifier, payload, pos - payload, mic)
     560             :             < 0) {
     561           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
     562           0 :                 return NULL;
     563             :         }
     564          19 :         if (os_memcmp(mic, pos, miclen) != 0) {
     565           0 :                 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
     566           0 :                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
     567           0 :                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
     568           0 :                 return NULL;
     569             :         }
     570          19 :         pos += miclen;
     571             : 
     572          19 :         return pos;
     573             : }
     574             : 
     575             : 
     576          19 : static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
     577             :                                                struct eap_gpsk_data *data,
     578             :                                                struct eap_method_ret *ret,
     579             :                                                const struct wpabuf *reqData,
     580             :                                                const u8 *payload,
     581             :                                                size_t payload_len)
     582             : {
     583             :         struct wpabuf *resp;
     584             :         const u8 *pos, *end;
     585             : 
     586          19 :         if (data->state != GPSK_3) {
     587           0 :                 ret->ignore = TRUE;
     588           0 :                 return NULL;
     589             :         }
     590             : 
     591          19 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
     592             : 
     593          19 :         end = payload + payload_len;
     594             : 
     595          19 :         pos = eap_gpsk_validate_rand(data, payload, end);
     596          19 :         pos = eap_gpsk_validate_id_server(data, pos, end);
     597          19 :         pos = eap_gpsk_validate_csuite(data, pos, end);
     598          19 :         pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
     599          19 :         pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
     600             : 
     601          19 :         if (pos == NULL) {
     602           0 :                 eap_gpsk_state(data, FAILURE);
     603           0 :                 return NULL;
     604             :         }
     605          19 :         if (pos != end) {
     606           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
     607             :                            "data in the end of GPSK-2",
     608           0 :                            (unsigned long) (end - pos));
     609             :         }
     610             : 
     611          19 :         resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData));
     612          19 :         if (resp == NULL)
     613           0 :                 return NULL;
     614             : 
     615          19 :         eap_gpsk_state(data, SUCCESS);
     616          19 :         ret->methodState = METHOD_DONE;
     617          19 :         ret->decision = DECISION_UNCOND_SUCC;
     618             : 
     619          19 :         return resp;
     620             : }
     621             : 
     622             : 
     623          19 : static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
     624             :                                             u8 identifier)
     625             : {
     626             :         struct wpabuf *resp;
     627             :         u8 *rpos, *start;
     628             :         size_t mlen;
     629             : 
     630          19 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
     631             : 
     632          19 :         mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
     633             : 
     634          19 :         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
     635             :                              EAP_CODE_RESPONSE, identifier);
     636          19 :         if (resp == NULL)
     637           0 :                 return NULL;
     638             : 
     639          19 :         wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
     640          19 :         start = wpabuf_put(resp, 0);
     641             : 
     642             :         /* No PD_Payload_3 */
     643          19 :         wpabuf_put_be16(resp, 0);
     644             : 
     645          19 :         rpos = wpabuf_put(resp, mlen);
     646          19 :         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
     647          19 :                                  data->specifier, start, rpos - start, rpos) <
     648             :             0) {
     649           0 :                 eap_gpsk_state(data, FAILURE);
     650           0 :                 wpabuf_free(resp);
     651           0 :                 return NULL;
     652             :         }
     653             : 
     654          19 :         return resp;
     655             : }
     656             : 
     657             : 
     658          40 : static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
     659             :                                         struct eap_method_ret *ret,
     660             :                                         const struct wpabuf *reqData)
     661             : {
     662          40 :         struct eap_gpsk_data *data = priv;
     663             :         struct wpabuf *resp;
     664             :         const u8 *pos;
     665             :         size_t len;
     666             : 
     667          40 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
     668          40 :         if (pos == NULL || len < 1) {
     669           0 :                 ret->ignore = TRUE;
     670           0 :                 return NULL;
     671             :         }
     672             : 
     673          40 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
     674             : 
     675          40 :         ret->ignore = FALSE;
     676          40 :         ret->methodState = METHOD_MAY_CONT;
     677          40 :         ret->decision = DECISION_FAIL;
     678          40 :         ret->allowNotifications = FALSE;
     679             : 
     680          40 :         switch (*pos) {
     681             :         case EAP_GPSK_OPCODE_GPSK_1:
     682          21 :                 resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
     683             :                                                pos + 1, len - 1);
     684          21 :                 break;
     685             :         case EAP_GPSK_OPCODE_GPSK_3:
     686          19 :                 resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
     687             :                                                pos + 1, len - 1);
     688          19 :                 break;
     689             :         default:
     690           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
     691           0 :                            "unknown opcode %d", *pos);
     692           0 :                 ret->ignore = TRUE;
     693           0 :                 return NULL;
     694             :         }
     695             : 
     696          40 :         return resp;
     697             : }
     698             : 
     699             : 
     700          40 : static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
     701             : {
     702          40 :         struct eap_gpsk_data *data = priv;
     703          40 :         return data->state == SUCCESS;
     704             : }
     705             : 
     706             : 
     707          19 : static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
     708             : {
     709          19 :         struct eap_gpsk_data *data = priv;
     710             :         u8 *key;
     711             : 
     712          19 :         if (data->state != SUCCESS)
     713           0 :                 return NULL;
     714             : 
     715          19 :         key = os_malloc(EAP_MSK_LEN);
     716          19 :         if (key == NULL)
     717           0 :                 return NULL;
     718          19 :         os_memcpy(key, data->msk, EAP_MSK_LEN);
     719          19 :         *len = EAP_MSK_LEN;
     720             : 
     721          19 :         return key;
     722             : }
     723             : 
     724             : 
     725           0 : static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
     726             : {
     727           0 :         struct eap_gpsk_data *data = priv;
     728             :         u8 *key;
     729             : 
     730           0 :         if (data->state != SUCCESS)
     731           0 :                 return NULL;
     732             : 
     733           0 :         key = os_malloc(EAP_EMSK_LEN);
     734           0 :         if (key == NULL)
     735           0 :                 return NULL;
     736           0 :         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
     737           0 :         *len = EAP_EMSK_LEN;
     738             : 
     739           0 :         return key;
     740             : }
     741             : 
     742             : 
     743          19 : static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
     744             : {
     745          19 :         struct eap_gpsk_data *data = priv;
     746             :         u8 *sid;
     747             : 
     748          19 :         if (data->state != SUCCESS)
     749           0 :                 return NULL;
     750             : 
     751          19 :         sid = os_malloc(data->id_len);
     752          19 :         if (sid == NULL)
     753           0 :                 return NULL;
     754          19 :         os_memcpy(sid, data->session_id, data->id_len);
     755          19 :         *len = data->id_len;
     756             : 
     757          19 :         return sid;
     758             : }
     759             : 
     760             : 
     761           4 : int eap_peer_gpsk_register(void)
     762             : {
     763             :         struct eap_method *eap;
     764             :         int ret;
     765             : 
     766           4 :         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
     767             :                                     EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
     768           4 :         if (eap == NULL)
     769           0 :                 return -1;
     770             : 
     771           4 :         eap->init = eap_gpsk_init;
     772           4 :         eap->deinit = eap_gpsk_deinit;
     773           4 :         eap->process = eap_gpsk_process;
     774           4 :         eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
     775           4 :         eap->getKey = eap_gpsk_getKey;
     776           4 :         eap->get_emsk = eap_gpsk_get_emsk;
     777           4 :         eap->getSessionId = eap_gpsk_get_session_id;
     778             : 
     779           4 :         ret = eap_peer_method_register(eap);
     780           4 :         if (ret)
     781           0 :                 eap_peer_method_free(eap);
     782           4 :         return ret;
     783             : }

Generated by: LCOV version 1.10