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