diff options
author | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 1999-12-07 08:58:01 +0000 |
---|---|---|
committer | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 1999-12-07 08:58:01 +0000 |
commit | 9ee72983c9413873178f66eeef808559910d3b00 (patch) | |
tree | db02351874ac2ce0ff39a336d2613177a7144626 | |
parent | 93a0c92573a551bbe49ca24721d08094be1b29c9 (diff) |
New ah_new_input(), protocol-independent processing (still lacking
IPv6-specific protocol header processing).
-rw-r--r-- | sys/netinet/ip_ah.c | 8 | ||||
-rw-r--r-- | sys/netinet/ip_ah.h | 5 | ||||
-rw-r--r-- | sys/netinet/ip_ah_new.c | 379 | ||||
-rw-r--r-- | sys/netinet/ip_esp.c | 9 |
4 files changed, 229 insertions, 172 deletions
diff --git a/sys/netinet/ip_ah.c b/sys/netinet/ip_ah.c index 07f18d3a323..30f87aa50d1 100644 --- a/sys/netinet/ip_ah.c +++ b/sys/netinet/ip_ah.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ah.c,v 1.29 1999/12/06 23:02:08 angelos Exp $ */ +/* $OpenBSD: ip_ah.c,v 1.30 1999/12/07 08:57:59 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -198,7 +198,6 @@ ah_input(m, va_alist) offsetof(struct ip, ip_p)); if (m == NULL) { - DPRINTF(("ah_input(): authentication failed for AH packet from %s to %s, spi %08x\n", inet_ntoa4(ipn.ip_src), ipsp_address(sunion), ntohl(ahn.ah_spi))); ahstat.ahs_badkcr++; return; } @@ -211,6 +210,8 @@ ah_input(m, va_alist) ipo = mtod(m, struct ip *); ipo->ip_len = htons(m->m_pkthdr.len); + HTONS(ipo->ip_id); + HTONS(ipo->ip_off); ipo->ip_sum = 0; ipo->ip_sum = in_cksum(m, ipo->ip_hl << 2); @@ -283,6 +284,8 @@ ah_input(m, va_alist) } else m->m_pkthdr.tdbi = NULL; + printf("here4\n"); + /* Packet is authentic */ m->m_flags |= M_AUTH; @@ -310,6 +313,7 @@ ah_input(m, va_alist) bpf_mtap(m->m_pkthdr.rcvif->if_bpf, &m0); } #endif + splx(s); /* diff --git a/sys/netinet/ip_ah.h b/sys/netinet/ip_ah.h index c08e18a9c58..e822d592c1d 100644 --- a/sys/netinet/ip_ah.h +++ b/sys/netinet/ip_ah.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ah.h,v 1.17 1999/10/29 02:10:01 angelos Exp $ */ +/* $OpenBSD: ip_ah.h,v 1.18 1999/12/07 08:57:59 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -83,6 +83,9 @@ struct ah_new #define AH_NEW_FLENGTH (sizeof(struct ah_new)) +/* Size of the largest hash function output used in AH-new, in bytes */ +#define AH_MAX_HASHLEN 20 + /* * Names for AH sysctl objects */ diff --git a/sys/netinet/ip_ah_new.c b/sys/netinet/ip_ah_new.c index 639dc7dbff4..22f01b7f91e 100644 --- a/sys/netinet/ip_ah_new.c +++ b/sys/netinet/ip_ah_new.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ah_new.c,v 1.29 1999/12/06 07:14:35 angelos Exp $ */ +/* $OpenBSD: ip_ah_new.c,v 1.30 1999/12/07 08:58:00 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -50,7 +50,6 @@ #include <sys/time.h> #include <sys/kernel.h> #include <sys/socketvar.h> - #include <machine/cpu.h> #include <machine/endian.h> @@ -62,10 +61,11 @@ #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> -#include <netinet/in_pcb.h> -#include <netinet/in_var.h> -#include <netinet/ip_var.h> -#include <netinet/ip_icmp.h> + +#ifdef INET6 +#include <netinet6/in6.h> +#include <netinet6/ip6.h> +#endif /* INET6 */ #include <netinet/ip_ipsp.h> #include <netinet/ip_ah.h> @@ -77,6 +77,10 @@ #define DPRINTF(x) #endif +#ifndef offsetof +#define offsetof(s, e) ((int)&((s *)0)->e) +#endif + extern struct auth_hash auth_hash_hmac_md5_96; extern struct auth_hash auth_hash_hmac_sha1_96; extern struct auth_hash auth_hash_hmac_ripemd_160_96; @@ -88,10 +92,8 @@ struct auth_hash *ah_new_hash[] = { }; /* - * ah_new_attach() is called from the transformation initialization code. - * It just returns. + * ah_new_attach() is called from the transformation initialization code */ - int ah_new_attach() { @@ -187,68 +189,71 @@ ah_new_zeroize(struct tdb *tdbp) /* * ah_new_input() gets called to verify that an input packet - * passes authentication. + * passes authentication */ struct mbuf * ah_new_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) { struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform; - struct ip *ip, ipo; - struct ah_new *aho, *ah; - int ohlen, len, count, off, errc; - u_int32_t btsx; - struct mbuf *m0; + unsigned char calcauth[AH_MAX_HASHLEN]; + int len, count, off, roff; + struct mbuf *m0, *m1; union authctx ctx; - u_int8_t optval; - u_char buffer[40]; - - aho = (struct ah_new *) buffer; - ohlen = sizeof(struct ip) + AH_NEW_FLENGTH; - - if (m->m_len < ohlen) - { - if ((m = m_pullup(m, ohlen)) == NULL) - { - ahstat.ahs_hdrops++; - DPRINTF(("ah_new_input(): (possibly too short) packet dropped\n")); - return NULL; - } - } + struct ah_new ah; + +#ifdef INET + unsigned char *ptr; + struct ip *ipo; +#endif /* INET */ - ip = mtod(m, struct ip *); + /* Save the AH header, we use it throughout */ + m_copydata(m, skip, sizeof(ah), (unsigned char *) &ah); - /* Adjust, if options are present */ - if ((ip->ip_hl << 2) > sizeof(struct ip)) + /* Replay window checking */ + if (tdb->tdb_wnd > 0) { - if ((m = m_pullup(m, ohlen - sizeof (struct ip) + - (ip->ip_hl << 2))) == NULL) + switch (checkreplaywindow32(ntohl(ah.ah_rpl), 0, &(tdb->tdb_rpl), + tdb->tdb_wnd, &(tdb->tdb_bitmap))) { - DPRINTF(("ah_new_input(): m_pullup() failed\n")); - ahstat.ahs_hdrops++; - return NULL; + case 0: /* All's well */ + break; + + case 1: + DPRINTF(("ah_new_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 NULL; + + case 2: + case 3: + DPRINTF(("ah_new_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 NULL; + + default: + DPRINTF(("ah_new_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 NULL; } - - ip = mtod(m, struct ip *); - ah = (struct ah_new *) ((u_int8_t *) ip + (ip->ip_hl << 2)); - ohlen += ((ip->ip_hl << 2) - sizeof(struct ip)); } - else - ah = (struct ah_new *) (ip + 1); - if (ah->ah_hl * sizeof(u_int32_t) != AH_HMAC_HASHLEN + AH_HMAC_RPLENGTH) + /* Verify AH header length */ + if (ah.ah_hl * sizeof(u_int32_t) != AH_HMAC_HASHLEN + AH_HMAC_RPLENGTH) { - DPRINTF(("ah_new_input(): bad authenticator length for packet from %s to %s, spi %08x\n", inet_ntoa4(ip->ip_src), inet_ntoa4(ip->ip_dst), ntohl(ah->ah_spi))); + DPRINTF(("ah_new_input(): bad authenticator length %d for packet in SA %s/%08x\n", ah.ah_hl * sizeof(u_int32_t), ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); ahstat.ahs_badauthl++; m_freem(m); return NULL; } /* Update the counters */ - tdb->tdb_cur_bytes += ip->ip_len - (ip->ip_hl << 2) - - ah->ah_hl * sizeof(u_int32_t); - ahstat.ahs_ibytes += ip->ip_len - (ip->ip_hl << 2) - - ah->ah_hl * sizeof(u_int32_t); + tdb->tdb_cur_bytes += (m->m_pkthdr.len - skip - + ah.ah_hl * sizeof(u_int32_t)); + ahstat.ahs_ibytes += (m->m_pkthdr.len - skip - + ah.ah_hl * sizeof(u_int32_t)); /* Hard expiration */ if ((tdb->tdb_flags & TDBF_BYTES) && @@ -268,115 +273,131 @@ ah_new_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ } - /* Replay window checking */ - if (tdb->tdb_wnd > 0) + bcopy(tdb->tdb_ictx, &ctx, ahx->ctxsize); + + switch (tdb->tdb_dst.sa.sa_family) { - btsx = ntohl(ah->ah_rpl); - if ((errc = checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl), tdb->tdb_wnd, - &(tdb->tdb_bitmap))) != 0) - { - switch(errc) +#ifdef INET + case AF_INET: + /* + * This is the most painless way of dealing with IPv4 header + * and option processing -- just make sure they're in + * contiguous memory. + */ + m = m_pullup(m, skip); + if (m == NULL) { - case 1: - DPRINTF(("ah_new_input(): replay counter wrapped for packets from %s to %s, spi %08x\n", inet_ntoa4(ip->ip_src), inet_ntoa4(ip->ip_dst), ntohl(ah->ah_spi))); - ahstat.ahs_wrap++; - break; - - case 2: - case 3: - DPRINTF(("ah_new_input(): duplicate packet received from %s to %s, spi %08x\n", inet_ntoa4(ip->ip_src), inet_ntoa4(ip->ip_dst), ntohl(ah->ah_spi))); - ahstat.ahs_replay++; - break; + DPRINTF(("ah_new_input(): m_pullup() failed, SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + ahstat.ahs_hdrops++; + return NULL; } - m_freem(m); - return NULL; - } - } - - ipo = *ip; - ipo.ip_tos = 0; - ipo.ip_len += (ip->ip_hl << 2); /* adjusted in ip_intr() */ - HTONS(ipo.ip_len); - HTONS(ipo.ip_id); - ipo.ip_off = 0; - ipo.ip_ttl = 0; - ipo.ip_sum = 0; - - bcopy(tdb->tdb_ictx, &ctx, ahx->ctxsize); - ahx->Update(&ctx, (unsigned char *) &ipo, sizeof(struct ip)); + ptr = mtod(m, unsigned char *); - /* Options */ - if ((ip->ip_hl << 2) > sizeof(struct ip)) - for (off = sizeof(struct ip); off < (ip->ip_hl << 2);) - { - optval = ((u_int8_t *) ip)[off]; - switch (optval) - { - case IPOPT_EOL: - ahx->Update(&ctx, ipseczeroes, 1); + ipo = (struct ip *) ptr; + ipo->ip_tos = 0; + ipo->ip_len += skip; /* adjusted in ip_intr() */ + HTONS(ipo->ip_len); + HTONS(ipo->ip_id); + ipo->ip_off = 0; + ipo->ip_ttl = 0; + ipo->ip_sum = 0; + ahx->Update(&ctx, ptr, sizeof(struct ip)); - off = ip->ip_hl << 2; - break; + /* IPv4 option processing */ + for (off = sizeof(struct ip); off < skip;) + { + switch (ptr[off]) + { + case IPOPT_EOL: + ahx->Update(&ctx, ptr + off, 1); + off = skip; /* End the loop */ + break; + + case IPOPT_NOP: + ahx->Update(&ctx, ptr + off, 1); + off++; + break; + + case IPOPT_SECURITY: /* 0x82 */ + case 0x85: /* Extended security */ + case 0x86: /* Commercial security */ + case 0x94: /* Router alert */ + case 0x95: /* RFC1770 */ + ahx->Update(&ctx, ptr + off, ptr[off + 1]); + off += ptr[off + 1]; + break; + + default: + ahx->Update(&ctx, ipseczeroes, ptr[off + 1]); + off += ptr[off + 1]; + break; + } + } - case IPOPT_NOP: - ahx->Update(&ctx, ipseczeroes, 1); + break; +#endif /* INET */ - off++; - break; +#ifdef INET6 + /* XXX */ +#endif /* INET6 */ - case IPOPT_SECURITY: - case 133: - case 134: - optval = ((u_int8_t *) ip)[off + 1]; + default: + DPRINTF(("ah_new_input(): unsupported protocol family %d in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + ahstat.ahs_hdrops++; + m_freem(m); + return NULL; + + } - ahx->Update(&ctx, (u_int8_t *) ip + off, optval); + /* Record the begining of the AH header */ + for (len = 0, m1 = m; m1 && (len + m1->m_len <= skip); m1 = m1->m_next) + len += m1->m_len; - off += optval; - break; + if (m1 == NULL) + { + DPRINTF(("ah_new_input(): bad mbuf chain for packet in SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + ahstat.ahs_hdrops++; + m_freem(m); + return NULL; + } + else + roff = skip - len; - default: - optval = ((u_int8_t *) ip)[off + 1]; + /* Skip the AH header */ + for (len = 0, m0 = m1; + m0 && (len + m0->m_len <= AH_NEW_FLENGTH + roff); + m0 = m0->m_next) + len += m0->m_len; - ahx->Update(&ctx, ipseczeroes, optval); + if (m0 == NULL) + { + DPRINTF(("ah_new_input(): bad mbuf chain for packet in SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + ahstat.ahs_hdrops++; + m_freem(m); + return NULL; + } + else + off = (AH_NEW_FLENGTH + roff) - len; - off += optval; - break; - } - } + /* Include the AH header (minus the authenticator) in the computation */ + ahx->Update(&ctx, (unsigned char *) &ah, AH_NEW_FLENGTH - AH_HMAC_HASHLEN); - ahx->Update(&ctx, (unsigned char *) ah, AH_NEW_FLENGTH - AH_HMAC_HASHLEN); + /* All-zeroes for the authenticator */ ahx->Update(&ctx, ipseczeroes, AH_HMAC_HASHLEN); - /* - * Code shamelessly stolen from m_copydata - */ - off = ohlen; - len = m->m_pkthdr.len - off; - m0 = m; - - while (off > 0) - { - if (m0 == 0) - { - DPRINTF(("ah_new_input(): bad mbuf chain for packet from %s to %s, spi %08x\n", inet_ntoa4(ip->ip_src), inet_ntoa4(ip->ip_dst), ntohl(ah->ah_spi))); - ahstat.ahs_hdrops++; - m_freem(m); - return NULL; - } - - if (off < m0->m_len) - break; - - off -= m0->m_len; - m0 = m0->m_next; - } + /* Amount of data to be verified */ + len = m->m_pkthdr.len - skip - AH_NEW_FLENGTH; + /* Loop through the mbuf chain computing the HMAC */ while (len > 0) { - if (m0 == 0) + if (m0 == NULL) { - DPRINTF(("ah_new_input(): bad mbuf chain for packet from %s to %s, spi %08x\n", inet_ntoa4(ip->ip_src), inet_ntoa4(ip->ip_dst), ntohl(ah->ah_spi))); + DPRINTF(("ah_new_input(): bad mbuf chain for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); ahstat.ahs_hdrops++; m_freem(m); return NULL; @@ -391,42 +412,76 @@ ah_new_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) m0 = m0->m_next; } - ahx->Final((unsigned char *) (aho->ah_data), &ctx); + /* Finish HMAC computation */ + ahx->Final(calcauth, &ctx); bcopy(tdb->tdb_octx, &ctx, ahx->ctxsize); - ahx->Update(&ctx, (unsigned char *) (aho->ah_data), ahx->hashsize); - ahx->Final((unsigned char *) (aho->ah_data), &ctx); + ahx->Update(&ctx, calcauth, ahx->hashsize); + ahx->Final(calcauth, &ctx); - if (bcmp(aho->ah_data, ah->ah_data, AH_HMAC_HASHLEN)) + /* Verify */ + if (bcmp(&(ah.ah_data), calcauth, AH_HMAC_HASHLEN)) { - DPRINTF(("ah_new_input(): authentication failed for packet from %s to %s, spi %08x\n", inet_ntoa4(ip->ip_src), inet_ntoa4(ip->ip_dst), ntohl(ah->ah_spi))); + DPRINTF(("ah_new_input(): authentication failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); ahstat.ahs_badauth++; m_freem(m); return NULL; } - - ipo = *ip; - ipo.ip_p = ah->ah_nh; - /* Save options */ - m_copydata(m, sizeof(struct ip), (ip->ip_hl << 2) - sizeof(struct ip), - (caddr_t) buffer); + /* Fix the Next Protocol field */ + m_copyback(m, protoff, 1, (u_char *) &(ah.ah_nh)); - m->m_len -= AH_NEW_FLENGTH; - m->m_data += AH_NEW_FLENGTH; - m->m_pkthdr.len -= AH_NEW_FLENGTH; + /* + * Remove the AH header from the mbuf. + */ + if (roff == 0) + { + /* The AH header was conveniently at the begining of the mbuf */ + m_adj(m1, AH_NEW_FLENGTH); + if (!(m1->m_flags & M_PKTHDR)) + m->m_pkthdr.len -= AH_NEW_FLENGTH; + } + else + if (roff + AH_NEW_FLENGTH >= 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 + * begining of the remainder of the mbuf chain, if any. + */ + if (roff + AH_NEW_FLENGTH > m1->m_len) + { + /* Adjust the next mbuf by the remainder */ + m_adj(m1->m_next, roff + AH_NEW_FLENGTH - m1->m_len); - ip = mtod(m, struct ip *); - *ip = ipo; - ip->ip_len = htons(ip->ip_len - AH_NEW_FLENGTH + (ip->ip_hl << 2)); - HTONS(ip->ip_id); - HTONS(ip->ip_off); - ip->ip_sum = 0; + /* The second mbuf is guaranteed not to have a pkthdr... */ + m->m_pkthdr.len -= (roff + AH_NEW_FLENGTH - m1->m_len); + } + + /* Now, let's unlink the mbuf chain for a second...*/ + m0 = m1->m_next; + m1->m_next = NULL; - /* Copy the options back */ - m_copyback(m, sizeof(struct ip), (ip->ip_hl << 2) - sizeof(struct ip), - (caddr_t) buffer); + /* ...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); - ip->ip_sum = in_cksum(m, (ip->ip_hl << 2)); + /* 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 + AH_NEW_FLENGTH, + mtod(m1, u_char *) + roff, + m1->m_len - (roff + AH_NEW_FLENGTH)); + m1->m_len -= AH_NEW_FLENGTH; + m->m_pkthdr.len -= AH_NEW_FLENGTH; + } return m; } diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c index ab3eae18fea..e2ea7211264 100644 --- a/sys/netinet/ip_esp.c +++ b/sys/netinet/ip_esp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_esp.c,v 1.27 1999/12/06 07:14:35 angelos Exp $ */ +/* $OpenBSD: ip_esp.c,v 1.28 1999/12/07 08:58:00 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -35,11 +35,6 @@ * PURPOSE. */ -/* - * Encapsulation Security Payload Processing - * Per RFC1827 (Atkinson, 1995) - */ - #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -91,7 +86,7 @@ extern struct enc_softc encif[]; int esp_enable = 0; /* - * esp_input gets called when we receive an packet with an ESP. + * esp_input gets called when we receive an ESP-protected packet */ void |