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.
18 #include "eap_server/eap_i.h"
19 #include "eap_common/eap_gpsk_common.h"
22 struct eap_gpsk_data
{
23 enum { GPSK_1
, GPSK_3
, SUCCESS
, FAILURE
} state
;
24 u8 rand_server
[EAP_GPSK_RAND_LEN
];
25 u8 rand_peer
[EAP_GPSK_RAND_LEN
];
27 u8 emsk
[EAP_EMSK_LEN
];
28 u8 sk
[EAP_GPSK_MAX_SK_LEN
];
30 u8 pk
[EAP_GPSK_MAX_PK_LEN
];
36 #define MAX_NUM_CSUITES 2
37 struct eap_gpsk_csuite csuite_list
[MAX_NUM_CSUITES
];
39 int vendor
; /* CSuite/Vendor */
40 int specifier
; /* CSuite/Specifier */
44 static const char * eap_gpsk_state_txt(int state
)
61 static void eap_gpsk_state(struct eap_gpsk_data
*data
, int state
)
63 wpa_printf(MSG_DEBUG
, "EAP-GPSK: %s -> %s",
64 eap_gpsk_state_txt(data
->state
),
65 eap_gpsk_state_txt(state
));
70 static void * eap_gpsk_init(struct eap_sm
*sm
)
72 struct eap_gpsk_data
*data
;
74 data
= os_zalloc(sizeof(*data
));
79 /* TODO: add support for configuring ID_Server */
80 data
->id_server
= (u8
*) os_strdup("hostapd");
82 data
->id_server_len
= os_strlen((char *) data
->id_server
);
84 data
->csuite_count
= 0;
85 if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF
,
86 EAP_GPSK_CIPHER_AES
)) {
87 WPA_PUT_BE32(data
->csuite_list
[data
->csuite_count
].vendor
,
88 EAP_GPSK_VENDOR_IETF
);
89 WPA_PUT_BE16(data
->csuite_list
[data
->csuite_count
].specifier
,
93 if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF
,
94 EAP_GPSK_CIPHER_SHA256
)) {
95 WPA_PUT_BE32(data
->csuite_list
[data
->csuite_count
].vendor
,
96 EAP_GPSK_VENDOR_IETF
);
97 WPA_PUT_BE16(data
->csuite_list
[data
->csuite_count
].specifier
,
98 EAP_GPSK_CIPHER_SHA256
);
106 static void eap_gpsk_reset(struct eap_sm
*sm
, void *priv
)
108 struct eap_gpsk_data
*data
= priv
;
109 os_free(data
->id_server
);
110 os_free(data
->id_peer
);
115 static struct wpabuf
* eap_gpsk_build_gpsk_1(struct eap_sm
*sm
,
116 struct eap_gpsk_data
*data
, u8 id
)
121 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Request/GPSK-1");
123 if (os_get_random(data
->rand_server
, EAP_GPSK_RAND_LEN
)) {
124 wpa_printf(MSG_ERROR
, "EAP-GPSK: Failed to get random data");
125 eap_gpsk_state(data
, FAILURE
);
128 wpa_hexdump(MSG_MSGDUMP
, "EAP-GPSK: RAND_Server",
129 data
->rand_server
, EAP_GPSK_RAND_LEN
);
131 len
= 1 + 2 + data
->id_server_len
+ EAP_GPSK_RAND_LEN
+ 2 +
132 data
->csuite_count
* sizeof(struct eap_gpsk_csuite
);
133 req
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, len
,
134 EAP_CODE_REQUEST
, id
);
136 wpa_printf(MSG_ERROR
, "EAP-GPSK: Failed to allocate memory "
137 "for request/GPSK-1");
138 eap_gpsk_state(data
, FAILURE
);
142 wpabuf_put_u8(req
, EAP_GPSK_OPCODE_GPSK_1
);
143 wpabuf_put_be16(req
, data
->id_server_len
);
144 wpabuf_put_data(req
, data
->id_server
, data
->id_server_len
);
145 wpabuf_put_data(req
, data
->rand_server
, EAP_GPSK_RAND_LEN
);
147 data
->csuite_count
* sizeof(struct eap_gpsk_csuite
));
148 wpabuf_put_data(req
, data
->csuite_list
,
149 data
->csuite_count
* sizeof(struct eap_gpsk_csuite
));
155 static struct wpabuf
* eap_gpsk_build_gpsk_3(struct eap_sm
*sm
,
156 struct eap_gpsk_data
*data
, u8 id
)
160 struct eap_gpsk_csuite
*csuite
;
163 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Request/GPSK-3");
165 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
166 len
= 1 + 2 * EAP_GPSK_RAND_LEN
+ 2 + data
->id_server_len
+
167 sizeof(struct eap_gpsk_csuite
) + 2 + miclen
;
168 req
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, len
,
169 EAP_CODE_REQUEST
, id
);
171 wpa_printf(MSG_ERROR
, "EAP-GPSK: Failed to allocate memory "
172 "for request/GPSK-3");
173 eap_gpsk_state(data
, FAILURE
);
177 wpabuf_put_u8(req
, EAP_GPSK_OPCODE_GPSK_3
);
178 start
= wpabuf_put(req
, 0);
180 wpabuf_put_data(req
, data
->rand_peer
, EAP_GPSK_RAND_LEN
);
181 wpabuf_put_data(req
, data
->rand_server
, EAP_GPSK_RAND_LEN
);
182 wpabuf_put_be16(req
, data
->id_server_len
);
183 wpabuf_put_data(req
, data
->id_server
, data
->id_server_len
);
184 csuite
= wpabuf_put(req
, sizeof(*csuite
));
185 WPA_PUT_BE32(csuite
->vendor
, data
->vendor
);
186 WPA_PUT_BE16(csuite
->specifier
, data
->specifier
);
188 /* no PD_Payload_2 */
189 wpabuf_put_be16(req
, 0);
191 pos
= wpabuf_put(req
, miclen
);
192 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
193 data
->specifier
, start
, pos
- start
, pos
) < 0)
196 eap_gpsk_state(data
, FAILURE
);
204 static struct wpabuf
* eap_gpsk_buildReq(struct eap_sm
*sm
, void *priv
, u8 id
)
206 struct eap_gpsk_data
*data
= priv
;
208 switch (data
->state
) {
210 return eap_gpsk_build_gpsk_1(sm
, data
, id
);
212 return eap_gpsk_build_gpsk_3(sm
, data
, id
);
214 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Unknown state %d in buildReq",
222 static Boolean
eap_gpsk_check(struct eap_sm
*sm
, void *priv
,
223 struct wpabuf
*respData
)
225 struct eap_gpsk_data
*data
= priv
;
229 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, respData
, &len
);
230 if (pos
== NULL
|| len
< 1) {
231 wpa_printf(MSG_INFO
, "EAP-GPSK: Invalid frame");
235 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received frame: opcode=%d", *pos
);
237 if (data
->state
== GPSK_1
&& *pos
== EAP_GPSK_OPCODE_GPSK_2
)
240 if (data
->state
== GPSK_3
&& *pos
== EAP_GPSK_OPCODE_GPSK_4
)
243 wpa_printf(MSG_INFO
, "EAP-GPSK: Unexpected opcode=%d in state=%d",
250 static void eap_gpsk_process_gpsk_2(struct eap_sm
*sm
,
251 struct eap_gpsk_data
*data
,
252 const u8
*payload
, size_t payloadlen
)
256 const struct eap_gpsk_csuite
*csuite
;
258 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
260 if (data
->state
!= GPSK_1
)
263 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Response/GPSK-2");
266 end
= payload
+ payloadlen
;
269 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
271 eap_gpsk_state(data
, FAILURE
);
274 alen
= WPA_GET_BE16(pos
);
276 if (end
- pos
< alen
) {
277 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
279 eap_gpsk_state(data
, FAILURE
);
282 os_free(data
->id_peer
);
283 data
->id_peer
= os_malloc(alen
);
284 if (data
->id_peer
== NULL
) {
285 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Not enough memory to store "
286 "%d-octet ID_Peer", alen
);
289 os_memcpy(data
->id_peer
, pos
, alen
);
290 data
->id_peer_len
= alen
;
291 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Peer",
292 data
->id_peer
, data
->id_peer_len
);
296 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
298 eap_gpsk_state(data
, FAILURE
);
301 alen
= WPA_GET_BE16(pos
);
303 if (end
- pos
< alen
) {
304 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
306 eap_gpsk_state(data
, FAILURE
);
309 if (alen
!= data
->id_server_len
||
310 os_memcmp(pos
, data
->id_server
, alen
) != 0) {
311 wpa_printf(MSG_DEBUG
, "EAP-GPSK: ID_Server in GPSK-1 and "
312 "GPSK-2 did not match");
313 eap_gpsk_state(data
, FAILURE
);
318 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
319 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
321 eap_gpsk_state(data
, FAILURE
);
324 os_memcpy(data
->rand_peer
, pos
, EAP_GPSK_RAND_LEN
);
325 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Peer",
326 data
->rand_peer
, EAP_GPSK_RAND_LEN
);
327 pos
+= EAP_GPSK_RAND_LEN
;
329 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
330 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
332 eap_gpsk_state(data
, FAILURE
);
335 if (os_memcmp(data
->rand_server
, pos
, EAP_GPSK_RAND_LEN
) != 0) {
336 wpa_printf(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-1 and "
337 "GPSK-2 did not match");
338 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-1",
339 data
->rand_server
, EAP_GPSK_RAND_LEN
);
340 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-2",
341 pos
, EAP_GPSK_RAND_LEN
);
342 eap_gpsk_state(data
, FAILURE
);
345 pos
+= EAP_GPSK_RAND_LEN
;
348 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
349 "CSuite_List length");
350 eap_gpsk_state(data
, FAILURE
);
353 alen
= WPA_GET_BE16(pos
);
355 if (end
- pos
< alen
) {
356 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
358 eap_gpsk_state(data
, FAILURE
);
361 if (alen
!= data
->csuite_count
* sizeof(struct eap_gpsk_csuite
) ||
362 os_memcmp(pos
, data
->csuite_list
, alen
) != 0) {
363 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite_List in GPSK-1 and "
364 "GPSK-2 did not match");
365 eap_gpsk_state(data
, FAILURE
);
370 if (end
- pos
< (int) sizeof(*csuite
)) {
371 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
373 eap_gpsk_state(data
, FAILURE
);
376 csuite
= (const struct eap_gpsk_csuite
*) pos
;
377 for (i
= 0; i
< data
->csuite_count
; i
++) {
378 if (os_memcmp(csuite
, &data
->csuite_list
[i
], sizeof(*csuite
))
382 if (i
== data
->csuite_count
) {
383 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Peer selected unsupported "
385 WPA_GET_BE32(csuite
->vendor
),
386 WPA_GET_BE16(csuite
->specifier
));
387 eap_gpsk_state(data
, FAILURE
);
390 data
->vendor
= WPA_GET_BE32(csuite
->vendor
);
391 data
->specifier
= WPA_GET_BE16(csuite
->specifier
);
392 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite_Sel %d:%d",
393 data
->vendor
, data
->specifier
);
394 pos
+= sizeof(*csuite
);
397 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
398 "PD_Payload_1 length");
399 eap_gpsk_state(data
, FAILURE
);
402 alen
= WPA_GET_BE16(pos
);
404 if (end
- pos
< alen
) {
405 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
407 eap_gpsk_state(data
, FAILURE
);
410 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_1", pos
, alen
);
413 if (sm
->user
== NULL
|| sm
->user
->password
== NULL
) {
414 wpa_printf(MSG_INFO
, "EAP-GPSK: No PSK/password configured "
416 eap_gpsk_state(data
, FAILURE
);
420 if (eap_gpsk_derive_keys(sm
->user
->password
, sm
->user
->password_len
,
421 data
->vendor
, data
->specifier
,
422 data
->rand_peer
, data
->rand_server
,
423 data
->id_peer
, data
->id_peer_len
,
424 data
->id_server
, data
->id_server_len
,
425 data
->msk
, data
->emsk
,
426 data
->sk
, &data
->sk_len
,
427 data
->pk
, &data
->pk_len
) < 0) {
428 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to derive keys");
429 eap_gpsk_state(data
, FAILURE
);
433 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
434 if (end
- pos
< (int) miclen
) {
435 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for MIC "
436 "(left=%d miclen=%d)", end
- pos
, miclen
);
437 eap_gpsk_state(data
, FAILURE
);
440 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
441 data
->specifier
, payload
, pos
- payload
, mic
)
443 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to compute MIC");
444 eap_gpsk_state(data
, FAILURE
);
447 if (os_memcmp(mic
, pos
, miclen
) != 0) {
448 wpa_printf(MSG_INFO
, "EAP-GPSK: Incorrect MIC in GPSK-2");
449 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Received MIC", pos
, miclen
);
450 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Computed MIC", mic
, miclen
);
451 eap_gpsk_state(data
, FAILURE
);
457 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %d bytes of extra "
458 "data in the end of GPSK-2", end
- pos
);
461 eap_gpsk_state(data
, GPSK_3
);
465 static void eap_gpsk_process_gpsk_4(struct eap_sm
*sm
,
466 struct eap_gpsk_data
*data
,
467 const u8
*payload
, size_t payloadlen
)
472 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
474 if (data
->state
!= GPSK_3
)
477 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Response/GPSK-4");
480 end
= payload
+ payloadlen
;
483 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
484 "PD_Payload_1 length");
485 eap_gpsk_state(data
, FAILURE
);
488 alen
= WPA_GET_BE16(pos
);
490 if (end
- pos
< alen
) {
491 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
493 eap_gpsk_state(data
, FAILURE
);
496 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_1", pos
, alen
);
499 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
500 if (end
- pos
< (int) miclen
) {
501 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for MIC "
502 "(left=%d miclen=%d)", end
- pos
, miclen
);
503 eap_gpsk_state(data
, FAILURE
);
506 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
507 data
->specifier
, payload
, pos
- payload
, mic
)
509 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to compute MIC");
510 eap_gpsk_state(data
, FAILURE
);
513 if (os_memcmp(mic
, pos
, miclen
) != 0) {
514 wpa_printf(MSG_INFO
, "EAP-GPSK: Incorrect MIC in GPSK-4");
515 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Received MIC", pos
, miclen
);
516 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Computed MIC", mic
, miclen
);
517 eap_gpsk_state(data
, FAILURE
);
523 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %d bytes of extra "
524 "data in the end of GPSK-4", end
- pos
);
527 eap_gpsk_state(data
, SUCCESS
);
531 static void eap_gpsk_process(struct eap_sm
*sm
, void *priv
,
532 struct wpabuf
*respData
)
534 struct eap_gpsk_data
*data
= priv
;
538 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, respData
, &len
);
539 if (pos
== NULL
|| len
< 1)
543 case EAP_GPSK_OPCODE_GPSK_2
:
544 eap_gpsk_process_gpsk_2(sm
, data
, pos
+ 1, len
- 1);
546 case EAP_GPSK_OPCODE_GPSK_4
:
547 eap_gpsk_process_gpsk_4(sm
, data
, pos
+ 1, len
- 1);
553 static Boolean
eap_gpsk_isDone(struct eap_sm
*sm
, void *priv
)
555 struct eap_gpsk_data
*data
= priv
;
556 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
560 static u8
* eap_gpsk_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
562 struct eap_gpsk_data
*data
= priv
;
565 if (data
->state
!= SUCCESS
)
568 key
= os_malloc(EAP_MSK_LEN
);
571 os_memcpy(key
, data
->msk
, EAP_MSK_LEN
);
578 static u8
* eap_gpsk_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
580 struct eap_gpsk_data
*data
= priv
;
583 if (data
->state
!= SUCCESS
)
586 key
= os_malloc(EAP_EMSK_LEN
);
589 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
596 static Boolean
eap_gpsk_isSuccess(struct eap_sm
*sm
, void *priv
)
598 struct eap_gpsk_data
*data
= priv
;
599 return data
->state
== SUCCESS
;
603 int eap_server_gpsk_register(void)
605 struct eap_method
*eap
;
608 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
609 EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, "GPSK");
613 eap
->init
= eap_gpsk_init
;
614 eap
->reset
= eap_gpsk_reset
;
615 eap
->buildReq
= eap_gpsk_buildReq
;
616 eap
->check
= eap_gpsk_check
;
617 eap
->process
= eap_gpsk_process
;
618 eap
->isDone
= eap_gpsk_isDone
;
619 eap
->getKey
= eap_gpsk_getKey
;
620 eap
->isSuccess
= eap_gpsk_isSuccess
;
621 eap
->get_emsk
= eap_gpsk_get_emsk
;
623 ret
= eap_server_method_register(eap
);
625 eap_server_method_free(eap
);