summaryrefslogtreecommitdiff
path: root/sys/netinet/ip_espdesmd5.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1997-02-20 01:08:13 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1997-02-20 01:08:13 +0000
commit27f7e7b789913e142fd048ad0f5e9fe6fee94c27 (patch)
tree92f475f4da1f7ac2c6a9fac20881c666173e7600 /sys/netinet/ip_espdesmd5.c
parent64c38b22e9e85f411969b697297f6dfd609dc83c (diff)
IPSEC package by John Ioannidis and Angelos D. Keromytis. Written in
Greece. From ftp.funet.fi:/pub/unix/security/net/ip/BSDipsec.tar.gz
Diffstat (limited to 'sys/netinet/ip_espdesmd5.c')
-rw-r--r--sys/netinet/ip_espdesmd5.c805
1 files changed, 805 insertions, 0 deletions
diff --git a/sys/netinet/ip_espdesmd5.c b/sys/netinet/ip_espdesmd5.c
new file mode 100644
index 00000000000..ed1b2c9845a
--- /dev/null
+++ b/sys/netinet/ip_espdesmd5.c
@@ -0,0 +1,805 @@
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Based on draft-ietf-ipsec-esp-des-md5-03.txt.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
+
+#include <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_esp.h>
+
+extern struct ifnet loif;
+
+extern void des_ecb_encrypt(caddr_t, caddr_t, caddr_t, int);
+extern void des_set_key(caddr_t, caddr_t);
+
+int
+espdesmd5_attach()
+{
+ return 0;
+}
+
+/*
+ * espdesmd5_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data, in
+ * this case, the encryption and decryption key schedules
+ */
+
+int
+espdesmd5_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ struct espdesmd5_xdata *xd;
+ struct encap_msghdr *em;
+ struct espdesmd5_xencap txd;
+ u_char buf[ESPDESMD5_KEYSZ];
+ int len;
+ MD5_CTX ctx;
+
+ tdbp->tdb_xform = xsp;
+
+ m = m_pullup(m, ESPDESMD5_ULENGTH);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_init: can't pull up %d bytes\n", ESP_ULENGTH);
+#endif ENCDEBUG
+ return ENOBUFS;
+ }
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof (struct espdesmd5_xdata),
+ M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ return ENOBUFS;
+ bzero(tdbp->tdb_xdata, sizeof (struct espdesmd5_xdata));
+ xd = (struct espdesmd5_xdata *)tdbp->tdb_xdata;
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI_FLEN != ESPDESMD5_ULENGTH)
+ {
+ free((caddr_t)tdbp->tdb_xdata, M_XDATA);
+ tdbp->tdb_xdata = NULL;
+ return EINVAL;
+ }
+
+ m_copydata(m, EMT_SETSPI_FLEN, em->em_msglen - EMT_SETSPI_FLEN, (caddr_t)&txd);
+
+ if ((txd.edx_ivlen != 0) && (txd.edx_ivlen != 8))
+ {
+ free((caddr_t)tdbp->tdb_xdata, M_XDATA);
+ tdbp->tdb_xdata = NULL;
+ return EINVAL;
+ }
+
+ bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
+
+ xd->edx_ivlen = txd.edx_ivlen;
+ xd->edx_bitmap = 0;
+ xd->edx_wnd = txd.edx_wnd;
+
+ /* Fix the IV */
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ {
+ if (txd.edx_initiator)
+ printf("INITIATOR\n");
+ printf("IV length: %d\n", txd.edx_ivlen);
+ }
+#endif
+ if (txd.edx_ivlen)
+ bcopy(txd.edx_ivv, xd->edx_iv, ESPDESMD5_IVS);
+ else
+ {
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_IPADI :
+ ESPDESMD5_IPADR;
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ bcopy(buf, xd->edx_iv, ESPDESMD5_IVS);
+#ifdef ENCDEBUG
+ printf("IV ");
+ if (encdebug)
+ for (len = 0; len < ESPDESMD5_IVS; len++)
+ printf(" %02x", xd->edx_iv[len]);
+ printf("\n");
+#endif
+ }
+
+ /* DES key */
+
+ realMD5Init(&ctx);
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_DPADI : ESPDESMD5_DPADR;
+
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ des_set_key((caddr_t)buf, (caddr_t)(xd->edx_eks));
+
+ /* HMAC contexts */
+
+ realMD5Init(&ctx);
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_HPADI : ESPDESMD5_HPADR;
+
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+
+ bzero(buf + ESPDESMD5_ALEN, ESPDESMD5_KEYSZ - ESPDESMD5_ALEN);
+
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] ^= ESPDESMD5_IPAD_VAL;
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ xd->edx_ictx = ctx;
+
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] ^= (ESPDESMD5_IPAD_VAL ^ ESPDESMD5_OPAD_VAL);
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ xd->edx_octx = ctx;
+
+ /* Replay counter */
+
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_RPADI :
+ ESPDESMD5_RPADR;
+
+ realMD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ bcopy(buf, (unsigned char *)&(xd->edx_rpl), ESPDESMD5_RPLENGTH);
+ xd->edx_initial = xd->edx_rpl - 1;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("Initial replay counter: %x (%x)\n", xd->edx_rpl,
+ xd->edx_initial);
+#endif
+
+ bzero(&txd, sizeof(struct espdesmd5_xencap));
+ bzero(buf, ESPDESMD5_KEYSZ);
+ bzero(&ctx, sizeof(MD5_CTX));
+
+ return 0;
+}
+
+int
+espdesmd5_zeroize(struct tdb *tdbp)
+{
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+
+struct mbuf *
+espdesmd5_input(struct mbuf *m, struct tdb *tdb)
+{
+ struct espdesmd5_xdata *xd;
+ struct ip *ip, ipo;
+ u_char iv[8], niv[8], blk[8], auth[ESPDESMD5_ALEN];
+ u_char iauth[ESPDESMD5_ALEN];
+ u_char *idat, *odat;
+ struct esp *esp;
+ struct ifnet *rcvif;
+ int plen, ilen, olen, i, authp, oplen, errc;
+ u_int32_t rplc, tbitmap, trpl;
+ u_char padsize, nextproto;
+ struct mbuf *mi, *mo;
+ MD5_CTX ctx;
+
+ xd = (struct espdesmd5_xdata *)tdb->tdb_xdata;
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_input: receive interface is NULL!!!\n");
+#endif ENCDEBUG
+ rcvif = &loif;
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo = *ip;
+ esp = (struct esp *)(ip + 1);
+
+ plen = m->m_pkthdr.len - sizeof (struct ip) - sizeof (u_long) - xd->edx_ivlen;
+ if (plen & 07)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_input: payload not a multiple of 8 octets\n");
+#endif ENCDEBUG
+ espstat.esps_badilen++;
+ m_freem(m);
+ return NULL;
+ }
+
+ oplen = plen;
+ ilen = m->m_len - sizeof (struct ip) - ESPDESMD5_IVS - sizeof(u_long);
+ idat = mtod(m, unsigned char *) + sizeof (struct ip) + sizeof(u_long) +
+ ESPDESMD5_IVS;
+
+ if (xd->edx_ivlen == 0) /* KeyIV in use */
+ {
+ bcopy(xd->edx_iv, iv, ESPDESMD5_IVS);
+ ilen += ESPDESMD5_IVS;
+ idat -= ESPDESMD5_IVS;
+ }
+ else
+ bcopy(idat - ESPDESMD5_IVS, iv, ESPDESMD5_IVS);
+
+ olen = ilen;
+ odat = idat;
+ mi = mo = m;
+ i = 0;
+ authp = 0;
+
+ ctx = xd->edx_ictx;
+
+ MD5Update(&ctx, (unsigned char *)&(tdb->tdb_spi), sizeof(u_int32_t));
+ MD5Update(&ctx, iv, ESPDESMD5_IVS);
+
+#ifdef ENCDEBUG
+ printf("IV ");
+ for (i = 0; i < ESPDESMD5_IVS; i++)
+ printf(" %02x", iv[i]);
+ printf("\n");
+ i = 0;
+#endif
+
+ /*
+ * At this point:
+ * plen is # of encapsulated payload octets
+ * ilen is # of octets left in this mbuf
+ * idat is first encapsulated payload octed in this mbuf
+ * same for olen and odat
+ * iv contains the IV.
+ * mi and mo point to the first mbuf
+ *
+ * From now on until the end of the mbuf chain:
+ * . move the next eight octets of the chain into blk[]
+ * (ilen, idat, and mi are adjusted accordingly)
+ * and save it back into iv[]
+ * . decrypt blk[], xor with iv[], put back into chain
+ * (olen, odat, amd mo are adjusted accordingly)
+ * . repeat
+ */
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("espdesmd5_input: bad chain (i)\n");
+ ilen = mi->m_len;
+ idat = (u_char *)mi->m_data;
+ }
+
+ blk[i] = niv[i] = *idat++;
+ i++;
+ ilen--;
+
+ if (i == 8)
+ {
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks), 0);
+ for (i=0; i<8; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("espdesmd5_input: bad chain (o)\n");
+ olen = mo->m_len;
+ odat = (u_char *)mo->m_data;
+ }
+ *odat = blk[i] ^ iv[i];
+ iv[i] = niv[i];
+ blk[i] = *odat++; /* needed elsewhere */
+ olen--;
+ }
+ i = 0;
+
+ if (plen < ESPDESMD5_ALEN)
+ {
+ bcopy(blk, auth + authp, ESPDESMD5_DESBLK);
+ authp += ESPDESMD5_DESBLK;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("Copying authenticator from %d\n",
+ plen);
+#endif
+ }
+ else
+ {
+ if (plen == ESPDESMD5_ALEN + 1)
+ {
+ nextproto = blk[7];
+ padsize = blk[6];
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("Next protocol: %d\nPadsize: %d\n", nextproto, padsize);
+#endif
+ }
+ else
+ if (plen + 7 == oplen)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("SEQ %02x %02x %02x %02x\n",
+ blk[0], blk[1], blk[2],
+ blk[3]);
+#endif
+ tbitmap = xd->edx_bitmap; /* Save it */
+ trpl = xd->edx_rpl;
+ rplc = ntohl(*((u_int32_t *)blk));
+ if ((errc = checkreplaywindow32(rplc, xd->edx_initial, &(xd->edx_rpl), xd->edx_wnd, &(xd->edx_bitmap))) != 0)
+ {
+ switch (errc)
+ {
+ case 1:
+#ifdef ENCDEBUG
+ printf("espdesmd5_input: replay counter wrapped\n");
+#endif
+ espstat.esps_wrap++;
+ break;
+ case 2:
+#ifdef ENCDEBUG
+ printf("espdesmd5_input: received old packet, seq = %08x\n", rplc);
+#endif
+ espstat.esps_replay++;
+ break;
+ case 3:
+#ifdef ENCDEBUG
+ printf("espdesmd5_input: packet already received\n");
+#endif
+ espstat.esps_replay++;
+ break;
+ }
+ m_freem(m);
+ return NULL;
+ }
+ }
+
+ MD5Update(&ctx, blk, ESPDESMD5_DESBLK);
+ }
+ }
+
+ plen--;
+ }
+
+ /*
+ * Now, the entire chain has been decrypted.
+ */
+
+ MD5Final(iauth, &ctx);
+ ctx = xd->edx_octx;
+ MD5Update(&ctx, iauth, ESPDESMD5_ALEN);
+ MD5Final(iauth, &ctx);
+
+#ifdef ENCDEBUG
+ printf("RECEIVED ");
+ for (rplc = 0; rplc < ESPDESMD5_ALEN; rplc++)
+ printf(" %02x", auth[rplc]);
+ printf("\nSHOULD HAVE ");
+ for (rplc = 0; rplc < ESPDESMD5_ALEN; rplc++)
+ printf(" %02x", iauth[rplc]);
+ printf("\n");
+#endif
+
+ if (bcmp(auth, iauth, ESPDESMD5_ALEN))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_input: bad auth\n");
+#endif
+ xd->edx_rpl = trpl;
+ xd->edx_bitmap = tbitmap; /* Restore */
+ espstat.esps_badauth++;
+ m_freem(m);
+ return NULL;
+ }
+
+ m_adj(m, - padsize - 2 - ESPDESMD5_ALEN);
+ m_adj(m, 4 + xd->edx_ivlen + ESPDESMD5_RPLENGTH);
+
+ if (m->m_len < sizeof (struct ip))
+ {
+ m = m_pullup(m, sizeof (struct ip));
+ if (m == NULL)
+ {
+ xd->edx_rpl = trpl;
+ xd->edx_bitmap = tbitmap;
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo.ip_p = nextproto;
+ ipo.ip_id = htons(ipo.ip_id);
+ ipo.ip_off = 0;
+ ipo.ip_len += sizeof (struct ip) - ESPDESMD5_RPLENGTH - 4 - xd->edx_ivlen - padsize - 2 - ESPDESMD5_ALEN;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("IP packet size %d\n", ipo.ip_len);
+#endif
+ ipo.ip_len = htons(ipo.ip_len);
+ ipo.ip_sum = 0;
+ *ip = ipo;
+ ip->ip_sum = in_cksum(m, sizeof (struct ip));
+
+ return m;
+}
+
+int
+espdesmd5_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb, struct mbuf **mp)
+{
+ struct espdesmd5_xdata *xd;
+ struct ip *ip, ipo;
+ int i, ilen, olen, ohlen, nh, rlen, plen, padding;
+ u_int32_t rplc;
+ u_long spi;
+ struct mbuf *mi, *mo, *ms;
+ u_char *pad, *idat, *odat;
+ u_char iv[ESPDESMD5_IVS], blk[8], auth[ESPDESMD5_ALEN];
+ MD5_CTX ctx;
+
+ m = m_pullup(m, sizeof (struct ip)); /* Get IP header in one mbuf */
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+ spi = tdb->tdb_spi;
+
+ xd = (struct espdesmd5_xdata *)tdb->tdb_xdata;
+ ilen = ntohs(ip->ip_len); /* Size of the packet */
+ ohlen = sizeof (u_int32_t) + xd->edx_ivlen; /* size of plaintext ESP */
+
+ if (xd->edx_rpl == xd->edx_initial)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: replay counter wrapped\n");
+#endif
+ espstat.esps_wrap++;
+ return EHOSTDOWN; /* XXX */
+ }
+
+ ipo = *ip;
+ nh = ipo.ip_p;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: next protocol is %d\n", nh);
+#endif
+
+ /* Raw payload length */
+ rlen = ESPDESMD5_RPLENGTH + ilen - sizeof (struct ip);
+
+ padding = ((8 - ((rlen + 2) % 8)) % 8) + 2;
+
+ pad = (u_char *)m_pad(m, padding);
+ if (pad == NULL)
+ return ENOBUFS;
+
+ pad[padding-2] = padding - 2;
+ pad[padding-1] = nh;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: padding %d bytes\n", padding);
+#endif
+
+ plen = rlen + padding + ESPDESMD5_ALEN;
+
+ ctx = xd->edx_ictx; /* Get inner padding cached */
+
+ bcopy(xd->edx_iv, iv, ESPDESMD5_IVS);
+
+ MD5Update(&ctx, (u_char *)&spi, sizeof(u_long));
+ MD5Update(&ctx, iv, ESPDESMD5_IVS);
+ rplc = htonl(xd->edx_rpl);
+ MD5Update(&ctx, (unsigned char *)&rplc, ESPDESMD5_RPLENGTH);
+ xd->edx_rpl++;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: using replay counter %x\n",
+ xd->edx_rpl - 1);
+#endif
+ mi = m;
+
+ /* MD5 the data */
+ while (mi != NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: MD5'ing %d bytes\n", mi->m_len);
+#endif
+ if (mi == m)
+ MD5Update(&ctx, (u_char *)mi->m_data + sizeof(struct ip),
+ mi->m_len - sizeof(struct ip));
+ else
+ MD5Update(&ctx, (u_char *)mi->m_data, mi->m_len);
+ mi = mi->m_next;
+ }
+
+ MD5Final(auth, &ctx);
+ ctx = xd->edx_octx;
+ MD5Update(&ctx, auth, ESPDESMD5_ALEN);
+ MD5Final(auth, &ctx); /* That's the authenticator */
+
+ /*
+ * This routine is different from espdes_output() in that
+ * here we construct the whole packet before starting encrypting.
+ */
+
+ m = m_pullup(m, sizeof(struct ip) + ESPDESMD5_RPLENGTH +
+ sizeof(u_int32_t) + xd->edx_ivlen);
+ if (m == NULL)
+ return ENOBUFS;
+
+ /* Copy data if necessary */
+ if (m->m_len - sizeof(struct ip))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: pushing data\n");
+#endif
+ ms = m_copym(m, sizeof(struct ip), m->m_len - sizeof(struct ip),
+ M_DONTWAIT);
+ if (ms == NULL)
+ return ENOBUFS;
+
+ ms->m_next = m->m_next;
+ m->m_next = ms;
+ m->m_len = sizeof(struct ip);
+ }
+
+ /* Copy SPI, IV (or not) and replay counter */
+ bcopy((caddr_t)&spi, mtod(m, caddr_t) + sizeof (struct ip),
+ sizeof (u_int32_t));
+ bcopy((caddr_t)iv, mtod(m, caddr_t) + sizeof (struct ip) +
+ sizeof (u_int32_t), xd->edx_ivlen);
+ bcopy((caddr_t)&rplc, mtod(m, caddr_t) + sizeof(struct ip) +
+ sizeof(u_int32_t) + xd->edx_ivlen, ESPDESMD5_RPLENGTH);
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: replay counter (wire value) %x\n", rplc);
+#endif
+
+ /* Adjust the length accordingly */
+ m->m_len += sizeof(u_int32_t) + ESPDESMD5_RPLENGTH + xd->edx_ivlen;
+ m->m_pkthdr.len += sizeof(u_int32_t) + ESPDESMD5_RPLENGTH +
+ xd->edx_ivlen;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: mbuf chain length %d\n", m->m_pkthdr.len);
+#endif
+
+ /* Let's append the authenticator too */
+ MGET(ms, M_DONTWAIT, MT_DATA);
+ if (ms == NULL)
+ return ENOBUFS;
+
+ bcopy(auth, mtod(ms, u_char *), ESPDESMD5_ALEN);
+ ms->m_len = ESPDESMD5_ALEN;
+
+ m_cat(m, ms);
+ m->m_pkthdr.len += ESPDESMD5_ALEN; /* Adjust length */
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: final mbuf chain length %d\n",
+ m->m_pkthdr.len);
+#endif
+
+ ilen = olen = m->m_len - sizeof (struct ip) - sizeof(u_int32_t) -
+ xd->edx_ivlen;
+ idat = odat = mtod(m, u_char *) + sizeof (struct ip) +
+ sizeof(u_int32_t) + xd->edx_ivlen;
+ i = 0;
+ mi = mo = m;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: starting encryption with ilen=%d, plen=%d\n", ilen, plen);
+#endif
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("espdesmd5_output: bad chain (i)\n");
+ ilen = mi->m_len;
+ idat = (u_char *)mi->m_data;
+ }
+
+ blk[i] = *idat++ ^ iv[i];
+
+ i++;
+ ilen--;
+
+ if (i == 8) /* We have full block */
+ {
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks), 1);
+ for (i=0; i<8; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("espdesmd5_output: bad chain (o)\n");
+ olen = mo->m_len;
+ odat = (u_char *)mo->m_data;
+ }
+ *odat++ = blk[i];
+ iv[i] = blk[i];
+ olen--;
+ }
+ i = 0;
+ }
+
+ plen--;
+ }
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("espdesmd5_output: almost done now\n");
+#endif
+
+ bcopy(iv, xd->edx_iv, ESPDESMD5_IVS); /* New IV */
+
+ /* Fix the length and the next protocol, copy back and off we go */
+ ipo.ip_len = htons(sizeof (struct ip) + ohlen + rlen + padding +
+ ESPDESMD5_ALEN);
+ ipo.ip_p = IPPROTO_ESP;
+ bcopy((caddr_t)&ipo, mtod(m, caddr_t), sizeof(struct ip));
+
+ *mp = m;
+ return 0;
+}
+
+
+/*
+ * both versions of the checkreplaywindow for 32 and 64 bit counters
+ * return 0 on success
+ * return 1 for counter == 0
+ * return 2 for very old packet
+ * return 3 for packet within current window but already received
+ */
+
+int
+checkreplaywindow64(u_int64_t seq, u_int64_t *lastseq, u_int64_t window, u_int64_t *bitmap)
+{
+ u_int64_t diff;
+
+ if (seq == 0)
+ return 1;
+
+ if (seq > *lastseq)
+ {
+ diff = seq - *lastseq;
+ if (diff < window)
+ *bitmap = ((*bitmap) << diff) | 1;
+ else
+ *bitmap = 1;
+ *lastseq = seq;
+ return 0;
+ }
+ diff = *lastseq - seq;
+ if (diff >= window)
+ {
+ espstat.esps_wrap++;
+ return 2;
+ }
+ if ((*bitmap) & (((u_int64_t) 1) << diff))
+ {
+ espstat.esps_replay++;
+ return 3;
+ }
+ *bitmap |= (((u_int64_t) 1) << diff);
+ return 0;
+}
+
+int
+checkreplaywindow32(u_int32_t seq, u_int32_t initial, u_int32_t *lastseq, u_int32_t window, u_int32_t *bitmap)
+{
+ u_int32_t diff;
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("checkreplaywindow32: seq=%x lastseq=%x\n", seq, *lastseq);
+#endif
+
+ seq -= initial;
+
+ if (seq == 0)
+ return 1;
+
+ if (seq > *lastseq - initial)
+ {
+ diff = seq - (*lastseq - initial);
+ if (diff < window)
+ *bitmap = ((*bitmap) << diff) | 1;
+ else
+ *bitmap = 1;
+ *lastseq = seq + initial;
+ return 0;
+ }
+ diff = *lastseq - initial - seq;
+ if (diff >= window)
+ {
+ espstat.esps_wrap++;
+ return 2;
+ }
+ if ((*bitmap) & (((u_int32_t) 1) << diff))
+ {
+ espstat.esps_replay++;
+ return 3;
+ }
+ *bitmap |= (((u_int32_t) 1) << diff);
+ return 0;
+}