summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/crypto/cryptodev.h14
-rw-r--r--sys/crypto/cryptosoft.c31
-rw-r--r--sys/net/if_pfsync.h4
-rw-r--r--sys/net/pfkeyv2.h19
-rw-r--r--sys/net/pfkeyv2_convert.c8
-rw-r--r--sys/net/pfkeyv2_parsemessage.c4
-rw-r--r--sys/netinet/ip_ah.c50
-rw-r--r--sys/netinet/ip_esp.c182
-rw-r--r--sys/netinet/ip_ipsp.h11
9 files changed, 237 insertions, 86 deletions
diff --git a/sys/crypto/cryptodev.h b/sys/crypto/cryptodev.h
index 8f345f4f5ea..b7add969bc4 100644
--- a/sys/crypto/cryptodev.h
+++ b/sys/crypto/cryptodev.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cryptodev.h,v 1.55 2010/12/16 16:56:08 jsg Exp $ */
+/* $OpenBSD: cryptodev.h,v 1.56 2012/06/29 14:48:04 mikeb Exp $ */
/*
* The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
@@ -108,7 +108,8 @@
#define CRYPTO_AES_192_GMAC 25
#define CRYPTO_AES_256_GMAC 26
#define CRYPTO_AES_GMAC 27
-#define CRYPTO_ALGORITHM_MAX 27 /* Keep updated */
+#define CRYPTO_ESN 28 /* Support for Extended Sequence Numbers */
+#define CRYPTO_ALGORITHM_MAX 28 /* Keep updated */
/* Algorithm flags */
#define CRYPTO_ALG_FLAG_SUPPORTED 0x01 /* Algorithm is supported */
@@ -121,7 +122,12 @@ struct cryptoini {
int cri_klen; /* Key length, in bits */
int cri_rnd; /* Algorithm rounds, where relevant */
caddr_t cri_key; /* key to use */
- u_int8_t cri_iv[EALG_MAX_BLOCK_LEN]; /* IV to use */
+ union {
+ u_int8_t iv[EALG_MAX_BLOCK_LEN]; /* IV to use */
+ u_int8_t esn[4]; /* high-order ESN */
+ } u;
+#define cri_iv u.iv
+#define cri_esn u.esn
struct cryptoini *cri_next;
};
@@ -138,8 +144,10 @@ struct cryptodesc {
#define CRD_F_IV_EXPLICIT 0x04 /* IV explicitly provided */
#define CRD_F_DSA_SHA_NEEDED 0x08 /* Compute SHA-1 of buffer for DSA */
#define CRD_F_COMP 0x10 /* Set when doing compression */
+#define CRD_F_ESN 0x20 /* Set when ESN field is provided */
struct cryptoini CRD_INI; /* Initialization/context data */
+#define crd_esn CRD_INI.cri_esn
#define crd_iv CRD_INI.cri_iv
#define crd_key CRD_INI.cri_key
#define crd_rnd CRD_INI.cri_rnd
diff --git a/sys/crypto/cryptosoft.c b/sys/crypto/cryptosoft.c
index 6e2406b444d..962b09e15f3 100644
--- a/sys/crypto/cryptosoft.c
+++ b/sys/crypto/cryptosoft.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cryptosoft.c,v 1.63 2011/01/11 23:00:21 markus Exp $ */
+/* $OpenBSD: cryptosoft.c,v 1.64 2012/06/29 14:48:04 mikeb Exp $ */
/*
* The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
@@ -446,6 +446,9 @@ swcr_authcompute(struct cryptop *crp, struct cryptodesc *crd,
if (err)
return err;
+ if (crd->crd_flags & CRD_F_ESN)
+ axf->Update(&ctx, crd->crd_esn, 4);
+
switch (sw->sw_alg) {
case CRYPTO_MD5_HMAC:
case CRYPTO_SHA1_HMAC:
@@ -505,7 +508,7 @@ swcr_combined(struct cryptop *crp)
struct uio *uio = NULL;
caddr_t buf = (caddr_t)crp->crp_buf;
uint32_t *blkp;
- int i, blksz, ivlen, outtype, len;
+ int aadlen, blksz, i, ivlen, outtype, left, len;
for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
for (sw = swcr_sessions[crp->crp_sid & 0xffffffff];
@@ -576,10 +579,22 @@ swcr_combined(struct cryptop *crp)
axf->Reinit(&ctx, iv, ivlen);
/* Supply MAC with AAD */
- for (i = 0; i < crda->crd_len; i += blksz) {
- len = MIN(crda->crd_len - i, blksz);
- COPYDATA(outtype, buf, crda->crd_skip + i, len, blk);
- axf->Update(&ctx, blk, len);
+ aadlen = crda->crd_len;
+ if (crda->crd_flags & CRD_F_ESN)
+ aadlen += 4;
+ for (i = 0; i < aadlen; i += blksz) {
+ len = 0;
+ if (i < crda->crd_len) {
+ len = MIN(crda->crd_len - i, blksz);
+ COPYDATA(outtype, buf, crda->crd_skip + i, len, blk);
+ }
+ left = blksz - len;
+ if (crda->crd_flags & CRD_F_ESN && left > 0) {
+ bcopy(crda->crd_esn, blk + len, MIN(left, aadlen - i));
+ len += MIN(left, aadlen - i);
+ }
+ bzero(blk + len, blksz - len);
+ axf->Update(&ctx, blk, blksz);
}
if (exf->reinit)
@@ -937,6 +952,9 @@ swcr_newsession(u_int32_t *sid, struct cryptoini *cri)
cxf = &comp_algo_deflate;
(*swd)->sw_cxf = cxf;
break;
+ case CRYPTO_ESN:
+ /* nothing to do */
+ break;
default:
swcr_freesession(i);
return EINVAL;
@@ -1192,6 +1210,7 @@ swcr_init(void)
algs[CRYPTO_AES_128_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
algs[CRYPTO_AES_192_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
algs[CRYPTO_AES_256_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
+ algs[CRYPTO_ESN] = CRYPTO_ALG_FLAG_SUPPORTED;
crypto_register(swcr_id, algs, swcr_newsession,
swcr_freesession, swcr_process);
diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h
index c22e14a8819..8e9e84b5f0c 100644
--- a/sys/net/if_pfsync.h
+++ b/sys/net/if_pfsync.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pfsync.h,v 1.44 2010/11/29 05:31:38 dlg Exp $ */
+/* $OpenBSD: if_pfsync.h,v 1.45 2012/06/29 14:48:04 mikeb Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -212,7 +212,7 @@ struct pfsync_bus {
struct pfsync_tdb {
u_int32_t spi;
union sockaddr_union dst;
- u_int32_t rpl;
+ u_int64_t rpl;
u_int64_t cur_bytes;
u_int8_t sproto;
u_int8_t updates;
diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h
index 641b9ff3405..5720d37dd69 100644
--- a/sys/net/pfkeyv2.h
+++ b/sys/net/pfkeyv2.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfkeyv2.h,v 1.60 2010/10/06 22:19:20 mikeb Exp $ */
+/* $OpenBSD: pfkeyv2.h,v 1.61 2012/06/29 14:48:04 mikeb Exp $ */
/*
* @(#)COPYRIGHT 1.1 (NRL) January 1998
*
@@ -330,15 +330,16 @@ struct sadb_x_tap {
#define SADB_X_CALG_LZS 3
#define SADB_X_CALG_MAX 3
-#define SADB_SAFLAGS_PFS 0x001 /* perfect forward secrecy */
-#define SADB_X_SAFLAGS_HALFIV 0x002 /* Used for ESP-old */
-#define SADB_X_SAFLAGS_TUNNEL 0x004 /* Force tunneling */
-#define SADB_X_SAFLAGS_CHAINDEL 0x008 /* Delete whole SA chain */
-#define SADB_X_SAFLAGS_RANDOMPADDING 0x080 /* Random ESP padding */
-#define SADB_X_SAFLAGS_NOREPLAY 0x100 /* No replay counter */
-#define SADB_X_SAFLAGS_UDPENCAP 0x200 /* ESP in UDP */
+#define SADB_SAFLAGS_PFS 0x001 /* perfect forward secrecy */
+#define SADB_X_SAFLAGS_HALFIV 0x002 /* Used for ESP-old */
+#define SADB_X_SAFLAGS_TUNNEL 0x004 /* Force tunneling */
+#define SADB_X_SAFLAGS_CHAINDEL 0x008 /* Delete whole SA chain */
+#define SADB_X_SAFLAGS_RANDOMPADDING 0x080 /* Random ESP padding */
+#define SADB_X_SAFLAGS_NOREPLAY 0x100 /* No replay counter */
+#define SADB_X_SAFLAGS_UDPENCAP 0x200 /* ESP in UDP */
+#define SADB_X_SAFLAGS_ESN 0x400 /* Extended Sequence Number */
-#define SADB_X_POLICYFLAGS_POLICY 0x0001 /* This is a static policy */
+#define SADB_X_POLICYFLAGS_POLICY 0x0001 /* This is a static policy */
#define SADB_IDENTTYPE_RESERVED 0
#define SADB_IDENTTYPE_PREFIX 1
diff --git a/sys/net/pfkeyv2_convert.c b/sys/net/pfkeyv2_convert.c
index a029328b025..d265d58985d 100644
--- a/sys/net/pfkeyv2_convert.c
+++ b/sys/net/pfkeyv2_convert.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfkeyv2_convert.c,v 1.35 2011/04/13 11:28:47 markus Exp $ */
+/* $OpenBSD: pfkeyv2_convert.c,v 1.36 2012/06/29 14:48:04 mikeb Exp $ */
/*
* The author of this code is Angelos D. Keromytis (angelos@keromytis.org)
*
@@ -149,6 +149,9 @@ import_sa(struct tdb *tdb, struct sadb_sa *sadb_sa, struct ipsecinit *ii)
if (sadb_sa->sadb_sa_flags & SADB_X_SAFLAGS_UDPENCAP)
tdb->tdb_flags |= TDBF_UDPENCAP;
+
+ if (sadb_sa->sadb_sa_flags & SADB_X_SAFLAGS_ESN)
+ tdb->tdb_flags |= TDBF_ESN;
}
if (sadb_sa->sadb_sa_state != SADB_SASTATE_MATURE)
@@ -292,6 +295,9 @@ export_sa(void **p, struct tdb *tdb)
if (tdb->tdb_flags & TDBF_UDPENCAP)
sadb_sa->sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP;
+ if (tdb->tdb_flags & TDBF_ESN)
+ sadb_sa->sadb_sa_flags |= SADB_X_SAFLAGS_ESN;
+
*p += sizeof(struct sadb_sa);
}
diff --git a/sys/net/pfkeyv2_parsemessage.c b/sys/net/pfkeyv2_parsemessage.c
index b85eb919eac..2d8f6d26eaa 100644
--- a/sys/net/pfkeyv2_parsemessage.c
+++ b/sys/net/pfkeyv2_parsemessage.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfkeyv2_parsemessage.c,v 1.45 2012/03/28 19:43:21 claudio Exp $ */
+/* $OpenBSD: pfkeyv2_parsemessage.c,v 1.46 2012/06/29 14:48:04 mikeb Exp $ */
/*
* @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
@@ -430,7 +430,7 @@ pfkeyv2_parsemessage(void *p, int len, void **headers)
return (EINVAL);
}
- if (sadb_sa->sadb_sa_replay > 32) {
+ if (sadb_sa->sadb_sa_replay > 64) {
DPRINTF(("pfkeyv2_parsemessage: unsupported "
"replay window size %d in SA extension "
"header %d\n", sadb_sa->sadb_sa_replay,
diff --git a/sys/netinet/ip_ah.c b/sys/netinet/ip_ah.c
index 0d0d4b62cb4..03c64e94a33 100644
--- a/sys/netinet/ip_ah.c
+++ b/sys/netinet/ip_ah.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ah.c,v 1.99 2011/01/11 15:42:05 deraadt Exp $ */
+/* $OpenBSD: ip_ah.c,v 1.100 2012/06/29 14:48:04 mikeb Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -99,7 +99,7 @@ int
ah_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii)
{
struct auth_hash *thash = NULL;
- struct cryptoini cria;
+ struct cryptoini cria, crin;
/* Authentication operation. */
switch (ii->ii_authalg) {
@@ -166,6 +166,13 @@ ah_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii)
cria.cri_klen = ii->ii_authkeylen * 8;
cria.cri_key = ii->ii_authkey;
+ if ((tdbp->tdb_wnd > 0) && !(tdbp->tdb_flags & TDBF_NOREPLAY) &&
+ (tdbp->tdb_flags & TDBF_ESN)) {
+ bzero(&crin, sizeof(crin));
+ crin.cri_alg = CRYPTO_ESN;
+ cria.cri_next = &crin;
+ }
+
return crypto_newsession(&tdbp->tdb_cryptoid, &cria, 0);
}
@@ -543,7 +550,7 @@ ah_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform;
struct tdb_crypto *tc;
struct m_tag *mtag;
- u_int32_t btsx;
+ u_int32_t btsx, esn;
u_int8_t hl;
int rplen;
@@ -565,8 +572,8 @@ ah_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
sizeof(u_int32_t), (caddr_t) &btsx);
btsx = ntohl(btsx);
- switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl),
- tdb->tdb_wnd, &(tdb->tdb_bitmap), 0)) {
+ switch (checkreplaywindow(btsx, &tdb->tdb_rpl, tdb->tdb_wnd,
+ &tdb->tdb_bitmap, &esn, tdb->tdb_flags & TDBF_ESN, 0)) {
case 0: /* All's well. */
break;
@@ -585,15 +592,15 @@ ah_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
"SA %s/%08x\n", ipsp_address(tdb->tdb_dst),
ntohl(tdb->tdb_spi)));
+ ahstat.ahs_replay++;
m_freem(m);
return ENOBUFS;
default:
DPRINTF(("ah_input(): bogus value from "
- "checkreplaywindow32() in SA %s/%08x\n",
+ "checkreplaywindow() in SA %s/%08x\n",
ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
- ahstat.ahs_replay++;
m_freem(m);
return ENOBUFS;
}
@@ -652,6 +659,13 @@ ah_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
crda->crd_key = tdb->tdb_amxkey;
crda->crd_klen = tdb->tdb_amxkeylen * 8;
+ if ((tdb->tdb_wnd > 0) && !(tdb->tdb_flags & TDBF_NOREPLAY) &&
+ (tdb->tdb_flags & TDBF_ESN)) {
+ esn = htonl(esn);
+ bcopy(&esn, crda->crd_esn, 4);
+ crda->crd_flags |= CRD_F_ESN;
+ }
+
#ifdef notyet
/* Find out if we've already done crypto. */
for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL);
@@ -745,7 +759,7 @@ ah_input_cb(void *op)
struct cryptop *crp;
struct m_tag *mtag;
struct tdb *tdb;
- u_int32_t btsx;
+ u_int32_t btsx, esn;
u_int8_t prot;
caddr_t ptr;
@@ -846,8 +860,8 @@ ah_input_cb(void *op)
sizeof(u_int32_t), (caddr_t) &btsx);
btsx = ntohl(btsx);
- switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl),
- tdb->tdb_wnd, &(tdb->tdb_bitmap), 1)) {
+ switch (checkreplaywindow(btsx, &tdb->tdb_rpl, tdb->tdb_wnd,
+ &tdb->tdb_bitmap, &esn, tdb->tdb_flags & TDBF_ESN, 1)) {
case 0: /* All's well. */
#if NPFSYNC > 0
pfsync_update_tdb(tdb,0);
@@ -869,15 +883,15 @@ ah_input_cb(void *op)
"SA %s/%08x\n", ipsp_address(tdb->tdb_dst),
ntohl(tdb->tdb_spi)));
+ ahstat.ahs_replay++;
error = ENOBUFS;
goto baddone;
default:
DPRINTF(("ah_input_cb(): bogus value from "
- "checkreplaywindow32() in SA %s/%08x\n",
+ "checkreplaywindow() in SA %s/%08x\n",
ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
- ahstat.ahs_replay++;
error = ENOBUFS;
goto baddone;
}
@@ -1144,7 +1158,8 @@ ah_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes, M_NOWAIT);
if (!(tdb->tdb_flags & TDBF_NOREPLAY)) {
- ah->ah_rpl = htonl(tdb->tdb_rpl++);
+ tdb->tdb_rpl++;
+ ah->ah_rpl = htonl((u_int32_t)(tdb->tdb_rpl & 0xffffffff));
#if NPFSYNC > 0
pfsync_update_tdb(tdb,1);
#endif
@@ -1171,6 +1186,15 @@ ah_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
crda->crd_key = tdb->tdb_amxkey;
crda->crd_klen = tdb->tdb_amxkeylen * 8;
+ if ((tdb->tdb_wnd > 0) && !(tdb->tdb_flags & TDBF_NOREPLAY) &&
+ (tdb->tdb_flags & TDBF_ESN)) {
+ u_int32_t esn;
+
+ esn = htonl((u_int32_t)(tdb->tdb_rpl >> 32));
+ bcopy(&esn, crda->crd_esn, 4);
+ crda->crd_flags |= CRD_F_ESN;
+ }
+
/* Allocate IPsec-specific opaque crypto info. */
if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0)
tc = malloc(sizeof(*tc) + skip, M_XDATA, M_NOWAIT | M_ZERO);
diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c
index 86b056bfff9..6edbb9e74b7 100644
--- a/sys/netinet/ip_esp.c
+++ b/sys/netinet/ip_esp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_esp.c,v 1.116 2011/01/11 15:42:05 deraadt Exp $ */
+/* $OpenBSD: ip_esp.c,v 1.117 2012/06/29 14:48:04 mikeb Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -101,7 +101,7 @@ esp_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii)
{
struct enc_xform *txform = NULL;
struct auth_hash *thash = NULL;
- struct cryptoini cria, crie;
+ struct cryptoini cria, crie, crin;
if (!ii->ii_encalg && !ii->ii_authalg) {
DPRINTF(("esp_init(): neither authentication nor encryption "
@@ -279,7 +279,14 @@ esp_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii)
bzero(&cria, sizeof(cria));
cria.cri_alg = tdbp->tdb_authalgxform->type;
- cria.cri_next = NULL;
+
+ if ((tdbp->tdb_wnd > 0) && !(tdbp->tdb_flags & TDBF_NOREPLAY) &&
+ (tdbp->tdb_flags & TDBF_ESN)) {
+ bzero(&crin, sizeof(crin));
+ crin.cri_alg = CRYPTO_ESN;
+ cria.cri_next = &crin;
+ }
+
cria.cri_klen = ii->ii_authkeylen * 8;
cria.cri_key = ii->ii_authkey;
}
@@ -328,7 +335,7 @@ esp_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
struct tdb_crypto *tc;
int plen, alen, hlen;
struct m_tag *mtag;
- u_int32_t btsx;
+ u_int32_t btsx, esn;
/* Determine the ESP header length */
if (tdb->tdb_flags & TDBF_NOREPLAY)
@@ -364,8 +371,8 @@ esp_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
(unsigned char *) &btsx);
btsx = ntohl(btsx);
- switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl),
- tdb->tdb_wnd, &(tdb->tdb_bitmap), 0)) {
+ switch (checkreplaywindow(btsx, &tdb->tdb_rpl, tdb->tdb_wnd,
+ &tdb->tdb_bitmap, &esn, tdb->tdb_flags & TDBF_ESN, 0)) {
case 0: /* All's well */
break;
@@ -379,12 +386,12 @@ esp_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
case 3:
DPRINTF(("esp_input(): duplicate packet received in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
m_freem(m);
+ espstat.esps_replay++;
return EACCES;
default:
m_freem(m);
- DPRINTF(("esp_input(): bogus value from checkreplaywindow32() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
- espstat.esps_replay++;
+ DPRINTF(("esp_input(): bogus value from checkreplaywindow() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
return EACCES;
}
}
@@ -462,6 +469,13 @@ esp_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
crda->crd_key = tdb->tdb_amxkey;
crda->crd_klen = tdb->tdb_amxkeylen * 8;
+ if ((tdb->tdb_wnd > 0) && !(tdb->tdb_flags & TDBF_NOREPLAY) &&
+ (tdb->tdb_flags & TDBF_ESN)) {
+ esn = htonl(esn);
+ bcopy(&esn, crda->crd_esn, 4);
+ crda->crd_flags |= CRD_F_ESN;
+ }
+
if (espx && espx->type == CRYPTO_AES_GCM_16)
crda->crd_len = hlen - tdb->tdb_ivlen;
else
@@ -536,7 +550,7 @@ esp_input_cb(void *op)
struct cryptop *crp;
struct m_tag *mtag;
struct tdb *tdb;
- u_int32_t btsx;
+ u_int32_t btsx, esn;
caddr_t ptr;
crp = (struct cryptop *) op;
@@ -619,8 +633,8 @@ esp_input_cb(void *op)
(unsigned char *) &btsx);
btsx = ntohl(btsx);
- switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl),
- tdb->tdb_wnd, &(tdb->tdb_bitmap), 1)) {
+ switch (checkreplaywindow(btsx, &tdb->tdb_rpl, tdb->tdb_wnd,
+ &tdb->tdb_bitmap, &esn, tdb->tdb_flags & TDBF_ESN, 1)) {
case 0: /* All's well */
#if NPFSYNC > 0
pfsync_update_tdb(tdb,0);
@@ -636,12 +650,12 @@ esp_input_cb(void *op)
case 2:
case 3:
DPRINTF(("esp_input_cb(): duplicate packet received in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
+ espstat.esps_replay++;
error = EACCES;
goto baddone;
default:
- DPRINTF(("esp_input_cb(): bogus value from checkreplaywindow32() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
- espstat.esps_replay++;
+ DPRINTF(("esp_input_cb(): bogus value from checkreplaywindow() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
error = EACCES;
goto baddone;
}
@@ -916,7 +930,9 @@ esp_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
/* Initialize ESP header. */
bcopy((caddr_t) &tdb->tdb_spi, mtod(mo, caddr_t), sizeof(u_int32_t));
if (!(tdb->tdb_flags & TDBF_NOREPLAY)) {
- u_int32_t replay = htonl(tdb->tdb_rpl++);
+ u_int32_t replay;
+ tdb->tdb_rpl++;
+ replay = htonl((u_int32_t)tdb->tdb_rpl);
bcopy((caddr_t) &replay, mtod(mo, caddr_t) + sizeof(u_int32_t),
sizeof(u_int32_t));
#if NPFSYNC > 0
@@ -1032,6 +1048,15 @@ esp_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
crda->crd_key = tdb->tdb_amxkey;
crda->crd_klen = tdb->tdb_amxkeylen * 8;
+ if ((tdb->tdb_wnd > 0) && !(tdb->tdb_flags & TDBF_NOREPLAY) &&
+ (tdb->tdb_flags & TDBF_ESN)) {
+ u_int32_t esn;
+
+ esn = htonl((u_int32_t)(tdb->tdb_rpl >> 32));
+ bcopy(&esn, crda->crd_esn, 4);
+ crda->crd_flags |= CRD_F_ESN;
+ }
+
if (espx && espx->type == CRYPTO_AES_GCM_16)
crda->crd_len = hlen - tdb->tdb_ivlen;
else
@@ -1127,6 +1152,34 @@ esp_output_cb(void *op)
return error;
}
+static __inline int
+checkreplay(u_int64_t *bitmap, u_int32_t diff)
+{
+ if (*bitmap & (1ULL << diff))
+ return (1);
+ return (0);
+}
+
+static __inline void
+setreplay(u_int64_t *bitmap, u_int32_t diff, u_int32_t window, int wupdate)
+{
+ if (wupdate) {
+ if (diff < window)
+ *bitmap = ((*bitmap) << diff) | 1;
+ else
+ *bitmap = 1;
+ } else
+ *bitmap |= 1ULL << diff;
+}
+
+/*
+ * To prevent ESN desynchronization replay distance specifies maximum
+ * valid difference between the received SN and the last authenticated
+ * one. It's arbitrary chosen to be 1000 packets, meaning that only
+ * up to 999 packets can be lost.
+ */
+#define REPLAY_DISTANCE (1000)
+
/*
* return 0 on success
* return 1 for counter == 0
@@ -1134,46 +1187,85 @@ esp_output_cb(void *op)
* return 3 for packet within current window but already received
*/
int
-checkreplaywindow32(u_int32_t seq, u_int32_t initial, u_int32_t *lastseq,
- u_int32_t window, u_int32_t *bitmap, int commit)
+checkreplaywindow(u_int32_t seq, u_int64_t *last, u_int32_t window,
+ u_int64_t *bitmap, u_int32_t *seqhigh, int esn, int commit)
{
- u_int32_t diff, llseq, lbitmap;
-
- /* Just do the checking, without "committing" any changes. */
- if (commit == 0) {
- llseq = *lastseq;
- lbitmap = *bitmap;
+ u_int32_t tl, th, wl;
+ u_int32_t seqh, diff;
- lastseq = &llseq;
- bitmap = &lbitmap;
- }
+ tl = (u_int32_t)*last;
+ th = (u_int32_t)(*last >> 32);
- seq -= initial;
+ /* Zero SN is not allowed */
+ if (seq == 0 && tl == 0 && th == 0)
+ return (1);
- if (seq == 0)
- return 1;
+ /* Current replay window starts here */
+ wl = tl - window + 1;
- if (seq > *lastseq - initial) {
- diff = seq - (*lastseq - initial);
- if (diff < window)
- *bitmap = ((*bitmap) << diff) | 1;
- else
- *bitmap = 1;
- *lastseq = seq + initial;
- return 0;
+ /*
+ * We keep the high part intact when:
+ * 1) the SN is within [wl, 0xffffffff] and the whole window is
+ * within one subspace;
+ * 2) the SN is within [0, wl) and window spans two subspaces.
+ */
+ if ((tl >= window - 1 && seq >= wl) ||
+ (tl < window - 1 && seq < wl)) {
+ seqh = *seqhigh = th;
+ if (seq > tl) {
+ if (seq - tl >= REPLAY_DISTANCE)
+ return (2);
+ if (commit) {
+ setreplay(bitmap, seq - tl, window, 1);
+ *last = ((u_int64_t)seqh << 32) | seq;
+ }
+ } else {
+ if (checkreplay(bitmap, tl - seq))
+ return (3);
+ if (commit)
+ setreplay(bitmap, tl - seq, window, 0);
+ }
+ return (0);
}
- diff = *lastseq - initial - seq;
- if (diff >= window) {
- espstat.esps_wrap++;
- return 2;
+ /* Can't wrap if not doing ESN */
+ if (!esn)
+ return (1);
+
+ /*
+ * SN is within [wl, 0xffffffff] and wl is within
+ * [0xffffffff-window, 0xffffffff]. This means we got a SN
+ * which is within our replay window, but in the previous
+ * subspace.
+ */
+ if (tl < window - 1 && seq >= wl) {
+ seqh = *seqhigh = th - 1;
+ diff = (u_int32_t)((((u_int64_t)th << 32) | tl) -
+ (((u_int64_t)seqh << 32) | seq));
+ if (checkreplay(bitmap, diff))
+ return (3);
+ if (commit)
+ setreplay(bitmap, diff, window, 0);
+ return (0);
}
- if ((*bitmap) & (((u_int32_t) 1) << diff)) {
- espstat.esps_replay++;
- return 3;
+ /*
+ * SN has wrapped and the last authenticated SN is in the old
+ * subspace.
+ */
+
+ if (seq - tl >= REPLAY_DISTANCE)
+ return (2);
+
+ seqh = *seqhigh = th + 1;
+ if (seqh == 0) /* Don't let high bit to wrap */
+ return (1);
+ if (commit) {
+ diff = (u_int32_t)((((u_int64_t)seqh << 32) | seq) -
+ (((u_int64_t)th << 32) | tl));
+ setreplay(bitmap, diff, window, 1);
+ *last = ((u_int64_t)seqh << 32) | seq;
}
- *bitmap |= (((u_int32_t) 1) << diff);
- return 0;
+ return (0);
}
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
index 0e9b8a1c22f..80df24988d1 100644
--- a/sys/netinet/ip_ipsp.h
+++ b/sys/netinet/ip_ipsp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.h,v 1.146 2010/10/06 22:19:20 mikeb Exp $ */
+/* $OpenBSD: ip_ipsp.h,v 1.147 2012/06/29 14:48:04 mikeb Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr),
@@ -307,6 +307,7 @@ struct tdb { /* tunnel descriptor block */
#define TDBF_UDPENCAP 0x20000 /* UDP encapsulation */
#define TDBF_PFSYNC 0x40000 /* TDB will be synced */
#define TDBF_PFSYNC_RPL 0x80000 /* Replay counter should be bumped */
+#define TDBF_ESN 0x100000 /* 64-bit sequence numbers (ESN) */
u_int32_t tdb_flags; /* Flags related to this TDB */
@@ -355,8 +356,8 @@ struct tdb { /* tunnel descriptor block */
u_int8_t *tdb_amxkey; /* Raw authentication key */
u_int8_t *tdb_emxkey; /* Raw encryption key */
- u_int32_t tdb_rpl; /* Replay counter */
- u_int32_t tdb_bitmap; /* Used for replay sliding window */
+ u_int64_t tdb_rpl; /* Replay counter */
+ u_int64_t tdb_bitmap; /* Used for replay sliding window */
u_int8_t tdb_iv[4]; /* Used for HALF-IV ESP */
@@ -624,8 +625,8 @@ extern int tcp_signature_tdb_output(struct mbuf *, struct tdb *,
struct mbuf **, int, int);
/* Replay window */
-extern int checkreplaywindow32(u_int32_t, u_int32_t, u_int32_t *, u_int32_t,
- u_int32_t *, int);
+extern int checkreplaywindow(u_int32_t, u_int64_t *, u_int32_t, u_int64_t *,
+ u_int32_t *, int, int);
extern unsigned char ipseczeroes[];