summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/ip_ah.c50
-rw-r--r--sys/netinet/ip_esp.c182
-rw-r--r--sys/netinet/ip_ipsp.h11
3 files changed, 180 insertions, 63 deletions
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[];