⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ah_core.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
static void
ah_hmac_sha2_512_result(state, addr)
	struct ah_algorithm_state *state;
	caddr_t addr;
{
	u_char digest[SHA512_DIGEST_LENGTH];
	u_char *ipad;
	u_char *opad;
	SHA512_CTX *ctxt;

	if (!state || !state->foo)
		panic("ah_hmac_sha2_512_result: what?");

	ipad = (u_char *)state->foo;
	opad = (u_char *)(ipad + 64);
	ctxt = (SHA512_CTX *)(opad + 64);

	SHA512_Final((caddr_t)&digest[0], ctxt);

	bzero(ctxt, sizeof(*ctxt));
	SHA512_Init(ctxt);
	SHA512_Update(ctxt, opad, 64);
	SHA512_Update(ctxt, (caddr_t)&digest[0], sizeof(digest));
	SHA512_Final((caddr_t)&digest[0], ctxt);

	bcopy(&digest[0], (void *)addr, HMACSIZE);

	free(state->foo, M_TEMP);
}

/*------------------------------------------------------------*/

/*
 * go generate the checksum.
 */
static void
ah_update_mbuf(m, off, len, algo, algos)
	struct mbuf *m;
	int off;
	int len;
	const struct ah_algorithm *algo;
	struct ah_algorithm_state *algos;
{
	struct mbuf *n;
	int tlen;

	/* easy case first */
	if (off + len <= m->m_len) {
		(algo->update)(algos, mtod(m, caddr_t) + off, len);
		return;
	}

	for (n = m; n; n = n->m_next) {
		if (off < n->m_len)
			break;

		off -= n->m_len;
	}

	if (!n)
		panic("ah_update_mbuf: wrong offset specified");

	for (/* nothing */; n && len > 0; n = n->m_next) {
		if (n->m_len == 0)
			continue;
		if (n->m_len - off < len)
			tlen = n->m_len - off;
		else
			tlen = len;

		(algo->update)(algos, mtod(n, caddr_t) + off, tlen);

		len -= tlen;
		off = 0;
	}
}

#ifdef INET
/*
 * Go generate the checksum. This function won't modify the mbuf chain
 * except AH itself.
 *
 * NOTE: the function does not free mbuf on failure.
 * Don't use m_copy(), it will try to share cluster mbuf by using refcnt.
 */
int
ah4_calccksum(m, ahdat, len, algo, sav)
	struct mbuf *m;
	caddr_t ahdat;
	size_t len;
	const struct ah_algorithm *algo;
	struct secasvar *sav;
{
	int off;
	int hdrtype;
	size_t advancewidth;
	struct ah_algorithm_state algos;
	u_char sumbuf[AH_MAXSUMSIZE];
	int error = 0;
	int ahseen;
	struct mbuf *n = NULL;

	if ((m->m_flags & M_PKTHDR) == 0)
		return EINVAL;

	ahseen = 0;
	hdrtype = -1;	/* dummy, it is called IPPROTO_IP */

	off = 0;

	error = (algo->init)(&algos, sav);
	if (error)
		return error;

