2 * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-03.txt) server
3 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
20 #include "eap_gpsk_common.h"
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
];
28 u8 emsk
[EAP_EMSK_LEN
];
29 u8 sk
[EAP_GPSK_MAX_SK_LEN
];
31 u8 pk
[EAP_GPSK_MAX_PK_LEN
];
37 #define MAX_NUM_CSUITES 2
38 struct eap_gpsk_csuite csuite_list
[MAX_NUM_CSUITES
];
40 int vendor
; /* CSuite/Vendor */
41 int specifier
; /* CSuite/Specifier */
45 static const char * eap_gpsk_state_txt(int state
)
62 static void eap_gpsk_state(struct eap_gpsk_data
*data
, int state
)
64 wpa_printf(MSG_DEBUG
, "EAP-GPSK: %s -> %s",
65 eap_gpsk_state_txt(data
->state
),
66 eap_gpsk_state_txt(state
));
71 static void * eap_gpsk_init(struct eap_sm
*sm
)
73 struct eap_gpsk_data
*data
;
75 data
= wpa_zalloc(sizeof(*data
));
80 /* TODO: add support for configuring ID_Server */
81 data
->id_server
= (u8
*) strdup("hostapd");
83 data
->id_server_len
= strlen((char *) data
->id_server
);
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
,
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
++;
107 static void eap_gpsk_reset(struct eap_sm
*sm
, void *priv
)
109 struct eap_gpsk_data
*data
= priv
;
110 free(data
->id_server
);
111 free(data
->id_client
);
116 static u8
* eap_gpsk_build_gpsk_1(struct eap_sm
*sm
,
117 struct eap_gpsk_data
*data
,
118 int id
, size_t *reqDataLen
)
124 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Request/GPSK-1");
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
);
131 wpa_hexdump(MSG_MSGDUMP
, "EAP-GPSK: RAND_Server",
132 data
->rand_server
, EAP_GPSK_RAND_LEN
);
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
);
139 wpa_printf(MSG_ERROR
, "EAP-GPSK: Failed to allocate memory "
140 "for request/GPSK-1");
141 eap_gpsk_state(data
, FAILURE
);
145 *pos
++ = EAP_GPSK_OPCODE_GPSK_1
;
147 WPA_PUT_BE16(pos
, data
->id_server_len
);
150 memcpy(pos
, data
->id_server
, data
->id_server_len
);
151 pos
+= data
->id_server_len
;
153 memcpy(pos
, data
->rand_server
, EAP_GPSK_RAND_LEN
);
154 pos
+= EAP_GPSK_RAND_LEN
;
156 WPA_PUT_BE16(pos
, data
->csuite_count
* sizeof(struct eap_gpsk_csuite
));
158 memcpy(pos
, data
->csuite_list
,
159 data
->csuite_count
* sizeof(struct eap_gpsk_csuite
));
165 static u8
* eap_gpsk_build_gpsk_3(struct eap_sm
*sm
,
166 struct eap_gpsk_data
*data
,
167 int id
, size_t *reqDataLen
)
171 struct eap_gpsk_csuite
*csuite
;
174 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Request/GPSK-3");
176 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
177 len
= 1 + 2 * EAP_GPSK_RAND_LEN
+ sizeof(struct eap_gpsk_csuite
) + 2 +
179 req
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, reqDataLen
,
180 len
, EAP_CODE_REQUEST
, id
, &pos
);
182 wpa_printf(MSG_ERROR
, "EAP-GPSK: Failed to allocate memory "
183 "for request/GPSK-3");
184 eap_gpsk_state(data
, FAILURE
);
188 *pos
++ = EAP_GPSK_OPCODE_GPSK_3
;
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
);
200 /* no PD_Payload_2 */
201 WPA_PUT_BE16(pos
, 0);
204 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
205 data
->specifier
, start
, pos
- start
, pos
) < 0)
208 eap_gpsk_state(data
, FAILURE
);
216 static u8
* eap_gpsk_buildReq(struct eap_sm
*sm
, void *priv
, int id
,
219 struct eap_gpsk_data
*data
= priv
;
221 switch (data
->state
) {
223 return eap_gpsk_build_gpsk_1(sm
, data
, id
, reqDataLen
);
225 return eap_gpsk_build_gpsk_3(sm
, data
, id
, reqDataLen
);
227 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Unknown state %d in buildReq",
235 static Boolean
eap_gpsk_check(struct eap_sm
*sm
, void *priv
,
236 u8
*respData
, size_t respDataLen
)
238 struct eap_gpsk_data
*data
= priv
;
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");
249 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received frame: opcode=%d", *pos
);
251 if (data
->state
== GPSK_1
&& *pos
== EAP_GPSK_OPCODE_GPSK_2
)
254 if (data
->state
== GPSK_3
&& *pos
== EAP_GPSK_OPCODE_GPSK_4
)
257 wpa_printf(MSG_INFO
, "EAP-GPSK: Unexpected opcode=%d in state=%d",
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
)
271 const struct eap_gpsk_csuite
*csuite
;
273 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
275 if (data
->state
!= GPSK_1
)
278 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Response/GPSK-2");
281 end
= payload
+ payloadlen
;
284 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
286 eap_gpsk_state(data
, FAILURE
);
289 alen
= WPA_GET_BE16(pos
);
291 if (end
- pos
< alen
) {
292 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
294 eap_gpsk_state(data
, FAILURE
);
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
);
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
);
311 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
313 eap_gpsk_state(data
, FAILURE
);
316 alen
= WPA_GET_BE16(pos
);
318 if (end
- pos
< alen
) {
319 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
321 eap_gpsk_state(data
, FAILURE
);
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
);
333 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
334 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
336 eap_gpsk_state(data
, FAILURE
);
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
;
344 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
345 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
347 eap_gpsk_state(data
, FAILURE
);
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
);
360 pos
+= EAP_GPSK_RAND_LEN
;
363 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
364 "CSuite_List length");
365 eap_gpsk_state(data
, FAILURE
);
368 alen
= WPA_GET_BE16(pos
);
370 if (end
- pos
< alen
) {
371 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
373 eap_gpsk_state(data
, FAILURE
);
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
);
385 if (end
- pos
< (int) sizeof(*csuite
)) {
386 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
388 eap_gpsk_state(data
, FAILURE
);
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
)) ==
397 if (i
== data
->csuite_count
) {
398 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Peer selected unsupported "
400 WPA_GET_BE24(csuite
->vendor
),
401 WPA_GET_BE24(csuite
->specifier
));
402 eap_gpsk_state(data
, FAILURE
);
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
);
412 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
413 "PD_Payload_1 length");
414 eap_gpsk_state(data
, FAILURE
);
417 alen
= WPA_GET_BE16(pos
);
419 if (end
- pos
< alen
) {
420 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
422 eap_gpsk_state(data
, FAILURE
);
425 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_1", pos
, alen
);
428 if (sm
->user
== NULL
|| sm
->user
->password
== NULL
) {
429 wpa_printf(MSG_INFO
, "EAP-GPSK: No PSK/password configured "
431 eap_gpsk_state(data
, FAILURE
);
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
);
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
);
455 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
456 data
->specifier
, payload
, pos
- payload
, mic
)
458 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to compute MIC");
459 eap_gpsk_state(data
, FAILURE
);
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
);
472 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %d bytes of extra "
473 "data in the end of GPSK-2", end
- pos
);
476 eap_gpsk_state(data
, GPSK_3
);
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
)
488 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
490 if (data
->state
!= GPSK_3
)
493 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Response/GPSK-4");
496 end
= payload
+ payloadlen
;
499 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
500 "PD_Payload_1 length");
501 eap_gpsk_state(data
, FAILURE
);
504 alen
= WPA_GET_BE16(pos
);
506 if (end
- pos
< alen
) {
507 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
509 eap_gpsk_state(data
, FAILURE
);
512 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_1", pos
, alen
);
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
);
522 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
523 data
->specifier
, payload
, pos
- payload
, mic
)
525 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to compute MIC");
526 eap_gpsk_state(data
, FAILURE
);
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
);
539 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %d bytes of extra "
540 "data in the end of GPSK-4", end
- pos
);
543 eap_gpsk_state(data
, SUCCESS
);
547 static void eap_gpsk_process(struct eap_sm
*sm
, void *priv
,
548 u8
*respData
, size_t respDataLen
)
550 struct eap_gpsk_data
*data
= priv
;
554 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
,
555 respData
, respDataLen
, &len
);
556 if (pos
== NULL
|| len
< 1)
560 case EAP_GPSK_OPCODE_GPSK_2
:
561 eap_gpsk_process_gpsk_2(sm
, data
, respData
, respDataLen
,
564 case EAP_GPSK_OPCODE_GPSK_4
:
565 eap_gpsk_process_gpsk_4(sm
, data
, respData
, respDataLen
,
572 static Boolean
eap_gpsk_isDone(struct eap_sm
*sm
, void *priv
)
574 struct eap_gpsk_data
*data
= priv
;
575 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
579 static u8
* eap_gpsk_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
581 struct eap_gpsk_data
*data
= priv
;
584 if (data
->state
!= SUCCESS
)
587 key
= malloc(EAP_MSK_LEN
);
590 memcpy(key
, data
->msk
, EAP_MSK_LEN
);
597 static u8
* eap_gpsk_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
599 struct eap_gpsk_data
*data
= priv
;
602 if (data
->state
!= SUCCESS
)
605 key
= malloc(EAP_EMSK_LEN
);
608 memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
615 static Boolean
eap_gpsk_isSuccess(struct eap_sm
*sm
, void *priv
)
617 struct eap_gpsk_data
*data
= priv
;
618 return data
->state
== SUCCESS
;
622 int eap_server_gpsk_register(void)
624 struct eap_method
*eap
;
627 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
628 EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, "GPSK");
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
;
642 ret
= eap_server_method_register(eap
);
644 eap_server_method_free(eap
);