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