summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1997-02-20 01:08:13 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1997-02-20 01:08:13 +0000
commit27f7e7b789913e142fd048ad0f5e9fe6fee94c27 (patch)
tree92f475f4da1f7ac2c6a9fac20881c666173e7600
parent64c38b22e9e85f411969b697297f6dfd609dc83c (diff)
IPSEC package by John Ioannidis and Angelos D. Keromytis. Written in
Greece. From ftp.funet.fi:/pub/unix/security/net/ip/BSDipsec.tar.gz
-rw-r--r--sys/conf/files19
-rw-r--r--sys/kern/uipc_domain.c5
-rw-r--r--sys/miscfs/kernfs/kernfs_vnops.c17
-rw-r--r--sys/net/encap.c393
-rw-r--r--sys/net/encap.h230
-rw-r--r--sys/net/if_enc.c247
-rw-r--r--sys/net/if_types.h1
-rw-r--r--sys/net/route.c18
-rw-r--r--sys/netinet/in.h4
-rw-r--r--sys/netinet/in_proto.c34
-rw-r--r--sys/netinet/ip_ah.c160
-rw-r--r--sys/netinet/ip_ah.h162
-rw-r--r--sys/netinet/ip_ahhmacmd5.c459
-rw-r--r--sys/netinet/ip_ahhmacsha1.c463
-rw-r--r--sys/netinet/ip_ahmd5.c353
-rw-r--r--sys/netinet/ip_esp.c158
-rw-r--r--sys/netinet/ip_esp.h179
-rw-r--r--sys/netinet/ip_esp3desmd5.c749
-rw-r--r--sys/netinet/ip_espdes.c516
-rw-r--r--sys/netinet/ip_espdesmd5.c805
-rw-r--r--sys/netinet/ip_ip4.c222
-rw-r--r--sys/netinet/ip_ip4.h40
-rw-r--r--sys/netinet/ip_ipsp.c259
-rw-r--r--sys/netinet/ip_ipsp.h139
-rw-r--r--sys/netinet/ip_md5.h71
-rw-r--r--sys/netinet/ip_md5c.c383
-rw-r--r--sys/netinet/ip_mroute.c23
-rw-r--r--sys/netinet/ip_output.c182
-rw-r--r--sys/netinet/ip_sha1.c166
-rw-r--r--sys/netinet/ip_sha1.h16
-rw-r--r--sys/netinet/ip_var.h6
-rw-r--r--sys/sys/malloc.h11
-rw-r--r--sys/sys/socket.h9
33 files changed, 6481 insertions, 18 deletions
diff --git a/sys/conf/files b/sys/conf/files
index dbcb9628c28..f3c3d77442b 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.49 1996/12/23 02:42:23 deraadt Exp $
+# $OpenBSD: files,v 1.50 1997/02/20 01:07:37 deraadt Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -86,6 +86,7 @@ pseudo-device tun: ifnet
pseudo-device bpfilter: ifnet
pseudo-device strip: ifnet
pseudo-device random
+pseudo-device enc: ifnet
# XXX machine-independent SCSI files should live somewhere here, maybe
@@ -252,6 +253,8 @@ file net/raw_usrreq.c
file net/route.c
file net/rtsock.c
file net/slcompress.c sl | ppp | strip
+file net/if_enc.c inet
+file net/encap.c inet
file netccitt/ccitt_proto.c ccitt
file netccitt/hd_debug.c hdlc
file netccitt/hd_input.c hdlc
@@ -294,6 +297,20 @@ file netinet/fil.c ipfilter
file netinet/ip_nat.c ipfilter
file netinet/ip_frag.c ipfilter
file netinet/ip_state.c ipfilter
+file netinet/ip_ah.c inet | ipsec
+file netinet/ip_esp.c inet | ipsec
+file netinet/ip_espdes.c inet | ipsec
+file netinet/ip_espdesmd5.c inet | ipsec
+file netinet/ip_ipsp.c inet | ipsec
+file netinet/ip_ahmd5.c inet | ipsec
+file netinet/ip_ip4.c inet | ipsec
+file netinet/ip_ahhmacmd5.c inet | ipsec
+file netinet/ip_ahhmacsha1.c inet | ipsec
+file netinet/ip_sha1.c inet | ipsec
+file netinet/ip_md5c.c inet | ipsec
+file netinet/libdeslite/ecb_enc.c inet | ipsec
+file netinet/libdeslite/set_key.c inet | ipsec
+file netinet/ip_esp3desmd5.c inet | ipsec
file netiso/clnp_debug.c iso
file netiso/clnp_er.c iso
file netiso/clnp_frag.c iso
diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c
index 406a420d352..790eceafddf 100644
--- a/sys/kern/uipc_domain.c
+++ b/sys/kern/uipc_domain.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_domain.c,v 1.3 1996/04/27 13:21:06 mickey Exp $ */
+/* $OpenBSD: uipc_domain.c,v 1.4 1997/02/20 01:07:26 deraadt Exp $ */
/* $NetBSD: uipc_domain.c,v 1.14 1996/02/09 19:00:44 christos Exp $ */
/*
@@ -69,6 +69,9 @@ domaininit()
ADDDOMAIN(route);
#ifdef INET
ADDDOMAIN(inet);
+#ifdef IPSEC
+ ADDDOMAIN(encap);
+#endif
#endif
#ifdef IPX
ADDDOMAIN(ipx);
diff --git a/sys/miscfs/kernfs/kernfs_vnops.c b/sys/miscfs/kernfs/kernfs_vnops.c
index f77a606a13e..0a94d88248b 100644
--- a/sys/miscfs/kernfs/kernfs_vnops.c
+++ b/sys/miscfs/kernfs/kernfs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kernfs_vnops.c,v 1.6 1997/01/15 03:06:28 kstailey Exp $ */
+/* $OpenBSD: kernfs_vnops.c,v 1.7 1997/02/20 01:08:12 deraadt Exp $ */
/* $NetBSD: kernfs_vnops.c,v 1.43 1996/03/16 23:52:47 christos Exp $ */
/*
@@ -75,6 +75,10 @@ static int ncpu = 1; /* XXX */
extern char machine[], cpu_model[];
extern char ostype[], osrelease[];
+#ifdef IPSEC
+extern int ipsp_kern __P((int, char **, int));
+#endif
+
struct kern_target {
u_char kt_type;
u_char kt_namlen;
@@ -90,6 +94,9 @@ struct kern_target {
#define KTT_MSGBUF 89
#define KTT_USERMEM 91
#define KTT_DOMAIN 95
+#ifdef IPSEC
+#define KTT_IPSECSPI 107
+#endif
u_char kt_tag;
u_char kt_vtype;
mode_t kt_mode;
@@ -124,6 +131,9 @@ struct kern_target {
{ DT_REG, N("time"), 0, KTT_TIME, VREG, READ_MODE },
{ DT_REG, N("usermem"), 0, KTT_USERMEM, VREG, READ_MODE },
{ DT_REG, N("version"), version, KTT_STRING, VREG, READ_MODE },
+#ifdef IPSEC
+ { DT_REG, N("ipsec"), 0, KTT_IPSECSPI, VREG, READ_MODE },
+#endif
#undef N
};
static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]);
@@ -304,7 +314,10 @@ kernfs_xread(kt, off, bufp, len)
case KTT_USERMEM:
sprintf(*bufp, "%u\n", physmem - cnt.v_wire_count);
break;
-
+#ifdef IPSEC
+ case KTT_IPSECSPI:
+ return(ipsp_kern(off, bufp, len));
+#endif
default:
return (0);
}
diff --git a/sys/net/encap.c b/sys/net/encap.c
new file mode 100644
index 00000000000..a8e1de64073
--- /dev/null
+++ b/sys/net/encap.c
@@ -0,0 +1,393 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/raw_cb.h>
+#include <machine/stdarg.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#endif
+
+#include <net/encap.h>
+#include <netinet/ip_ipsp.h>
+
+extern struct ifnet loif;
+
+extern int ipspkernfs_dirty;
+
+void encap_init(void);
+int encap_output __P((struct mbuf *, ...));
+int encap_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *);
+
+extern int tdb_init(struct tdb *, struct mbuf *);
+
+extern struct domain encapdomain;
+
+struct sockaddr encap_dst = { 2, PF_ENCAP, };
+struct sockaddr encap_src = { 2, PF_ENCAP, };
+struct sockproto encap_proto = { PF_ENCAP, };
+
+struct protosw encapsw[] = {
+{ SOCK_RAW, &encapdomain, 0, PR_ATOMIC|PR_ADDR,
+ raw_input, encap_output, raw_ctlinput, 0,
+ encap_usrreq,
+ encap_init, 0, 0, 0,
+},
+};
+
+struct domain encapdomain =
+ { AF_ENCAP, "encapsulation", 0, 0, 0,
+ encapsw, &encapsw[sizeof(encapsw)/sizeof(encapsw[0])], 0,
+ rn_inithead, 16, sizeof(struct sockaddr_encap)};
+
+
+void
+encap_init()
+{
+ struct xformsw *xsp;
+
+ for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++)
+ {
+ printf("encap_init: attaching <%s>\n", xsp->xf_name);
+ (*(xsp->xf_attach))();
+ }
+}
+
+/*ARGSUSED*/
+int
+encap_usrreq(register struct socket *so, int req, struct mbuf *m, struct mbuf *nam, struct mbuf *control)
+{
+ register int error = 0;
+ register struct rawcb *rp = sotorawcb(so);
+ int s;
+
+ if (req == PRU_ATTACH)
+ {
+ MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
+ if ((so->so_pcb = (caddr_t)rp))
+ bzero(so->so_pcb, sizeof(*rp));
+
+ }
+ s = splnet();
+ error = raw_usrreq(so, req, m, nam, control);
+ rp = sotorawcb(so);
+ if ((req == PRU_ATTACH) && rp)
+ {
+ /* int af = rp->rcb_proto.sp_protocol; */
+
+ if (error)
+ {
+ free((caddr_t)rp, M_PCB);
+ splx(s);
+ return error;
+ }
+ rp->rcb_faddr = &encap_src;
+ soisconnected(so);
+ so->so_options |= SO_USELOOPBACK;
+ }
+ splx(s);
+ return error;
+}
+
+int
+#ifdef __STDC__
+encap_output(struct mbuf *m, ...)
+#else
+encap_output(m, va_alist)
+ register struct mbuf *m;
+ va_dcl
+#endif
+{
+#define SENDERR(e) do { error = e; goto flush;} while (0)
+ struct socket *so;
+ int len, emlen, error = 0, nspis, i;
+ struct encap_msghdr *emp;
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ struct sockaddr_encap *sen, *sen2;
+ struct sockaddr_in *sin;
+ struct tdb *tdbp, *tprev;
+ va_list ap;
+
+ va_start(ap, m);
+ so = va_arg(ap, struct socket *);
+ va_end(ap);
+
+ if ((m == 0) || ((m->m_len < sizeof(long)) &&
+ (m = m_pullup(m, sizeof(long))) == 0))
+ return ENOBUFS;
+
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic("encap_output");
+
+ len = m->m_pkthdr.len;
+ emp = mtod(m, struct encap_msghdr *);
+ emlen = emp->em_msglen;
+ if ((len < emlen))
+ SENDERR(EINVAL);
+
+ if (m->m_len < emlen)
+ {
+ m = m_pullup(m, emlen);
+ if (m == NULL)
+ SENDERR(ENOBUFS);
+
+ emp = mtod(m, struct encap_msghdr *);
+ }
+
+ switch (emp->em_type)
+ {
+ case EMT_IFADDR:
+ /*
+ * Set the default source address for an encap interface
+ */
+
+ ifp = &(enc_softc[emp->em_ifn].enc_if);
+
+ if ((ifp->if_addrlist.tqh_first == NULL) ||
+ (ifp->if_addrlist.tqh_first->ifa_addr == NULL) ||
+ (ifp->if_addrlist.tqh_first->ifa_addr->sa_family != AF_ENCAP))
+ {
+ MALLOC(ifa, struct ifaddr *, sizeof (struct ifaddr) + 2*SENT_DEFIF_LEN, M_IFADDR, M_WAITOK);
+ if (ifa == NULL)
+ SENDERR(ENOBUFS);
+ bzero((caddr_t)ifa, sizeof (struct ifaddr) + 2*SENT_DEFIF_LEN);
+ sen = (struct sockaddr_encap *)(ifa + 1);
+ sen2 = (struct sockaddr_encap *)((caddr_t)sen + SENT_DEFIF_LEN);
+ ifa->ifa_addr = (struct sockaddr *)sen;
+ ifa->ifa_dstaddr = (struct sockaddr *)sen2;
+ ifa->ifa_ifp = ifp;
+ TAILQ_INSERT_HEAD(&(ifp->if_addrlist), ifa, ifa_list);
+ }
+ else
+ {
+ sen = (struct sockaddr_encap *)((&(ifp->if_addrlist))->tqh_first->ifa_addr);
+ sen2 = (struct sockaddr_encap *)((&(ifp->if_addrlist))->tqh_first->ifa_dstaddr);
+ }
+
+ sen->sen_family = AF_ENCAP;
+ sen->sen_len = SENT_DEFIF_LEN;
+ sen->sen_type = SENT_DEFIF;
+ sin = (struct sockaddr_in *) &(sen->sen_dfl);
+ sin->sin_len = sizeof(*sin);
+ sin->sin_family = AF_INET;
+ sin->sin_addr = emp->em_ifa;
+
+ *sen2 = *sen;
+
+ break;
+
+ case EMT_SETSPI:
+ if (emp->em_if >= nencap)
+ SENDERR(ENODEV);
+
+ tdbp = gettdb(emp->em_spi, emp->em_dst);
+ if (tdbp == NULL)
+ {
+ MALLOC(tdbp, struct tdb *, sizeof (*tdbp), M_TDB, M_WAITOK);
+ if (tdbp == NULL)
+ SENDERR(ENOBUFS);
+
+ bzero((caddr_t)tdbp, sizeof(*tdbp));
+
+ tdbp->tdb_spi = emp->em_spi;
+ tdbp->tdb_dst = emp->em_dst;
+ tdbp->tdb_rcvif = &(enc_softc[emp->em_if].enc_if);
+ puttdb(tdbp);
+ }
+ else
+ (*tdbp->tdb_xform->xf_zeroize)(tdbp);
+
+ error = tdb_init(tdbp, m);
+ ipspkernfs_dirty = 1;
+ break;
+
+ case EMT_DELSPI:
+ if (emp->em_if >= nencap)
+ SENDERR(ENODEV);
+
+ tdbp = gettdb(emp->em_spi, emp->em_dst);
+ if (tdbp == NULL)
+ {
+ error = EINVAL;
+ break;
+ }
+
+ if (emp->em_alg != tdbp->tdb_xform->xf_type)
+ {
+ error = EINVAL;
+ break;
+ }
+
+ error = tdb_delete(tdbp, 0);
+ break;
+
+ case EMT_DELSPICHAIN:
+ if (emp->em_if >= nencap)
+ SENDERR(ENODEV);
+
+ tdbp = gettdb(emp->em_spi, emp->em_dst);
+ if (tdbp == NULL)
+ {
+ error = EINVAL;
+ break;
+ }
+
+ if (emp->em_alg != tdbp->tdb_xform->xf_type)
+ {
+ error = EINVAL;
+ break;
+ }
+
+ error = tdb_delete(tdbp, 1);
+ break;
+
+ case EMT_GRPSPIS:
+ nspis = (emlen - 4) / 12;
+ if (nspis * 12 + 4 != emlen)
+ {
+ SENDERR(EINVAL);
+ break;
+ }
+
+ for (i = 0; i < nspis; i++)
+ if ((tdbp = gettdb(emp->em_rel[i].emr_spi, emp->em_rel[i].emr_dst)) == NULL)
+ SENDERR(ENOENT);
+ else
+ emp->em_rel[i].emr_tdb = tdbp;
+ tprev = emp->em_rel[0].emr_tdb;
+ tprev->tdb_inext = NULL;
+ for (i = 1; i < nspis; i++)
+ {
+ tdbp = emp->em_rel[i].emr_tdb;
+ tprev->tdb_onext = tdbp;
+ tdbp->tdb_inext = tprev;
+ tprev = tdbp;
+ }
+ tprev->tdb_onext = NULL;
+ ipspkernfs_dirty = 1;
+ error = 0;
+ break;
+
+ default:
+ SENDERR(EINVAL);
+ }
+
+ return error;
+
+ flush:
+ if (m)
+ m_freem(m);
+ return error;
+}
+
+struct ifaddr *
+encap_findgwifa(struct sockaddr *gw)
+{
+ struct sockaddr_encap *egw = (struct sockaddr_encap *)gw;
+ u_char *op = (u_char *)gw;
+ int i, j;
+ struct ifaddr *retval = loif.if_addrlist.tqh_first;
+ union
+ {
+ struct in_addr ia;
+ u_char io[4];
+ } iao;
+
+ switch (egw->sen_type)
+ {
+ case SENT_IPSP:
+ return enc_softc[egw->sen_ipsp_ifn].enc_if.if_addrlist.tqh_first;
+ break;
+
+ case SENT_IP4:
+ /*
+ * Pretty-much standard options walking code.
+ * Repeated elsewhere as necessary
+ */
+
+ for (i = SENT_IP4_LEN; i < egw->sen_len;)
+ switch (op[i])
+ {
+ case SENO_EOL:
+ goto opt_done;
+
+ case SENO_NOP:
+ i++;
+ continue;
+
+ case SENO_IFN:
+ if (op[i+1] != 3)
+ {
+ return NULL;
+ }
+ retval = enc_softc[op[i+2]].enc_if.if_addrlist.tqh_first;
+ goto opt_done;
+
+ case SENO_IFIP4A:
+ if (op[i+1] != 6) /* XXX -- IPv4 address */
+ {
+ return NULL;
+ }
+ iao.io[0] = op[i+2];
+ iao.io[1] = op[i+3];
+ iao.io[2] = op[i+4];
+ iao.io[3] = op[i+5];
+
+ for (j = 0; j < nencap; j++)
+ {
+ struct ifaddr *ia = (struct ifaddr *)enc_softc[j].enc_if.if_addrlist.tqh_first;
+
+ struct sockaddr_in *si = (struct sockaddr_in *)ia->ifa_addr;
+
+ if ((si->sin_family == AF_INET) && (si->sin_addr.s_addr == iao.ia.s_addr))
+ {
+ retval = ia;
+ goto opt_done;
+ }
+ }
+ i += 6;
+ break;
+
+ default:
+ if (op[i+1] == 0)
+ return NULL;
+ i += op[i+i];
+ }
+ opt_done:
+ break;
+ }
+ return retval;
+}
diff --git a/sys/net/encap.h b/sys/net/encap.h
new file mode 100644
index 00000000000..4d105db0cd7
--- /dev/null
+++ b/sys/net/encap.h
@@ -0,0 +1,230 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * encap.h
+ *
+ * Declarations useful in the encapsulation code.
+ */
+
+/*
+ * Definitions for encapsulation-related phenomena.
+ *
+ * A lot of encapsulation protocols (ipip, swipe, ip_encap, ipsp, etc.)
+ * select their tunnel based on the destination (and sometimes the source)
+ * of the packet. The encap address/protocol family provides a generic
+ * mechanism for specifying tunnels.
+ */
+
+/*
+ * A tunnel is characterized by which source/destination address pairs
+ * (with netmasks) it is valid for (the "destination" as far as the
+ * routing code is concerned), and what the source (local) and destination
+ * (remote) endpoints of the tunnel, and the SPI, should be (the "gateway"
+ * as far as the routing code is concerned.
+ */
+
+
+struct sockaddr_encap
+{
+ u_int8_t sen_len; /* length */
+ u_int8_t sen_family; /* AF_ENCAP */
+ u_int16_t sen_type; /* see SENT_* */
+ union
+ {
+ u_int8_t Data[16]; /* other stuff mapped here */
+ struct sockaddr Dfl; /* SENT_DEFIF */
+ struct /* SENT_SA */
+ {
+ struct sockaddr Src;
+ struct sockaddr Dst;
+ } Sa;
+#ifdef INET
+ struct /* SENT_SAIN */
+ {
+ struct sockaddr_in Src;
+ struct sockaddr_in Dst;
+ } Sin;
+ struct /* SENT_IP4 */
+ {
+ struct in_addr Src;
+ struct in_addr Dst;
+ u_int16_t Sport;
+ u_int16_t Dport;
+ u_int8_t Proto;
+ u_int8_t Filler[3];
+ } Sip4;
+ struct /* SENT_IPSP */
+ {
+ struct in_addr Src;
+ struct in_addr Dst;
+ u_int32_t Spi;
+ u_int8_t Ifn;
+ u_int8_t Filler[3];
+ } Sipsp;
+#endif
+ } Sen;
+};
+
+#define sen_data Sen.Data
+#define sen_dfl Sen.Dfl
+#define sen_sa_src Sen.Sa.Src
+#define sen_sa_dst Sen.Sa.Dst
+#ifdef INET
+#define sen_sin_src Sen.Sin.Src
+#define sen_sin_dst Sen.Sin.Dst
+#define sen_ip_src Sen.Sip4.Src
+#define sen_ip_dst Sen.Sip4.Dst
+#define sen_ipsp_src Sen.Sipsp.Src
+#define sen_ipsp_dst Sen.Sipsp.Dst
+#define sen_ipsp_spi Sen.Sipsp.Spi
+#define sen_ipsp_ifn Sen.Sipsp.Ifn
+#define sen_proto Sen.Sip4.Proto
+#define sen_sport Sen.Sip4.Sport
+#define sen_dport Sen.Sip4.Dport
+#endif
+
+/*
+ * The "type" is really part of the address as far as the routing
+ * system is concerned. By using only one bit in the type field
+ * for each type, we sort-of make sure that different types of
+ * encapsulation addresses won't be matched against the wrong type.
+ *
+ */
+
+#define SENT_DEFIF 0x0001 /* data is a default sockaddr for if */
+#define SENT_SA 0x0002 /* data is two struct sockaddr */
+#define SENT_SAIN 0x0004 /* data is two struct sockaddr_in */
+#define SENT_IP4 0x0008 /* data is two struct in_addr */
+#define SENT_IPSP 0x0010 /* data as in IP4 plus SPI and if# */
+
+/*
+ * SENT_HDRLEN is the length of the "header"
+ * SENT_*_LEN are the lengths of various forms of sen_data
+ * SENT_*_OFF are the offsets in the sen_data array of various fields
+ */
+
+#define SENT_HDRLEN (2*sizeof(u_int8_t)+sizeof(u_int16_t))
+
+#define SENT_DEFIF_LEN (SENT_HDRLEN + sizeof (struct sockaddr_in))
+
+#define SENT_IP4_SRCOFF (0)
+#define SENT_IP4_DSTOFF (sizeof (struct in_addr))
+#define SENT_IP4_OPTOFF (2*sizeof(struct in_addr)+2*sizeof(u_int16_t)+sizeof(u_int8_t)+3*sizeof(u_int8_t))
+
+#define SENT_IP4_LEN (SENT_HDRLEN + SENT_IP4_OPTOFF)
+
+#define SENT_IPSP_LEN (SENT_HDRLEN + 2 * sizeof (struct in_addr) + sizeof (u_int32_t) + 4)
+
+/*
+ * Options 0x00 and 01 are 1-byte options (no arguments).
+ * The rest of the options are T-L-V fields, where the L includes
+ * the T and L bytes; thus, the minimum length for an option with
+ * no arguments is 2. An option of length less than 2 causes en EINVAL
+ */
+
+
+#define SENO_EOL 0x00 /* End of Options, or placeholder */
+#define SENO_NOP 0x01 /* No Operation. Skip */
+#define SENO_NAME 0x02 /* tunnel name, NUL-terminated */
+#define SENO_SPI 0x03 /* Security Parameters Index */
+#define SENO_IFN 0x04 /* Encap interface number */
+#define SENO_IFIP4A 0x05 /* Encap interface IPv4 address */
+#define SENO_IPSA 0x06 /* Encap interface generic sockaddr */
+
+struct enc_softc
+{
+ struct ifnet enc_if;
+};
+
+/*
+ * Tunnel descriptors are setup and torn down using a socket of the
+ * AF_ENCAP domain. The following defines the messages that can
+ * be sent down that socket.
+ */
+
+#define EM_MAXRELSPIS 4 /* at most five chained xforms */
+
+
+struct encap_msghdr
+{
+ u_int16_t em_msglen; /* message length */
+ u_int8_t em_version; /* for future expansion */
+ u_int8_t em_type; /* message type */
+ union
+ {
+ struct
+ {
+ struct in_addr Ia;
+ u_int8_t Ifn;
+ u_int8_t xxx[3]; /* makes life a lot easier */
+ } Ifa;
+
+ struct
+ {
+ u_int32_t Spi; /* SPI */
+ struct in_addr Dst; /* Destination address */
+ int32_t If; /* enc i/f for input */
+ int32_t Alg; /* Algorithm to use */
+ u_int8_t Dat[1]; /* Data */
+ } Xfm;
+
+ struct
+ {
+ u_int32_t emr_spi; /* SPI */
+ struct in_addr emr_dst; /* Dest */
+ struct tdb * emr_tdb; /* used internally! */
+
+ } Rel[EM_MAXRELSPIS];
+ } Eu;
+};
+
+#define em_ifa Eu.Ifa.Ia
+#define em_ifn Eu.Ifa.Ifn
+
+#define em_spi Eu.Xfm.Spi
+#define em_dst Eu.Xfm.Dst
+#define em_if Eu.Xfm.If
+#define em_alg Eu.Xfm.Alg
+#define em_dat Eu.Xfm.Dat
+
+#define em_rel Eu.Rel
+
+#define EMT_IFADDR 1 /* set enc if addr */
+#define EMT_SETSPI 2 /* Set SPI properties */
+#define EMT_GRPSPIS 3 /* Group SPIs (output order) */
+#define EMT_DELSPI 4 /* delete an SPI */
+#define EMT_DELSPICHAIN 5 /* delete an SPI chain starting from */
+
+#define EM_MINLEN 8 /* count!!! */
+#define EMT_IFADDR_LEN 12
+#define EMT_SETSPI_FLEN 20
+#define EMT_GRPSPIS_FLEN 4
+#define EMT_DELSPI_FLEN 20
+#define EMT_DELSPICHAIN_FLEN 20
+
+#ifdef _KERNEL
+extern struct ifaddr *encap_findgwifa(struct sockaddr *);
+extern struct enc_softc *enc_softc;
+extern int32_t nencap;
+#endif
diff --git a/sys/net/if_enc.c b/sys/net/if_enc.c
new file mode 100644
index 00000000000..5cecd2dfaaf
--- /dev/null
+++ b/sys/net/if_enc.c
@@ -0,0 +1,247 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Encapsulation interface driver.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#ifdef ISO
+extern struct ifqueue clnlintrq;
+#endif
+
+#ifdef NS
+extern struct ifqueue nsintrq;
+#endif
+
+#include "bpfilter.h"
+
+#define ENCMTU (1024+512)
+
+/*
+ * Called from boot code to establish enc interfaces.
+ */
+
+struct enc_softc
+{
+ struct ifnet enc_if;
+} ;
+
+struct enc_softc *enc_softc;
+
+int nencap;
+
+int encoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *);
+int encioctl(struct ifnet *, u_long, caddr_t);
+void encrtrequest(int, struct rtentry *, struct sockaddr *);
+
+void
+encattach(int nenc)
+{
+ register struct enc_softc *enc;
+ register int i = 0;
+
+ nencap = nenc;
+
+ enc_softc = malloc(nenc * sizeof (*enc_softc), M_DEVBUF, M_WAIT);
+ bzero(enc_softc, nenc * sizeof (*enc_softc));
+ for (enc = enc_softc; i < nenc; enc++)
+ {
+ enc->enc_if.if_index = i;
+ sprintf(enc->enc_if.if_xname, "enc%d", i++);
+ enc->enc_if.if_list.tqe_next = NULL;
+ enc->enc_if.if_mtu = ENCMTU;
+ enc->enc_if.if_flags = IFF_LOOPBACK;
+ enc->enc_if.if_type = IFT_ENC;
+ enc->enc_if.if_ioctl = encioctl;
+ enc->enc_if.if_output = encoutput;
+ enc->enc_if.if_hdrlen = 0;
+ enc->enc_if.if_addrlen = 0;
+ if_attach(&enc->enc_if);
+ bpfattach(&enc->enc_if.if_bpf, &enc->enc_if, DLT_NULL, sizeof(u_int));
+ }
+}
+
+/*
+ * Shamelessly stolen from looutput()
+ */
+int
+encoutput(ifp, m, dst, rt)
+struct ifnet *ifp;
+register struct mbuf *m;
+struct sockaddr *dst;
+register struct rtentry *rt;
+{
+ int s, isr;
+ register struct ifqueue *ifq = 0;
+
+ /* register struct enc_softc *ec = &enc_softc[ifp->if_index]; */
+
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic("encoutput no HDR");
+ ifp->if_lastchange = time;
+ if (ifp->if_bpf) {
+ /*
+ * We need to prepend the address family as
+ * a four byte field. Cons up a dummy header
+ * to pacify bpf. This is safe because bpf
+ * will only read from the mbuf (i.e., it won't
+ * try to free it or keep a pointer a to it).
+ */
+ struct mbuf m0;
+ u_int af = dst->sa_family;
+
+ m0.m_next = m;
+ m0.m_len = 4;
+ m0.m_data = (char *)&af;
+
+ bpf_mtap(ifp->if_bpf, &m0);
+ }
+ m->m_pkthdr.rcvif = ifp;
+
+ if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
+ m_freem(m);
+ return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
+ rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
+ }
+ ifp->if_opackets++;
+ ifp->if_obytes += m->m_pkthdr.len;
+ switch (dst->sa_family) {
+
+#ifdef INET
+ case AF_INET:
+ ifq = &ipintrq;
+ isr = NETISR_IP;
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ ifq = &nsintrq;
+ isr = NETISR_NS;
+ break;
+#endif
+#ifdef ISO
+ case AF_ISO:
+ ifq = &clnlintrq;
+ isr = NETISR_ISO;
+ break;
+#endif
+ default:
+ m_freem(m);
+ return (EAFNOSUPPORT);
+ }
+ s = splimp();
+ if (IF_QFULL(ifq)) {
+ IF_DROP(ifq);
+ m_freem(m);
+ splx(s);
+ return (ENOBUFS);
+ }
+ IF_ENQUEUE(ifq, m);
+ schednetisr(isr);
+ ifp->if_ipackets++;
+ ifp->if_ibytes += m->m_pkthdr.len;
+ splx(s);
+ return (0);
+}
+
+/* ARGSUSED */
+void
+encrtrequest(cmd, rt, sa)
+ int cmd;
+ struct rtentry *rt;
+ struct sockaddr *sa;
+{
+
+ if (rt)
+ rt->rt_rmx.rmx_mtu = ENCMTU;
+}
+
+/*
+ * Process an ioctl request.
+ * Also shamelessly stolen from loioctl()
+ */
+
+/* ARGSUSED */
+int
+encioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ register struct ifaddr *ifa;
+ register struct ifreq *ifr;
+ register int error = 0;
+
+ switch (cmd)
+ {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ ifa = (struct ifaddr *)data;
+ /*
+ * Everything else is done at a higher level.
+ */
+ break;
+
+ switch (ifr->ifr_addr.sa_family) {
+
+#ifdef INET
+ case AF_INET:
+ break;
+#endif
+ case AF_ENCAP:
+ break;
+
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ return error;
+}
diff --git a/sys/net/if_types.h b/sys/net/if_types.h
index fc3e749edac..4b8fe650a59 100644
--- a/sys/net/if_types.h
+++ b/sys/net/if_types.h
@@ -95,3 +95,4 @@
#define IFT_SMDSICIP 0x34 /* SMDS InterCarrier Interface */
#define IFT_PROPVIRTUAL 0x35 /* Proprietary Virtual/internal */
#define IFT_PROPMUX 0x36 /* Proprietary Multiplexing */
+#define IFT_ENC 0x37 /* Encapsulation */
diff --git a/sys/net/route.c b/sys/net/route.c
index 59f83f1d4a8..05ef2994fa7 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.2 1996/03/03 21:07:19 niklas Exp $ */
+/* $OpenBSD: route.c,v 1.3 1997/02/20 01:07:43 deraadt Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
@@ -57,6 +57,10 @@
#include <netns/ns.h>
#endif
+#ifdef IPSEC
+#include <net/encap.h>
+#endif
+
#define SA(p) ((struct sockaddr *)(p))
int rttrash; /* routes not in table but not freed */
@@ -283,6 +287,18 @@ ifa_ifwithroute(flags, dst, gateway)
struct sockaddr *dst, *gateway;
{
register struct ifaddr *ifa;
+
+#ifdef IPSEC
+ /*
+ * If the destination is a AF_ENCAP address, we'll look
+ * for the existence of a encap interface number or address
+ * in the options list of the gateway. By default, we'll return
+ * encap0.
+ */
+ if (dst && (dst->sa_family == AF_ENCAP))
+ return encap_findgwifa(gateway);
+#endif
+
if ((flags & RTF_GATEWAY) == 0) {
/*
* If we are adding a route to an interface,
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index 7e9c0fa0dc4..d69dbcef7c9 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.h,v 1.6 1996/07/29 02:34:29 downsj Exp $ */
+/* $OpenBSD: in.h,v 1.7 1997/02/20 01:07:45 deraadt Exp $ */
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
/*
@@ -58,6 +58,8 @@
#define IPPROTO_UDP 17 /* user datagram protocol */
#define IPPROTO_IDP 22 /* xns idp */
#define IPPROTO_TP 29 /* tp-4 w/ class negotiation */
+#define IPPROTO_ESP 50 /* Encap. Security Payload */
+#define IPPROTO_AH 51 /* Authentication header */
#define IPPROTO_EON 80 /* ISO cnlp */
#define IPPROTO_ENCAP 98 /* encapsulation header */
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index 295ca096960..66c5ddd6047 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_proto.c,v 1.6 1996/10/08 07:33:25 niklas Exp $ */
+/* $OpenBSD: in_proto.c,v 1.7 1997/02/20 01:07:46 deraadt Exp $ */
/* $NetBSD: in_proto.c,v 1.14 1996/02/18 18:58:32 christos Exp $ */
/*
@@ -94,6 +94,18 @@ void iplinit __P((void));
#define ip_init iplinit
#endif
+#ifdef IPSEC
+#include <net/encap.h>
+#include <netinet/ip_ipsp.h>
+
+extern void ah_input __P((struct mbuf *, ...));
+extern void esp_input __P((struct mbuf *, ...));
+extern int ah_output __P((struct mbuf *, struct sockaddr_encap *,
+ struct tdb *, struct mbuf **));
+extern int esp_output __P((struct mbuf *, struct sockaddr_encap *,
+ struct tdb *, struct mbuf **));
+#endif
+
extern struct domain inetdomain;
struct protosw inetsw[] = {
@@ -128,7 +140,13 @@ struct protosw inetsw[] = {
rip_usrreq, /* XXX */
0, 0, 0, 0,
},
-#endif /* MROUTING */
+#elif defined(IPSEC)
+{ SOCK_RAW, &inetdomain, IPPROTO_IPIP, PR_ATOMIC|PR_ADDR,
+ ipe4_input, rip_output, 0, rip_ctloutput,
+ rip_usrreq, /* XXX */
+ 0, 0, 0, 0,
+},
+#endif /* MROUTING/IPSEC */
{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR,
igmp_input, rip_output, 0, rip_ctloutput,
rip_usrreq,
@@ -163,6 +181,18 @@ struct protosw inetsw[] = {
0, 0, 0, 0,
},
#endif /* NSIP */
+#ifdef IPSEC
+{ SOCK_RAW, &inetdomain, IPPROTO_AH, PR_ATOMIC|PR_ADDR,
+ ah_input, rip_output, 0, rip_ctloutput,
+ rip_usrreq,
+ 0, 0, 0, 0,
+},
+{ SOCK_RAW, &inetdomain, IPPROTO_ESP, PR_ATOMIC|PR_ADDR,
+ esp_input, rip_output, 0, rip_ctloutput,
+ rip_usrreq,
+ 0, 0, 0, 0,
+},
+#endif
/* raw wildcard */
{ SOCK_RAW, &inetdomain, 0, PR_ATOMIC|PR_ADDR,
rip_input, rip_output, 0, rip_ctloutput,
diff --git a/sys/netinet/ip_ah.c b/sys/netinet/ip_ah.c
new file mode 100644
index 00000000000..e08f4c22fdb
--- /dev/null
+++ b/sys/netinet/ip_ah.c
@@ -0,0 +1,160 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Authentication Header Processing
+ * Per RFC1826 (Atkinson, 1995)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#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>
+
+#include <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_ah.h>
+
+
+/*
+ * ah_input gets called when we receive an packet with an AH.
+ */
+
+void
+ah_input(register struct mbuf *m, int iphlen)
+{
+ struct ip *ipo;
+ struct ah *ahp;
+ struct tdb *tdbp;
+ struct ifqueue *ifq = NULL;
+ int s;
+
+ /*
+ * Strip IP options, if any.
+ */
+
+ if (iphlen > sizeof (struct ip))
+ {
+ ip_stripoptions(m, (struct mbuf *)0);
+ iphlen = sizeof (struct ip);
+ }
+
+ /*
+ * Make sure that at least the fixed part of the AH header is
+ * in the first mbuf.
+ */
+
+ ipo = mtod(m, struct ip *);
+ if (m->m_len < iphlen + AH_FLENGTH)
+ {
+ if ((m = m_pullup(m, iphlen + AH_FLENGTH)) == 0)
+ {
+ ahstat.ahs_hdrops++;
+ return;
+ }
+ ipo = mtod(m, struct ip *);
+ }
+ ahp = (struct ah *)((caddr_t)ipo + iphlen);
+
+ /*
+ * Find tunnel control block and (indirectly) call the appropriate
+ * tranform routine. The resulting mbuf chain is a valid
+ * IP packet ready to go through input processing.
+ */
+
+ tdbp = gettdb(ahp->ah_spi, ipo->ip_dst);
+ if (tdbp == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_input: no tdb for spi=%x\n", ahp->ah_spi);
+#endif ENCDEBUG
+ m_freem(m);
+ ahstat.ahs_notdb++;
+ return;
+ }
+
+ if (tdbp->tdb_xform == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_input: no xform for spi=%x\n", ahp->ah_spi);
+#endif ENCDEBUG
+ m_freem(m);
+ ahstat.ahs_noxform++;
+ return;
+ }
+
+ m->m_pkthdr.rcvif = tdbp->tdb_rcvif;
+
+ m = (*(tdbp->tdb_xform->xf_input))(m, tdbp);
+
+ if (m == NULL)
+ {
+ ahstat.ahs_badkcr++;
+ return;
+ }
+
+ /*
+ * Interface pointer is already in first mbuf; chop off the
+ * `outer' header and reschedule.
+ */
+
+ ifq = &ipintrq;
+
+ s = splimp(); /* isn't it already? */
+ if (IF_QFULL(ifq))
+ {
+ IF_DROP(ifq);
+ m_freem(m);
+ ahstat.ahs_qfull++;
+ splx(s);
+ return;
+ }
+ IF_ENQUEUE(ifq, m);
+ schednetisr(NETISR_IP);
+ splx(s);
+ return;
+}
diff --git a/sys/netinet/ip_ah.h b/sys/netinet/ip_ah.h
new file mode 100644
index 00000000000..4ac4334dd36
--- /dev/null
+++ b/sys/netinet/ip_ah.h
@@ -0,0 +1,162 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Authentication Header Processing
+ * Per RFC1826 (Atkinson, 1995)
+ */
+
+#include <netinet/ip_md5.h>
+#include <netinet/ip_sha1.h>
+
+struct ah
+{
+ u_int8_t ah_nh; /* Next header (protocol) */
+ u_int8_t ah_hl; /* AH length, in 32-bit words */
+ u_int16_t ah_rv; /* reserved, must be 0 */
+ u_int32_t ah_spi; /* Security Parameters Index */
+ u_int8_t ah_data[1]; /* More, really*/
+};
+
+#define AH_FLENGTH 8 /* size of fixed part */
+
+struct ahstat
+{
+ u_int32_t ahs_hdrops; /* packet shorter than header shows */
+ u_int32_t ahs_notdb;
+ u_int32_t ahs_badkcr;
+ u_int32_t ahs_badauth;
+ u_int32_t ahs_noxform;
+ u_int32_t ahs_qfull;
+ u_int32_t ahs_wrap;
+ u_int32_t ahs_replay;
+ u_int32_t ahs_badauthl; /* bad authenticator length */
+};
+
+#define AHHMACMD5_KMAX 64 /* max 512 bits key */
+#define AHHMACMD5_AMAX 64 /* up to 512 bits of authenticator */
+#define AHHMACMD5_RPLS 2 /* 64 bits of replay counter */
+
+#define HMACMD5_HASHLEN 16
+#define HMACMD5_RPLENGTH 8
+
+#define HMACMD5_IPAD_VAL 0x36
+#define HMACMD5_OPAD_VAL 0x5C
+
+#define AHHMACMD5_KMAX 64 /* max 512 bits key */
+#define AHHMACMD5_AMAX 64 /* up to 512 bits of authenticator */
+#define AHHMACMD5_RPLS 2 /* 64 bits of replay counter */
+
+#define HMACMD5_HASHLEN 16
+#define HMACMD5_RPLENGTH 8
+
+#define HMACMD5_IPAD_VAL 0x36
+#define HMACMD5_OPAD_VAL 0x5C
+
+struct ahhmacmd5
+{
+ u_int8_t ah_nh; /* Next header (protocol) */
+ u_int8_t ah_hl; /* AH length, in 32-bit words */
+ u_int16_t ah_rv; /* reserved, must be 0 */
+ u_int32_t ah_spi; /* Security Parameters Index */
+ u_int64_t ah_rpl; /* Replay prevention */
+ u_int8_t ah_data[AHHMACMD5_AMAX];/* Authenticator */
+};
+
+struct ahhmacmd5_xencap
+{
+ u_int16_t amx_alen;
+ u_int16_t amx_rpl;
+ int32_t amx_wnd;
+ u_int8_t amx_key[AHHMACMD5_KMAX];
+};
+
+struct ahhmacmd5_xdata
+{
+ u_int32_t amx_alen; /* authenticator length */
+ int32_t amx_wnd;
+ u_int64_t amx_rpl; /* Replay counter */
+ u_int64_t amx_bitmap;
+ MD5_CTX amx_ictx; /* Internal key+padding */
+ MD5_CTX amx_octx; /* External key+padding */
+};
+
+#define AHHMACSHA1_KMAX 64 /* max 512 bits key */
+#define AHHMACSHA1_AMAX 64 /* up to 512 bits of authenticator */
+#define AHHMACSHA1_RPLS 2 /* 64 bits of replay counter */
+
+#define HMACSHA1_HASHLEN 20
+#define HMACSHA1_RPLENGTH 8
+
+#define HMACSHA1_IPAD_VAL 0x36
+#define HMACSHA1_OPAD_VAL 0x5C
+
+struct ahhmacsha1
+{
+ u_int8_t ah_nh; /* Next header (protocol) */
+ u_int8_t ah_hl; /* AH length, in 32-bit words */
+ u_int16_t ah_rv; /* reserved, must be 0 */
+ u_int32_t ah_spi; /* Security Parameters Index */
+ u_int64_t ah_rpl; /* Replay prevention */
+ u_int8_t ah_data[AHHMACSHA1_AMAX];/* Authenticator */
+};
+
+struct ahhmacsha1_xencap
+{
+ u_int32_t amx_alen;
+ int32_t amx_wnd;
+ u_int8_t amx_key[AHHMACSHA1_KMAX];
+};
+
+struct ahhmacsha1_xdata
+{
+ u_int32_t amx_alen; /* authenticator length */
+ int32_t amx_wnd;
+ u_int64_t amx_rpl; /* Replay counter */
+ u_int64_t amx_bitmap;
+ SHA1_CTX amx_ictx; /* Internal key+padding */
+ SHA1_CTX amx_octx; /* External key+padding */
+};
+
+#define AHMD5_KMAX 32 /* max 256 bits key */
+#define AHMD5_AMAX 64 /* up to 512 bits of authenticator */
+
+struct ahmd5
+{
+ u_int8_t ah_nh; /* Next header (protocol) */
+ u_int8_t ah_hl; /* AH length, in 32-bit words */
+ u_int16_t ah_rv; /* reserved, must be 0 */
+ u_int32_t ah_spi; /* Security Parameters Index */
+ u_int8_t ah_data[AHMD5_AMAX]; /* */
+};
+
+struct ahmd5_xdata
+{
+ u_int16_t amx_klen; /* Key material length */
+ u_int16_t amx_alen; /* authenticator length */
+ u_int8_t amx_key[AHMD5_KMAX]; /* Key material */
+};
+
+#ifdef _KERNEL
+struct ahstat ahstat;
+#endif
diff --git a/sys/netinet/ip_ahhmacmd5.c b/sys/netinet/ip_ahhmacmd5.c
new file mode 100644
index 00000000000..008fef0e575
--- /dev/null
+++ b/sys/netinet/ip_ahhmacmd5.c
@@ -0,0 +1,459 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Based on draft-ietf-ipsec-ah-hmac-md5-04.txt.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#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>
+
+#include <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_ah.h>
+
+/*
+ * ahhmacmd5_attach() is called from the transformation initialization code.
+ * It just returns.
+ */
+
+int
+ahhmacmd5_attach()
+{
+ return 0;
+}
+
+/*
+ * ahhmacmd5_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data.
+ */
+
+int
+ahhmacmd5_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ struct ahhmacmd5_xdata *xd;
+ struct ahhmacmd5_xencap txd;
+ struct encap_msghdr *em;
+ int len;
+
+ tdbp->tdb_xform = xsp;
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof (struct ahhmacmd5_xdata),
+ M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ return ENOBUFS;
+ bzero(tdbp->tdb_xdata, sizeof (struct ahhmacmd5_xdata));
+ bzero(&txd, sizeof(struct ahhmacmd5_xencap));
+ xd = (struct ahhmacmd5_xdata *)tdbp->tdb_xdata;
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI_FLEN > sizeof (struct ahhmacmd5_xencap))
+ {
+ free((caddr_t)tdbp->tdb_xdata, M_XDATA);
+ tdbp->tdb_xdata = NULL;
+ return EINVAL;
+ }
+
+ m_copydata(m, EMT_SETSPI_FLEN, em->em_msglen - EMT_SETSPI_FLEN, (caddr_t)&txd);
+
+ xd->amx_rpl = 1;
+ xd->amx_alen = txd.amx_alen;
+ xd->amx_bitmap = 0;
+ xd->amx_wnd = txd.amx_wnd;
+
+ realMD5Init(&(xd->amx_ictx));
+ realMD5Init(&(xd->amx_octx));
+
+ for (len = 0; len < AHHMACMD5_KMAX; len++)
+ txd.amx_key[len] ^= HMACMD5_IPAD_VAL;
+
+ MD5Update(&(xd->amx_ictx), txd.amx_key, AHHMACMD5_KMAX);
+
+ for (len = 0; len < AHHMACMD5_KMAX; len++)
+ txd.amx_key[len] ^= (HMACMD5_IPAD_VAL ^ HMACMD5_OPAD_VAL);
+
+ MD5Update(&(xd->amx_octx), txd.amx_key, AHHMACMD5_KMAX);
+ bzero(&txd, sizeof(struct ahhmacmd5_xencap));
+ bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
+
+ return 0;
+}
+
+/*
+ * Free memory
+ */
+
+int
+ahhmacmd5_zeroize(struct tdb *tdbp)
+{
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+/*
+ * ahhmacmd5_input() gets called to verify that an input packet
+ * passes authentication.
+ */
+
+extern struct ifnet loif;
+
+struct mbuf *
+ahhmacmd5_input(struct mbuf *m, struct tdb *tdb)
+{
+ struct ahhmacmd5_xdata *xd;
+ struct ip *ip, ipo;
+ struct ah *ah;
+ struct ahhmacmd5 aho, *ahp;
+ struct ifnet *rcvif;
+ int ohlen, len, count, off, ado, errc;
+ u_int64_t btsx;
+ struct mbuf *m0;
+ MD5_CTX ctx;
+
+ xd = (struct ahhmacmd5_xdata *)tdb->tdb_xdata;
+ ohlen = sizeof (struct ip) + AH_FLENGTH + xd->amx_alen;
+ if (xd->amx_wnd >= 0)
+ ohlen += HMACMD5_RPLENGTH;
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ahhmacmd5_input: receive interface is NULL!!!\n");
+#endif
+ rcvif = &loif;
+ }
+
+ if (m->m_len < ohlen)
+ {
+ if ((m = m_pullup(m, ohlen)) == NULL)
+ {
+ ahstat.ahs_hdrops++;
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ ah = (struct ah *)(ip + 1);
+ ahp = (struct ahhmacmd5 *)ah;
+
+ if (xd->amx_wnd >= 0)
+ ado = HMACMD5_RPLENGTH;
+ else
+ ado = 0;
+
+ if (ah->ah_hl != xd->amx_alen + ado)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ahhmacmd5_input: bad authenticator length\n");
+#endif
+ ahstat.ahs_badauthl++;
+ m_freem(m);
+ return NULL;
+ }
+
+ ipo = *ip;
+ ipo.ip_tos = 0;
+ ipo.ip_len += sizeof (struct ip); /* adjusted in ip_intr() */
+ HTONS(ipo.ip_len);
+ HTONS(ipo.ip_id);
+ ipo.ip_off = htons(ipo.ip_off & IP_DF); /* XXX -- and the C bit? */
+ ipo.ip_ttl = 0;
+ ipo.ip_sum = 0;
+
+ ctx = xd->amx_ictx;
+ MD5Update(&ctx, (unsigned char *)&ipo, sizeof (struct ip));
+ if (xd->amx_wnd >= 0)
+ MD5Update(&ctx, (unsigned char *)ahp, AH_FLENGTH + HMACMD5_RPLENGTH);
+ else
+ MD5Update(&ctx, (unsigned char *)ahp, AH_FLENGTH);
+ MD5Update(&ctx, ipseczeroes, xd->amx_alen);
+
+ /*
+ * Code shamelessly stolen from m_copydata
+ */
+ off = ohlen;
+ len = m->m_pkthdr.len - off;
+ m0 = m;
+
+ while (off > 0)
+ {
+ if (m0 == 0)
+ panic("ahhmacmd5_input: m_copydata (off)");
+ if (off < m0->m_len)
+ break;
+ off -= m0->m_len;
+ m0 = m0->m_next;
+ }
+
+ while (len > 0)
+ {
+ if (m0 == 0)
+ panic("ahhmacmd5_input: m_copydata (copy)");
+ count = min(m0->m_len - off, len);
+ MD5Update(&ctx, mtod(m0, unsigned char *) + off, count);
+ len -= count;
+ off = 0;
+ m0 = m0->m_next;
+ }
+
+ MD5Final((unsigned char *)(&(aho.ah_data[0])), &ctx);
+ ctx = xd->amx_octx;
+ MD5Update(&ctx, (unsigned char *)(&(aho.ah_data[0])), HMACMD5_HASHLEN);
+ MD5Final((unsigned char *)(&(aho.ah_data[0])), &ctx);
+
+ if (bcmp(aho.ah_data, ah->ah_data + ado, xd->amx_alen))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ahhmacmd5_input: bad auth\n"); /* XXX */
+#endif
+ ahstat.ahs_badauth++;
+ m_freem(m);
+ return NULL;
+ }
+
+ if (xd->amx_wnd >= 0)
+ {
+ btsx = ntohq(ahp->ah_rpl);
+ if ((errc = checkreplaywindow64(btsx, &(xd->amx_rpl),
+ xd->amx_wnd, &(xd->amx_bitmap)))
+ != 0)
+ {
+ switch(errc)
+ {
+ case 1:
+#ifdef ENCDEBUG
+ printf("ahhmacmd5_input: replay counter wrapped\n");
+#endif
+ ahstat.ahs_wrap++;
+ break;
+ case 2:
+#ifdef ENCDEBUG
+ printf("ahhmacmd5_input: received old packet\n");
+#endif
+ ahstat.ahs_replay++;
+ break;
+ case 3:
+#ifdef ENCDEBUG
+ printf("ahhmacmd5_input: packet already received\n");
+#endif
+ ahstat.ahs_replay++;
+ break;
+ }
+ m_freem(m);
+ return NULL;
+ }
+ }
+
+ ipo = *ip;
+ ipo.ip_p = ah->ah_nh;
+
+ m->m_len -= (ohlen - sizeof(struct ip));
+ m->m_data += (ohlen - sizeof(struct ip));
+ m->m_pkthdr.len -= (ohlen - sizeof(struct ip));
+ m->m_pkthdr.rcvif = rcvif; /* this should not be necessary */
+
+ ip = mtod(m, struct ip *);
+ *ip = ipo;
+ ip->ip_len = htons(ip->ip_len - ohlen + 2 * sizeof (struct ip));
+ HTONS(ip->ip_id);
+ HTONS(ip->ip_off);
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(m, sizeof (struct ip));
+
+ return m;
+}
+
+
+#define AHXPORT
+
+int
+ahhmacmd5_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb, struct mbuf **mp)
+{
+ struct ahhmacmd5_xdata *xd;
+ struct ip *ip, ipo;
+ struct ah *ah;
+ struct ahhmacmd5 *ahp, aho;
+ register int len, off, count;
+ register struct mbuf *m0;
+ MD5_CTX ctx;
+ int ilen, ohlen;
+
+
+ m = m_pullup(m, sizeof (struct ip));
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+
+ xd = (struct ahhmacmd5_xdata *)tdb->tdb_xdata;
+
+ ilen = ntohs(ip->ip_len);
+
+#ifdef AHXPORT
+ ohlen = AH_FLENGTH + xd->amx_alen;
+#else
+ ohlen = sizeof (struct ip) + AH_FLENGTH + xd->amx_alen;
+#endif
+ if (xd->amx_wnd >= 0)
+ ohlen += HMACMD5_RPLENGTH;
+
+ ipo.ip_v = IPVERSION;
+ ipo.ip_hl = 5;
+ ipo.ip_tos = 0;
+ ipo.ip_len = htons(ohlen + ilen);
+ ipo.ip_id = ip->ip_id;
+ ipo.ip_off = htons(ntohs(ip->ip_off) & IP_DF);
+ ipo.ip_ttl = 0;
+ ipo.ip_p = IPPROTO_AH;
+ ipo.ip_sum = 0;
+#ifdef AHXPORT
+ ipo.ip_src = ip->ip_src;
+ ipo.ip_dst = ip->ip_dst;
+ aho.ah_nh = ip->ip_p;
+#else
+ ipo.ip_src = gw->sen_ipsp_src;
+ ipo.ip_dst = gw->sen_ipsp_dst;
+ aho.ah_nh = IPPROTO_IP4;
+#endif
+ aho.ah_hl = (xd->amx_alen >> 2);
+ if (xd->amx_wnd >= 0)
+ aho.ah_hl += (HMACMD5_RPLENGTH / sizeof(u_int32_t));
+ aho.ah_rv = 0;
+ aho.ah_spi = tdb->tdb_spi;
+
+ if (xd->amx_wnd >= 0)
+ {
+ if (xd->amx_rpl == 0)
+ {
+#ifdef ENCDEBUG
+ printf("ahhmacmd5_output: key should have changed long ago\n");
+#endif
+ ahstat.ahs_wrap++;
+ return NULL;
+ }
+ }
+
+ aho.ah_rpl = htonq(xd->amx_rpl++);
+
+ ctx = xd->amx_ictx;
+ MD5Update(&ctx, (unsigned char *)&ipo, sizeof (struct ip));
+ if (xd->amx_wnd >= 0)
+ MD5Update(&ctx, (unsigned char *)&aho, AH_FLENGTH + HMACMD5_RPLENGTH);
+ else
+ MD5Update(&ctx, (unsigned char *)&aho, AH_FLENGTH);
+ MD5Update(&ctx, ipseczeroes, xd->amx_alen);
+
+#ifdef AHXPORT
+ off = sizeof (struct ip);
+#else
+ off = 0;
+#endif
+
+ /*
+ * Code shamelessly stolen from m_copydata
+ */
+ len = m->m_pkthdr.len - off;
+
+ m0 = m;
+
+ while (len > 0)
+ {
+ if (m0 == 0)
+ panic("ahhmacmd5_output: m_copydata");
+ count = min(m0->m_len - off, len);
+ MD5Update(&ctx, mtod(m0, unsigned char *) + off, count);
+
+ len -= count;
+ off = 0;
+ m0 = m0->m_next;
+ }
+
+ MD5Final((unsigned char *)(&(aho.ah_data[0])), &ctx);
+ ctx = xd->amx_octx;
+ MD5Update(&ctx, (unsigned char *)(&(aho.ah_data[0])), HMACMD5_HASHLEN);
+ MD5Final((unsigned char *)(&(aho.ah_data[0])), &ctx);
+
+ ipo.ip_tos = ip->ip_tos;
+ ipo.ip_id = ip->ip_id;
+ ipo.ip_off = ip->ip_off;
+ ipo.ip_ttl = ip->ip_ttl;
+/* ipo.ip_len = ntohs(ipo.ip_len); */
+
+ M_PREPEND(m, ohlen, M_DONTWAIT);
+ if (m == NULL)
+ return ENOBUFS;
+
+ m = m_pullup(m, ohlen + sizeof (struct ip));
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+ ah = (struct ah *)(ip + 1);
+ ahp = (struct ahhmacmd5 *)ah;
+ *ip = ipo;
+ ah->ah_nh = aho.ah_nh;
+ ah->ah_hl = aho.ah_hl;
+ ah->ah_rv = aho.ah_rv;
+ ah->ah_spi = aho.ah_spi;
+ if (xd->amx_wnd >= 0)
+ {
+ ahp->ah_rpl = aho.ah_rpl;
+ bcopy((unsigned char *)(&(aho.ah_data[0])),
+ ahp->ah_data, xd->amx_alen);
+ }
+ else
+ bcopy((unsigned char *)(&(aho.ah_data[0])),
+ ah->ah_data, xd->amx_alen);
+
+ *mp = m;
+
+ return 0;
+}
diff --git a/sys/netinet/ip_ahhmacsha1.c b/sys/netinet/ip_ahhmacsha1.c
new file mode 100644
index 00000000000..af306827e7c
--- /dev/null
+++ b/sys/netinet/ip_ahhmacsha1.c
@@ -0,0 +1,463 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Based on draft-ietf-ipsec-ah-hmac-sha-04.txt.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#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>
+
+#include <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_ah.h>
+
+/*
+ * ahhmacsha1_attach() is called from the transformation initialization code.
+ * It just returns.
+ */
+
+int
+ahhmacsha1_attach()
+{
+ return 0;
+}
+
+/*
+ * ahhmacsha1_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data.
+ */
+
+int
+ahhmacsha1_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ struct ahhmacsha1_xdata *xd;
+ struct ahhmacsha1_xencap txd;
+ struct encap_msghdr *em;
+ int len;
+
+ tdbp->tdb_xform = xsp;
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof (struct ahhmacsha1_xdata),
+ M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ return ENOBUFS;
+ bzero(tdbp->tdb_xdata, sizeof (struct ahhmacsha1_xdata));
+ bzero(&txd, sizeof(struct ahhmacsha1_xencap));
+ xd = (struct ahhmacsha1_xdata *)tdbp->tdb_xdata;
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI_FLEN > sizeof (struct ahhmacsha1_xencap))
+ {
+ free((caddr_t)tdbp->tdb_xdata, M_XDATA);
+ tdbp->tdb_xdata = NULL;
+ return EINVAL;
+ }
+
+ m_copydata(m, EMT_SETSPI_FLEN, em->em_msglen - EMT_SETSPI_FLEN, (caddr_t)&txd);
+
+ xd->amx_rpl = 1;
+ xd->amx_alen = txd.amx_alen;
+ xd->amx_bitmap = 0;
+ xd->amx_wnd = txd.amx_wnd;
+
+ SHA1Init(&(xd->amx_ictx));
+ SHA1Init(&(xd->amx_octx));
+
+ for (len = 0; len < AHHMACSHA1_KMAX; len++)
+ txd.amx_key[len] ^= HMACSHA1_IPAD_VAL;
+
+ SHA1Update(&(xd->amx_ictx), txd.amx_key, AHHMACSHA1_KMAX);
+
+ for (len = 0; len < AHHMACSHA1_KMAX; len++)
+ txd.amx_key[len] ^= (HMACSHA1_IPAD_VAL ^ HMACSHA1_OPAD_VAL);
+
+ SHA1Update(&(xd->amx_octx), txd.amx_key, AHHMACSHA1_KMAX);
+ bzero(&txd, sizeof(struct ahhmacsha1_xencap));
+ bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
+
+ return 0;
+}
+
+/*
+ * Free memory
+ */
+
+int
+ahhmacsha1_zeroize(struct tdb *tdbp)
+{
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+/*
+ * ahhmacsha1_input() gets called to verify that an input packet
+ * passes authentication.
+ */
+
+extern struct ifnet loif;
+
+struct mbuf *
+ahhmacsha1_input(struct mbuf *m, struct tdb *tdb)
+{
+ struct ahhmacsha1_xdata *xd;
+ struct ip *ip, ipo;
+ struct ah *ah;
+ struct ahhmacsha1 aho, *ahp;
+ struct ifnet *rcvif;
+ int ohlen, len, count, off, ado, errc;
+ u_int64_t btsx;
+ struct mbuf *m0;
+ SHA1_CTX ctx;
+
+ xd = (struct ahhmacsha1_xdata *)tdb->tdb_xdata;
+ ohlen = sizeof (struct ip) + AH_FLENGTH + xd->amx_alen;
+ if (xd->amx_wnd >= 0)
+ ohlen += HMACSHA1_RPLENGTH;
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ahhmacsha1_input: receive interface is NULL!!!\n");
+#endif
+ rcvif = &loif;
+ }
+
+ if (m->m_len < ohlen)
+ {
+ if ((m = m_pullup(m, ohlen)) == NULL)
+ {
+ ahstat.ahs_hdrops++;
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ ah = (struct ah *)(ip + 1);
+ ahp = (struct ahhmacsha1 *)ah;
+
+ if (xd->amx_wnd >= 0)
+ ado = HMACSHA1_RPLENGTH;
+ else
+ ado = 0;
+
+ if (ah->ah_hl != xd->amx_alen + ado)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ahhmacsha1_input: bad authenticator length\n");
+#endif
+ ahstat.ahs_badauthl++;
+ m_freem(m);
+ return NULL;
+ }
+
+ ipo = *ip;
+ ipo.ip_tos = 0;
+ ipo.ip_len += sizeof (struct ip); /* adjusted in ip_intr() */
+ HTONS(ipo.ip_len);
+ HTONS(ipo.ip_id);
+ ipo.ip_off = htons(ipo.ip_off & IP_DF); /* XXX -- and the C bit? */
+ ipo.ip_ttl = 0;
+ ipo.ip_sum = 0;
+
+ ctx = xd->amx_ictx;
+ SHA1Update(&ctx, (unsigned char *)&ipo, sizeof (struct ip));
+ if (xd->amx_wnd >= 0)
+ SHA1Update(&ctx, (unsigned char *)ahp,
+ AH_FLENGTH + HMACSHA1_RPLENGTH);
+ else
+ SHA1Update(&ctx, (unsigned char *)ahp, AH_FLENGTH);
+ SHA1Update(&ctx, ipseczeroes, xd->amx_alen);
+
+ /*
+ * Code shamelessly stolen from m_copydata
+ */
+ off = ohlen;
+ len = m->m_pkthdr.len - off;
+ m0 = m;
+
+ while (off > 0)
+ {
+ if (m0 == 0)
+ panic("ahhmacsha1_input: m_copydata (off)");
+ if (off < m0->m_len)
+ break;
+ off -= m0->m_len;
+ m0 = m0->m_next;
+ }
+
+ while (len > 0)
+ {
+ if (m0 == 0)
+ panic("ahhmacsha1_input: m_copydata (copy)");
+ count = min(m0->m_len - off, len);
+ SHA1Update(&ctx, mtod(m0, unsigned char *) + off, count);
+ len -= count;
+ off = 0;
+ m0 = m0->m_next;
+ }
+
+ SHA1Final((unsigned char *)(&(aho.ah_data[0])), &ctx);
+ ctx = xd->amx_octx;
+ SHA1Update(&ctx, (unsigned char *)(&(aho.ah_data[0])),
+ HMACSHA1_HASHLEN);
+ SHA1Final((unsigned char *)(&(aho.ah_data[0])), &ctx);
+
+ if (bcmp(aho.ah_data, ah->ah_data + ado, xd->amx_alen))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ahhmacsha1_input: bad auth\n"); /* XXX */
+#endif
+ ahstat.ahs_badauth++;
+ m_freem(m);
+ return NULL;
+ }
+
+ if (xd->amx_wnd >= 0)
+ {
+ btsx = ntohq(ahp->ah_rpl);
+ if ((errc = checkreplaywindow64(btsx, &(xd->amx_rpl),
+ xd->amx_wnd, &(xd->amx_bitmap)))
+ != 0)
+ {
+ switch(errc)
+ {
+ case 1:
+#ifdef ENCDEBUG
+ printf("ahhmacsha1_input: replay counter wrapped\n");
+#endif
+ ahstat.ahs_wrap++;
+ break;
+ case 2:
+#ifdef ENCDEBUG
+ printf("ahhmacsha1_input: received old packet\n");
+#endif
+ ahstat.ahs_replay++;
+ break;
+ case 3:
+#ifdef ENCDEBUG
+ printf("ahhmacsha1_input: packet already received\n");
+#endif
+ ahstat.ahs_replay++;
+ break;
+ }
+ m_freem(m);
+ return NULL;
+ }
+ }
+
+ ipo = *ip;
+ ipo.ip_p = ah->ah_nh;
+
+ m->m_len -= (ohlen - sizeof(struct ip));
+ m->m_data += (ohlen - sizeof(struct ip));
+ m->m_pkthdr.len -= (ohlen - sizeof(struct ip));
+ m->m_pkthdr.rcvif = rcvif; /* this should not be necessary */
+
+ ip = mtod(m, struct ip *);
+ *ip = ipo;
+ ip->ip_len = htons(ip->ip_len - ohlen + 2 * sizeof (struct ip));
+ HTONS(ip->ip_id);
+ HTONS(ip->ip_off);
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(m, sizeof (struct ip));
+
+ return m;
+}
+
+
+#define AHXPORT
+
+int
+ahhmacsha1_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb, struct mbuf **mp)
+{
+ struct ahhmacsha1_xdata *xd;
+ struct ip *ip, ipo;
+ struct ah *ah;
+ struct ahhmacsha1 *ahp, aho;
+ register int len, off, count;
+ register struct mbuf *m0;
+ SHA1_CTX ctx;
+ int ilen, ohlen;
+
+
+ m = m_pullup(m, sizeof (struct ip));
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+
+ xd = (struct ahhmacsha1_xdata *)tdb->tdb_xdata;
+
+ ilen = ntohs(ip->ip_len);
+
+#ifdef AHXPORT
+ ohlen = AH_FLENGTH + xd->amx_alen;
+#else
+ ohlen = sizeof (struct ip) + AH_FLENGTH + xd->amx_alen;
+#endif
+ if (xd->amx_wnd >= 0)
+ ohlen += HMACSHA1_RPLENGTH;
+
+ ipo.ip_v = IPVERSION;
+ ipo.ip_hl = 5;
+ ipo.ip_tos = 0;
+ ipo.ip_len = htons(ohlen + ilen);
+ ipo.ip_id = ip->ip_id;
+ ipo.ip_off = htons(ntohs(ip->ip_off) & IP_DF);
+ ipo.ip_ttl = 0;
+ ipo.ip_p = IPPROTO_AH;
+ ipo.ip_sum = 0;
+#ifdef AHXPORT
+ ipo.ip_src = ip->ip_src;
+ ipo.ip_dst = ip->ip_dst;
+ aho.ah_nh = ip->ip_p;
+#else
+ ipo.ip_src = gw->sen_ipsp_src;
+ ipo.ip_dst = gw->sen_ipsp_dst;
+ aho.ah_nh = IPPROTO_IP4;
+#endif
+ aho.ah_hl = (xd->amx_alen >> 2);
+ if (xd->amx_wnd >= 0)
+ aho.ah_hl += (HMACSHA1_RPLENGTH / sizeof(u_int32_t));
+ aho.ah_rv = 0;
+ aho.ah_spi = tdb->tdb_spi;
+
+ if (xd->amx_wnd >= 0)
+ {
+ if (xd->amx_rpl == 0)
+ {
+#ifdef ENCDEBUG
+ printf("ahhmacsha1_output: key should have changed long ago\n");
+#endif
+ ahstat.ahs_wrap++;
+ return NULL;
+ }
+ }
+
+ aho.ah_rpl = htonq(xd->amx_rpl++);
+
+ ctx = xd->amx_ictx;
+ SHA1Update(&ctx, (unsigned char *)&ipo, sizeof (struct ip));
+ if (xd->amx_wnd >= 0)
+ SHA1Update(&ctx, (unsigned char *)&aho,
+ AH_FLENGTH + HMACSHA1_RPLENGTH);
+ else
+ SHA1Update(&ctx, (unsigned char *)&aho, AH_FLENGTH);
+ SHA1Update(&ctx, ipseczeroes, xd->amx_alen);
+
+#ifdef AHXPORT
+ off = sizeof (struct ip);
+#else
+ off = 0;
+#endif
+
+ /*
+ * Code shamelessly stolen from m_copydata
+ */
+ len = m->m_pkthdr.len - off;
+
+ m0 = m;
+
+ while (len > 0)
+ {
+ if (m0 == 0)
+ panic("ahhmacsha1_output: m_copydata");
+ count = min(m0->m_len - off, len);
+ SHA1Update(&ctx, mtod(m0, unsigned char *) + off, count);
+
+ len -= count;
+ off = 0;
+ m0 = m0->m_next;
+ }
+
+ SHA1Final((unsigned char *)(&(aho.ah_data[0])), &ctx);
+ ctx = xd->amx_octx;
+ SHA1Update(&ctx, (unsigned char *)(&(aho.ah_data[0])),
+ HMACSHA1_HASHLEN);
+ SHA1Final((unsigned char *)(&(aho.ah_data[0])), &ctx);
+
+ ipo.ip_tos = ip->ip_tos;
+ ipo.ip_id = ip->ip_id;
+ ipo.ip_off = ip->ip_off;
+ ipo.ip_ttl = ip->ip_ttl;
+/* ipo.ip_len = ntohs(ipo.ip_len); */
+
+ M_PREPEND(m, ohlen, M_DONTWAIT);
+ if (m == NULL)
+ return ENOBUFS;
+
+ m = m_pullup(m, ohlen + sizeof (struct ip));
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+ ah = (struct ah *)(ip + 1);
+ ahp = (struct ahhmacsha1 *)ah;
+ *ip = ipo;
+ ah->ah_nh = aho.ah_nh;
+ ah->ah_hl = aho.ah_hl;
+ ah->ah_rv = aho.ah_rv;
+ ah->ah_spi = aho.ah_spi;
+ if (xd->amx_wnd >= 0)
+ {
+ ahp->ah_rpl = aho.ah_rpl;
+ bcopy((unsigned char *)(&(aho.ah_data[0])),
+ ahp->ah_data, xd->amx_alen);
+ }
+ else
+ bcopy((unsigned char *)(&(aho.ah_data[0])),
+ ah->ah_data, xd->amx_alen);
+
+ *mp = m;
+
+ return 0;
+}
diff --git a/sys/netinet/ip_ahmd5.c b/sys/netinet/ip_ahmd5.c
new file mode 100644
index 00000000000..27429cb5fa1
--- /dev/null
+++ b/sys/netinet/ip_ahmd5.c
@@ -0,0 +1,353 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Authentication Header Processing
+ * Per RFC1828 (Metzger & Simpson, 1995)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#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>
+
+#include <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_ah.h>
+
+/*
+ * ahmd5_attach() is called from the transformation initialization code.
+ * It just returns.
+ */
+
+int
+ahmd5_attach()
+{
+ return 0;
+}
+
+/*
+ * ahmd5_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data.
+ */
+
+int
+ahmd5_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ struct ahmd5_xdata *xd;
+ struct encap_msghdr *em;
+
+ tdbp->tdb_xform = xsp;
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof (struct ahmd5_xdata),
+ M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ return ENOBUFS;
+ bzero(tdbp->tdb_xdata, sizeof (struct ahmd5_xdata));
+ xd = (struct ahmd5_xdata *)tdbp->tdb_xdata;
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI_FLEN > sizeof (struct ahmd5_xdata))
+ {
+ free((caddr_t)tdbp->tdb_xdata, M_XDATA);
+ tdbp->tdb_xdata = NULL;
+ return EINVAL;
+ }
+ m_copydata(m, EMT_SETSPI_FLEN, em->em_msglen - EMT_SETSPI_FLEN, (caddr_t)xd);
+ bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
+ return 0;
+}
+
+/*
+ * Free memory
+ */
+
+int
+ahmd5_zeroize(struct tdb *tdbp)
+{
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+/*
+ * ahmd5_input() gets called to verify that an input packet
+ * passes authentication.
+ */
+
+extern struct ifnet loif;
+
+struct mbuf *
+ahmd5_input(struct mbuf *m, struct tdb *tdb)
+{
+ struct ahmd5_xdata *xd;
+ struct ip *ip, ipo;
+ struct ah *ah;
+ struct ahmd5 aho;
+ struct ifnet *rcvif;
+ int ohlen, len, count, off;
+ struct mbuf *m0;
+ MD5_CTX ctx;
+
+ xd = (struct ahmd5_xdata *)tdb->tdb_xdata;
+ ohlen = sizeof (struct ip) + AH_FLENGTH + xd->amx_alen;
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ahmd5_input: receive interface is NULL!!!\n");
+#endif
+ rcvif = &loif;
+ }
+
+ if (m->m_len < ohlen)
+ {
+ if ((m = m_pullup(m, ohlen)) == NULL)
+ {
+ ahstat.ahs_hdrops++;
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ ah = (struct ah *)(ip + 1);
+
+ ipo = *ip;
+ ipo.ip_tos = 0;
+ ipo.ip_len += sizeof (struct ip); /* adjusted in ip_intr() */
+ HTONS(ipo.ip_len);
+ HTONS(ipo.ip_id);
+ ipo.ip_off = htons(ipo.ip_off & IP_DF); /* XXX -- and the C bit? */
+ ipo.ip_ttl = 0;
+ ipo.ip_sum = 0;
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char *)xd->amx_key, xd->amx_klen);
+ MD5Final(NULL, &ctx); /* non-std usage of MD5Final! */
+ MD5Update(&ctx, (unsigned char *)&ipo, sizeof (struct ip));
+ MD5Update(&ctx, (unsigned char *)ah, AH_FLENGTH);
+ MD5Update(&ctx, ipseczeroes, xd->amx_alen);
+
+ /*
+ * Code shamelessly stolen from m_copydata
+ */
+ off = ohlen;
+ len = m->m_pkthdr.len - off;
+ m0 = m;
+
+ while (off > 0)
+ {
+ if (m0 == 0)
+ panic("ahmd5_input: m_copydata (off)");
+ if (off < m0->m_len)
+ break;
+ off -= m0->m_len;
+ m0 = m0->m_next;
+ }
+
+ while (len > 0)
+ {
+ if (m0 == 0)
+ panic("ahmd5_input: m_copydata (copy)");
+ count = min(m0->m_len - off, len);
+ MD5Update(&ctx, mtod(m0, unsigned char *) + off, count);
+ len -= count;
+ off = 0;
+ m0 = m0->m_next;
+ }
+
+
+ MD5Update(&ctx, (unsigned char *)xd->amx_key, xd->amx_klen);
+ MD5Final((unsigned char *)(&(aho.ah_data[0])), &ctx);
+
+ if (bcmp(aho.ah_data, ah->ah_data, xd->amx_alen))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ahmd5_input: bad auth\n"); /* XXX */
+#endif
+ ahstat.ahs_badauth++;
+ m_freem(m);
+ return NULL;
+ }
+
+ ipo = *ip;
+ ipo.ip_p = ah->ah_nh;
+
+ m->m_len -= (ohlen - sizeof(struct ip));
+ m->m_data += (ohlen - sizeof(struct ip));
+ m->m_pkthdr.len -= (ohlen - sizeof(struct ip));
+ m->m_pkthdr.rcvif = rcvif; /* this should not be necessary */
+
+ ip = mtod(m, struct ip *);
+ *ip = ipo;
+ ip->ip_len = htons(ip->ip_len - ohlen + 2 * sizeof (struct ip));
+ HTONS(ip->ip_id);
+ HTONS(ip->ip_off);
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(m, sizeof (struct ip));
+
+ return m;
+}
+
+
+#define AHXPORT
+
+int
+ahmd5_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb, struct mbuf **mp)
+{
+ struct ahmd5_xdata *xd;
+ struct ip *ip, ipo;
+ struct ah *ah, aho;
+ register int len, off, count;
+ register struct mbuf *m0;
+
+ MD5_CTX ctx;
+
+ int ilen, ohlen;
+
+
+ m = m_pullup(m, sizeof (struct ip));
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+
+ xd = (struct ahmd5_xdata *)tdb->tdb_xdata;
+
+ ilen = ntohs(ip->ip_len);
+
+#ifdef AHXPORT
+ ohlen = AH_FLENGTH + xd->amx_alen;
+#else
+ ohlen = sizeof (struct ip) + AH_FLENGTH + xd->amx_alen;
+#endif
+
+ ipo.ip_v = IPVERSION;
+ ipo.ip_hl = 5;
+ ipo.ip_tos = 0;
+ ipo.ip_len = htons(ohlen + ilen);
+ ipo.ip_id = ip->ip_id;
+ ipo.ip_off = htons(ntohs(ip->ip_off) & IP_DF);
+ ipo.ip_ttl = 0;
+ ipo.ip_p = IPPROTO_AH;
+ ipo.ip_sum = 0;
+#ifdef AHXPORT
+ ipo.ip_src = ip->ip_src;
+ ipo.ip_dst = ip->ip_dst;
+ aho.ah_nh = ip->ip_p;
+#else
+ ipo.ip_src = gw->sen_ipsp_src;
+ ipo.ip_dst = gw->sen_ipsp_dst;
+ aho.ah_nh = IPPROTO_IP4;
+#endif
+ aho.ah_hl = xd->amx_alen >> 2;
+ aho.ah_rv = 0;
+ aho.ah_spi = tdb->tdb_spi;
+
+ realMD5Init(&ctx);
+
+ MD5Update(&ctx, (unsigned char *)xd->amx_key, xd->amx_klen);
+ MD5Final(NULL, &ctx);
+ MD5Update(&ctx, (unsigned char *)&ipo, sizeof (struct ip));
+ MD5Update(&ctx, (unsigned char *)&aho, AH_FLENGTH);
+ MD5Update(&ctx, ipseczeroes, xd->amx_alen);
+
+#ifdef AHXPORT
+ off = sizeof (struct ip);
+#else
+ off = 0;
+#endif
+
+ /*
+ * Code shamelessly stolen from m_copydata
+ */
+ len = m->m_pkthdr.len - off;
+
+ m0 = m;
+
+ while (len > 0)
+ {
+ if (m0 == 0)
+ panic("ahmd5_output: m_copydata");
+ count = min(m0->m_len - off, len);
+ MD5Update(&ctx, mtod(m0, unsigned char *) + off, count);
+ len -= count;
+ off = 0;
+ m0 = m0->m_next;
+ }
+
+ MD5Update(&ctx, (unsigned char *)xd->amx_key, xd->amx_klen);
+
+ ipo.ip_tos = ip->ip_tos;
+ ipo.ip_id = ip->ip_id;
+ ipo.ip_off = ip->ip_off;
+ ipo.ip_ttl = ip->ip_ttl;
+/* ipo.ip_len = ntohs(ipo.ip_len); */
+
+ M_PREPEND(m, ohlen, M_DONTWAIT);
+ if (m == NULL)
+ return ENOBUFS;
+
+ m = m_pullup(m, ohlen + sizeof (struct ip));
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+ ah = (struct ah *)(ip + 1);
+ *ip = ipo;
+ ah->ah_nh = aho.ah_nh;
+ ah->ah_hl = aho.ah_hl;
+ ah->ah_rv = aho.ah_rv;
+ ah->ah_spi = aho.ah_spi;
+
+
+ MD5Final(&(ah->ah_data[0]), &ctx);
+
+ *mp = m;
+
+ return 0;
+}
diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c
new file mode 100644
index 00000000000..13541d3b59e
--- /dev/null
+++ b/sys/netinet/ip_esp.c
@@ -0,0 +1,158 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Encapsulation Security Payload Processing
+ * Per RFC1827 (Atkinson, 1995)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#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 <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_esp.h>
+
+/*
+ * esp_input gets called when we receive an packet with an ESP.
+ */
+
+void
+esp_input(register struct mbuf *m, int iphlen)
+{
+ struct ip *ipo;
+ struct ifqueue *ifq = NULL;
+ int s;
+ u_long spi;
+ struct tdb *tdbp;
+
+ /*
+ * Strip IP options, if any.
+ */
+
+ if (iphlen > sizeof (struct ip))
+ {
+ ip_stripoptions(m, (struct mbuf *)0);
+ iphlen = sizeof (struct ip);
+ }
+
+ /*
+ * Make sure that at least the SPI is in the same mbuf
+ */
+
+ ipo = mtod(m, struct ip *);
+ if (m->m_len < iphlen + ESP_FLENGTH)
+ {
+ if ((m = m_pullup(m, iphlen + ESP_FLENGTH)) == 0)
+ {
+ espstat.esps_hdrops++;
+ return;
+ }
+ ipo = mtod(m, struct ip *);
+ }
+ spi = *((u_long *)((caddr_t)ipo + iphlen));
+
+ /*
+ * Find tunnel control block and (indirectly) call the appropriate
+ * kernel crypto routine. The resulting mbuf chain is a valid
+ * IP packet ready to go through input processing.
+ */
+
+ tdbp = gettdb(spi, ipo->ip_dst);
+ if (tdbp == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_input: no tdb for spi=%x\n", spi);
+#endif ENCDEBUG
+ m_freem(m);
+ espstat.esps_notdb++;
+ return;
+ }
+
+ if (tdbp->tdb_xform == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_input: no xform for spi=%x\n", spi);
+#endif ENCDEBUG
+ m_freem(m);
+ espstat.esps_noxform++;
+ return;
+ }
+
+ m->m_pkthdr.rcvif = tdbp->tdb_rcvif;
+
+ m = (*(tdbp->tdb_xform->xf_input))(m, tdbp);
+
+ if (m == NULL)
+ {
+ espstat.esps_badkcr++;
+ return;
+ }
+
+ /*
+ * Interface pointer is already in first mbuf; chop off the
+ * `outer' header and reschedule.
+ */
+
+ ifq = &ipintrq;
+
+ s = splimp(); /* isn't it already? */
+ if (IF_QFULL(ifq))
+ {
+ IF_DROP(ifq);
+ m_freem(m);
+ espstat.esps_qfull++;
+ splx(s);
+ return;
+ }
+ IF_ENQUEUE(ifq, m);
+ schednetisr(NETISR_IP);
+ splx(s);
+ return;
+}
diff --git a/sys/netinet/ip_esp.h b/sys/netinet/ip_esp.h
new file mode 100644
index 00000000000..abd2abf1f62
--- /dev/null
+++ b/sys/netinet/ip_esp.h
@@ -0,0 +1,179 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Encapsulation Security Payload Processing
+ * Per RFC1827 (Atkinson, 1995)
+ */
+
+#ifndef _MD5_H_
+#include <netinet/ip_md5.h>
+#endif
+
+#define ESPDESMD5_KEYSZ 64
+#define ESPDESMD5_IVS 8
+#define ESPDESMD5_ALEN 16
+#define ESPDESMD5_IPAD_VAL 0x36
+#define ESPDESMD5_OPAD_VAL 0x5C
+#define ESPDESMD5_DESBLK 8
+#define ESPDESMD5_RPLENGTH 4
+#define ESPDESMD5_DPADI 0x5C
+#define ESPDESMD5_DPADR 0x3A
+#define ESPDESMD5_IPADI 0xAC
+#define ESPDESMD5_IPADR 0x55
+#define ESPDESMD5_HPADI 0x53
+#define ESPDESMD5_HPADR 0x3C
+#define ESPDESMD5_RPADI 0x35
+#define ESPDESMD5_RPADR 0xCC
+
+#define ESP3DESMD5_KEYSZ 64
+#define ESP3DESMD5_IVS 8
+#define ESP3DESMD5_ALEN 16
+#define ESP3DESMD5_IPAD_VAL 0x36
+#define ESP3DESMD5_OPAD_VAL 0x5C
+#define ESP3DESMD5_DESBLK 8
+#define ESP3DESMD5_RPLENGTH 4
+#define ESP3DESMD5_DPADI 0x5C
+#define ESP3DESMD5_DPADR 0x3A
+#define ESP3DESMD5_IPADI 0xAC
+#define ESP3DESMD5_IPADR 0x55
+#define ESP3DESMD5_HPADI 0x53
+#define ESP3DESMD5_HPADR 0x3C
+#define ESP3DESMD5_RPADI 0x35
+#define ESP3DESMD5_RPADR 0xCC
+
+struct esp
+{
+ u_int32_t esp_spi; /* Security Parameters Index */
+ u_int8_t esp_iv[8]; /* iv[4] may actually be data! */
+};
+
+struct espstat
+{
+ u_long esps_hdrops; /* packet shorter than header shows */
+ u_long esps_notdb;
+ u_long esps_badkcr;
+ u_long esps_qfull;
+ u_long esps_noxform;
+ u_long esps_badilen;
+ u_long esps_wrap; /* Replay counter wrapped around */
+ u_long esps_badauth; /* Only valid for transforms with auth */
+ u_long esps_replay; /* Possible packet replay detected */
+};
+
+struct espdes_xdata
+{
+ int32_t edx_ivlen; /* 4 or 8 */
+ union
+ {
+ u_int8_t Iv[8]; /* that's enough space */
+ u_int32_t Ivl; /* XXX make sure this is 4 bytes */
+ u_int64_t Ivq; /* XXX make sure this is 8 bytes! */
+ }Iu;
+#define edx_iv Iu.Iv
+#define edx_ivl Iu.Ivl
+#define edx_ivq Iu.Ivq
+ union
+ {
+ u_int8_t Rk[8];
+ u_int32_t Eks[16][2];
+ }Xu;
+#define edx_rk Xu.Rk
+#define edx_eks Xu.Eks
+};
+
+struct esp3desmd5_xencap
+{
+ int8_t edx_ivlen; /* 0 or 8 */
+ int8_t edx_initiator; /* 1 if setting an I key */
+ u_int16_t edx_keylen;
+ u_int32_t edx_wnd;
+ u_int8_t edx_ivv[ESP3DESMD5_IVS];
+ u_int8_t edx_key[ESP3DESMD5_KEYSZ];
+};
+
+struct espdesmd5_xencap
+{
+ int8_t edx_ivlen; /* 0 or 8 */
+ int8_t edx_initiator; /* 1 if setting an I key */
+ u_int16_t edx_keylen;
+ u_int32_t edx_wnd;
+ u_int8_t edx_ivv[ESPDESMD5_IVS];
+ u_int8_t edx_key[ESPDESMD5_KEYSZ];
+};
+
+#define ESPDESMD5_ULENGTH 8+ESPDESMD5_IVS+ESPDESMD5_KEYSZ
+#define ESP3DESMD5_ULENGTH 8+ESP3DESMD5_IVS+ESP3DESMD5_KEYSZ
+
+struct espdesmd5_xdata
+{
+ int32_t edx_ivlen; /* 0 or 8 */
+ u_int32_t edx_rpl; /* Replay counter */
+ u_int32_t edx_wnd; /* Replay window */
+ u_int32_t edx_bitmap;
+ u_int32_t edx_initial; /* initial replay value */
+ union
+ {
+ u_int8_t Iv[8]; /* that's enough space */
+ u_int32_t Ivl; /* XXX make sure this is 4 bytes */
+ u_int64_t Ivq; /* XXX make sure this is 8 bytes! */
+ }Iu;
+ union
+ {
+ u_int8_t Rk[8];
+ u_int32_t Eks[16][2];
+ }Xu;
+ MD5_CTX edx_ictx;
+ MD5_CTX edx_octx;
+};
+
+struct esp3desmd5_xdata
+{
+ int32_t edx_ivlen; /* 0 or 4 or 8 */
+ u_int32_t edx_rpl; /* Replay counter */
+ u_int32_t edx_wnd; /* Replay window */
+ u_int32_t edx_bitmap;
+ u_int32_t edx_initial;
+ union
+ {
+ u_int8_t Iv[8]; /* that's enough space */
+ u_int32_t Ivl; /* XXX make sure this is 4 bytes */
+ u_int64_t Ivq; /* XXX make sure this is 8 bytes! */
+ }Iu;
+ union
+ {
+ u_int8_t Rk[3][8];
+ u_int32_t Eks[3][16][2];
+ }Xu;
+ MD5_CTX edx_ictx;
+ MD5_CTX edx_octx;
+};
+
+#define ESP_FLENGTH 12
+#define ESP_ULENGTH 20 /* coming from user mode */
+
+#ifdef _KERNEL
+
+struct espstat espstat;
+
+#endif
diff --git a/sys/netinet/ip_esp3desmd5.c b/sys/netinet/ip_esp3desmd5.c
new file mode 100644
index 00000000000..d0d5b204ac3
--- /dev/null
+++ b/sys/netinet/ip_esp3desmd5.c
@@ -0,0 +1,749 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Based on draft-ietf-ipsec-esp-3des-md5-00.txt.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#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 <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_esp.h>
+
+extern struct ifnet loif;
+
+extern void des_ecb_encrypt(caddr_t, caddr_t, caddr_t, int);
+extern void des_set_key(caddr_t, caddr_t);
+
+int
+esp3desmd5_attach()
+{
+ return 0;
+}
+
+/*
+ * esp3desmd5_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data, in
+ * this case, the encryption and decryption key schedules
+ */
+
+int
+esp3desmd5_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ struct esp3desmd5_xdata *xd;
+ struct encap_msghdr *em;
+ struct esp3desmd5_xencap txd;
+ u_char buf[ESP3DESMD5_KEYSZ];
+ int len;
+ MD5_CTX ctx;
+
+ tdbp->tdb_xform = xsp;
+
+ m = m_pullup(m, ESP3DESMD5_ULENGTH);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_init: can't pull up %d bytes\n", ESP_ULENGTH);
+#endif ENCDEBUG
+ return ENOBUFS;
+ }
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof (struct esp3desmd5_xdata),
+ M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ return ENOBUFS;
+ bzero(tdbp->tdb_xdata, sizeof (struct esp3desmd5_xdata));
+ xd = (struct esp3desmd5_xdata *)tdbp->tdb_xdata;
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI_FLEN != ESP3DESMD5_ULENGTH)
+ {
+ free((caddr_t)tdbp->tdb_xdata, M_XDATA);
+ tdbp->tdb_xdata = NULL;
+ return EINVAL;
+ }
+
+ m_copydata(m, EMT_SETSPI_FLEN, em->em_msglen - EMT_SETSPI_FLEN, (caddr_t)&txd);
+
+ if ((txd.edx_ivlen != 0) && (txd.edx_ivlen != 8))
+ {
+ free((caddr_t)tdbp->tdb_xdata, M_XDATA);
+ tdbp->tdb_xdata = NULL;
+ return EINVAL;
+ }
+
+ bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
+
+ xd->edx_ivlen = txd.edx_ivlen;
+ xd->edx_bitmap = 0;
+ xd->edx_wnd = txd.edx_wnd;
+
+ /* Fix the IV */
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ {
+ if (txd.edx_initiator)
+ printf("INITIATOR\n");
+ printf("IV length: %d\n", txd.edx_ivlen);
+ }
+#endif
+ if (txd.edx_ivlen)
+ bcopy(txd.edx_ivv, xd->edx_iv, ESP3DESMD5_IVS);
+ else
+ {
+ for (len = 0; len < ESP3DESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESP3DESMD5_IPADI :
+ ESP3DESMD5_IPADR;
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESP3DESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ bcopy(buf, xd->edx_iv, ESP3DESMD5_IVS);
+#ifdef ENCDEBUG
+ printf("IV ");
+ if (encdebug)
+ for (len = 0; len < ESP3DESMD5_IVS; len++)
+ printf(" %02x", xd->edx_iv[len]);
+ printf("\n");
+#endif
+ }
+
+ /* DES key */
+
+ for (len = 1; len < ESP3DESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESP3DESMD5_DPADI : ESP3DESMD5_DPADR;
+
+ buf[0] = 0;
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESP3DESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ des_set_key((caddr_t)buf, (caddr_t)(xd->edx_eks[0]));
+
+ buf[0] = 1;
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESP3DESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ des_set_key((caddr_t)buf, (caddr_t)(xd->edx_eks[1]));
+
+ buf[0] = 2;
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESP3DESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ des_set_key((caddr_t)buf, (caddr_t)(xd->edx_eks[2]));
+
+ /* HMAC contexts */
+
+ realMD5Init(&ctx);
+ for (len = 0; len < ESP3DESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESP3DESMD5_HPADI : ESP3DESMD5_HPADR;
+
+ MD5Update(&ctx, buf, ESP3DESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+
+ bzero(buf + ESP3DESMD5_ALEN, ESP3DESMD5_KEYSZ - ESP3DESMD5_ALEN);
+
+ for (len = 0; len < ESP3DESMD5_KEYSZ; len++)
+ buf[len] ^= ESP3DESMD5_IPAD_VAL;
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESP3DESMD5_KEYSZ);
+ xd->edx_ictx = ctx;
+
+ for (len = 0; len < ESP3DESMD5_KEYSZ; len++)
+ buf[len] ^= (ESP3DESMD5_IPAD_VAL ^ ESP3DESMD5_OPAD_VAL);
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESP3DESMD5_KEYSZ);
+ xd->edx_octx = ctx;
+
+ /* Replay counter */
+
+ for (len = 0; len < ESP3DESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESP3DESMD5_RPADI :
+ ESP3DESMD5_RPADR;
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESP3DESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ bcopy(buf, (unsigned char *)&(xd->edx_rpl), ESP3DESMD5_RPLENGTH);
+ xd->edx_initial = xd->edx_rpl - 1;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("Initial replay counter: %x (%x)\n", xd->edx_rpl,
+ xd->edx_initial);
+#endif
+
+ bzero(&txd, sizeof(struct esp3desmd5_xencap));
+ bzero(buf, ESP3DESMD5_KEYSZ);
+ bzero(&ctx, sizeof(MD5_CTX));
+
+ return 0;
+}
+
+int
+esp3desmd5_zeroize(struct tdb *tdbp)
+{
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+
+struct mbuf *
+esp3desmd5_input(struct mbuf *m, struct tdb *tdb)
+{
+ struct esp3desmd5_xdata *xd;
+ struct ip *ip, ipo;
+ u_char iv[8], niv[8], blk[8], auth[ESP3DESMD5_ALEN];
+ u_char iauth[ESP3DESMD5_ALEN];
+ u_char *idat, *odat;
+ struct esp *esp;
+ struct ifnet *rcvif;
+ int plen, ilen, olen, i, authp, oplen, errc;
+ u_int32_t rplc, tbitmap, trpl;
+ u_char padsize, nextproto;
+ struct mbuf *mi, *mo;
+ MD5_CTX ctx;
+
+ xd = (struct esp3desmd5_xdata *)tdb->tdb_xdata;
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_input: receive interface is NULL!!!\n");
+#endif ENCDEBUG
+ rcvif = &loif;
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo = *ip;
+ esp = (struct esp *)(ip + 1);
+
+ plen = m->m_pkthdr.len - sizeof (struct ip) - sizeof (u_long) - xd->edx_ivlen;
+ if (plen & 07)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_input: payload not a multiple of 8 octets\n");
+#endif ENCDEBUG
+ espstat.esps_badilen++;
+ m_freem(m);
+ return NULL;
+ }
+
+ oplen = plen;
+ ilen = m->m_len - sizeof (struct ip) - ESP3DESMD5_IVS - sizeof(u_long);
+ idat = mtod(m, unsigned char *) + sizeof (struct ip) + sizeof(u_long) +
+ ESP3DESMD5_IVS;
+
+ if (xd->edx_ivlen == 0) /* KeyIV in use */
+ {
+ bcopy(xd->edx_iv, iv, ESP3DESMD5_IVS);
+ ilen += ESP3DESMD5_IVS;
+ idat -= ESP3DESMD5_IVS;
+ }
+ else
+ bcopy(idat - ESP3DESMD5_IVS, iv, ESP3DESMD5_IVS);
+
+ olen = ilen;
+ odat = idat;
+ mi = mo = m;
+ i = 0;
+ authp = 0;
+
+ ctx = xd->edx_ictx;
+
+ MD5Update(&ctx, (unsigned char *)&(tdb->tdb_spi), sizeof(u_int32_t));
+ MD5Update(&ctx, iv, ESP3DESMD5_IVS);
+
+#ifdef ENCDEBUG
+ printf("IV ");
+ for (i = 0; i < ESP3DESMD5_IVS; i++)
+ printf(" %02x", iv[i]);
+ printf("\n");
+ i = 0;
+#endif
+
+ /*
+ * At this point:
+ * plen is # of encapsulated payload octets
+ * ilen is # of octets left in this mbuf
+ * idat is first encapsulated payload octed in this mbuf
+ * same for olen and odat
+ * iv contains the IV.
+ * mi and mo point to the first mbuf
+ *
+ * From now on until the end of the mbuf chain:
+ * . move the next eight octets of the chain into blk[]
+ * (ilen, idat, and mi are adjusted accordingly)
+ * and save it back into iv[]
+ * . decrypt blk[], xor with iv[], put back into chain
+ * (olen, odat, amd mo are adjusted accordingly)
+ * . repeat
+ */
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("esp3desmd5_input: bad chain (i)\n");
+ ilen = mi->m_len;
+ idat = (u_char *)mi->m_data;
+ }
+
+ blk[i] = niv[i] = *idat++;
+ i++;
+ ilen--;
+
+ if (i == 8)
+ {
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks[2]),
+ 0);
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks[1]),
+ 0);
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks[0]),
+ 0);
+ for (i=0; i<8; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("esp3desmd5_input: bad chain (o)\n");
+ olen = mo->m_len;
+ odat = (u_char *)mo->m_data;
+ }
+ *odat = blk[i] ^ iv[i];
+ iv[i] = niv[i];
+ blk[i] = *odat++; /* needed elsewhere */
+ olen--;
+ }
+ i = 0;
+
+ if (plen < ESP3DESMD5_ALEN)
+ {
+ bcopy(blk, auth + authp, ESP3DESMD5_DESBLK);
+ authp += ESP3DESMD5_DESBLK;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("Copying authenticator from %d\n",
+ plen);
+#endif
+ }
+ else
+ {
+ if (plen == ESP3DESMD5_ALEN + 1)
+ {
+ nextproto = blk[7];
+ padsize = blk[6];
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("Next protocol: %d\nPadsize: %d\n", nextproto, padsize);
+#endif
+ }
+ else
+ if (plen + 7 == oplen)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("SEQ %02x %02x %02x %02x\n",
+ blk[0], blk[1], blk[2],
+ blk[3]);
+#endif
+ tbitmap = xd->edx_bitmap; /* Save it */
+ trpl = xd->edx_rpl;
+ rplc = ntohl(*((u_int32_t *)blk));
+ if ((errc = checkreplaywindow32(rplc, xd->edx_initial, &(xd->edx_rpl), xd->edx_wnd, &(xd->edx_bitmap))) != 0)
+ {
+ switch (errc)
+ {
+ case 1:
+#ifdef ENCDEBUG
+ printf("esp3desmd5_input: replay counter wrapped\n");
+#endif
+ espstat.esps_wrap++;
+ break;
+ case 2:
+#ifdef ENCDEBUG
+ printf("esp3desmd5_input: received old packet, seq = %08x\n", rplc);
+#endif
+ espstat.esps_replay++;
+ break;
+ case 3:
+#ifdef ENCDEBUG
+ printf("esp3desmd5_input: packet already received\n");
+#endif
+ espstat.esps_replay++;
+ break;
+ }
+ m_freem(m);
+ return NULL;
+ }
+ }
+
+ MD5Update(&ctx, blk, ESP3DESMD5_DESBLK);
+ }
+ }
+
+ plen--;
+ }
+
+ /*
+ * Now, the entire chain has been decrypted.
+ */
+
+ MD5Final(iauth, &ctx);
+ ctx = xd->edx_octx;
+ MD5Update(&ctx, iauth, ESP3DESMD5_ALEN);
+ MD5Final(iauth, &ctx);
+
+#ifdef ENCDEBUG
+ printf("RECEIVED ");
+ for (rplc = 0; rplc < ESP3DESMD5_ALEN; rplc++)
+ printf(" %02x", auth[rplc]);
+ printf("\nSHOULD HAVE ");
+ for (rplc = 0; rplc < ESP3DESMD5_ALEN; rplc++)
+ printf(" %02x", iauth[rplc]);
+ printf("\n");
+#endif
+
+ if (bcmp(auth, iauth, ESP3DESMD5_ALEN))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_input: bad auth\n");
+#endif
+ xd->edx_rpl = trpl;
+ xd->edx_bitmap = tbitmap; /* Restore */
+ espstat.esps_badauth++;
+ m_freem(m);
+ return NULL;
+ }
+
+ m_adj(m, - padsize - 2 - ESP3DESMD5_ALEN);
+ m_adj(m, 4 + xd->edx_ivlen + ESP3DESMD5_RPLENGTH);
+
+ if (m->m_len < sizeof (struct ip))
+ {
+ m = m_pullup(m, sizeof (struct ip));
+ if (m == NULL)
+ {
+ xd->edx_rpl = trpl;
+ xd->edx_bitmap = tbitmap;
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo.ip_p = nextproto;
+ ipo.ip_id = htons(ipo.ip_id);
+ ipo.ip_off = 0;
+ ipo.ip_len += sizeof (struct ip) - ESP3DESMD5_RPLENGTH - 4 - xd->edx_ivlen - padsize - 2 - ESP3DESMD5_ALEN;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("IP packet size %d\n", ipo.ip_len);
+#endif
+ ipo.ip_len = htons(ipo.ip_len);
+ ipo.ip_sum = 0;
+ *ip = ipo;
+ ip->ip_sum = in_cksum(m, sizeof (struct ip));
+
+ return m;
+}
+
+int
+esp3desmd5_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb, struct mbuf **mp)
+{
+ struct esp3desmd5_xdata *xd;
+ struct ip *ip, ipo;
+ int i, ilen, olen, ohlen, nh, rlen, plen, padding;
+ u_int32_t rplc;
+ u_long spi;
+ struct mbuf *mi, *mo, *ms;
+ u_char *pad, *idat, *odat;
+ u_char iv[ESP3DESMD5_IVS], blk[8], auth[ESP3DESMD5_ALEN];
+ MD5_CTX ctx;
+
+ m = m_pullup(m, sizeof (struct ip)); /* Get IP header in one mbuf */
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+ spi = tdb->tdb_spi;
+
+ xd = (struct esp3desmd5_xdata *)tdb->tdb_xdata;
+ ilen = ntohs(ip->ip_len); /* Size of the packet */
+ ohlen = sizeof (u_int32_t) + xd->edx_ivlen; /* size of plaintext ESP */
+
+ if (xd->edx_rpl == xd->edx_initial)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: replay counter wrapped\n");
+#endif
+ espstat.esps_wrap++;
+ return EHOSTDOWN; /* XXX */
+ }
+
+ ipo = *ip;
+ nh = ipo.ip_p;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: next protocol is %d\n", nh);
+#endif
+
+ /* Raw payload length */
+ rlen = ESP3DESMD5_RPLENGTH + ilen - sizeof (struct ip);
+
+ padding = ((8 - ((rlen + 2) % 8)) % 8) + 2;
+
+ pad = (u_char *)m_pad(m, padding);
+ if (pad == NULL)
+ return ENOBUFS;
+
+ pad[padding-2] = padding - 2;
+ pad[padding-1] = nh;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: padding %d bytes\n", padding);
+#endif
+
+ plen = rlen + padding + ESP3DESMD5_ALEN;
+
+ ctx = xd->edx_ictx; /* Get inner padding cached */
+
+ bcopy(xd->edx_iv, iv, ESP3DESMD5_IVS);
+
+ MD5Update(&ctx, (u_char *)&spi, sizeof(u_long));
+ MD5Update(&ctx, iv, ESP3DESMD5_IVS);
+ rplc = htonl(xd->edx_rpl);
+ MD5Update(&ctx, (unsigned char *)&rplc, ESP3DESMD5_RPLENGTH);
+ xd->edx_rpl++;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: using replay counter %x\n",
+ xd->edx_rpl - 1);
+#endif
+ mi = m;
+
+ /* MD5 the data */
+ while (mi != NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: MD5'ing %d bytes\n", mi->m_len);
+#endif
+ if (mi == m)
+ MD5Update(&ctx, (u_char *)mi->m_data + sizeof(struct ip),
+ mi->m_len - sizeof(struct ip));
+ else
+ MD5Update(&ctx, (u_char *)mi->m_data, mi->m_len);
+ mi = mi->m_next;
+ }
+
+ MD5Final(auth, &ctx);
+ ctx = xd->edx_octx;
+ MD5Update(&ctx, auth, ESP3DESMD5_ALEN);
+ MD5Final(auth, &ctx); /* That's the authenticator */
+
+ /*
+ * This routine is different from espdes_output() in that
+ * here we construct the whole packet before starting encrypting.
+ */
+
+ m = m_pullup(m, sizeof(struct ip) + ESP3DESMD5_RPLENGTH +
+ sizeof(u_int32_t) + xd->edx_ivlen);
+ if (m == NULL)
+ return ENOBUFS;
+
+ /* Copy data if necessary */
+ if (m->m_len - sizeof(struct ip))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: pushing data\n");
+#endif
+ ms = m_copym(m, sizeof(struct ip), m->m_len - sizeof(struct ip),
+ M_DONTWAIT);
+ if (ms == NULL)
+ return ENOBUFS;
+
+ ms->m_next = m->m_next;
+ m->m_next = ms;
+ m->m_len = sizeof(struct ip);
+ }
+
+ /* Copy SPI, IV (or not) and replay counter */
+ bcopy((caddr_t)&spi, mtod(m, caddr_t) + sizeof (struct ip),
+ sizeof (u_int32_t));
+ bcopy((caddr_t)iv, mtod(m, caddr_t) + sizeof (struct ip) +
+ sizeof (u_int32_t), xd->edx_ivlen);
+ bcopy((caddr_t)&rplc, mtod(m, caddr_t) + sizeof(struct ip) +
+ sizeof(u_int32_t) + xd->edx_ivlen, ESP3DESMD5_RPLENGTH);
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: replay counter (wire value) %x\n", rplc);
+#endif
+
+ /* Adjust the length accordingly */
+ m->m_len += sizeof(u_int32_t) + ESP3DESMD5_RPLENGTH + xd->edx_ivlen;
+ m->m_pkthdr.len += sizeof(u_int32_t) + ESP3DESMD5_RPLENGTH +
+ xd->edx_ivlen;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: mbuf chain length %d\n", m->m_pkthdr.len);
+#endif
+
+ /* Let's append the authenticator too */
+ MGET(ms, M_DONTWAIT, MT_DATA);
+ if (ms == NULL)
+ return ENOBUFS;
+
+ bcopy(auth, mtod(ms, u_char *), ESP3DESMD5_ALEN);
+ ms->m_len = ESP3DESMD5_ALEN;
+
+ m_cat(m, ms);
+ m->m_pkthdr.len += ESP3DESMD5_ALEN; /* Adjust length */
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: final mbuf chain length %d\n",
+ m->m_pkthdr.len);
+#endif
+
+ ilen = olen = m->m_len - sizeof (struct ip) - sizeof(u_int32_t) -
+ xd->edx_ivlen;
+ idat = odat = mtod(m, u_char *) + sizeof (struct ip) +
+ sizeof(u_int32_t) + xd->edx_ivlen;
+ i = 0;
+ mi = mo = m;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: starting encryption with ilen=%d, plen=%d\n", ilen, plen);
+#endif
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("esp3desmd5_output: bad chain (i)\n");
+ ilen = mi->m_len;
+ idat = (u_char *)mi->m_data;
+ }
+
+ blk[i] = *idat++ ^ iv[i];
+
+ i++;
+ ilen--;
+
+ if (i == 8) /* We have full block */
+ {
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks[0]),
+ 1);
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks[1]),
+ 1);
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks[2]),
+ 1);
+ for (i=0; i<8; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("esp3desmd5_output: bad chain (o)\n");
+ olen = mo->m_len;
+ odat = (u_char *)mo->m_data;
+ }
+ *odat++ = blk[i];
+ iv[i] = blk[i];
+ olen--;
+ }
+ i = 0;
+ }
+
+ plen--;
+ }
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp3desmd5_output: almost done now\n");
+#endif
+
+ if (xd->edx_ivlen != 0)
+ bcopy(iv, xd->edx_iv, ESP3DESMD5_IVS); /* New IV */
+
+ /* Fix the length and the next protocol, copy back and off we go */
+ ipo.ip_len = htons(sizeof (struct ip) + ohlen + rlen + padding +
+ ESP3DESMD5_ALEN);
+ ipo.ip_p = IPPROTO_ESP;
+ bcopy((caddr_t)&ipo, mtod(m, caddr_t), sizeof(struct ip));
+
+ *mp = m;
+ return 0;
+}
diff --git a/sys/netinet/ip_espdes.c b/sys/netinet/ip_espdes.c
new file mode 100644
index 00000000000..b034a3e78db
--- /dev/null
+++ b/sys/netinet/ip_espdes.c
@@ -0,0 +1,516 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * DES-CBC
+ * Per RFC1829 (Metzger & Simpson, 1995)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#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 <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_esp.h>
+#include <dev/rndvar.h>
+
+extern struct ifnet loif;
+
+extern void des_ecb_encrypt(caddr_t, caddr_t, caddr_t, int);
+extern void des_set_key(caddr_t, caddr_t);
+
+extern MD5_CTX IP4_ctx;
+
+extern int ticks;
+#ifdef EXT_CLOCK
+extern int clock_count;
+#endif
+
+int
+espdes_attach()
+{
+ return 0;
+}
+
+/*
+ * espdes_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data, in
+ * this case, the encryption and decryption key schedules
+ */
+
+int
+espdes_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ struct espdes_xdata *xd;
+ struct encap_msghdr *em;
+ u_long rk[2];
+
+ tdbp->tdb_xform = xsp;
+
+ m = m_pullup(m, ESP_ULENGTH);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdes_init: can't pull up %d bytes\n", ESP_ULENGTH);
+#endif ENCDEBUG
+ return ENOBUFS;
+ }
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof (struct espdes_xdata),
+ M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ return ENOBUFS;
+ bzero(tdbp->tdb_xdata, sizeof (struct espdes_xdata));
+ xd = (struct espdes_xdata *)tdbp->tdb_xdata;
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI_FLEN != ESP_ULENGTH)
+ {
+ free((caddr_t)tdbp->tdb_xdata, M_XDATA);
+ tdbp->tdb_xdata = NULL;
+ return EINVAL;
+ }
+
+ m_copydata(m, EMT_SETSPI_FLEN, ESP_ULENGTH, (caddr_t)xd);
+
+ rk[0] = xd->edx_eks[0][0]; /* some overloading doesn't hurt */
+ rk[1] = xd->edx_eks[0][1]; /* XXX -- raw-major order */
+
+ des_set_key((caddr_t)rk, (caddr_t)(xd->edx_eks));
+ rk[0] = rk[1] = 0; /* zeroize! */
+
+ return 0;
+}
+
+int
+espdes_zeroize(struct tdb *tdbp)
+{
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+
+struct mbuf *
+espdes_input(struct mbuf *m, struct tdb *tdb)
+{
+ struct espdes_xdata *xd;
+ struct ip *ip, ipo;
+ u_char iv[8], niv[8], blk[8];
+ u_char *idat, *odat;
+ struct esp *esp;
+ struct ifnet *rcvif;
+ int ohlen, plen, ilen, olen, i;
+ struct mbuf *mi, *mo;
+
+ xd = (struct espdes_xdata *)tdb->tdb_xdata;
+ ohlen = sizeof (struct ip) + ESP_FLENGTH;
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdes_input: receive interface is NULL!!!\n");
+#endif ENCDEBUG
+ rcvif = &loif;
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo = *ip;
+ esp = (struct esp *)(ip + 1);
+
+ plen = m->m_pkthdr.len - sizeof (struct ip) - sizeof (u_long) - xd->edx_ivlen;
+ if (plen & 07)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdes_input: payload not a multiple of 8 octets\n");
+#endif ENCDEBUG
+ espstat.esps_badilen++;
+ m_freem(m);
+ return NULL;
+ }
+
+ ilen = m->m_len - sizeof (struct ip) - 8;
+ idat = mtod(m, unsigned char *) + sizeof (struct ip) + 8;
+
+ iv[0] = esp->esp_iv[0];
+ iv[1] = esp->esp_iv[1];
+ iv[2] = esp->esp_iv[2];
+ iv[3] = esp->esp_iv[3];
+ if (xd->edx_ivlen == 4)
+ {
+ iv[4] = ~esp->esp_iv[0];
+ iv[5] = ~esp->esp_iv[1];
+ iv[6] = ~esp->esp_iv[2];
+ iv[7] = ~esp->esp_iv[3];
+ }
+ else
+ {
+ iv[4] = esp->esp_iv[4];
+ iv[5] = esp->esp_iv[5];
+ iv[6] = esp->esp_iv[6];
+ iv[7] = esp->esp_iv[7];
+
+ ilen -= 4;
+ idat += 4;
+ }
+
+ olen = ilen;
+ odat = idat;
+ mi = mo = m;
+ i = 0;
+
+ /*
+ * At this point:
+ * plen is # of encapsulated payload octets
+ * ilen is # of octets left in this mbuf
+ * idat is first encapsulated payload octed in this mbuf
+ * same for olen and odat
+ * iv contains the IV.
+ * mi and mo point to the first mbuf
+ *
+ * From now on until the end of the mbuf chain:
+ * . move the next eight octets of the chain into blk[]
+ * (ilen, idat, and mi are adjusted accordingly)
+ * and save it back into iv[]
+ * . decrypt blk[], xor with iv[], put back into chain
+ * (olen, odat, amd mo are adjusted accordingly)
+ * . repeat
+ */
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("espdes_input: bad chain (i)\n");
+ ilen = mi->m_len;
+ idat = (u_char *)mi->m_data;
+ }
+
+ blk[i] = niv[i] = *idat++;
+ i++;
+ ilen--;
+
+ if (i == 8)
+ {
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks), 0);
+ for (i=0; i<8; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("espdes_input: bad chain (o)\n");
+ olen = mo->m_len;
+ odat = (u_char *)mo->m_data;
+ }
+ *odat = blk[i] ^ iv[i];
+ iv[i] = niv[i];
+ blk[i] = *odat++; /* needed elsewhere */
+ olen--;
+ }
+ i = 0;
+ }
+
+ plen--;
+ }
+
+ /*
+ * Now, the entire chain has been decrypted. As a side effect,
+ * blk[7] contains the next protocol, and blk[6] contains the
+ * amount of padding the original chain had. Chop off the
+ * appropriate parts of the chain, and return.
+ */
+
+ m_adj(m, -blk[6] - 2);
+ m_adj(m, 4 + xd->edx_ivlen);
+ if (m->m_len < sizeof (struct ip))
+ {
+ m = m_pullup(m, sizeof (struct ip));
+ if (m == NULL)
+ {
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo.ip_p = blk[7];
+ ipo.ip_id = htons(ipo.ip_id);
+ ipo.ip_off = 0;
+ ipo.ip_len += sizeof (struct ip) - 4 - xd->edx_ivlen - blk[6] - 2;
+ ipo.ip_len = htons(ipo.ip_len);
+ ipo.ip_sum = 0;
+ *ip = ipo;
+ ip->ip_sum = in_cksum(m, sizeof (struct ip));
+
+ return m;
+}
+
+int
+espdes_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb, struct mbuf **mp)
+{
+ struct espdes_xdata *xd;
+ struct ip *ip, ipo;
+ int i, ilen, olen, ohlen, nh, rlen, plen, padding;
+ u_long spi;
+ struct mbuf *mi, *mo;
+ u_char *pad, *idat, *odat;
+ u_char iv[8], blk[8];
+
+
+ m = m_pullup(m, sizeof (struct ip));
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+ spi = tdb->tdb_spi;
+
+ xd = (struct espdes_xdata *)tdb->tdb_xdata;
+ ilen = ntohs(ip->ip_len);
+ ohlen = sizeof (u_long) + xd->edx_ivlen;
+
+ ipo = *ip;
+ nh = ipo.ip_p;
+
+ rlen = ilen - sizeof (struct ip); /* raw payload length */
+ padding = ((8 - ((rlen + 2) % 8)) % 8) + 2;
+
+ pad = (u_char *)m_pad(m, padding);
+ if (pad == NULL)
+ return ENOBUFS;
+
+ pad[padding-2] = padding - 2;
+ pad[padding-1] = nh;
+
+ plen = rlen + padding;
+ mi = mo = m;
+ ilen = olen = m->m_len - sizeof (struct ip);
+ idat = odat = mtod(m, u_char *) + sizeof (struct ip);
+ i = 0;
+
+ /*
+ * We are now ready to encrypt the payload.
+ */
+
+ xd->edx_ivl++;
+
+ iv[0] = xd->edx_iv[0];
+ iv[1] = xd->edx_iv[1];
+ iv[2] = xd->edx_iv[2];
+ iv[3] = xd->edx_iv[3];
+ if (xd->edx_ivlen == 4)
+ {
+ iv[4] = ~xd->edx_iv[0];
+ iv[5] = ~xd->edx_iv[1];
+ iv[6] = ~xd->edx_iv[2];
+ iv[7] = ~xd->edx_iv[3];
+ }
+ else
+ {
+ iv[4] = xd->edx_iv[4];
+ iv[5] = xd->edx_iv[5];
+ iv[6] = xd->edx_iv[6];
+ iv[7] = xd->edx_iv[7];
+ }
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("espdes_output: bad chain (i)\n");
+ ilen = mi->m_len;
+ idat = (u_char *)mi->m_data;
+ }
+
+ blk[i] = *idat++ ^ iv[i];
+
+ i++;
+ ilen--;
+
+ if (i == 8)
+ {
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks), 1);
+ for (i=0; i<8; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("espdes_output: bad chain (o)\n");
+ olen = mo->m_len;
+ odat = (u_char *)mo->m_data;
+ }
+ *odat++ = blk[i];
+ iv[i] = blk[i];
+ olen--;
+ }
+ i = 0;
+ }
+
+ plen--;
+ }
+
+ /*
+ * Done with encryption. Let's wedge in the ESP header
+ * and send it out.
+ */
+
+ M_PREPEND(m, ohlen, M_DONTWAIT);
+ if (m == NULL)
+ return ENOBUFS;
+
+ m = m_pullup(m, sizeof(struct ip) + xd->edx_ivlen + sizeof(u_long));
+ if (m == NULL)
+ return ENOBUFS;
+
+ ipo.ip_len = htons(sizeof (struct ip) + ohlen + rlen + padding);
+ ipo.ip_p = IPPROTO_ESP;
+
+ iv[0] = xd->edx_iv[0];
+ iv[1] = xd->edx_iv[1];
+ iv[2] = xd->edx_iv[2];
+ iv[3] = xd->edx_iv[3];
+ if (xd->edx_ivlen == 8)
+ {
+ iv[4] = xd->edx_iv[4];
+ iv[5] = xd->edx_iv[5];
+ iv[6] = xd->edx_iv[6];
+ iv[7] = xd->edx_iv[7];
+ }
+
+ bcopy((caddr_t)&ipo, mtod(m, caddr_t), sizeof (struct ip));
+ bcopy((caddr_t)&spi, mtod(m, caddr_t) + sizeof (struct ip), sizeof (u_long));
+ bcopy((caddr_t)iv, mtod(m, caddr_t) + sizeof (struct ip) + sizeof (u_long), xd->edx_ivlen);
+
+ *mp = m;
+ return 0;
+}
+
+
+
+/*
+ *
+ *
+ * m_pad(m, n) pads <m> with <n> bytes at the end. The packet header
+ * length is updated, and a pointer to the first byte of the padding
+ * (which is guaranteed to be all in one mbuf) is returned.
+ *
+ */
+
+caddr_t
+m_pad(struct mbuf *m, int n)
+{
+ register int len, pad;
+ register struct mbuf *m0, *m1;
+ caddr_t retval;
+ u_char dat;
+
+ if (n <= 0) /* no stupid arguments */
+ 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)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("m_pad: length mismatch (should be %d instead of %d\n",
+ m->m_pkthdr.len, m->m_pkthdr.len + m0->m_len - len);
+#endif ENCDEBUG
+ m_freem(m);
+ return NULL;
+ }
+
+ 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);
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("m_pad: cannot append\n");
+#endif ENCDEBUG
+ 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;
+
+ for (len = 0; len < n; len++)
+ {
+ get_random_bytes((void *)&dat, sizeof(dat));
+ retval[len] = len + dat;
+ }
+
+ return retval;
+}
diff --git a/sys/netinet/ip_espdesmd5.c b/sys/netinet/ip_espdesmd5.c
new file mode 100644
index 00000000000..ed1b2c9845a
--- /dev/null
+++ b/sys/netinet/ip_espdesmd5.c
@@ -0,0 +1,805 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Based on draft-ietf-ipsec-esp-des-md5-03.txt.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#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 <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_esp.h>
+
+extern struct ifnet loif;
+
+extern void des_ecb_encrypt(caddr_t, caddr_t, caddr_t, int);
+extern void des_set_key(caddr_t, caddr_t);
+
+int
+espdesmd5_attach()
+{
+ return 0;
+}
+
+/*
+ * espdesmd5_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data, in
+ * this case, the encryption and decryption key schedules
+ */
+
+int
+espdesmd5_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ struct espdesmd5_xdata *xd;
+ struct encap_msghdr *em;
+ struct espdesmd5_xencap txd;
+ u_char buf[ESPDESMD5_KEYSZ];
+ int len;
+ MD5_CTX ctx;
+
+ tdbp->tdb_xform = xsp;
+
+ m = m_pullup(m, ESPDESMD5_ULENGTH);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_init: can't pull up %d bytes\n", ESP_ULENGTH);
+#endif ENCDEBUG
+ return ENOBUFS;
+ }
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof (struct espdesmd5_xdata),
+ M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ return ENOBUFS;
+ bzero(tdbp->tdb_xdata, sizeof (struct espdesmd5_xdata));
+ xd = (struct espdesmd5_xdata *)tdbp->tdb_xdata;
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI_FLEN != ESPDESMD5_ULENGTH)
+ {
+ free((caddr_t)tdbp->tdb_xdata, M_XDATA);
+ tdbp->tdb_xdata = NULL;
+ return EINVAL;
+ }
+
+ m_copydata(m, EMT_SETSPI_FLEN, em->em_msglen - EMT_SETSPI_FLEN, (caddr_t)&txd);
+
+ if ((txd.edx_ivlen != 0) && (txd.edx_ivlen != 8))
+ {
+ free((caddr_t)tdbp->tdb_xdata, M_XDATA);
+ tdbp->tdb_xdata = NULL;
+ return EINVAL;
+ }
+
+ bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
+
+ xd->edx_ivlen = txd.edx_ivlen;
+ xd->edx_bitmap = 0;
+ xd->edx_wnd = txd.edx_wnd;
+
+ /* Fix the IV */
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ {
+ if (txd.edx_initiator)
+ printf("INITIATOR\n");
+ printf("IV length: %d\n", txd.edx_ivlen);
+ }
+#endif
+ if (txd.edx_ivlen)
+ bcopy(txd.edx_ivv, xd->edx_iv, ESPDESMD5_IVS);
+ else
+ {
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_IPADI :
+ ESPDESMD5_IPADR;
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ bcopy(buf, xd->edx_iv, ESPDESMD5_IVS);
+#ifdef ENCDEBUG
+ printf("IV ");
+ if (encdebug)
+ for (len = 0; len < ESPDESMD5_IVS; len++)
+ printf(" %02x", xd->edx_iv[len]);
+ printf("\n");
+#endif
+ }
+
+ /* DES key */
+
+ realMD5Init(&ctx);
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_DPADI : ESPDESMD5_DPADR;
+
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ des_set_key((caddr_t)buf, (caddr_t)(xd->edx_eks));
+
+ /* HMAC contexts */
+
+ realMD5Init(&ctx);
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_HPADI : ESPDESMD5_HPADR;
+
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+
+ bzero(buf + ESPDESMD5_ALEN, ESPDESMD5_KEYSZ - ESPDESMD5_ALEN);
+
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] ^= ESPDESMD5_IPAD_VAL;
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ xd->edx_ictx = ctx;
+
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] ^= (ESPDESMD5_IPAD_VAL ^ ESPDESMD5_OPAD_VAL);
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ xd->edx_octx = ctx;
+
+ /* Replay counter */
+
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_RPADI :
+ ESPDESMD5_RPADR;
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ bcopy(buf, (unsigned char *)&(xd->edx_rpl), ESPDESMD5_RPLENGTH);
+ xd->edx_initial = xd->edx_rpl - 1;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("Initial replay counter: %x (%x)\n", xd->edx_rpl,
+ xd->edx_initial);
+#endif
+
+ bzero(&txd, sizeof(struct espdesmd5_xencap));
+ bzero(buf, ESPDESMD5_KEYSZ);
+ bzero(&ctx, sizeof(MD5_CTX));
+
+ return 0;
+}
+
+int
+espdesmd5_zeroize(struct tdb *tdbp)
+{
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+
+struct mbuf *
+espdesmd5_input(struct mbuf *m, struct tdb *tdb)
+{
+ struct espdesmd5_xdata *xd;
+ struct ip *ip, ipo;
+ u_char iv[8], niv[8], blk[8], auth[ESPDESMD5_ALEN];
+ u_char iauth[ESPDESMD5_ALEN];
+ u_char *idat, *odat;
+ struct esp *esp;
+ struct ifnet *rcvif;
+ int plen, ilen, olen, i, authp, oplen, errc;
+ u_int32_t rplc, tbitmap, trpl;
+ u_char padsize, nextproto;
+ struct mbuf *mi, *mo;
+ MD5_CTX ctx;
+
+ xd = (struct espdesmd5_xdata *)tdb->tdb_xdata;
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_input: receive interface is NULL!!!\n");
+#endif ENCDEBUG
+ rcvif = &loif;
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo = *ip;
+ esp = (struct esp *)(ip + 1);
+
+ plen = m->m_pkthdr.len - sizeof (struct ip) - sizeof (u_long) - xd->edx_ivlen;
+ if (plen & 07)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_input: payload not a multiple of 8 octets\n");
+#endif ENCDEBUG
+ espstat.esps_badilen++;
+ m_freem(m);
+ return NULL;
+ }
+
+ oplen = plen;
+ ilen = m->m_len - sizeof (struct ip) - ESPDESMD5_IVS - sizeof(u_long);
+ idat = mtod(m, unsigned char *) + sizeof (struct ip) + sizeof(u_long) +
+ ESPDESMD5_IVS;
+
+ if (xd->edx_ivlen == 0) /* KeyIV in use */
+ {
+ bcopy(xd->edx_iv, iv, ESPDESMD5_IVS);
+ ilen += ESPDESMD5_IVS;
+ idat -= ESPDESMD5_IVS;
+ }
+ else
+ bcopy(idat - ESPDESMD5_IVS, iv, ESPDESMD5_IVS);
+
+ olen = ilen;
+ odat = idat;
+ mi = mo = m;
+ i = 0;
+ authp = 0;
+
+ ctx = xd->edx_ictx;
+
+ MD5Update(&ctx, (unsigned char *)&(tdb->tdb_spi), sizeof(u_int32_t));
+ MD5Update(&ctx, iv, ESPDESMD5_IVS);
+
+#ifdef ENCDEBUG
+ printf("IV ");
+ for (i = 0; i < ESPDESMD5_IVS; i++)
+ printf(" %02x", iv[i]);
+ printf("\n");
+ i = 0;
+#endif
+
+ /*
+ * At this point:
+ * plen is # of encapsulated payload octets
+ * ilen is # of octets left in this mbuf
+ * idat is first encapsulated payload octed in this mbuf
+ * same for olen and odat
+ * iv contains the IV.
+ * mi and mo point to the first mbuf
+ *
+ * From now on until the end of the mbuf chain:
+ * . move the next eight octets of the chain into blk[]
+ * (ilen, idat, and mi are adjusted accordingly)
+ * and save it back into iv[]
+ * . decrypt blk[], xor with iv[], put back into chain
+ * (olen, odat, amd mo are adjusted accordingly)
+ * . repeat
+ */
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("espdesmd5_input: bad chain (i)\n");
+ ilen = mi->m_len;
+ idat = (u_char *)mi->m_data;
+ }
+
+ blk[i] = niv[i] = *idat++;
+ i++;
+ ilen--;
+
+ if (i == 8)
+ {
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks), 0);
+ for (i=0; i<8; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("espdesmd5_input: bad chain (o)\n");
+ olen = mo->m_len;
+ odat = (u_char *)mo->m_data;
+ }
+ *odat = blk[i] ^ iv[i];
+ iv[i] = niv[i];
+ blk[i] = *odat++; /* needed elsewhere */
+ olen--;
+ }
+ i = 0;
+
+ if (plen < ESPDESMD5_ALEN)
+ {
+ bcopy(blk, auth + authp, ESPDESMD5_DESBLK);
+ authp += ESPDESMD5_DESBLK;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("Copying authenticator from %d\n",
+ plen);
+#endif
+ }
+ else
+ {
+ if (plen == ESPDESMD5_ALEN + 1)
+ {
+ nextproto = blk[7];
+ padsize = blk[6];
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("Next protocol: %d\nPadsize: %d\n", nextproto, padsize);
+#endif
+ }
+ else
+ if (plen + 7 == oplen)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("SEQ %02x %02x %02x %02x\n",
+ blk[0], blk[1], blk[2],
+ blk[3]);
+#endif
+ tbitmap = xd->edx_bitmap; /* Save it */
+ trpl = xd->edx_rpl;
+ rplc = ntohl(*((u_int32_t *)blk));
+ if ((errc = checkreplaywindow32(rplc, xd->edx_initial, &(xd->edx_rpl), xd->edx_wnd, &(xd->edx_bitmap))) != 0)
+ {
+ switch (errc)
+ {
+ case 1:
+#ifdef ENCDEBUG
+ printf("espdesmd5_input: replay counter wrapped\n");
+#endif
+ espstat.esps_wrap++;
+ break;
+ case 2:
+#ifdef ENCDEBUG
+ printf("espdesmd5_input: received old packet, seq = %08x\n", rplc);
+#endif
+ espstat.esps_replay++;
+ break;
+ case 3:
+#ifdef ENCDEBUG
+ printf("espdesmd5_input: packet already received\n");
+#endif
+ espstat.esps_replay++;
+ break;
+ }
+ m_freem(m);
+ return NULL;
+ }
+ }
+
+ MD5Update(&ctx, blk, ESPDESMD5_DESBLK);
+ }
+ }
+
+ plen--;
+ }
+
+ /*
+ * Now, the entire chain has been decrypted.
+ */
+
+ MD5Final(iauth, &ctx);
+ ctx = xd->edx_octx;
+ MD5Update(&ctx, iauth, ESPDESMD5_ALEN);
+ MD5Final(iauth, &ctx);
+
+#ifdef ENCDEBUG
+ printf("RECEIVED ");
+ for (rplc = 0; rplc < ESPDESMD5_ALEN; rplc++)
+ printf(" %02x", auth[rplc]);
+ printf("\nSHOULD HAVE ");
+ for (rplc = 0; rplc < ESPDESMD5_ALEN; rplc++)
+ printf(" %02x", iauth[rplc]);
+ printf("\n");
+#endif
+
+ if (bcmp(auth, iauth, ESPDESMD5_ALEN))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_input: bad auth\n");
+#endif
+ xd->edx_rpl = trpl;
+ xd->edx_bitmap = tbitmap; /* Restore */
+ espstat.esps_badauth++;
+ m_freem(m);
+ return NULL;
+ }
+
+ m_adj(m, - padsize - 2 - ESPDESMD5_ALEN);
+ m_adj(m, 4 + xd->edx_ivlen + ESPDESMD5_RPLENGTH);
+
+ if (m->m_len < sizeof (struct ip))
+ {
+ m = m_pullup(m, sizeof (struct ip));
+ if (m == NULL)
+ {
+ xd->edx_rpl = trpl;
+ xd->edx_bitmap = tbitmap;
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo.ip_p = nextproto;
+ ipo.ip_id = htons(ipo.ip_id);
+ ipo.ip_off = 0;
+ ipo.ip_len += sizeof (struct ip) - ESPDESMD5_RPLENGTH - 4 - xd->edx_ivlen - padsize - 2 - ESPDESMD5_ALEN;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("IP packet size %d\n", ipo.ip_len);
+#endif
+ ipo.ip_len = htons(ipo.ip_len);
+ ipo.ip_sum = 0;
+ *ip = ipo;
+ ip->ip_sum = in_cksum(m, sizeof (struct ip));
+
+ return m;
+}
+
+int
+espdesmd5_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb, struct mbuf **mp)
+{
+ struct espdesmd5_xdata *xd;
+ struct ip *ip, ipo;
+ int i, ilen, olen, ohlen, nh, rlen, plen, padding;
+ u_int32_t rplc;
+ u_long spi;
+ struct mbuf *mi, *mo, *ms;
+ u_char *pad, *idat, *odat;
+ u_char iv[ESPDESMD5_IVS], blk[8], auth[ESPDESMD5_ALEN];
+ MD5_CTX ctx;
+
+ m = m_pullup(m, sizeof (struct ip)); /* Get IP header in one mbuf */
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+ spi = tdb->tdb_spi;
+
+ xd = (struct espdesmd5_xdata *)tdb->tdb_xdata;
+ ilen = ntohs(ip->ip_len); /* Size of the packet */
+ ohlen = sizeof (u_int32_t) + xd->edx_ivlen; /* size of plaintext ESP */
+
+ if (xd->edx_rpl == xd->edx_initial)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: replay counter wrapped\n");
+#endif
+ espstat.esps_wrap++;
+ return EHOSTDOWN; /* XXX */
+ }
+
+ ipo = *ip;
+ nh = ipo.ip_p;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: next protocol is %d\n", nh);
+#endif
+
+ /* Raw payload length */
+ rlen = ESPDESMD5_RPLENGTH + ilen - sizeof (struct ip);
+
+ padding = ((8 - ((rlen + 2) % 8)) % 8) + 2;
+
+ pad = (u_char *)m_pad(m, padding);
+ if (pad == NULL)
+ return ENOBUFS;
+
+ pad[padding-2] = padding - 2;
+ pad[padding-1] = nh;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: padding %d bytes\n", padding);
+#endif
+
+ plen = rlen + padding + ESPDESMD5_ALEN;
+
+ ctx = xd->edx_ictx; /* Get inner padding cached */
+
+ bcopy(xd->edx_iv, iv, ESPDESMD5_IVS);
+
+ MD5Update(&ctx, (u_char *)&spi, sizeof(u_long));
+ MD5Update(&ctx, iv, ESPDESMD5_IVS);
+ rplc = htonl(xd->edx_rpl);
+ MD5Update(&ctx, (unsigned char *)&rplc, ESPDESMD5_RPLENGTH);
+ xd->edx_rpl++;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: using replay counter %x\n",
+ xd->edx_rpl - 1);
+#endif
+ mi = m;
+
+ /* MD5 the data */
+ while (mi != NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: MD5'ing %d bytes\n", mi->m_len);
+#endif
+ if (mi == m)
+ MD5Update(&ctx, (u_char *)mi->m_data + sizeof(struct ip),
+ mi->m_len - sizeof(struct ip));
+ else
+ MD5Update(&ctx, (u_char *)mi->m_data, mi->m_len);
+ mi = mi->m_next;
+ }
+
+ MD5Final(auth, &ctx);
+ ctx = xd->edx_octx;
+ MD5Update(&ctx, auth, ESPDESMD5_ALEN);
+ MD5Final(auth, &ctx); /* That's the authenticator */
+
+ /*
+ * This routine is different from espdes_output() in that
+ * here we construct the whole packet before starting encrypting.
+ */
+
+ m = m_pullup(m, sizeof(struct ip) + ESPDESMD5_RPLENGTH +
+ sizeof(u_int32_t) + xd->edx_ivlen);
+ if (m == NULL)
+ return ENOBUFS;
+
+ /* Copy data if necessary */
+ if (m->m_len - sizeof(struct ip))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: pushing data\n");
+#endif
+ ms = m_copym(m, sizeof(struct ip), m->m_len - sizeof(struct ip),
+ M_DONTWAIT);
+ if (ms == NULL)
+ return ENOBUFS;
+
+ ms->m_next = m->m_next;
+ m->m_next = ms;
+ m->m_len = sizeof(struct ip);
+ }
+
+ /* Copy SPI, IV (or not) and replay counter */
+ bcopy((caddr_t)&spi, mtod(m, caddr_t) + sizeof (struct ip),
+ sizeof (u_int32_t));
+ bcopy((caddr_t)iv, mtod(m, caddr_t) + sizeof (struct ip) +
+ sizeof (u_int32_t), xd->edx_ivlen);
+ bcopy((caddr_t)&rplc, mtod(m, caddr_t) + sizeof(struct ip) +
+ sizeof(u_int32_t) + xd->edx_ivlen, ESPDESMD5_RPLENGTH);
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: replay counter (wire value) %x\n", rplc);
+#endif
+
+ /* Adjust the length accordingly */
+ m->m_len += sizeof(u_int32_t) + ESPDESMD5_RPLENGTH + xd->edx_ivlen;
+ m->m_pkthdr.len += sizeof(u_int32_t) + ESPDESMD5_RPLENGTH +
+ xd->edx_ivlen;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: mbuf chain length %d\n", m->m_pkthdr.len);
+#endif
+
+ /* Let's append the authenticator too */
+ MGET(ms, M_DONTWAIT, MT_DATA);
+ if (ms == NULL)
+ return ENOBUFS;
+
+ bcopy(auth, mtod(ms, u_char *), ESPDESMD5_ALEN);
+ ms->m_len = ESPDESMD5_ALEN;
+
+ m_cat(m, ms);
+ m->m_pkthdr.len += ESPDESMD5_ALEN; /* Adjust length */
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: final mbuf chain length %d\n",
+ m->m_pkthdr.len);
+#endif
+
+ ilen = olen = m->m_len - sizeof (struct ip) - sizeof(u_int32_t) -
+ xd->edx_ivlen;
+ idat = odat = mtod(m, u_char *) + sizeof (struct ip) +
+ sizeof(u_int32_t) + xd->edx_ivlen;
+ i = 0;
+ mi = mo = m;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: starting encryption with ilen=%d, plen=%d\n", ilen, plen);
+#endif
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("espdesmd5_output: bad chain (i)\n");
+ ilen = mi->m_len;
+ idat = (u_char *)mi->m_data;
+ }
+
+ blk[i] = *idat++ ^ iv[i];
+
+ i++;
+ ilen--;
+
+ if (i == 8) /* We have full block */
+ {
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks), 1);
+ for (i=0; i<8; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("espdesmd5_output: bad chain (o)\n");
+ olen = mo->m_len;
+ odat = (u_char *)mo->m_data;
+ }
+ *odat++ = blk[i];
+ iv[i] = blk[i];
+ olen--;
+ }
+ i = 0;
+ }
+
+ plen--;
+ }
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: almost done now\n");
+#endif
+
+ bcopy(iv, xd->edx_iv, ESPDESMD5_IVS); /* New IV */
+
+ /* Fix the length and the next protocol, copy back and off we go */
+ ipo.ip_len = htons(sizeof (struct ip) + ohlen + rlen + padding +
+ ESPDESMD5_ALEN);
+ ipo.ip_p = IPPROTO_ESP;
+ bcopy((caddr_t)&ipo, mtod(m, caddr_t), sizeof(struct ip));
+
+ *mp = m;
+ return 0;
+}
+
+
+/*
+ * both versions of the checkreplaywindow for 32 and 64 bit counters
+ * return 0 on success
+ * return 1 for counter == 0
+ * return 2 for very old packet
+ * return 3 for packet within current window but already received
+ */
+
+int
+checkreplaywindow64(u_int64_t seq, u_int64_t *lastseq, u_int64_t window, u_int64_t *bitmap)
+{
+ u_int64_t diff;
+
+ if (seq == 0)
+ return 1;
+
+ if (seq > *lastseq)
+ {
+ diff = seq - *lastseq;
+ if (diff < window)
+ *bitmap = ((*bitmap) << diff) | 1;
+ else
+ *bitmap = 1;
+ *lastseq = seq;
+ return 0;
+ }
+ diff = *lastseq - seq;
+ if (diff >= window)
+ {
+ espstat.esps_wrap++;
+ return 2;
+ }
+ if ((*bitmap) & (((u_int64_t) 1) << diff))
+ {
+ espstat.esps_replay++;
+ return 3;
+ }
+ *bitmap |= (((u_int64_t) 1) << diff);
+ return 0;
+}
+
+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 diff;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("checkreplaywindow32: seq=%x lastseq=%x\n", seq, *lastseq);
+#endif
+
+ seq -= initial;
+
+ 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;
+ 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 --git a/sys/netinet/ip_ip4.c b/sys/netinet/ip_ip4.c
new file mode 100644
index 00000000000..b16b0786d8e
--- /dev/null
+++ b/sys/netinet/ip_ip4.c
@@ -0,0 +1,222 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * IP-inside-IP processing
+ */
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#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>
+
+#include <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_ip4.h>
+#include <dev/rndvar.h>
+
+
+
+/*
+ * ip4_input gets called when we receive an encapsulated packet,
+ * either because we got it at a real interface, or because AH or ESP
+ * were being used in tunnel mode (in which case the rcvif element will
+ * contain the address of the encapX interface associated with the tunnel.
+ */
+
+void
+ip4_input(register struct mbuf *m, int iphlen)
+{
+ struct ip *ipo, *ipi;
+ struct ifqueue *ifq = NULL;
+ int s;
+ /*
+ * Strip IP options, if any.
+ */
+
+ if (iphlen > sizeof (struct ip))
+ {
+ ip_stripoptions(m, (struct mbuf *)0);
+ iphlen = sizeof (struct ip);
+ }
+
+ /*
+ * Make sure next IP header is in the first mbuf.
+ *
+ * Careful here! we are receiving the packet from ipintr;
+ * this means that the ip_len field has been adjusted to
+ * not count the ip header, and is also in host order.
+ */
+
+ ipo = mtod(m, struct ip *);
+
+ if (m->m_len < iphlen + sizeof (struct ip))
+ {
+ if ((m = m_pullup(m, iphlen + sizeof (struct ip))) == 0)
+ {
+ ip4stat.ip4s_hdrops++;
+ return;
+ }
+ ipo = mtod(m, struct ip *);
+ }
+ ipi = (struct ip *)((caddr_t)ipo + iphlen);
+
+ /*
+ * XXX - Should we do anything to the inner packet?
+ * Does arriving at the far end of the tunnel count as one hop
+ * (thus requiring ipi->ip_ttl to be decremented)?
+ */
+
+ if (ipi->ip_v != IPVERSION)
+ {
+ ip4stat.ip4s_notip4++;
+ return;
+ }
+
+ /*
+ * Interface pointer is already in first mbuf; chop off the
+ * `outer' header and reschedule.
+ */
+
+ m->m_len -= iphlen;
+ m->m_pkthdr.len -= iphlen;
+ m->m_data += iphlen;
+
+ /* XXX -- interface pointer stays the same (which is probably
+ * the way it should be.
+ */
+
+ ifq = &ipintrq;
+
+ s = splimp(); /* isn't it already? */
+ if (IF_QFULL(ifq))
+ {
+ IF_DROP(ifq);
+ m_freem(m);
+ ip4stat.ip4s_qfull++;
+ splx(s);
+ return;
+ }
+ IF_ENQUEUE(ifq, m);
+ schednetisr(NETISR_IP);
+ splx(s);
+
+ return;
+}
+
+int
+ipe4_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb, struct mbuf **mp)
+{
+ struct ip *ipo, *ipi;
+ ushort ilen;
+
+ ipi = mtod(m, struct ip *);
+ ilen = ntohs(ipi->ip_len);
+
+ M_PREPEND(m, sizeof (struct ip), M_DONTWAIT);
+ if (m == 0)
+ return ENOBUFS;
+
+ ipo = mtod(m, struct ip *);
+
+ ipo->ip_v = IPVERSION;
+ ipo->ip_hl = 5;
+ ipo->ip_tos = ipi->ip_tos;
+ ipo->ip_len = htons(ilen + sizeof (struct ip));
+ /* ipo->ip_id = htons(ip_id++); */
+ get_random_bytes((void *)&(ipo->ip_id), sizeof(ipo->ip_id));
+ ipo->ip_off = ipi->ip_off & ~(IP_MF | IP_OFFMASK); /* keep C and DF */
+ ipo->ip_ttl = ipi->ip_ttl; /* already decremented if fwding */
+ ipo->ip_p = IPPROTO_IPIP;
+ ipo->ip_sum = 0;
+ ipo->ip_src = gw->sen_ipsp_src;
+ ipo->ip_dst = gw->sen_ipsp_dst;
+
+/* printf("ip4_output: [%x->%x](l=%d, p=%d)",
+ ntohl(ipi->ip_src.s_addr), ntohl(ipi->ip_dst.s_addr),
+ ilen, ipi->ip_p);
+ printf(" through [%x->%x](l=%d, p=%d)\n",
+ ntohl(ipo->ip_src.s_addr), ntohl(ipo->ip_dst.s_addr),
+ ipo->ip_len, ipo->ip_p);*/
+
+ *mp = m;
+ return 0;
+
+/* return ip_output(m, NULL, NULL, IP_ENCAPSULATED, NULL);*/
+}
+
+int
+ipe4_attach()
+{
+ return 0;
+}
+
+int
+ipe4_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ printf("ipe4_init: setting up\n");
+ tdbp->tdb_xform = xsp;
+ if (m)
+ m_freem(m);
+ return 0;
+}
+
+int
+ipe4_zeroize(struct tdb *tdbp)
+{
+ /* Nothing much really - we don't need any state */
+ return 0;
+}
+
+
+
+void
+ipe4_input(struct mbuf *m, ...)
+{
+ printf("ipe4_input: should never be called\n");
+ if (m)
+ m_freem(m);
+}
diff --git a/sys/netinet/ip_ip4.h b/sys/netinet/ip_ip4.h
new file mode 100644
index 00000000000..4e580fe7524
--- /dev/null
+++ b/sys/netinet/ip_ip4.h
@@ -0,0 +1,40 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * IP-inside-IP processing.
+ * Not quite all the functionality of RFC-1853, but the main idea is there.
+ */
+
+struct ip4stat
+{
+ u_long ip4s_ipackets; /* total input packets */
+ u_long ip4s_hdrops; /* packet shorter than header shows */
+ u_long ip4s_badlen;
+ u_long ip4s_notip4;
+ u_long ip4s_qfull;
+};
+
+#ifdef _KERNEL
+struct ip4stat ip4stat;
+#endif
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c
new file mode 100644
index 00000000000..390745def98
--- /dev/null
+++ b/sys/netinet/ip_ipsp.c
@@ -0,0 +1,259 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * IPSP Processing
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#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>
+
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#define IPSEC_IPSP_C
+#include <netinet/ip_ipsp.h>
+#undef IPSEC_IPSP_C
+#include <netinet/ip_ah.h>
+#include <netinet/ip_esp.h>
+
+#ifdef ENCDEBUG
+int encdebug = 1;
+#endif
+
+/*
+ * This is the proper place to define the various encapsulation transforms.
+ * CAUTION: the human-readable string should be LESS than 200 bytes if the
+ * kernfs is to work properly.
+ */
+
+struct xformsw xformsw[] = {
+{ XF_IP4, 0, "IPv4 Simple Encapsulation",
+ ipe4_attach, ipe4_init, ipe4_zeroize,
+ (struct mbuf * (*)(struct mbuf *, struct tdb *))ipe4_input, ipe4_output, },
+{ XF_AHMD5, XFT_AUTH, "Keyed MD5 Authentication",
+ ahmd5_attach, ahmd5_init, ahmd5_zeroize,
+ ahmd5_input, ahmd5_output, },
+{ XF_ESPDES, XFT_CONF, "DES-CBC Encryption",
+ espdes_attach, espdes_init, espdes_zeroize,
+ espdes_input, espdes_output, },
+{ XF_AHHMACMD5, XFT_AUTH, "HMAC MD5 Authentication",
+ ahhmacmd5_attach, ahhmacmd5_init, ahhmacmd5_zeroize,
+ ahhmacmd5_input, ahhmacmd5_output, },
+{ XF_AHHMACSHA1, XFT_AUTH, "HMAC SHA1 Authentication",
+ ahhmacsha1_attach, ahhmacsha1_init, ahhmacsha1_zeroize,
+ ahhmacsha1_input, ahhmacsha1_output, },
+{ XF_ESPDESMD5, XFT_CONF, "DES-CBC Encryption + MD5 Authentication",
+ espdesmd5_attach, espdesmd5_init, espdesmd5_zeroize,
+ espdesmd5_input, espdesmd5_output, },
+{ XF_ESP3DESMD5, XFT_CONF, "3DES-CBC Encryption + MD5 Authentication",
+ esp3desmd5_attach, esp3desmd5_init, esp3desmd5_zeroize,
+ esp3desmd5_input, esp3desmd5_output, },
+};
+
+struct xformsw *xformswNXFORMSW = &xformsw[sizeof(xformsw)/sizeof(xformsw[0])];
+
+unsigned char ipseczeroes[IPSEC_ZEROES_SIZE]; /* zeroes! */
+
+static char *ipspkernfs = NULL;
+static int ipspkernfs_len = 0;
+int ipspkernfs_dirty = 1;
+
+/*
+ * An IPSP SAID is really the concatenation of the SPI found in the
+ * packet and the destination address of the packet. When we receive
+ * an IPSP packet, we need to look up its tunnel descriptor block,
+ * based on the SPI in the packet and the destination address (which is
+ * really one of our addresses if we received the packet!
+ */
+
+struct tdb *
+gettdb(u_long spi, struct in_addr dst)
+{
+ int hashval;
+ struct tdb *tdbp;
+
+ hashval = (spi+dst.s_addr) % TDB_HASHMOD;
+
+ for (tdbp = tdbh[hashval]; tdbp; tdbp = tdbp->tdb_hnext)
+ if ((tdbp->tdb_spi == spi) && (tdbp->tdb_dst.s_addr == dst.s_addr))
+ break;
+
+ return tdbp;
+}
+
+void
+puttdb(struct tdb *tdbp)
+{
+ int hashval;
+ hashval = ((tdbp->tdb_spi + tdbp->tdb_dst.s_addr) % TDB_HASHMOD);
+ tdbp->tdb_hnext = tdbh[hashval];
+ tdbh[hashval] = tdbp;
+ ipspkernfs_dirty = 1;
+}
+
+int
+tdb_delete(struct tdb *tdbp, int delchain)
+{
+ struct tdb *tdbpp;
+ int hashval;
+
+ hashval = ((tdbp->tdb_spi + tdbp->tdb_dst.s_addr) % TDB_HASHMOD);
+
+ if (tdbh[hashval] == tdbp)
+ {
+ tdbpp = tdbp;
+ tdbh[hashval] = tdbp->tdb_hnext;
+ }
+ else
+ for (tdbpp = tdbh[hashval]; tdbpp != NULL; tdbpp = tdbpp->tdb_hnext)
+ if (tdbpp->tdb_hnext == tdbp)
+ {
+ tdbpp->tdb_hnext = tdbp->tdb_hnext;
+ tdbpp = tdbp;
+ }
+
+ if (tdbp != tdbpp)
+ return EINVAL; /* Should never happen */
+
+ ipspkernfs_dirty = 1;
+ tdbpp = tdbp->tdb_onext;
+ (*(tdbp->tdb_xform->xf_zeroize))(tdbp);
+ FREE(tdbp, M_TDB);
+ if (delchain && tdbpp)
+ return tdb_delete(tdbpp, delchain);
+ else
+ return 0;
+}
+
+int
+tdb_init(struct tdb *tdbp, struct mbuf *m)
+{
+ int alg;
+ struct encap_msghdr *em;
+ struct xformsw *xsp;
+
+ em = mtod(m, struct encap_msghdr *);
+ alg = em->em_alg;
+
+ for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++)
+ if (xsp->xf_type == alg)
+ return (*(xsp->xf_init))(tdbp, xsp, m);
+
+ printf("tdbinit: no alg %d for spi %x, addr %x\n", alg, tdbp->tdb_spi, ntohl(tdbp->tdb_dst.s_addr));
+
+ m_freem(m);
+ return EINVAL;
+}
+
+
+int
+ipsp_kern(int off, char **bufp, int len)
+{
+ struct tdb *tdbp;
+ int i, k;
+ char *b, buf[512];
+
+ if (off != 0)
+ return 0;
+
+ if ((!ipspkernfs_dirty) && (ipspkernfs))
+ {
+ *bufp = ipspkernfs;
+ return ipspkernfs_len;
+ }
+ else
+ ipspkernfs_dirty = 0;
+
+ if (ipspkernfs)
+ {
+ FREE(ipspkernfs, M_XDATA);
+ ipspkernfs = NULL;
+ }
+
+ for (i = 0, k = 0; i < TDB_HASHMOD; i++)
+ for (tdbp = tdbh[i]; tdbp != (struct tdb *) NULL; tdbp = tdbp->tdb_hnext)
+ {
+ /* Being paranoid to avoid buffer overflows */
+
+ if (strlen(tdbp->tdb_xform->xf_name) >= 200)
+ return 0;
+
+ b = (char *)&(tdbp->tdb_dst.s_addr);
+ k += sprintf(buf,
+ "SPI=%x, destination=%d.%d.%d.%d, interface=%s\n algorithm=%d (%s)\n next SPI=%x, previous SPI=%x\n",
+ ntohl(tdbp->tdb_spi), ((int)b[0] & 0xff), ((int)b[1] & 0xff),
+ ((int)b[2] & 0xff), ((int)b[3] & 0xff),
+ (tdbp->tdb_rcvif ? tdbp->tdb_rcvif->if_xname : "none"),
+ tdbp->tdb_xform->xf_type, tdbp->tdb_xform->xf_name,
+ (tdbp->tdb_onext ? ntohl(tdbp->tdb_onext->tdb_spi) : 0),
+ (tdbp->tdb_inext ? ntohl(tdbp->tdb_inext->tdb_spi) : 0));
+ }
+
+ if (k == 0)
+ return 0;
+
+ MALLOC(ipspkernfs, char *, k + 1, M_XDATA, M_DONTWAIT);
+ if (!ipspkernfs)
+ return 0;
+
+ ipspkernfs_len = k + 1;
+
+ for (i = 0, k = 0; i < TDB_HASHMOD; i++)
+ for (tdbp = tdbh[i]; tdbp != (struct tdb *) NULL; tdbp = tdbp->tdb_hnext)
+ {
+ b = (char *)&(tdbp->tdb_dst.s_addr);
+ k += sprintf(ipspkernfs + k,
+ "SPI=%x, destination=%d.%d.%d.%d, interface=%s\n algorithm=%d (%s)\n next SPI=%x, previous SPI=%x\n",
+ ntohl(tdbp->tdb_spi), ((int)b[0] & 0xff), ((int)b[1] & 0xff),
+ ((int)b[2] & 0xff), ((int)b[3] & 0xff),
+ (tdbp->tdb_rcvif ? tdbp->tdb_rcvif->if_xname : "none"),
+ tdbp->tdb_xform->xf_type, tdbp->tdb_xform->xf_name,
+ (tdbp->tdb_onext ? ntohl(tdbp->tdb_onext->tdb_spi) : 0),
+ (tdbp->tdb_inext ? ntohl(tdbp->tdb_inext->tdb_spi) : 0));
+ }
+
+ ipspkernfs[k] = '\0';
+ *bufp = ipspkernfs;
+ return ipspkernfs_len;
+}
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
new file mode 100644
index 00000000000..85e122a752e
--- /dev/null
+++ b/sys/netinet/ip_ipsp.h
@@ -0,0 +1,139 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * IPSP global definitions.
+ */
+
+struct tdb /* tunnel descriptor block */
+{
+ struct tdb *tdb_hnext; /* next in hash chain */
+ struct tdb *tdb_onext; /* next in output */
+ struct tdb *tdb_inext; /* next in input (prev!) */
+ u_long tdb_spi; /* SPI to use */
+ struct in_addr tdb_dst; /* dest address for this SPI */
+ struct ifnet *tdb_rcvif; /* related rcv encap interface */
+ struct xformsw *tdb_xform; /* transformation to use */
+ caddr_t tdb_xdata; /* transformation data (opaque) */
+};
+
+#define TDB_HASHMOD 257
+
+struct xformsw
+{
+ u_short xf_type; /* Unique ID of xform */
+ u_short xf_flags; /* flags (see below) */
+ char *xf_name; /* human-readable name */
+ int (*xf_attach)(void); /* called at config time */
+ int (*xf_init)(struct tdb *, struct xformsw *, struct mbuf *); /* xform initialization */
+ int (*xf_zeroize)(struct tdb *); /* termination */
+ struct mbuf *(*xf_input)(struct mbuf *, struct tdb *); /* called when packet received */
+ int (*xf_output)(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **); /* called when packet sent */
+};
+
+#define XF_IP4 1 /* IP inside IP */
+#define XF_AHMD5 2 /* AH MD5 */
+#define XF_AHSHA1 3 /* AH SHA */
+#define XF_ESPDES 4 /* ESP DES-CBC */
+#define XF_ESP3DES 5 /* ESP DES3-CBC */
+#define XF_AHHMACMD5 6 /* AH-HMAC-MD5 with opt replay prot */
+#define XF_AHHMACSHA1 7 /* AH-HMAC-SHA1 with opt replay prot */
+#define XF_ESPDESMD5 8 /* ESP DES-CBC + MD5 */
+#define XF_ESP3DESMD5 9 /* ESP 3DES-CBC + MD5 */
+
+#define XFT_AUTH 0x0001
+#define XFT_CONF 0x0100
+
+#define IPSEC_ZEROES_SIZE 64
+
+#ifdef IPSEC_IPSP_C
+#if BYTE_ORDER == LITTLE_ENDIAN
+inline u_int64_t
+htonq(u_int64_t q)
+{
+ register u_int32_t u, l;
+ u = q >> 32;
+ l = (u_int32_t) q;
+
+ return htonl(u) | ((u_int64_t)htonl(l) << 32);
+}
+
+#define ntohq(_x) htonq(_x)
+
+#elif BYTE_ORDER == BIG_ENDIAN
+
+#define htonq(_x) (_x)
+#define ntohq(_x) htonq(_x)
+
+#else
+#error "Please fix <machine/endian.h>"
+#endif
+#else
+u_int64_t htonq(u_int64_t);
+#define ntohq(_x) htonq(_x)
+extern unsigned char ipseczeroes[IPSEC_ZEROES_SIZE];
+#endif
+
+#ifdef _KERNEL
+#undef ENCDEBUG
+extern int encdebug;
+
+struct tdb *tdbh[TDB_HASHMOD];
+extern struct xformsw xformsw[], *xformswNXFORMSW;
+
+extern struct tdb *gettdb(u_long, struct in_addr);
+extern void puttdb(struct tdb *);
+extern int tdb_delete(struct tdb *, int);
+
+extern int ipe4_attach(void), ipe4_init(struct tdb *, struct xformsw *, struct mbuf *), ipe4_zeroize(struct tdb *);
+extern int ipe4_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
+extern void ipe4_input __P((struct mbuf *, ...));
+
+extern int ahmd5_attach(void), ahmd5_init(struct tdb *, struct xformsw *, struct mbuf *), ahmd5_zeroize(struct tdb *);
+extern int ahmd5_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
+extern struct mbuf *ahmd5_input(struct mbuf *, struct tdb *);
+
+extern int ahhmacmd5_attach(void), ahhmacmd5_init(struct tdb *, struct xformsw *, struct mbuf *), ahhmacmd5_zeroize(struct tdb *);
+extern int ahhmacmd5_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
+extern struct mbuf *ahhmacmd5_input(struct mbuf *, struct tdb *);
+
+extern int ahhmacsha1_attach(void), ahhmacsha1_init(struct tdb *, struct xformsw *, struct mbuf *), ahhmacsha1_zeroize(struct tdb *);
+extern int ahhmacsha1_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
+extern struct mbuf *ahhmacsha1_input(struct mbuf *, struct tdb *);
+
+extern int espdes_attach(void), espdes_init(struct tdb *, struct xformsw *, struct mbuf *), espdes_zeroize(struct tdb *);
+extern int espdes_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
+extern struct mbuf *espdes_input(struct mbuf *, struct tdb *);
+
+extern int espdesmd5_attach(void), espdesmd5_init(struct tdb *, struct xformsw *, struct mbuf *), espdesmd5_zeroize(struct tdb *);
+extern int espdesmd5_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
+extern struct mbuf *espdesmd5_input(struct mbuf *, struct tdb *);
+
+extern int esp3desmd5_attach(void), esp3desmd5_init(struct tdb *, struct xformsw *, struct mbuf *), esp3desmd5_zeroize(struct tdb *);
+extern int esp3desmd5_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
+extern struct mbuf *esp3desmd5_input(struct mbuf *, struct tdb *);
+
+extern caddr_t m_pad(struct mbuf *, int);
+extern int checkreplaywindow32(u_int32_t, u_int32_t, u_int32_t *, u_int32_t, u_int32_t *);
+extern int checkreplaywindow64(u_int64_t, u_int64_t *, u_int64_t, u_int64_t *);
+#endif
diff --git a/sys/netinet/ip_md5.h b/sys/netinet/ip_md5.h
new file mode 100644
index 00000000000..2e102c8fcdc
--- /dev/null
+++ b/sys/netinet/ip_md5.h
@@ -0,0 +1,71 @@
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+ The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 1
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void realMD5Init PROTO_LIST ((MD5_CTX *));
+void MD5Update PROTO_LIST
+ ((MD5_CTX *, unsigned char *, unsigned int));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+#define _MD5_H_
diff --git a/sys/netinet/ip_md5c.c b/sys/netinet/ip_md5c.c
new file mode 100644
index 00000000000..80eae87b3c7
--- /dev/null
+++ b/sys/netinet/ip_md5c.c
@@ -0,0 +1,383 @@
+/*
+ * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
+ * changes to accomodate it in the kernel by ji.
+ */
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/*
+ * Additions by JI
+ *
+ * HAVEMEMCOPY is defined if mem* routines are available
+ *
+ * HAVEHTON is defined if htons() and htonl() can be used
+ * for big/little endian conversions
+ *
+ */
+
+#include <sys/param.h>
+#include <netinet/ip_md5.h>
+#include <string.h>
+
+#define HAVEBCOPY
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define Encode MD5_memcpy
+#define Decode MD5_memcpy
+#else
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+#endif
+
+#ifdef HAVEMEMCOPY
+#include <memory.h>
+#define MD5_memcpy memcpy
+#define MD5_memset memset
+#else
+#ifdef HAVEBCOPY
+#define MD5_memcpy(_a,_b,_c) bcopy((_b),(_a),(_c))
+#define MD5_memset(_a,_b,_c) bzero((_a),(_c))
+#else
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+#endif
+#endif
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void realMD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ if (digest != NULL) /* Bill Simpson's padding */
+ {
+ /* store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+ }
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+#if BYTE_ORDER != LITTLE_ENDIAN
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+#endif
+
+#ifndef HAVEMEMCOPY
+#ifndef HAVEBCOPY
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+#endif
+#endif
+
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index 7eeb38ee6ad..ddfe57f6d3a 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_mroute.c,v 1.4 1996/05/10 12:31:19 deraadt Exp $ */
+/* $OpenBSD: ip_mroute.c,v 1.5 1997/02/20 01:08:04 deraadt Exp $ */
/* $NetBSD: ip_mroute.c,v 1.27 1996/05/07 02:40:50 thorpej Exp $ */
/*
@@ -42,6 +42,10 @@
#include <machine/stdarg.h>
+#ifdef IPSEC
+#include <dev/rndvar.h>
+#endif
+
#define IP_MULTICASTOPTS 0
#define M_PULLUP(m, len) \
do { \
@@ -1393,7 +1397,11 @@ encap_send(ip, vifp, m)
*/
ip_copy = mtod(mb_copy, struct ip *);
*ip_copy = multicast_encap_iphdr;
+#ifdef IPSEC
+ get_random_bytes((void *)&(ip_copy->ip_id), sizeof(ip_copy->ip_id));
+#else
ip_copy->ip_id = htons(ip_id++);
+#endif
ip_copy->ip_len = len;
ip_copy->ip_src = vifp->v_lcl_addr;
ip_copy->ip_dst = vifp->v_rmt_addr;
@@ -1439,16 +1447,19 @@ ipip_input(m, va_alist)
register int s;
register struct ifqueue *ifq;
register struct vif *vifp;
+ int isencaped = 0;
va_list ap;
va_start(ap, m);
hlen = va_arg(ap, int);
va_end(ap);
+#ifndef IPSEC
if (!have_encap_tunnel) {
rip_input(m);
return;
}
+#endif
/*
* dump the packet if it's not to a multicast destination or if
@@ -1458,6 +1469,10 @@ ipip_input(m, va_alist)
* at most one tunnel with the remote site).
*/
if (!IN_MULTICAST(((struct ip *)((char *)ip + hlen))->ip_dst.s_addr)) {
+#ifdef IPSEC
+ isencaped = 1;
+ goto acceptedhere;
+#endif
++mrtstat.mrts_bad_tunnel;
m_freem(m);
return;
@@ -1485,10 +1500,16 @@ ipip_input(m, va_alist)
} else
vifp = last_encap_vif;
+acceptedhere:
m->m_data += hlen;
m->m_len -= hlen;
m->m_pkthdr.len -= hlen;
+#ifdef IPSEC
+ if (isencaped == 0)
+ m->m_pkthdr.rcvif = vifp->v_ifp;
+#else
m->m_pkthdr.rcvif = vifp->v_ifp;
+#endif
ifq = &ipintrq;
s = splimp();
if (IF_QFULL(ifq)) {
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 2b31d8dd9f2..0bfe9cce3f7 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.6 1996/07/29 02:34:31 downsj Exp $ */
+/* $OpenBSD: ip_output.c,v 1.7 1997/02/20 01:08:06 deraadt Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -61,6 +61,13 @@
#include <machine/stdarg.h>
+#ifdef IPSEC
+#include <net/encap.h>
+#include <netinet/ip_ipsp.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#endif
+
static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
static void ip_mloopback
__P((struct ifnet *, struct mbuf *, struct sockaddr_in *));
@@ -96,6 +103,11 @@ ip_output(m0, va_alist)
int flags;
struct ip_moptions *imo;
va_list ap;
+#ifdef IPSEC
+ struct mbuf *mp;
+ struct udphdr *udp;
+ struct tcphdr *tcp;
+#endif
va_start(ap, m0);
opt = va_arg(ap, struct mbuf *);
@@ -127,6 +139,174 @@ ip_output(m0, va_alist)
} else {
hlen = ip->ip_hl << 2;
}
+
+#ifdef IPSEC
+ /*
+ * Check if the packet needs encapsulation
+ */
+ if (!(flags & IP_ENCAPSULATED)) {
+ struct route_enc {
+ struct rtentry *re_rt;
+ struct sockaddr_encap re_dst;
+ } re0, *re = &re0;
+ struct sockaddr_encap *dst, *gw;
+ struct tdb *tdb;
+
+ bzero((caddr_t)re, sizeof (*re));
+ dst = (struct sockaddr_encap *)&re->re_dst;
+ dst->sen_family = AF_ENCAP;
+ dst->sen_len = SENT_IP4_LEN;
+ dst->sen_type = SENT_IP4;
+ dst->sen_ip_src = ip->ip_src;
+ dst->sen_ip_dst = ip->ip_dst;
+ dst->sen_proto = ip->ip_p;
+
+ if ((m->m_len < hlen + 2*sizeof(u_int16_t)) &&
+ ((m = m_pullup(m, hlen + 2*sizeof(u_int16_t))) == 0))
+ goto bad;
+
+ switch (ip->ip_p) {
+ case IPPROTO_TCP:
+ udp = (struct udphdr *) (mtod(m, u_char *) + hlen);
+ dst->sen_sport = ntohs(udp->uh_sport);
+ dst->sen_dport = ntohs(udp->uh_dport);
+ break;
+ case IPPROTO_UDP:
+ tcp = (struct tcphdr *) (mtod(m, u_char *) + hlen);
+ dst->sen_sport = ntohs(tcp->th_sport);
+ dst->sen_dport = ntohs(tcp->th_dport);
+ break;
+ default:
+ dst->sen_sport = 0;
+ dst->sen_dport = 0;
+ }
+ rtalloc((struct route *)re);
+ if (re->re_rt == NULL)
+ goto no_encap;
+
+ gw = (struct sockaddr_encap *)(re->re_rt->rt_gateway);
+ if (gw == NULL || gw->sen_type != SENT_IPSP) {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: no gw or gw data not IPSP\n");
+#endif ENCDEBUG
+ m_freem(m);
+ RTFREE(re->re_rt);
+ return EHOSTUNREACH;
+ }
+
+ ifp = re->re_rt->rt_ifp;
+
+ if (ip->ip_src.s_addr == INADDR_ANY) {
+ struct sockaddr_encap *sen;
+ struct sockaddr_in *sinp;
+
+ if (ifp->if_addrlist.tqh_first)
+ sen = (struct sockaddr_encap *)
+ ifp->if_addrlist.tqh_first->ifa_addr;
+ else {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: interface %s has no default address\n",
+ ifp->if_xname);
+#endif ENCDEBUG
+ return ENXIO;
+ }
+
+ if (sen->sen_family != AF_ENCAP) {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: %s does not have AF_ENCAP address\n",
+ ifp->if_xname);
+#endif ENCDEBUG
+ m_freem(m);
+ RTFREE(re->re_rt);
+ return EHOSTDOWN;
+ }
+
+ if (sen->sen_type != SENT_DEFIF) {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: %s does not have SENT_DEFIF address\n",
+ ifp->if_xname);
+#endif ENCDEBUG
+ m_freem(m);
+ RTFREE(re->re_rt);
+ return EHOSTDOWN;
+ }
+ sinp = (struct sockaddr_in *)&(sen->sen_dfl);
+ ip->ip_src = sinp->sin_addr;
+ }
+
+ if (hlen > sizeof (struct ip)) { /* XXX IPOPT */
+ ip_stripoptions(m, (struct mbuf *)0);
+ hlen = sizeof (struct ip);
+ }
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: encapsulating %x->%x through %x->%x\n",
+ ip->ip_src.s_addr, ip->ip_dst.s_addr,
+ gw->sen_ipsp_src, gw->sen_ipsp_dst);
+#endif
+ ip->ip_len = htons((u_short)ip->ip_len);
+ ip->ip_off = htons((u_short)ip->ip_off);
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(m, hlen);
+
+ /*
+ * At this point we have an IPSP "gateway" (tunnel) spec.
+ * Use the destination of the tunnel and the SPI to
+ * look up the necessary Tunnel Control Block. Look it up,
+ * and then pass it, along with the packet and the gw,
+ * to the appropriate transformation.
+ */
+
+ tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, gw->sen_ipsp_dst);
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: tdb=0x%x, tdb->tdb_xform=0x%x, tdb->tdb_xform->xf_output=%x\n", tdb, tdb->tdb_xform, tdb->tdb_xform->xf_output);
+#endif ENCDEBUG
+
+ while (tdb && tdb->tdb_xform) {
+ m0 = NULL;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: calling %s\n",
+ tdb->tdb_xform->xf_name);
+#endif ENCDEBUG
+ error = (*(tdb->tdb_xform->xf_output))(m, gw, tdb, &mp);
+ if (mp == NULL)
+ error = EFAULT;
+ if (error) {
+ RTFREE(re->re_rt);
+ return error;
+ }
+ tdb = tdb->tdb_onext;
+ m = mp;
+ }
+
+ /*
+ * At this point, mp is pointing to an mbuf chain with the
+ * processed packet. Call ourselves recursively, but
+ * bypass the encap code.
+ */
+
+ RTFREE(re->re_rt);
+
+ ip = mtod(m, struct ip *);
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+
+ return ip_output(m, NULL, NULL, IP_ENCAPSULATED | IP_RAWOUTPUT, NULL);
+
+no_encap:
+ if (re->re_rt)
+ RTFREE(re->re_rt);
+ }
+#endif IPSEC
+
/*
* Route packet.
*/
diff --git a/sys/netinet/ip_sha1.c b/sys/netinet/ip_sha1.c
new file mode 100644
index 00000000000..c90a61d0033
--- /dev/null
+++ b/sys/netinet/ip_sha1.c
@@ -0,0 +1,166 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#define SHA1HANDSOFF
+
+#include <sys/param.h>
+#include <netinet/ip_sha1.h>
+#include <string.h>
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64])
+{
+unsigned long a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ unsigned long l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ bcopy(buffer, block, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)
+{
+unsigned int i;
+unsigned long j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j) context->count[1] += (len>>29)+1;
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ bcopy(data, &context->buffer[j], (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ bcopy(&data[i], &context->buffer[j], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+unsigned long i, j;
+unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = j = 0;
+ bzero(context->buffer, 64);
+ bzero(context->state, 20);
+ bzero(context->count, 8);
+ bzero(&finalcount, 8);
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
diff --git a/sys/netinet/ip_sha1.h b/sys/netinet/ip_sha1.h
new file mode 100644
index 00000000000..e4fd065782c
--- /dev/null
+++ b/sys/netinet/ip_sha1.h
@@ -0,0 +1,16 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+*/
+
+typedef struct {
+ unsigned long state[5];
+ unsigned long count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index c79623bd0a8..743172b3cf9 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_var.h,v 1.4 1997/01/26 01:23:44 tholo Exp $ */
+/* $OpenBSD: ip_var.h,v 1.5 1997/02/20 01:08:09 deraadt Exp $ */
/* $NetBSD: ip_var.h,v 1.16 1996/02/13 23:43:20 christos Exp $ */
/*
@@ -154,6 +154,10 @@ struct ipstat {
#define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */
#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */
+#ifdef IPSEC
+#define IP_ENCAPSULATED 0x0800 /* encapsulated already */
+#endif
+
struct ipstat ipstat;
LIST_HEAD(ipqhead, ipq) ipq; /* ip reass. queue */
u_int16_t ip_id; /* ip packet ctr, for ids */
diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
index 02e4a1dc8e0..63743b5102d 100644
--- a/sys/sys/malloc.h
+++ b/sys/sys/malloc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: malloc.h,v 1.8 1997/02/13 18:11:04 kstailey Exp $ */
+/* $OpenBSD: malloc.h,v 1.9 1997/02/20 01:07:34 deraadt Exp $ */
/* $NetBSD: malloc.h,v 1.23 1996/04/05 04:52:52 mhitch Exp $ */
/*
@@ -123,7 +123,9 @@
#define M_AFS 70 /* Andrew File System */
#define M_ADOSFSBITMAP 71 /* adosfs bitmap */
#define M_EXT2FSNODE 72 /* EXT2FS vnode private part */
-#define M_PFIL 73 /* packer filter */
+#define M_PFIL 73 /* packer filter */
+#define M_TDB 75 /* Transforms database */
+#define M_XDATA 76 /* IPsec data */
#define M_TEMP 84 /* misc temporary data buffers */
#define M_LAST 85 /* Must be last type + 1 */
@@ -202,7 +204,10 @@
"adosfs bitmap", /* 71 M_ADOSFSBITMAP */ \
"EXT2FS node", /* 72 M_EXT2FSNODE */ \
"pfil", /* 73 M_PFIL */ \
- NULL, NULL, NULL, NULL, NULL, \
+ NULL, \
+ "tdb", /* 75 M_TDB */ \
+ "xform_data", /* 76 M_XDATA */ \
+ NULL, NULL, \
NULL, NULL, NULL, NULL, NULL, \
"temp", /* 84 M_TEMP */ \
}
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index 2069279f6c5..d9e2c6f390d 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: socket.h,v 1.8 1996/12/12 13:50:53 mickey Exp $ */
+/* $OpenBSD: socket.h,v 1.9 1997/02/20 01:07:35 deraadt Exp $ */
/* $NetBSD: socket.h,v 1.14 1996/02/09 18:25:36 christos Exp $ */
/*
@@ -125,8 +125,8 @@ struct linger {
#define AF_ISDN 26 /* Integrated Services Digital Network*/
#define AF_E164 AF_ISDN /* CCITT E.164 recommendation */
#define AF_NATM 27 /* native ATM access */
-
-#define AF_MAX 28
+#define AF_ENCAP 28
+#define AF_MAX 29
/*
* Structure used by kernel to store most
@@ -180,7 +180,7 @@ struct sockproto {
#define PF_PIP pseudo_AF_PIP
#define PF_ISDN AF_ISDN
#define PF_NATM AF_NATM
-
+#define PF_ENCAP AF_ENCAP
#define PF_MAX AF_MAX
/*
@@ -221,6 +221,7 @@ struct sockproto {
{ "sip", CTLTYPE_NODE }, \
{ "pip", CTLTYPE_NODE }, \
{ "natm", CTLTYPE_NODE }, \
+ { "ipsec", CTLTYPE_NODE }, \
}
/*