Beispiel #1
0
int
ikev2_pld_parse(struct iked *env, struct ike_header *hdr,
    struct iked_message *msg, off_t offset)
{
	log_debug("%s: header ispi %s rspi %s"
	    " nextpayload %s version 0x%02x exchange %s flags 0x%02x"
	    " msgid %d length %d response %d", __func__,
	    print_spi(betoh64(hdr->ike_ispi), 8),
	    print_spi(betoh64(hdr->ike_rspi), 8),
	    print_map(hdr->ike_nextpayload, ikev2_payload_map),
	    hdr->ike_version,
	    print_map(hdr->ike_exchange, ikev2_exchange_map),
	    hdr->ike_flags,
	    betoh32(hdr->ike_msgid),
	    betoh32(hdr->ike_length),
	    msg->msg_response);

	if (ibuf_size(msg->msg_data) < betoh32(hdr->ike_length)) {
		log_debug("%s: short message", __func__);
		return (-1);
	}

	offset += sizeof(*hdr);

	return (ikev2_pld_payloads(env, msg, offset,
	    betoh32(hdr->ike_length), hdr->ike_nextpayload, 0));
}
Beispiel #2
0
void
ikev1_recv(struct iked *env, struct iked_message *msg)
{
	struct ike_header	*hdr;

	if (ibuf_size(msg->msg_data) <= sizeof(*hdr)) {
		log_debug("%s: short message", __func__);
		return;
	}

	hdr = (struct ike_header *)ibuf_data(msg->msg_data);

	log_debug("%s: header ispi %s rspi %s"
	    " nextpayload %u version 0x%02x exchange %u flags 0x%02x"
	    " msgid %u length %u", __func__,
	    print_spi(betoh64(hdr->ike_ispi), 8),
	    print_spi(betoh64(hdr->ike_rspi), 8),
	    hdr->ike_nextpayload,
	    hdr->ike_version,
	    hdr->ike_exchange,
	    hdr->ike_flags,
	    betoh32(hdr->ike_msgid),
	    betoh32(hdr->ike_length));

	log_debug("%s: IKEv1 not supported", __func__);
}
Beispiel #3
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);
}
Beispiel #4
0
int
ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld,
    struct iked_message *msg, off_t offset)
{
	struct ikev2_notify	*n;
	u_int8_t		*buf, md[SHA_DIGEST_LENGTH];
	size_t			 len;
	u_int32_t		 spi32;
	u_int64_t		 spi64;
	struct iked_spi		*rekey;
	u_int16_t		 type;
	u_int16_t		 group;

	if ((n = ibuf_seek(msg->msg_data, offset, sizeof(*n))) == NULL)
		return (-1);
	type = betoh16(n->n_type);

	log_debug("%s: protoid %s spisize %d type %s",
	    __func__,
	    print_map(n->n_protoid, ikev2_saproto_map), n->n_spisize,
	    print_map(type, ikev2_n_map));

	len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(*n);
	if ((buf = ibuf_seek(msg->msg_data, offset + sizeof(*n), len)) == NULL)
		return (-1);

	print_hex(buf, 0, len);

	if (!ikev2_msg_frompeer(msg))
		return (0);

