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 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 
     64 	identity = eap_get_config_identity(sm, &identity_len);
     65 	if (identity == NULL) {
     66 		wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available");
     67 		return NULL;
     68 	}
     69 
     70 	data = os_zalloc(sizeof(*data));
     71 	if (data == NULL)
     72 		return NULL;
     73 	data->state = WAIT_START;
     74 	data->fragment_size = IKEV2_FRAGMENT_SIZE;
     75 	data->ikev2.state = SA_INIT;
     76 	data->ikev2.peer_auth = PEER_AUTH_SECRET;
     77 	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
     78 	if (data->ikev2.key_pad == NULL)
     79 		goto failed;
     80 	data->ikev2.key_pad_len = 21;
     81 	data->ikev2.IDr = os_malloc(identity_len);
     82 	if (data->ikev2.IDr == NULL)
     83 		goto failed;
     84 	os_memcpy(data->ikev2.IDr, identity, identity_len);
     85 	data->ikev2.IDr_len = identity_len;
     86 
     87 	password = eap_get_config_password(sm, &password_len);
     88 	if (password) {
     89 		data->ikev2.shared_secret = os_malloc(password_len);
     90 		if (data->ikev2.shared_secret == NULL)
     91 			goto failed;
     92 		os_memcpy(data->ikev2.shared_secret, password, password_len);
     93 		data->ikev2.shared_secret_len = password_len;
     94 	}
     95 
     96 	return data;
     97 
     98 failed:
     99 	ikev2_responder_deinit(&data->ikev2);
    100 	os_free(data);
    101 	return NULL;
    102 }
    103 
    104 
    105 static void eap_ikev2_deinit(struct eap_sm *sm, void *priv)
    106 {
    107 	struct eap_ikev2_data *data = priv;
    108 	wpabuf_free(data->in_buf);
    109 	wpabuf_free(data->out_buf);
    110 	ikev2_responder_deinit(&data->ikev2);
    111 	os_free(data);
    112 }
    113 
    114 
    115 static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data)
    116 {
    117 	if (eap_ikev2_derive_keymat(
    118 		    data->ikev2.proposal.prf, &data->ikev2.keys,
    119 		    data->ikev2.i_nonce, data->ikev2.i_nonce_len,
    120 		    data->ikev2.r_nonce, data->ikev2.r_nonce_len,
    121 		    data->keymat) < 0) {
    122 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to "
    123 			   "derive key material");
    124 		return -1;
    125 	}
    126 	data->keymat_ok = 1;
    127 	return 0;
    128 }
    129 
    130 
    131 static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data,
    132 					   struct eap_method_ret *ret, u8 id)
    133 {
    134 	struct wpabuf *resp;
    135 	u8 flags;
    136 	size_t send_len, plen, icv_len = 0;
    137 
    138 	ret->ignore = FALSE;
    139 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response");
    140 	ret->allowNotifications = TRUE;
    141 
    142 	flags = 0;
    143 	send_len = wpabuf_len(data->out_buf) - data->out_used;
    144 	if (1 + send_len > data->fragment_size) {
    145 		send_len = data->fragment_size - 1;
    146 		flags |= IKEV2_FLAGS_MORE_FRAGMENTS;
    147 		if (data->out_used == 0) {
    148 			flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
    149 			send_len -= 4;
    150 		}
    151 	}
    152 #ifdef CCNS_PL
    153 	/* Some issues figuring out the length of the message if Message Length
    154 	 * field not included?! */
    155 	if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED))
    156 		flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
    157 #endif /* CCNS_PL */
    158 
    159 	plen = 1 + send_len;
    160 	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
    161 		plen += 4;
    162 	if (data->keys_ready) {
    163 		const struct ikev2_integ_alg *integ;
    164 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum "
    165 			   "Data");
    166 		flags |= IKEV2_FLAGS_ICV_INCLUDED;
    167 		integ = ikev2_get_integ(data->ikev2.proposal.integ);
    168 		if (integ == NULL) {
    169 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
    170 				   "transform / cannot generate ICV");
    171 			return NULL;
    172 		}
    173 		icv_len = integ->hash_len;
    174 
    175 		plen += icv_len;
    176 	}
    177 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen,
    178 			     EAP_CODE_RESPONSE, id);
    179 	if (resp == NULL)
    180 		return NULL;
    181 
    182 	wpabuf_put_u8(resp, flags); /* Flags */
    183 	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
    184 		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
    185 
    186 	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
    187 			send_len);
    188 	data->out_used += send_len;
    189 
    190 	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
    191 		const u8 *msg = wpabuf_head(resp);
    192 		size_t len = wpabuf_len(resp);
    193 		ikev2_integ_hash(data->ikev2.proposal.integ,
    194 				 data->ikev2.keys.SK_ar,
    195 				 data->ikev2.keys.SK_integ_len,
    196 				 msg, len, wpabuf_put(resp, icv_len));
    197 	}
    198 
    199 	ret->methodState = METHOD_MAY_CONT;
    200 	ret->decision = DECISION_FAIL;
    201 
    202 	if (data->out_used == wpabuf_len(data->out_buf)) {
    203 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
    204 			   "(message sent completely)",
    205 			   (unsigned long) send_len);
    206 		wpabuf_free(data->out_buf);
    207 		data->out_buf = NULL;
    208 		data->out_used = 0;
    209 		switch (data->ikev2.state) {
    210 		case SA_AUTH:
    211 			/* SA_INIT was sent out, so message have to be
    212 			 * integrity protected from now on. */
    213 			data->keys_ready = 1;
    214 			break;
    215 		case IKEV2_DONE:
    216 			ret->methodState = METHOD_DONE;
    217 			if (data->state == FAIL)
    218 				break;
    219 			ret->decision = DECISION_COND_SUCC;
    220 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
    221 				   "completed successfully");
    222 			if (eap_ikev2_peer_keymat(data))
    223 				break;
    224 			eap_ikev2_state(data, DONE);
    225 			break;
    226 		case IKEV2_FAILED:
    227 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
    228 				   "failed");
    229 			ret->methodState = METHOD_DONE;
    230 			ret->decision = DECISION_FAIL;
    231 			break;
    232 		default:
    233 			break;
    234 		}
    235 	} else {
    236 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
    237 			   "(%lu more to send)", (unsigned long) send_len,
    238 			   (unsigned long) wpabuf_len(data->out_buf) -
    239 			   data->out_used);
    240 		eap_ikev2_state(data, WAIT_FRAG_ACK);
    241 	}
    242 
    243 	return resp;
    244 }
    245 
    246 
    247 static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
    248 				 const struct wpabuf *reqData,
    249 				 u8 flags, const u8 *pos, const u8 **end)
    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) {
    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) < 0) {
    350 		ret->ignore = TRUE;
    351 		return NULL;
    352 	}
    353 
    354 	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
    355 		if (end - pos < 4) {
    356 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
    357 			ret->ignore = TRUE;
    358 			return NULL;
    359 		}
    360 		message_length = WPA_GET_BE32(pos);
    361 		pos += 4;
    362 
    363 		if (message_length < (u32) (end - pos)) {
    364 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
    365 				   "Length (%d; %ld remaining in this msg)",
    366 				   message_length, (long) (end - pos));
    367 			ret->ignore = TRUE;
    368 			return NULL;
    369 		}
    370 	}
    371 
    372 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
    373 		   "Message Length %u", flags, message_length);
    374 
    375 	if (data->state == WAIT_FRAG_ACK) {
    376 #ifdef CCNS_PL
    377 		if (len > 1) /* Empty Flags field included in ACK */
    378 #else /* CCNS_PL */
    379 		if (len != 0)
    380 #endif /* CCNS_PL */
    381 		{
    382 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
    383 				   "in WAIT_FRAG_ACK state");
    384 			ret->ignore = TRUE;
    385 			return NULL;
    386 		}
    387 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
    388 		eap_ikev2_state(data, PROC_MSG);
    389 		return eap_ikev2_build_msg(data, ret, id);
    390 	}
    391 
    392 	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
    393 		ret->ignore = TRUE;
    394 		return NULL;
    395 	}
    396 
    397 	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
    398 		return eap_ikev2_process_fragment(data, ret, id, flags,
    399 						  message_length, pos,
    400 						  end - pos);
    401 	}
    402 
    403 	if (data->in_buf == NULL) {
    404 		/* Wrap unfragmented messages as wpabuf without extra copy */
    405 		wpabuf_set(&tmpbuf, pos, end - pos);
    406 		data->in_buf = &tmpbuf;
    407 	}
    408 
    409 	if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) {
    410 		if (data->in_buf == &tmpbuf)
    411 			data->in_buf = NULL;
    412 		eap_ikev2_state(data, FAIL);
    413 		return NULL;
    414 	}
    415 
    416 	if (data->in_buf != &tmpbuf)
    417 		wpabuf_free(data->in_buf);
    418 	data->in_buf = NULL;
    419 
    420 	if (data->out_buf == NULL) {
    421 		data->out_buf = ikev2_responder_build(&data->ikev2);
    422 		if (data->out_buf == NULL) {
    423 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate "
    424 				   "IKEv2 message");
    425 			return NULL;
    426 		}
    427 		data->out_used = 0;
    428 	}
    429 
    430 	eap_ikev2_state(data, PROC_MSG);
    431 	return eap_ikev2_build_msg(data, ret, id);
    432 }
    433 
    434 
    435 static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
    436 {
    437 	struct eap_ikev2_data *data = priv;
    438 	return data->state == DONE && data->keymat_ok;
    439 }
    440 
    441 
    442 static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
    443 {
    444 	struct eap_ikev2_data *data = priv;
    445 	u8 *key;
    446 
    447 	if (data->state != DONE || !data->keymat_ok)
    448 		return NULL;
    449 
    450 	key = os_malloc(EAP_MSK_LEN);
    451 	if (key) {
    452 		os_memcpy(key, data->keymat, EAP_MSK_LEN);
    453 		*len = EAP_MSK_LEN;
    454 	}
    455 
    456 	return key;
    457 }
    458 
    459 
    460 static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
    461 {
    462 	struct eap_ikev2_data *data = priv;
    463 	u8 *key;
    464 
    465 	if (data->state != DONE || !data->keymat_ok)
    466 		return NULL;
    467 
    468 	key = os_malloc(EAP_EMSK_LEN);
    469 	if (key) {
    470 		os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
    471 		*len = EAP_EMSK_LEN;
    472 	}
    473 
    474 	return key;
    475 }
    476 
    477 
    478 static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
    479 {
    480 	struct eap_ikev2_data *data = priv;
    481 	u8 *sid;
    482 	size_t sid_len;
    483 	size_t offset;
    484 
    485 	if (data->state != DONE || !data->keymat_ok)
    486 		return NULL;
    487 
    488 	sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
    489 	sid = os_malloc(sid_len);
    490 	if (sid) {
    491 		offset = 0;
    492 		sid[offset] = EAP_TYPE_IKEV2;
    493 		offset++;
    494 		os_memcpy(sid + offset, data->ikev2.i_nonce,
    495 			  data->ikev2.i_nonce_len);
    496 		offset += data->ikev2.i_nonce_len;
    497 		os_memcpy(sid + offset, data->ikev2.r_nonce,
    498 			  data->ikev2.r_nonce_len);
    499 		*len = sid_len;
    500 		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
    501 			    sid, sid_len);
    502 	}
    503 
    504 	return sid;
    505 }
    506 
    507 
    508 int eap_peer_ikev2_register(void)
    509 {
    510 	struct eap_method *eap;
    511 	int ret;
    512 
    513 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
    514 				    EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
    515 				    "IKEV2");
    516 	if (eap == NULL)
    517 		return -1;
    518 
    519 	eap->init = eap_ikev2_init;
    520 	eap->deinit = eap_ikev2_deinit;
    521 	eap->process = eap_ikev2_process;
    522 	eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
    523 	eap->getKey = eap_ikev2_getKey;
    524 	eap->get_emsk = eap_ikev2_get_emsk;
    525 	eap->getSessionId = eap_ikev2_get_session_id;
    526 
    527 	ret = eap_peer_method_register(eap);
    528 	if (ret)
    529 		eap_peer_method_free(eap);
    530 	return ret;
    531 }
    532