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