diff options
author | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 2001-06-26 06:19:00 +0000 |
---|---|---|
committer | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 2001-06-26 06:19:00 +0000 |
commit | 97dcba5b2f6f34385ffbae1a6c2d741e3f9589a3 (patch) | |
tree | 4a7f2fac474f6d614c2d280c2cd29b53ccc93ea0 /sys | |
parent | 523e298b4ae65ffcfc379531551a4f2d32ce0fd8 (diff) |
KNF
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/ip_ah.c | 1997 | ||||
-rw-r--r-- | sys/netinet/ip_esp.c | 1879 |
2 files changed, 1933 insertions, 1943 deletions
diff --git a/sys/netinet/ip_ah.c b/sys/netinet/ip_ah.c index 7b7ae76c3d8..9dccd3e0373 100644 --- a/sys/netinet/ip_ah.c +++ b/sys/netinet/ip_ah.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ah.c,v 1.62 2001/06/25 05:11:58 angelos Exp $ */ +/* $OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -74,12 +74,12 @@ #endif /* - * ah_attach() is called from the transformation initialization code + * ah_attach() is called from the transformation initialization code. */ int ah_attach() { - return 0; + return 0; } /* @@ -88,64 +88,64 @@ ah_attach() int ah_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii) { - struct auth_hash *thash = NULL; - struct cryptoini cria; + struct auth_hash *thash = NULL; + struct cryptoini cria; - /* Authentication operation */ - switch (ii->ii_authalg) - { + /* Authentication operation. */ + switch (ii->ii_authalg) { case SADB_AALG_MD5HMAC: - thash = &auth_hash_hmac_md5_96; - break; + thash = &auth_hash_hmac_md5_96; + break; case SADB_AALG_SHA1HMAC: - thash = &auth_hash_hmac_sha1_96; - break; + thash = &auth_hash_hmac_sha1_96; + break; case SADB_AALG_RIPEMD160HMAC: - thash = &auth_hash_hmac_ripemd_160_96; - break; + thash = &auth_hash_hmac_ripemd_160_96; + break; case SADB_X_AALG_MD5: - thash = &auth_hash_key_md5; - break; + thash = &auth_hash_key_md5; + break; case SADB_X_AALG_SHA1: - thash = &auth_hash_key_sha1; - break; + thash = &auth_hash_key_sha1; + break; default: - DPRINTF(("ah_init(): unsupported authentication algorithm %d specified\n", ii->ii_authalg)); - return EINVAL; - } + DPRINTF(("ah_init(): unsupported authentication algorithm %d specified\n", ii->ii_authalg)); + return EINVAL; + } - if ((ii->ii_authkeylen != thash->keysize) && (thash->keysize != 0)) - { - DPRINTF(("ah_init(): keylength %d doesn't match algorithm %s keysize (%d)\n", ii->ii_authkeylen, thash->name, thash->keysize)); - return EINVAL; - } + if (ii->ii_authkeylen != thash->keysize && thash->keysize != 0) { + DPRINTF(("ah_init(): keylength %d doesn't match algorithm " + "%s keysize (%d)\n", ii->ii_authkeylen, thash->name, + thash->keysize)); + return EINVAL; + } - tdbp->tdb_xform = xsp; - tdbp->tdb_authalgxform = thash; - tdbp->tdb_bitmap = 0; - tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL; + tdbp->tdb_xform = xsp; + tdbp->tdb_authalgxform = thash; + tdbp->tdb_bitmap = 0; + tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL; - DPRINTF(("ah_init(): initialized TDB with hash algorithm %s\n", - thash->name)); + DPRINTF(("ah_init(): initialized TDB with hash algorithm %s\n", + thash->name)); - tdbp->tdb_amxkeylen = ii->ii_authkeylen; - MALLOC(tdbp->tdb_amxkey, u_int8_t *, tdbp->tdb_amxkeylen, M_XDATA, - M_WAITOK); + tdbp->tdb_amxkeylen = ii->ii_authkeylen; + MALLOC(tdbp->tdb_amxkey, u_int8_t *, tdbp->tdb_amxkeylen, M_XDATA, + M_WAITOK); - bcopy(ii->ii_authkey, tdbp->tdb_amxkey, tdbp->tdb_amxkeylen); + bcopy(ii->ii_authkey, tdbp->tdb_amxkey, tdbp->tdb_amxkeylen); - /* Initialize crypto session */ - bzero(&cria, sizeof(cria)); - cria.cri_alg = tdbp->tdb_authalgxform->type; - cria.cri_klen = ii->ii_authkeylen * 8; - cria.cri_key = ii->ii_authkey; + /* Initialize crypto session. */ + bzero(&cria, sizeof(cria)); + cria.cri_alg = tdbp->tdb_authalgxform->type; + cria.cri_klen = ii->ii_authkeylen * 8; + cria.cri_key = ii->ii_authkey; - return crypto_newsession(&tdbp->tdb_cryptoid, &cria, 0); + return crypto_newsession(&tdbp->tdb_cryptoid, &cria, 0); } /* @@ -154,18 +154,17 @@ ah_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii) int ah_zeroize(struct tdb *tdbp) { - int err; - - if (tdbp->tdb_amxkey) - { - bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen); - FREE(tdbp->tdb_amxkey, M_XDATA); - tdbp->tdb_amxkey = NULL; - } - - err = crypto_freesession(tdbp->tdb_cryptoid); - tdbp->tdb_cryptoid = 0; - return err; + int err; + + if (tdbp->tdb_amxkey) { + bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen); + FREE(tdbp->tdb_amxkey, M_XDATA); + tdbp->tdb_amxkey = NULL; + } + + err = crypto_freesession(tdbp->tdb_cryptoid); + tdbp->tdb_cryptoid = 0; + return err; } /* @@ -174,312 +173,313 @@ ah_zeroize(struct tdb *tdbp) int ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out) { - struct mbuf *m = *m0; - unsigned char *ptr; - int off, count; + struct mbuf *m = *m0; + unsigned char *ptr; + int off, count; #ifdef INET - struct ip *ip; + struct ip *ip; #endif /* INET */ #ifdef INET6 - struct ip6_ext *ip6e; - struct ip6_hdr ip6; - int alloc, len, ad; + struct ip6_ext *ip6e; + struct ip6_hdr ip6; + int alloc, len, ad; #endif /* INET6 */ - switch (proto) - { + switch (proto) { #ifdef INET case AF_INET: - /* - * This is the least painful way of dealing with IPv4 header - * and option processing -- just make sure they're in - * contiguous memory. - */ - *m0 = m = m_pullup(m, skip); - if (m == NULL) - { - DPRINTF(("ah_massage_headers(): m_pullup() failed\n")); - ahstat.ahs_hdrops++; - return ENOBUFS; - } - - /* Fix the IP header */ - ip = mtod(m, struct ip *); - ip->ip_tos = 0; - ip->ip_ttl = 0; - ip->ip_sum = 0; - - /* - * On input, fix ip_len which has been byte-swapped - * at ip_input() - */ - if (!out) - { - ip->ip_len += skip; - HTONS(ip->ip_len); - - if ((alg == CRYPTO_MD5_KPDK) || (alg == CRYPTO_SHA1_KPDK)) - ip->ip_off = htons(ip->ip_off & IP_DF); - else - ip->ip_off = 0; - } - else - { - if ((alg == CRYPTO_MD5_KPDK) || (alg == CRYPTO_SHA1_KPDK)) - ip->ip_off = htons(ntohs(ip->ip_off) & IP_DF); - else - ip->ip_off = 0; - } - - ptr = mtod(m, unsigned char *) + sizeof(struct ip); - - /* IPv4 option processing */ - for (off = sizeof(struct ip); off < skip;) - { - if (ptr[off] == IPOPT_EOL || ptr[off] == IPOPT_NOP || - off + 1 < skip) - ; - else - { - DPRINTF(("ah_massage_headers(): illegal IPv4 option length for option %d\n", ptr[off])); - ahstat.ahs_hdrops++; - m_freem(m); - return EINVAL; + /* + * This is the least painful way of dealing with IPv4 header + * and option processing -- just make sure they're in + * contiguous memory. + */ + *m0 = m = m_pullup(m, skip); + if (m == NULL) { + DPRINTF(("ah_massage_headers(): m_pullup() failed\n")); + ahstat.ahs_hdrops++; + return ENOBUFS; } - switch (ptr[off]) - { - case IPOPT_EOL: - off = skip; /* End the loop */ - break; - - case IPOPT_NOP: - off++; - break; - - case IPOPT_SECURITY: /* 0x82 */ - case 0x85: /* Extended security */ - case 0x86: /* Commercial security */ - case 0x94: /* Router alert */ - case 0x95: /* RFC1770 */ - /* Sanity check for option length */ - if (ptr[off + 1] < 2) - { - DPRINTF(("ah_massage_headers(): illegal IPv4 option length for option %d\n", ptr[off])); - ahstat.ahs_hdrops++; - m_freem(m); - return EINVAL; - } - - off += ptr[off + 1]; - break; + /* Fix the IP header */ + ip = mtod(m, struct ip *); + ip->ip_tos = 0; + ip->ip_ttl = 0; + ip->ip_sum = 0; + + /* + * On input, fix ip_len which has been byte-swapped + * at ip_input(). + */ + if (!out) { + ip->ip_len += skip; + HTONS(ip->ip_len); + + if (alg == CRYPTO_MD5_KPDK || alg == CRYPTO_SHA1_KPDK) + ip->ip_off = htons(ip->ip_off & IP_DF); + else + ip->ip_off = 0; + } else { + if (alg == CRYPTO_MD5_KPDK || alg == CRYPTO_SHA1_KPDK) + ip->ip_off = htons(ntohs(ip->ip_off) & IP_DF); + else + ip->ip_off = 0; + } - case IPOPT_LSRR: - case IPOPT_SSRR: - /* Sanity check for option length */ - if (ptr[off + 1] < 2) - { - DPRINTF(("ah_massage_headers(): illegal IPv4 option length for option %d\n", ptr[off])); - ahstat.ahs_hdrops++; - m_freem(m); - return EINVAL; + ptr = mtod(m, unsigned char *) + sizeof(struct ip); + + /* IPv4 option processing */ + for (off = sizeof(struct ip); off < skip;) { + if (ptr[off] == IPOPT_EOL || ptr[off] == IPOPT_NOP || + off + 1 < skip) + ; + else { + DPRINTF(("ah_massage_headers(): illegal IPv4 " + "option length for option %d\n", + ptr[off])); + + ahstat.ahs_hdrops++; + m_freem(m); + return EINVAL; } - /* - * On output, if we have either of the source routing - * options, we should swap the destination address of - * the IP header with the last address specified in - * the option, as that is what the destination's - * IP header will look like. - */ - if (out) - bcopy(ptr + off + ptr[off + 1] - - sizeof(struct in_addr), - &(ip->ip_dst), sizeof(struct in_addr)); - - /* Fall through */ - default: - /* Sanity check for option length */ - if (ptr[off + 1] < 2) - { - DPRINTF(("ah_massage_headers(): illegal IPv4 option length for option %d\n", ptr[off])); - ahstat.ahs_hdrops++; - m_freem(m); - return EINVAL; + switch (ptr[off]) { + case IPOPT_EOL: + off = skip; /* End the loop. */ + break; + + case IPOPT_NOP: + off++; + break; + + case IPOPT_SECURITY: /* 0x82 */ + case 0x85: /* Extended security. */ + case 0x86: /* Commercial security. */ + case 0x94: /* Router alert */ + case 0x95: /* RFC1770 */ + /* Sanity check for option length. */ + if (ptr[off + 1] < 2) { + DPRINTF(("ah_massage_headers(): " + "illegal IPv4 option length for " + "option %d\n", ptr[off])); + + ahstat.ahs_hdrops++; + m_freem(m); + return EINVAL; + } + + off += ptr[off + 1]; + break; + + case IPOPT_LSRR: + case IPOPT_SSRR: + /* Sanity check for option length. */ + if (ptr[off + 1] < 2) { + DPRINTF(("ah_massage_headers(): " + "illegal IPv4 option length for " + "option %d\n", ptr[off])); + + ahstat.ahs_hdrops++; + m_freem(m); + return EINVAL; + } + + /* + * On output, if we have either of the + * source routing options, we should + * swap the destination address of the + * IP header with the last address + * specified in the option, as that is + * what the destination's IP header + * will look like. + */ + if (out) + bcopy(ptr + off + ptr[off + 1] - + sizeof(struct in_addr), + &(ip->ip_dst), sizeof(struct in_addr)); + + /* Fall through */ + default: + /* Sanity check for option length. */ + if (ptr[off + 1] < 2) { + DPRINTF(("ah_massage_headers(): " + "illegal IPv4 option length for " + "option %d\n", ptr[off])); + ahstat.ahs_hdrops++; + m_freem(m); + return EINVAL; + } + + /* Zeroize all other options. */ + count = ptr[off + 1]; + bcopy(ipseczeroes, ptr, count); + off += count; + break; } - /* Zeroize all other options */ - count = ptr[off + 1]; - bcopy(ipseczeroes, ptr, count); - off += count; - break; - } + /* Sanity check. */ + if (off > skip) { + DPRINTF(("ah_massage_headers(): malformed " + "IPv4 options header\n")); - /* Sanity check */ - if (off > skip) - { - DPRINTF(("ah_massage_headers(): malformed IPv4 options header\n")); - ahstat.ahs_hdrops++; - m_freem(m); - return EINVAL; + ahstat.ahs_hdrops++; + m_freem(m); + return EINVAL; + } } - } - break; + break; #endif /* INET */ #ifdef INET6 case AF_INET6: /* Ugly... */ - /* Copy and "cook" the IPv6 header */ - m_copydata(m, 0, sizeof(ip6), (caddr_t) &ip6); + /* Copy and "cook" the IPv6 header. */ + m_copydata(m, 0, sizeof(ip6), (caddr_t) &ip6); - /* We don't do IPv6 Jumbograms */ - if (ip6.ip6_plen == 0) - { - DPRINTF(("ah_massage_headers(): unsupported IPv6 jumbogram")); - ahstat.ahs_hdrops++; - m_freem(m); - return EMSGSIZE; - } - - ip6.ip6_flow = 0; - ip6.ip6_hlim = 0; - ip6.ip6_vfc &= ~IPV6_VERSION_MASK; - ip6.ip6_vfc |= IPV6_VERSION; - - /* scoped address handling */ - if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_src)) - ip6.ip6_src.s6_addr16[1] = 0; - if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_dst)) - ip6.ip6_dst.s6_addr16[1] = 0; - - /* Done with IPv6 header */ - m_copyback(m, 0, sizeof(struct ip6_hdr), (caddr_t) &ip6); - - /* Let's deal with the remaining headers (if any) */ - if (skip - sizeof(struct ip6_hdr) > 0) - { - if (m->m_len <= skip) - { - MALLOC(ptr, unsigned char *, skip - sizeof(struct ip6_hdr), - M_XDATA, M_NOWAIT); - if (ptr == NULL) - { - DPRINTF(("ah_massage_headers(): failed to allocate memory for IPv6 headers\n")); + /* We don't do IPv6 Jumbograms. */ + if (ip6.ip6_plen == 0) { + DPRINTF(("ah_massage_headers(): unsupported IPv6 " + "jumbogram")); ahstat.ahs_hdrops++; m_freem(m); - return ENOBUFS; - } - - /* Copy all the protocol headers after the IPv6 header */ - m_copydata(m, sizeof(struct ip6_hdr), - skip - sizeof(struct ip6_hdr), ptr); - alloc = 1; + return EMSGSIZE; } - else - { - /* No need to allocate memory */ - ptr = mtod(m, unsigned char *) + sizeof(struct ip6_hdr); - alloc = 0; - } - } - else - break; - - off = ip6.ip6_nxt & 0xff; /* Next header type */ - - for (len = 0; len < skip - sizeof(struct ip6_hdr);) - switch (off) - { - case IPPROTO_HOPOPTS: - case IPPROTO_DSTOPTS: - ip6e = (struct ip6_ext *) (ptr + len); - - /* - * Process the mutable/immutable options -- borrows - * heavily from the KAME code. - */ - for (count = len + sizeof(struct ip6_ext); - count < len + ((ip6e->ip6e_len + 1) << 3);) - { - if (ptr[count] == IP6OPT_PAD1) - { - count++; - continue; /* Skip padding */ - } - - /* Sanity check */ - if (count > len + ((ip6e->ip6e_len + 1) << 3)) - { - DPRINTF(("ah_massage_headers(): malformed IPv6 options header\n")); - ahstat.ahs_hdrops++; - m_freem(m); - - /* Free, if we allocated */ - if (alloc) - FREE(ptr, M_XDATA); - - return EINVAL; - } - - ad = ptr[count + 1]; - - /* If mutable option, zeroize */ - if (ptr[count] & IP6OPT_MUTABLE) - bcopy(ipseczeroes, ptr + count, ptr[count + 1]); - - count += ad; - - /* Sanity check */ - if (count > skip - sizeof(struct ip6_hdr)) - { - DPRINTF(("ah_massage_headers(): malformed IPv6 options header\n")); - ahstat.ahs_hdrops++; - m_freem(m); - - /* Free, if we allocated */ - if (alloc) - FREE(ptr, M_XDATA); - - return EINVAL; - } - } - - len += ((ip6e->ip6e_len + 1) << 3); /* Advance */ - off = ip6e->ip6e_nxt; - break; - - case IPPROTO_ROUTING: - /* Always include routing headers in computation */ - ip6e = (struct ip6_ext *) (ptr + len); - len += ((ip6e->ip6e_len + 1) << 3); /* Advance */ - off = ip6e->ip6e_nxt; - break; - - default: - DPRINTF(("ah_massage_headers(): unexpected IPv6 header type %d\n", off)); - if (alloc) + + ip6.ip6_flow = 0; + ip6.ip6_hlim = 0; + ip6.ip6_vfc &= ~IPV6_VERSION_MASK; + ip6.ip6_vfc |= IPV6_VERSION; + + /* Scoped address handling. */ + if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_src)) + ip6.ip6_src.s6_addr16[1] = 0; + if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_dst)) + ip6.ip6_dst.s6_addr16[1] = 0; + + /* Done with IPv6 header. */ + m_copyback(m, 0, sizeof(struct ip6_hdr), (caddr_t) &ip6); + + /* Let's deal with the remaining headers (if any). */ + if (skip - sizeof(struct ip6_hdr) > 0) { + if (m->m_len <= skip) { + MALLOC(ptr, unsigned char *, + skip - sizeof(struct ip6_hdr), + M_XDATA, M_NOWAIT); + if (ptr == NULL) { + DPRINTF(("ah_massage_headers(): failed to allocate memory for IPv6 headers\n")); + ahstat.ahs_hdrops++; + m_freem(m); + return ENOBUFS; + } + + /* + * Copy all the protocol headers after + * the IPv6 header. + */ + m_copydata(m, sizeof(struct ip6_hdr), + skip - sizeof(struct ip6_hdr), ptr); + alloc = 1; + } else { + /* No need to allocate memory. */ + ptr = mtod(m, unsigned char *) + + sizeof(struct ip6_hdr); + alloc = 0; + } + } else + break; + + off = ip6.ip6_nxt & 0xff; /* Next header type. */ + + for (len = 0; len < skip - sizeof(struct ip6_hdr);) + switch (off) { + case IPPROTO_HOPOPTS: + case IPPROTO_DSTOPTS: + ip6e = (struct ip6_ext *) (ptr + len); + + /* + * Process the mutable/immutable + * options -- borrows heavily from the + * KAME code. + */ + for (count = len + sizeof(struct ip6_ext); + count < len + ((ip6e->ip6e_len + 1) << 3);) { + if (ptr[count] == IP6OPT_PAD1) { + count++; + continue; /* Skip padding. */ + } + + /* Sanity check. */ + if (count > len + + ((ip6e->ip6e_len + 1) << 3)) { + ahstat.ahs_hdrops++; + m_freem(m); + + /* Free, if we allocated. */ + if (alloc) + FREE(ptr, M_XDATA); + return EINVAL; + } + + ad = ptr[count + 1]; + + /* If mutable option, zeroize. */ + if (ptr[count] & IP6OPT_MUTABLE) + bcopy(ipseczeroes, ptr + count, + ptr[count + 1]); + + count += ad; + + /* Sanity check. */ + if (count > + skip - sizeof(struct ip6_hdr)) { + ahstat.ahs_hdrops++; + m_freem(m); + + /* Free, if we allocated. */ + if (alloc) + FREE(ptr, M_XDATA); + return EINVAL; + } + } + + /* Advance. */ + len += ((ip6e->ip6e_len + 1) << 3); + off = ip6e->ip6e_nxt; + break; + + case IPPROTO_ROUTING: + /* + * Always include routing headers in + * computation. + */ + ip6e = (struct ip6_ext *) (ptr + len); + len += ((ip6e->ip6e_len + 1) << 3); + off = ip6e->ip6e_nxt; + break; + + default: + DPRINTF(("ah_massage_headers(): unexpected " + "IPv6 header type %d\n", off)); + if (alloc) + FREE(ptr, M_XDATA); + ahstat.ahs_hdrops++; + m_freem(m); + return EINVAL; + } + + /* Copyback and free, if we allocated. */ + if (alloc) { + m_copyback(m, sizeof(struct ip6_hdr), + skip - sizeof(struct ip6_hdr), ptr); FREE(ptr, M_XDATA); - ahstat.ahs_hdrops++; - m_freem(m); - return EINVAL; - } - - /* Copyback and free, if we allocated */ - if (alloc) - { - m_copyback(m, sizeof(struct ip6_hdr), - skip - sizeof(struct ip6_hdr), ptr); - FREE(ptr, M_XDATA); - } - - break; + } + + break; #endif /* INET6 */ - } + } - return 0; + return 0; } /* @@ -489,184 +489,193 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out) int ah_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) { - struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform; - struct tdb_ident *tdbi; - struct tdb_crypto *tc; - struct m_tag *mtag; - u_int32_t btsx; - u_int8_t hl; - int rplen; - - struct cryptodesc *crda = NULL; - struct cryptop *crp; - - if (!(tdb->tdb_flags & TDBF_NOREPLAY)) - rplen = AH_FLENGTH + sizeof(u_int32_t); - else - rplen = AH_FLENGTH; - - /* Save the AH header, we use it throughout */ - m_copydata(m, skip + offsetof(struct ah, ah_hl), sizeof(u_int8_t), - (caddr_t) &hl); - - /* Replay window checking, if applicable */ - if ((tdb->tdb_wnd > 0) && (!(tdb->tdb_flags & TDBF_NOREPLAY))) - { - m_copydata(m, skip + offsetof(struct ah, ah_rpl), sizeof(u_int32_t), - (caddr_t) &btsx); - btsx = ntohl(btsx); - - switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl), - tdb->tdb_wnd, &(tdb->tdb_bitmap))) - { - case 0: /* All's well */ - break; + struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform; + struct tdb_ident *tdbi; + struct tdb_crypto *tc; + struct m_tag *mtag; + u_int32_t btsx; + u_int8_t hl; + int rplen; + + struct cryptodesc *crda = NULL; + struct cryptop *crp; + + if (!(tdb->tdb_flags & TDBF_NOREPLAY)) + rplen = AH_FLENGTH + sizeof(u_int32_t); + else + rplen = AH_FLENGTH; + + /* Save the AH header, we use it throughout. */ + m_copydata(m, skip + offsetof(struct ah, ah_hl), sizeof(u_int8_t), + (caddr_t) &hl); + + /* Replay window checking, if applicable. */ + if ((tdb->tdb_wnd > 0) && (!(tdb->tdb_flags & TDBF_NOREPLAY))) { + m_copydata(m, skip + offsetof(struct ah, ah_rpl), + sizeof(u_int32_t), (caddr_t) &btsx); + btsx = ntohl(btsx); + + switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl), + tdb->tdb_wnd, &(tdb->tdb_bitmap))) { + case 0: /* All's well. */ + break; - case 1: - DPRINTF(("ah_input(): replay counter wrapped for SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - ahstat.ahs_wrap++; + case 1: + DPRINTF(("ah_input(): replay counter wrapped for " + "SA %s/%08x\n", ipsp_address(tdb->tdb_dst), + ntohl(tdb->tdb_spi))); + + ahstat.ahs_wrap++; + m_freem(m); + return ENOBUFS; + + case 2: + case 3: + DPRINTF(("ah_input(): duplicate packet received in " + "SA %s/%08x\n", ipsp_address(tdb->tdb_dst), + ntohl(tdb->tdb_spi))); + + ahstat.ahs_replay++; + m_freem(m); + return ENOBUFS; + + default: + DPRINTF(("ah_input(): bogus value from " + "checkreplaywindow32() in SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + + ahstat.ahs_replay++; + m_freem(m); + return ENOBUFS; + } + } + + /* Verify AH header length. */ + if (hl * sizeof(u_int32_t) != ahx->authsize + rplen - AH_FLENGTH) { + DPRINTF(("ah_input(): bad authenticator length %d for packet " + "in SA %s/%08x\n", hl * sizeof(u_int32_t), + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + + ahstat.ahs_badauthl++; m_freem(m); - return ENOBUFS; + return EACCES; + } + + /* Update the counters. */ + tdb->tdb_cur_bytes += + (m->m_pkthdr.len - skip - hl * sizeof(u_int32_t)); + ahstat.ahs_ibytes += (m->m_pkthdr.len - skip - hl * sizeof(u_int32_t)); - case 2: - case 3: - DPRINTF(("ah_input(): duplicate packet received in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - ahstat.ahs_replay++; + /* Hard expiration. */ + if (tdb->tdb_flags & TDBF_BYTES && + tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes) { + pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); + tdb_delete(tdb); m_freem(m); - return ENOBUFS; + return ENXIO; + } - default: - DPRINTF(("ah_input(): bogus value from checkreplaywindow32() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - ahstat.ahs_replay++; - m_freem(m); - return ENOBUFS; + /* Notify on expiration. */ + if (tdb->tdb_flags & TDBF_SOFT_BYTES && + tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes) + { + pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking. */ } - } - - /* Verify AH header length */ - if (hl * sizeof(u_int32_t) != ahx->authsize + rplen - AH_FLENGTH) - { - DPRINTF(("ah_input(): bad authenticator length %d for packet in SA %s/%08x\n", hl * sizeof(u_int32_t), ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - ahstat.ahs_badauthl++; - m_freem(m); - return EACCES; - } - - /* Update the counters */ - tdb->tdb_cur_bytes += (m->m_pkthdr.len - skip - hl * sizeof(u_int32_t)); - ahstat.ahs_ibytes += (m->m_pkthdr.len - skip - hl * sizeof(u_int32_t)); - - /* Hard expiration */ - if ((tdb->tdb_flags & TDBF_BYTES) && - (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) - { - pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); - tdb_delete(tdb); - m_freem(m); - return ENXIO; - } - - /* Notify on expiration */ - if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && - (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) - { - pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ - } - - /* Get crypto descriptors */ - crp = crypto_getreq(1); - if (crp == NULL) - { - m_freem(m); - DPRINTF(("ah_input(): failed to acquire crypto descriptors\n")); - ahstat.ahs_crypto++; - return ENOBUFS; - } - - crda = crp->crp_desc; - - crda->crd_skip = 0; - crda->crd_len = m->m_pkthdr.len; - crda->crd_inject = skip + rplen; - - /* Authentication operation */ - crda->crd_alg = ahx->type; - crda->crd_key = tdb->tdb_amxkey; - crda->crd_klen = tdb->tdb_amxkeylen * 8; - - /* Find out if we've already done crypto */ - for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL); - mtag != NULL; - mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) - { - tdbi = (struct tdb_ident *) (mtag + 1); - if (tdbi->proto == tdb->tdb_sproto && tdbi->spi == tdb->tdb_spi && - !bcmp(&tdbi->dst, &tdb->tdb_dst, sizeof(union sockaddr_union))) - break; - } - - /* Allocate IPsec-specific opaque crypto info */ - if (mtag == NULL) - MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto) + skip + - rplen + ahx->authsize, M_XDATA, M_NOWAIT); - else /* Hash verification has already been done successfully */ - MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto), M_XDATA, - M_NOWAIT); - if (tc == NULL) - { - m_freem(m); - crypto_freereq(crp); - DPRINTF(("ah_input(): failed to allocate tdb_crypto\n")); - ahstat.ahs_crypto++; - return ENOBUFS; - } - bzero(tc, sizeof(struct tdb_crypto)); + /* Get crypto descriptors. */ + crp = crypto_getreq(1); + if (crp == NULL) { + m_freem(m); + DPRINTF(("ah_input(): failed to acquire crypto " + "descriptors\n")); + ahstat.ahs_crypto++; + return ENOBUFS; + } - /* Only save information if crypto processing is needed */ - if (mtag == NULL) - { - /* - * Save the authenticator, the skipped portion of the packet, - * and the AH header. - */ - m_copydata(m, 0, skip + rplen + ahx->authsize, (caddr_t) (tc + 1)); + crda = crp->crp_desc; + + crda->crd_skip = 0; + crda->crd_len = m->m_pkthdr.len; + crda->crd_inject = skip + rplen; + + /* Authentication operation. */ + crda->crd_alg = ahx->type; + crda->crd_key = tdb->tdb_amxkey; + crda->crd_klen = tdb->tdb_amxkeylen * 8; + + /* Find out if we've already done crypto. */ + for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL); + mtag != NULL; + mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) { + tdbi = (struct tdb_ident *) (mtag + 1); + if (tdbi->proto == tdb->tdb_sproto && + tdbi->spi == tdb->tdb_spi && + !bcmp(&tdbi->dst, &tdb->tdb_dst, + sizeof(union sockaddr_union))) + break; + } - /* Zeroize the authenticator on the packet */ - m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes); + /* Allocate IPsec-specific opaque crypto info. */ + if (mtag == NULL) + MALLOC(tc, struct tdb_crypto *, + sizeof(struct tdb_crypto) + skip + + rplen + ahx->authsize, M_XDATA, M_NOWAIT); + else /* Hash verification has already been done successfully. */ + MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto), + M_XDATA, M_NOWAIT); + if (tc == NULL) { + m_freem(m); + crypto_freereq(crp); + DPRINTF(("ah_input(): failed to allocate tdb_crypto\n")); + ahstat.ahs_crypto++; + return ENOBUFS; + } - /* "Massage" the packet headers for crypto processing */ - if ((btsx = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family, - skip, ahx->type, 0)) != 0) - { - /* mbuf will be free'd by callee */ - FREE(tc, M_XDATA); - crypto_freereq(crp); - return btsx; + bzero(tc, sizeof(struct tdb_crypto)); + + /* Only save information if crypto processing is needed. */ + if (mtag == NULL) { + /* + * Save the authenticator, the skipped portion of the packet, + * and the AH header. + */ + m_copydata(m, 0, skip + rplen + ahx->authsize, + (caddr_t) (tc + 1)); + + /* Zeroize the authenticator on the packet. */ + m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes); + + /* "Massage" the packet headers for crypto processing. */ + if ((btsx = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family, + skip, ahx->type, 0)) != 0) { + /* mbuf will be free'd by callee. */ + FREE(tc, M_XDATA); + crypto_freereq(crp); + return btsx; + } } - } - - /* Crypto operation descriptor */ - crp->crp_ilen = m->m_pkthdr.len; /* Total input length */ - crp->crp_flags = CRYPTO_F_IMBUF; - crp->crp_buf = (caddr_t) m; - crp->crp_callback = (int (*) (struct cryptop *)) ah_input_cb; - crp->crp_sid = tdb->tdb_cryptoid; - crp->crp_opaque = (caddr_t) tc; - - /* These are passed as-is to the callback */ - tc->tc_skip = skip; - tc->tc_protoff = protoff; - tc->tc_spi = tdb->tdb_spi; - tc->tc_proto = tdb->tdb_sproto; - tc->tc_ptr = (caddr_t) mtag; /* Save the mtag we've identified */ - bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union)); - - if (mtag == NULL) - return crypto_dispatch(crp); - else - return ah_input_cb(crp); + + /* Crypto operation descriptor. */ + crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */ + crp->crp_flags = CRYPTO_F_IMBUF; + crp->crp_buf = (caddr_t) m; + crp->crp_callback = (int (*) (struct cryptop *)) ah_input_cb; + crp->crp_sid = tdb->tdb_cryptoid; + crp->crp_opaque = (caddr_t) tc; + + /* These are passed as-is to the callback. */ + tc->tc_skip = skip; + tc->tc_protoff = protoff; + tc->tc_spi = tdb->tdb_spi; + tc->tc_proto = tdb->tdb_sproto; + tc->tc_ptr = (caddr_t) mtag; /* Save the mtag we've identified. */ + bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union)); + + if (mtag == NULL) + return crypto_dispatch(crp); + else + return ah_input_cb(crp); } /* @@ -675,188 +684,191 @@ ah_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) int ah_input_cb(void *op) { - int roff, rplen, error, skip, protoff; - unsigned char calc[AH_ALEN_MAX]; - struct mbuf *m1, *m0, *m; - struct cryptodesc *crd; - struct auth_hash *ahx; - struct tdb_crypto *tc; - struct cryptop *crp; - struct m_tag *mtag; - struct tdb *tdb; - u_int8_t prot; - caddr_t ptr; - int s, err; - - crp = (struct cryptop *) op; - crd = crp->crp_desc; - - tc = (struct tdb_crypto *) crp->crp_opaque; - skip = tc->tc_skip; - protoff = tc->tc_protoff; - mtag = (struct m_tag *) tc->tc_ptr; - m = (struct mbuf *) crp->crp_buf; - - s = spltdb(); - - tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto); - FREE(tc, M_XDATA); - if (tdb == NULL) - { - ahstat.ahs_notdb++; - DPRINTF(("ah_input_cb(): TDB is expired while in crypto")); - goto baddone; - } - - ahx = (struct auth_hash *) tdb->tdb_authalgxform; - - /* Check for crypto errors */ - if (crp->crp_etype) - { - if (tdb->tdb_cryptoid != 0) - tdb->tdb_cryptoid = crp->crp_sid; - - if (crp->crp_etype == EAGAIN) - { - splx(s); - return crypto_dispatch(crp); - } - - ahstat.ahs_noxform++; - DPRINTF(("ah_input_cb(): crypto error %d\n", crp->crp_etype)); - error = crp->crp_etype; - goto baddone; - } - else - { - crypto_freereq(crp); /* No longer needed */ - crp = NULL; - } - - /* Shouldn't happen... */ - if (m == NULL) - { - ahstat.ahs_crypto++; - DPRINTF(("ah_input_cb(): bogus returned buffer from crypto\n")); - error = EINVAL; - goto baddone; - } - - if (!(tdb->tdb_flags & TDBF_NOREPLAY)) - rplen = AH_FLENGTH + sizeof(u_int32_t); - else - rplen = AH_FLENGTH; - - /* Copy authenticator off the packet. */ - m_copydata(m, skip + rplen, ahx->authsize, calc); - - /* - * If we have an mtag, we don't need to verify the authenticator -- - * it has been verified by an IPsec-aware NIC. - */ - if (mtag == NULL) - { - ptr = (caddr_t) (tc + 1); + int roff, rplen, error, skip, protoff; + unsigned char calc[AH_ALEN_MAX]; + struct mbuf *m1, *m0, *m; + struct cryptodesc *crd; + struct auth_hash *ahx; + struct tdb_crypto *tc; + struct cryptop *crp; + struct m_tag *mtag; + struct tdb *tdb; + u_int8_t prot; + caddr_t ptr; + int s, err; + + crp = (struct cryptop *) op; + crd = crp->crp_desc; + + tc = (struct tdb_crypto *) crp->crp_opaque; + skip = tc->tc_skip; + protoff = tc->tc_protoff; + mtag = (struct m_tag *) tc->tc_ptr; + m = (struct mbuf *) crp->crp_buf; + + s = spltdb(); + + tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto); + FREE(tc, M_XDATA); + if (tdb == NULL) { + ahstat.ahs_notdb++; + DPRINTF(("ah_input_cb(): TDB is expired while in crypto")); + goto baddone; + } - /* Verify authenticator */ - if (bcmp(ptr + skip + rplen, calc, ahx->authsize)) - { - DPRINTF(("ah_input(): authentication failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - ahstat.ahs_badauth++; - error = EACCES; - goto baddone; + ahx = (struct auth_hash *) tdb->tdb_authalgxform; + + /* Check for crypto errors. */ + if (crp->crp_etype) { + if (tdb->tdb_cryptoid != 0) + tdb->tdb_cryptoid = crp->crp_sid; + + if (crp->crp_etype == EAGAIN) { + splx(s); + return crypto_dispatch(crp); + } + + ahstat.ahs_noxform++; + DPRINTF(("ah_input_cb(): crypto error %d\n", crp->crp_etype)); + error = crp->crp_etype; + goto baddone; + } else { + crypto_freereq(crp); /* No longer needed. */ + crp = NULL; + } + + /* Shouldn't happen... */ + if (m == NULL) { + ahstat.ahs_crypto++; + DPRINTF(("ah_input_cb(): bogus returned buffer from " + "crypto\n")); + error = EINVAL; + goto baddone; + } + + if (!(tdb->tdb_flags & TDBF_NOREPLAY)) + rplen = AH_FLENGTH + sizeof(u_int32_t); + else + rplen = AH_FLENGTH; + + /* Copy authenticator off the packet. */ + m_copydata(m, skip + rplen, ahx->authsize, calc); + + /* + * If we have an mtag, we don't need to verify the authenticator -- + * it has been verified by an IPsec-aware NIC. + */ + if (mtag == NULL) { + ptr = (caddr_t) (tc + 1); + + /* Verify authenticator. */ + if (bcmp(ptr + skip + rplen, calc, ahx->authsize)) { + DPRINTF(("ah_input(): authentication failed for " + "packet in SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + + ahstat.ahs_badauth++; + error = EACCES; + goto baddone; + } + + /* Fix the Next Protocol field. */ + ((u_int8_t *) ptr)[protoff] = ((u_int8_t *) ptr)[skip]; + + /* Copyback the saved (uncooked) network headers. */ + m_copyback(m, 0, skip, ptr); + } else { + /* Fix the Next Protocol field. */ + m_copydata(m, skip, sizeof(u_int8_t), &prot); + m_copyback(m, protoff, sizeof(u_int8_t), &prot); + } + + /* Record the beginning of the AH header. */ + m1 = m_getptr(m, skip, &roff); + if (m1 == NULL) { + ahstat.ahs_hdrops++; + splx(s); + m_freem(m); + + DPRINTF(("ah_input(): bad mbuf chain for packet in SA " + "%s/%08x\n", ipsp_address(tdb->tdb_dst), + ntohl(tdb->tdb_spi))); + + return EINVAL; } - /* Fix the Next Protocol field */ - ((u_int8_t *) ptr)[protoff] = ((u_int8_t *) ptr)[skip]; - - /* Copyback the saved (uncooked) network headers */ - m_copyback(m, 0, skip, ptr); - } - else - { - /* Fix the Next Protocol field */ - m_copydata(m, skip, sizeof(u_int8_t), &prot); - m_copyback(m, protoff, sizeof(u_int8_t), &prot); - } - - /* Record the beginning of the AH header */ - m1 = m_getptr(m, skip, &roff); - if (m1 == NULL) - { - ahstat.ahs_hdrops++; - splx(s); - DPRINTF(("ah_input(): bad mbuf chain for packet in SA %s/%08x\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - return EINVAL; - } - - /* Remove the AH header from the mbuf */ - if (roff == 0) - { - /* The AH header was conveniently at the beginning of the mbuf */ - m_adj(m1, rplen + ahx->authsize); - if (!(m1->m_flags & M_PKTHDR)) - m->m_pkthdr.len -= rplen + ahx->authsize; - } - else - if (roff + rplen + ahx->authsize >= m1->m_len) - { - /* - * Part or all of the AH header is at the end of this mbuf, so first - * let's remove the remainder of the AH header from the - * beginning of the remainder of the mbuf chain, if any. - */ - if (roff + rplen + ahx->authsize > m1->m_len) - { - /* Adjust the next mbuf by the remainder */ - m_adj(m1->m_next, roff + rplen + ahx->authsize - m1->m_len); - - /* The second mbuf is guaranteed not to have a pkthdr... */ - m->m_pkthdr.len -= (roff + rplen + ahx->authsize - m1->m_len); - } - - /* Now, let's unlink the mbuf chain for a second...*/ - m0 = m1->m_next; - m1->m_next = NULL; - - /* ...and trim the end of the first part of the chain...sick */ - m_adj(m1, -(m1->m_len - roff)); - if (!(m1->m_flags & M_PKTHDR)) - m->m_pkthdr.len -= (m1->m_len - roff); - - /* Finally, let's relink */ - m1->m_next = m0; - } - else - { - /* - * The AH header lies in the "middle" of the mbuf...do an - * overlapping copy of the remainder of the mbuf over the ESP - * header. - */ - bcopy(mtod(m1, u_char *) + roff + rplen + ahx->authsize, - mtod(m1, u_char *) + roff, - m1->m_len - (roff + rplen + ahx->authsize)); - m1->m_len -= rplen + ahx->authsize; - m->m_pkthdr.len -= rplen + ahx->authsize; - } - - err = ipsec_common_input_cb(m, tdb, skip, protoff, mtag); - splx(s); - return err; + /* Remove the AH header from the mbuf. */ + if (roff == 0) { + /* + * The AH header was conveniently at the beginning of + * the mbuf. + */ + m_adj(m1, rplen + ahx->authsize); + if (!(m1->m_flags & M_PKTHDR)) + m->m_pkthdr.len -= rplen + ahx->authsize; + } else + if (roff + rplen + ahx->authsize >= m1->m_len) { + /* + * Part or all of the AH header is at the end + * of this mbuf, so first let's remove the + * remainder of the AH header from the + * beginning of the remainder of the mbuf + * chain, if any. + */ + if (roff + rplen + ahx->authsize > m1->m_len) { + /* Adjust the next mbuf by the remainder. */ + m_adj(m1->m_next, roff + rplen + + ahx->authsize - m1->m_len); + + /* + * The second mbuf is guaranteed not + * to have a pkthdr... + */ + m->m_pkthdr.len -= + (roff + rplen + ahx->authsize - m1->m_len); + } + + /* Now, let's unlink the mbuf chain for a second... */ + m0 = m1->m_next; + m1->m_next = NULL; + + /* + * ...and trim the end of the first part of + * the chain...sick + */ + m_adj(m1, -(m1->m_len - roff)); + if (!(m1->m_flags & M_PKTHDR)) + m->m_pkthdr.len -= (m1->m_len - roff); + + /* Finally, let's relink. */ + m1->m_next = m0; + } else { + /* + * The AH header lies in the "middle" of the + * mbuf...do an overlapping copy of the + * remainder of the mbuf over the ESP header. + */ + bcopy(mtod(m1, u_char *) + roff + rplen + + ahx->authsize, mtod(m1, u_char *) + roff, + m1->m_len - (roff + rplen + ahx->authsize)); + m1->m_len -= rplen + ahx->authsize; + m->m_pkthdr.len -= rplen + ahx->authsize; + } + + err = ipsec_common_input_cb(m, tdb, skip, protoff, mtag); + splx(s); + return err; baddone: - splx(s); + splx(s); - if (m != NULL) - m_freem(m); + if (m != NULL) + m_freem(m); - if (crp != NULL) - crypto_freereq(crp); + if (crp != NULL) + crypto_freereq(crp); - return error; + return error; } /* @@ -864,294 +876,289 @@ ah_input_cb(void *op) */ int ah_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip, - int protoff) + int protoff) { - struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform; - struct cryptodesc *crda; - struct tdb_crypto *tc; - struct mbuf *mo, *mi; - struct cryptop *crp; - u_int16_t iplen; - int len, rplen; - u_int8_t prot; - struct ah *ah; + struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform; + struct cryptodesc *crda; + struct tdb_crypto *tc; + struct mbuf *mo, *mi; + struct cryptop *crp; + u_int16_t iplen; + int len, rplen; + u_int8_t prot; + struct ah *ah; #if NBPFILTER > 0 - { - struct ifnet *ifn; - struct enchdr hdr; - struct mbuf m1; + { + struct ifnet *ifn; + struct enchdr hdr; + struct mbuf m1; - bzero (&hdr, sizeof(hdr)); + bzero (&hdr, sizeof(hdr)); - hdr.af = tdb->tdb_dst.sa.sa_family; - hdr.spi = tdb->tdb_spi; - hdr.flags |= M_AUTH; + hdr.af = tdb->tdb_dst.sa.sa_family; + hdr.spi = tdb->tdb_spi; + hdr.flags |= M_AUTH; - m1.m_next = m; - m1.m_len = ENC_HDRLEN; - m1.m_data = (char *) &hdr; + m1.m_next = m; + m1.m_len = ENC_HDRLEN; + m1.m_data = (char *) &hdr; - ifn = &(encif[0].sc_if); + ifn = &(encif[0].sc_if); - if (ifn->if_bpf) - bpf_mtap(ifn->if_bpf, &m1); - } + if (ifn->if_bpf) + bpf_mtap(ifn->if_bpf, &m1); + } #endif - ahstat.ahs_output++; - - /* Check for replay counter wrap-around in automatic (not manual) keying */ - if ((tdb->tdb_rpl == 0) && (tdb->tdb_wnd > 0) && - (!(tdb->tdb_flags & TDBF_NOREPLAY))) - { - DPRINTF(("ah_output(): SA %s/%08x should have expired\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - ahstat.ahs_wrap++; - return NULL; - } - - if (!(tdb->tdb_flags & TDBF_NOREPLAY)) - rplen = AH_FLENGTH + sizeof(u_int32_t); - else - rplen = AH_FLENGTH; - - switch (tdb->tdb_dst.sa.sa_family) - { + ahstat.ahs_output++; + + /* + * Check for replay counter wrap-around in automatic (not + * manual) keying. + */ + if ((tdb->tdb_rpl == 0) && (tdb->tdb_wnd > 0) && + (!(tdb->tdb_flags & TDBF_NOREPLAY))) { + DPRINTF(("ah_output(): SA %s/%08x should have expired\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + ahstat.ahs_wrap++; + return NULL; + } + + if (!(tdb->tdb_flags & TDBF_NOREPLAY)) + rplen = AH_FLENGTH + sizeof(u_int32_t); + else + rplen = AH_FLENGTH; + + switch (tdb->tdb_dst.sa.sa_family) { #ifdef INET case AF_INET: - /* Check for IP maximum packet size violations */ - if (rplen + ahx->authsize + m->m_pkthdr.len > IP_MAXPACKET) - { - DPRINTF(("ah_output(): packet in SA %s/%08x got too big\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - ahstat.ahs_toobig++; - return EMSGSIZE; - } - break; + /* Check for IP maximum packet size violations. */ + if (rplen + ahx->authsize + m->m_pkthdr.len > IP_MAXPACKET) { + DPRINTF(("ah_output(): packet in SA %s/%08x got too " + "big\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + ahstat.ahs_toobig++; + return EMSGSIZE; + } + break; #endif /* INET */ #ifdef INET6 case AF_INET6: - /* Check for IPv6 maximum packet size violations */ - if (rplen + ahx->authsize + m->m_pkthdr.len > IPV6_MAXPACKET) - { - DPRINTF(("ah_output(): packet in SA %s/%08x got too big\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - ahstat.ahs_toobig++; - return EMSGSIZE; - } - break; + /* Check for IPv6 maximum packet size violations. */ + if (rplen + ahx->authsize + m->m_pkthdr.len > IPV6_MAXPACKET) { + DPRINTF(("ah_output(): packet in SA %s/%08x " + "got too big\n", ipsp_address(tdb->tdb_dst), + ntohl(tdb->tdb_spi))); + m_freem(m); + ahstat.ahs_toobig++; + return EMSGSIZE; + } + break; #endif /* INET6 */ default: - DPRINTF(("ah_output(): unknown/unsupported protocol family %d, SA %s/%08x\n", tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - ahstat.ahs_nopf++; - return EPFNOSUPPORT; - } - - /* Update the counters */ - tdb->tdb_cur_bytes += m->m_pkthdr.len - skip; - ahstat.ahs_obytes += m->m_pkthdr.len - skip; - - /* Hard expiration */ - if ((tdb->tdb_flags & TDBF_BYTES) && - (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) - { - pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); - tdb_delete(tdb); - m_freem(m); - return EINVAL; - } - - /* Notify on expiration */ - if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && - (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) - { - pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ - } - - /* - * Loop through mbuf chain; if we find an M_EXT mbuf with - * more than one reference, replace the rest of the chain. - */ - mi = m; - while (mi != NULL && - (!(mi->m_flags & M_EXT) || !MCLISREFERENCED(mi))) - { - mo = mi; - mi = mi->m_next; - } - - if (mi != NULL) - { - /* Replace the rest of the mbuf chain. */ - struct mbuf *n = m_copym2(mi, 0, M_COPYALL, M_DONTWAIT); - - if (n == NULL) - { - ahstat.ahs_hdrops++; - m_freem(m); - return ENOBUFS; - } - - if (mo != NULL) - mo->m_next = n; - else - m = n; - - m_freem(mi); - } - - /* Inject AH header */ - mi = m_inject(m, skip, rplen + ahx->authsize, M_DONTWAIT); - if (mi == NULL) - { - DPRINTF(("ah_output(): failed to inject AH header for SA %s/%08x\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - ahstat.ahs_wrap++; - return ENOBUFS; - } - - /* - * The AH header is guaranteed by m_inject() to be in contiguous memory, - * at the beginning of the returned mbuf. - */ - ah = mtod(mi, struct ah *); - - /* Initialize the AH header */ - m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &ah->ah_nh); - ah->ah_hl = (rplen + ahx->authsize - AH_FLENGTH) / sizeof(u_int32_t); - ah->ah_rv = 0; - ah->ah_spi = tdb->tdb_spi; - - /* Zeroize authenticator */ - m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes); - - if (!(tdb->tdb_flags & TDBF_NOREPLAY)) - ah->ah_rpl = htonl(tdb->tdb_rpl++); - - /* Get crypto descriptors */ - crp = crypto_getreq(1); - if (crp == NULL) - { - m_freem(m); - DPRINTF(("ah_output(): failed to acquire crypto descriptors\n")); - ahstat.ahs_crypto++; - return ENOBUFS; - } - - crda = crp->crp_desc; - - crda->crd_skip = 0; - crda->crd_inject = skip + rplen; - crda->crd_len = m->m_pkthdr.len; - - /* Authentication operation */ - crda->crd_alg = ahx->type; - crda->crd_key = tdb->tdb_amxkey; - crda->crd_klen = tdb->tdb_amxkeylen * 8; - - /* Allocate IPsec-specific opaque crypto info */ - if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) - MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto) + skip, - M_XDATA, M_NOWAIT); - else - MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto), M_XDATA, - M_NOWAIT); - if (tc == NULL) - { - m_freem(m); - crypto_freereq(crp); - DPRINTF(("ah_output(): failed to allocate tdb_crypto\n")); - ahstat.ahs_crypto++; - return ENOBUFS; - } + DPRINTF(("ah_output(): unknown/unsupported protocol " + "family %d, SA %s/%08x\n", tdb->tdb_dst.sa.sa_family, + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + ahstat.ahs_nopf++; + return EPFNOSUPPORT; + } - bzero(tc, sizeof(struct tdb_crypto)); + /* Update the counters. */ + tdb->tdb_cur_bytes += m->m_pkthdr.len - skip; + ahstat.ahs_obytes += m->m_pkthdr.len - skip; + + /* Hard expiration. */ + if (tdb->tdb_flags & TDBF_BYTES && + tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes) { + pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); + tdb_delete(tdb); + m_freem(m); + return EINVAL; + } - /* Save the skipped portion of the packet */ - if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) - { - m_copydata(m, 0, skip, (caddr_t) (tc + 1)); + /* Notify on expiration. */ + if (tdb->tdb_flags & TDBF_SOFT_BYTES && + tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes) { + pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ + } /* - * Fix IP header length on the header used for authentication. We don't - * need to fix the original header length as it will be fixed by our - * caller. + * Loop through mbuf chain; if we find an M_EXT mbuf with + * more than one reference, replace the rest of the chain. */ - switch (tdb->tdb_dst.sa.sa_family) - { + mi = m; + while (mi != NULL && + (!(mi->m_flags & M_EXT) || !MCLISREFERENCED(mi))) { + mo = mi; + mi = mi->m_next; + } + + if (mi != NULL) { + /* Replace the rest of the mbuf chain. */ + struct mbuf *n = m_copym2(mi, 0, M_COPYALL, M_DONTWAIT); + + if (n == NULL) { + ahstat.ahs_hdrops++; + m_freem(m); + return ENOBUFS; + } + + if (mo != NULL) + mo->m_next = n; + else + m = n; + + m_freem(mi); + } + + /* Inject AH header. */ + mi = m_inject(m, skip, rplen + ahx->authsize, M_DONTWAIT); + if (mi == NULL) { + DPRINTF(("ah_output(): failed to inject AH header for SA " + "%s/%08x\n", ipsp_address(tdb->tdb_dst), + ntohl(tdb->tdb_spi))); + + m_freem(m); + ahstat.ahs_wrap++; + return ENOBUFS; + } + + /* + * The AH header is guaranteed by m_inject() to be in + * contiguous memory, at the beginning of the returned mbuf. + */ + ah = mtod(mi, struct ah *); + + /* Initialize the AH header. */ + m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &ah->ah_nh); + ah->ah_hl = (rplen + ahx->authsize - AH_FLENGTH) / sizeof(u_int32_t); + ah->ah_rv = 0; + ah->ah_spi = tdb->tdb_spi; + + /* Zeroize authenticator. */ + m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes); + + if (!(tdb->tdb_flags & TDBF_NOREPLAY)) + ah->ah_rpl = htonl(tdb->tdb_rpl++); + + /* Get crypto descriptors. */ + crp = crypto_getreq(1); + if (crp == NULL) { + m_freem(m); + DPRINTF(("ah_output(): failed to acquire crypto " + "descriptors\n")); + ahstat.ahs_crypto++; + return ENOBUFS; + } + + crda = crp->crp_desc; + + crda->crd_skip = 0; + crda->crd_inject = skip + rplen; + crda->crd_len = m->m_pkthdr.len; + + /* Authentication operation. */ + crda->crd_alg = ahx->type; + crda->crd_key = tdb->tdb_amxkey; + crda->crd_klen = tdb->tdb_amxkeylen * 8; + + /* Allocate IPsec-specific opaque crypto info. */ + if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) + MALLOC(tc, struct tdb_crypto *, + sizeof(struct tdb_crypto) + skip, M_XDATA, M_NOWAIT); + else + MALLOC(tc, struct tdb_crypto *, + sizeof(struct tdb_crypto), M_XDATA, M_NOWAIT); + if (tc == NULL) { + m_freem(m); + crypto_freereq(crp); + DPRINTF(("ah_output(): failed to allocate tdb_crypto\n")); + ahstat.ahs_crypto++; + return ENOBUFS; + } + + bzero(tc, sizeof(struct tdb_crypto)); + + /* Save the skipped portion of the packet. */ + if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) { + m_copydata(m, 0, skip, (caddr_t) (tc + 1)); + + /* + * Fix IP header length on the header used for + * authentication. We don't need to fix the original + * header length as it will be fixed by our caller. + */ + switch (tdb->tdb_dst.sa.sa_family) { #ifdef INET - case AF_INET: - bcopy(((caddr_t)(tc + 1)) + offsetof(struct ip, ip_len), - (caddr_t) &iplen, sizeof(u_int16_t)); - iplen = htons(ntohs(iplen) + rplen + ahx->authsize); - m_copyback(m, offsetof(struct ip, ip_len), sizeof(u_int16_t), - (caddr_t) &iplen); - break; + case AF_INET: + bcopy(((caddr_t)(tc + 1)) + + offsetof(struct ip, ip_len), + (caddr_t) &iplen, sizeof(u_int16_t)); + iplen = htons(ntohs(iplen) + rplen + ahx->authsize); + m_copyback(m, offsetof(struct ip, ip_len), + sizeof(u_int16_t), (caddr_t) &iplen); + break; #endif /* INET */ #ifdef INET6 - case AF_INET6: - bcopy(((caddr_t)(tc + 1)) + offsetof(struct ip6_hdr, ip6_plen), - (caddr_t) &iplen, sizeof(u_int16_t)); - iplen = htons(ntohs(iplen) + rplen + ahx->authsize); - m_copyback(m, offsetof(struct ip6_hdr, ip6_plen), - sizeof(u_int16_t), (caddr_t) &iplen); - break; + case AF_INET6: + bcopy(((caddr_t)(tc + 1)) + + offsetof(struct ip6_hdr, ip6_plen), + (caddr_t) &iplen, sizeof(u_int16_t)); + iplen = htons(ntohs(iplen) + rplen + ahx->authsize); + m_copyback(m, offsetof(struct ip6_hdr, ip6_plen), + sizeof(u_int16_t), (caddr_t) &iplen); + break; #endif /* INET6 */ - } + } - /* Fix the Next Header field in saved header. */ - ((u_int8_t *) (tc + 1))[protoff] = IPPROTO_AH; + /* Fix the Next Header field in saved header. */ + ((u_int8_t *) (tc + 1))[protoff] = IPPROTO_AH; - /* Update the Next Protocol field in the IP header. */ - prot = IPPROTO_AH; - m_copyback(m, protoff, sizeof(u_int8_t), (caddr_t) &prot); + /* Update the Next Protocol field in the IP header. */ + prot = IPPROTO_AH; + m_copyback(m, protoff, sizeof(u_int8_t), (caddr_t) &prot); - /* "Massage" the packet headers for crypto processing */ - if ((len = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family, - skip, ahx->type, 1)) != 0) - { - /* mbuf will be free'd by callee */ - FREE(tc, M_XDATA); - crypto_freereq(crp); - return len; + /* "Massage" the packet headers for crypto processing. */ + if ((len = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family, + skip, ahx->type, 1)) != 0) { + /* mbuf will be free'd by callee. */ + FREE(tc, M_XDATA); + crypto_freereq(crp); + return len; + } + } else { + /* Update the Next Protocol field in the IP header. */ + prot = IPPROTO_AH; + m_copyback(m, protoff, sizeof(u_int8_t), (caddr_t) &prot); } - } - else - { - /* Update the Next Protocol field in the IP header. */ - prot = IPPROTO_AH; - m_copyback(m, protoff, sizeof(u_int8_t), (caddr_t) &prot); - } - - /* Crypto operation descriptor */ - crp->crp_ilen = m->m_pkthdr.len; /* Total input length */ - crp->crp_flags = CRYPTO_F_IMBUF; - crp->crp_buf = (caddr_t) m; - crp->crp_callback = (int (*) (struct cryptop *)) ah_output_cb; - crp->crp_sid = tdb->tdb_cryptoid; - crp->crp_opaque = (caddr_t) tc; - - /* These are passed as-is to the callback */ - tc->tc_skip = skip; - tc->tc_protoff = protoff; - tc->tc_spi = tdb->tdb_spi; - tc->tc_proto = tdb->tdb_sproto; - bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union)); - - if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) - return crypto_dispatch(crp); - else - return ah_output_cb(crp); + + /* Crypto operation descriptor. */ + crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */ + crp->crp_flags = CRYPTO_F_IMBUF; + crp->crp_buf = (caddr_t) m; + crp->crp_callback = (int (*) (struct cryptop *)) ah_output_cb; + crp->crp_sid = tdb->tdb_cryptoid; + crp->crp_opaque = (caddr_t) tc; + + /* These are passed as-is to the callback. */ + tc->tc_skip = skip; + tc->tc_protoff = protoff; + tc->tc_spi = tdb->tdb_spi; + tc->tc_proto = tdb->tdb_sproto; + bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union)); + + if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) + return crypto_dispatch(crp); + else + return ah_output_cb(crp); } /* @@ -1160,78 +1167,78 @@ ah_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip, int ah_output_cb(void *op) { - int skip, protoff, error; - struct tdb_crypto *tc; - struct cryptop *crp; - struct tdb *tdb; - struct mbuf *m; - caddr_t ptr; - int err, s; - - crp = (struct cryptop *) op; - tc = (struct tdb_crypto *) crp->crp_opaque; - skip = tc->tc_skip; - protoff = tc->tc_protoff; - ptr = (caddr_t) (tc + 1); - m = (struct mbuf *) crp->crp_buf; - - s = spltdb(); - - tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto); - - FREE(tc, M_XDATA); - if (tdb == NULL) - { - ahstat.ahs_notdb++; - DPRINTF(("ah_output_cb(): TDB is expired while in crypto\n")); - goto baddone; - } - - /* Check for crypto errors */ - if (crp->crp_etype) - { - if (tdb->tdb_cryptoid != 0) - tdb->tdb_cryptoid = crp->crp_sid; - - if (crp->crp_etype == EAGAIN) - { - splx(s); - return crypto_dispatch(crp); - } - - ahstat.ahs_noxform++; - DPRINTF(("ah_output_cb(): crypto error %d\n", crp->crp_etype)); - error = crp->crp_etype; - goto baddone; - } - - /* Shouldn't happen... */ - if (m == NULL) - { - ahstat.ahs_crypto++; - DPRINTF(("ah_output_cb(): bogus returned buffer from crypto\n")); - error = EINVAL; - goto baddone; - } - - /* Copy original headers (with the new protocol number) back in place */ - if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) - m_copyback(m, 0, skip, ptr); - - /* No longer needed */ - crypto_freereq(crp); - - err = ipsp_process_done(m, tdb); - splx(s); - return err; + int skip, protoff, error; + struct tdb_crypto *tc; + struct cryptop *crp; + struct tdb *tdb; + struct mbuf *m; + caddr_t ptr; + int err, s; + + crp = (struct cryptop *) op; + tc = (struct tdb_crypto *) crp->crp_opaque; + skip = tc->tc_skip; + protoff = tc->tc_protoff; + ptr = (caddr_t) (tc + 1); + m = (struct mbuf *) crp->crp_buf; + + s = spltdb(); + + tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto); + + FREE(tc, M_XDATA); + if (tdb == NULL) { + ahstat.ahs_notdb++; + DPRINTF(("ah_output_cb(): TDB is expired while in crypto\n")); + goto baddone; + } + + /* Check for crypto errors. */ + if (crp->crp_etype) { + if (tdb->tdb_cryptoid != 0) + tdb->tdb_cryptoid = crp->crp_sid; + + if (crp->crp_etype == EAGAIN) { + splx(s); + return crypto_dispatch(crp); + } + + ahstat.ahs_noxform++; + DPRINTF(("ah_output_cb(): crypto error %d\n", crp->crp_etype)); + error = crp->crp_etype; + goto baddone; + } + + /* Shouldn't happen... */ + if (m == NULL) { + ahstat.ahs_crypto++; + DPRINTF(("ah_output_cb(): bogus returned buffer from " + "crypto\n")); + error = EINVAL; + goto baddone; + } + + /* + * Copy original headers (with the new protocol number) back + * in place. + */ + if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) + m_copyback(m, 0, skip, ptr); + + /* No longer needed. */ + crypto_freereq(crp); + + err = ipsp_process_done(m, tdb); + splx(s); + return err; baddone: - splx(s); + splx(s); - if (m != NULL) - m_freem(m); + if (m != NULL) + m_freem(m); - crypto_freereq(crp); + crypto_freereq(crp); - return error; + return error; } diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c index dfabee511eb..87e8b516062 100644 --- a/sys/netinet/ip_esp.c +++ b/sys/netinet/ip_esp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_esp.c,v 1.68 2001/06/25 05:11:58 angelos Exp $ */ +/* $OpenBSD: ip_esp.c,v 1.69 2001/06/26 06:18:59 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -80,7 +80,7 @@ int esp_attach() { - return 0; + return 0; } /* @@ -89,143 +89,143 @@ esp_attach() int esp_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii) { - struct enc_xform *txform = NULL; - struct auth_hash *thash = NULL; - struct cryptoini cria, crie; - - if (ii->ii_encalg) - { - switch (ii->ii_encalg) - { - case SADB_EALG_DESCBC: - txform = &enc_xform_des; - break; - - case SADB_EALG_3DESCBC: - txform = &enc_xform_3des; - break; - - case SADB_X_EALG_AES: - txform = &enc_xform_rijndael128; - break; - - case SADB_X_EALG_BLF: - txform = &enc_xform_blf; - break; - - case SADB_X_EALG_CAST: - txform = &enc_xform_cast5; - break; - - case SADB_X_EALG_SKIPJACK: - txform = &enc_xform_skipjack; - break; + struct enc_xform *txform = NULL; + struct auth_hash *thash = NULL; + struct cryptoini cria, crie; - default: - DPRINTF(("esp_init(): unsupported encryption algorithm %d specified\n", ii->ii_encalg)); - return EINVAL; - } - - if (ii->ii_enckeylen < txform->minkey) + if (ii->ii_encalg) { - DPRINTF(("esp_init(): keylength %d too small (min length is %d) for algorithm %s\n", ii->ii_enckeylen, txform->minkey, txform->name)); - return EINVAL; + switch (ii->ii_encalg) + { + case SADB_EALG_DESCBC: + txform = &enc_xform_des; + break; + + case SADB_EALG_3DESCBC: + txform = &enc_xform_3des; + break; + + case SADB_X_EALG_AES: + txform = &enc_xform_rijndael128; + break; + + case SADB_X_EALG_BLF: + txform = &enc_xform_blf; + break; + + case SADB_X_EALG_CAST: + txform = &enc_xform_cast5; + break; + + case SADB_X_EALG_SKIPJACK: + txform = &enc_xform_skipjack; + break; + + default: + DPRINTF(("esp_init(): unsupported encryption algorithm %d specified\n", ii->ii_encalg)); + return EINVAL; + } + + if (ii->ii_enckeylen < txform->minkey) + { + DPRINTF(("esp_init(): keylength %d too small (min length is %d) for algorithm %s\n", ii->ii_enckeylen, txform->minkey, txform->name)); + return EINVAL; + } + + if (ii->ii_enckeylen > txform->maxkey) + { + DPRINTF(("esp_init(): keylength %d too large (max length is %d) for algorithm %s\n", ii->ii_enckeylen, txform->maxkey, txform->name)); + return EINVAL; + } + + tdbp->tdb_encalgxform = txform; + + DPRINTF(("esp_init(): initialized TDB with enc algorithm %s\n", + txform->name)); + + tdbp->tdb_ivlen = txform->blocksize; + if (tdbp->tdb_flags & TDBF_HALFIV) + tdbp->tdb_ivlen /= 2; } - if (ii->ii_enckeylen > txform->maxkey) + if (ii->ii_authalg) { - DPRINTF(("esp_init(): keylength %d too large (max length is %d) for algorithm %s\n", ii->ii_enckeylen, txform->maxkey, txform->name)); - return EINVAL; + switch (ii->ii_authalg) + { + case SADB_AALG_MD5HMAC: + thash = &auth_hash_hmac_md5_96; + break; + + case SADB_AALG_SHA1HMAC: + thash = &auth_hash_hmac_sha1_96; + break; + + case SADB_AALG_RIPEMD160HMAC: + thash = &auth_hash_hmac_ripemd_160_96; + break; + + default: + DPRINTF(("esp_init(): unsupported authentication algorithm %d specified\n", ii->ii_authalg)); + return EINVAL; + } + + if (ii->ii_authkeylen != thash->keysize) + { + DPRINTF(("esp_init(): keylength %d doesn't match algorithm %s keysize (%d)\n", ii->ii_authkeylen, thash->name, thash->keysize)); + return EINVAL; + } + + tdbp->tdb_authalgxform = thash; + + DPRINTF(("esp_init(): initialized TDB with hash algorithm %s\n", + thash->name)); } - tdbp->tdb_encalgxform = txform; - - DPRINTF(("esp_init(): initialized TDB with enc algorithm %s\n", - txform->name)); + tdbp->tdb_xform = xsp; + tdbp->tdb_bitmap = 0; + tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL; - tdbp->tdb_ivlen = txform->blocksize; - if (tdbp->tdb_flags & TDBF_HALFIV) - tdbp->tdb_ivlen /= 2; - } - - if (ii->ii_authalg) - { - switch (ii->ii_authalg) + /* Initialize crypto session */ + if (tdbp->tdb_encalgxform) { - case SADB_AALG_MD5HMAC: - thash = &auth_hash_hmac_md5_96; - break; + /* Save the raw keys */ + tdbp->tdb_emxkeylen = ii->ii_enckeylen; + MALLOC(tdbp->tdb_emxkey, u_int8_t *, tdbp->tdb_emxkeylen, M_XDATA, + M_WAITOK); + bcopy(ii->ii_enckey, tdbp->tdb_emxkey, tdbp->tdb_emxkeylen); - case SADB_AALG_SHA1HMAC: - thash = &auth_hash_hmac_sha1_96; - break; + bzero(&crie, sizeof(crie)); - case SADB_AALG_RIPEMD160HMAC: - thash = &auth_hash_hmac_ripemd_160_96; - break; + crie.cri_alg = tdbp->tdb_encalgxform->type; - default: - DPRINTF(("esp_init(): unsupported authentication algorithm %d specified\n", ii->ii_authalg)); - return EINVAL; + if (tdbp->tdb_authalgxform) + crie.cri_next = &cria; + else + crie.cri_next = NULL; + + crie.cri_klen = ii->ii_enckeylen * 8; + crie.cri_key = ii->ii_enckey; + /* XXX Rounds ? */ } - if (ii->ii_authkeylen != thash->keysize) + if (tdbp->tdb_authalgxform) { - DPRINTF(("esp_init(): keylength %d doesn't match algorithm %s keysize (%d)\n", ii->ii_authkeylen, thash->name, thash->keysize)); - return EINVAL; + /* Save the raw keys */ + tdbp->tdb_amxkeylen = ii->ii_authkeylen; + MALLOC(tdbp->tdb_amxkey, u_int8_t *, tdbp->tdb_amxkeylen, M_XDATA, + M_WAITOK); + bcopy(ii->ii_authkey, tdbp->tdb_amxkey, tdbp->tdb_amxkeylen); + + bzero(&cria, sizeof(cria)); + + cria.cri_alg = tdbp->tdb_authalgxform->type; + cria.cri_next = NULL; + cria.cri_klen = ii->ii_authkeylen * 8; + cria.cri_key = ii->ii_authkey; } - tdbp->tdb_authalgxform = thash; - - DPRINTF(("esp_init(): initialized TDB with hash algorithm %s\n", - thash->name)); - } - - tdbp->tdb_xform = xsp; - tdbp->tdb_bitmap = 0; - tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL; - - /* Initialize crypto session */ - if (tdbp->tdb_encalgxform) - { - /* Save the raw keys */ - tdbp->tdb_emxkeylen = ii->ii_enckeylen; - MALLOC(tdbp->tdb_emxkey, u_int8_t *, tdbp->tdb_emxkeylen, M_XDATA, - M_WAITOK); - bcopy(ii->ii_enckey, tdbp->tdb_emxkey, tdbp->tdb_emxkeylen); - - bzero(&crie, sizeof(crie)); - - crie.cri_alg = tdbp->tdb_encalgxform->type; - - if (tdbp->tdb_authalgxform) - crie.cri_next = &cria; - else - crie.cri_next = NULL; - - crie.cri_klen = ii->ii_enckeylen * 8; - crie.cri_key = ii->ii_enckey; - /* XXX Rounds ? */ - } - - if (tdbp->tdb_authalgxform) - { - /* Save the raw keys */ - tdbp->tdb_amxkeylen = ii->ii_authkeylen; - MALLOC(tdbp->tdb_amxkey, u_int8_t *, tdbp->tdb_amxkeylen, M_XDATA, - M_WAITOK); - bcopy(ii->ii_authkey, tdbp->tdb_amxkey, tdbp->tdb_amxkeylen); - - bzero(&cria, sizeof(cria)); - - cria.cri_alg = tdbp->tdb_authalgxform->type; - cria.cri_next = NULL; - cria.cri_klen = ii->ii_authkeylen * 8; - cria.cri_key = ii->ii_authkey; - } - - return crypto_newsession(&tdbp->tdb_cryptoid, - (tdbp->tdb_encalgxform ? &crie : &cria), 0); + return crypto_newsession(&tdbp->tdb_cryptoid, + (tdbp->tdb_encalgxform ? &crie : &cria), 0); } /* @@ -234,25 +234,25 @@ esp_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii) int esp_zeroize(struct tdb *tdbp) { - int err; - - if (tdbp->tdb_amxkey) - { - bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen); - FREE(tdbp->tdb_amxkey, M_XDATA); - tdbp->tdb_amxkey = NULL; - } - - if (tdbp->tdb_emxkey) - { - bzero(tdbp->tdb_emxkey, tdbp->tdb_emxkeylen); - FREE(tdbp->tdb_emxkey, M_XDATA); - tdbp->tdb_emxkey = NULL; - } - - err = crypto_freesession(tdbp->tdb_cryptoid); - tdbp->tdb_cryptoid = 0; - return err; + int err; + + if (tdbp->tdb_amxkey) + { + bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen); + FREE(tdbp->tdb_amxkey, M_XDATA); + tdbp->tdb_amxkey = NULL; + } + + if (tdbp->tdb_emxkey) + { + bzero(tdbp->tdb_emxkey, tdbp->tdb_emxkeylen); + FREE(tdbp->tdb_emxkey, M_XDATA); + tdbp->tdb_emxkey = NULL; + } + + err = crypto_freesession(tdbp->tdb_cryptoid); + tdbp->tdb_cryptoid = 0; + return err; } #define MAXBUFSIZ (AH_ALEN_MAX > ESP_MAX_IVS ? AH_ALEN_MAX : ESP_MAX_IVS) @@ -263,205 +263,205 @@ esp_zeroize(struct tdb *tdbp) int esp_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) { - struct auth_hash *esph = (struct auth_hash *) tdb->tdb_authalgxform; - struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform; - struct tdb_ident *tdbi; - struct tdb_crypto *tc; - int plen, alen, hlen; - struct m_tag *mtag; - u_int32_t btsx; - - struct cryptodesc *crde = NULL, *crda = NULL; - struct cryptop *crp; - - /* Determine the ESP header length */ - if (tdb->tdb_flags & TDBF_NOREPLAY) - hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; /* "old" ESP */ - else - hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; /* "new" ESP */ - - if (esph) - alen = AH_HMAC_HASHLEN; - else - alen = 0; - - if (espx) - { - /* - * Verify payload length is multiple of encryption algorithm - * block size. - */ - plen = m->m_pkthdr.len - (skip + hlen + alen); - if ((plen & (espx->blocksize - 1)) || (plen <= 0)) + struct auth_hash *esph = (struct auth_hash *) tdb->tdb_authalgxform; + struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform; + struct tdb_ident *tdbi; + struct tdb_crypto *tc; + int plen, alen, hlen; + struct m_tag *mtag; + u_int32_t btsx; + + struct cryptodesc *crde = NULL, *crda = NULL; + struct cryptop *crp; + + /* Determine the ESP header length */ + if (tdb->tdb_flags & TDBF_NOREPLAY) + hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; /* "old" ESP */ + else + hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; /* "new" ESP */ + + if (esph) + alen = AH_HMAC_HASHLEN; + else + alen = 0; + + if (espx) { - DPRINTF(("esp_input(): payload of %d octets not a multiple of %d octets, SA %s/%08x\n", plen, espx->blocksize, ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - espstat.esps_badilen++; - m_freem(m); - return EINVAL; + /* + * Verify payload length is multiple of encryption algorithm + * block size. + */ + plen = m->m_pkthdr.len - (skip + hlen + alen); + if ((plen & (espx->blocksize - 1)) || (plen <= 0)) + { + DPRINTF(("esp_input(): payload of %d octets not a multiple of %d octets, SA %s/%08x\n", plen, espx->blocksize, ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_badilen++; + m_freem(m); + return EINVAL; + } } - } - - /* Replay window checking, if appropriate */ - if ((tdb->tdb_wnd > 0) && (!(tdb->tdb_flags & TDBF_NOREPLAY))) - { - m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t), - (unsigned char *) &btsx); - btsx = ntohl(btsx); - switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl), tdb->tdb_wnd, - &(tdb->tdb_bitmap))) + /* Replay window checking, if appropriate */ + if ((tdb->tdb_wnd > 0) && (!(tdb->tdb_flags & TDBF_NOREPLAY))) { - case 0: /* All's well */ - break; + m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t), + (unsigned char *) &btsx); + btsx = ntohl(btsx); + + switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl), tdb->tdb_wnd, + &(tdb->tdb_bitmap))) + { + case 0: /* All's well */ + break; + + case 1: + DPRINTF(("esp_input(): replay counter wrapped for SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_wrap++; + m_freem(m); + return EACCES; + + case 2: + case 3: + DPRINTF(("esp_input(): duplicate packet received in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_replay++; + m_freem(m); + return EACCES; + + default: + DPRINTF(("esp_input(): bogus value from checkreplaywindow32() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_replay++; + m_freem(m); + return EACCES; + } + } - case 1: - DPRINTF(("esp_input(): replay counter wrapped for SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - espstat.esps_wrap++; - m_freem(m); - return EACCES; + /* Update the counters */ + tdb->tdb_cur_bytes += m->m_pkthdr.len - skip - hlen - alen; + espstat.esps_ibytes += m->m_pkthdr.len - skip - hlen - alen; - case 2: - case 3: - DPRINTF(("esp_input(): duplicate packet received in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - espstat.esps_replay++; + /* Hard expiration */ + if ((tdb->tdb_flags & TDBF_BYTES) && + (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) + { + pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); + tdb_delete(tdb); m_freem(m); - return EACCES; + return ENXIO; + } - default: - DPRINTF(("esp_input(): bogus value from checkreplaywindow32() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - espstat.esps_replay++; - m_freem(m); - return EACCES; + /* Notify on soft expiration */ + if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && + (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) + { + pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ } - } - - /* Update the counters */ - tdb->tdb_cur_bytes += m->m_pkthdr.len - skip - hlen - alen; - espstat.esps_ibytes += m->m_pkthdr.len - skip - hlen - alen; - - /* Hard expiration */ - if ((tdb->tdb_flags & TDBF_BYTES) && - (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) - { - pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); - tdb_delete(tdb); - m_freem(m); - return ENXIO; - } - - /* Notify on soft expiration */ - if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && - (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) - { - pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ - } - - /* Find out if we've already done crypto */ - for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL); - mtag != NULL; - mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) - { - tdbi = (struct tdb_ident *) (mtag + 1); - if (tdbi->proto == tdb->tdb_sproto && tdbi->spi == tdb->tdb_spi && - !bcmp(&tdbi->dst, &tdb->tdb_dst, sizeof(union sockaddr_union))) - break; - } - - /* Get crypto descriptors */ - crp = crypto_getreq(esph && espx ? 2 : 1); - if (crp == NULL) - { - m_freem(m); - DPRINTF(("esp_input(): failed to acquire crypto descriptors\n")); - espstat.esps_crypto++; - return ENOBUFS; - } - - /* Get IPsec-specific opaque pointer */ - if (esph == NULL || mtag != NULL) - MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto), - M_XDATA, M_NOWAIT); - else - MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto) + alen, - M_XDATA, M_NOWAIT); - if (tc == NULL) - { - m_freem(m); - crypto_freereq(crp); - DPRINTF(("esp_input(): failed to allocate tdb_crypto\n")); - espstat.esps_crypto++; - return ENOBUFS; - } - bzero(tc, sizeof(struct tdb_crypto)); - tc->tc_ptr = (caddr_t) mtag; + /* Find out if we've already done crypto */ + for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL); + mtag != NULL; + mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) + { + tdbi = (struct tdb_ident *) (mtag + 1); + if (tdbi->proto == tdb->tdb_sproto && tdbi->spi == tdb->tdb_spi && + !bcmp(&tdbi->dst, &tdb->tdb_dst, sizeof(union sockaddr_union))) + break; + } - if (esph) - { - crda = crp->crp_desc; - crde = crda->crd_next; + /* Get crypto descriptors */ + crp = crypto_getreq(esph && espx ? 2 : 1); + if (crp == NULL) + { + m_freem(m); + DPRINTF(("esp_input(): failed to acquire crypto descriptors\n")); + espstat.esps_crypto++; + return ENOBUFS; + } - /* Authentication descriptor */ - crda->crd_skip = skip; - crda->crd_len = m->m_pkthdr.len - (skip + alen); - crda->crd_inject = m->m_pkthdr.len - alen; + /* Get IPsec-specific opaque pointer */ + if (esph == NULL || mtag != NULL) + MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto), + M_XDATA, M_NOWAIT); + else + MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto) + alen, + M_XDATA, M_NOWAIT); + if (tc == NULL) + { + m_freem(m); + crypto_freereq(crp); + DPRINTF(("esp_input(): failed to allocate tdb_crypto\n")); + espstat.esps_crypto++; + return ENOBUFS; + } - crda->crd_alg = esph->type; - crda->crd_key = tdb->tdb_amxkey; - crda->crd_klen = tdb->tdb_amxkeylen * 8; + bzero(tc, sizeof(struct tdb_crypto)); + tc->tc_ptr = (caddr_t) mtag; - /* Copy the authenticator */ - if (mtag == NULL) - m_copydata(m, m->m_pkthdr.len - alen, alen, (caddr_t) (tc + 1)); - } - else - crde = crp->crp_desc; - - /* Crypto operation descriptor */ - crp->crp_ilen = m->m_pkthdr.len; /* Total input length */ - crp->crp_flags = CRYPTO_F_IMBUF; - crp->crp_buf = (caddr_t) m; - crp->crp_callback = (int (*) (struct cryptop *)) esp_input_cb; - crp->crp_sid = tdb->tdb_cryptoid; - crp->crp_opaque = (caddr_t) tc; - - /* These are passed as-is to the callback */ - tc->tc_skip = skip; - tc->tc_protoff = protoff; - tc->tc_spi = tdb->tdb_spi; - tc->tc_proto = tdb->tdb_sproto; - bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union)); - - /* Decryption descriptor */ - if (espx) - { - crde->crd_skip = skip + hlen; - crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen); - crde->crd_inject = skip + hlen - tdb->tdb_ivlen; - - if (tdb->tdb_flags & TDBF_HALFIV) + if (esph) { - /* Copy half-IV from packet */ - m_copydata(m, crde->crd_inject, tdb->tdb_ivlen, crde->crd_iv); + crda = crp->crp_desc; + crde = crda->crd_next; - /* Cook IV */ - for (btsx = 0; btsx < tdb->tdb_ivlen; btsx++) - crde->crd_iv[tdb->tdb_ivlen + btsx] = ~crde->crd_iv[btsx]; + /* Authentication descriptor */ + crda->crd_skip = skip; + crda->crd_len = m->m_pkthdr.len - (skip + alen); + crda->crd_inject = m->m_pkthdr.len - alen; - crde->crd_flags |= CRD_F_IV_EXPLICIT; - } + crda->crd_alg = esph->type; + crda->crd_key = tdb->tdb_amxkey; + crda->crd_klen = tdb->tdb_amxkeylen * 8; - crde->crd_alg = espx->type; - crde->crd_key = tdb->tdb_emxkey; - crde->crd_klen = tdb->tdb_emxkeylen * 8; - /* XXX Rounds ? */ - } + /* Copy the authenticator */ + if (mtag == NULL) + m_copydata(m, m->m_pkthdr.len - alen, alen, (caddr_t) (tc + 1)); + } + else + crde = crp->crp_desc; + + /* Crypto operation descriptor */ + crp->crp_ilen = m->m_pkthdr.len; /* Total input length */ + crp->crp_flags = CRYPTO_F_IMBUF; + crp->crp_buf = (caddr_t) m; + crp->crp_callback = (int (*) (struct cryptop *)) esp_input_cb; + crp->crp_sid = tdb->tdb_cryptoid; + crp->crp_opaque = (caddr_t) tc; + + /* These are passed as-is to the callback */ + tc->tc_skip = skip; + tc->tc_protoff = protoff; + tc->tc_spi = tdb->tdb_spi; + tc->tc_proto = tdb->tdb_sproto; + bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union)); + + /* Decryption descriptor */ + if (espx) + { + crde->crd_skip = skip + hlen; + crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen); + crde->crd_inject = skip + hlen - tdb->tdb_ivlen; + + if (tdb->tdb_flags & TDBF_HALFIV) + { + /* Copy half-IV from packet */ + m_copydata(m, crde->crd_inject, tdb->tdb_ivlen, crde->crd_iv); + + /* Cook IV */ + for (btsx = 0; btsx < tdb->tdb_ivlen; btsx++) + crde->crd_iv[tdb->tdb_ivlen + btsx] = ~crde->crd_iv[btsx]; + + crde->crd_flags |= CRD_F_IV_EXPLICIT; + } + + crde->crd_alg = espx->type; + crde->crd_key = tdb->tdb_emxkey; + crde->crd_klen = tdb->tdb_emxkeylen * 8; + /* XXX Rounds ? */ + } - if (mtag == NULL) - return crypto_dispatch(crp); - else - return esp_input_cb(crp); + if (mtag == NULL) + return crypto_dispatch(crp); + else + return esp_input_cb(crp); } /* @@ -470,216 +470,216 @@ esp_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) int esp_input_cb(void *op) { - u_int8_t lastthree[3], aalg[AH_HMAC_HASHLEN]; - int hlen, roff, skip, protoff, error; - struct mbuf *m1, *mo, *m; - struct cryptodesc *crd; - struct auth_hash *esph; - struct enc_xform *espx; - struct tdb_crypto *tc; - struct cryptop *crp; - struct m_tag *mtag; - struct tdb *tdb; - int s, err = 0; - caddr_t ptr; - - crp = (struct cryptop *) op; - crd = crp->crp_desc; - - tc = (struct tdb_crypto *) crp->crp_opaque; - skip = tc->tc_skip; - protoff = tc->tc_protoff; - mtag = (struct m_tag *) tc->tc_ptr; - m = (struct mbuf *) crp->crp_buf; - - s = spltdb(); - - tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto); - FREE(tc, M_XDATA); - if (tdb == NULL) - { - espstat.esps_notdb++; - DPRINTF(("esp_input_cb(): TDB is expired while in crypto")); - goto baddone; - } - - esph = (struct auth_hash *) tdb->tdb_authalgxform; - espx = (struct enc_xform *) tdb->tdb_encalgxform; - - /* Check for crypto errors */ - if (crp->crp_etype) - { - /* Reset the session ID */ - if (tdb->tdb_cryptoid != 0) - tdb->tdb_cryptoid = crp->crp_sid; - - if (crp->crp_etype == EAGAIN) - { - splx(s); - return crypto_dispatch(crp); - } - - espstat.esps_noxform++; - DPRINTF(("esp_input_cb(): crypto error %d\n", crp->crp_etype)); - error = crp->crp_etype; - goto baddone; - } - - /* Shouldn't happen... */ - if (m == NULL) - { - espstat.esps_crypto++; - DPRINTF(("esp_input_cb(): bogus returned buffer from crypto\n")); - error = EINVAL; - goto baddone; - } - - /* If authentication was performed, check now. */ - if (esph != NULL) - { - /* - * If we have a tag, it means an IPsec-aware NIC did the verification - * for us. - */ - if (mtag != NULL) + u_int8_t lastthree[3], aalg[AH_HMAC_HASHLEN]; + int hlen, roff, skip, protoff, error; + struct mbuf *m1, *mo, *m; + struct cryptodesc *crd; + struct auth_hash *esph; + struct enc_xform *espx; + struct tdb_crypto *tc; + struct cryptop *crp; + struct m_tag *mtag; + struct tdb *tdb; + int s, err = 0; + caddr_t ptr; + + crp = (struct cryptop *) op; + crd = crp->crp_desc; + + tc = (struct tdb_crypto *) crp->crp_opaque; + skip = tc->tc_skip; + protoff = tc->tc_protoff; + mtag = (struct m_tag *) tc->tc_ptr; + m = (struct mbuf *) crp->crp_buf; + + s = spltdb(); + + tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto); + FREE(tc, M_XDATA); + if (tdb == NULL) + { + espstat.esps_notdb++; + DPRINTF(("esp_input_cb(): TDB is expired while in crypto")); + goto baddone; + } + + esph = (struct auth_hash *) tdb->tdb_authalgxform; + espx = (struct enc_xform *) tdb->tdb_encalgxform; + + /* Check for crypto errors */ + if (crp->crp_etype) + { + /* Reset the session ID */ + if (tdb->tdb_cryptoid != 0) + tdb->tdb_cryptoid = crp->crp_sid; + + if (crp->crp_etype == EAGAIN) + { + splx(s); + return crypto_dispatch(crp); + } + + espstat.esps_noxform++; + DPRINTF(("esp_input_cb(): crypto error %d\n", crp->crp_etype)); + error = crp->crp_etype; + goto baddone; + } + + /* Shouldn't happen... */ + if (m == NULL) { - /* Copy the authenticator from the packet */ - m_copydata(m, m->m_pkthdr.len - esph->authsize, esph->authsize, - aalg); - - ptr = (caddr_t) (tc + 1); - - /* Verify authenticator */ - if (bcmp(ptr, aalg, esph->authsize)) - { - DPRINTF(("esp_input_cb(): authentication failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - espstat.esps_badauth++; - error = EACCES; + espstat.esps_crypto++; + DPRINTF(("esp_input_cb(): bogus returned buffer from crypto\n")); + error = EINVAL; goto baddone; - } } - /* Remove trailing authenticator */ - m_adj(m, -(esph->authsize)); - } - - /* Release the crypto descriptors */ - crypto_freereq(crp); - - /* Determine the ESP header length */ - if (tdb->tdb_flags & TDBF_NOREPLAY) - hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; /* "old" ESP */ - else - hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; /* "new" ESP */ - - /* Find beginning of ESP header */ - m1 = m_getptr(m, skip, &roff); - if (m1 == NULL) - { - espstat.esps_hdrops++; - splx(s); - DPRINTF(("esp_input_cb(): bad mbuf chain, SA %s/%08x\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - return EINVAL; - } - - /* Remove the ESP header and IV from the mbuf. */ - if (roff == 0) - { - /* The ESP header was conveniently at the beginning of the mbuf */ - m_adj(m1, hlen); - if (!(m1->m_flags & M_PKTHDR)) - m->m_pkthdr.len -= hlen; - } - else - if (roff + hlen >= m1->m_len) - { - /* - * Part or all of the ESP header is at the end of this mbuf, so - * first let's remove the remainder of the ESP header from the - * beginning of the remainder of the mbuf chain, if any. - */ - if (roff + hlen > m1->m_len) - { - /* Adjust the next mbuf by the remainder */ - m_adj(m1->m_next, roff + hlen - m1->m_len); - - /* The second mbuf is guaranteed not to have a pkthdr... */ - m->m_pkthdr.len -= (roff + hlen - m1->m_len); - } - - /* Now, let's unlink the mbuf chain for a second...*/ - mo = m1->m_next; - m1->m_next = NULL; - - /* ...and trim the end of the first part of the chain...sick */ - m_adj(m1, -(m1->m_len - roff)); - if (!(m1->m_flags & M_PKTHDR)) - m->m_pkthdr.len -= (m1->m_len - roff); - - /* Finally, let's relink */ - m1->m_next = mo; - } - else - { - /* - * The ESP header lies in the "middle" of the mbuf...do an - * overlapping copy of the remainder of the mbuf over the ESP - * header. - */ - bcopy(mtod(m1, u_char *) + roff + hlen, mtod(m1, u_char *) + roff, - m1->m_len - (roff + hlen)); - m1->m_len -= hlen; - m->m_pkthdr.len -= hlen; - } - - /* Save the last three bytes of decrypted data */ - m_copydata(m, m->m_pkthdr.len - 3, 3, lastthree); - - /* Verify pad length */ - if (lastthree[1] + 2 > m->m_pkthdr.len - skip) - { - espstat.esps_badilen++; - splx(s); - DPRINTF(("esp_input_cb(): invalid padding length %d for packet in SA %s/%08x\n", lastthree[1], ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - return EINVAL; - } - - /* Verify correct decryption by checking the last padding bytes */ - if (!(tdb->tdb_flags & TDBF_RANDOMPADDING)) - { - if ((lastthree[1] != lastthree[0]) && (lastthree[1] != 0)) + /* If authentication was performed, check now. */ + if (esph != NULL) + { + /* + * If we have a tag, it means an IPsec-aware NIC did the verification + * for us. + */ + if (mtag != NULL) + { + /* Copy the authenticator from the packet */ + m_copydata(m, m->m_pkthdr.len - esph->authsize, esph->authsize, + aalg); + + ptr = (caddr_t) (tc + 1); + + /* Verify authenticator */ + if (bcmp(ptr, aalg, esph->authsize)) + { + DPRINTF(("esp_input_cb(): authentication failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_badauth++; + error = EACCES; + goto baddone; + } + } + + /* Remove trailing authenticator */ + m_adj(m, -(esph->authsize)); + } + + /* Release the crypto descriptors */ + crypto_freereq(crp); + + /* Determine the ESP header length */ + if (tdb->tdb_flags & TDBF_NOREPLAY) + hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; /* "old" ESP */ + else + hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; /* "new" ESP */ + + /* Find beginning of ESP header */ + m1 = m_getptr(m, skip, &roff); + if (m1 == NULL) + { + espstat.esps_hdrops++; + splx(s); + DPRINTF(("esp_input_cb(): bad mbuf chain, SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + return EINVAL; + } + + /* Remove the ESP header and IV from the mbuf. */ + if (roff == 0) + { + /* The ESP header was conveniently at the beginning of the mbuf */ + m_adj(m1, hlen); + if (!(m1->m_flags & M_PKTHDR)) + m->m_pkthdr.len -= hlen; + } + else + if (roff + hlen >= m1->m_len) + { + /* + * Part or all of the ESP header is at the end of this mbuf, so + * first let's remove the remainder of the ESP header from the + * beginning of the remainder of the mbuf chain, if any. + */ + if (roff + hlen > m1->m_len) + { + /* Adjust the next mbuf by the remainder */ + m_adj(m1->m_next, roff + hlen - m1->m_len); + + /* The second mbuf is guaranteed not to have a pkthdr... */ + m->m_pkthdr.len -= (roff + hlen - m1->m_len); + } + + /* Now, let's unlink the mbuf chain for a second...*/ + mo = m1->m_next; + m1->m_next = NULL; + + /* ...and trim the end of the first part of the chain...sick */ + m_adj(m1, -(m1->m_len - roff)); + if (!(m1->m_flags & M_PKTHDR)) + m->m_pkthdr.len -= (m1->m_len - roff); + + /* Finally, let's relink */ + m1->m_next = mo; + } + else + { + /* + * The ESP header lies in the "middle" of the mbuf...do an + * overlapping copy of the remainder of the mbuf over the ESP + * header. + */ + bcopy(mtod(m1, u_char *) + roff + hlen, mtod(m1, u_char *) + roff, + m1->m_len - (roff + hlen)); + m1->m_len -= hlen; + m->m_pkthdr.len -= hlen; + } + + /* Save the last three bytes of decrypted data */ + m_copydata(m, m->m_pkthdr.len - 3, 3, lastthree); + + /* Verify pad length */ + if (lastthree[1] + 2 > m->m_pkthdr.len - skip) + { + espstat.esps_badilen++; + splx(s); + DPRINTF(("esp_input_cb(): invalid padding length %d for packet in SA %s/%08x\n", lastthree[1], ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + return EINVAL; + } + + /* Verify correct decryption by checking the last padding bytes */ + if (!(tdb->tdb_flags & TDBF_RANDOMPADDING)) { - espstat.esps_badenc++; - splx(s); - DPRINTF(("esp_input(): decryption failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - return EINVAL; + if ((lastthree[1] != lastthree[0]) && (lastthree[1] != 0)) + { + espstat.esps_badenc++; + splx(s); + DPRINTF(("esp_input(): decryption failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + return EINVAL; + } } - } - /* Trim the mbuf chain to remove the trailing authenticator and padding */ - m_adj(m, -(lastthree[1] + 2)); + /* Trim the mbuf chain to remove the trailing authenticator and padding */ + m_adj(m, -(lastthree[1] + 2)); - /* Restore the Next Protocol field */ - m_copyback(m, protoff, sizeof(u_int8_t), lastthree + 2); + /* Restore the Next Protocol field */ + m_copyback(m, protoff, sizeof(u_int8_t), lastthree + 2); - /* Back to generic IPsec input processing */ - err = ipsec_common_input_cb(m, tdb, skip, protoff, mtag); - splx(s); - return err; + /* Back to generic IPsec input processing */ + err = ipsec_common_input_cb(m, tdb, skip, protoff, mtag); + splx(s); + return err; baddone: - splx(s); + splx(s); - if (m) - m_freem(m); + if (m != NULL) + m_freem(m); - crypto_freereq(crp); + crypto_freereq(crp); - return error; + return error; } /* @@ -687,302 +687,296 @@ esp_input_cb(void *op) */ int esp_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip, - int protoff) + int protoff) { - struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform; - struct auth_hash *esph = (struct auth_hash *) tdb->tdb_authalgxform; - int ilen, hlen, rlen, plen, padding, blks, alen; - struct mbuf *mi, *mo = (struct mbuf *) NULL; - struct tdb_crypto *tc; - unsigned char *pad; - u_int8_t prot; + struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform; + struct auth_hash *esph = (struct auth_hash *) tdb->tdb_authalgxform; + int ilen, hlen, rlen, plen, padding, blks, alen; + struct mbuf *mi, *mo = (struct mbuf *) NULL; + struct tdb_crypto *tc; + unsigned char *pad; + u_int8_t prot; - struct cryptodesc *crde = NULL, *crda = NULL; - struct cryptop *crp; + struct cryptodesc *crde = NULL, *crda = NULL; + struct cryptop *crp; #if NBPFILTER > 0 - { - struct ifnet *ifn; - struct enchdr hdr; - struct mbuf m1; + { + struct ifnet *ifn; + struct enchdr hdr; + struct mbuf m1; - bzero (&hdr, sizeof(hdr)); + bzero (&hdr, sizeof(hdr)); - hdr.af = tdb->tdb_dst.sa.sa_family; - hdr.spi = tdb->tdb_spi; - if (espx) - hdr.flags |= M_CONF; - if (esph) - hdr.flags |= M_AUTH; + hdr.af = tdb->tdb_dst.sa.sa_family; + hdr.spi = tdb->tdb_spi; + if (espx) + hdr.flags |= M_CONF; + if (esph) + hdr.flags |= M_AUTH; - m1.m_next = m; - m1.m_len = ENC_HDRLEN; - m1.m_data = (char *) &hdr; + m1.m_next = m; + m1.m_len = ENC_HDRLEN; + m1.m_data = (char *) &hdr; - ifn = &(encif[0].sc_if); + ifn = &(encif[0].sc_if); - if (ifn->if_bpf) - bpf_mtap(ifn->if_bpf, &m1); - } + if (ifn->if_bpf) + bpf_mtap(ifn->if_bpf, &m1); + } #endif - if (tdb->tdb_flags & TDBF_NOREPLAY) - hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; - else - hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; - - rlen = m->m_pkthdr.len - skip; /* Raw payload length */ - if (espx) - blks = espx->blocksize; - else - blks = 4; /* If no encryption is used, we have to be 4-byte aligned */ - - padding = ((blks - ((rlen + 2) % blks)) % blks) + 2; - plen = rlen + padding; /* Padded payload length */ - - if (esph) - alen = AH_HMAC_HASHLEN; - else - alen = 0; - - espstat.esps_output++; - - /* Check for replay counter wrap-around in automatic (not manual) keying */ - if ((!(tdb->tdb_flags & TDBF_NOREPLAY)) && - (tdb->tdb_rpl == 0) && (tdb->tdb_wnd > 0)) - { - DPRINTF(("esp_output(): SA %s/%08x should have expired\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - espstat.esps_wrap++; - return EACCES; - } - - switch (tdb->tdb_dst.sa.sa_family) - { + if (tdb->tdb_flags & TDBF_NOREPLAY) + hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; + else + hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; + + rlen = m->m_pkthdr.len - skip; /* Raw payload length. */ + if (espx) + blks = espx->blocksize; + else + blks = 4; /* If no encryption, we have to be 4-byte aligned. */ + + padding = ((blks - ((rlen + 2) % blks)) % blks) + 2; + plen = rlen + padding; /* Padded payload length. */ + + if (esph) + alen = AH_HMAC_HASHLEN; + else + alen = 0; + + espstat.esps_output++; + + /* + * Check for replay counter wrap-around in automatic (not + * manual) keying. + */ + if ((!(tdb->tdb_flags & TDBF_NOREPLAY)) && + (tdb->tdb_rpl == 0) && (tdb->tdb_wnd > 0)) { + DPRINTF(("esp_output(): SA %s/%08x should have expired\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + espstat.esps_wrap++; + return EACCES; + } + + switch (tdb->tdb_dst.sa.sa_family) { #ifdef INET case AF_INET: - /* Check for IP maximum packet size violations */ - if (skip + hlen + rlen + padding + alen > IP_MAXPACKET) - { - DPRINTF(("esp_output(): packet in SA %s/%08x got too big\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - espstat.esps_toobig++; - return EMSGSIZE; - } - break; + /* Check for IP maximum packet size violations. */ + if (skip + hlen + rlen + padding + alen > IP_MAXPACKET) { + DPRINTF(("esp_output(): packet in SA %s/%08x got " + "too big\n", ipsp_address(tdb->tdb_dst), + ntohl(tdb->tdb_spi))); + m_freem(m); + espstat.esps_toobig++; + return EMSGSIZE; + } + break; #endif /* INET */ #ifdef INET6 case AF_INET6: - /* Check for IPv6 maximum packet size violations */ - if (skip + hlen + rlen + padding + alen > IPV6_MAXPACKET) - { - DPRINTF(("esp_output(): packet in SA %s/%08x got too big\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - espstat.esps_toobig++; - return EMSGSIZE; - } - break; + /* Check for IPv6 maximum packet size violations. */ + if (skip + hlen + rlen + padding + alen > IPV6_MAXPACKET) { + DPRINTF(("esp_output(): packet in SA %s/%08x got too " + "big\n", ipsp_address(tdb->tdb_dst), + ntohl(tdb->tdb_spi))); + m_freem(m); + espstat.esps_toobig++; + return EMSGSIZE; + } + break; #endif /* INET6 */ default: - DPRINTF(("esp_output(): unknown/unsupported protocol family %d, SA %s/%08x\n", tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - espstat.esps_nopf++; - return EPFNOSUPPORT; - } - - /* Update the counters */ - tdb->tdb_cur_bytes += m->m_pkthdr.len - skip; - espstat.esps_obytes += m->m_pkthdr.len - skip; - - /* Hard byte expiration */ - if ((tdb->tdb_flags & TDBF_BYTES) && - (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) - { - pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); - tdb_delete(tdb); - m_freem(m); - return EINVAL; - } - - /* Soft byte expiration */ - if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && - (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) - { - pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ - } - - /* - * Loop through mbuf chain; if we find an M_EXT mbuf with - * more than one reference, replace the rest of the chain. - */ - mi = m; - while (mi != NULL && - (!(mi->m_flags & M_EXT) || !MCLISREFERENCED(mi))) - { - mo = mi; - mi = mi->m_next; - } - - if (mi != NULL) - { - /* Replace the rest of the mbuf chain. */ - struct mbuf *n = m_copym2(mi, 0, M_COPYALL, M_DONTWAIT); - - if (n == NULL) - { - DPRINTF(("esp_output(): bad mbuf chain, SA %s/%08x\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - espstat.esps_hdrops++; - m_freem(m); - return ENOBUFS; - } - - if (mo != NULL) - mo->m_next = n; - else - m = n; - - m_freem(mi); - } - - /* Inject ESP header */ - mo = m_inject(m, skip, hlen, M_DONTWAIT); - if (mo == NULL) - { - DPRINTF(("esp_output(): failed to inject ESP header for SA %s/%08x\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - espstat.esps_wrap++; - return ENOBUFS; - } - - /* Initialize ESP header */ - bcopy((caddr_t) &tdb->tdb_spi, mtod(mo, caddr_t), sizeof(u_int32_t)); - if (!(tdb->tdb_flags & TDBF_NOREPLAY)) - { - u_int32_t replay = htonl(tdb->tdb_rpl++); - bcopy((caddr_t) &replay, mtod(mo, caddr_t) + sizeof(u_int32_t), - sizeof(u_int32_t)); - } - - /* - * Add padding -- better to do it ourselves than use the crypto engine, - * although if/when we support compression, we'd have to do that. - */ - pad = (u_char *) m_pad(m, padding + alen); - if (pad == NULL) - { - DPRINTF(("esp_output(): m_pad() failed for SA %s/%08x\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - return ENOBUFS; - } - - /* Self-describing padding ? */ - if (!(tdb->tdb_flags & TDBF_RANDOMPADDING)) - for (ilen = 0; ilen < padding - 2; ilen++) - pad[ilen] = ilen + 1; - else - get_random_bytes((void *) pad, padding - 2); /* Random padding */ - - /* Fix padding length and Next Protocol in padding itself */ - pad[padding - 2] = padding - 2; - m_copydata(m, protoff, sizeof(u_int8_t), pad + padding - 1); - - /* Fix Next Protocol in IPv4/IPv6 header */ - prot = IPPROTO_ESP; - m_copyback(m, protoff, sizeof(u_int8_t), (u_char *) &prot); - - /* Get crypto descriptors */ - crp = crypto_getreq(esph && espx ? 2 : 1); - if (crp == NULL) - { - m_freem(m); - DPRINTF(("esp_output(): failed to acquire crypto descriptors\n")); - espstat.esps_crypto++; - return ENOBUFS; - } - - if (espx) - { - crde = crp->crp_desc; - crda = crde->crd_next; - - /* Encryption descriptor */ - crde->crd_skip = skip + hlen; - crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen); - crde->crd_flags = CRD_F_ENCRYPT; - crde->crd_inject = skip + hlen - tdb->tdb_ivlen; + DPRINTF(("esp_output(): unknown/unsupported protocol " + "family %d, SA %s/%08x\n", tdb->tdb_dst.sa.sa_family + , ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + espstat.esps_nopf++; + return EPFNOSUPPORT; + } - if (tdb->tdb_flags & TDBF_HALFIV) - { - /* Copy half-iv in the packet */ - m_copyback(m, crde->crd_inject, tdb->tdb_ivlen, tdb->tdb_iv); + /* Update the counters. */ + tdb->tdb_cur_bytes += m->m_pkthdr.len - skip; + espstat.esps_obytes += m->m_pkthdr.len - skip; - /* Cook half-iv */ - bcopy(tdb->tdb_iv, crde->crd_iv, tdb->tdb_ivlen); - for (ilen = 0; ilen < tdb->tdb_ivlen; ilen++) - crde->crd_iv[tdb->tdb_ivlen + ilen] = ~crde->crd_iv[ilen]; + /* Hard byte expiration. */ + if (tdb->tdb_flags & TDBF_BYTES && + tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes) { + pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); + tdb_delete(tdb); + m_freem(m); + return EINVAL; + } - crde->crd_flags |= CRD_F_IV_PRESENT | CRD_F_IV_EXPLICIT; + /* Soft byte expiration. */ + if (tdb->tdb_flags & TDBF_SOFT_BYTES && + tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes) { + pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking. */ } - /* Encryption operation */ - crde->crd_alg = espx->type; - crde->crd_key = tdb->tdb_emxkey; - crde->crd_klen = tdb->tdb_emxkeylen * 8; - /* XXX Rounds ? */ - } - else - crda = crp->crp_desc; - - /* IPsec-specific opaque crypto info */ - MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto), - M_XDATA, M_NOWAIT); - if (tc == NULL) - { - m_freem(m); - crypto_freereq(crp); - DPRINTF(("esp_output(): failed to allocate tdb_crypto\n")); - espstat.esps_crypto++; - return ENOBUFS; - } - - bzero(tc, sizeof(struct tdb_crypto)); - tc->tc_spi = tdb->tdb_spi; - tc->tc_proto = tdb->tdb_sproto; - bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union)); - - /* Crypto operation descriptor */ - crp->crp_ilen = m->m_pkthdr.len; /* Total input length */ - crp->crp_flags = CRYPTO_F_IMBUF; - crp->crp_buf = (caddr_t) m; - crp->crp_callback = (int (*) (struct cryptop *)) esp_output_cb; - crp->crp_opaque = (caddr_t) tc; - crp->crp_sid = tdb->tdb_cryptoid; - - if (esph) - { - /* Authentication descriptor */ - crda->crd_skip = skip; - crda->crd_len = m->m_pkthdr.len - (skip + alen); - crda->crd_inject = m->m_pkthdr.len - alen; - - /* Authentication operation */ - crda->crd_alg = esph->type; - crda->crd_key = tdb->tdb_amxkey; - crda->crd_klen = tdb->tdb_amxkeylen * 8; - } - - if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) - return crypto_dispatch(crp); - else - return esp_output_cb(crp); + /* + * Loop through mbuf chain; if we find an M_EXT mbuf with + * more than one reference, replace the rest of the chain. + */ + mi = m; + while (mi != NULL && + (!(mi->m_flags & M_EXT) || !MCLISREFERENCED(mi))) { + mo = mi; + mi = mi->m_next; + } + + if (mi != NULL) { + /* Replace the rest of the mbuf chain. */ + struct mbuf *n = m_copym2(mi, 0, M_COPYALL, M_DONTWAIT); + + if (n == NULL) { + DPRINTF(("esp_output(): bad mbuf chain, SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_hdrops++; + m_freem(m); + return ENOBUFS; + } + + if (mo != NULL) + mo->m_next = n; + else + m = n; + + m_freem(mi); + } + + /* Inject ESP header. */ + mo = m_inject(m, skip, hlen, M_DONTWAIT); + if (mo == NULL) { + DPRINTF(("esp_output(): failed to inject ESP header for " + "SA %s/%08x\n", ipsp_address(tdb->tdb_dst), + ntohl(tdb->tdb_spi))); + m_freem(m); + espstat.esps_wrap++; + return ENOBUFS; + } + + /* Initialize ESP header. */ + bcopy((caddr_t) &tdb->tdb_spi, mtod(mo, caddr_t), sizeof(u_int32_t)); + if (!(tdb->tdb_flags & TDBF_NOREPLAY)) { + u_int32_t replay = htonl(tdb->tdb_rpl++); + bcopy((caddr_t) &replay, mtod(mo, caddr_t) + sizeof(u_int32_t), + sizeof(u_int32_t)); + } + + /* + * Add padding -- better to do it ourselves than use the crypto engine, + * although if/when we support compression, we'd have to do that. + */ + pad = (u_char *) m_pad(m, padding + alen); + if (pad == NULL) { + DPRINTF(("esp_output(): m_pad() failed for SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + return ENOBUFS; + } + + /* Self-describing or random padding ? */ + if (!(tdb->tdb_flags & TDBF_RANDOMPADDING)) + for (ilen = 0; ilen < padding - 2; ilen++) + pad[ilen] = ilen + 1; + else + get_random_bytes((void *) pad, padding - 2); + + /* Fix padding length and Next Protocol in padding itself. */ + pad[padding - 2] = padding - 2; + m_copydata(m, protoff, sizeof(u_int8_t), pad + padding - 1); + + /* Fix Next Protocol in IPv4/IPv6 header. */ + prot = IPPROTO_ESP; + m_copyback(m, protoff, sizeof(u_int8_t), (u_char *) &prot); + + /* Get crypto descriptors. */ + crp = crypto_getreq(esph && espx ? 2 : 1); + if (crp == NULL) { + m_freem(m); + DPRINTF(("esp_output(): failed to acquire crypto " + "descriptors\n")); + espstat.esps_crypto++; + return ENOBUFS; + } + + if (espx) { + crde = crp->crp_desc; + crda = crde->crd_next; + + /* Encryption descriptor. */ + crde->crd_skip = skip + hlen; + crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen); + crde->crd_flags = CRD_F_ENCRYPT; + crde->crd_inject = skip + hlen - tdb->tdb_ivlen; + + if (tdb->tdb_flags & TDBF_HALFIV) { + /* Copy half-iv in the packet. */ + m_copyback(m, crde->crd_inject, tdb->tdb_ivlen, + tdb->tdb_iv); + + /* Cook half-iv. */ + bcopy(tdb->tdb_iv, crde->crd_iv, tdb->tdb_ivlen); + for (ilen = 0; ilen < tdb->tdb_ivlen; ilen++) + crde->crd_iv[tdb->tdb_ivlen + ilen] = + ~crde->crd_iv[ilen]; + + crde->crd_flags |= + CRD_F_IV_PRESENT | CRD_F_IV_EXPLICIT; + } + + /* Encryption operation. */ + crde->crd_alg = espx->type; + crde->crd_key = tdb->tdb_emxkey; + crde->crd_klen = tdb->tdb_emxkeylen * 8; + /* XXX Rounds ? */ + } else + crda = crp->crp_desc; + + /* IPsec-specific opaque crypto info. */ + MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto), + M_XDATA, M_NOWAIT); + if (tc == NULL) { + m_freem(m); + crypto_freereq(crp); + DPRINTF(("esp_output(): failed to allocate tdb_crypto\n")); + espstat.esps_crypto++; + return ENOBUFS; + } + + bzero(tc, sizeof(struct tdb_crypto)); + tc->tc_spi = tdb->tdb_spi; + tc->tc_proto = tdb->tdb_sproto; + bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union)); + + /* Crypto operation descriptor. */ + crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */ + crp->crp_flags = CRYPTO_F_IMBUF; + crp->crp_buf = (caddr_t) m; + crp->crp_callback = (int (*) (struct cryptop *)) esp_output_cb; + crp->crp_opaque = (caddr_t) tc; + crp->crp_sid = tdb->tdb_cryptoid; + + if (esph) { + /* Authentication descriptor. */ + crda->crd_skip = skip; + crda->crd_len = m->m_pkthdr.len - (skip + alen); + crda->crd_inject = m->m_pkthdr.len - alen; + + /* Authentication operation. */ + crda->crd_alg = esph->type; + crda->crd_key = tdb->tdb_amxkey; + crda->crd_klen = tdb->tdb_amxkeylen * 8; + } + + if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) + return crypto_dispatch(crp); + else + return esp_output_cb(crp); } /* @@ -991,81 +985,79 @@ esp_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip, int esp_output_cb(void *op) { - struct cryptop *crp = (struct cryptop *) op; - struct tdb_crypto *tc; - struct tdb *tdb; - struct mbuf *m; - int error, s; - - tc = (struct tdb_crypto *) crp->crp_opaque; - m = (struct mbuf *) crp->crp_buf; - - s = spltdb(); - - tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto); - - FREE(tc, M_XDATA); - if (tdb == NULL) - { - espstat.esps_notdb++; - DPRINTF(("esp_output_cb(): TDB is expired while in crypto\n")); - goto baddone; - } - - /* Check for crypto errors */ - if (crp->crp_etype) - { - /* Reset session ID */ - if (tdb->tdb_cryptoid != 0) - tdb->tdb_cryptoid = crp->crp_sid; - - if (crp->crp_etype == EAGAIN) - { - splx(s); - return crypto_dispatch(crp); - } - - espstat.esps_noxform++; - DPRINTF(("esp_output_cb(): crypto error %d\n", crp->crp_etype)); - error = crp->crp_etype; - goto baddone; - } - - /* Shouldn't happen... */ - if (m == NULL) - { - espstat.esps_crypto++; - DPRINTF(("esp_output_cb(): bogus returned buffer from crypto\n")); - error = EINVAL; - goto baddone; - } - - /* Release crypto descriptors */ - crypto_freereq(crp); - - /* - * If we're doing half-iv, keep a copy of the last few bytes of the - * encrypted part, for use as the next IV. Note that HALF-IV is only - * supposed to be used without authentication (the old ESP specs). - */ - if (tdb->tdb_flags & TDBF_HALFIV) - m_copydata(m, m->m_pkthdr.len - tdb->tdb_ivlen, tdb->tdb_ivlen, - tdb->tdb_iv); - - /* Call the IPsec input callback */ - error = ipsp_process_done(m, tdb); - splx(s); - return error; + struct cryptop *crp = (struct cryptop *) op; + struct tdb_crypto *tc; + struct tdb *tdb; + struct mbuf *m; + int error, s; + + tc = (struct tdb_crypto *) crp->crp_opaque; + m = (struct mbuf *) crp->crp_buf; + + s = spltdb(); + + tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto); + + FREE(tc, M_XDATA); + if (tdb == NULL) { + espstat.esps_notdb++; + DPRINTF(("esp_output_cb(): TDB is expired while in crypto\n")); + goto baddone; + } + + /* Check for crypto errors. */ + if (crp->crp_etype) { + /* Reset session ID. */ + if (tdb->tdb_cryptoid != 0) + tdb->tdb_cryptoid = crp->crp_sid; + + if (crp->crp_etype == EAGAIN) { + splx(s); + return crypto_dispatch(crp); + } + + espstat.esps_noxform++; + DPRINTF(("esp_output_cb(): crypto error %d\n", + crp->crp_etype)); + error = crp->crp_etype; + goto baddone; + } + + /* Shouldn't happen... */ + if (m == NULL) { + espstat.esps_crypto++; + DPRINTF(("esp_output_cb(): bogus returned buffer from " + "crypto\n")); + error = EINVAL; + goto baddone; + } + + /* Release crypto descriptors. */ + crypto_freereq(crp); + + /* + * If we're doing half-iv, keep a copy of the last few bytes of the + * encrypted part, for use as the next IV. Note that HALF-IV is only + * supposed to be used without authentication (the old ESP specs). + */ + if (tdb->tdb_flags & TDBF_HALFIV) + m_copydata(m, m->m_pkthdr.len - tdb->tdb_ivlen, tdb->tdb_ivlen, + tdb->tdb_iv); + + /* Call the IPsec input callback. */ + error = ipsp_process_done(m, tdb); + splx(s); + return error; baddone: - splx(s); + splx(s); - if (m) - m_freem(m); + if (m != NULL) + m_freem(m); - crypto_freereq(crp); + crypto_freereq(crp); - return error; + return error; } /* @@ -1076,41 +1068,38 @@ esp_output_cb(void *op) */ int checkreplaywindow32(u_int32_t seq, u_int32_t initial, u_int32_t *lastseq, - u_int32_t window, u_int32_t *bitmap) + u_int32_t window, u_int32_t *bitmap) { - u_int32_t diff; + u_int32_t diff; - seq -= initial; + seq -= initial; - if (seq == 0) - return 1; + if (seq == 0) + return 1; - if (seq > *lastseq - initial) - { - diff = seq - (*lastseq - initial); - if (diff < window) - *bitmap = ((*bitmap) << diff) | 1; - else - *bitmap = 1; - *lastseq = seq + initial; + if (seq > *lastseq - initial) { + diff = seq - (*lastseq - initial); + if (diff < window) + *bitmap = ((*bitmap) << diff) | 1; + else + *bitmap = 1; + *lastseq = seq + initial; + return 0; + } + + diff = *lastseq - initial - seq; + if (diff >= window) { + espstat.esps_wrap++; + return 2; + } + + if ((*bitmap) & (((u_int32_t) 1) << diff)) { + espstat.esps_replay++; + return 3; + } + + *bitmap |= (((u_int32_t) 1) << diff); return 0; - } - - diff = *lastseq - initial - seq; - if (diff >= window) - { - espstat.esps_wrap++; - return 2; - } - - if ((*bitmap) & (((u_int32_t) 1) << diff)) - { - espstat.esps_replay++; - return 3; - } - - *bitmap |= (((u_int32_t) 1) << diff); - return 0; } /* @@ -1122,71 +1111,65 @@ checkreplaywindow32(u_int32_t seq, u_int32_t initial, u_int32_t *lastseq, caddr_t m_pad(struct mbuf *m, int n) { - register struct mbuf *m0, *m1; - register int len, pad; - caddr_t retval; - - if (n <= 0) /* no stupid arguments */ - { - DPRINTF(("m_pad(): pad length invalid (%d)\n", n)); - return NULL; - } - - len = m->m_pkthdr.len; - pad = n; - - m0 = m; - - while (m0->m_len < len) - { - len -= m0->m_len; - m0 = m0->m_next; - } - - if (m0->m_len != len) - { - DPRINTF(("m_pad(): length mismatch (should be %d instead of %d)\n", - m->m_pkthdr.len, m->m_pkthdr.len + m0->m_len - len)); - m_freem(m); - return NULL; - } - - /* Check for zero-length trailing mbufs, and find the last one */ - for (m1 = m0; m1->m_next; m1 = m1->m_next) - { - if (m1->m_next->m_len != 0) - { - DPRINTF(("m_pad(): length mismatch (should be %d instead of %d)\n", - m->m_pkthdr.len, m->m_pkthdr.len + m1->m_next->m_len)); - m_freem(m); - return NULL; + register struct mbuf *m0, *m1; + register int len, pad; + caddr_t retval; + + if (n <= 0) { /* No stupid arguments. */ + DPRINTF(("m_pad(): pad length invalid (%d)\n", n)); + return NULL; } - m0 = m1->m_next; - } + len = m->m_pkthdr.len; + pad = n; + m0 = m; - if ((m0->m_flags & M_EXT) || - (m0->m_data + m0->m_len + pad >= &(m0->m_dat[MLEN]))) - { - /* - * Add an mbuf to the chain - */ - MGET(m1, M_DONTWAIT, MT_DATA); - if (m1 == 0) - { - m_freem(m0); - DPRINTF(("m_pad(): cannot append\n")); - return NULL; + while (m0->m_len < len) { + len -= m0->m_len; + m0 = m0->m_next; } - m0->m_next = m1; - m0 = m1; - m0->m_len = 0; - } + if (m0->m_len != len) { + DPRINTF(("m_pad(): length mismatch (should be %d instead of " + "%d)\n", m->m_pkthdr.len, + m->m_pkthdr.len + m0->m_len - len)); + + m_freem(m); + return NULL; + } + + /* Check for zero-length trailing mbufs, and find the last one. */ + for (m1 = m0; m1->m_next; m1 = m1->m_next) { + if (m1->m_next->m_len != 0) { + DPRINTF(("m_pad(): length mismatch (should be %d " + "instead of %d)\n", m->m_pkthdr.len, + m->m_pkthdr.len + m1->m_next->m_len)); + + m_freem(m); + return NULL; + } + + m0 = m1->m_next; + } + + if ((m0->m_flags & M_EXT) || + m0->m_data + m0->m_len + pad >= &(m0->m_dat[MLEN])) { + /* Add an mbuf to the chain. */ + MGET(m1, M_DONTWAIT, MT_DATA); + if (m1 == 0) { + m_freem(m0); + DPRINTF(("m_pad(): cannot append\n")); + return NULL; + } + + m0->m_next = m1; + m0 = m1; + m0->m_len = 0; + } - retval = m0->m_data + m0->m_len; - m0->m_len += pad; - m->m_pkthdr.len += pad; + retval = m0->m_data + m0->m_len; + m0->m_len += pad; + m->m_pkthdr.len += pad; - return retval; + return retval; } |