summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>1997-08-26 12:02:51 +0000
committerNiels Provos <provos@cvs.openbsd.org>1997-08-26 12:02:51 +0000
commit849abbcd3c3f1e07157dff9e2a48749adf85561d (patch)
tree0221e86537b97006122ed8c819f3430f7ba0157f
parent8cd4d12bc3a43ab1d219c44c23d9de367fd9b8cc (diff)
new esp: encryption, authentication and replay protection +
tiny bug fixes
-rw-r--r--sys/netinet/ip_ah_new.c4
-rw-r--r--sys/netinet/ip_esp.h14
-rw-r--r--sys/netinet/ip_esp_new.c1036
-rw-r--r--sys/netinet/ip_esp_old.c7
4 files changed, 731 insertions, 330 deletions
diff --git a/sys/netinet/ip_ah_new.c b/sys/netinet/ip_ah_new.c
index 3ab1c619eaf..ccc77ec0cb3 100644
--- a/sys/netinet/ip_ah_new.c
+++ b/sys/netinet/ip_ah_new.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ah_new.c,v 1.6 1997/07/27 23:30:34 niklas Exp $ */
+/* $OpenBSD: ip_ah_new.c,v 1.7 1997/08/26 12:02:48 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -367,7 +367,7 @@ ah_new_input(struct mbuf *m, struct tdb *tdb)
case 2:
case 3:
- log(LOG_WARNING, "ahhmachmd5_input(): duplicate packet received, %x->%x spi %08x", ip->ip_src, ip->ip_dst, ntohl(ah->ah_spi));
+ log(LOG_WARNING, "ah_new_input(): duplicate packet received, %x->%x spi %08x", ip->ip_src, ip->ip_dst, ntohl(ah->ah_spi));
ahstat.ahs_replay++;
break;
}
diff --git a/sys/netinet/ip_esp.h b/sys/netinet/ip_esp.h
index ceb335693b1..2ea85d2e3e4 100644
--- a/sys/netinet/ip_esp.h
+++ b/sys/netinet/ip_esp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_esp.h,v 1.9 1997/07/14 08:48:46 provos Exp $ */
+/* $OpenBSD: ip_esp.h,v 1.10 1997/08/26 12:02:49 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -55,6 +55,13 @@ struct esp_old
u_int8_t esp_iv[8]; /* iv[4] may actually be data! */
};
+struct esp_new
+{
+ u_int32_t esp_spi; /* Security Parameter Index */
+ u_int32_t esp_rpl; /* Sequence Number, Replay Counter */
+ u_int8_t esp_iv[8]; /* Data may start already at iv[0]! */
+};
+
struct espstat
{
u_int32_t esps_hdrops; /* packet shorter than header shows */
@@ -109,7 +116,7 @@ struct esp_new_xencap
{
u_int32_t edx_enc_algorithm;
u_int32_t edx_hash_algorithm;
- int32_t edx_ivlen; /* 0 or 8 */
+ u_int32_t edx_ivlen; /* 0 or 8 */
u_int32_t edx_keylen;
u_int32_t edx_wnd;
u_int32_t edx_flags;
@@ -123,7 +130,7 @@ struct esp_new_xdata
{
u_int32_t edx_enc_algorithm;
u_int32_t edx_hash_algorithm;
- int32_t edx_ivlen; /* 0 or 8 */
+ u_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;
@@ -161,6 +168,7 @@ struct esp_new_xdata
#define edx_sha1_octx Hashes.SHA1stuff.edx_octx
#define ESP_OLD_FLENGTH 12
+#define ESP_NEW_FLENGTH 16
#ifdef _KERNEL
struct espstat espstat;
diff --git a/sys/netinet/ip_esp_new.c b/sys/netinet/ip_esp_new.c
index 5c09292ae0b..7a913d6276a 100644
--- a/sys/netinet/ip_esp_new.c
+++ b/sys/netinet/ip_esp_new.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_esp_new.c,v 1.1 1997/07/11 23:37:57 provos Exp $ */
+/* $OpenBSD: ip_esp_new.c,v 1.2 1997/08/26 12:02:49 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -24,7 +24,8 @@
*/
/*
- * Based on draft-ietf-ipsec-esp-des-md5-03.txt.
+ * Based on draft-ietf-ipsec-esp-v2-00.txt and
+ * draft-ietf-ipsec-ciph-{des,3des}-{derived,expiv}-00.txt
*/
#include <sys/param.h>
@@ -57,18 +58,25 @@
#include <netinet/ip_icmp.h>
#include <netinet/ip_ipsp.h>
#include <netinet/ip_esp.h>
+#include <netinet/ip_ah.h>
#include <sys/syslog.h>
+extern void encap_sendnotify(int, struct tdb *);
extern void des_ecb3_encrypt(caddr_t, caddr_t, caddr_t, caddr_t, caddr_t, int);
extern void des_ecb_encrypt(caddr_t, caddr_t, caddr_t, int);
extern void des_set_key(caddr_t, caddr_t);
+/*
+ * esp_new_attach() is called from the transformation initialization code.
+ * It just returns.
+ */
+
int
esp_new_attach()
{
#ifdef ENCDEBUG
if (encdebug)
- printf("ah_new_attach(): setting up\n");
+ printf("esp_new_attach(): setting up\n");
#endif /* ENCDEBUG */
return 0;
}
@@ -82,11 +90,12 @@ esp_new_attach()
int
esp_new_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
{
-#if 0
struct esp_new_xdata *xd;
struct esp_new_xencap txd;
struct encap_msghdr *em;
caddr_t buffer = NULL;
+ int blocklen, i, enc_keylen, auth_keylen;
+ u_int32_t rk[6];
if (m->m_len < ENCAP_MSG_FIXED_LEN)
{
@@ -101,7 +110,7 @@ esp_new_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
}
em = mtod(m, struct encap_msghdr *);
- if (em->em_msglen - EMT_SETSPI <= ESP_NEW_XENCAP_LEN)
+ if (em->em_msglen - EMT_SETSPI_FLEN <= ESP_NEW_XENCAP_LEN)
{
log(LOG_WARNING, "esp_new_init(): initialization failed");
return EINVAL;
@@ -110,7 +119,7 @@ esp_new_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
/* Just copy the standard fields */
m_copydata(m, EMT_SETSPI_FLEN, ESP_NEW_XENCAP_LEN, (caddr_t) &txd);
- /* Check wether the encryption algorithm is supported */
+ /* Check whether the encryption algorithm is supported */
switch (txd.edx_enc_algorithm)
{
case ALG_ENC_DES:
@@ -127,7 +136,7 @@ esp_new_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
return EINVAL;
}
- /* Check whether the encryption algorithm is supported */
+ /* Check whether the authentication algorithm is supported */
if (txd.edx_flags & ESP_NEW_FLAG_AUTH)
switch (txd.edx_hash_algorithm)
{
@@ -135,12 +144,13 @@ esp_new_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
case ALG_AUTH_SHA1:
#ifdef ENCDEBUG
if (encdebug)
- printf("esp_new_init(): initialized TDB with hash algorithm %d\n", txd.edx_enc_algorithm);
+ printf("esp_new_init(): initialized TDB with hash algorithm %d\n", txd.edx_hash_algorithm);
#endif /* ENCDEBUG */
+ blocklen = HMAC_BLOCK_LEN;
break;
default:
- log(LOG_WARNING, "esp_old_init(): unsupported encryption algorithm %d specified", txd.edx_enc_algorithm);
+ log(LOG_WARNING, "esp_new_init(): unsupported authentication algorithm %d specified", txd.edx_enc_algorithm);
return EINVAL;
}
@@ -152,7 +162,46 @@ esp_new_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
return EINVAL;
}
- /* XXX Check the IV lengths */
+ switch (txd.edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ if ((txd.edx_ivlen != 0) && (txd.edx_ivlen != 8))
+ {
+ log(LOG_WARNING, "esp_new_init(): unsupported IV length %d",
+ txd.edx_ivlen);
+ return EINVAL;
+ }
+
+ if (txd.edx_keylen < 8)
+ {
+ log(LOG_WARNING, "esp_new_init(): bad key length",
+ txd.edx_keylen);
+ return EINVAL;
+ }
+
+ enc_keylen = 8;
+
+ break;
+
+ case ALG_ENC_3DES:
+ if ((txd.edx_ivlen != 0) && (txd.edx_ivlen != 8))
+ {
+ log(LOG_WARNING, "esp_new_init(): unsupported IV length %d",
+ txd.edx_ivlen);
+ return EINVAL;
+ }
+
+ if (txd.edx_keylen < 24)
+ {
+ log(LOG_WARNING, "esp_new_init(): bad key length",
+ txd.edx_keylen);
+ return EINVAL;
+ }
+
+ enc_keylen = 24;
+
+ break;
+ }
MALLOC(tdbp->tdb_xdata, caddr_t, sizeof(struct esp_new_xdata),
M_XDATA, M_WAITOK);
@@ -165,103 +214,135 @@ esp_new_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
return ENOBUFS;
}
- /* Or larger ? XXX */
- MALLOC(buffer, caddr_t, txd.edx_keylen, M_TEMP, M_WAITOK);
- if (buffer == NULL)
- {
-#ifdef ENCDEBUG
- if (encdebug)
- printf("esp_new_init(): MALLOC() failed\n");
-#endif /* ENCDEBUG */
- free(tdbp->tdb_xdata, M_XDATA);
- return ENOBUFS;
- }
-
- bzero(buffer, txd.edx_keylen);
bzero(tdbp->tdb_xdata, sizeof(struct esp_new_xdata));
xd = (struct esp_new_xdata *) tdbp->tdb_xdata;
/* Pointer to the transform */
tdbp->tdb_xform = xsp;
-#if 0
xd->edx_ivlen = txd.edx_ivlen;
+ xd->edx_enc_algorithm = txd.edx_enc_algorithm;
xd->edx_wnd = txd.edx_wnd;
+ xd->edx_flags = txd.edx_flags;
+ xd->edx_hash_algorithm = txd.edx_hash_algorithm;
- /* Fix the IV */
- 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;
+ /* Copy the IV */
+ m_copydata(m, EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN, xd->edx_ivlen,
+ (caddr_t) xd->edx_iv);
- MD5Init(&ctx);
- MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
- MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
- MD5Final(buf, &ctx);
- bcopy(buf, xd->edx_iv, ESPDESMD5_IVS);
+ switch (xd->edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ /* Copy the key material */
+ m_copydata(m, EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN + xd->edx_ivlen,
+ enc_keylen, (caddr_t) rk);
+
+ des_set_key((caddr_t) rk, (caddr_t) (xd->edx_eks[0]));
+ break;
+
+ case ALG_ENC_3DES:
+ /* Copy the key material */
+ m_copydata(m, EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN + xd->edx_ivlen,
+ enc_keylen, (caddr_t) rk);
+
+ des_set_key((caddr_t) rk, (caddr_t) (xd->edx_eks[0]));
+ des_set_key((caddr_t) rk + 2, (caddr_t) (xd->edx_eks[1]));
+ des_set_key((caddr_t) rk + 4, (caddr_t) (xd->edx_eks[2]));
+ break;
}
- /* DES key */
+ /* Replay counters are mandatory, even without auth */
+ xd->edx_rpl = AH_HMAC_INITIAL_RPL;
+ xd->edx_wnd = txd.edx_wnd;
+ xd->edx_bitmap = 0;
- MD5Init(&ctx);
- for (len = 0; len < ESPDESMD5_KEYSZ; len++)
- buf[len] = txd.edx_initiator ? ESPDESMD5_DPADI : ESPDESMD5_DPADR;
+ if (txd.edx_flags & ESP_NEW_FLAG_AUTH)
+ {
+ auth_keylen = txd.edx_keylen - xd->edx_ivlen - enc_keylen;
+
+ /* Or larger ? XXX */
+ MALLOC(buffer, caddr_t,
+ auth_keylen < blocklen ? blocklen : auth_keylen,
+ M_TEMP, M_WAITOK);
+ if (buffer == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_init(): MALLOC() failed\n");
+#endif /* ENCDEBUG */
+ free(tdbp->tdb_xdata, M_XDATA);
+ return ENOBUFS;
+ }
+
+ bzero(buffer, auth_keylen < blocklen ? blocklen : auth_keylen);
+
+ /* Copy the key to the buffer */
+ m_copydata(m, EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN + xd->edx_ivlen +
+ enc_keylen, auth_keylen, buffer);
+
+ /* Shorten the key if necessary */
+ if (auth_keylen > blocklen)
+ {
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Init(&(xd->edx_md5_ictx));
+ MD5Update(&(xd->edx_md5_ictx), buffer, auth_keylen);
+ bzero(buffer,
+ auth_keylen < blocklen ? blocklen : auth_keylen);
+ MD5Final(buffer, &(xd->edx_md5_ictx));
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Init(&(xd->edx_sha1_ictx));
+ SHA1Update(&(xd->edx_sha1_ictx), buffer, auth_keylen);
+ bzero(buffer,
+ auth_keylen < blocklen ? blocklen : auth_keylen);
+ SHA1Final(buffer, &(xd->edx_sha1_ictx));
+ break;
+ }
+ }
+
+ /* Precompute the I and O pads of the HMAC */
+ for (i = 0; i < blocklen; i++)
+ buffer[i] ^= HMAC_IPAD_VAL;
+
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Init(&(xd->edx_md5_ictx));
+ MD5Update(&(xd->edx_md5_ictx), buffer, blocklen);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Init(&(xd->edx_sha1_ictx));
+ SHA1Update(&(xd->edx_sha1_ictx), buffer, blocklen);
+ break;
+ }
- 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 */
-
- MD5Init(&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;
-
- MD5Init(&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);
-
- MD5Init(&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;
-
- MD5Init(&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;
-
- bzero(&ctx, sizeof(MD5_CTX));
+ for (i = 0; i < blocklen; i++)
+ buffer[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
+
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Init(&(xd->edx_md5_octx));
+ MD5Update(&(xd->edx_md5_octx), buffer, blocklen);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Init(&(xd->edx_sha1_octx));
+ SHA1Update(&(xd->edx_sha1_octx), buffer, blocklen);
+ break;
+ }
+
+ bzero(buffer, blocklen);
+ free(buffer, M_TEMP);
+ }
- bzero(buffer, txd.edx_keylen); /* fix XXX */
- free(buffer, M_TEMP);
-#endif
-
+ bzero(rk, 6 * sizeof(u_int32_t)); /* paranoid */
bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
-#endif
+
return 0;
}
@@ -280,22 +361,60 @@ esp_new_zeroize(struct tdb *tdbp)
struct mbuf *
esp_new_input(struct mbuf *m, struct tdb *tdb)
{
-#if 0
struct esp_new_xdata *xd;
struct ip *ip, ipo;
- u_char iv[8], niv[8], blk[8], auth[ESPDESMD5_ALEN];
- u_char iauth[ESPDESMD5_ALEN];
+ u_char iv[ESP_3DES_IVS], niv[ESP_3DES_IVS], blk[ESP_3DES_BLKS], opts[40];
u_char *idat, *odat;
- struct esp *esp;
+ struct esp_new *esp;
struct ifnet *rcvif;
- int plen, ilen, olen, i, authp, oplen, errc;
- u_int32_t rplc, tbitmap, trpl;
- u_char padsize, nextproto;
+ int ohlen, oplen, plen, alen, ilen, olen, i, blks;
+ int count, off, errc;
+ u_int32_t btsx;
struct mbuf *mi, *mo;
- MD5_CTX ctx;
+ MD5_CTX md5ctx;
+ SHA1_CTX sha1ctx;
+ u_char buf[AH_ALEN_MAX], buf2[AH_ALEN_MAX];
xd = (struct esp_new_xdata *)tdb->tdb_xdata;
+ switch (xd->edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ blks = ESP_DES_BLKS;
+ break;
+
+ case ALG_ENC_3DES:
+ blks = ESP_3DES_BLKS;
+ break;
+
+ default:
+ log(LOG_ALERT,
+ "esp_new_input(): unsupported algorithm %d in SA %x/%08x",
+ xd->edx_enc_algorithm, tdb->tdb_dst, ntohl(tdb->tdb_spi));
+ m_freem(m);
+ return NULL;
+ }
+
+ if (xd->edx_flags & ESP_NEW_FLAG_AUTH)
+ {
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ case ALG_AUTH_SHA1:
+ alen = AH_HMAC_HASHLEN;
+ break;
+
+ default:
+ log(LOG_ALERT,
+ "esp_new_input(): unsupported algorithm %d in SA %x/%08x",
+ xd->edx_hash_algorithm, tdb->tdb_dst, ntohl(tdb->tdb_spi));
+ m_freem(m);
+ return NULL;
+ }
+ } else
+ alen = 0;
+
+
rcvif = m->m_pkthdr.rcvif;
if (rcvif == NULL)
{
@@ -306,47 +425,198 @@ esp_new_input(struct mbuf *m, struct tdb *tdb)
rcvif = &enc_softc;
}
+ if (m->m_len < sizeof(struct ip))
+ {
+ if ((m = m_pullup(m, sizeof(struct ip))) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_input(): (possibly too short) packet dropped\n");
+#endif /* ENCDEBUG */
+ espstat.esps_hdrops++;
+ return NULL;
+ }
+ }
+
ip = mtod(m, struct ip *);
+ ohlen = (ip->ip_hl << 2) + ESP_NEW_FLENGTH;
+
+ /* Make sure the IP header, any IP options, and the ESP header are here */
+ if (m->m_len < ohlen + blks)
+ {
+ if ((m = m_pullup(m, ohlen + blks)) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_input(): m_pullup() failed\n");
+#endif /* ENCDEBUG */
+ espstat.esps_hdrops++;
+ return NULL;
+ }
+
+ ip = mtod(m, struct ip *);
+ }
+
+ esp = (struct esp_new *) ((u_int8_t *) ip + (ip->ip_hl << 2));
+
ipo = *ip;
- esp = (struct esp *)(ip + 1);
- plen = m->m_pkthdr.len - sizeof (struct ip) - sizeof (u_int32_t) -
- xd->edx_ivlen;
- if (plen & 07)
+ /* Replay window checking */
+ if (xd->edx_wnd >= 0)
+ {
+ btsx = ntohl(esp->esp_rpl);
+ if ((errc = checkreplaywindow32(btsx, 0, &(xd->edx_rpl), xd->edx_wnd,
+ &(xd->edx_bitmap))) != 0)
+ {
+ switch(errc)
+ {
+ case 1:
+ log(LOG_ERR, "esp_new_input(): replay counter wrapped for packets from %x to %x, spi %08x\n", ip->ip_src, ip->ip_dst, ntohl(esp->esp_spi));
+ espstat.esps_wrap++;
+ break;
+
+ case 2:
+ case 3:
+ log(LOG_WARNING, "esp_new_input(): duplicate packet received, %x->%x spi %08x", ip->ip_src, ip->ip_dst, ntohl(esp->esp_spi));
+ espstat.esps_replay++;
+ break;
+ }
+
+ m_freem(m);
+ return NULL;
+ }
+ }
+
+ /* Skip the IP header, IP options, SPI, SN and IV and minus Auth Data*/
+ plen = m->m_pkthdr.len - (ip->ip_hl << 2) - 2*sizeof (u_int32_t) -
+ xd->edx_ivlen - alen;
+ if (plen & (blks -1))
{
#ifdef ENCDEBUG
if (encdebug)
- printf("esp_new_input(): payload not a multiple of 8 octets\n");
+ printf("esp_new_input(): payload not a multiple of %d octets for packet from %x to %x, spi %08x\n", blks, ipo.ip_src, ipo.ip_dst, ntohl(tdb->tdb_spi));
#endif /* ENCDEBUG */
espstat.esps_badilen++;
m_freem(m);
return NULL;
}
+ if (xd->edx_flags & ESP_NEW_FLAG_AUTH)
+ {
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ md5ctx = xd->edx_md5_ictx;;
+ break;
+
+ case ALG_AUTH_SHA1:
+ sha1ctx = xd->edx_sha1_ictx;
+ break;
+ }
+
+ /* Auth covers SPI + SN + IV*/
+ oplen = plen + 2*sizeof(u_int32_t) + xd->edx_ivlen;
+ off = (ip->ip_hl << 2);
+
+ mo = m;
+ while (oplen > 0)
+ {
+ if (mo == 0)
+ panic("esp_new_input(): m_copydata (copy)");
+
+ count = min(mo->m_len - off, oplen);
+
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, mtod(mo, unsigned char *) + off, count);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, mtod(mo, unsigned char *) + off, count);
+ break;
+ }
+
+ oplen -= count;
+ if (oplen == 0)
+ {
+ /* Get the authentication data */
+ if (mo->m_len - off - count >= alen)
+ bcopy(mtod(mo, unsigned char *) + off + count, buf, alen);
+ else
+ {
+ int olen = alen, tmp = 0;
+
+ mi = mo;
+ off += count;
+
+ while (mi != NULL && olen > 0) {
+ count = min(mi->m_len - off, olen);
+ bcopy(mtod(mi, unsigned char *) + off, buf + tmp, count);
+
+ off = 0;
+ tmp += count;
+ olen -= count;
+ mi = mi->m_next;
+ }
+ }
+ }
+
+ off = 0;
+ mo = mo->m_next;
+ }
+
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Final(buf2, &md5ctx);
+ md5ctx = xd->edx_md5_octx;
+ MD5Update(&md5ctx, buf2, AH_MD5_ALEN);
+ MD5Final(buf2, &md5ctx);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Final(buf2, &sha1ctx);
+ sha1ctx = xd->edx_sha1_octx;
+ SHA1Update(&sha1ctx, buf2, AH_SHA1_ALEN);
+ SHA1Final(buf2, &sha1ctx);
+ break;
+ }
+
+
+ if (bcmp(buf2, buf, AH_HMAC_HASHLEN))
+ {
+ log(LOG_ALERT,
+ "esp_new_input(): authentication failed for packet from %x to %x, spi %08x", ip->ip_src, ip->ip_dst, ntohl(esp->esp_spi));
+ espstat.esps_badauth++;
+ m_freem(m);
+ return NULL;
+ }
+ }
+
oplen = plen;
- ilen = m->m_len - sizeof (struct ip) - ESPDESMD5_IVS - sizeof(u_int32_t);
- idat = mtod(m, unsigned char *) + sizeof (struct ip) + sizeof(u_int32_t) +
- ESPDESMD5_IVS;
+ ilen = m->m_len - (ip->ip_hl << 2) - 2*sizeof(u_int32_t);
+ idat = mtod(m, unsigned char *) + (ip->ip_hl << 2) + 2*sizeof(u_int32_t);
- if (xd->edx_ivlen == 0) /* KeyIV in use */
+ if (xd->edx_ivlen == 0) /* Derived IV in use */
{
- bcopy(xd->edx_iv, iv, ESPDESMD5_IVS);
- ilen += ESPDESMD5_IVS;
- idat -= ESPDESMD5_IVS;
+ bcopy((u_char *)&esp->esp_rpl, iv, sizeof(esp->esp_rpl));
+ iv[4] = ~iv[0];
+ iv[5] = ~iv[1];
+ iv[6] = ~iv[2];
+ iv[7] = ~iv[3];
}
else
- bcopy(idat - ESPDESMD5_IVS, iv, ESPDESMD5_IVS);
+ {
+ bcopy(idat, iv, xd->edx_ivlen);
+ ilen -= xd->edx_ivlen;
+ idat += xd->edx_ivlen;
+ }
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);
/*
* At this point:
@@ -373,6 +643,7 @@ esp_new_input(struct mbuf *m, struct tdb *tdb)
mi = mi->m_next;
if (mi == NULL)
panic("esp_new_input(): bad chain (i)\n");
+
ilen = mi->m_len;
idat = (u_char *)mi->m_data;
}
@@ -381,9 +652,21 @@ esp_new_input(struct mbuf *m, struct tdb *tdb)
i++;
ilen--;
- if (i == 8)
+ if (i == blks)
{
- des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks), 0);
+ switch (xd->edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ des_ecb_encrypt(blk, blk, (caddr_t) (xd->edx_eks[0]), 0);
+ break;
+
+ case ALG_ENC_3DES:
+ des_ecb3_encrypt(blk, blk, (caddr_t) (xd->edx_eks[2]),
+ (caddr_t) (xd->edx_eks[1]),
+ (caddr_t) (xd->edx_eks[0]), 0);
+ break;
+ }
+
for (i=0; i<8; i++)
{
while (olen == 0)
@@ -391,122 +674,104 @@ esp_new_input(struct mbuf *m, struct tdb *tdb)
mo = mo->m_next;
if (mo == NULL)
panic("esp_new_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;
- }
- else
- {
- if (plen == ESPDESMD5_ALEN + 1)
- {
- nextproto = blk[7];
- padsize = blk[6];
- }
- else
- if (plen + 7 == oplen)
- {
- 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("esp_new_input: replay counter wrapped\n");
-#endif
- espstat.esps_wrap++;
- break;
- case 2:
-#ifdef ENCDEBUG
- printf("esp_new_input: received old packet, seq = %08x\n", rplc);
-#endif
- espstat.esps_replay++;
- break;
- case 3:
-#ifdef ENCDEBUG
- printf("esp_new_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);
+ /* Save the options */
+ m_copydata(m, sizeof(struct ip), (ipo.ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) opts);
- if (bcmp(auth, iauth, ESPDESMD5_ALEN))
- {
-#ifdef ENCDEBUG
- if (encdebug)
- printf("esp_new_input: bad auth\n");
-#endif
- xd->edx_rpl = trpl;
- xd->edx_bitmap = tbitmap; /* Restore */
- espstat.esps_badauth++;
- m_freem(m);
- return NULL;
- }
+ /*
+ * 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, - padsize - 2 - 234893289);
- m_adj(m, 4 + xd->edx_ivlen + ESPDESMD5_RPLENGTH);
+ m_adj(m, - blk[6] - 2 - alen);
+ m_adj(m, 2*sizeof(u_int32_t) + xd->edx_ivlen);
- if (m->m_len < sizeof (struct ip))
+ if (m->m_len < (ipo.ip_hl << 2))
{
- m = m_pullup(m, sizeof (struct ip));
+ m = m_pullup(m, (ipo.ip_hl << 2));
if (m == NULL)
{
- xd->edx_rpl = trpl;
- xd->edx_bitmap = tbitmap;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_input(): m_pullup() failed for packet from %x to %x, SA %x/%08x\n", ipo.ip_src, ipo.ip_dst, tdb->tdb_dst, ntohl(tdb->tdb_spi));
+#endif /* ENCDEBUG */
return NULL;
}
}
ip = mtod(m, struct ip *);
- ipo.ip_p = nextproto;
+ ipo.ip_p = blk[7];
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;
+ ipo.ip_len += (ipo.ip_hl << 2) - 2*sizeof(u_int32_t) - xd->edx_ivlen -
+ blk[6] - 2 - alen;
ipo.ip_len = htons(ipo.ip_len);
ipo.ip_sum = 0;
*ip = ipo;
- ip->ip_sum = in_cksum(m, sizeof (struct ip));
+
+ /* Copy the options back */
+ m_copyback(m, sizeof(struct ip), (ipo.ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) opts);
+
+ ip->ip_sum = in_cksum(m, (ip->ip_hl << 2));
/* Update the counters */
tdb->tdb_cur_packets++;
- tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) + padsize +
- 2 + ESPDESMD5_ALEN;
+ tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) +
+ blk[6] + 2 + alen;
+ espstat.esps_ibytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) +
+ blk[6] + 2 + alen;
+
+ /* Notify on expiration */
+ if (tdb->tdb_flags & TDBF_SOFT_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_soft_packets)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_PACKETS;
+ }
+ else
+ if (tdb->tdb_flags & TDBF_SOFT_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_BYTES;
+ }
+
+ if (tdb->tdb_flags & TDBF_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_exp_packets)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+ else
+ if (tdb->tdb_flags & TDBF_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
-#endif
return m;
}
@@ -514,153 +779,174 @@ int
esp_new_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
struct mbuf **mp)
{
-#if 0
struct esp_new_xdata *xd;
struct ip *ip, ipo;
int i, ilen, olen, ohlen, nh, rlen, plen, padding;
- u_int32_t rplc;
- u_int32_t spi;
- struct mbuf *mi, *mo, *ms;
+ struct esp_new espo;
+ struct mbuf *mi, *mo;
u_char *pad, *idat, *odat;
- u_char iv[ESPDESMD5_IVS], blk[8], auth[ESPDESMD5_ALEN], opts[40];
- MD5_CTX ctx;
- int iphlen;
+ u_char iv[ESP_3DES_IVS], blk[ESP_3DES_IVS], auth[AH_ALEN_MAX], opts[40];
+ MD5_CTX md5ctx;
+ SHA1_CTX sha1ctx;
+ int iphlen, blks, alen;
+ xd = (struct esp_new_xdata *) tdb->tdb_xdata;
+
+ switch (xd->edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ blks = ESP_DES_BLKS;
+ break;
+
+ case ALG_ENC_3DES:
+ blks = ESP_3DES_BLKS;
+ break;
+
+ default:
+ log(LOG_ALERT,
+ "esp_new_output(): unsupported algorithm %d in SA %x/%08x",
+ xd->edx_enc_algorithm, tdb->tdb_dst, ntohl(tdb->tdb_spi));
+ m_freem(m);
+ return NULL;
+ }
+
+ if (xd->edx_flags & ESP_NEW_FLAG_AUTH)
+ {
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ case ALG_AUTH_SHA1:
+ alen = AH_HMAC_HASHLEN;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_output(): using hash algorithm %d\n",
+ xd->edx_hash_algorithm);
+#endif /* ENCDEBUG */
+ break;
+
+ default:
+ log(LOG_ALERT,
+ "esp_new_output(): unsupported algorithm %d in SA %x/%08x",
+ xd->edx_hash_algorithm, tdb->tdb_dst, ntohl(tdb->tdb_spi));
+ m_freem(m);
+ return NULL;
+ }
+ } else
+ alen = 0;
+
espstat.esps_output++;
+
m = m_pullup(m, sizeof (struct ip)); /* Get IP header in one mbuf */
if (m == NULL)
- return ENOBUFS;
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_output(): m_pullup() failed, SA %x/%08x\n",
+ tdb->tdb_dst, ntohl(tdb->tdb_spi));
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ if (xd->edx_rpl == 0)
+ {
+ log(LOG_ALERT, "esp_new_output(): SA %x/%0x8 should have expired",
+ tdb->tdb_dst, ntohl(tdb->tdb_spi));
+ m_freem(m);
+ espstat.esps_wrap++;
+ return NULL;
+ }
+
+ espo.esp_spi = tdb->tdb_spi;
+ espo.esp_rpl = htonl(xd->edx_rpl++);
ip = mtod(m, struct ip *);
- spi = tdb->tdb_spi;
- iphlen = ip->ip_hl << 2;
+ iphlen = (ip->ip_hl << 2);
/*
- * If options are present, pullup the IP header, the options
- * and one DES block (8 bytes) of data.
+ * If options are present, pullup the IP header, the options.
*/
if (iphlen != sizeof(struct ip))
{
m = m_pullup(m, iphlen + 8);
if (m == NULL)
- return ENOBUFS;
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_input(): m_pullup() failed for SA %x/%08x\n",
+ tdb->tdb_dst, ntohl(tdb->tdb_spi));
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
ip = mtod(m, struct ip *);
/* Keep the options */
- bcopy(mtod(m, u_char *) + sizeof(struct ip), opts,
- iphlen - sizeof(struct ip));
+ m_copydata(m, sizeof(struct ip), iphlen - sizeof(struct ip),
+ (caddr_t) opts);
}
- xd = (struct esp_new_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 */
+ ohlen = 2*sizeof (u_int32_t) + xd->edx_ivlen;
- if (xd->edx_rpl == xd->edx_initial)
- {
-#ifdef ENCDEBUG
- if (encdebug)
- printf("esp_new_output: replay counter wrapped\n");
-#endif
- espstat.esps_wrap++;
- return EHOSTDOWN; /* XXX */
- }
-
ipo = *ip;
nh = ipo.ip_p;
/* Raw payload length */
- rlen = ESPDESMD5_RPLENGTH + ilen - iphlen;
+ rlen = ilen - iphlen;
+ padding = ((blks - ((rlen + 2) % blks)) % blks) + 2;
- padding = ((8 - ((rlen + 2) % 8)) % 8) + 2;
-
- pad = (u_char *)m_pad(m, padding);
+ pad = (u_char *) m_pad(m, padding + alen);
if (pad == NULL)
- return ENOBUFS;
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_output(): m_pad() failed for SA %x/%08x\n",
+ tdb->tdb_dst, ntohl(tdb->tdb_spi));
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
pad[padding-2] = padding - 2;
pad[padding-1] = nh;
- 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_int32_t));
- MD5Update(&ctx, iv, ESPDESMD5_IVS);
- rplc = htonl(xd->edx_rpl);
- MD5Update(&ctx, (unsigned char *)&rplc, ESPDESMD5_RPLENGTH);
- xd->edx_rpl++;
-
- mi = m;
+ mi = mo = m;
+ plen = rlen + padding;
+ ilen = olen = m->m_len - iphlen;
+ idat = odat = mtod(m, u_char *) + iphlen;
+ i = 0;
- /* MD5 the data */
- while (mi != NULL)
+ if (xd->edx_ivlen == 0)
{
- if (mi == m)
- MD5Update(&ctx, (u_char *)mi->m_data + iphlen,
- mi->m_len - iphlen);
- else
- MD5Update(&ctx, (u_char *)mi->m_data, mi->m_len);
- mi = mi->m_next;
+ bcopy((u_char *)&espo.esp_rpl, iv, 4);
+ iv[4] = ~iv[0];
+ iv[5] = ~iv[1];
+ iv[6] = ~iv[2];
+ iv[7] = ~iv[3];
+ } else
+ {
+ bcopy(xd->edx_iv, iv, xd->edx_ivlen);
+ bcopy(xd->edx_iv, espo.esp_iv, xd->edx_ivlen);
}
- 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, iphlen + ESPDESMD5_RPLENGTH +
- sizeof(u_int32_t) + xd->edx_ivlen);
- if (m == NULL)
- return ENOBUFS;
-
- /* Copy data if necessary */
- if (m->m_len - iphlen)
+ /* Authenticate the esp header */
+ if (xd->edx_flags & ESP_NEW_FLAG_AUTH)
{
- ms = m_copym(m, iphlen, m->m_len - iphlen, M_DONTWAIT);
- if (ms == NULL)
- return ENOBUFS;
-
- ms->m_next = m->m_next;
- m->m_next = ms;
- m->m_len = iphlen;
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ md5ctx = xd->edx_md5_ictx;
+ MD5Update(&md5ctx, (unsigned char *)&espo,
+ 2*sizeof(u_int32_t) + xd->edx_ivlen);
+ break;
+ case ALG_AUTH_SHA1:
+ sha1ctx = xd->edx_sha1_ictx;
+ SHA1Update(&sha1ctx, (unsigned char *)&espo,
+ 2*sizeof(u_int32_t) + xd->edx_ivlen);
+ break;
+ }
}
-
- /* Copy SPI, IV (or not) and replay counter */
- bcopy((caddr_t)&spi, mtod(m, caddr_t) + iphlen, sizeof (u_int32_t));
- bcopy((caddr_t)iv, mtod(m, caddr_t) + iphlen + sizeof (u_int32_t),
- xd->edx_ivlen);
- bcopy((caddr_t)&rplc, mtod(m, caddr_t) + iphlen + sizeof(u_int32_t) +
- xd->edx_ivlen, ESPDESMD5_RPLENGTH);
-
- /* 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;
-
- /* 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 */
-
- ilen = olen = m->m_len - iphlen - sizeof(u_int32_t) - xd->edx_ivlen;
- idat = odat = mtod(m, u_char *) + iphlen + sizeof(u_int32_t)
- + xd->edx_ivlen;
- i = 0;
- mi = mo = m;
+
+ /* Encrypt the payload */
while (plen > 0) /* while not done */
{
@@ -669,6 +955,7 @@ esp_new_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
mi = mi->m_next;
if (mi == NULL)
panic("esp_new_output(): bad chain (i)\n");
+
ilen = mi->m_len;
idat = (u_char *)mi->m_data;
}
@@ -678,19 +965,44 @@ esp_new_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
i++;
ilen--;
- if (i == 8) /* We have full block */
+ if (i == blks)
{
- des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks), 1);
- for (i = 0; i < 8; i++)
+ switch (xd->edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ des_ecb_encrypt(blk, blk, (caddr_t) (xd->edx_eks[0]), 1);
+ break;
+
+ case ALG_ENC_3DES:
+ des_ecb3_encrypt(blk, blk, (caddr_t) (xd->edx_eks[0]),
+ (caddr_t) (xd->edx_eks[1]),
+ (caddr_t) (xd->edx_eks[2]), 1);
+ break;
+ }
+
+ if (xd->edx_flags & ESP_NEW_FLAG_AUTH)
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, blk, blks);
+ break;
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, blk, blks);
+ break;
+ }
+
+ for (i = 0; i < blks; i++)
{
while (olen == 0)
{
mo = mo->m_next;
if (mo == NULL)
panic("esp_new_output(): bad chain (o)\n");
+
olen = mo->m_len;
odat = (u_char *)mo->m_data;
}
+
*odat++ = blk[i];
iv[i] = blk[i];
olen--;
@@ -701,26 +1013,108 @@ esp_new_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
plen--;
}
- if (xd->edx_ivlen != 0)
- bcopy(iv, xd->edx_iv, ESPDESMD5_IVS); /* New IV */
+ /* Put in authentication data */
+ if (xd->edx_flags & ESP_NEW_FLAG_AUTH)
+ {
+ switch (xd->edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Final(auth, &md5ctx);
+ md5ctx = xd->edx_md5_octx;
+ MD5Update(&md5ctx, auth, AH_MD5_ALEN);
+ MD5Final(auth, &md5ctx);
+ break;
+ case ALG_AUTH_SHA1:
+ SHA1Final(auth, &sha1ctx);
+ sha1ctx = xd->edx_sha1_octx;
+ SHA1Update(&sha1ctx, auth, AH_SHA1_ALEN);
+ SHA1Final(auth, &sha1ctx);
+ break;
+ }
+ /* Copy the final authenticator */
+ bcopy(auth, pad+padding, alen);
+ }
+
+ /*
+ * Done with encryption. Let's wedge in the ESP header
+ * and send it out.
+ */
+
+ M_PREPEND(m, ohlen, M_DONTWAIT);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_output(): M_PREPEND failed, SA %x/%08x\n",
+ tdb->tdb_dst, ntohl(tdb->tdb_spi));
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ m = m_pullup(m, iphlen + ohlen);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_output(): m_pullup() failed, SA %x/%08x\n",
+ tdb->tdb_dst, ntohl(tdb->tdb_spi));
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
/* Fix the length and the next protocol, copy back and off we go */
- ipo.ip_len = htons(iphlen + ohlen + rlen + padding +
- ESPDESMD5_ALEN);
+ ipo.ip_len = htons(iphlen + ohlen + rlen + padding + alen);
ipo.ip_p = IPPROTO_ESP;
- bcopy((caddr_t)&ipo, mtod(m, caddr_t), sizeof(struct ip));
-
- /* Copy back the options, if existing */
+
+ /* Save the last encrypted block, to be used as the next IV */
+ bcopy(blk, xd->edx_iv, xd->edx_ivlen);
+
+ m_copyback(m, 0, sizeof(struct ip), (caddr_t) &ipo);
+
+ /* Copy options, if existing */
if (iphlen != sizeof(struct ip))
- bcopy(opts, mtod(m, caddr_t) + sizeof(struct ip),
- iphlen - sizeof(struct ip));
-
+ m_copyback(m, sizeof(struct ip), iphlen - sizeof(struct ip),
+ (caddr_t) opts);
+
+ /* Copy in the esp header */
+ m_copyback(m, iphlen, ohlen, (caddr_t) &espo);
+
+ *mp = m;
+
/* Update the counters */
tdb->tdb_cur_packets++;
tdb->tdb_cur_bytes += rlen + padding;
+ espstat.esps_obytes += rlen + padding;
+
+ /* Notify on expiration */
+ if (tdb->tdb_flags & TDBF_SOFT_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_soft_packets)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_PACKETS;
+ }
+ else
+ if (tdb->tdb_flags & TDBF_SOFT_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_BYTES;
+ }
+
+ if (tdb->tdb_flags & TDBF_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_exp_packets)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+ else
+ if (tdb->tdb_flags & TDBF_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
- *mp = m;
-#endif
return 0;
}
diff --git a/sys/netinet/ip_esp_old.c b/sys/netinet/ip_esp_old.c
index e8bb76bfc0f..5e403ded801 100644
--- a/sys/netinet/ip_esp_old.c
+++ b/sys/netinet/ip_esp_old.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_esp_old.c,v 1.4 1997/07/27 23:30:36 niklas Exp $ */
+/* $OpenBSD: ip_esp_old.c,v 1.5 1997/08/26 12:02:50 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -310,10 +310,9 @@ esp_old_input(struct mbuf *m, struct tdb *tdb)
}
ip = mtod(m, struct ip *);
- esp = (struct esp_old *) ((u_int8_t *) ip + (ip->ip_hl << 2));
}
- else
- esp = (struct esp_old *) (ip + 1);
+
+ esp = (struct esp_old *) ((u_int8_t *) ip + (ip->ip_hl << 2));
ipo = *ip;