	switch (type) {
	case IKEV2_N_NAT_DETECTION_SOURCE_IP:
	case IKEV2_N_NAT_DETECTION_DESTINATION_IP:
		if (ikev2_nat_detection(env, msg, md, sizeof(md), type) == -1)
			return (-1);
		if (len != sizeof(md) || memcmp(buf, md, len) != 0) {
			log_debug("%s: %s detected NAT, enabling "
			    "UDP encapsulation", __func__,
			    print_map(type, ikev2_n_map));

			/*
			 * Enable UDP encapsulation of ESP packages if
			 * the check detected NAT.
			 */
			if (msg->msg_sa != NULL)
				msg->msg_sa->sa_udpencap = 1;
		}
		print_hex(md, 0, sizeof(md));
		break;
	case IKEV2_N_INVALID_KE_PAYLOAD:
		if (len != sizeof(group)) {
			log_debug("%s: malformed notification", __func__);
			return (-1);
		}
		if (!msg->msg_sa->sa_hdr.sh_initiator) {
			log_debug("%s: not an initiator", __func__);
			sa_free(env, msg->msg_sa);
			msg->msg_sa = NULL;
			return (-1);
		}
		memcpy(&group, buf, len);
		group = betoh16(group);
		if ((msg->msg_policy->pol_peerdh = group_get(group))
		    == NULL) {
			log_debug("%s: unable to select DH group %d", __func__,
			    group);
			return (-1);
		}
		log_debug("%s: responder selected DH group %d", __func__,
		    group);
		sa_free(env, msg->msg_sa);
		msg->msg_sa = NULL;
		timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa,
		    NULL);
		timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL);
		break;
	case IKEV2_N_NO_ADDITIONAL_SAS:
		/* This makes sense for Child SAs only atm */
		if (msg->msg_sa->sa_stateflags & IKED_REQ_CHILDSA) {
			ikev2_disable_rekeying(env, msg->msg_sa);
			msg->msg_sa->sa_stateflags &= ~IKED_REQ_CHILDSA;
		}
		break;
	case IKEV2_N_REKEY_SA:
		if (len != n->n_spisize) {
			log_debug("%s: malformed notification", __func__);
			return (-1);
		}
		rekey = &msg->msg_parent->msg_rekey;
		if (rekey->spi != 0) {
			log_debug("%s: rekeying of multiple SAs not supported",
			    __func__);
			return (-1);
		}
		switch (n->n_spisize) {
		case 4:
			memcpy(&spi32, buf, len);
			rekey->spi = betoh32(spi32);
			break;
		case 8:
			memcpy(&spi64, buf, len);
			rekey->spi = betoh64(spi64);
			break;
		default:
			log_debug("%s: invalid spi size %d", __func__,
			    n->n_spisize);
			return (-1);
		}
		rekey->spi_size = n->n_spisize;
		rekey->spi_protoid = n->n_protoid;

		log_debug("%s: rekey %s spi %s", __func__,
		    print_map(n->n_protoid, ikev2_saproto_map),
		    print_spi(rekey->spi, n->n_spisize));
		break;
	}

	return (0);
}
Beispiel #5
0
int
ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld,
    struct iked_message *msg, off_t offset)
{
	struct ikev2_sa_proposal	 sap;
	struct iked_proposal		*prop = NULL;
	u_int32_t			 spi32;
	u_int64_t			 spi = 0, spi64;
	u_int8_t			*msgbuf = ibuf_data(msg->msg_data);
	struct iked_proposals		*props;

	props = &msg->msg_parent->msg_proposals;

	memcpy(&sap, msgbuf + offset, sizeof(sap));
	offset += sizeof(sap);

	if (sap.sap_spisize) {
		switch (sap.sap_spisize) {
		case 4:
			memcpy(&spi32, msgbuf + offset, 4);
			spi = betoh32(spi32);
			break;
		case 8:
			memcpy(&spi64, msgbuf + offset, 8);
			spi = betoh64(spi64);
			break;
		default:
			log_debug("%s: unsupported SPI size %d",
			    __func__, sap.sap_spisize);
			return (-1);
		}

		offset += sap.sap_spisize;
	}

	log_debug("%s: more %d reserved %d length %d"
	    " proposal #%d protoid %s spisize %d xforms %d spi %s",
	    __func__, sap.sap_more, sap.sap_reserved,
	    betoh16(sap.sap_length), sap.sap_proposalnr,
	    print_map(sap.sap_protoid, ikev2_saproto_map), sap.sap_spisize,
	    sap.sap_transforms, print_spi(spi, sap.sap_spisize));

	if (ikev2_msg_frompeer(msg)) {
		if ((msg->msg_parent->msg_prop = config_add_proposal(props,
		    sap.sap_proposalnr, sap.sap_protoid)) == NULL) {
			log_debug("%s: invalid proposal", __func__);
			return (-1);
		}
		prop = msg->msg_parent->msg_prop;
		prop->prop_peerspi.spi = spi;
		prop->prop_peerspi.spi_protoid = sap.sap_protoid;
		prop->prop_peerspi.spi_size = sap.sap_spisize;

		prop->prop_localspi.spi_protoid = sap.sap_protoid;
		prop->prop_localspi.spi_size = sap.sap_spisize;
	}

	/*
	 * Parse the attached transforms
	 */
	if (sap.sap_transforms &&
	    ikev2_pld_xform(env, &sap, msg, offset) != 0) {
		log_debug("%s: invalid proposal transforms", __func__);
		return (-1);
	}

	return (0);
}
/*
 * NB: This function parses both the SA header and the first proposal.
 * Additional proposals are ignored.
 */
int
ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld,
    struct iked_message *msg, size_t offset, size_t left)
{
	struct ikev2_sa_proposal	 sap;
	struct iked_proposal		*prop = NULL;
	u_int32_t			 spi32;
	u_int64_t			 spi = 0, spi64;
	u_int8_t			*msgbuf = ibuf_data(msg->msg_data);
	struct iked_proposals		*props;
	size_t				 total;

	if (ikev2_validate_sa(msg, offset, left, pld, &sap))
		return (-1);

	if (sap.sap_more)
		log_debug("%s: more than one proposal specified", __func__);

	/* Assumed size of the first proposals, including SPI if present. */
	total = (betoh16(sap.sap_length) - sizeof(sap));

	props = &msg->msg_parent->msg_proposals;

	offset += sizeof(sap);
	left -= sizeof(sap);

	if (sap.sap_spisize) {
		if (left < sap.sap_spisize) {
			log_debug("%s: malformed payload: SPI larger than "
			    "actual payload (%zu < %d)", __func__, left,
			    sap.sap_spisize);
			return (-1);
		}
		if (total < sap.sap_spisize) {
			log_debug("%s: malformed payload: SPI larger than "
			    "proposal (%zu < %d)", __func__, total,
			    sap.sap_spisize);
			return (-1);
		}
		if (total < sap.sap_spisize) {
			log_debug("%s: malformed payload: SPI too large "
			    "(%zu < %d)", __func__, total, sap.sap_spisize);
			return (-1);
		}
		switch (sap.sap_spisize) {
		case 4:
			memcpy(&spi32, msgbuf + offset, 4);
			spi = betoh32(spi32);
			break;
		case 8:
			memcpy(&spi64, msgbuf + offset, 8);
			spi = betoh64(spi64);
			break;
		default:
			log_debug("%s: unsupported SPI size %d",
			    __func__, sap.sap_spisize);
			return (-1);
		}

		offset += sap.sap_spisize;
		left -= sap.sap_spisize;

		/* Assumed size of the proposal, now without SPI. */
		total -= sap.sap_spisize;
	}

	/*
	 * As we verified sanity of packet headers, this check will
	 * be always false, but just to be sure we keep it.
	 */
	if (left < total) {
		log_debug("%s: payload malformed: too long for payload "
		    "(%zu < %zu)", __func__, left, total);
		return (-1);
	}

	log_debug("%s: more %d reserved %d length %d"
	    " proposal #%d protoid %s spisize %d xforms %d spi %s",
	    __func__, sap.sap_more, sap.sap_reserved,
	    betoh16(sap.sap_length), sap.sap_proposalnr,
	    print_map(sap.sap_protoid, ikev2_saproto_map), sap.sap_spisize,
	    sap.sap_transforms, print_spi(spi, sap.sap_spisize));

	if (ikev2_msg_frompeer(msg)) {
		if ((msg->msg_parent->msg_prop = config_add_proposal(props,
		    sap.sap_proposalnr, sap.sap_protoid)) == NULL) {
			log_debug("%s: invalid proposal", __func__);
			return (-1);
		}
		prop = msg->msg_parent->msg_prop;
		prop->prop_peerspi.spi = spi;
		prop->prop_peerspi.spi_protoid = sap.sap_protoid;
		prop->prop_peerspi.spi_size = sap.sap_spisize;

		prop->prop_localspi.spi_protoid = sap.sap_protoid;
		prop->prop_localspi.spi_size = sap.sap_spisize;
	}

	/*
	 * Parse the attached transforms
	 */
	if (sap.sap_transforms &&
	    ikev2_pld_xform(env, &sap, msg, offset, total) != 0) {
		log_debug("%s: invalid proposal transforms", __func__);
		return (-1);
	}

	return (0);
}