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 + -
显示快捷键?