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