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 		data->in_buf = wpabuf_alloc(message_length);
    305 		if (data->in_buf == NULL) {
    306 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
    307 				   "message");
    308 			ret->ignore = TRUE;
    309 			return NULL;
    310 		}
    311 		wpabuf_put_data(data->in_buf, buf, len);
    312 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first "
    313 			   "fragment, waiting for %lu bytes more",
    314 			   (unsigned long) len,
    315 			   (unsigned long) wpabuf_tailroom(data->in_buf));
    316 	}
    317 
    318 	return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
    319 }
    320 
    321 
    322 static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
    323 					 struct eap_method_ret *ret,
    324 					 const struct wpabuf *reqData)
    325 {
    326 	struct eap_ikev2_data *data = priv;
    327 	const u8 *start, *pos, *end;
    328 	size_t len;
    329 	u8 flags, id;
    330 	u32 message_length = 0;
    331 	struct wpabuf tmpbuf;
    332 
    333 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len);
    334 	if (pos == NULL) {
    335 		ret->ignore = TRUE;
    336 		return NULL;
    337 	}
    338 
    339 	id = eap_get_id(reqData);
    340 
    341 	start = pos;
    342 	end = start + len;
    343 
    344 	if (len == 0)
    345 		flags = 0; /* fragment ack */
    346 	else
    347 		flags = *pos++;
    348 
    349 	if (eap_ikev2_process_icv(data, reqData, flags, pos, &end,
    350 				  data->state == WAIT_FRAG_ACK && len == 0) < 0)
    351 	{
    352 		ret->ignore = TRUE;
    353 		return NULL;
    354 	}
    355 
    356 	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
    357 		if (end - pos < 4) {
    358 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
    359 			ret->ignore = TRUE;
    360 			return NULL;
    361 		}
    362 		message_length = WPA_GET_BE32(pos);
    363 		pos += 4;
    364 
    365 		if (message_length < (u32) (end - pos)) {
    366 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
    367 				   "Length (%d; %ld remaining in this msg)",
    368 				   message_length, (long) (end - pos));
    369 			ret->ignore = TRUE;
    370 			return NULL;
    371 		}
    372 	}
    373 
    374 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
    375 		   "Message Length %u", flags, message_length);
    376 
    377 	if (data->state == WAIT_FRAG_ACK) {
    378 		if (len != 0) {
    379 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
    380 				   "in WAIT_FRAG_ACK state");
    381 			ret->ignore = TRUE;
    382 			return NULL;
    383 		}
    384 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
    385 		eap_ikev2_state(data, PROC_MSG);
    386 		return eap_ikev2_build_msg(data, ret, id);
    387 	}
    388 
    389 	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
    390 		ret->ignore = TRUE;
    391 		return NULL;
    392 	}
    393 
    394 	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
    395 		return eap_ikev2_process_fragment(data, ret, id, flags,
    396 						  message_length, pos,
    397 						  end - pos);
    398 	}
    399 
    400 	if (data->in_buf == NULL) {
    401 		/* Wrap unfragmented messages as wpabuf without extra copy */
    402 		wpabuf_set(&tmpbuf, pos, end - pos);
    403 		data->in_buf = &tmpbuf;
    404 	}
    405 
    406 	if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) {
    407 		if (data->in_buf == &tmpbuf)
    408 			data->in_buf = NULL;
    409 		eap_ikev2_state(data, FAIL);
    410 		return NULL;
    411 	}
    412 
    413 	if (data->in_buf != &tmpbuf)
    414 		wpabuf_free(data->in_buf);
    415 	data->in_buf = NULL;
    416 
    417 	if (data->out_buf == NULL) {
    418 		data->out_buf = ikev2_responder_build(&data->ikev2);
    419 		if (data->out_buf == NULL) {
    420 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate "
    421 				   "IKEv2 message");
    422 			return NULL;
    423 		}
    424 		data->out_used = 0;
    425 	}
    426 
    427 	eap_ikev2_state(data, PROC_MSG);
    428 	return eap_ikev2_build_msg(data, ret, id);
    429 }
    430 
    431 
    432 static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
    433 {
    434 	struct eap_ikev2_data *data = priv;
    435 	return data->state == DONE && data->keymat_ok;
    436 }
    437 
    438 
    439 static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
    440 {
    441 	struct eap_ikev2_data *data = priv;
    442 	u8 *key;
    443 
    444 	if (data->state != DONE || !data->keymat_ok)
    445 		return NULL;
    446 
    447 	key = os_malloc(EAP_MSK_LEN);
    448 	if (key) {
    449 		os_memcpy(key, data->keymat, EAP_MSK_LEN);
    450 		*len = EAP_MSK_LEN;
    451 	}
    452 
    453 	return key;
    454 }
    455 
    456 
    457 static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
    458 {
    459 	struct eap_ikev2_data *data = priv;
    460 	u8 *key;
    461 
    462 	if (data->state != DONE || !data->keymat_ok)
    463 		return NULL;
    464 
    465 	key = os_malloc(EAP_EMSK_LEN);
    466 	if (key) {
    467 		os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
    468 		*len = EAP_EMSK_LEN;
    469 	}
    470 
    471 	return key;
    472 }
    473 
    474 
    475 static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
    476 {
    477 	struct eap_ikev2_data *data = priv;
    478 	u8 *sid;
    479 	size_t sid_len;
    480 	size_t offset;
    481 
    482 	if (data->state != DONE || !data->keymat_ok)
    483 		return NULL;
    484 
    485 	sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
    486 	sid = os_malloc(sid_len);
    487 	if (sid) {
    488 		offset = 0;
    489 		sid[offset] = EAP_TYPE_IKEV2;
    490 		offset++;
    491 		os_memcpy(sid + offset, data->ikev2.i_nonce,
    492 			  data->ikev2.i_nonce_len);
    493 		offset += data->ikev2.i_nonce_len;
    494 		os_memcpy(sid + offset, data->ikev2.r_nonce,
    495 			  data->ikev2.r_nonce_len);
    496 		*len = sid_len;
    497 		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
    498 			    sid, sid_len);
    499 	}
    500 
    501 	return sid;
    502 }
    503 
    504 
    505 int eap_peer_ikev2_register(void)
    506 {
    507 	struct eap_method *eap;
    508 	int ret;
    509 
    510 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
    511 				    EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
    512 				    "IKEV2");
    513 	if (eap == NULL)
    514 		return -1;
    515 
    516 	eap->init = eap_ikev2_init;
    517 	eap->deinit = eap_ikev2_deinit;
    518 	eap->process = eap_ikev2_process;
    519 	eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
    520 	eap->getKey = eap_ikev2_getKey;
    521 	eap->get_emsk = eap_ikev2_get_emsk;
    522 	eap->getSessionId = eap_ikev2_get_session_id;
    523 
    524 	ret = eap_peer_method_register(eap);
    525 	if (ret)
    526 		eap_peer_method_free(eap);
    527 	return ret;
    528 }
    529