예제 #1
0
파일: eap.c 프로젝트: SylvestreG/bitrig
int
eap_challenge_request(struct iked *env, struct iked_sa *sa,
    struct eap_header *hdr)
{
	struct eap_message		*eap;
	struct eap_mschap_challenge	*ms;
	const char			*name;
	int				 ret = -1;
	struct ibuf			*e;

	if ((e = ibuf_static()) == NULL)
		return (-1);

	if ((eap = ibuf_advance(e, sizeof(*eap))) == NULL)
		goto done;
	eap->eap_code = EAP_CODE_REQUEST;
	eap->eap_id = hdr->eap_id + 1;
	eap->eap_type = sa->sa_policy->pol_auth.auth_eap;

	switch (sa->sa_policy->pol_auth.auth_eap) {
	case EAP_TYPE_MSCHAP_V2:
		name = IKED_USER;	/* XXX should be user-configurable */
		eap->eap_length = htobe16(sizeof(*eap) +
		    sizeof(*ms) + strlen(name));

		if ((ms = ibuf_advance(e, sizeof(*ms))) == NULL)
			return (-1);
		ms->msc_opcode = EAP_MSOPCODE_CHALLENGE;
		ms->msc_id = eap->eap_id;
		ms->msc_length = htobe16(sizeof(*ms) + strlen(name));
		ms->msc_valuesize = sizeof(ms->msc_challenge);
		arc4random_buf(ms->msc_challenge, sizeof(ms->msc_challenge));
		if (ibuf_add(e, name, strlen(name)) == -1)
			goto done;

		/* Store the EAP challenge value */
		sa->sa_eap.id_type = eap->eap_type;
		if ((sa->sa_eap.id_buf = ibuf_new(ms->msc_challenge,
		    sizeof(ms->msc_challenge))) == NULL)
			goto done;
		break;
	default:
		log_debug("%s: unsupported EAP type %s", __func__,
		    print_map(eap->eap_type, eap_type_map));
		goto done;
	}

	ret = ikev2_send_ike_e(env, sa, e,
	    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);

 done:
	ibuf_release(e);

