From 09715d90bf3324f6f2f4e41aecbfc8943b1a2dc5 Mon Sep 17 00:00:00 2001 From: vanhu Date: Thu, 28 Apr 2011 08:49:43 +0000 Subject: [PATCH] MFC 218794, 219026: Fixed IPsec's HMAC_SHA256-512 support to be RFC4868 compliant. This will break interoperability with all older versions of FreeBSD for those algorithms. Reviewed by: bz, gnn Obtained from: NETASQ git-svn-id: svn://svn.freebsd.org/base/stable/8@221157 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- UPDATING | 10 +++++++ sys/netipsec/key.c | 9 +++++- sys/netipsec/xform.h | 1 + sys/netipsec/xform_ah.c | 24 +++++++++++++-- sys/netipsec/xform_esp.c | 63 +++++++++++++++++++++++++++++++++------- sys/opencrypto/xform.h | 3 +- 6 files changed, 96 insertions(+), 14 deletions(-) diff --git a/UPDATING b/UPDATING index 4b27b43e2..6d9b66315 100644 --- a/UPDATING +++ b/UPDATING @@ -15,6 +15,16 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 8.x IS SLOW ON IA64 OR SUN4V: debugging tools present in HEAD were left in place because sun4v support still needs work to become production ready. +20110428: + IPsec's HMAC_SHA256-512 support has been fixed to be RFC4868 + compliant, and will now use half of hash for authentication. + This will break interoperability with all stacks (including all + older FreeBSD versions) who implement + draft-ietf-ipsec-ciph-sha-256-00 (they use 96 bits of hash for + authentication). + The only workaround with such peers is to use another HMAC + algorithm for IPsec ("phase 2") authentication. + 20110221: 8.2-RELEASE. diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index 71632b8d3..ff6a90f26 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -6103,6 +6103,9 @@ key_getsizes_ah( case SADB_X_AALG_MD5: *min = *max = 16; break; case SADB_X_AALG_SHA: *min = *max = 20; break; case SADB_X_AALG_NULL: *min = 1; *max = 256; break; + case SADB_X_AALG_SHA2_256: *min = *max = 32; break; + case SADB_X_AALG_SHA2_384: *min = *max = 48; break; + case SADB_X_AALG_SHA2_512: *min = *max = 64; break; default: DPRINTF(("%s: unknown AH algorithm %u\n", __func__, alg)); @@ -6128,7 +6131,11 @@ key_getcomb_ah() for (i = 1; i <= SADB_AALG_MAX; i++) { #if 1 /* we prefer HMAC algorithms, not old algorithms */ - if (i != SADB_AALG_SHA1HMAC && i != SADB_AALG_MD5HMAC) + if (i != SADB_AALG_SHA1HMAC && + i != SADB_AALG_MD5HMAC && + i != SADB_X_AALG_SHA2_256 && + i != SADB_X_AALG_SHA2_384 && + i != SADB_X_AALG_SHA2_512) continue; #endif algo = ah_algorithm_lookup(i); diff --git a/sys/netipsec/xform.h b/sys/netipsec/xform.h index 92f7866a1..47e2cfeec 100644 --- a/sys/netipsec/xform.h +++ b/sys/netipsec/xform.h @@ -46,6 +46,7 @@ #include #define AH_HMAC_HASHLEN 12 /* 96 bits of authenticator */ +#define AH_HMAC_MAXHASHLEN (SHA2_512_HASH_LEN/2) /* Keep this updated */ #define AH_HMAC_INITIAL_RPL 1 /* replay counter initial value */ /* diff --git a/sys/netipsec/xform_ah.c b/sys/netipsec/xform_ah.c index d77f2463d..5701f90f7 100644 --- a/sys/netipsec/xform_ah.c +++ b/sys/netipsec/xform_ah.c @@ -85,8 +85,7 @@ * to use a fixed 16-byte authenticator. The new algorithm use 12-byte * authenticator. */ -#define AUTHSIZE(sav) \ - ((sav->flags & SADB_X_EXT_OLD) ? 16 : AH_HMAC_HASHLEN) +#define AUTHSIZE(sav) ah_authsize(sav) VNET_DEFINE(int, ah_enable) = 1; /* control flow of packets with AH */ VNET_DEFINE(int, ah_cleartos) = 1; /* clear ip_tos when doing AH calc */ @@ -105,6 +104,27 @@ static unsigned char ipseczeroes[256]; /* larger than an ip6 extension hdr */ static int ah_input_cb(struct cryptop*); static int ah_output_cb(struct cryptop*); +static int +ah_authsize(struct secasvar *sav) +{ + + IPSEC_ASSERT(sav != NULL, ("%s: sav == NULL", __func__)); + + if (sav->flags & SADB_X_EXT_OLD) + return 16; + + switch (sav->alg_auth) { + case SADB_X_AALG_SHA2_256: + return 16; + case SADB_X_AALG_SHA2_384: + return 24; + case SADB_X_AALG_SHA2_512: + return 32; + default: + return AH_HMAC_HASHLEN; + } + /* NOTREACHED */ +} /* * NB: this is public for use by the PF_KEY support. */ diff --git a/sys/netipsec/xform_esp.c b/sys/netipsec/xform_esp.c index a84f525a0..fe1a27a9a 100644 --- a/sys/netipsec/xform_esp.c +++ b/sys/netipsec/xform_esp.c @@ -297,7 +297,19 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) else hlen = sizeof (struct newesp) + sav->ivlen; /* Authenticator hash size */ - alen = esph ? AH_HMAC_HASHLEN : 0; + if (esph != NULL) { + switch (esph->type) { + case CRYPTO_SHA2_256_HMAC: + case CRYPTO_SHA2_384_HMAC: + case CRYPTO_SHA2_512_HMAC: + alen = esph->hashsize/2; + break; + default: + alen = AH_HMAC_HASHLEN; + break; + } + }else + alen = 0; /* * Verify payload length is multiple of encryption algorithm @@ -450,8 +462,8 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) static int esp_input_cb(struct cryptop *crp) { - u_int8_t lastthree[3], aalg[AH_HMAC_HASHLEN]; - int hlen, skip, protoff, error; + u_int8_t lastthree[3], aalg[AH_HMAC_MAXHASHLEN]; + int hlen, skip, protoff, error, alen; struct mbuf *m; struct cryptodesc *crd; struct auth_hash *esph; @@ -519,6 +531,16 @@ esp_input_cb(struct cryptop *crp) /* If authentication was performed, check now. */ if (esph != NULL) { + switch (esph->type) { + case CRYPTO_SHA2_256_HMAC: + case CRYPTO_SHA2_384_HMAC: + case CRYPTO_SHA2_512_HMAC: + alen = esph->hashsize/2; + break; + default: + alen = AH_HMAC_HASHLEN; + break; + } /* * If we have a tag, it means an IPsec-aware NIC did * the verification for us. Otherwise we need to @@ -527,13 +549,13 @@ esp_input_cb(struct cryptop *crp) V_ahstat.ahs_hist[sav->alg_auth]++; if (mtag == NULL) { /* Copy the authenticator from the packet */ - m_copydata(m, m->m_pkthdr.len - AH_HMAC_HASHLEN, - AH_HMAC_HASHLEN, aalg); + m_copydata(m, m->m_pkthdr.len - alen, + alen, aalg); ptr = (caddr_t) (tc + 1); /* Verify authenticator */ - if (bcmp(ptr, aalg, AH_HMAC_HASHLEN) != 0) { + if (bcmp(ptr, aalg, alen) != 0) { DPRINTF(("%s: " "authentication hash mismatch for packet in SA %s/%08lx\n", __func__, @@ -546,7 +568,7 @@ esp_input_cb(struct cryptop *crp) } /* Remove trailing authenticator */ - m_adj(m, -AH_HMAC_HASHLEN); + m_adj(m, -alen); } /* Release the crypto descriptors */ @@ -690,7 +712,16 @@ esp_output( plen = rlen + padding; /* Padded payload length. */ if (esph) + switch (esph->type) { + case CRYPTO_SHA2_256_HMAC: + case CRYPTO_SHA2_384_HMAC: + case CRYPTO_SHA2_512_HMAC: + alen = esph->hashsize/2; + break; + default: alen = AH_HMAC_HASHLEN; + break; + } else alen = 0; @@ -944,7 +975,7 @@ esp_output_cb(struct cryptop *crp) #ifdef REGRESSION /* Emulate man-in-the-middle attack when ipsec_integrity is TRUE. */ if (V_ipsec_integrity) { - static unsigned char ipseczeroes[AH_HMAC_HASHLEN]; + static unsigned char ipseczeroes[AH_HMAC_MAXHASHLEN]; struct auth_hash *esph; /* @@ -953,8 +984,20 @@ esp_output_cb(struct cryptop *crp) */ esph = sav->tdb_authalgxform; if (esph != NULL) { - m_copyback(m, m->m_pkthdr.len - AH_HMAC_HASHLEN, - AH_HMAC_HASHLEN, ipseczeroes); + int alen; + + switch (esph->type) { + case CRYPTO_SHA2_256_HMAC: + case CRYPTO_SHA2_384_HMAC: + case CRYPTO_SHA2_512_HMAC: + alen = esph->hashsize/2; + break; + default: + alen = AH_HMAC_HASHLEN; + break; + } + m_copyback(m, m->m_pkthdr.len - alen, + alen, ipseczeroes); } } #endif diff --git a/sys/opencrypto/xform.h b/sys/opencrypto/xform.h index 0a7f981d5..8df7b07e8 100644 --- a/sys/opencrypto/xform.h +++ b/sys/opencrypto/xform.h @@ -43,7 +43,8 @@ struct auth_hash { void (*Final) (u_int8_t *, void *); }; -#define AH_ALEN_MAX 20 /* max authenticator hash length */ +/* XXX use a define common with other hash stuff ! */ +#define AH_ALEN_MAX 64 /* max authenticator hash length */ struct enc_xform { int type; -- 2.45.0