Home | History | Annotate | Download | only in eap_peer
      1 /*
      2  * EAP-IKEv2 peer (RFC 5106)
      3  * Copyright (c) 2007-2014, 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 
      9 #include "includes.h"
     10 
     11 #include "common.h"
     12 #include "eap_i.h"
     13 #include "eap_common/eap_ikev2_common.h"
     14 #include "ikev2.h"
     15 
     16 
     17 struct eap_ikev2_data {
     18 	struct ikev2_responder_data ikev2;
     19 	enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
     20 	struct wpabuf *in_buf;
     21 	struct wpabuf *out_buf;
     22 	size_t out_used;
     23 	size_t fragment_size;
     24 	int keys_ready;
     25 	u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN];
     26 	int keymat_ok;
     27 };
     28 
     29 
     30 static const char * eap_ikev2_state_txt(int state)
     31 {
     32 	switch (state) {
     33 	case WAIT_START:
     34 		return "WAIT_START";
     35 	case PROC_MSG:
     36 		return "PROC_MSG";
     37 	case WAIT_FRAG_ACK:
     38 		return "WAIT_FRAG_ACK";
     39 	case DONE:
     40 		return "DONE";
     41 	case FAIL:
     42 		return "FAIL";
     43 	default:
     44 		return "?";
     45 	}
     46 }
     47 
     48 
     49 static void eap_ikev2_state(struct eap_ikev2_data *data, int state)
     50 {
     51 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s",
     52 		   eap_ikev2_state_txt(data->state),
     53 		   eap_ikev2_state_txt(state));
     54 	data->state = state;
     55 }
     56 
     57 
     58 static void * eap_ikev2_init(struct eap_sm *sm)
     59 {
     60 	struct eap_ikev2_data *data;
     61 	const u8 *identity, *password;
     62 	size_t identity_len, password_len;
     63 	int fragment_size;
     64 
     65 	identity = eap_get_config_identity(sm, &identity_len);
     66 	if (identity == NULL) {
     67 		wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available");
     68 		return NULL;
     69 	}
     70 
     71 	data = os_zalloc(sizeof(*data));
     72 	if (data == NULL)
     73 		return NULL;
     74 	data->state = WAIT_START;
     75 	fragment_size = eap_get_config_fragment_size(sm);
     76 	if (fragment_size <= 0)
     77 		data->fragment_size = IKEV2_FRAGMENT_SIZE;
     78 	else
     79 		data->fragment_size = fragment_size;
     80 	data->ikev2.state = SA_INIT;
     81 	data->ikev2.peer_auth = PEER_AUTH_SECRET;
     82 	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
     83 	if (data->ikev2.key_pad == NULL)
     84 		goto failed;
     85 	data->ikev2.key_pad_len = 21;
     86 	data->ikev2.IDr = os_malloc(identity_len);
     87 	if (data->ikev2.IDr == NULL)
     88 		goto failed;
     89 	os_memcpy(data->ikev2.IDr, identity, identity_len);
     90 	data->ikev2.IDr_len = identity_len;
     91 
     92 	password = eap_get_config_password(sm, &password_len);
     93 	if (password) {
     94 		data->ikev2.shared_secret = os_malloc(password_len);
     95 		if (data->ikev2.shared_secret == NULL)
     96 			goto failed;
     97 		os_memcpy(data->ikev2.shared_secret, password, password_len);
     98 		data->ikev2.shared_secret_len = password_len;
     99 	}
    100 
    101 	return data;
    102 
    103 failed:
    104 	ikev2_responder_deinit(&data->ikev2);
    105 	os_free(data);
    106 	return NULL;
    107 }
    108 
    109 
    110 static void eap_ikev2_deinit(struct eap_sm *sm, void *priv)
    111 {
    112 	struct eap_ikev2_data *data = priv;
    113 	wpabuf_free(data->in_buf);
    114 	wpabuf_free(data->out_buf);
    115 	ikev2_responder_deinit(&data->ikev2);
    116 	bin_clear_free(data, sizeof(*data));
    117 }
    118 
    119 
    120 static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data)
    121 {
    122 	if (eap_ikev2_derive_keymat(
    123 		    data->ikev2.proposal.prf, &data->ikev2.keys,
    124 		    data->ikev2.i_nonce, data->ikev2.i_nonce_len,
    125 		    data->ikev2.r_nonce, data->ikev2.r_nonce_len,
    126 		    data->keymat) < 0) {
    127 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to "
    128 			   "derive key material");
    129 		return -1;
    130 	}
    131 	data->keymat_ok = 1;
    132 	return 0;
    133 }
    134 
    135 
    136 static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data,
    137 					   struct eap_method_ret *ret, u8 id)
    138 {
    139 	struct wpabuf *resp;
    140 	u8 flags;
    141 	size_t send_len, plen, icv_len = 0;
    142 
    143 	ret->ignore = FALSE;
    144 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response");
    145 	ret->allowNotifications = TRUE;
    146 
    147 	flags = 0;
    148 	send_len = wpabuf_len(data->out_buf) - data->out_used;
    149 	if (1 + send_len > data->fragment_size) {
    150 		send_len = data->fragment_size - 1;
    151 		flags |= IKEV2_FLAGS_MORE_FRAGMENTS;
    152 		if (data->out_used == 0) {
    153 			flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
    154 			send_len -= 4;
    155 		}
    156 	}
    157 
    158 	plen = 1 + send_len;
    159 	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
    160 		plen += 4;
    161 	if (data->keys_ready) {
    162 		const struct ikev2_integ_alg *integ;
    163 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum "
    164 			   "Data");
    165 		flags |= IKEV2_FLAGS_ICV_INCLUDED;
    166 		integ = ikev2_get_integ(data->ikev2.proposal.integ);
    167 		if (integ == NULL) {
    168 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
    169 				   "transform / cannot generate ICV");
    170 			return NULL;
    171 		}
    172 		icv_len = integ->hash_len;
    173 
    174 		plen += icv_len;
    175 	}
    176 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen,
    177 			     EAP_CODE_RESPONSE, id);
    178 	if (resp == NULL)
    179 		return NULL;
    180 
    181 	wpabuf_put_u8(resp, flags); /* Flags */
    182 	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
    183 		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
    184 
    185 	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
    186 			send_len);
    187 	data->out_used += send_len;
    188 
    189 	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
    190 		const u8 *msg = wpabuf_head(resp);
    191 		size_t len = wpabuf_len(resp);
    192 		ikev2_integ_hash(data->ikev2.proposal.integ,
    193 				 data->ikev2.keys.SK_ar,
    194 				 data->ikev2.keys.SK_integ_len,
    195 				 msg, len, wpabuf_put(resp, icv_len));
    196 	}
    197 
    198 	ret->methodState = METHOD_MAY_CONT;
    199 	ret->decision = DECISION_FAIL;
    200 
    201 	if (data->out_used == wpabuf_len(data->out_buf)) {
    202 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
    203 			   "(message sent completely)",
    204 			   (unsigned long) send_len);
    205 		wpabuf_free(data->out_buf);
    206 		data->out_buf = NULL;
    207 		data->out_used = 0;
    208 		switch (data->ikev2.state) {
    209 		case SA_AUTH:
    210 			/* SA_INIT was sent out, so message have to be
    211 			 * integrity protected from now on. */
    212 			data->keys_ready = 1;
    213 			break;
    214 		case IKEV2_DONE:
    215 			ret->methodState = METHOD_DONE;
    216 			if (data->state == FAIL)
    217 				break;
    218 			ret->decision = DECISION_COND_SUCC;
    219 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
    220 				   "completed successfully");
    221 			if (eap_ikev2_peer_keymat(data))
    222 				break;
    223 			eap_ikev2_state(data, DONE);
    224 			break;
    225 		case IKEV2_FAILED:
    226 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
    227 				   "failed");
    228 			ret->methodState = METHOD_DONE;
    229 			ret->decision = DECISION_FAIL;
    230 			break;
    231 		default:
    232 			break;
    233 		}
    234 	} else {
    235 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
    236 			   "(%lu more to send)", (unsigned long) send_len,
    237 			   (unsigned long) wpabuf_len(data->out_buf) -
    238 			   data->out_used);
    239 		eap_ikev2_state(data, WAIT_FRAG_ACK);
    240 	}
    241 
    242 	return resp;
    243 }
    244 
    245 
    246 static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
    247 				 const struct wpabuf *reqData,
    248 				 u8 flags, const u8 *pos, const u8 **end,
    249 				 int frag_ack)
    250 {
    251 	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
    252 		int icv_len = eap_ikev2_validate_icv(
    253 			data->ikev2.proposal.integ, &data->ikev2.keys, 1,
    254 			reqData, pos, *end);
    255 		if (icv_len < 0)
    256 			return -1;
    257 		/* Hide Integrity Checksum Data from further processing */
    258 		*end -= icv_len;
    259 	} else if (data->keys_ready && !frag_ack) {
    260 		wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
    261 			   "included integrity checksum");
    262 		return -1;
    263 	}
    264 
    265 	return 0;
    266 }
    267 
    268 
    269 static int eap_ikev2_process_cont(struct eap_ikev2_data *data,
    270 				  const u8 *buf, size_t len)
    271 {
    272 	/* Process continuation of a pending message */
    273 	if (len > wpabuf_tailroom(data->in_buf)) {
    274 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow");
    275 		eap_ikev2_state(data, FAIL);
    276 		return -1;
    277 	}
    278 
    279 	wpabuf_put_data(data->in_buf, buf, len);
    280 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting "
    281 		   "for %lu bytes more", (unsigned long) len,
    282 		   (unsigned long) wpabuf_tailroom(data->in_buf));
    283 
    284 	return 0;
    285 }
    286 
    287 
    288 static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data,
    289 						  struct eap_method_ret *ret,
    290 						  u8 id, u8 flags,
    291 						  u32 message_length,
    292 						  const u8 *buf, size_t len)
    293 {
    294 	/* Process a fragment that is not the last one of the message */
    295 	if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
    296 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
    297 			   "a fragmented packet");
    298 		ret->ignore = TRUE;
    299 		return NULL;
    300 	}
    301 
    302 	if (data->in_buf == NULL) {
    303 		/* First fragment of the message */
    304 		if (message_length > 50000) {
    305 			/* Limit maximum memory allocation */
    306 			wpa_printf(MSG_DEBUG,
    307 				   "EAP-IKEV2: Ignore too long message");
    308 			ret->ignore = TRUE;
    309 			return NULL;
    310 		}
    311 		data->in_buf = wpabuf_alloc(message_length);
    312 		if (data->in_buf == NULL) {
    313 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
    314 				   "message");
    315 			ret->ignore = TRUE;
    316 			return NULL;
    317 		}
    318 		wpabuf_put_data(data->in_buf, buf, len);
    319 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first "
    320 			   "fragment, waiting for %lu bytes more",
    321 			   (unsigned long) len,
    322 			   (unsigned long) wpabuf_tailroom(data->in_buf));
    323 	}
    324 
    325 	ret->ignore = FALSE;
    326 	return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
    327 }
    328 
    329 
    330 static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
    331 					 struct eap_method_ret *ret,
    332 					 const struct wpabuf *reqData)
    333 {
    334 	struct eap_ikev2_data *data = priv;
    335 	const u8 *start, *pos, *end;
    336 	size_t len;
    337 	u8 flags, id;
    338 	u32 message_length = 0;
    339 	struct wpabuf tmpbuf;
    340 
    341 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len);
    342 	if (pos == NULL) {
    343 		ret->ignore = TRUE;
    344 		return NULL;
    345 	}
    346 
    347 	id = eap_get_id(reqData);
    348 
    349 	start = pos;
    350 	end = start + len;
    351 
    352 	if (len == 0)
    353 		flags = 0; /* fragment ack */
    354 	else
    355 		flags = *pos++;
    356 
    357 	if (eap_ikev2_process_icv(data, reqData, flags, pos, &end,
    358 				  data->state == WAIT_FRAG_ACK && len == 0) < 0)
    359 	{
    360 		ret->ignore = TRUE;
    361 		return NULL;
    362 	}
    363 
    364 	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
    365 		if (end - pos < 4) {
    366 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
    367 			ret->ignore = TRUE;
    368 			return NULL;
    369 		}
    370 		message_length = WPA_GET_BE32(pos);
    371 		pos += 4;
    372 
    373 		if (message_length < (u32) (end - pos)) {
    374 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
    375 				   "Length (%d; %ld remaining in this msg)",
    376 				   message_length, (long) (end - pos));
    377 			ret->ignore = TRUE;
    378 			return NULL;
    379 		}
    380 	}
    381 
    382 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
    383 		   "Message Length %u", flags, message_length);
    384 
    385 	if (data->state == WAIT_FRAG_ACK) {
    386 		if (len != 0) {
    387 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
    388 				   "in WAIT_FRAG_ACK state");
    389 			ret->ignore = TRUE;
    390 			return NULL;
    391 		}
    392 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
    393 		eap_ikev2_state(data, PROC_MSG);
    394 		return eap_ikev2_build_msg(data, ret, id);
    395 	}
    396 
    397 	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
    398 		ret->ignore = TRUE;
    399 		return NULL;
    400 	}
    401 
    402 	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
    403 		return eap_ikev2_process_fragment(data, ret, id, flags,
    404 						  message_length, pos,
    405 						  end - pos);
    406 	}
    407 
    408 	if (data->in_buf == NULL) {
    409 		/* Wrap unfragmented messages as wpabuf without extra copy */
    410 		wpabuf_set(&tmpbuf, pos, end - pos);
    411 		data->in_buf = &tmpbuf;
    412 	}
    413 
    414 	if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) {
    415 		if (data->in_buf == &tmpbuf)
    416 			data->in_buf = NULL;
    417 		eap_ikev2_state(data, FAIL);
    418 		return NULL;
    419 	}
    420 
    421 	if (data->in_buf != &tmpbuf)
    422 		wpabuf_free(data->in_buf);
    423 	data->in_buf = NULL;
    424 
    425 	if (data->out_buf == NULL) {
    426 		data->out_buf = ikev2_responder_build(&data->ikev2);
    427 		if (data->out_buf == NULL) {
    428 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate "
    429 				   "IKEv2 message");
    430 			return NULL;
    431 		}
    432 		data->out_used = 0;
    433 	}
    434 
    435 	eap_ikev2_state(data, PROC_MSG);
    436 	return eap_ikev2_build_msg(data, ret, id);
    437 }
    438 
    439 
    440 static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
    441 {
    442 	struct eap_ikev2_data *data = priv;
    443 	return data->state == DONE && data->keymat_ok;
    444 }
    445 
    446 
    447 static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
    448 {
    449 	struct eap_ikev2_data *data = priv;
    450 	u8 *key;
    451 
    452 	if (data->state != DONE || !data->keymat_ok)
    453 		return NULL;
    454 
    455 	key = os_malloc(EAP_MSK_LEN);
    456 	if (key) {
    457 		os_memcpy(key, data->keymat, EAP_MSK_LEN);
    458 		*len = EAP_MSK_LEN;
    459 	}
    460 
    461 	return key;
    462 }
    463 
    464 
    465 static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
    466 {
    467 	struct eap_ikev2_data *data = priv;
    468 	u8 *key;
    469 
    470 	if (data->state != DONE || !data->keymat_ok)
    471 		return NULL;
    472 
    473 	key = os_malloc(EAP_EMSK_LEN);
    474 	if (key) {
    475 		os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
    476 		*len = EAP_EMSK_LEN;
    477 	}
    478 
    479 	return key;
    480 }
    481 
    482 
    483 static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
    484 {
    485 	struct eap_ikev2_data *data = priv;
    486 	u8 *sid;
    487 	size_t sid_len;
    488 	size_t offset;
    489 
    490 	if (data->state != DONE || !data->keymat_ok)
    491 		return NULL;
    492 
    493 	sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
    494 	sid = os_malloc(sid_len);
    495 	if (sid) {
    496 		offset = 0;
    497 		sid[offset] = EAP_TYPE_IKEV2;
    498 		offset++;
    499 		os_memcpy(sid + offset, data->ikev2.i_nonce,
    500 			  data->ikev2.i_nonce_len);
    501 		offset += data->ikev2.i_nonce_len;
    502 		os_memcpy(sid + offset, data->ikev2.r_nonce,
    503 			  data->ikev2.r_nonce_len);
    504 		*len = sid_len;
    505 		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
    506 			    sid, sid_len);
    507 	}
    508 
    509 	return sid;
    510 }
    511 
    512 
    513 int eap_peer_ikev2_register(void)
    514 {
    515 	struct eap_method *eap;
    516 
    517 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
    518 				    EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
    519 				    "IKEV2");
    520 	if (eap == NULL)
    521 		return -1;
    522 
    523 	eap->init = eap_ikev2_init;
    524 	eap->deinit = eap_ikev2_deinit;
    525 	eap->process = eap_ikev2_process;
    526 	eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
    527 	eap->getKey = eap_ikev2_getKey;
    528 	eap->get_emsk = eap_ikev2_get_emsk;
    529 	eap->getSessionId = eap_ikev2_get_session_id;
    530 
    531 	return eap_peer_method_register(eap);
    532 }
    533