]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/hostapd/eap_gpsk.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / contrib / hostapd / eap_gpsk.c
1 /*
2  * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-08.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_peer[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_peer;
34         size_t id_peer_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_BE32(data->csuite_list[data->csuite_count].vendor,
89                              EAP_GPSK_VENDOR_IETF);
90                 WPA_PUT_BE16(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_BE32(data->csuite_list[data->csuite_count].vendor,
97                              EAP_GPSK_VENDOR_IETF);
98                 WPA_PUT_BE16(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_peer);
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 + 2 + data->id_server_len +
178                 sizeof(struct eap_gpsk_csuite) + 2 + 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_peer, 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         WPA_PUT_BE16(pos, data->id_server_len);
196         pos += 2;
197         if (data->id_server)
198                 memcpy(pos, data->id_server, data->id_server_len);
199         pos += data->id_server_len;
200         csuite = (struct eap_gpsk_csuite *) pos;
201         WPA_PUT_BE32(csuite->vendor, data->vendor);
202         WPA_PUT_BE16(csuite->specifier, data->specifier);
203         pos += sizeof(*csuite);
204
205         /* no PD_Payload_2 */
206         WPA_PUT_BE16(pos, 0);
207         pos += 2;
208
209         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
210                                  data->specifier, start, pos - start, pos) < 0)
211         {
212                 free(req);
213                 eap_gpsk_state(data, FAILURE);
214                 return NULL;
215         }
216
217         return (u8 *) req;
218 }
219
220
221 static u8 * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, int id,
222                               size_t *reqDataLen)
223 {
224         struct eap_gpsk_data *data = priv;
225
226         switch (data->state) {
227         case GPSK_1:
228                 return eap_gpsk_build_gpsk_1(sm, data, id, reqDataLen);
229         case GPSK_3:
230                 return eap_gpsk_build_gpsk_3(sm, data, id, reqDataLen);
231         default:
232                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq",
233                            data->state);
234                 break;
235         }
236         return NULL;
237 }
238
239
240 static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv,
241                               u8 *respData, size_t respDataLen)
242 {
243         struct eap_gpsk_data *data = priv;
244         const u8 *pos;
245         size_t len;
246
247         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK,
248                                respData, respDataLen, &len);
249         if (pos == NULL || len < 1) {
250                 wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame");
251                 return TRUE;
252         }
253
254         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos);
255
256         if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2)
257                 return FALSE;
258
259         if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4)
260                 return FALSE;
261
262         wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d",
263                    *pos, data->state);
264
265         return TRUE;
266 }
267
268
269 static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
270                                     struct eap_gpsk_data *data,
271                                     u8 *respData, size_t respDataLen,
272                                     const u8 *payload, size_t payloadlen)
273 {
274         const u8 *pos, *end;
275         u16 alen;
276         const struct eap_gpsk_csuite *csuite;
277         size_t i, miclen;
278         u8 mic[EAP_GPSK_MAX_MIC_LEN];
279
280         if (data->state != GPSK_1)
281                 return;
282
283         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2");
284
285         pos = payload;
286         end = payload + payloadlen;
287
288         if (end - pos < 2) {
289                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
290                            "ID_Peer length");
291                 eap_gpsk_state(data, FAILURE);
292                 return;
293         }
294         alen = WPA_GET_BE16(pos);
295         pos += 2;
296         if (end - pos < alen) {
297                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
298                            "ID_Peer");
299                 eap_gpsk_state(data, FAILURE);
300                 return;
301         }
302         free(data->id_peer);
303         data->id_peer = malloc(alen);
304         if (data->id_peer == NULL) {
305                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store "
306                            "%d-octet ID_Peer", alen);
307                 return;
308         }
309         memcpy(data->id_peer, pos, alen);
310         data->id_peer_len = alen;
311         wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
312                           data->id_peer, data->id_peer_len);
313         pos += alen;
314
315         if (end - pos < 2) {
316                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
317                            "ID_Server length");
318                 eap_gpsk_state(data, FAILURE);
319                 return;
320         }
321         alen = WPA_GET_BE16(pos);
322         pos += 2;
323         if (end - pos < alen) {
324                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
325                            "ID_Server");
326                 eap_gpsk_state(data, FAILURE);
327                 return;
328         }
329         if (alen != data->id_server_len ||
330             memcmp(pos, data->id_server, alen) != 0) {
331                 wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
332                            "GPSK-2 did not match");
333                 eap_gpsk_state(data, FAILURE);
334                 return;
335         }
336         pos += alen;
337
338         if (end - pos < EAP_GPSK_RAND_LEN) {
339                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
340                            "RAND_Peer");
341                 eap_gpsk_state(data, FAILURE);
342                 return;
343         }
344         memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN);
345         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
346                     data->rand_peer, EAP_GPSK_RAND_LEN);
347         pos += EAP_GPSK_RAND_LEN;
348
349         if (end - pos < EAP_GPSK_RAND_LEN) {
350                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
351                            "RAND_Server");
352                 eap_gpsk_state(data, FAILURE);
353                 return;
354         }
355         if (memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) {
356                 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
357                            "GPSK-2 did not match");
358                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
359                             data->rand_server, EAP_GPSK_RAND_LEN);
360                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2",
361                             pos, EAP_GPSK_RAND_LEN);
362                 eap_gpsk_state(data, FAILURE);
363                 return;
364         }
365         pos += EAP_GPSK_RAND_LEN;
366
367         if (end - pos < 2) {
368                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
369                            "CSuite_List length");
370                 eap_gpsk_state(data, FAILURE);
371                 return;
372         }
373         alen = WPA_GET_BE16(pos);
374         pos += 2;
375         if (end - pos < alen) {
376                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
377                            "CSuite_List");
378                 eap_gpsk_state(data, FAILURE);
379                 return;
380         }
381         if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) ||
382             memcmp(pos, data->csuite_list, alen) != 0) {
383                 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and "
384                            "GPSK-2 did not match");
385                 eap_gpsk_state(data, FAILURE);
386                 return;
387         }
388         pos += alen;
389
390         if (end - pos < (int) sizeof(*csuite)) {
391                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
392                            "CSuite_Sel");
393                 eap_gpsk_state(data, FAILURE);
394                 return;
395         }
396         csuite = (const struct eap_gpsk_csuite *) pos;
397         for (i = 0; i < data->csuite_count; i++) {
398                 if (memcmp(csuite, &data->csuite_list[i], sizeof(*csuite)) ==
399                     0)
400                         break;
401         }
402         if (i == data->csuite_count) {
403                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
404                            "ciphersuite %d:%d",
405                            WPA_GET_BE32(csuite->vendor),
406                            WPA_GET_BE16(csuite->specifier));
407                 eap_gpsk_state(data, FAILURE);
408                 return;
409         }
410         data->vendor = WPA_GET_BE32(csuite->vendor);
411         data->specifier = WPA_GET_BE16(csuite->specifier);
412         wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
413                    data->vendor, data->specifier);
414         pos += sizeof(*csuite); 
415
416         if (end - pos < 2) {
417                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
418                            "PD_Payload_1 length");
419                 eap_gpsk_state(data, FAILURE);
420                 return;
421         }
422         alen = WPA_GET_BE16(pos);
423         pos += 2;
424         if (end - pos < alen) {
425                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
426                            "PD_Payload_1");
427                 eap_gpsk_state(data, FAILURE);
428                 return;
429         }
430         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
431         pos += alen;
432
433         if (sm->user == NULL || sm->user->password == NULL) {
434                 wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured "
435                            "for the user");
436                 eap_gpsk_state(data, FAILURE);
437                 return;
438         }
439
440         if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len,
441                                  data->vendor, data->specifier,
442                                  data->rand_peer, data->rand_server,
443                                  data->id_peer, data->id_peer_len,
444                                  data->id_server, data->id_server_len,
445                                  data->msk, data->emsk,
446                                  data->sk, &data->sk_len,
447                                  data->pk, &data->pk_len) < 0) {
448                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
449                 eap_gpsk_state(data, FAILURE);
450                 return;
451         }
452
453         miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
454         if (end - pos < (int) miclen) {
455                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
456                            "(left=%d miclen=%d)", end - pos, miclen);
457                 eap_gpsk_state(data, FAILURE);
458                 return;
459         }
460         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
461                                  data->specifier, payload, pos - payload, mic)
462             < 0) {
463                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
464                 eap_gpsk_state(data, FAILURE);
465                 return;
466         }
467         if (memcmp(mic, pos, miclen) != 0) {
468                 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
469                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
470                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
471                 eap_gpsk_state(data, FAILURE);
472                 return;
473         }
474         pos += miclen;
475
476         if (pos != end) {
477                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
478                            "data in the end of GPSK-2", end - pos);
479         }
480
481         eap_gpsk_state(data, GPSK_3);
482 }
483
484
485 static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
486                                     struct eap_gpsk_data *data,
487                                     u8 *respData, size_t respDataLen,
488                                     const u8 *payload, size_t payloadlen)
489 {
490         const u8 *pos, *end;
491         u16 alen;
492         size_t miclen;
493         u8 mic[EAP_GPSK_MAX_MIC_LEN];
494
495         if (data->state != GPSK_3)
496                 return;
497
498         wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4");
499
500         pos = payload;
501         end = payload + payloadlen;
502
503         if (end - pos < 2) {
504                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
505                            "PD_Payload_1 length");
506                 eap_gpsk_state(data, FAILURE);
507                 return;
508         }
509         alen = WPA_GET_BE16(pos);
510         pos += 2;
511         if (end - pos < alen) {
512                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
513                            "PD_Payload_1");
514                 eap_gpsk_state(data, FAILURE);
515                 return;
516         }
517         wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
518         pos += alen;
519
520         miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
521         if (end - pos < (int) miclen) {
522                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
523                            "(left=%d miclen=%d)", end - pos, miclen);
524                 eap_gpsk_state(data, FAILURE);
525                 return;
526         }
527         if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
528                                  data->specifier, payload, pos - payload, mic)
529             < 0) {
530                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
531                 eap_gpsk_state(data, FAILURE);
532                 return;
533         }
534         if (memcmp(mic, pos, miclen) != 0) {
535                 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
536                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
537                 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
538                 eap_gpsk_state(data, FAILURE);
539                 return;
540         }
541         pos += miclen;
542
543         if (pos != end) {
544                 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
545                            "data in the end of GPSK-4", end - pos);
546         }
547
548         eap_gpsk_state(data, SUCCESS);
549 }
550
551
552 static void eap_gpsk_process(struct eap_sm *sm, void *priv,
553                              u8 *respData, size_t respDataLen)
554 {
555         struct eap_gpsk_data *data = priv;
556         const u8 *pos;
557         size_t len;
558
559         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK,
560                                respData, respDataLen, &len);
561         if (pos == NULL || len < 1)
562                 return;
563
564         switch (*pos) {
565         case EAP_GPSK_OPCODE_GPSK_2:
566                 eap_gpsk_process_gpsk_2(sm, data, respData, respDataLen,
567                                         pos + 1, len - 1);
568                 break;
569         case EAP_GPSK_OPCODE_GPSK_4:
570                 eap_gpsk_process_gpsk_4(sm, data, respData, respDataLen,
571                                         pos + 1, len - 1);
572                 break;
573         }
574 }
575
576
577 static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv)
578 {
579         struct eap_gpsk_data *data = priv;
580         return data->state == SUCCESS || data->state == FAILURE;
581 }
582
583
584 static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
585 {
586         struct eap_gpsk_data *data = priv;
587         u8 *key;
588
589         if (data->state != SUCCESS)
590                 return NULL;
591
592         key = malloc(EAP_MSK_LEN);
593         if (key == NULL)
594                 return NULL;
595         memcpy(key, data->msk, EAP_MSK_LEN);
596         *len = EAP_MSK_LEN;
597
598         return key;
599 }
600
601
602 static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
603 {
604         struct eap_gpsk_data *data = priv;
605         u8 *key;
606
607         if (data->state != SUCCESS)
608                 return NULL;
609
610         key = malloc(EAP_EMSK_LEN);
611         if (key == NULL)
612                 return NULL;
613         memcpy(key, data->emsk, EAP_EMSK_LEN);
614         *len = EAP_EMSK_LEN;
615
616         return key;
617 }
618
619
620 static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
621 {
622         struct eap_gpsk_data *data = priv;
623         return data->state == SUCCESS;
624 }
625
626
627 int eap_server_gpsk_register(void)
628 {
629         struct eap_method *eap;
630         int ret;
631
632         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
633                                       EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
634         if (eap == NULL)
635                 return -1;
636
637         eap->init = eap_gpsk_init;
638         eap->reset = eap_gpsk_reset;
639         eap->buildReq = eap_gpsk_buildReq;
640         eap->check = eap_gpsk_check;
641         eap->process = eap_gpsk_process;
642         eap->isDone = eap_gpsk_isDone;
643         eap->getKey = eap_gpsk_getKey;
644         eap->isSuccess = eap_gpsk_isSuccess;
645         eap->get_emsk = eap_gpsk_get_emsk;
646
647         ret = eap_server_method_register(eap);
648         if (ret)
649                 eap_server_method_free(eap);
650         return ret;
651 }