summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-12-07 08:58:01 +0000
committerAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-12-07 08:58:01 +0000
commit9ee72983c9413873178f66eeef808559910d3b00 (patch)
treedb02351874ac2ce0ff39a336d2613177a7144626
parent93a0c92573a551bbe49ca24721d08094be1b29c9 (diff)
New ah_new_input(), protocol-independent processing (still lacking
IPv6-specific protocol header processing).
-rw-r--r--sys/netinet/ip_ah.c8
-rw-r--r--sys/netinet/ip_ah.h5
-rw-r--r--sys/netinet/ip_ah_new.c379
-rw-r--r--sys/netinet/ip_esp.c9
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