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 1422976643 Lines: 363 402 90.3 %
Date: 2015-02-03 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        1138 : static const char * eap_gpsk_state_txt(int state)
      50             : {
      51        1138 :         switch (state) {
      52             :         case GPSK_1:
      53         293 :                 return "GPSK-1";
      54             :         case GPSK_3:
      55         559 :                 return "GPSK-3";
      56             :         case SUCCESS:
      57         262 :                 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         569 : static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
      68             : {
      69        1138 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
      70         569 :                    eap_gpsk_state_txt(data->state),
      71             :                    eap_gpsk_state_txt(state));
      72         569 :         data->state = state;
      73         569 : }
      74             : 
      75             : 
      76             : static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
      77             : 
      78             : 
      79         296 : 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         296 :         password = eap_get_config_password(sm, &password_len);
      87         296 :         if (password == NULL) {
      88           0 :                 wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
      89           0 :                 return NULL;
      90             :         }
      91             : 
      92         296 :         data = os_zalloc(sizeof(*data));
      93         296 :         if (data == NULL)
      94           0 :                 return NULL;
      95         296 :         data->state = GPSK_1;
      96             : 
      97         296 :         identity = eap_get_config_identity(sm, &identity_len);
      98         296 :         if (identity) {
      99         296 :                 data->id_peer = os_malloc(identity_len);
     100         296 :                 if (data->id_peer == NULL) {
     101           0 :                         eap_gpsk_deinit(sm, data);
     102           0 :                         return NULL;
     103             :                 }
     104         296 :                 os_memcpy(data->id_peer, identity, identity_len);
     105         296 :                 data->id_peer_len = identity_len;
     106             :         }
     107             : 
     108         296 :         phase1 = eap_get_config_phase1(sm);
     109         296 :         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         296 :         data->psk = os_malloc(password_len);
     121         296 :         if (data->psk == NULL) {
     122           0 :                 eap_gpsk_deinit(sm, data);
     123           0 :                 return NULL;
     124             :         }
     125         296 :         os_memcpy(data->psk, password, password_len);
     126         296 :         data->psk_len = password_len;
     127             : 
     128         296 :         return data;
     129             : }
     130             : 
     131             : 
     132         296 : static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
     133             : {
     134         296 :         struct eap_gpsk_data *data = priv;
     135         296 :         os_free(data->id_server);
     136         296 :         os_free(data->id_peer);
     137         296 :         if (data->psk) {
     138         296 :                 os_memset(data->psk, 0, data->psk_len);
     139         296 :                 os_free(data->psk);
     140             :         }
     141         296 :         bin_clear_free(data, sizeof(*data));
     142         296 : }
     143             : 
     144             : 
     145         293 : 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         293 :         if (end - pos < 2) {
     151           1 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
     152           1 :                 return NULL;
     153             :         }
     154         292 :         alen = WPA_GET_BE16(pos);
     155         292 :         pos += 2;
     156         292 :         if (end - pos < alen) {
     157           1 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
     158           1 :                 return NULL;
     159             :         }
     160         291 :         os_free(data->id_server);
     161         291 :         data->id_server = os_malloc(alen);
     162         291 :         if (data->id_server == NULL) {
     163           0 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
     164           0 :                 return NULL;
     165             :         }
     166         291 :         os_memcpy(data->id_server, pos, alen);
     167         291 :         data->id_server_len = alen;
     168         582 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
     169         291 :                           data->id_server, data->id_server_len);
     170         291 :         pos += alen;
     171             : 
     172         291 :         return pos;
     173             : }
     174             : 
     175             : 
     176         293 : static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
     177             :                                                const u8 *pos, const u8 *end)
     178             : {
     179         293 :         if (pos == NULL)
     180           2 :                 return NULL;
     181             : 
     182         291 :         if (end - pos < EAP_GPSK_RAND_LEN) {
     183           1 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
     184           1 :                 return NULL;
     185             :         }
     186         290 :         os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
     187         290 :         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
     188         290 :                     data->rand_server, EAP_GPSK_RAND_LEN);
     189         290 :         pos += EAP_GPSK_RAND_LEN;
     190             : 
     191         290 :         return pos;
     192             : }
     193             : 
     194             : 
     195         286 : 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         286 :         count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
     204         286 :         data->vendor = EAP_GPSK_VENDOR_IETF;
     205         286 :         data->specifier = EAP_GPSK_CIPHER_RESERVED;
     206         286 :         csuite = (struct eap_gpsk_csuite *) csuite_list;
     207         841 :         for (i = 0; i < count; i++) {
     208             :                 int vendor, specifier;
     209         555 :                 vendor = WPA_GET_BE32(csuite->vendor);
     210         555 :                 specifier = WPA_GET_BE16(csuite->specifier);
     211         555 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
     212             :                            i, vendor, specifier);
     213        1110 :                 if (data->vendor == EAP_GPSK_VENDOR_IETF &&
     214         843 :                     data->specifier == EAP_GPSK_CIPHER_RESERVED &&
     215         575 :                     eap_gpsk_supported_ciphersuite(vendor, specifier) &&
     216         292 :                     (!data->forced_cipher || data->forced_cipher == specifier))
     217             :                 {
     218         284 :                         data->vendor = vendor;
     219         284 :                         data->specifier = specifier;
     220             :                 }
     221         555 :                 csuite++;
     222             :         }
     223         572 :         if (data->vendor == EAP_GPSK_VENDOR_IETF &&
     224         286 :             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         284 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
     230             :                    data->vendor, data->specifier);
     231             : 
     232         284 :         return 0;
     233             : }
     234             : 
     235             : 
     236         293 : 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         293 :         if (pos == NULL)
     245           3 :                 return NULL;
     246             : 
     247         290 :         if (end - pos < 2) {
     248           1 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
     249           1 :                 return NULL;
     250             :         }
     251         289 :         len = WPA_GET_BE16(pos);
     252         289 :         pos += 2;
     253         289 :         if (len > (size_t) (end - pos)) {
     254           1 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
     255           1 :                 return NULL;
     256             :         }
     257         288 :         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         286 :         if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
     264           2 :                 return NULL;
     265             : 
     266         284 :         *list = pos;
     267         284 :         *list_len = len;
     268         284 :         pos += len;
     269             : 
     270         284 :         return pos;
     271             : }
     272             : 
     273             : 
     274         294 : 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             :                                                const struct wpabuf *reqData,
     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         294 :         if (data->state != GPSK_1) {
     286           1 :                 ret->ignore = TRUE;
     287           1 :                 return NULL;
     288             :         }
     289             : 
     290         293 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
     291             : 
     292         293 :         end = payload + payload_len;
     293             : 
     294         293 :         pos = eap_gpsk_process_id_server(data, payload, end);
     295         293 :         pos = eap_gpsk_process_rand_server(data, pos, end);
     296         293 :         pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
     297             :                                            &csuite_list_len, pos, end);
     298         293 :         if (pos == NULL) {
     299           9 :                 ret->methodState = METHOD_DONE;
     300           9 :                 eap_gpsk_state(data, FAILURE);
     301           9 :                 return NULL;
     302             :         }
     303             : 
     304         284 :         resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData),
     305             :                                     csuite_list, csuite_list_len);
     306         284 :         if (resp == NULL)
     307           1 :                 return NULL;
     308             : 
     309         283 :         eap_gpsk_state(data, GPSK_3);
     310             : 
     311         283 :         return resp;
     312             : }
     313             : 
     314             : 
     315         284 : 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         284 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
     326             : 
     327         284 :         miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
     328         568 :         len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
     329         284 :                 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
     330         284 :                 sizeof(struct eap_gpsk_csuite) + 2 + miclen;
     331             : 
     332         284 :         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
     333             :                              EAP_CODE_RESPONSE, identifier);
     334         284 :         if (resp == NULL)
     335           0 :                 return NULL;
     336             : 
     337         284 :         wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
     338         284 :         start = wpabuf_put(resp, 0);
     339             : 
     340         568 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
     341         284 :                           data->id_peer, data->id_peer_len);
     342         284 :         wpabuf_put_be16(resp, data->id_peer_len);
     343         284 :         wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
     344             : 
     345         284 :         wpabuf_put_be16(resp, data->id_server_len);
     346         284 :         wpabuf_put_data(resp, data->id_server, data->id_server_len);
     347             : 
     348         284 :         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         284 :         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
     356         284 :                     data->rand_peer, EAP_GPSK_RAND_LEN);
     357         284 :         wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
     358         284 :         wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
     359             : 
     360         284 :         wpabuf_put_be16(resp, csuite_list_len);
     361         284 :         wpabuf_put_data(resp, csuite_list, csuite_list_len);
     362             : 
     363         284 :         csuite = wpabuf_put(resp, sizeof(*csuite));
     364         284 :         WPA_PUT_BE32(csuite->vendor, data->vendor);
     365         284 :         WPA_PUT_BE16(csuite->specifier, data->specifier);
     366             : 
     367        1420 :         if (eap_gpsk_derive_keys(data->psk, data->psk_len,
     368             :                                  data->vendor, data->specifier,
     369         284 :                                  data->rand_peer, data->rand_server,
     370         284 :                                  data->id_peer, data->id_peer_len,
     371         284 :                                  data->id_server, data->id_server_len,
     372         284 :                                  data->msk, data->emsk,
     373         284 :                                  data->sk, &data->sk_len,
     374         284 :                                  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        1132 :         if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
     382             :                                        data->vendor, data->specifier,
     383         283 :                                        data->rand_peer, data->rand_server,
     384         283 :                                        data->id_peer, data->id_peer_len,
     385         283 :                                        data->id_server, data->id_server_len,
     386             :                                        EAP_TYPE_GPSK,
     387         283 :                                        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         566 :         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
     394         283 :                     data->session_id, data->id_len);
     395             : 
     396             :         /* No PD_Payload_1 */
     397         283 :         wpabuf_put_be16(resp, 0);
     398             : 
     399         283 :         rpos = wpabuf_put(resp, miclen);
     400         283 :         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
     401         283 :                                  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         283 :         return resp;
     409             : }
     410             : 
     411             : 
     412         276 : static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
     413             :                                          const u8 *pos, const u8 *end)
     414             : {
     415         276 :         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         275 :         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         274 :         pos += EAP_GPSK_RAND_LEN;
     430             : 
     431         274 :         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         273 :         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         272 :         pos += EAP_GPSK_RAND_LEN;
     446             : 
     447         272 :         return pos;
     448             : }
     449             : 
     450             : 
     451         276 : 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         276 :         if (pos == NULL)
     457           4 :                 return NULL;
     458             : 
     459         272 :         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         271 :         len = WPA_GET_BE16(pos);
     466         271 :         pos += 2;
     467             : 
     468         271 :         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         539 :         if (len != data->id_server_len ||
     475         269 :             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         268 :         pos += len;
     486             : 
     487         268 :         return pos;
     488             : }
     489             : 
     490             : 
     491         276 : 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         276 :         if (pos == NULL)
     498           8 :                 return NULL;
     499             : 
     500         268 :         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         267 :         csuite = (const struct eap_gpsk_csuite *) pos;
     506         267 :         vendor = WPA_GET_BE32(csuite->vendor);
     507         267 :         specifier = WPA_GET_BE16(csuite->specifier);
     508         267 :         pos += sizeof(*csuite);
     509         267 :         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         266 :         return pos;
     517             : }
     518             : 
     519             : 
     520         276 : 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         276 :         if (pos == NULL)
     526          10 :                 return NULL;
     527             : 
     528         266 :         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         265 :         alen = WPA_GET_BE16(pos);
     534         265 :         pos += 2;
     535         265 :         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         264 :         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
     541         264 :         pos += alen;
     542             : 
     543         264 :         return pos;
     544             : }
     545             : 
     546             : 
     547         276 : 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         276 :         if (pos == NULL)
     555          12 :                 return NULL;
     556             : 
     557         264 :         miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
     558         264 :         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         263 :         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
     566         263 :                                  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         263 :         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         262 :         pos += miclen;
     578             : 
     579         262 :         return pos;
     580             : }
     581             : 
     582             : 
     583         277 : 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             :                                                const struct wpabuf *reqData,
     587             :                                                const u8 *payload,
     588             :                                                size_t payload_len)
     589             : {
     590             :         struct wpabuf *resp;
     591             :         const u8 *pos, *end;
     592             : 
     593         277 :         if (data->state != GPSK_3) {
     594           1 :                 ret->ignore = TRUE;
     595           1 :                 return NULL;
     596             :         }
     597             : 
     598         276 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
     599             : 
     600         276 :         end = payload + payload_len;
     601             : 
     602         276 :         pos = eap_gpsk_validate_rand(data, payload, end);
     603         276 :         pos = eap_gpsk_validate_id_server(data, pos, end);
     604         276 :         pos = eap_gpsk_validate_csuite(data, pos, end);
     605         276 :         pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
     606         276 :         pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
     607             : 
     608         276 :         if (pos == NULL) {
     609          14 :                 eap_gpsk_state(data, FAILURE);
     610          14 :                 return NULL;
     611             :         }
     612         262 :         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         262 :         resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData));
     619         262 :         if (resp == NULL)
     620           0 :                 return NULL;
     621             : 
     622         262 :         eap_gpsk_state(data, SUCCESS);
     623         262 :         ret->methodState = METHOD_DONE;
     624         262 :         ret->decision = DECISION_UNCOND_SUCC;
     625             : 
     626         262 :         return resp;
     627             : }
     628             : 
     629             : 
     630         262 : 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         262 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
     638             : 
     639         262 :         mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
     640             : 
     641         262 :         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
     642             :                              EAP_CODE_RESPONSE, identifier);
     643         262 :         if (resp == NULL)
     644           0 :                 return NULL;
     645             : 
     646         262 :         wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
     647         262 :         start = wpabuf_put(resp, 0);
     648             : 
     649             :         /* No PD_Payload_3 */
     650         262 :         wpabuf_put_be16(resp, 0);
     651             : 
     652         262 :         rpos = wpabuf_put(resp, mlen);
     653         262 :         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
     654         262 :                                  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         262 :         return resp;
     662             : }
     663             : 
     664             : 
     665         573 : 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         573 :         struct eap_gpsk_data *data = priv;
     670             :         struct wpabuf *resp;
     671             :         const u8 *pos;
     672             :         size_t len;
     673             : 
     674         573 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
     675         573 :         if (pos == NULL || len < 1) {
     676           1 :                 ret->ignore = TRUE;
     677           1 :                 return NULL;
     678             :         }
     679             : 
     680         572 :         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
     681             : 
     682         572 :         ret->ignore = FALSE;
     683         572 :         ret->methodState = METHOD_MAY_CONT;
     684         572 :         ret->decision = DECISION_FAIL;
     685         572 :         ret->allowNotifications = FALSE;
     686             : 
     687         572 :         switch (*pos) {
     688             :         case EAP_GPSK_OPCODE_GPSK_1:
     689         294 :                 resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
     690             :                                                pos + 1, len - 1);
     691         294 :                 break;
     692             :         case EAP_GPSK_OPCODE_GPSK_3:
     693         277 :                 resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
     694             :                                                pos + 1, len - 1);
     695         277 :                 break;
     696             :         default:
     697           1 :                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
     698           1 :                            "unknown opcode %d", *pos);
     699           1 :                 ret->ignore = TRUE;
     700           1 :                 return NULL;
     701             :         }
     702             : 
     703         571 :         return resp;
     704             : }
     705             : 
     706             : 
     707         569 : static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
     708             : {
     709         569 :         struct eap_gpsk_data *data = priv;
     710         569 :         return data->state == SUCCESS;
     711             : }
     712             : 
     713             : 
     714         262 : static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
     715             : {
     716         262 :         struct eap_gpsk_data *data = priv;
     717             :         u8 *key;
     718             : 
     719         262 :         if (data->state != SUCCESS)
     720           0 :                 return NULL;
     721             : 
     722         262 :         key = os_malloc(EAP_MSK_LEN);
     723         262 :         if (key == NULL)
     724           0 :                 return NULL;
     725         262 :         os_memcpy(key, data->msk, EAP_MSK_LEN);
     726         262 :         *len = EAP_MSK_LEN;
     727             : 
     728         262 :         return key;
     729             : }
     730             : 
     731             : 
     732           1 : static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
     733             : {
     734           1 :         struct eap_gpsk_data *data = priv;
     735             :         u8 *key;
     736             : 
     737           1 :         if (data->state != SUCCESS)
     738           0 :                 return NULL;
     739             : 
     740           1 :         key = os_malloc(EAP_EMSK_LEN);
     741           1 :         if (key == NULL)
     742           0 :                 return NULL;
     743           1 :         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
     744           1 :         *len = EAP_EMSK_LEN;
     745             : 
     746           1 :         return key;
     747             : }
     748             : 
     749             : 
     750         262 : static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
     751             : {
     752         262 :         struct eap_gpsk_data *data = priv;
     753             :         u8 *sid;
     754             : 
     755         262 :         if (data->state != SUCCESS)
     756           0 :                 return NULL;
     757             : 
     758         262 :         sid = os_malloc(data->id_len);
     759         262 :         if (sid == NULL)
     760           0 :                 return NULL;
     761         262 :         os_memcpy(sid, data->session_id, data->id_len);
     762         262 :         *len = data->id_len;
     763             : 
     764         262 :         return sid;
     765             : }
     766             : 
     767             : 
     768          30 : int eap_peer_gpsk_register(void)
     769             : {
     770             :         struct eap_method *eap;
     771             :         int ret;
     772             : 
     773          30 :         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
     774             :                                     EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
     775          30 :         if (eap == NULL)
     776           0 :                 return -1;
     777             : 
     778          30 :         eap->init = eap_gpsk_init;
     779          30 :         eap->deinit = eap_gpsk_deinit;
     780          30 :         eap->process = eap_gpsk_process;
     781          30 :         eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
     782          30 :         eap->getKey = eap_gpsk_getKey;
     783          30 :         eap->get_emsk = eap_gpsk_get_emsk;
     784          30 :         eap->getSessionId = eap_gpsk_get_session_id;
     785             : 
     786          30 :         ret = eap_peer_method_register(eap);
     787          30 :         if (ret)
     788           0 :                 eap_peer_method_free(eap);
     789          30 :         return ret;
     790             : }

Generated by: LCOV version 1.10