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