	advancewidth = 0;	/* safety */

again:
	/* gory. */
	switch (hdrtype) {
	case -1:	/* first one only */
	    {
		/*
		 * copy ip hdr, modify to fit the AH checksum rule,
		 * then take a checksum.
		 */
		struct ip iphdr;
		size_t hlen;

		m_copydata(m, off, sizeof(iphdr), (caddr_t)&iphdr);
#ifdef _IP_VHL
		hlen = IP_VHL_HL(iphdr.ip_vhl) << 2;
#else
		hlen = iphdr.ip_hl << 2;
#endif
		iphdr.ip_ttl = 0;
		iphdr.ip_sum = htons(0);
		if (ip4_ah_cleartos)
			iphdr.ip_tos = 0;
		iphdr.ip_off = htons(ntohs(iphdr.ip_off) & ip4_ah_offsetmask);
		(algo->update)(&algos, (caddr_t)&iphdr, sizeof(struct ip));

		if (hlen != sizeof(struct ip)) {
			u_char *p;
			int i, l, skip;

			if (hlen > MCLBYTES) {
				error = EMSGSIZE;
				goto fail;
			}
			MGET(n, M_DONTWAIT, MT_DATA);
			if (n && hlen > MLEN) {
				MCLGET(n, M_DONTWAIT);
				if ((n->m_flags & M_EXT) == 0) {
					m_free(n);
					n = NULL;
				}
			}
			if (n == NULL) {
				error = ENOBUFS;
				goto fail;
			}
			m_copydata(m, off, hlen, mtod(n, caddr_t));

			/*
			 * IP options processing.
			 * See RFC2402 appendix A.
			 */
			p = mtod(n, u_char *);
			i = sizeof(struct ip);
			while (i < hlen) {
				if (i + IPOPT_OPTVAL >= hlen) {
					ipseclog((LOG_ERR, "ah4_calccksum: "
					    "invalid IP option\n"));
					error = EINVAL;
					goto fail;
				}
				if (p[i + IPOPT_OPTVAL] == IPOPT_EOL ||
				    p[i + IPOPT_OPTVAL] == IPOPT_NOP ||
				    i + IPOPT_OLEN < hlen)
					;
				else {
					ipseclog((LOG_ERR,
					    "ah4_calccksum: invalid IP option "
					    "(type=%02x)\n",
					    p[i + IPOPT_OPTVAL]));
					error = EINVAL;
					goto fail;
				}

				skip = 1;
				switch (p[i + IPOPT_OPTVAL]) {
				case IPOPT_EOL:
				case IPOPT_NOP:
					l = 1;
					skip = 0;
					break;
				case IPOPT_SECURITY:	/* 0x82 */
				case 0x85:	/* Extended security */
				case 0x86:	/* Commercial security */
				case 0x94:	/* Router alert */
				case 0x95:	/* RFC1770 */
					l = p[i + IPOPT_OLEN];
					if (l < 2)
						goto invalopt;
					skip = 0;
					break;
				default:
					l = p[i + IPOPT_OLEN];
					if (l < 2)
						goto invalopt;
					skip = 1;
					break;
				}
				if (l < 1 || hlen - i < l) {
			invalopt:
					ipseclog((LOG_ERR,
					    "ah4_calccksum: invalid IP option "
					    "(type=%02x len=%02x)\n",
					    p[i + IPOPT_OPTVAL],
					    p[i + IPOPT_OLEN]));
					error = EINVAL;
					goto fail;
				}
				if (skip)
					bzero(p + i, l);
				if (p[i + IPOPT_OPTVAL] == IPOPT_EOL)
					break;
				i += l;
			}
			p = mtod(n, u_char *) + sizeof(struct ip);
			(algo->update)(&algos, p, hlen - sizeof(struct ip));

			m_free(n);
			n = NULL;
		}

		hdrtype = (iphdr.ip_p) & 0xff;
		advancewidth = hlen;
		break;
	    }

	case IPPROTO_AH:
	    {
		struct ah ah;
		int siz;
		int hdrsiz;
		int totlen;

		m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
		hdrsiz = (sav->flags & SADB_X_EXT_OLD)
				? sizeof(struct ah)
				: sizeof(struct newah);
		siz = (*algo->sumsiz)(sav);
		totlen = (ah.ah_len + 2) << 2;

		/*
		 * special treatment is necessary for the first one, not others
		 */
		if (!ahseen) {
			if (totlen > m->m_pkthdr.len - off ||
			    totlen > MCLBYTES) {
				error = EMSGSIZE;
				goto fail;
			}
			MGET(n, M_DONTWAIT, MT_DATA);
			if (n && totlen > MLEN) {
				MCLGET(n, M_DONTWAIT);
				if ((n->m_flags & M_EXT) == 0) {
					m_free(n);
					n = NULL;
				}
			}
			if (n == NULL) {
				error = ENOBUFS;
				goto fail;
			}
			m_copydata(m, off, totlen, mtod(n, caddr_t));
			n->m_len = totlen;
			bzero(mtod(n, caddr_t) + hdrsiz, siz);
			(algo->update)(&algos, mtod(n, caddr_t), n->m_len);
			m_free(n);
			n = NULL;
		} else
			ah_update_mbuf(m, off, totlen, algo, &algos);
		ahseen++;

		hdrtype = ah.ah_nxt;
		advancewidth = totlen;
		break;
	    }

	default:
		ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo, &algos);
		advancewidth = m->m_pkthdr.len - off;
		break;
	}

	off += advancewidth;
	if (off < m->m_pkthdr.len)
		goto again;

	if (len < (*algo->sumsiz)(sav)) {
		error = EINVAL;
		goto fail;
	}

	(algo->result)(&algos, &sumbuf[0]);
	bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav));

	if (n)
		m_free(n);
	return error;

fail:
	if (n)
		m_free(n);
	return error;
}
#endif

#ifdef INET6
/*
 * Go generate the checksum. This function won't modify the mbuf chain
 * except AH itself.
 *
 * NOTE: the function does not free mbuf on failure.
 * Don't use m_copy(), it will try to share cluster mbuf by using refcnt.
 */
int
ah6_calccksum(m, ahdat, len, algo, sav)
	struct mbuf *m;
	caddr_t ahdat;
	size_t len;
	const struct ah_algorithm *algo;
	struct secasvar *sav;
{
	int newoff, off;
	int proto, nxt;
	struct mbuf *n = NULL;
	int error;
	int ahseen;
	struct ah_algorithm_state algos;
	u_char sumbuf[AH_MAXSUMSIZE];

	if ((m->m_flags & M_PKTHDR) == 0)
		return EINVAL;

	error = (algo->init)(&algos, sav);
	if (error)
		return error;

	off = 0;
	proto = IPPROTO_IPV6;
	nxt = -1;
	ahseen = 0;

 again:
	newoff = ip6_nexthdr(m, off, proto, &nxt);
	if (newoff < 0)
		newoff = m->m_pkthdr.len;
	else if (newoff <= off) {
		error = EINVAL;
		goto fail;
	}

