ah_core.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,667 行 · 第 1/3 页

C
1,667
字号
static voidah_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 voidah_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. */intah4_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. */intah6_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 + =
减小字号Ctrl + -
显示快捷键?