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 1443382998 Lines: 365 404 90.3 %
Date: 2015-09-27 Functions: 23 23 100.0 %

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

Generated by: LCOV version 1.10