Merge branch 'vendor/OPENSSL'
[dragonfly.git] / contrib / hostapd / src / eap_server / eap_server_gpsk.c
1 /*
2  * hostapd / EAP-GPSK (RFC 5433) server
3  * Copyright (c) 2006-2007, 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_server/eap_i.h"
14 #include "eap_common/eap_gpsk_common.h"
15
16
17 struct eap_gpsk_data {
18         enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
19         u8 rand_server[EAP_GPSK_RAND_LEN];
20         u8 rand_peer[EAP_GPSK_RAND_LEN];
21         u8 msk[EAP_MSK_LEN];
22         u8 emsk[EAP_EMSK_LEN];
23         u8 sk[EAP_GPSK_MAX_SK_LEN];
24         size_t sk_len;
25         u8 pk[EAP_GPSK_MAX_PK_LEN];
26         size_t pk_len;
27         u8 *id_peer;
28         size_t id_peer_len;
29 #define MAX_NUM_CSUITES 2
30         struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES];
31         size_t csuite_count;
32         int vendor; /* CSuite/Vendor */
33         int specifier; /* CSuite/Specifier */
34 };
35
36
37 static const char * eap_gpsk_state_txt(int state)
38 {
39         switch (state) {
40         case GPSK_1:
41                 return "GPSK-1";
42         case GPSK_3:
43                 return "GPSK-3";
44         case SUCCESS:
45                 return "SUCCESS";
46         case FAILURE:
47                 return "FAILURE";
48         default:
49                 return "?";
50         }
51 }
52
53
54 static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
55 {
56         wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
57                    eap_gpsk_state_txt(data->state),
58                    eap_gpsk_state_txt(state));
59         data->state = state;
60 }
61
62
63 static void * eap_gpsk_init(struct eap_sm *sm)
64 {
65         struct eap_gpsk_data *data;
66
67         data = os_zalloc(sizeof(*data));
68         if (data == NULL)
69                 return NULL;
70         data->state = GPSK_1;
71
72         data->csuite_count = 0;
73         if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
74                                            EAP_GPSK_CIPHER_AES)) {
75                 WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
76                              EAP_GPSK_VENDOR_IETF);
77                 WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
78                              EAP_GPSK_CIPHER_AES);
79                 data->csuite_count++;
80         }
81         if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
82                                            EAP_GPSK_CIPHER_SHA256)) {
83                 WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
84                              EAP_GPSK_VENDOR_IETF);
85                 WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
86                              EAP_GPSK_CIPHER_SHA256);
87                 data->csuite_count++;
88         }
89
90         return data;
91 }
92
93
94 static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
95 {
96         struct eap_gpsk_data *data = priv;
97         os_free(data->id_peer);
98         os_free(data);
99 }
100
101
102 static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
103                                              struct eap_gpsk_data *data, u8 id)
104 {
105         size_t len;
106         struct wpabuf *req;
107
108         wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1");
109
110         if (random_get_bytes(data->rand_server, EAP_GPSK_RAND_LEN)) {
111                 wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data");
112                 eap_gpsk_state(data, FAILURE);
113                 return NULL;
114         }
115         wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
116                     data->rand_server, EAP_GPSK_RAND_LEN);
117
118         len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 +
119                 data->csuite_count * sizeof(struct eap_gpsk_csuite);
120         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
121                             EAP_CODE_REQUEST, id);
122         if (req == NULL) {
123                 wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
124                            "for request/GPSK-1");
125                 eap_gpsk_state(data, FAILURE);
126                 return NULL;
127         }
128
129         wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
130         wpabuf_put_be16(req, sm->server_id_len);
131         wpabuf_put_data(req, sm->server_id, sm->server_id_len);
132         wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
133         wpabuf_put_be16(req,
134                         data->csuite_count * sizeof(struct eap_gpsk_csuite));
135         wpabuf_put_data(req, data->csuite_list,
136                         data->csuite_count * sizeof(struct eap_gpsk_csuite));
137
138         return req;
139 }
140
141
142 static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
143                                              struct eap_gpsk_data *data, u8 id)
144 {
145         u8 *pos, *start;
146         size_t len, miclen;
147         struct eap_gpsk_csuite *csuite;
148         struct wpabuf *req;
149
150         wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
151
152         miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
153         len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len +
154                 sizeof(struct eap_gpsk_csuite) + 2 + miclen;
155         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
156                             EAP_CODE_REQUEST, id);
157         if (req == NULL) {
158                 wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
159                            "for request/GPSK-3");
160                 eap_gpsk_state(data, FAILURE);
161                 return NULL;
162         }
163
164         wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3);
165         start = wpabuf_put(req, 0);
166
167         wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
168         wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
169         wpabuf_put_be16(req, sm->server_id_len);
170         wpabuf_put_data(req, sm->server_id, sm->server_id_len);
171         csuite = wpabuf_put(req, sizeof(*csuite));
172         WPA_PUT_BE32(csuite->vendor, data->vendor);
173         WPA_PUT_BE16(csuite->specifier, data->specifier);
174
175         /* no PD_Payload_2 */
176         wpabuf_put_be16(req, 0);
177
178         pos = wpabuf_put(req, miclen);
179         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
180                                  data->specifier, start, pos - start, pos) < 0)
181         {
182                 os_free(req);
183                 eap_gpsk_state(data, FAILURE);
184                 return NULL;
185         }
186
187         return req;
188 }
189
190
191 static struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id)
192 {
193         struct eap_gpsk_data *data = priv;
194
195         switch (data->state) {
196         case GPSK_1:
197                 return eap_gpsk_build_gpsk_1(sm, data, id);
198         case GPSK_3:
199                 return eap_gpsk_build_gpsk_3(sm, data, id);
200         default:
201                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq",
202                            data->state);
203                 break;
204         }
205         return NULL;
206 }
207
208
209 static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv,
210                               struct wpabuf *respData)
211 {
212         struct eap_gpsk_data *data = priv;
213         const u8 *pos;
214         size_t len;
215
216         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
217         if (pos == NULL || len < 1) {
218                 wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame");
219                 return TRUE;
220         }
221
222         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos);
223
224         if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2)
225                 return FALSE;
226
227         if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4)
228                 return FALSE;
229
230         wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d",
231                    *pos, data->state);
232
233         return TRUE;
234 }
235
236
237 static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
238                                     struct eap_gpsk_data *data,
239                                     const u8 *payload, size_t payloadlen)
240 {
241         const u8 *pos, *end;
242         u16 alen;
243         const struct eap_gpsk_csuite *csuite;
244         size_t i, miclen;
245         u8 mic[EAP_GPSK_MAX_MIC_LEN];
246
247         if (data->state != GPSK_1)
248                 return;
249
250         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2");
251
252         pos = payload;
253         end = payload + payloadlen;
254
255         if (end - pos < 2) {
256                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
257                            "ID_Peer length");
258                 eap_gpsk_state(data, FAILURE);
259                 return;
260         }
261         alen = WPA_GET_BE16(pos);
262         pos += 2;
263         if (end - pos < alen) {
264                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
265                            "ID_Peer");
266                 eap_gpsk_state(data, FAILURE);
267                 return;
268         }
269         os_free(data->id_peer);
270         data->id_peer = os_malloc(alen);
271         if (data->id_peer == NULL) {
272                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store "
273                            "%d-octet ID_Peer", alen);
274                 return;
275         }
276         os_memcpy(data->id_peer, pos, alen);
277         data->id_peer_len = alen;
278         wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
279                           data->id_peer, data->id_peer_len);
280         pos += alen;
281
282         if (end - pos < 2) {
283                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
284                            "ID_Server length");
285                 eap_gpsk_state(data, FAILURE);
286                 return;
287         }
288         alen = WPA_GET_BE16(pos);
289         pos += 2;
290         if (end - pos < alen) {
291                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
292                            "ID_Server");
293                 eap_gpsk_state(data, FAILURE);
294                 return;
295         }
296         if (alen != sm->server_id_len ||
297             os_memcmp(pos, sm->server_id, alen) != 0) {
298                 wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
299                            "GPSK-2 did not match");
300                 eap_gpsk_state(data, FAILURE);
301                 return;
302         }
303         pos += alen;
304
305         if (end - pos < EAP_GPSK_RAND_LEN) {
306                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
307                            "RAND_Peer");
308                 eap_gpsk_state(data, FAILURE);
309                 return;
310         }
311         os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN);
312         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
313                     data->rand_peer, EAP_GPSK_RAND_LEN);
314         pos += EAP_GPSK_RAND_LEN;
315
316         if (end - pos < EAP_GPSK_RAND_LEN) {
317                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
318                            "RAND_Server");
319                 eap_gpsk_state(data, FAILURE);
320                 return;
321         }
322         if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) {
323                 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
324                            "GPSK-2 did not match");
325                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
326                             data->rand_server, EAP_GPSK_RAND_LEN);
327                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2",
328                             pos, EAP_GPSK_RAND_LEN);
329                 eap_gpsk_state(data, FAILURE);
330                 return;
331         }
332         pos += EAP_GPSK_RAND_LEN;
333
334         if (end - pos < 2) {
335                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
336                            "CSuite_List length");
337                 eap_gpsk_state(data, FAILURE);
338                 return;
339         }
340         alen = WPA_GET_BE16(pos);
341         pos += 2;
342         if (end - pos < alen) {
343                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
344                            "CSuite_List");
345                 eap_gpsk_state(data, FAILURE);
346                 return;
347         }
348         if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) ||
349             os_memcmp(pos, data->csuite_list, alen) != 0) {
350                 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and "
351                            "GPSK-2 did not match");
352                 eap_gpsk_state(data, FAILURE);
353                 return;
354         }
355         pos += alen;
356
357         if (end - pos < (int) sizeof(*csuite)) {
358                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
359                            "CSuite_Sel");
360                 eap_gpsk_state(data, FAILURE);
361                 return;
362         }
363         csuite = (const struct eap_gpsk_csuite *) pos;
364         for (i = 0; i < data->csuite_count; i++) {
365                 if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite))
366                     == 0)
367                         break;
368         }
369         if (i == data->csuite_count) {
370                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
371                            "ciphersuite %d:%d",
372                            WPA_GET_BE32(csuite->vendor),
373                            WPA_GET_BE16(csuite->specifier));
374                 eap_gpsk_state(data, FAILURE);
375                 return;
376         }
377         data->vendor = WPA_GET_BE32(csuite->vendor);
378         data->specifier = WPA_GET_BE16(csuite->specifier);
379         wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
380                    data->vendor, data->specifier);
381         pos += sizeof(*csuite); 
382
383         if (end - pos < 2) {
384                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
385                            "PD_Payload_1 length");
386                 eap_gpsk_state(data, FAILURE);
387                 return;
388         }
389         alen = WPA_GET_BE16(pos);
390         pos += 2;
391         if (end - pos < alen) {
392                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
393                            "PD_Payload_1");
394                 eap_gpsk_state(data, FAILURE);
395                 return;
396         }
397         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
398         pos += alen;
399
400         if (sm->user == NULL || sm->user->password == NULL) {
401                 wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured "
402                            "for the user");
403                 eap_gpsk_state(data, FAILURE);
404                 return;
405         }
406
407         if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len,
408                                  data->vendor, data->specifier,
409                                  data->rand_peer, data->rand_server,
410                                  data->id_peer, data->id_peer_len,
411                                  sm->server_id, sm->server_id_len,
412                                  data->msk, data->emsk,
413                                  data->sk, &data->sk_len,
414                                  data->pk, &data->pk_len) < 0) {
415                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
416                 eap_gpsk_state(data, FAILURE);
417                 return;
418         }
419
420         miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
421         if (end - pos < (int) miclen) {
422                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
423                            "(left=%lu miclen=%lu)",
424                            (unsigned long) (end - pos),
425                            (unsigned long) miclen);
426                 eap_gpsk_state(data, FAILURE);
427                 return;
428         }
429         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
430                                  data->specifier, payload, pos - payload, mic)
431             < 0) {
432                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
433                 eap_gpsk_state(data, FAILURE);
434                 return;
435         }
436         if (os_memcmp(mic, pos, miclen) != 0) {
437                 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
438                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
439                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
440                 eap_gpsk_state(data, FAILURE);
441                 return;
442         }
443         pos += miclen;
444
445         if (pos != end) {
446                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
447                            "data in the end of GPSK-2",
448                            (unsigned long) (end - pos));
449         }
450
451         eap_gpsk_state(data, GPSK_3);
452 }
453
454
455 static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
456                                     struct eap_gpsk_data *data,
457                                     const u8 *payload, size_t payloadlen)
458 {
459         const u8 *pos, *end;
460         u16 alen;
461         size_t miclen;
462         u8 mic[EAP_GPSK_MAX_MIC_LEN];
463
464         if (data->state != GPSK_3)
465                 return;
466
467         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4");
468
469         pos = payload;
470         end = payload + payloadlen;
471
472         if (end - pos < 2) {
473                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
474                            "PD_Payload_1 length");
475                 eap_gpsk_state(data, FAILURE);
476                 return;
477         }
478         alen = WPA_GET_BE16(pos);
479         pos += 2;
480         if (end - pos < alen) {
481                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
482                            "PD_Payload_1");
483                 eap_gpsk_state(data, FAILURE);
484                 return;
485         }
486         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
487         pos += alen;
488
489         miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
490         if (end - pos < (int) miclen) {
491                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
492                            "(left=%lu miclen=%lu)",
493                            (unsigned long) (end - pos),
494                            (unsigned long) miclen);
495                 eap_gpsk_state(data, FAILURE);
496                 return;
497         }
498         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
499                                  data->specifier, payload, pos - payload, mic)
500             < 0) {
501                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
502                 eap_gpsk_state(data, FAILURE);
503                 return;
504         }
505         if (os_memcmp(mic, pos, miclen) != 0) {
506                 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
507                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
508                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
509                 eap_gpsk_state(data, FAILURE);
510                 return;
511         }
512         pos += miclen;
513
514         if (pos != end) {
515                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
516                            "data in the end of GPSK-4",
517                            (unsigned long) (end - pos));
518         }
519
520         eap_gpsk_state(data, SUCCESS);
521 }
522
523
524 static void eap_gpsk_process(struct eap_sm *sm, void *priv,
525                              struct wpabuf *respData)
526 {
527         struct eap_gpsk_data *data = priv;
528         const u8 *pos;
529         size_t len;
530
531         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
532         if (pos == NULL || len < 1)
533                 return;
534
535         switch (*pos) {
536         case EAP_GPSK_OPCODE_GPSK_2:
537                 eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1);
538                 break;
539         case EAP_GPSK_OPCODE_GPSK_4:
540                 eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1);
541                 break;
542         }
543 }
544
545
546 static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv)
547 {
548         struct eap_gpsk_data *data = priv;
549         return data->state == SUCCESS || data->state == FAILURE;
550 }
551
552
553 static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
554 {
555         struct eap_gpsk_data *data = priv;
556         u8 *key;
557
558         if (data->state != SUCCESS)
559                 return NULL;
560
561         key = os_malloc(EAP_MSK_LEN);
562         if (key == NULL)
563                 return NULL;
564         os_memcpy(key, data->msk, EAP_MSK_LEN);
565         *len = EAP_MSK_LEN;
566
567         return key;
568 }
569
570
571 static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
572 {
573         struct eap_gpsk_data *data = priv;
574         u8 *key;
575
576         if (data->state != SUCCESS)
577                 return NULL;
578
579         key = os_malloc(EAP_EMSK_LEN);
580         if (key == NULL)
581                 return NULL;
582         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
583         *len = EAP_EMSK_LEN;
584
585         return key;
586 }
587
588
589 static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
590 {
591         struct eap_gpsk_data *data = priv;
592         return data->state == SUCCESS;
593 }
594
595
596 int eap_server_gpsk_register(void)
597 {
598         struct eap_method *eap;
599         int ret;
600
601         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
602                                       EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
603         if (eap == NULL)
604                 return -1;
605
606         eap->init = eap_gpsk_init;
607         eap->reset = eap_gpsk_reset;
608         eap->buildReq = eap_gpsk_buildReq;
609         eap->check = eap_gpsk_check;
610         eap->process = eap_gpsk_process;
611         eap->isDone = eap_gpsk_isDone;
612         eap->getKey = eap_gpsk_getKey;
613         eap->isSuccess = eap_gpsk_isSuccess;
614         eap->get_emsk = eap_gpsk_get_emsk;
615
616         ret = eap_server_method_register(eap);
617         if (ret)
618                 eap_server_method_free(eap);
619         return ret;
620 }