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