	switch (proto) {
	case IPPROTO_IPV6:
		/*
		 * special treatment is necessary for the first one, not others
		 */
		if (off == 0) {
			struct ip6_hdr ip6copy;

			if (newoff - off != sizeof(struct ip6_hdr)) {
				error = EINVAL;
				goto fail;
			}

			m_copydata(m, off, newoff - off, (caddr_t)&ip6copy);
			/* RFC2402 */
			ip6copy.ip6_flow = 0;
			ip6copy.ip6_vfc &= ~IPV6_VERSION_MASK;
			ip6copy.ip6_vfc |= IPV6_VERSION;
			ip6copy.ip6_hlim = 0;
			if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_src))
				ip6copy.ip6_src.s6_addr16[1] = 0x0000;
			if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_dst))
				ip6copy.ip6_dst.s6_addr16[1] = 0x0000;
			(algo->update)(&algos, (caddr_t)&ip6copy,
				       sizeof(struct ip6_hdr));
		} else {
			newoff = m->m_pkthdr.len;
			ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo,
			    &algos);
		}
		break;

	case IPPROTO_AH:
	    {
		int siz;
		int hdrsiz;

		hdrsiz = (sav->flags & SADB_X_EXT_OLD)
				? sizeof(struct ah)
				: sizeof(struct newah);
		siz = (*algo->sumsiz)(sav);

		/*
		 * special treatment is necessary for the first one, not others
		 */
		if (!ahseen) {
			if (newoff - off > MCLBYTES) {
				error = EMSGSIZE;
				goto fail;
			}
			MGET(n, M_DONTWAIT, MT_DATA);
			if (n && newoff - off > MLEN) {
				MCLGET(n, M_DONTWAIT);
				if ((n->m_flags & M_EXT) == 0) {
					m_free(n);
					n = NULL;
				}
			}
			if (n == NULL) {
				error = ENOBUFS;
				goto fail;
			}
			m_copydata(m, off, newoff - off, mtod(n, caddr_t));
			n->m_len = newoff - off;
			bzero(mtod(n, caddr_t) + hdrsiz, siz);
			(algo->update)(&algos, mtod(n, caddr_t), n->m_len);
			m_free(n);
			n = NULL;
		} else
			ah_update_mbuf(m, off, newoff - off, algo, &algos);
		ahseen++;
		break;
	    }

	 case IPPROTO_HOPOPTS:
	 case IPPROTO_DSTOPTS:
	 {
		struct ip6_ext *ip6e;
		int hdrlen, optlen;
		u_int8_t *p, *optend, *optp;

		if (newoff - off > MCLBYTES) {
			error = EMSGSIZE;
			goto fail;
		}
		MGET(n, M_DONTWAIT, MT_DATA);
		if (n && newoff - off > MLEN) {
			MCLGET(n, M_DONTWAIT);
			if ((n->m_flags & M_EXT) == 0) {
				m_free(n);
				n = NULL;
			}
		}
		if (n == NULL) {
			error = ENOBUFS;
			goto fail;
		}
		m_copydata(m, off, newoff - off, mtod(n, caddr_t));
		n->m_len = newoff - off;

		ip6e = mtod(n, struct ip6_ext *);
		hdrlen = (ip6e->ip6e_len + 1) << 3;
		if (newoff - off < hdrlen) {
			 error = EINVAL;
			 m_free(n);
			 n = NULL;
			 goto fail;
		}
		p = mtod(n, u_int8_t *);
		optend = p + hdrlen;

		/*
		 * ICV calculation for the options header including all
		 * options.  This part is a little tricky since there are
		 * two type of options; mutable and immutable.  We try to
		 * null-out mutable ones here.
		 */
		optp = p + 2;
		while (optp < optend) {
			if (optp[0] == IP6OPT_PAD1)
				optlen = 1;
			else {
				if (optp + 2 > optend) {
					error = EINVAL;
					m_free(n);
					n = NULL;
					goto fail;
				}
				optlen = optp[1] + 2;
			}

			if (optp + optlen > optend) {
				error = EINVAL;
				m_free(n);
				n = NULL;
				goto fail;
			}

			if (optp[0] & IP6OPT_MUTABLE)
				bzero(optp + 2, optlen - 2);

			optp += optlen;
		}

		(algo->update)(&algos, mtod(n, caddr_t), n->m_len);
		m_free(n);
		n = NULL;
		break;
	 }

	 case IPPROTO_ROUTING:
		/*
		 * For an input packet, we can just calculate `as is'.
		 * For an output packet, we assume ip6_output have already
		 * made packet how it will be received at the final
		 * destination.
		 */
		/* FALLTHROUGH */

	default:
		ah_update_mbuf(m, off, newoff - off, algo, &algos);
		break;
	}

	if (newoff < m->m_pkthdr.len) {
		proto = nxt;
		off = newoff;
		goto again;
	}

	if (len < (*algo->sumsiz)(sav)) {
		error = EINVAL;
		goto fail;
	}

	(algo->result)(&algos, &sumbuf[0]);
	bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav));

	/* just in case */
	if (n)
		m_free(n);
	return 0;
fail:
	/* just in case */
	if (n)
		m_free(n);
	return error;
}
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -