Exemplo n.º 1
0
/*
 * RFC 3173 p 2.2. Non-Expansion Policy:
 * If the total size of a compressed payload and the IPComp header, as
 * defined in section 3, is not smaller than the size of the original
 * payload, the IP datagram MUST be sent in the original non-compressed
 * form.
 *
 * When we use IPComp in tunnel mode, for small packets we will receive
 * encapsulated IP-IP datagrams without any compression and without IPComp
 * header.
 */
static int
ipcomp_encapcheck(union sockaddr_union *src, union sockaddr_union *dst)
{
	struct secasvar *sav;

	sav = key_allocsa_tunnel(src, dst, IPPROTO_IPCOMP);
	if (sav == NULL)
		return (0);
	key_freesav(&sav);

	if (src->sa.sa_family == AF_INET)
		return (sizeof(struct in_addr) << 4);
	else
		return (sizeof(struct in6_addr) << 4);
}
Exemplo n.º 2
0
/*
 * ESP input processing, called (eventually) through the protocol switch.
 */
static int
esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
{
	IPSEC_DEBUG_DECLARE(char buf[128]);
	const struct auth_hash *esph;
	const struct enc_xform *espx;
	struct xform_data *xd;
	struct cryptodesc *crde;
	struct cryptop *crp;
	struct newesp *esp;
	uint8_t *ivp;
	uint64_t cryptoid;
	int alen, error, hlen, plen;

	IPSEC_ASSERT(sav != NULL, ("null SA"));
	IPSEC_ASSERT(sav->tdb_encalgxform != NULL, ("null encoding xform"));

	error = EINVAL;
	/* Valid IP Packet length ? */
	if ( (skip&3) || (m->m_pkthdr.len&3) ){
		DPRINTF(("%s: misaligned packet, skip %u pkt len %u",
				__func__, skip, m->m_pkthdr.len));
		ESPSTAT_INC(esps_badilen);
		goto bad;
	}
	/* XXX don't pullup, just copy header */
	IP6_EXTHDR_GET(esp, struct newesp *, m, skip, sizeof (struct newesp));

	esph = sav->tdb_authalgxform;
	espx = sav->tdb_encalgxform;

	/* Determine the ESP header and auth length */
	if (sav->flags & SADB_X_EXT_OLD)
		hlen = sizeof (struct esp) + sav->ivlen;
	else
		hlen = sizeof (struct newesp) + sav->ivlen;

	alen = xform_ah_authsize(esph);

	/*
	 * Verify payload length is multiple of encryption algorithm
	 * block size.
	 *
	 * NB: This works for the null algorithm because the blocksize
	 *     is 4 and all packets must be 4-byte aligned regardless
	 *     of the algorithm.
	 */
	plen = m->m_pkthdr.len - (skip + hlen + alen);
	if ((plen & (espx->blocksize - 1)) || (plen <= 0)) {
		DPRINTF(("%s: payload of %d octets not a multiple of %d octets,"
		    "  SA %s/%08lx\n", __func__, plen, espx->blocksize,
		    ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
		    (u_long)ntohl(sav->spi)));
		ESPSTAT_INC(esps_badilen);
		goto bad;
	}

	/*
	 * Check sequence number.
	 */
	SECASVAR_LOCK(sav);
	if (esph != NULL && sav->replay != NULL && sav->replay->wsize != 0) {
		if (ipsec_chkreplay(ntohl(esp->esp_seq), sav) == 0) {
			SECASVAR_UNLOCK(sav);
			DPRINTF(("%s: packet replay check for %s\n", __func__,
			    ipsec_sa2str(sav, buf, sizeof(buf))));
			ESPSTAT_INC(esps_replay);
			error = EACCES;
			goto bad;
		}
	}
	cryptoid = sav->tdb_cryptoid;
	SECASVAR_UNLOCK(sav);

	/* Update the counters */
	ESPSTAT_ADD(esps_ibytes, m->m_pkthdr.len - (skip + hlen + alen));

	/* Get crypto descriptors */
	crp = crypto_getreq(esph && espx ? 2 : 1);
	if (crp == NULL) {
		DPRINTF(("%s: failed to acquire crypto descriptors\n",
			__func__));
		ESPSTAT_INC(esps_crypto);
		error = ENOBUFS;
		goto bad;
	}

	/* Get IPsec-specific opaque pointer */
	xd = malloc(sizeof(*xd) + alen, M_XDATA, M_NOWAIT | M_ZERO);
	if (xd == NULL) {
		DPRINTF(("%s: failed to allocate xform_data\n", __func__));
		ESPSTAT_INC(esps_crypto);
		crypto_freereq(crp);
		error = ENOBUFS;
		goto bad;
	}

	if (esph != NULL) {
		struct cryptodesc *crda = crp->crp_desc;

		IPSEC_ASSERT(crda != NULL, ("null ah crypto descriptor"));

		/* Authentication descriptor */
		crda->crd_skip = skip;
		if (SAV_ISGCM(sav))
			crda->crd_len = 8;	/* RFC4106 5, SPI + SN */
		else
			crda->crd_len = m->m_pkthdr.len - (skip + alen);
		crda->crd_inject = m->m_pkthdr.len - alen;

		crda->crd_alg = esph->type;

		/* Copy the authenticator */
		m_copydata(m, m->m_pkthdr.len - alen, alen,
		    (caddr_t) (xd + 1));

		/* Chain authentication request */
		crde = crda->crd_next;
	} else {
		crde = crp->crp_desc;
	}

	/* Crypto operation descriptor */
	crp->crp_ilen = m->m_pkthdr.len; /* Total input length */
	crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
	crp->crp_buf = (caddr_t) m;
	crp->crp_callback = esp_input_cb;
	crp->crp_sid = cryptoid;
	crp->crp_opaque = (caddr_t) xd;

	/* These are passed as-is to the callback */
	xd->sav = sav;
	xd->protoff = protoff;
	xd->skip = skip;
	xd->cryptoid = cryptoid;

	/* Decryption descriptor */
	IPSEC_ASSERT(crde != NULL, ("null esp crypto descriptor"));
	crde->crd_skip = skip + hlen;
	crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
	crde->crd_inject = skip + hlen - sav->ivlen;

	if (SAV_ISCTRORGCM(sav)) {
		ivp = &crde->crd_iv[0];

		/* GCM IV Format: RFC4106 4 */
		/* CTR IV Format: RFC3686 4 */
		/* Salt is last four bytes of key, RFC4106 8.1 */
		/* Nonce is last four bytes of key, RFC3686 5.1 */
		memcpy(ivp, sav->key_enc->key_data +
		    _KEYLEN(sav->key_enc) - 4, 4);

		if (SAV_ISCTR(sav)) {
			/* Initial block counter is 1, RFC3686 4 */
			be32enc(&ivp[sav->ivlen + 4], 1);
		}

		m_copydata(m, skip + hlen - sav->ivlen, sav->ivlen, &ivp[4]);
		crde->crd_flags |= CRD_F_IV_EXPLICIT;
	}

	crde->crd_alg = espx->type;

	return (crypto_dispatch(crp));
bad:
	m_freem(m);
	key_freesav(&sav);
	return (error);
}
Exemplo n.º 3
0
/*
 * Potentially decap ESP in UDP frame.  Check for an ESP header.
 * If present, strip the UDP header and push the result through IPSec.
 *
 * Returns error if mbuf consumed and/or processed, otherwise 0.
 */
int
udp_ipsec_input(struct mbuf *m, int off, int af)
{
	union sockaddr_union dst;
	struct secasvar *sav;
	struct udphdr *udp;
	struct ip *ip;
	uint32_t spi;
	int hlen;

	/*
	 * Just return if packet doesn't have enough data.
	 * We need at least [IP header + UDP header + ESP header].
	 * NAT-Keepalive packet has only one byte of payload, so it
	 * by default will not be processed.
	 */
	if (m->m_pkthdr.len < off + sizeof(struct esp))
		return (0);

	m_copydata(m, off, sizeof(uint32_t), (caddr_t)&spi);
	if (spi == 0)	/* Non-ESP marker. */
		return (0);

	/*
	 * Find SA and check that it is configured for UDP
	 * encapsulation.
	 */
	bzero(&dst, sizeof(dst));
	dst.sa.sa_family = af;
	switch (af) {
#ifdef INET
	case AF_INET:
		dst.sin.sin_len = sizeof(struct sockaddr_in);
		ip = mtod(m, struct ip *);
		ip->ip_p = IPPROTO_ESP;
		off = offsetof(struct ip, ip_p);
		hlen = ip->ip_hl << 2;
		dst.sin.sin_addr = ip->ip_dst;
		break;
#endif
#ifdef INET6
	case AF_INET6:
		/* Not yet */
		/* FALLTHROUGH */
#endif
	default:
		ESPSTAT_INC(esps_nopf);
		m_freem(m);
		return (EPFNOSUPPORT);
	}

	sav = key_allocsa(&dst, IPPROTO_ESP, spi);
	if (sav == NULL) {
		ESPSTAT_INC(esps_notdb);
		m_freem(m);
		return (ENOENT);
	}
	udp = mtodo(m, hlen);
	if (sav->natt == NULL ||
	    sav->natt->sport != udp->uh_sport ||
	    sav->natt->dport != udp->uh_dport) {
		/* XXXAE: should we check source address? */
		ESPSTAT_INC(esps_notdb);
		key_freesav(&sav);
		m_freem(m);
		return (ENOENT);
	}
	/*
	 * Remove the UDP header
	 * Before:
	 *   <--- off --->
	 *   +----+------+-----+
	 *   | IP |  UDP | ESP |
	 *   +----+------+-----+
	 *        <-skip->
	 * After:
	 *          +----+-----+
	 *          | IP | ESP |
	 *          +----+-----+
	 *   <-skip->
	 */
	m_striphdr(m, hlen, sizeof(*udp));
	/*
	 * We cannot yet update the cksums so clear any h/w cksum flags
	 * as they are no longer valid.
	 */
	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID)
		m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
	/*
	 * We can update ip_len and ip_sum here, but ipsec4_input_cb()
	 * will do this anyway, so don't touch them here.
	 */
	ESPSTAT_INC(esps_input);
	(*sav->tdb_xform->xf_input)(m, sav, hlen, off);
	return (EINPROGRESS);	/* Consumed by IPsec. */
}