2 * EAP peer method: EAP-GPSK (RFC 5433)
3 * Copyright (c) 2006-2008, 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_peer/eap_i.h"
19 #include "eap_common/eap_gpsk_common.h"
21 struct eap_gpsk_data
{
22 enum { GPSK_1
, GPSK_3
, SUCCESS
, FAILURE
} state
;
23 u8 rand_server
[EAP_GPSK_RAND_LEN
];
24 u8 rand_peer
[EAP_GPSK_RAND_LEN
];
26 u8 emsk
[EAP_EMSK_LEN
];
27 u8 sk
[EAP_GPSK_MAX_SK_LEN
];
29 u8 pk
[EAP_GPSK_MAX_PK_LEN
];
37 int vendor
; /* CSuite/Specifier */
38 int specifier
; /* CSuite/Specifier */
44 static struct wpabuf
* eap_gpsk_send_gpsk_2(struct eap_gpsk_data
*data
,
46 const u8
*csuite_list
,
47 size_t csuite_list_len
);
48 static struct wpabuf
* eap_gpsk_send_gpsk_4(struct eap_gpsk_data
*data
,
52 #ifndef CONFIG_NO_STDOUT_DEBUG
53 static const char * eap_gpsk_state_txt(int state
)
68 #endif /* CONFIG_NO_STDOUT_DEBUG */
71 static void eap_gpsk_state(struct eap_gpsk_data
*data
, int state
)
73 wpa_printf(MSG_DEBUG
, "EAP-GPSK: %s -> %s",
74 eap_gpsk_state_txt(data
->state
),
75 eap_gpsk_state_txt(state
));
80 static void eap_gpsk_deinit(struct eap_sm
*sm
, void *priv
);
83 static void * eap_gpsk_init(struct eap_sm
*sm
)
85 struct eap_gpsk_data
*data
;
86 const u8
*identity
, *password
;
87 size_t identity_len
, password_len
;
89 password
= eap_get_config_password(sm
, &password_len
);
90 if (password
== NULL
) {
91 wpa_printf(MSG_INFO
, "EAP-GPSK: No key (password) configured");
95 data
= os_zalloc(sizeof(*data
));
100 identity
= eap_get_config_identity(sm
, &identity_len
);
102 data
->id_peer
= os_malloc(identity_len
);
103 if (data
->id_peer
== NULL
) {
104 eap_gpsk_deinit(sm
, data
);
107 os_memcpy(data
->id_peer
, identity
, identity_len
);
108 data
->id_peer_len
= identity_len
;
111 data
->psk
= os_malloc(password_len
);
112 if (data
->psk
== NULL
) {
113 eap_gpsk_deinit(sm
, data
);
116 os_memcpy(data
->psk
, password
, password_len
);
117 data
->psk_len
= password_len
;
123 static void eap_gpsk_deinit(struct eap_sm
*sm
, void *priv
)
125 struct eap_gpsk_data
*data
= priv
;
126 os_free(data
->id_server
);
127 os_free(data
->id_peer
);
133 static const u8
* eap_gpsk_process_id_server(struct eap_gpsk_data
*data
,
134 const u8
*pos
, const u8
*end
)
139 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short GPSK-1 packet");
142 alen
= WPA_GET_BE16(pos
);
144 if (end
- pos
< alen
) {
145 wpa_printf(MSG_DEBUG
, "EAP-GPSK: ID_Server overflow");
148 os_free(data
->id_server
);
149 data
->id_server
= os_malloc(alen
);
150 if (data
->id_server
== NULL
) {
151 wpa_printf(MSG_DEBUG
, "EAP-GPSK: No memory for ID_Server");
154 os_memcpy(data
->id_server
, pos
, alen
);
155 data
->id_server_len
= alen
;
156 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Server",
157 data
->id_server
, data
->id_server_len
);
164 static const u8
* eap_gpsk_process_rand_server(struct eap_gpsk_data
*data
,
165 const u8
*pos
, const u8
*end
)
170 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
171 wpa_printf(MSG_DEBUG
, "EAP-GPSK: RAND_Server overflow");
174 os_memcpy(data
->rand_server
, pos
, EAP_GPSK_RAND_LEN
);
175 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server",
176 data
->rand_server
, EAP_GPSK_RAND_LEN
);
177 pos
+= EAP_GPSK_RAND_LEN
;
183 static int eap_gpsk_select_csuite(struct eap_sm
*sm
,
184 struct eap_gpsk_data
*data
,
185 const u8
*csuite_list
,
186 size_t csuite_list_len
)
188 struct eap_gpsk_csuite
*csuite
;
191 count
= csuite_list_len
/ sizeof(struct eap_gpsk_csuite
);
192 data
->vendor
= EAP_GPSK_VENDOR_IETF
;
193 data
->specifier
= EAP_GPSK_CIPHER_RESERVED
;
194 csuite
= (struct eap_gpsk_csuite
*) csuite_list
;
195 for (i
= 0; i
< count
; i
++) {
196 int vendor
, specifier
;
197 vendor
= WPA_GET_BE32(csuite
->vendor
);
198 specifier
= WPA_GET_BE16(csuite
->specifier
);
199 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite[%d]: %d:%d",
200 i
, vendor
, specifier
);
201 if (data
->vendor
== EAP_GPSK_VENDOR_IETF
&&
202 data
->specifier
== EAP_GPSK_CIPHER_RESERVED
&&
203 eap_gpsk_supported_ciphersuite(vendor
, specifier
)) {
204 data
->vendor
= vendor
;
205 data
->specifier
= specifier
;
209 if (data
->vendor
== EAP_GPSK_VENDOR_IETF
&&
210 data
->specifier
== EAP_GPSK_CIPHER_RESERVED
) {
211 wpa_msg(sm
->msg_ctx
, MSG_INFO
, "EAP-GPSK: No supported "
212 "ciphersuite found");
215 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Selected ciphersuite %d:%d",
216 data
->vendor
, data
->specifier
);
222 static const u8
* eap_gpsk_process_csuite_list(struct eap_sm
*sm
,
223 struct eap_gpsk_data
*data
,
226 const u8
*pos
, const u8
*end
)
232 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short GPSK-1 packet");
235 *list_len
= WPA_GET_BE16(pos
);
237 if (end
- pos
< (int) *list_len
) {
238 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite_List overflow");
241 if (*list_len
== 0 || (*list_len
% sizeof(struct eap_gpsk_csuite
))) {
242 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Invalid CSuite_List len %lu",
243 (unsigned long) *list_len
);
249 if (eap_gpsk_select_csuite(sm
, data
, *list
, *list_len
) < 0)
256 static struct wpabuf
* eap_gpsk_process_gpsk_1(struct eap_sm
*sm
,
257 struct eap_gpsk_data
*data
,
258 struct eap_method_ret
*ret
,
259 const struct wpabuf
*reqData
,
263 size_t csuite_list_len
;
264 const u8
*csuite_list
, *pos
, *end
;
267 if (data
->state
!= GPSK_1
) {
272 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Request/GPSK-1");
274 end
= payload
+ payload_len
;
276 pos
= eap_gpsk_process_id_server(data
, payload
, end
);
277 pos
= eap_gpsk_process_rand_server(data
, pos
, end
);
278 pos
= eap_gpsk_process_csuite_list(sm
, data
, &csuite_list
,
279 &csuite_list_len
, pos
, end
);
281 eap_gpsk_state(data
, FAILURE
);
285 resp
= eap_gpsk_send_gpsk_2(data
, eap_get_id(reqData
),
286 csuite_list
, csuite_list_len
);
290 eap_gpsk_state(data
, GPSK_3
);
296 static struct wpabuf
* eap_gpsk_send_gpsk_2(struct eap_gpsk_data
*data
,
298 const u8
*csuite_list
,
299 size_t csuite_list_len
)
304 struct eap_gpsk_csuite
*csuite
;
306 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Sending Response/GPSK-2");
308 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
309 len
= 1 + 2 + data
->id_peer_len
+ 2 + data
->id_server_len
+
310 2 * EAP_GPSK_RAND_LEN
+ 2 + csuite_list_len
+
311 sizeof(struct eap_gpsk_csuite
) + 2 + miclen
;
313 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, len
,
314 EAP_CODE_RESPONSE
, identifier
);
318 wpabuf_put_u8(resp
, EAP_GPSK_OPCODE_GPSK_2
);
319 start
= wpabuf_put(resp
, 0);
321 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Peer",
322 data
->id_peer
, data
->id_peer_len
);
323 wpabuf_put_be16(resp
, data
->id_peer_len
);
324 wpabuf_put_data(resp
, data
->id_peer
, data
->id_peer_len
);
326 wpabuf_put_be16(resp
, data
->id_server_len
);
327 wpabuf_put_data(resp
, data
->id_server
, data
->id_server_len
);
329 if (os_get_random(data
->rand_peer
, EAP_GPSK_RAND_LEN
)) {
330 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to get random data "
332 eap_gpsk_state(data
, FAILURE
);
336 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Peer",
337 data
->rand_peer
, EAP_GPSK_RAND_LEN
);
338 wpabuf_put_data(resp
, data
->rand_peer
, EAP_GPSK_RAND_LEN
);
339 wpabuf_put_data(resp
, data
->rand_server
, EAP_GPSK_RAND_LEN
);
341 wpabuf_put_be16(resp
, csuite_list_len
);
342 wpabuf_put_data(resp
, csuite_list
, csuite_list_len
);
344 csuite
= wpabuf_put(resp
, sizeof(*csuite
));
345 WPA_PUT_BE32(csuite
->vendor
, data
->vendor
);
346 WPA_PUT_BE16(csuite
->specifier
, data
->specifier
);
348 if (eap_gpsk_derive_keys(data
->psk
, data
->psk_len
,
349 data
->vendor
, data
->specifier
,
350 data
->rand_peer
, data
->rand_server
,
351 data
->id_peer
, data
->id_peer_len
,
352 data
->id_server
, data
->id_server_len
,
353 data
->msk
, data
->emsk
,
354 data
->sk
, &data
->sk_len
,
355 data
->pk
, &data
->pk_len
) < 0) {
356 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to derive keys");
357 eap_gpsk_state(data
, FAILURE
);
362 /* No PD_Payload_1 */
363 wpabuf_put_be16(resp
, 0);
365 rpos
= wpabuf_put(resp
, miclen
);
366 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
367 data
->specifier
, start
, rpos
- start
, rpos
) <
369 eap_gpsk_state(data
, FAILURE
);
378 static const u8
* eap_gpsk_validate_rand(struct eap_gpsk_data
*data
,
379 const u8
*pos
, const u8
*end
)
381 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
382 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
386 if (os_memcmp(pos
, data
->rand_peer
, EAP_GPSK_RAND_LEN
) != 0) {
387 wpa_printf(MSG_DEBUG
, "EAP-GPSK: RAND_Peer in GPSK-2 and "
388 "GPSK-3 did not match");
389 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Peer in GPSK-2",
390 data
->rand_peer
, EAP_GPSK_RAND_LEN
);
391 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Peer in GPSK-3",
392 pos
, EAP_GPSK_RAND_LEN
);
395 pos
+= EAP_GPSK_RAND_LEN
;
397 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
398 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
402 if (os_memcmp(pos
, data
->rand_server
, EAP_GPSK_RAND_LEN
) != 0) {
403 wpa_printf(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-1 and "
404 "GPSK-3 did not match");
405 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-1",
406 data
->rand_server
, EAP_GPSK_RAND_LEN
);
407 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-3",
408 pos
, EAP_GPSK_RAND_LEN
);
411 pos
+= EAP_GPSK_RAND_LEN
;
417 static const u8
* eap_gpsk_validate_id_server(struct eap_gpsk_data
*data
,
418 const u8
*pos
, const u8
*end
)
425 if (end
- pos
< (int) 2) {
426 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
427 "length(ID_Server)");
431 len
= WPA_GET_BE16(pos
);
434 if (end
- pos
< (int) len
) {
435 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
440 if (len
!= data
->id_server_len
||
441 os_memcmp(pos
, data
->id_server
, len
) != 0) {
442 wpa_printf(MSG_INFO
, "EAP-GPSK: ID_Server did not match with "
443 "the one used in GPSK-1");
444 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Server in GPSK-1",
445 data
->id_server
, data
->id_server_len
);
446 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Server in GPSK-3",
457 static const u8
* eap_gpsk_validate_csuite(struct eap_gpsk_data
*data
,
458 const u8
*pos
, const u8
*end
)
460 int vendor
, specifier
;
461 const struct eap_gpsk_csuite
*csuite
;
466 if (end
- pos
< (int) sizeof(*csuite
)) {
467 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
471 csuite
= (const struct eap_gpsk_csuite
*) pos
;
472 vendor
= WPA_GET_BE32(csuite
->vendor
);
473 specifier
= WPA_GET_BE16(csuite
->specifier
);
474 pos
+= sizeof(*csuite
);
475 if (vendor
!= data
->vendor
|| specifier
!= data
->specifier
) {
476 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
477 "match with the one sent in GPSK-2 (%d:%d)",
478 vendor
, specifier
, data
->vendor
, data
->specifier
);
486 static const u8
* eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data
*data
,
487 const u8
*pos
, const u8
*end
)
495 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
496 "PD_Payload_2 length");
499 alen
= WPA_GET_BE16(pos
);
501 if (end
- pos
< alen
) {
502 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
503 "%d-octet PD_Payload_2", alen
);
506 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_2", pos
, alen
);
513 static const u8
* eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data
*data
,
515 const u8
*pos
, const u8
*end
)
518 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
523 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
524 if (end
- pos
< (int) miclen
) {
525 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for MIC "
526 "(left=%lu miclen=%lu)",
527 (unsigned long) (end
- pos
),
528 (unsigned long) miclen
);
531 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
532 data
->specifier
, payload
, pos
- payload
, mic
)
534 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to compute MIC");
537 if (os_memcmp(mic
, pos
, miclen
) != 0) {
538 wpa_printf(MSG_INFO
, "EAP-GPSK: Incorrect MIC in GPSK-3");
539 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Received MIC", pos
, miclen
);
540 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Computed MIC", mic
, miclen
);
549 static struct wpabuf
* eap_gpsk_process_gpsk_3(struct eap_sm
*sm
,
550 struct eap_gpsk_data
*data
,
551 struct eap_method_ret
*ret
,
552 const struct wpabuf
*reqData
,
559 if (data
->state
!= GPSK_3
) {
564 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Request/GPSK-3");
566 end
= payload
+ payload_len
;
568 pos
= eap_gpsk_validate_rand(data
, payload
, end
);
569 pos
= eap_gpsk_validate_id_server(data
, pos
, end
);
570 pos
= eap_gpsk_validate_csuite(data
, pos
, end
);
571 pos
= eap_gpsk_validate_pd_payload_2(data
, pos
, end
);
572 pos
= eap_gpsk_validate_gpsk_3_mic(data
, payload
, pos
, end
);
575 eap_gpsk_state(data
, FAILURE
);
579 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %lu bytes of extra "
580 "data in the end of GPSK-2",
581 (unsigned long) (end
- pos
));
584 resp
= eap_gpsk_send_gpsk_4(data
, eap_get_id(reqData
));
588 eap_gpsk_state(data
, SUCCESS
);
589 ret
->methodState
= METHOD_DONE
;
590 ret
->decision
= DECISION_UNCOND_SUCC
;
596 static struct wpabuf
* eap_gpsk_send_gpsk_4(struct eap_gpsk_data
*data
,
603 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Sending Response/GPSK-4");
605 mlen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
607 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, 1 + 2 + mlen
,
608 EAP_CODE_RESPONSE
, identifier
);
612 wpabuf_put_u8(resp
, EAP_GPSK_OPCODE_GPSK_4
);
613 start
= wpabuf_put(resp
, 0);
615 /* No PD_Payload_3 */
616 wpabuf_put_be16(resp
, 0);
618 rpos
= wpabuf_put(resp
, mlen
);
619 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
620 data
->specifier
, start
, rpos
- start
, rpos
) <
622 eap_gpsk_state(data
, FAILURE
);
631 static struct wpabuf
* eap_gpsk_process(struct eap_sm
*sm
, void *priv
,
632 struct eap_method_ret
*ret
,
633 const struct wpabuf
*reqData
)
635 struct eap_gpsk_data
*data
= priv
;
640 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, reqData
, &len
);
641 if (pos
== NULL
|| len
< 1) {
646 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received frame: opcode %d", *pos
);
649 ret
->methodState
= METHOD_MAY_CONT
;
650 ret
->decision
= DECISION_FAIL
;
651 ret
->allowNotifications
= FALSE
;
654 case EAP_GPSK_OPCODE_GPSK_1
:
655 resp
= eap_gpsk_process_gpsk_1(sm
, data
, ret
, reqData
,
658 case EAP_GPSK_OPCODE_GPSK_3
:
659 resp
= eap_gpsk_process_gpsk_3(sm
, data
, ret
, reqData
,
663 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignoring message with "
664 "unknown opcode %d", *pos
);
673 static Boolean
eap_gpsk_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
675 struct eap_gpsk_data
*data
= priv
;
676 return data
->state
== SUCCESS
;
680 static u8
* eap_gpsk_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
682 struct eap_gpsk_data
*data
= priv
;
685 if (data
->state
!= SUCCESS
)
688 key
= os_malloc(EAP_MSK_LEN
);
691 os_memcpy(key
, data
->msk
, EAP_MSK_LEN
);
698 static u8
* eap_gpsk_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
700 struct eap_gpsk_data
*data
= priv
;
703 if (data
->state
!= SUCCESS
)
706 key
= os_malloc(EAP_EMSK_LEN
);
709 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
716 int eap_peer_gpsk_register(void)
718 struct eap_method
*eap
;
721 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
722 EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, "GPSK");
726 eap
->init
= eap_gpsk_init
;
727 eap
->deinit
= eap_gpsk_deinit
;
728 eap
->process
= eap_gpsk_process
;
729 eap
->isKeyAvailable
= eap_gpsk_isKeyAvailable
;
730 eap
->getKey
= eap_gpsk_getKey
;
731 eap
->get_emsk
= eap_gpsk_get_emsk
;
733 ret
= eap_peer_method_register(eap
);
735 eap_peer_method_free(eap
);