	return (ret);
}
예제 #2
0
파일: ikev2_msg.c 프로젝트: xcllnt/openiked
struct ibuf *
ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response)
{
	struct ibuf		*authmsg = NULL, *nonce, *prfkey, *buf;
	uint8_t			*ptr;
	struct iked_id		*id;
	size_t			 tmplen;

	/*
	 * Create the payload to be signed/MAC'ed for AUTH
	 */

	if (!response) {
		if ((nonce = sa->sa_rnonce) == NULL ||
		    (sa->sa_iid.id_type == 0) ||
		    (prfkey = sa->sa_key_iprf) == NULL ||
		    (buf = sa->sa_1stmsg) == NULL)
			return (NULL);
		id = &sa->sa_iid;
	} else {
		if ((nonce = sa->sa_inonce) == NULL ||
		    (sa->sa_rid.id_type == 0) ||
		    (prfkey = sa->sa_key_rprf) == NULL ||
		    (buf = sa->sa_2ndmsg) == NULL)
			return (NULL);
		id = &sa->sa_rid;
	}

	if ((authmsg = ibuf_dup(buf)) == NULL)
		return (NULL);
	if (ibuf_cat(authmsg, nonce) != 0)
		goto fail;

	if ((hash_setkey(sa->sa_prf, ibuf_data(prfkey),
	    ibuf_size(prfkey))) == NULL)
		goto fail;

	if ((ptr = ibuf_advance(authmsg,
	    hash_length(sa->sa_prf))) == NULL)
		goto fail;

	hash_init(sa->sa_prf);
	hash_update(sa->sa_prf, ibuf_data(id->id_buf), ibuf_size(id->id_buf));
	hash_final(sa->sa_prf, ptr, &tmplen);

	if (tmplen != hash_length(sa->sa_prf))
		goto fail;

	log_debug("%s: %s auth data length %zu",
	    __func__, response ? "responder" : "initiator",
	    ibuf_size(authmsg));
	print_hex(ibuf_data(authmsg), 0, ibuf_size(authmsg));

	return (authmsg);

 fail:
	ibuf_release(authmsg);
	return (NULL);
}
예제 #3
0
파일: eap.c 프로젝트: SylvestreG/bitrig
ssize_t
eap_identity_request(struct ibuf *e)
{
	struct eap_message		*eap;

	if ((eap = ibuf_advance(e, sizeof(*eap))) == NULL)
		return (-1);
	eap->eap_code = EAP_CODE_REQUEST;
	eap->eap_id = 0;
	eap->eap_length = htobe16(sizeof(*eap));
	eap->eap_type = EAP_TYPE_IDENTITY;

	return (sizeof(*eap));
}
예제 #4
0
파일: eap.c 프로젝트: SylvestreG/bitrig
int
eap_success(struct iked *env, struct iked_sa *sa, struct eap_header *hdr)
{
	struct eap_header		*resp;
	int				 ret = -1;
	struct ibuf			*e;

	if ((e = ibuf_static()) == NULL)
		return (-1);

	if ((resp = ibuf_advance(e, sizeof(*resp))) == NULL)
		goto done;
	resp->eap_code = EAP_CODE_SUCCESS;
	resp->eap_id = hdr->eap_id;
	resp->eap_length = htobe16(sizeof(*resp));

	ret = ikev2_send_ike_e(env, sa, e,
	    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);

 done:
	ibuf_release(e);

	return (ret);
}
예제 #5
0
파일: eap.c 프로젝트: SylvestreG/bitrig
int
eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap)
{
	struct iked_user		*usr;
	struct eap_message		*resp;
	struct eap_mschap_response	*msr;
	struct eap_mschap_peer		*msp;
	struct eap_mschap		*ms;
	struct eap_mschap_success	*mss;
	u_int8_t			*ptr, *pass;
	size_t				 len, passlen;
	char				*name, *msg;
	u_int8_t			 ntresponse[EAP_MSCHAP_NTRESPONSE_SZ];
	u_int8_t			 successmsg[EAP_MSCHAP_SUCCESS_SZ];
	struct ibuf			*eapmsg = NULL;
	int				 ret = -1;

	if (!sa_stateok(sa, IKEV2_STATE_EAP)) {
		log_debug("%s: unexpected EAP", __func__);
		return (0);	/* ignore */
	}

	if (sa->sa_hdr.sh_initiator) {
		log_debug("%s: initiator EAP not supported", __func__);
		return (-1);
	}

	/* Only MSCHAP-V2 */
	if (eap->eap_type != EAP_TYPE_MSCHAP_V2) {
		log_debug("%s: unsupported type EAP-%s", __func__,
		    print_map(eap->eap_type, eap_type_map));
		return (-1);
	}

	if (betoh16(eap->eap_length) < (sizeof(*eap) + sizeof(*ms))) {
		log_debug("%s: short message", __func__);
		return (-1);
	}

	ms = (struct eap_mschap *)(eap + 1);
	ptr = (u_int8_t *)(eap + 1);

	switch (ms->ms_opcode) {
	case EAP_MSOPCODE_RESPONSE:
		msr = (struct eap_mschap_response *)ms;
		if (betoh16(eap->eap_length) < (sizeof(*eap) + sizeof(*msr))) {
			log_debug("%s: short response", __func__);
			return (-1);
		}
		ptr += sizeof(*msr);
		len = betoh16(eap->eap_length) -
		    sizeof(*eap) - sizeof(*msr);
		if (len == 0 && sa->sa_eapid != NULL)
			name = strdup(sa->sa_eapid);
		else
			name = get_string(ptr, len);
		if (name == NULL) {
			log_debug("%s: invalid response name", __func__);
			return (-1);
		}
		if ((usr = user_lookup(env, name)) == NULL) {
			log_debug("%s: unknown user '%s'", __func__, name);
			free(name);
			return (-1);
		}
		free(name);

		if ((pass = string2unicode(usr->usr_pass, &passlen)) == NULL)
			return (-1);

		msp = &msr->msr_response.resp_peer;
		mschap_nt_response(ibuf_data(sa->sa_eap.id_buf),
		    msp->msp_challenge, usr->usr_name, strlen(usr->usr_name),
		    pass, passlen, ntresponse);

		if (memcmp(ntresponse, msp->msp_ntresponse,
		    sizeof(ntresponse)) != 0) {
			log_debug("%s: '%s' authentication failed", __func__,
			    usr->usr_name);
			free(pass);

			/* XXX should we send an EAP failure packet? */
			return (-1);
		}

		bzero(&successmsg, sizeof(successmsg));
		mschap_auth_response(pass, passlen,
		    ntresponse, ibuf_data(sa->sa_eap.id_buf),
		    msp->msp_challenge, usr->usr_name, strlen(usr->usr_name),
		    successmsg);
		if ((sa->sa_eapmsk = ibuf_new(NULL, MSCHAP_MSK_SZ)) == NULL) {
			log_debug("%s: failed to get MSK", __func__);
			free(pass);
			return (-1);
		}
		mschap_msk(pass, passlen, ntresponse,
		    ibuf_data(sa->sa_eapmsk));
		free(pass);

		log_info("%s: '%s' authenticated", __func__, usr->usr_name);


		if ((eapmsg = ibuf_static()) == NULL)
			return (-1);

		msg = " M=Welcome";

		if ((resp = ibuf_advance(eapmsg, sizeof(*resp))) == NULL)
			goto done;
		resp->eap_code = EAP_CODE_REQUEST;
		resp->eap_id = eap->eap_id + 1;
		resp->eap_length = htobe16(sizeof(*resp) + sizeof(*mss) +
		    sizeof(successmsg) + strlen(msg));
		resp->eap_type = EAP_TYPE_MSCHAP_V2;

		if ((mss = ibuf_advance(eapmsg, sizeof(*mss))) == NULL)
			goto done;
		mss->mss_opcode = EAP_MSOPCODE_SUCCESS;
		mss->mss_id = msr->msr_id;
		mss->mss_length = htobe16(sizeof(*mss) +
		    sizeof(successmsg) + strlen(msg));
		if (ibuf_add(eapmsg, successmsg, sizeof(successmsg)) != 0)
			goto done;
		if (ibuf_add(eapmsg, msg, strlen(msg)) != 0)
			goto done;
		break;
	case EAP_MSOPCODE_SUCCESS:
		if ((eapmsg = ibuf_static()) == NULL)
			return (-1);
		if ((resp = ibuf_advance(eapmsg, sizeof(*resp))) == NULL)
			goto done;
		resp->eap_code = EAP_CODE_RESPONSE;
		resp->eap_id = eap->eap_id;
		resp->eap_length = htobe16(sizeof(*resp) + sizeof(*ms));
		resp->eap_type = EAP_TYPE_MSCHAP_V2;
		if ((ms = ibuf_advance(eapmsg, sizeof(*ms))) == NULL)
			goto done;
		ms->ms_opcode = EAP_MSOPCODE_SUCCESS;
		break;
	case EAP_MSOPCODE_FAILURE:
	case EAP_MSOPCODE_CHANGE_PASSWORD:
	case EAP_MSOPCODE_CHALLENGE:
	default:
		log_debug("%s: EAP-%s unsupported "
		    "responder operation %s", __func__,
		    print_map(eap->eap_type, eap_type_map),
		    print_map(ms->ms_opcode, eap_msopcode_map));
		return (-1);
	}

	if (eapmsg != NULL)
		ret = ikev2_send_ike_e(env, sa, eapmsg,
		    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);

	if (ret == 0)
		sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS);

 done:
	ibuf_release(eapmsg);
	return (ret);
}
예제 #6
0
int
ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld,
    struct iked_message *msg, off_t offset)
{
	struct iked_childsa	**peersas = NULL;
	struct iked_sa		*sa = msg->msg_sa;
	struct ikev2_delete	*del, *localdel;
	struct ibuf		*resp = NULL;
	u_int64_t		*localspi = NULL;
	u_int64_t		 spi64, spi = 0;
	u_int32_t		 spi32;
	u_int8_t		*buf, *msgbuf = ibuf_data(msg->msg_data);
	size_t			 found = 0, failed = 0;
	int			 cnt, i, len, sz, ret = -1;

	/* Skip if it's a reply and we don't have to deal with it */
	if (ikev2_msg_frompeer(msg) && sa &&
	    (sa->sa_stateflags & IKED_REQ_INF)) {
		sa->sa_stateflags &= ~IKED_REQ_INF;
		if ((sa->sa_stateflags & IKED_REQ_DELETE) == 0)
			return (0);
	}

	if ((del = ibuf_seek(msg->msg_data, offset, sizeof(*del))) == NULL)
		return (-1);
	cnt = betoh16(del->del_nspi);
	sz = del->del_spisize;

	log_debug("%s: proto %s spisize %d nspi %d",
	    __func__, print_map(del->del_protoid, ikev2_saproto_map),
	    sz, cnt);

	buf = msgbuf + offset + sizeof(*del);
	len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(*del);

	print_hex(buf, 0, len);

	switch (sz) {
	case 4:
	case 8:
		break;
	default:
		if (ikev2_msg_frompeer(msg) &&
		    del->del_protoid == IKEV2_SAPROTO_IKE) {
			/* Send an empty informational response */
			if ((resp = ibuf_static()) == NULL)
				goto done;
			ret = ikev2_send_ike_e(env, sa, resp,
			    IKEV2_PAYLOAD_NONE,
			    IKEV2_EXCHANGE_INFORMATIONAL, 1);
			ibuf_release(resp);
			sa_state(env, sa, IKEV2_STATE_CLOSED);
			return (ret);
		}
		log_debug("%s: invalid SPI size", __func__);
		return (-1);
	}

