2 * EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-08.txt)
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 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 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 const u8
* eap_gpsk_process_csuite_list(struct eap_sm
*sm
,
223 struct eap_gpsk_data
*data
,
224 const u8
**list
, size_t *list_len
,
225 const u8
*pos
, const u8
*end
)
231 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short GPSK-1 packet");
234 *list_len
= WPA_GET_BE16(pos
);
236 if (end
- pos
< (int) *list_len
) {
237 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite_List overflow");
240 if (*list_len
== 0 || (*list_len
% sizeof(struct eap_gpsk_csuite
))) {
241 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Invalid CSuite_List len %d",
248 if (eap_gpsk_select_csuite(sm
, data
, *list
, *list_len
) < 0)
255 static struct wpabuf
* eap_gpsk_process_gpsk_1(struct eap_sm
*sm
,
256 struct eap_gpsk_data
*data
,
257 struct eap_method_ret
*ret
,
258 const struct wpabuf
*reqData
,
262 size_t csuite_list_len
;
263 const u8
*csuite_list
, *pos
, *end
;
266 if (data
->state
!= GPSK_1
) {
271 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Request/GPSK-1");
273 end
= payload
+ payload_len
;
275 pos
= eap_gpsk_process_id_server(data
, payload
, end
);
276 pos
= eap_gpsk_process_rand_server(data
, pos
, end
);
277 pos
= eap_gpsk_process_csuite_list(sm
, data
, &csuite_list
,
278 &csuite_list_len
, pos
, end
);
280 eap_gpsk_state(data
, FAILURE
);
284 resp
= eap_gpsk_send_gpsk_2(data
, eap_get_id(reqData
),
285 csuite_list
, csuite_list_len
);
289 eap_gpsk_state(data
, GPSK_3
);
295 static struct wpabuf
* eap_gpsk_send_gpsk_2(struct eap_gpsk_data
*data
,
297 const u8
*csuite_list
,
298 size_t csuite_list_len
)
303 struct eap_gpsk_csuite
*csuite
;
305 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Sending Response/GPSK-2");
307 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
308 len
= 1 + 2 + data
->id_peer_len
+ 2 + data
->id_server_len
+
309 2 * EAP_GPSK_RAND_LEN
+ 2 + csuite_list_len
+
310 sizeof(struct eap_gpsk_csuite
) + 2 + miclen
;
312 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, len
,
313 EAP_CODE_RESPONSE
, identifier
);
317 wpabuf_put_u8(resp
, EAP_GPSK_OPCODE_GPSK_2
);
318 start
= wpabuf_put(resp
, 0);
320 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Peer",
321 data
->id_peer
, data
->id_peer_len
);
322 wpabuf_put_be16(resp
, data
->id_peer_len
);
323 wpabuf_put_data(resp
, data
->id_peer
, data
->id_peer_len
);
325 wpabuf_put_be16(resp
, data
->id_server_len
);
326 wpabuf_put_data(resp
, data
->id_server
, data
->id_server_len
);
328 if (os_get_random(data
->rand_peer
, EAP_GPSK_RAND_LEN
)) {
329 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to get random data "
331 eap_gpsk_state(data
, FAILURE
);
335 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Peer",
336 data
->rand_peer
, EAP_GPSK_RAND_LEN
);
337 wpabuf_put_data(resp
, data
->rand_peer
, EAP_GPSK_RAND_LEN
);
338 wpabuf_put_data(resp
, data
->rand_server
, EAP_GPSK_RAND_LEN
);
340 wpabuf_put_be16(resp
, csuite_list_len
);
341 wpabuf_put_data(resp
, csuite_list
, csuite_list_len
);
343 csuite
= wpabuf_put(resp
, sizeof(*csuite
));
344 WPA_PUT_BE32(csuite
->vendor
, data
->vendor
);
345 WPA_PUT_BE16(csuite
->specifier
, data
->specifier
);
347 if (eap_gpsk_derive_keys(data
->psk
, data
->psk_len
,
348 data
->vendor
, data
->specifier
,
349 data
->rand_peer
, data
->rand_server
,
350 data
->id_peer
, data
->id_peer_len
,
351 data
->id_server
, data
->id_server_len
,
352 data
->msk
, data
->emsk
,
353 data
->sk
, &data
->sk_len
,
354 data
->pk
, &data
->pk_len
) < 0) {
355 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to derive keys");
356 eap_gpsk_state(data
, FAILURE
);
361 /* No PD_Payload_1 */
362 wpabuf_put_be16(resp
, 0);
364 rpos
= wpabuf_put(resp
, miclen
);
365 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
366 data
->specifier
, start
, rpos
- start
, rpos
) <
368 eap_gpsk_state(data
, FAILURE
);
377 const u8
* eap_gpsk_validate_rand(struct eap_gpsk_data
*data
, const u8
*pos
,
380 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
381 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
385 if (os_memcmp(pos
, data
->rand_peer
, EAP_GPSK_RAND_LEN
) != 0) {
386 wpa_printf(MSG_DEBUG
, "EAP-GPSK: RAND_Peer in GPSK-2 and "
387 "GPSK-3 did not match");
388 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Peer in GPSK-2",
389 data
->rand_peer
, EAP_GPSK_RAND_LEN
);
390 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Peer in GPSK-3",
391 pos
, EAP_GPSK_RAND_LEN
);
394 pos
+= EAP_GPSK_RAND_LEN
;
396 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
397 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
401 if (os_memcmp(pos
, data
->rand_server
, EAP_GPSK_RAND_LEN
) != 0) {
402 wpa_printf(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-1 and "
403 "GPSK-3 did not match");
404 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-1",
405 data
->rand_server
, EAP_GPSK_RAND_LEN
);
406 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-3",
407 pos
, EAP_GPSK_RAND_LEN
);
410 pos
+= EAP_GPSK_RAND_LEN
;
416 const u8
* eap_gpsk_validate_id_server(struct eap_gpsk_data
*data
,
417 const u8
*pos
, const u8
*end
)
424 if (end
- pos
< (int) 2) {
425 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
426 "length(ID_Server)");
430 len
= WPA_GET_BE16(pos
);
433 if (end
- pos
< (int) len
) {
434 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
439 if (len
!= data
->id_server_len
||
440 os_memcmp(pos
, data
->id_server
, len
) != 0) {
441 wpa_printf(MSG_INFO
, "EAP-GPSK: ID_Server did not match with "
442 "the one used in GPSK-1");
443 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Server in GPSK-1",
444 data
->id_server
, data
->id_server_len
);
445 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Server in GPSK-3",
455 const u8
* eap_gpsk_validate_csuite(struct eap_gpsk_data
*data
, const u8
*pos
,
458 int vendor
, specifier
;
459 const struct eap_gpsk_csuite
*csuite
;
464 if (end
- pos
< (int) sizeof(*csuite
)) {
465 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
469 csuite
= (const struct eap_gpsk_csuite
*) pos
;
470 vendor
= WPA_GET_BE32(csuite
->vendor
);
471 specifier
= WPA_GET_BE16(csuite
->specifier
);
472 pos
+= sizeof(*csuite
);
473 if (vendor
!= data
->vendor
|| specifier
!= data
->specifier
) {
474 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
475 "match with the one sent in GPSK-2 (%d:%d)",
476 vendor
, specifier
, data
->vendor
, data
->specifier
);
484 const u8
* eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data
*data
,
485 const u8
*pos
, const u8
*end
)
493 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
494 "PD_Payload_2 length");
497 alen
= WPA_GET_BE16(pos
);
499 if (end
- pos
< alen
) {
500 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
501 "%d-octet PD_Payload_2", alen
);
504 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_2", pos
, alen
);
511 const u8
* eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data
*data
,
513 const u8
*pos
, const u8
*end
)
516 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
521 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
522 if (end
- pos
< (int) miclen
) {
523 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for MIC "
524 "(left=%d miclen=%d)", end
- pos
, miclen
);
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");
533 if (os_memcmp(mic
, pos
, miclen
) != 0) {
534 wpa_printf(MSG_INFO
, "EAP-GPSK: Incorrect MIC in GPSK-3");
535 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Received MIC", pos
, miclen
);
536 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Computed MIC", mic
, miclen
);
545 static struct wpabuf
* eap_gpsk_process_gpsk_3(struct eap_sm
*sm
,
546 struct eap_gpsk_data
*data
,
547 struct eap_method_ret
*ret
,
548 const struct wpabuf
*reqData
,
555 if (data
->state
!= GPSK_3
) {
560 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Request/GPSK-3");
562 end
= payload
+ payload_len
;
564 pos
= eap_gpsk_validate_rand(data
, payload
, end
);
565 pos
= eap_gpsk_validate_id_server(data
, pos
, end
);
566 pos
= eap_gpsk_validate_csuite(data
, pos
, end
);
567 pos
= eap_gpsk_validate_pd_payload_2(data
, pos
, end
);
568 pos
= eap_gpsk_validate_gpsk_3_mic(data
, payload
, pos
, end
);
571 eap_gpsk_state(data
, FAILURE
);
575 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %d bytes of extra "
576 "data in the end of GPSK-2", end
- pos
);
579 resp
= eap_gpsk_send_gpsk_4(data
, eap_get_id(reqData
));
583 eap_gpsk_state(data
, SUCCESS
);
584 ret
->methodState
= METHOD_DONE
;
585 ret
->decision
= DECISION_UNCOND_SUCC
;
591 static struct wpabuf
* eap_gpsk_send_gpsk_4(struct eap_gpsk_data
*data
,
598 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Sending Response/GPSK-4");
600 mlen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
602 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, 1 + 2 + mlen
,
603 EAP_CODE_RESPONSE
, identifier
);
607 wpabuf_put_u8(resp
, EAP_GPSK_OPCODE_GPSK_4
);
608 start
= wpabuf_put(resp
, 0);
610 /* No PD_Payload_3 */
611 wpabuf_put_be16(resp
, 0);
613 rpos
= wpabuf_put(resp
, mlen
);
614 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
615 data
->specifier
, start
, rpos
- start
, rpos
) <
617 eap_gpsk_state(data
, FAILURE
);
626 static struct wpabuf
* eap_gpsk_process(struct eap_sm
*sm
, void *priv
,
627 struct eap_method_ret
*ret
,
628 const struct wpabuf
*reqData
)
630 struct eap_gpsk_data
*data
= priv
;
635 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, reqData
, &len
);
636 if (pos
== NULL
|| len
< 1) {
641 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received frame: opcode %d", *pos
);
644 ret
->methodState
= METHOD_MAY_CONT
;
645 ret
->decision
= DECISION_FAIL
;
646 ret
->allowNotifications
= FALSE
;
649 case EAP_GPSK_OPCODE_GPSK_1
:
650 resp
= eap_gpsk_process_gpsk_1(sm
, data
, ret
, reqData
,
653 case EAP_GPSK_OPCODE_GPSK_3
:
654 resp
= eap_gpsk_process_gpsk_3(sm
, data
, ret
, reqData
,
658 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignoring message with "
659 "unknown opcode %d", *pos
);
668 static Boolean
eap_gpsk_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
670 struct eap_gpsk_data
*data
= priv
;
671 return data
->state
== SUCCESS
;
675 static u8
* eap_gpsk_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
677 struct eap_gpsk_data
*data
= priv
;
680 if (data
->state
!= SUCCESS
)
683 key
= os_malloc(EAP_MSK_LEN
);
686 os_memcpy(key
, data
->msk
, EAP_MSK_LEN
);
693 static u8
* eap_gpsk_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
695 struct eap_gpsk_data
*data
= priv
;
698 if (data
->state
!= SUCCESS
)
701 key
= os_malloc(EAP_EMSK_LEN
);
704 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
711 int eap_peer_gpsk_register(void)
713 struct eap_method
*eap
;
716 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
717 EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, "GPSK");
721 eap
->init
= eap_gpsk_init
;
722 eap
->deinit
= eap_gpsk_deinit
;
723 eap
->process
= eap_gpsk_process
;
724 eap
->isKeyAvailable
= eap_gpsk_isKeyAvailable
;
725 eap
->getKey
= eap_gpsk_getKey
;
726 eap
->get_emsk
= eap_gpsk_get_emsk
;
728 ret
= eap_peer_method_register(eap
);
730 eap_peer_method_free(eap
);