OSDN Git Service

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