	if ((len / sz) != cnt) {
		log_debug("%s: invalid payload length %d/%d != %d",
		    __func__, len, sz, cnt);
		return (-1);
	}

	if (ikev2_msg_frompeer(msg) &&
	    ((peersas = calloc(cnt, sizeof(struct iked_childsa *))) == NULL ||
	     (localspi = calloc(cnt, sizeof(u_int64_t))) == NULL)) {
		log_warn("%s", __func__);
		goto done;
	}

	for (i = 0; i < cnt; i++) {
		switch (sz) {
		case 4:
			memcpy(&spi32, buf + (i * sz), sizeof(spi32));
			spi = betoh32(spi32);
			break;
		case 8:
			memcpy(&spi64, buf + (i * sz), sizeof(spi64));
			spi = betoh64(spi64);
			break;
		}

		log_debug("%s: spi %s", __func__, print_spi(spi, sz));

		if (peersas == NULL || sa == NULL)
			continue;

		if ((peersas[i] = childsa_lookup(sa, spi,
		    del->del_protoid)) == NULL) {
			log_warnx("%s: CHILD SA doesn't exist for spi %s",
			    __func__, print_spi(spi, del->del_spisize));
			goto done;
		}

		if (ikev2_childsa_delete(env, sa, del->del_protoid, spi,
		    &localspi[i], 0) == -1)
			failed++;
		else
			found++;

		/*
		 * Flows are left in the require mode so that it would be
		 * possible to quickly negotiate a new Child SA
		 */
	}

