IPSEC package by John Ioannidis and Angelos D. Keromytis. Written in
authorderaadt <deraadt@openbsd.org>
Thu, 20 Feb 1997 01:07:26 +0000 (01:07 +0000)
committerderaadt <deraadt@openbsd.org>
Thu, 20 Feb 1997 01:07:26 +0000 (01:07 +0000)
Greece. From ftp.funet.fi:/pub/unix/security/net/ip/BSDipsec.tar.gz

33 files changed:
sys/conf/files
sys/kern/uipc_domain.c
sys/miscfs/kernfs/kernfs_vnops.c
sys/net/encap.c [new file with mode: 0644]
sys/net/encap.h [new file with mode: 0644]
sys/net/if_enc.c [new file with mode: 0644]
sys/net/if_types.h
sys/net/route.c
sys/netinet/in.h
sys/netinet/in_proto.c
sys/netinet/ip_ah.c [new file with mode: 0644]
sys/netinet/ip_ah.h [new file with mode: 0644]
sys/netinet/ip_ahhmacmd5.c [new file with mode: 0644]
sys/netinet/ip_ahhmacsha1.c [new file with mode: 0644]
sys/netinet/ip_ahmd5.c [new file with mode: 0644]
sys/netinet/ip_esp.c [new file with mode: 0644]
sys/netinet/ip_esp.h [new file with mode: 0644]
sys/netinet/ip_esp3desmd5.c [new file with mode: 0644]
sys/netinet/ip_espdes.c [new file with mode: 0644]
sys/netinet/ip_espdesmd5.c [new file with mode: 0644]
sys/netinet/ip_ip4.c [new file with mode: 0644]
sys/netinet/ip_ip4.h [new file with mode: 0644]
sys/netinet/ip_ipsp.c [new file with mode: 0644]
sys/netinet/ip_ipsp.h [new file with mode: 0644]
sys/netinet/ip_md5.h [new file with mode: 0644]
sys/netinet/ip_md5c.c [new file with mode: 0644]
sys/netinet/ip_mroute.c
sys/netinet/ip_output.c
sys/netinet/ip_sha1.c [new file with mode: 0644]
sys/netinet/ip_sha1.h [new file with mode: 0644]
sys/netinet/ip_var.h
sys/sys/malloc.h
sys/sys/socket.h

index dbcb962..f3c3d77 100644 (file)
@@ -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
index 406a420..790ecea 100644 (file)
@@ -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);
index f77a606..0a94d88 100644 (file)
@@ -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 (file)
index 0000000..a8e1de6
--- /dev/null
@@ -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 (file)
index 0000000..4d105db
--- /dev/null
@@ -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 (file)
index 0000000..5cecd2d
--- /dev/null
@@ -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;
+}
index fc3e749..4b8fe65 100644 (file)
@@ -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 */
index 59f83f1..05ef299 100644 (file)
@@ -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 $      */
 
 /*
 #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,
index 7e9c0fa..d69dbce 100644 (file)
@@ -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 */
 
index 295ca09..66c5ddd 100644 (file)
@@ -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 (file)
index 0000000..e08f4c2
--- /dev/null
@@ -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 (file)
index 0000000..4ac4334
--- /dev/null
@@ -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 (file)
index 0000000..008fef0
--- /dev/null
@@ -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 (file)
index 0000000..af30682
--- /dev/null
@@ -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 (file)
index 0000000..27429cb
--- /dev/null
@@ -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 (file)
index 0000000..13541d3
--- /dev/null
@@ -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 (file)
index 0000000..abd2abf
--- /dev/null
@@ -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 (file)
index 0000000..d0d5b20
--- /dev/null
@@ -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 (file)
index 0000000..b034a3e
--- /dev/null
@@ -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 (file)
index 0000000..ed1b2c9
--- /dev/null
@@ -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 (file)
index 0000000..b16b078
--- /dev/null
@@ -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 (file)
index 0000000..4e580fe
--- /dev/null
@@ -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 (file)
index 0000000..390745d
--- /dev/null
@@ -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 (file)
index 0000000..85e122a
--- /dev/null
@@ -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 (file)
index 0000000..2e102c8
--- /dev/null
@@ -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 (file)
index 0000000..80eae87
--- /dev/null
@@ -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
+       
index 7eeb38e..ddfe57f 100644 (file)
@@ -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 $   */
 
 /*
 
 #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)) {
index 2b31d8d..0bfe9cc 100644 (file)
@@ -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 $  */
 
 /*
 
 #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 (file)
index 0000000..c90a61d
--- /dev/null
@@ -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 (file)
index 0000000..e4fd065
--- /dev/null
@@ -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);
index c79623b..743172b 100644 (file)
@@ -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 */
index 02e4a1d..63743b5 100644 (file)
@@ -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 $       */
 
 /*
 #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 */
 
        "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 */ \
 }
index 2069279..d9e2c6f 100644 (file)
@@ -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 }, \
 }
 
 /*