2 * EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-03.txt)
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.
19 #include "config_ssid.h"
20 #include "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_client
[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
];
38 int vendor
; /* CSuite/Specifier */
39 int specifier
; /* CSuite/Specifier */
45 #ifndef CONFIG_NO_STDOUT_DEBUG
46 static const char * eap_gpsk_state_txt(int state
)
61 #endif /* CONFIG_NO_STDOUT_DEBUG */
64 static void eap_gpsk_state(struct eap_gpsk_data
*data
, int state
)
66 wpa_printf(MSG_DEBUG
, "EAP-GPSK: %s -> %s",
67 eap_gpsk_state_txt(data
->state
),
68 eap_gpsk_state_txt(state
));
73 static void eap_gpsk_deinit(struct eap_sm
*sm
, void *priv
);
76 static void * eap_gpsk_init(struct eap_sm
*sm
)
78 struct wpa_ssid
*config
= eap_get_config(sm
);
79 struct eap_gpsk_data
*data
;
82 wpa_printf(MSG_INFO
, "EAP-GPSK: No configuration found");
86 if (config
->eappsk
== NULL
) {
87 wpa_printf(MSG_INFO
, "EAP-GPSK: No key (eappsk) configured");
91 data
= os_zalloc(sizeof(*data
));
97 data
->id_client
= os_malloc(config
->nai_len
);
98 if (data
->id_client
== NULL
) {
99 eap_gpsk_deinit(sm
, data
);
102 os_memcpy(data
->id_client
, config
->nai
, config
->nai_len
);
103 data
->id_client_len
= config
->nai_len
;
106 data
->psk
= os_malloc(config
->eappsk_len
);
107 if (data
->psk
== NULL
) {
108 eap_gpsk_deinit(sm
, data
);
111 os_memcpy(data
->psk
, config
->eappsk
, config
->eappsk_len
);
112 data
->psk_len
= config
->eappsk_len
;
118 static void eap_gpsk_deinit(struct eap_sm
*sm
, void *priv
)
120 struct eap_gpsk_data
*data
= priv
;
121 os_free(data
->id_server
);
122 os_free(data
->id_client
);
128 static u8
* eap_gpsk_process_gpsk_1(struct eap_sm
*sm
,
129 struct eap_gpsk_data
*data
,
130 struct eap_method_ret
*ret
,
131 const u8
*reqData
, size_t reqDataLen
,
132 const u8
*payload
, size_t payload_len
,
135 size_t len
, csuite_list_len
, miclen
;
136 struct eap_hdr
*resp
;
138 const u8
*csuite_list
, *pos
, *end
;
139 const struct eap_hdr
*req
;
140 struct eap_gpsk_csuite
*csuite
;
144 if (data
->state
!= GPSK_1
) {
149 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Request/GPSK-1");
151 req
= (const struct eap_hdr
*) reqData
;
153 end
= payload
+ payload_len
;
156 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short GPSK-1 packet");
159 alen
= WPA_GET_BE16(pos
);
161 if (end
- pos
< alen
) {
162 wpa_printf(MSG_DEBUG
, "EAP-GPSK: ID_Server overflow");
165 os_free(data
->id_server
);
166 data
->id_server
= os_malloc(alen
);
167 if (data
->id_server
== NULL
) {
168 wpa_printf(MSG_DEBUG
, "EAP-GPSK: No memory for ID_Server");
171 os_memcpy(data
->id_server
, pos
, alen
);
172 data
->id_server_len
= alen
;
173 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Server",
174 data
->id_server
, data
->id_server_len
);
177 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
178 wpa_printf(MSG_DEBUG
, "EAP-GPSK: RAND_Server overflow");
181 os_memcpy(data
->rand_server
, pos
, EAP_GPSK_RAND_LEN
);
182 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server",
183 data
->rand_server
, EAP_GPSK_RAND_LEN
);
184 pos
+= EAP_GPSK_RAND_LEN
;
187 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short GPSK-1 packet");
190 csuite_list_len
= WPA_GET_BE16(pos
);
192 if (end
- pos
< (int) csuite_list_len
) {
193 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite_List overflow");
198 if (csuite_list_len
== 0 ||
199 csuite_list_len
% sizeof(struct eap_gpsk_csuite
)) {
200 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Invalid CSuite_List len %d",
204 count
= csuite_list_len
/ sizeof(struct eap_gpsk_csuite
);
205 data
->vendor
= EAP_GPSK_VENDOR_IETF
;
206 data
->specifier
= EAP_GPSK_CIPHER_RESERVED
;
207 csuite
= (struct eap_gpsk_csuite
*) csuite_list
;
208 for (i
= 0; i
< count
; i
++) {
209 int vendor
, specifier
;
210 vendor
= WPA_GET_BE24(csuite
->vendor
);
211 specifier
= WPA_GET_BE24(csuite
->specifier
);
212 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite[%d]: %d:%d",
213 i
, vendor
, specifier
);
214 if (data
->vendor
== EAP_GPSK_VENDOR_IETF
&&
215 data
->specifier
== EAP_GPSK_CIPHER_RESERVED
&&
216 eap_gpsk_supported_ciphersuite(vendor
, specifier
)) {
217 data
->vendor
= vendor
;
218 data
->specifier
= specifier
;
222 if (data
->vendor
== EAP_GPSK_VENDOR_IETF
&&
223 data
->specifier
== EAP_GPSK_CIPHER_RESERVED
) {
224 wpa_msg(sm
->msg_ctx
, MSG_INFO
, "EAP-GPSK: No supported "
225 "ciphersuite found");
226 eap_gpsk_state(data
, FAILURE
);
229 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Selected ciphersuite %d:%d",
230 data
->vendor
, data
->specifier
);
232 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Sending Response/GPSK-2");
234 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
235 len
= 1 + 2 + data
->id_client_len
+ 2 + data
->id_server_len
+
236 2 * EAP_GPSK_RAND_LEN
+ 2 + csuite_list_len
+
237 sizeof(struct eap_gpsk_csuite
) + 2 + miclen
;
239 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, respDataLen
, len
,
240 EAP_CODE_RESPONSE
, req
->identifier
, &rpos
);
244 *rpos
++ = EAP_GPSK_OPCODE_GPSK_2
;
247 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Client",
248 data
->id_client
, data
->id_client_len
);
249 WPA_PUT_BE16(rpos
, data
->id_client_len
);
252 os_memcpy(rpos
, data
->id_client
, data
->id_client_len
);
253 rpos
+= data
->id_client_len
;
255 WPA_PUT_BE16(rpos
, data
->id_server_len
);
258 os_memcpy(rpos
, data
->id_server
, data
->id_server_len
);
259 rpos
+= data
->id_server_len
;
261 if (os_get_random(data
->rand_client
, EAP_GPSK_RAND_LEN
)) {
262 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to get random data "
264 eap_gpsk_state(data
, FAILURE
);
268 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Client",
269 data
->rand_client
, EAP_GPSK_RAND_LEN
);
270 os_memcpy(rpos
, data
->rand_client
, EAP_GPSK_RAND_LEN
);
271 rpos
+= EAP_GPSK_RAND_LEN
;
273 os_memcpy(rpos
, data
->rand_server
, EAP_GPSK_RAND_LEN
);
274 rpos
+= EAP_GPSK_RAND_LEN
;
276 WPA_PUT_BE16(rpos
, csuite_list_len
);
278 os_memcpy(rpos
, csuite_list
, csuite_list_len
);
279 rpos
+= csuite_list_len
;
281 csuite
= (struct eap_gpsk_csuite
*) rpos
;
282 WPA_PUT_BE24(csuite
->vendor
, data
->vendor
);
283 WPA_PUT_BE24(csuite
->specifier
, data
->specifier
);
284 rpos
= (u8
*) (csuite
+ 1);
286 if (eap_gpsk_derive_keys(data
->psk
, data
->psk_len
,
287 data
->vendor
, data
->specifier
,
288 data
->rand_client
, data
->rand_server
,
289 data
->id_client
, data
->id_client_len
,
290 data
->id_server
, data
->id_server_len
,
291 data
->msk
, data
->emsk
,
292 data
->sk
, &data
->sk_len
,
293 data
->pk
, &data
->pk_len
) < 0) {
294 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to derive keys");
295 eap_gpsk_state(data
, FAILURE
);
300 /* No PD_Payload_1 */
301 WPA_PUT_BE16(rpos
, 0);
304 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
305 data
->specifier
, start
, rpos
- start
, rpos
) <
307 eap_gpsk_state(data
, FAILURE
);
312 eap_gpsk_state(data
, GPSK_3
);
318 static u8
* eap_gpsk_process_gpsk_3(struct eap_sm
*sm
,
319 struct eap_gpsk_data
*data
,
320 struct eap_method_ret
*ret
,
321 const u8
*reqData
, size_t reqDataLen
,
322 const u8
*payload
, size_t payload_len
,
326 struct eap_hdr
*resp
;
328 const struct eap_hdr
*req
;
331 int vendor
, specifier
;
332 const struct eap_gpsk_csuite
*csuite
;
333 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
335 if (data
->state
!= GPSK_3
) {
340 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Request/GPSK-3");
342 req
= (const struct eap_hdr
*) reqData
;
344 end
= payload
+ payload_len
;
346 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
347 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
351 if (os_memcmp(pos
, data
->rand_client
, EAP_GPSK_RAND_LEN
) != 0) {
352 wpa_printf(MSG_DEBUG
, "EAP-GPSK: RAND_Client in GPSK-2 and "
353 "GPSK-3 did not match");
354 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Client in GPSK-2",
355 data
->rand_client
, EAP_GPSK_RAND_LEN
);
356 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Client in GPSK-3",
357 pos
, EAP_GPSK_RAND_LEN
);
358 eap_gpsk_state(data
, FAILURE
);
361 pos
+= EAP_GPSK_RAND_LEN
;
363 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
364 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
368 if (os_memcmp(pos
, data
->rand_server
, EAP_GPSK_RAND_LEN
) != 0) {
369 wpa_printf(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-1 and "
370 "GPSK-3 did not match");
371 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-1",
372 data
->rand_server
, EAP_GPSK_RAND_LEN
);
373 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-3",
374 pos
, EAP_GPSK_RAND_LEN
);
375 eap_gpsk_state(data
, FAILURE
);
378 pos
+= EAP_GPSK_RAND_LEN
;
380 if (end
- pos
< (int) sizeof(*csuite
)) {
381 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
385 csuite
= (const struct eap_gpsk_csuite
*) pos
;
386 vendor
= WPA_GET_BE24(csuite
->vendor
);
387 specifier
= WPA_GET_BE24(csuite
->specifier
);
388 pos
+= sizeof(*csuite
);
389 if (vendor
!= data
->vendor
|| specifier
!= data
->specifier
) {
390 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
391 "match with the one sent in GPSK-2 (%d:%d)",
392 vendor
, specifier
, data
->vendor
, data
->specifier
);
393 eap_gpsk_state(data
, FAILURE
);
398 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
399 "PD_Payload_2 length");
400 eap_gpsk_state(data
, FAILURE
);
403 alen
= WPA_GET_BE16(pos
);
405 if (end
- pos
< alen
) {
406 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for "
407 "%d-octet PD_Payload_2", alen
);
408 eap_gpsk_state(data
, FAILURE
);
411 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_2", pos
, alen
);
413 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
414 if (end
- pos
< (int) miclen
) {
415 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for MIC "
416 "(left=%d miclen=%d)", end
- pos
, miclen
);
417 eap_gpsk_state(data
, FAILURE
);
420 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
421 data
->specifier
, payload
, pos
- payload
, mic
)
423 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to compute MIC");
424 eap_gpsk_state(data
, FAILURE
);
427 if (os_memcmp(mic
, pos
, miclen
) != 0) {
428 wpa_printf(MSG_INFO
, "EAP-GPSK: Incorrect MIC in GPSK-3");
429 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Received MIC", pos
, miclen
);
430 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Computed MIC", mic
, miclen
);
431 eap_gpsk_state(data
, FAILURE
);
437 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %d bytes of extra "
438 "data in the end of GPSK-2", end
- pos
);
441 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Sending Response/GPSK-4");
443 len
= 1 + 2 + miclen
;
445 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, respDataLen
, len
,
446 EAP_CODE_RESPONSE
, req
->identifier
, &rpos
);
450 *rpos
++ = EAP_GPSK_OPCODE_GPSK_4
;
453 /* No PD_Payload_3 */
454 WPA_PUT_BE16(rpos
, 0);
457 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
458 data
->specifier
, start
, rpos
- start
, rpos
) <
460 eap_gpsk_state(data
, FAILURE
);
465 eap_gpsk_state(data
, SUCCESS
);
466 ret
->methodState
= METHOD_DONE
;
467 ret
->decision
= DECISION_UNCOND_SUCC
;
473 static u8
* eap_gpsk_process(struct eap_sm
*sm
, void *priv
,
474 struct eap_method_ret
*ret
,
475 const u8
*reqData
, size_t reqDataLen
,
478 struct eap_gpsk_data
*data
= priv
;
483 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
,
484 reqData
, reqDataLen
, &len
);
485 if (pos
== NULL
|| len
< 1) {
490 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received frame: opcode %d", *pos
);
493 ret
->methodState
= METHOD_MAY_CONT
;
494 ret
->decision
= DECISION_FAIL
;
495 ret
->allowNotifications
= FALSE
;
498 case EAP_GPSK_OPCODE_GPSK_1
:
499 resp
= eap_gpsk_process_gpsk_1(sm
, data
, ret
, reqData
,
500 reqDataLen
, pos
+ 1, len
- 1,
503 case EAP_GPSK_OPCODE_GPSK_3
:
504 resp
= eap_gpsk_process_gpsk_3(sm
, data
, ret
, reqData
,
505 reqDataLen
, pos
+ 1, len
- 1,
509 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignoring message with "
510 "unknown opcode %d", *pos
);
519 static Boolean
eap_gpsk_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
521 struct eap_gpsk_data
*data
= priv
;
522 return data
->state
== SUCCESS
;
526 static u8
* eap_gpsk_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
528 struct eap_gpsk_data
*data
= priv
;
531 if (data
->state
!= SUCCESS
)
534 key
= os_malloc(EAP_MSK_LEN
);
537 os_memcpy(key
, data
->msk
, EAP_MSK_LEN
);
544 static u8
* eap_gpsk_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
546 struct eap_gpsk_data
*data
= priv
;
549 if (data
->state
!= SUCCESS
)
552 key
= os_malloc(EAP_EMSK_LEN
);
555 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
562 int eap_peer_gpsk_register(void)
564 struct eap_method
*eap
;
567 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
568 EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, "GPSK");
572 eap
->init
= eap_gpsk_init
;
573 eap
->deinit
= eap_gpsk_deinit
;
574 eap
->process
= eap_gpsk_process
;
575 eap
->isKeyAvailable
= eap_gpsk_isKeyAvailable
;
576 eap
->getKey
= eap_gpsk_getKey
;
577 eap
->get_emsk
= eap_gpsk_get_emsk
;
579 ret
= eap_peer_method_register(eap
);
581 eap_peer_method_free(eap
);