2 * hostapd / EAP-GPSK (RFC 5433) server
3 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "crypto/random.h"
13 #include "eap_server/eap_i.h"
14 #include "eap_common/eap_gpsk_common.h"
17 struct eap_gpsk_data
{
18 enum { GPSK_1
, GPSK_3
, SUCCESS
, FAILURE
} state
;
19 u8 rand_server
[EAP_GPSK_RAND_LEN
];
20 u8 rand_peer
[EAP_GPSK_RAND_LEN
];
22 u8 emsk
[EAP_EMSK_LEN
];
23 u8 sk
[EAP_GPSK_MAX_SK_LEN
];
25 u8 pk
[EAP_GPSK_MAX_PK_LEN
];
31 #define MAX_NUM_CSUITES 2
32 struct eap_gpsk_csuite csuite_list
[MAX_NUM_CSUITES
];
34 int vendor
; /* CSuite/Vendor */
35 int specifier
; /* CSuite/Specifier */
39 static const char * eap_gpsk_state_txt(int state
)
56 static void eap_gpsk_state(struct eap_gpsk_data
*data
, int state
)
58 wpa_printf(MSG_DEBUG
, "EAP-GPSK: %s -> %s",
59 eap_gpsk_state_txt(data
->state
),
60 eap_gpsk_state_txt(state
));
65 static void * eap_gpsk_init(struct eap_sm
*sm
)
67 struct eap_gpsk_data
*data
;
69 data
= os_zalloc(sizeof(*data
));
74 data
->csuite_count
= 0;
75 if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF
,
76 EAP_GPSK_CIPHER_AES
)) {
77 WPA_PUT_BE32(data
->csuite_list
[data
->csuite_count
].vendor
,
78 EAP_GPSK_VENDOR_IETF
);
79 WPA_PUT_BE16(data
->csuite_list
[data
->csuite_count
].specifier
,
83 if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF
,
84 EAP_GPSK_CIPHER_SHA256
)) {
85 WPA_PUT_BE32(data
->csuite_list
[data
->csuite_count
].vendor
,
86 EAP_GPSK_VENDOR_IETF
);
87 WPA_PUT_BE16(data
->csuite_list
[data
->csuite_count
].specifier
,
88 EAP_GPSK_CIPHER_SHA256
);
96 static void eap_gpsk_reset(struct eap_sm
*sm
, void *priv
)
98 struct eap_gpsk_data
*data
= priv
;
99 os_free(data
->id_peer
);
100 bin_clear_free(data
, sizeof(*data
));
104 static struct wpabuf
* eap_gpsk_build_gpsk_1(struct eap_sm
*sm
,
105 struct eap_gpsk_data
*data
, u8 id
)
110 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Request/GPSK-1");
112 if (random_get_bytes(data
->rand_server
, EAP_GPSK_RAND_LEN
)) {
113 wpa_printf(MSG_ERROR
, "EAP-GPSK: Failed to get random data");
114 eap_gpsk_state(data
, FAILURE
);
117 wpa_hexdump(MSG_MSGDUMP
, "EAP-GPSK: RAND_Server",
118 data
->rand_server
, EAP_GPSK_RAND_LEN
);
120 len
= 1 + 2 + sm
->server_id_len
+ EAP_GPSK_RAND_LEN
+ 2 +
121 data
->csuite_count
* sizeof(struct eap_gpsk_csuite
);
122 req
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, len
,
123 EAP_CODE_REQUEST
, id
);
125 wpa_printf(MSG_ERROR
, "EAP-GPSK: Failed to allocate memory "
126 "for request/GPSK-1");
127 eap_gpsk_state(data
, FAILURE
);
131 wpabuf_put_u8(req
, EAP_GPSK_OPCODE_GPSK_1
);
132 wpabuf_put_be16(req
, sm
->server_id_len
);
133 wpabuf_put_data(req
, sm
->server_id
, sm
->server_id_len
);
134 wpabuf_put_data(req
, data
->rand_server
, EAP_GPSK_RAND_LEN
);
136 data
->csuite_count
* sizeof(struct eap_gpsk_csuite
));
137 wpabuf_put_data(req
, data
->csuite_list
,
138 data
->csuite_count
* sizeof(struct eap_gpsk_csuite
));
144 static struct wpabuf
* eap_gpsk_build_gpsk_3(struct eap_sm
*sm
,
145 struct eap_gpsk_data
*data
, u8 id
)
149 struct eap_gpsk_csuite
*csuite
;
152 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Request/GPSK-3");
154 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
155 len
= 1 + 2 * EAP_GPSK_RAND_LEN
+ 2 + sm
->server_id_len
+
156 sizeof(struct eap_gpsk_csuite
) + 2 + miclen
;
157 req
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, len
,
158 EAP_CODE_REQUEST
, id
);
160 wpa_printf(MSG_ERROR
, "EAP-GPSK: Failed to allocate memory "
161 "for request/GPSK-3");
162 eap_gpsk_state(data
, FAILURE
);
166 wpabuf_put_u8(req
, EAP_GPSK_OPCODE_GPSK_3
);
167 start
= wpabuf_put(req
, 0);
169 wpabuf_put_data(req
, data
->rand_peer
, EAP_GPSK_RAND_LEN
);
170 wpabuf_put_data(req
, data
->rand_server
, EAP_GPSK_RAND_LEN
);
171 wpabuf_put_be16(req
, sm
->server_id_len
);
172 wpabuf_put_data(req
, sm
->server_id
, sm
->server_id_len
);
173 csuite
= wpabuf_put(req
, sizeof(*csuite
));
174 WPA_PUT_BE32(csuite
->vendor
, data
->vendor
);
175 WPA_PUT_BE16(csuite
->specifier
, data
->specifier
);
177 /* no PD_Payload_2 */
178 wpabuf_put_be16(req
, 0);
180 pos
= wpabuf_put(req
, miclen
);
181 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
182 data
->specifier
, start
, pos
- start
, pos
) < 0)
185 eap_gpsk_state(data
, FAILURE
);
193 static struct wpabuf
* eap_gpsk_buildReq(struct eap_sm
*sm
, void *priv
, u8 id
)
195 struct eap_gpsk_data
*data
= priv
;
197 switch (data
->state
) {
199 return eap_gpsk_build_gpsk_1(sm
, data
, id
);
201 return eap_gpsk_build_gpsk_3(sm
, data
, id
);
203 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Unknown state %d in buildReq",
211 static Boolean
eap_gpsk_check(struct eap_sm
*sm
, void *priv
,
212 struct wpabuf
*respData
)
214 struct eap_gpsk_data
*data
= priv
;
218 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, respData
, &len
);
219 if (pos
== NULL
|| len
< 1) {
220 wpa_printf(MSG_INFO
, "EAP-GPSK: Invalid frame");
224 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received frame: opcode=%d", *pos
);
226 if (data
->state
== GPSK_1
&& *pos
== EAP_GPSK_OPCODE_GPSK_2
)
229 if (data
->state
== GPSK_3
&& *pos
== EAP_GPSK_OPCODE_GPSK_4
)
232 wpa_printf(MSG_INFO
, "EAP-GPSK: Unexpected opcode=%d in state=%d",
239 static void eap_gpsk_process_gpsk_2(struct eap_sm
*sm
,
240 struct eap_gpsk_data
*data
,
241 const u8
*payload
, size_t payloadlen
)
245 const struct eap_gpsk_csuite
*csuite
;
247 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
249 if (data
->state
!= GPSK_1
)
252 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Response/GPSK-2");
255 end
= payload
+ payloadlen
;
258 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
260 eap_gpsk_state(data
, FAILURE
);
263 alen
= WPA_GET_BE16(pos
);
265 if (end
- pos
< alen
) {
266 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
268 eap_gpsk_state(data
, FAILURE
);
271 os_free(data
->id_peer
);
272 data
->id_peer
= os_memdup(pos
, alen
);
273 if (data
->id_peer
== NULL
) {
274 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Not enough memory to store "
275 "%d-octet ID_Peer", alen
);
278 data
->id_peer_len
= alen
;
279 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-GPSK: ID_Peer",
280 data
->id_peer
, data
->id_peer_len
);
284 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
286 eap_gpsk_state(data
, FAILURE
);
289 alen
= WPA_GET_BE16(pos
);
291 if (end
- pos
< alen
) {
292 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
294 eap_gpsk_state(data
, FAILURE
);
297 if (alen
!= sm
->server_id_len
||
298 os_memcmp(pos
, sm
->server_id
, alen
) != 0) {
299 wpa_printf(MSG_DEBUG
, "EAP-GPSK: ID_Server in GPSK-1 and "
300 "GPSK-2 did not match");
301 eap_gpsk_state(data
, FAILURE
);
306 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
307 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
309 eap_gpsk_state(data
, FAILURE
);
312 os_memcpy(data
->rand_peer
, pos
, EAP_GPSK_RAND_LEN
);
313 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Peer",
314 data
->rand_peer
, EAP_GPSK_RAND_LEN
);
315 pos
+= EAP_GPSK_RAND_LEN
;
317 if (end
- pos
< EAP_GPSK_RAND_LEN
) {
318 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
320 eap_gpsk_state(data
, FAILURE
);
323 if (os_memcmp(data
->rand_server
, pos
, EAP_GPSK_RAND_LEN
) != 0) {
324 wpa_printf(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-1 and "
325 "GPSK-2 did not match");
326 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-1",
327 data
->rand_server
, EAP_GPSK_RAND_LEN
);
328 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: RAND_Server in GPSK-2",
329 pos
, EAP_GPSK_RAND_LEN
);
330 eap_gpsk_state(data
, FAILURE
);
333 pos
+= EAP_GPSK_RAND_LEN
;
336 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
337 "CSuite_List length");
338 eap_gpsk_state(data
, FAILURE
);
341 alen
= WPA_GET_BE16(pos
);
343 if (end
- pos
< alen
) {
344 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
346 eap_gpsk_state(data
, FAILURE
);
349 if (alen
!= data
->csuite_count
* sizeof(struct eap_gpsk_csuite
) ||
350 os_memcmp(pos
, data
->csuite_list
, alen
) != 0) {
351 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite_List in GPSK-1 and "
352 "GPSK-2 did not match");
353 eap_gpsk_state(data
, FAILURE
);
358 if (end
- pos
< (int) sizeof(*csuite
)) {
359 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
361 eap_gpsk_state(data
, FAILURE
);
364 csuite
= (const struct eap_gpsk_csuite
*) pos
;
365 for (i
= 0; i
< data
->csuite_count
; i
++) {
366 if (os_memcmp(csuite
, &data
->csuite_list
[i
], sizeof(*csuite
))
370 if (i
== data
->csuite_count
) {
371 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Peer selected unsupported "
373 WPA_GET_BE32(csuite
->vendor
),
374 WPA_GET_BE16(csuite
->specifier
));
375 eap_gpsk_state(data
, FAILURE
);
378 data
->vendor
= WPA_GET_BE32(csuite
->vendor
);
379 data
->specifier
= WPA_GET_BE16(csuite
->specifier
);
380 wpa_printf(MSG_DEBUG
, "EAP-GPSK: CSuite_Sel %d:%d",
381 data
->vendor
, data
->specifier
);
382 pos
+= sizeof(*csuite
);
385 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
386 "PD_Payload_1 length");
387 eap_gpsk_state(data
, FAILURE
);
390 alen
= WPA_GET_BE16(pos
);
392 if (end
- pos
< alen
) {
393 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
395 eap_gpsk_state(data
, FAILURE
);
398 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_1", pos
, alen
);
401 if (sm
->user
== NULL
|| sm
->user
->password
== NULL
) {
402 wpa_printf(MSG_INFO
, "EAP-GPSK: No PSK/password configured "
404 eap_gpsk_state(data
, FAILURE
);
408 if (eap_gpsk_derive_keys(sm
->user
->password
, sm
->user
->password_len
,
409 data
->vendor
, data
->specifier
,
410 data
->rand_peer
, data
->rand_server
,
411 data
->id_peer
, data
->id_peer_len
,
412 sm
->server_id
, sm
->server_id_len
,
413 data
->msk
, data
->emsk
,
414 data
->sk
, &data
->sk_len
,
415 data
->pk
, &data
->pk_len
) < 0) {
416 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to derive keys");
417 eap_gpsk_state(data
, FAILURE
);
421 if (eap_gpsk_derive_session_id(sm
->user
->password
,
422 sm
->user
->password_len
,
423 data
->vendor
, data
->specifier
,
424 data
->rand_peer
, data
->rand_server
,
425 data
->id_peer
, data
->id_peer_len
,
426 sm
->server_id
, sm
->server_id_len
,
428 data
->session_id
, &data
->id_len
) < 0) {
429 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to derive Session-Id");
430 eap_gpsk_state(data
, FAILURE
);
433 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Derived Session-Id",
434 data
->session_id
, data
->id_len
);
436 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
437 if (end
- pos
< (int) miclen
) {
438 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for MIC "
439 "(left=%lu miclen=%lu)",
440 (unsigned long) (end
- pos
),
441 (unsigned long) miclen
);
442 eap_gpsk_state(data
, FAILURE
);
445 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
446 data
->specifier
, payload
, pos
- payload
, mic
)
448 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to compute MIC");
449 eap_gpsk_state(data
, FAILURE
);
452 if (os_memcmp_const(mic
, pos
, miclen
) != 0) {
453 wpa_printf(MSG_INFO
, "EAP-GPSK: Incorrect MIC in GPSK-2");
454 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Received MIC", pos
, miclen
);
455 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Computed MIC", mic
, miclen
);
456 eap_gpsk_state(data
, FAILURE
);
462 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %lu bytes of extra "
463 "data in the end of GPSK-2",
464 (unsigned long) (end
- pos
));
467 eap_gpsk_state(data
, GPSK_3
);
471 static void eap_gpsk_process_gpsk_4(struct eap_sm
*sm
,
472 struct eap_gpsk_data
*data
,
473 const u8
*payload
, size_t payloadlen
)
478 u8 mic
[EAP_GPSK_MAX_MIC_LEN
];
480 if (data
->state
!= GPSK_3
)
483 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Received Response/GPSK-4");
486 end
= payload
+ payloadlen
;
489 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
490 "PD_Payload_1 length");
491 eap_gpsk_state(data
, FAILURE
);
494 alen
= WPA_GET_BE16(pos
);
496 if (end
- pos
< alen
) {
497 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Too short message for "
499 eap_gpsk_state(data
, FAILURE
);
502 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: PD_Payload_1", pos
, alen
);
505 miclen
= eap_gpsk_mic_len(data
->vendor
, data
->specifier
);
506 if (end
- pos
< (int) miclen
) {
507 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Message too short for MIC "
508 "(left=%lu miclen=%lu)",
509 (unsigned long) (end
- pos
),
510 (unsigned long) miclen
);
511 eap_gpsk_state(data
, FAILURE
);
514 if (eap_gpsk_compute_mic(data
->sk
, data
->sk_len
, data
->vendor
,
515 data
->specifier
, payload
, pos
- payload
, mic
)
517 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Failed to compute MIC");
518 eap_gpsk_state(data
, FAILURE
);
521 if (os_memcmp_const(mic
, pos
, miclen
) != 0) {
522 wpa_printf(MSG_INFO
, "EAP-GPSK: Incorrect MIC in GPSK-4");
523 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Received MIC", pos
, miclen
);
524 wpa_hexdump(MSG_DEBUG
, "EAP-GPSK: Computed MIC", mic
, miclen
);
525 eap_gpsk_state(data
, FAILURE
);
531 wpa_printf(MSG_DEBUG
, "EAP-GPSK: Ignored %lu bytes of extra "
532 "data in the end of GPSK-4",
533 (unsigned long) (end
- pos
));
536 eap_gpsk_state(data
, SUCCESS
);
540 static void eap_gpsk_process(struct eap_sm
*sm
, void *priv
,
541 struct wpabuf
*respData
)
543 struct eap_gpsk_data
*data
= priv
;
547 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, respData
, &len
);
548 if (pos
== NULL
|| len
< 1)
552 case EAP_GPSK_OPCODE_GPSK_2
:
553 eap_gpsk_process_gpsk_2(sm
, data
, pos
+ 1, len
- 1);
555 case EAP_GPSK_OPCODE_GPSK_4
:
556 eap_gpsk_process_gpsk_4(sm
, data
, pos
+ 1, len
- 1);
562 static Boolean
eap_gpsk_isDone(struct eap_sm
*sm
, void *priv
)
564 struct eap_gpsk_data
*data
= priv
;
565 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
569 static u8
* eap_gpsk_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
571 struct eap_gpsk_data
*data
= priv
;
574 if (data
->state
!= SUCCESS
)
577 key
= os_memdup(data
->msk
, EAP_MSK_LEN
);
586 static u8
* eap_gpsk_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
588 struct eap_gpsk_data
*data
= priv
;
591 if (data
->state
!= SUCCESS
)
594 key
= os_memdup(data
->emsk
, EAP_EMSK_LEN
);
603 static Boolean
eap_gpsk_isSuccess(struct eap_sm
*sm
, void *priv
)
605 struct eap_gpsk_data
*data
= priv
;
606 return data
->state
== SUCCESS
;
610 static u8
* eap_gpsk_get_session_id(struct eap_sm
*sm
, void *priv
, size_t *len
)
612 struct eap_gpsk_data
*data
= priv
;
615 if (data
->state
!= SUCCESS
)
618 sid
= os_memdup(data
->session_id
, data
->id_len
);
627 int eap_server_gpsk_register(void)
629 struct eap_method
*eap
;
631 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
632 EAP_VENDOR_IETF
, EAP_TYPE_GPSK
, "GPSK");
636 eap
->init
= eap_gpsk_init
;
637 eap
->reset
= eap_gpsk_reset
;
638 eap
->buildReq
= eap_gpsk_buildReq
;
639 eap
->check
= eap_gpsk_check
;
640 eap
->process
= eap_gpsk_process
;
641 eap
->isDone
= eap_gpsk_isDone
;
642 eap
->getKey
= eap_gpsk_getKey
;
643 eap
->isSuccess
= eap_gpsk_isSuccess
;
644 eap
->get_emsk
= eap_gpsk_get_emsk
;
645 eap
->getSessionId
= eap_gpsk_get_session_id
;
647 return eap_server_method_register(eap
);