	/* Parsed outgoing message? */
	if (!ikev2_msg_frompeer(msg))
		goto done;

	if (sa && (sa->sa_stateflags & IKED_REQ_DELETE)) {
		/* Finish rekeying */
		sa->sa_stateflags &= ~IKED_REQ_DELETE;
		ret = 0;
		goto done;
	}

	/* Response to the INFORMATIONAL with Delete payload */

	if ((resp = ibuf_static()) == NULL)
		goto done;

	if (found) {
		if ((localdel = ibuf_advance(resp, sizeof(*localdel))) == NULL)
			goto done;

		localdel->del_protoid = del->del_protoid;
		localdel->del_spisize = del->del_spisize;
		localdel->del_nspi = htobe16(found);

		for (i = 0; i < cnt; i++) {
			switch (sz) {
			case 4:
				spi32 = htobe32(localspi[i]);
				if (ibuf_add(resp, &spi32, sizeof(spi32)) != 0)
					goto done;
				break;
			case 8:
				spi64 = htobe64(localspi[i]);
				if (ibuf_add(resp, &spi64, sizeof(spi64)) != 0)
					goto done;
				break;
			}
		}

		log_warnx("%s: deleted %d spis", __func__, found);
	}

	if (found) {
		ret = ikev2_send_ike_e(env, sa, resp, IKEV2_PAYLOAD_DELETE,
		    IKEV2_EXCHANGE_INFORMATIONAL, 1);
	} else {
		/* XXX should we send an INVALID_SPI notification? */
		ret = 0;
	}

 done:
	if (localspi)
		free(localspi);
	if (peersas)
		free(peersas);
	ibuf_release(resp);
	return (ret);
}
예제 #7
0
파일: ikev2_msg.c 프로젝트: xcllnt/openiked
struct ibuf *
ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src)
{
	size_t			 len, encrlen, integrlen, blocklen, outlen;
	uint8_t			*buf, pad = 0, *ptr;
	struct ibuf		*encr, *dst = NULL, *out = NULL;

	buf = ibuf_data(src);
	len = ibuf_size(src);

	log_debug("%s: decrypted length %zu", __func__, len);
	print_hex(buf, 0, len);

	if (sa == NULL ||
	    sa->sa_encr == NULL ||
	    sa->sa_integr == NULL) {
		log_debug("%s: invalid SA", __func__);
		goto done;
	}

	if (sa->sa_hdr.sh_initiator)
		encr = sa->sa_key_iencr;
	else
		encr = sa->sa_key_rencr;

	blocklen = cipher_length(sa->sa_encr);
	integrlen = hash_length(sa->sa_integr);
	encrlen = roundup(len + sizeof(pad), blocklen);
	pad = encrlen - (len + sizeof(pad));

	/*
	 * Pad the payload and encrypt it
	 */
	if (pad) {
		if ((ptr = ibuf_advance(src, pad)) == NULL)
			goto done;
		arc4random_buf(ptr, pad);
	}
	if (ibuf_add(src, &pad, sizeof(pad)) != 0)
		goto done;

	log_debug("%s: padded length %zu", __func__, ibuf_size(src));
	print_hex(ibuf_data(src), 0, ibuf_size(src));

	cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr));
	cipher_setiv(sa->sa_encr, NULL, 0);
	cipher_init_encrypt(sa->sa_encr);

	if ((dst = ibuf_dup(sa->sa_encr->encr_iv)) == NULL)
		goto done;

	if ((out = ibuf_new(NULL,
	    cipher_outlength(sa->sa_encr, encrlen))) == NULL)
		goto done;

	outlen = ibuf_size(out);
	cipher_update(sa->sa_encr,
	    ibuf_data(src), encrlen, ibuf_data(out), &outlen);

	if (outlen && ibuf_add(dst, ibuf_data(out), outlen) != 0)
		goto done;

	if ((ptr = ibuf_advance(dst, integrlen)) == NULL)
		goto done;
	explicit_bzero(ptr, integrlen);

	log_debug("%s: length %zu, padding %d, output length %zu",
	    __func__, len + sizeof(pad), pad, ibuf_size(dst));
	print_hex(ibuf_data(dst), 0, ibuf_size(dst));

	ibuf_release(src);
	ibuf_release(out);
	return (dst);
 done:
	ibuf_release(src);
	ibuf_release(out);
	ibuf_release(dst);
	return (NULL);
}
예제 #8
0
파일: ikev2_msg.c 프로젝트: xcllnt/openiked
int
ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr,
    struct iked_message *msg)
{
#if 0
	/* XXX Disabled, see comment below */
	struct iked_message		 resp;
	struct ike_header		*hdr;
	struct ikev2_payload		*pld;
	struct ikev2_notify		*n;
	struct ibuf			*buf;
	struct iked_sa			 sa;
#endif

