Home | History | Annotate | Download | only in eap_peer
      1 /*
      2  * EAP peer method: EAP-PSK (RFC 4764)
      3  * Copyright (c) 2004-2008, Jouni Malinen <j (at) w1.fi>
      4  *
      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.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  *
     14  * Note: EAP-PSK is an EAP authentication method and as such, completely
     15  * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
     16  */
     17 
     18 #include "includes.h"
     19 
     20 #include "common.h"
     21 #include "crypto/aes_wrap.h"
     22 #include "crypto/random.h"
     23 #include "eap_common/eap_psk_common.h"
     24 #include "eap_i.h"
     25 
     26 
     27 struct eap_psk_data {
     28 	enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
     29 	u8 rand_p[EAP_PSK_RAND_LEN];
     30 	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
     31 	u8 *id_s, *id_p;
     32 	size_t id_s_len, id_p_len;
     33 	u8 msk[EAP_MSK_LEN];
     34 	u8 emsk[EAP_EMSK_LEN];
     35 };
     36 
     37 
     38 static void * eap_psk_init(struct eap_sm *sm)
     39 {
     40 	struct eap_psk_data *data;
     41 	const u8 *identity, *password;
     42 	size_t identity_len, password_len;
     43 
     44 	password = eap_get_config_password(sm, &password_len);
     45 	if (!password || password_len != 16) {
     46 		wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not "
     47 			   "configured");
     48 		return NULL;
     49 	}
     50 
     51 	data = os_zalloc(sizeof(*data));
     52 	if (data == NULL)
     53 		return NULL;
     54 	if (eap_psk_key_setup(password, data->ak, data->kdk)) {
     55 		os_free(data);
     56 		return NULL;
     57 	}
     58 	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
     59 	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
     60 	data->state = PSK_INIT;
     61 
     62 	identity = eap_get_config_identity(sm, &identity_len);
     63 	if (identity) {
     64 		data->id_p = os_malloc(identity_len);
     65 		if (data->id_p)
     66 			os_memcpy(data->id_p, identity, identity_len);
     67 		data->id_p_len = identity_len;
     68 	}
     69 	if (data->id_p == NULL) {
     70 		wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity");
     71 		os_free(data);
     72 		return NULL;
     73 	}
     74 
     75 	return data;
     76 }
     77 
     78 
     79 static void eap_psk_deinit(struct eap_sm *sm, void *priv)
     80 {
     81 	struct eap_psk_data *data = priv;
     82 	os_free(data->id_s);
     83 	os_free(data->id_p);
     84 	os_free(data);
     85 }
     86 
     87 
     88 static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
     89 					 struct eap_method_ret *ret,
     90 					 const struct wpabuf *reqData)
     91 {
     92 	const struct eap_psk_hdr_1 *hdr1;
     93 	struct eap_psk_hdr_2 *hdr2;
     94 	struct wpabuf *resp;
     95 	u8 *buf, *pos;
     96 	size_t buflen, len;
     97 	const u8 *cpos;
     98 
     99 	wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state");
    100 
    101 	cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
    102 	hdr1 = (const struct eap_psk_hdr_1 *) cpos;
    103 	if (cpos == NULL || len < sizeof(*hdr1)) {
    104 		wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message "
    105 			   "length (%lu; expected %lu or more)",
    106 			   (unsigned long) len,
    107 			   (unsigned long) sizeof(*hdr1));
    108 		ret->ignore = TRUE;
    109 		return NULL;
    110 	}
    111 	wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
    112 	if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) {
    113 		wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
    114 			   EAP_PSK_FLAGS_GET_T(hdr1->flags));
    115 		ret->methodState = METHOD_DONE;
    116 		ret->decision = DECISION_FAIL;
    117 		return NULL;
    118 	}
    119 	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
    120 		    EAP_PSK_RAND_LEN);
    121 	os_free(data->id_s);
    122 	data->id_s_len = len - sizeof(*hdr1);
    123 	data->id_s = os_malloc(data->id_s_len);
    124 	if (data->id_s == NULL) {
    125 		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
    126 			   "ID_S (len=%lu)", (unsigned long) data->id_s_len);
    127 		ret->ignore = TRUE;
    128 		return NULL;
    129 	}
    130 	os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
    131 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
    132 			  data->id_s, data->id_s_len);
    133 
    134 	if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) {
    135 		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
    136 		ret->ignore = TRUE;
    137 		return NULL;
    138 	}
    139 
    140 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
    141 			     sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE,
    142 			     eap_get_id(reqData));
    143 	if (resp == NULL)
    144 		return NULL;
    145 	hdr2 = wpabuf_put(resp, sizeof(*hdr2));
    146 	hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */
    147 	os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
    148 	os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
    149 	wpabuf_put_data(resp, data->id_p, data->id_p_len);
    150 	/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
    151 	buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
    152 	buf = os_malloc(buflen);
    153 	if (buf == NULL) {
    154 		wpabuf_free(resp);
    155 		return NULL;
    156 	}
    157 	os_memcpy(buf, data->id_p, data->id_p_len);
    158 	pos = buf + data->id_p_len;
    159 	os_memcpy(pos, data->id_s, data->id_s_len);
    160 	pos += data->id_s_len;
    161 	os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN);
    162 	pos += EAP_PSK_RAND_LEN;
    163 	os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
    164 	if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) {
    165 		os_free(buf);
    166 		wpabuf_free(resp);
    167 		return NULL;
    168 	}
    169 	os_free(buf);
    170 	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p,
    171 		    EAP_PSK_RAND_LEN);
    172 	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN);
    173 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P",
    174 			  data->id_p, data->id_p_len);
    175 
    176 	data->state = PSK_MAC_SENT;
    177 
    178 	return resp;
    179 }
    180 
    181 
    182 static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data,
    183 					 struct eap_method_ret *ret,
    184 					 const struct wpabuf *reqData)
    185 {
    186 	const struct eap_psk_hdr_3 *hdr3;
    187 	struct eap_psk_hdr_4 *hdr4;
    188 	struct wpabuf *resp;
    189 	u8 *buf, *rpchannel, nonce[16], *decrypted;
    190 	const u8 *pchannel, *tag, *msg;
    191 	u8 mac[EAP_PSK_MAC_LEN];
    192 	size_t buflen, left, data_len, len, plen;
    193 	int failed = 0;
    194 	const u8 *pos;
    195 
    196 	wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state");
    197 
    198 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK,
    199 			       reqData, &len);
    200 	hdr3 = (const struct eap_psk_hdr_3 *) pos;
    201 	if (pos == NULL || len < sizeof(*hdr3)) {
    202 		wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message "
    203 			   "length (%lu; expected %lu or more)",
    204 			   (unsigned long) len,
    205 			   (unsigned long) sizeof(*hdr3));
    206 		ret->ignore = TRUE;
    207 		return NULL;
    208 	}
    209 	left = len - sizeof(*hdr3);
    210 	pchannel = (const u8 *) (hdr3 + 1);
    211 	wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
    212 	if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) {
    213 		wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
    214 			   EAP_PSK_FLAGS_GET_T(hdr3->flags));
    215 		ret->methodState = METHOD_DONE;
    216 		ret->decision = DECISION_FAIL;
    217 		return NULL;
    218 	}
    219 	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
    220 		    EAP_PSK_RAND_LEN);
    221 	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN);
    222 	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left);
    223 
    224 	if (left < 4 + 16 + 1) {
    225 		wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
    226 			   "third message (len=%lu, expected 21)",
    227 			   (unsigned long) left);
    228 		ret->ignore = TRUE;
    229 		return NULL;
    230 	}
    231 
    232 	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
    233 	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
    234 	buf = os_malloc(buflen);
    235 	if (buf == NULL)
    236 		return NULL;
    237 	os_memcpy(buf, data->id_s, data->id_s_len);
    238 	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
    239 	if (omac1_aes_128(data->ak, buf, buflen, mac)) {
    240 		os_free(buf);
    241 		return NULL;
    242 	}
    243 	os_free(buf);
    244 	if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
    245 		wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
    246 			   "message");
    247 		ret->methodState = METHOD_DONE;
    248 		ret->decision = DECISION_FAIL;
    249 		return NULL;
    250 	}
    251 	wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully");
    252 
    253 	if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek,
    254 				data->msk, data->emsk)) {
    255 		ret->methodState = METHOD_DONE;
    256 		ret->decision = DECISION_FAIL;
    257 		return NULL;
    258 	}
    259 	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
    260 	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
    261 	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
    262 
    263 	os_memset(nonce, 0, 12);
    264 	os_memcpy(nonce + 12, pchannel, 4);
    265 	pchannel += 4;
    266 	left -= 4;
    267 
    268 	tag = pchannel;
    269 	pchannel += 16;
    270 	left -= 16;
    271 
    272 	msg = pchannel;
    273 
    274 	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce",
    275 		    nonce, sizeof(nonce));
    276 	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr",
    277 		    wpabuf_head(reqData), 5);
    278 	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
    279 
    280 	decrypted = os_malloc(left);
    281 	if (decrypted == NULL) {
    282 		ret->methodState = METHOD_DONE;
    283 		ret->decision = DECISION_FAIL;
    284 		return NULL;
    285 	}
    286 	os_memcpy(decrypted, msg, left);
    287 
    288 	if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
    289 				wpabuf_head(reqData),
    290 				sizeof(struct eap_hdr) + 1 +
    291 				sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted,
    292 				left, tag)) {
    293 		wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
    294 		os_free(decrypted);
    295 		return NULL;
    296 	}
    297 	wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
    298 		    decrypted, left);
    299 
    300 	/* Verify R flag */
    301 	switch (decrypted[0] >> 6) {
    302 	case EAP_PSK_R_FLAG_CONT:
    303 		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
    304 		failed = 1;
    305 		break;
    306 	case EAP_PSK_R_FLAG_DONE_SUCCESS:
    307 		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
    308 		break;
    309 	case EAP_PSK_R_FLAG_DONE_FAILURE:
    310 		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
    311 		wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected "
    312 			   "authentication");
    313 		failed = 1;
    314 		break;
    315 	}
    316 
    317 	data_len = 1;
    318 	if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1)
    319 		data_len++;
    320 	plen = sizeof(*hdr4) + 4 + 16 + data_len;
    321 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen,
    322 			     EAP_CODE_RESPONSE, eap_get_id(reqData));
    323 	if (resp == NULL) {
    324 		os_free(decrypted);
    325 		return NULL;
    326 	}
    327 	hdr4 = wpabuf_put(resp, sizeof(*hdr4));
    328 	hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */
    329 	os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
    330 	rpchannel = wpabuf_put(resp, 4 + 16 + data_len);
    331 
    332 	/* nonce++ */
    333 	inc_byte_array(nonce, sizeof(nonce));
    334 	os_memcpy(rpchannel, nonce + 12, 4);
    335 
    336 	if (decrypted[0] & EAP_PSK_E_FLAG) {
    337 		wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag");
    338 		failed = 1;
    339 		rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) |
    340 			EAP_PSK_E_FLAG;
    341 		if (left > 1) {
    342 			/* Add empty EXT_Payload with same EXT_Type */
    343 			rpchannel[4 + 16 + 1] = decrypted[1];
    344 		}
    345 	} else if (failed)
    346 		rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6;
    347 	else
    348 		rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
    349 
    350 	wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)",
    351 		    rpchannel + 4 + 16, data_len);
    352 	if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce),
    353 				wpabuf_head(resp),
    354 				sizeof(struct eap_hdr) + 1 + sizeof(*hdr4),
    355 				rpchannel + 4 + 16, data_len, rpchannel + 4)) {
    356 		os_free(decrypted);
    357 		wpabuf_free(resp);
    358 		return NULL;
    359 	}
    360 	wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)",
    361 		    rpchannel, 4 + 16 + data_len);
    362 
    363 	wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully",
    364 		   failed ? "un" : "");
    365 	data->state = PSK_DONE;
    366 	ret->methodState = METHOD_DONE;
    367 	ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
    368 
    369 	os_free(decrypted);
    370 
    371 	return resp;
    372 }
    373 
    374 
    375 static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv,
    376 				       struct eap_method_ret *ret,
    377 				       const struct wpabuf *reqData)
    378 {
    379 	struct eap_psk_data *data = priv;
    380 	const u8 *pos;
    381 	struct wpabuf *resp = NULL;
    382 	size_t len;
    383 
    384 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
    385 	if (pos == NULL) {
    386 		ret->ignore = TRUE;
    387 		return NULL;
    388 	}
    389 
    390 	ret->ignore = FALSE;
    391 	ret->methodState = METHOD_MAY_CONT;
    392 	ret->decision = DECISION_FAIL;
    393 	ret->allowNotifications = TRUE;
    394 
    395 	switch (data->state) {
    396 	case PSK_INIT:
    397 		resp = eap_psk_process_1(data, ret, reqData);
    398 		break;
    399 	case PSK_MAC_SENT:
    400 		resp = eap_psk_process_3(data, ret, reqData);
    401 		break;
    402 	case PSK_DONE:
    403 		wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
    404 			   "unexpected message");
    405 		ret->ignore = TRUE;
    406 		return NULL;
    407 	}
    408 
    409 	if (ret->methodState == METHOD_DONE) {
    410 		ret->allowNotifications = FALSE;
    411 	}
    412 
    413 	return resp;
    414 }
    415 
    416 
    417 static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
    418 {
    419 	struct eap_psk_data *data = priv;
    420 	return data->state == PSK_DONE;
    421 }
    422 
    423 
    424 static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
    425 {
    426 	struct eap_psk_data *data = priv;
    427 	u8 *key;
    428 
    429 	if (data->state != PSK_DONE)
    430 		return NULL;
    431 
    432 	key = os_malloc(EAP_MSK_LEN);
    433 	if (key == NULL)
    434 		return NULL;
    435 
    436 	*len = EAP_MSK_LEN;
    437 	os_memcpy(key, data->msk, EAP_MSK_LEN);
    438 
    439 	return key;
    440 }
    441 
    442 
    443 static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
    444 {
    445 	struct eap_psk_data *data = priv;
    446 	u8 *key;
    447 
    448 	if (data->state != PSK_DONE)
    449 		return NULL;
    450 
    451 	key = os_malloc(EAP_EMSK_LEN);
    452 	if (key == NULL)
    453 		return NULL;
    454 
    455 	*len = EAP_EMSK_LEN;
    456 	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
    457 
    458 	return key;
    459 }
    460 
    461 
    462 int eap_peer_psk_register(void)
    463 {
    464 	struct eap_method *eap;
    465 	int ret;
    466 
    467 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
    468 				    EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
    469 	if (eap == NULL)
    470 		return -1;
    471 
    472 	eap->init = eap_psk_init;
    473 	eap->deinit = eap_psk_deinit;
    474 	eap->process = eap_psk_process;
    475 	eap->isKeyAvailable = eap_psk_isKeyAvailable;
    476 	eap->getKey = eap_psk_getKey;
    477 	eap->get_emsk = eap_psk_get_emsk;
    478 
    479 	ret = eap_peer_method_register(eap);
    480 	if (ret)
    481 		eap_peer_method_free(eap);
    482 	return ret;
    483 }
    484