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);