	if (msg->msg_sa != NULL && msg->msg_policy != NULL) {
		/*
		 * Only permit informational requests from initiator
		 * on closing SAs (for DELETE).
		 */
		if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSING) {
			if (((oldhdr->ike_flags &
			    (IKEV2_FLAG_INITIATOR|IKEV2_FLAG_RESPONSE)) ==
			    IKEV2_FLAG_INITIATOR) &&
			    (oldhdr->ike_exchange ==
			    IKEV2_EXCHANGE_INFORMATIONAL))
				return (0);
			return (-1);
		}
		return (0);
	}

#if 0
	/*
	 * XXX Sending INVALID_IKE_SPIs notifications is disabled
	 * XXX because it is not mandatory and ignored by most
	 * XXX implementations.  We might want to enable it in
	 * XXX combination with a rate-limitation to avoid DoS situations.
	 */

	/* Fail without error message */
	if (msg->msg_response || msg->msg_policy == NULL)
		return (-1);

	/* Invalid IKE SA, return notification */
	if ((buf = ikev2_msg_init(env, &resp,
	    &msg->msg_peer, msg->msg_peerlen,
	    &msg->msg_local, msg->msg_locallen, 1)) == NULL)
		goto done;

	resp.msg_fd = msg->msg_fd;

	bzero(&sa, sizeof(sa));
	if ((oldhdr->ike_flags & IKEV2_FLAG_INITIATOR) == 0)
		sa.sa_hdr.sh_initiator = 1;
	sa.sa_hdr.sh_ispi = betoh64(oldhdr->ike_ispi);
	sa.sa_hdr.sh_rspi = betoh64(oldhdr->ike_rspi);

	resp.msg_msgid = betoh32(oldhdr->ike_msgid);

	/* IKE header */
	if ((hdr = ikev2_add_header(buf, &sa, resp.msg_msgid,
	    IKEV2_PAYLOAD_NOTIFY, IKEV2_EXCHANGE_INFORMATIONAL,
	    IKEV2_FLAG_RESPONSE)) == NULL)
		goto done;

	/* SA payload */
	if ((pld = ikev2_add_payload(buf)) == NULL)
		goto done;
	if ((n = ibuf_advance(buf, sizeof(*n))) == NULL)
		goto done;
	n->n_protoid = IKEV2_SAPROTO_IKE;
	n->n_spisize = 0;
	n->n_type = htobe16(IKEV2_N_INVALID_IKE_SPI);

	if (ikev2_next_payload(pld, sizeof(*n), IKEV2_PAYLOAD_NONE) == -1)
		goto done;

	if (ikev2_set_header(hdr, ibuf_size(buf) - sizeof(*hdr)) == -1)
		goto done;

	(void)ikev2_pld_parse(env, hdr, &resp, 0);
	(void)ikev2_msg_send(env, &resp);

 done:
	ikev2_msg_cleanup(env, &resp);
#endif

	/* Always fail */
	return (-1);
}