diff options
-rw-r--r-- | sys/crypto/cryptodev.h | 14 | ||||
-rw-r--r-- | sys/crypto/cryptosoft.c | 31 | ||||
-rw-r--r-- | sys/net/if_pfsync.h | 4 | ||||
-rw-r--r-- | sys/net/pfkeyv2.h | 19 | ||||
-rw-r--r-- | sys/net/pfkeyv2_convert.c | 8 | ||||
-rw-r--r-- | sys/net/pfkeyv2_parsemessage.c | 4 | ||||
-rw-r--r-- | sys/netinet/ip_ah.c | 50 | ||||
-rw-r--r-- | sys/netinet/ip_esp.c | 182 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.h | 11 |
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[]; |