2 * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-08.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_peer
[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_BE32(data
->csuite_list
[data
->csuite_count
].vendor
,
89 EAP_GPSK_VENDOR_IETF
);
90 WPA_PUT_BE16(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_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
++;
107 static void eap_gpsk_reset(struct eap_sm
*sm
, void *priv
)
109 struct eap_gpsk_data
*data
= priv
;
110 free(data
->id_server
);
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
+ 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
);
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_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
);
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
);
205 /* no PD_Payload_2 */
206 WPA_PUT_BE16(pos
, 0);
209 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
210 data
->specifier
, start
, pos
- start
, pos
) < 0)
213 eap_gpsk_state(data
, FAILURE
);
221 static u8
* eap_gpsk_buildReq(struct eap_sm
*sm
, void *priv
, int id
,
224 struct eap_gpsk_data
*data
= priv
;
226 switch (data
->state
) {
228 return eap_gpsk_build_gpsk_1(sm
, data
, id
, reqDataLen
);
230 return eap_gpsk_build_gpsk_3(sm
, data
, id
, reqDataLen
);
232 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Unknown state %d in buildReq",
240 static Boolean
eap_gpsk_check(struct eap_sm
*sm
, void *priv
,
241 u8
*respData
, size_t respDataLen
)
243 struct eap_gpsk_data
*data
= priv
;
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");
254 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received frame: opcode=%d", *pos
);
256 if (data
->state
== GPSK_1
&& *pos
== EAP_GPSK_OPCODE_GPSK_2
)
259 if (data
->state
== GPSK_3
&& *pos
== EAP_GPSK_OPCODE_GPSK_4
)
262 wpa_printf(MSG_INFO
, "EAP-GPSK: Unexpected opcode=%d in state=%d",
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
)
276 const struct eap_gpsk_csuite
*csuite
;
278 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
280 if (data
->state
!= GPSK_1
)
283 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Response/GPSK-2");
286 end
= payload
+ payloadlen
;
289 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
291 eap_gpsk_state(data
, FAILURE
);
294 alen
= WPA_GET_BE16(pos
);
296 if (end
- pos
< alen
) {
297 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
299 eap_gpsk_state(data
, FAILURE
);
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
);
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
);
316 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
318 eap_gpsk_state(data
, FAILURE
);
321 alen
= WPA_GET_BE16(pos
);
323 if (end
- pos
< alen
) {
324 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
326 eap_gpsk_state(data
, FAILURE
);
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
);
338 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
339 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
341 eap_gpsk_state(data
, FAILURE
);
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
;
349 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
350 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
352 eap_gpsk_state(data
, FAILURE
);
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
);
365 pos
+= EAP_GPSK_RAND_LEN
;
368 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
369 "CSuite_List length");
370 eap_gpsk_state(data
, FAILURE
);
373 alen
= WPA_GET_BE16(pos
);
375 if (end
- pos
< alen
) {
376 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
378 eap_gpsk_state(data
, FAILURE
);
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
);
390 if (end
- pos
< (int) sizeof(*csuite
)) {
391 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
393 eap_gpsk_state(data
, FAILURE
);
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
)) ==
402 if (i
== data
->csuite_count
) {
403 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Peer selected unsupported "
405 WPA_GET_BE32(csuite
->vendor
),
406 WPA_GET_BE16(csuite
->specifier
));
407 eap_gpsk_state(data
, FAILURE
);
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
);
417 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
418 "PD_Payload_1 length");
419 eap_gpsk_state(data
, FAILURE
);
422 alen
= WPA_GET_BE16(pos
);
424 if (end
- pos
< alen
) {
425 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
427 eap_gpsk_state(data
, FAILURE
);
430 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_1", pos
, alen
);
433 if (sm
->user
== NULL
|| sm
->user
->password
== NULL
) {
434 wpa_printf(MSG_INFO
, "EAP-GPSK: No PSK/password configured "
436 eap_gpsk_state(data
, FAILURE
);
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
);
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
);
460 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
461 data
->specifier
, payload
, pos
- payload
, mic
)
463 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to compute MIC");
464 eap_gpsk_state(data
, FAILURE
);
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
);
477 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %d bytes of extra "
478 "data in the end of GPSK-2", end
- pos
);
481 eap_gpsk_state(data
, GPSK_3
);
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
)
493 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
495 if (data
->state
!= GPSK_3
)
498 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Response/GPSK-4");
501 end
= payload
+ payloadlen
;
504 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
505 "PD_Payload_1 length");
506 eap_gpsk_state(data
, FAILURE
);
509 alen
= WPA_GET_BE16(pos
);
511 if (end
- pos
< alen
) {
512 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
514 eap_gpsk_state(data
, FAILURE
);
517 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_1", pos
, alen
);
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
);
527 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
528 data
->specifier
, payload
, pos
- payload
, mic
)
530 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to compute MIC");
531 eap_gpsk_state(data
, FAILURE
);
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
);
544 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %d bytes of extra "
545 "data in the end of GPSK-4", end
- pos
);
548 eap_gpsk_state(data
, SUCCESS
);
552 static void eap_gpsk_process(struct eap_sm
*sm
, void *priv
,
553 u8
*respData
, size_t respDataLen
)
555 struct eap_gpsk_data
*data
= priv
;
559 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
,
560 respData
, respDataLen
, &len
);
561 if (pos
== NULL
|| len
< 1)
565 case EAP_GPSK_OPCODE_GPSK_2
:
566 eap_gpsk_process_gpsk_2(sm
, data
, respData
, respDataLen
,
569 case EAP_GPSK_OPCODE_GPSK_4
:
570 eap_gpsk_process_gpsk_4(sm
, data
, respData
, respDataLen
,
577 static Boolean
eap_gpsk_isDone(struct eap_sm
*sm
, void *priv
)
579 struct eap_gpsk_data
*data
= priv
;
580 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
584 static u8
* eap_gpsk_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
586 struct eap_gpsk_data
*data
= priv
;
589 if (data
->state
!= SUCCESS
)
592 key
= malloc(EAP_MSK_LEN
);
595 memcpy(key
, data
->msk
, EAP_MSK_LEN
);
602 static u8
* eap_gpsk_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
604 struct eap_gpsk_data
*data
= priv
;
607 if (data
->state
!= SUCCESS
)
610 key
= malloc(EAP_EMSK_LEN
);
613 memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
620 static Boolean
eap_gpsk_isSuccess(struct eap_sm
*sm
, void *priv
)
622 struct eap_gpsk_data
*data
= priv
;
623 return data
->state
== SUCCESS
;
627 int eap_server_gpsk_register(void)
629 struct eap_method
*eap
;
632 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
633 EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, "GPSK");
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
;
647 ret
= eap_server_method_register(eap
);
649 eap_server_method_free(eap
);