diff options
Diffstat (limited to 'sys/netipsec')
-rw-r--r-- | sys/netipsec/ipsec_output.c | 3 | ||||
-rw-r--r-- | sys/netipsec/key.c | 2 | ||||
-rw-r--r-- | sys/netipsec/key_debug.c | 5 | ||||
-rw-r--r-- | sys/netipsec/keydb.h | 8 | ||||
-rw-r--r-- | sys/netipsec/xform.h | 1 | ||||
-rw-r--r-- | sys/netipsec/xform_ah.c | 35 | ||||
-rw-r--r-- | sys/netipsec/xform_esp.c | 204 |
7 files changed, 138 insertions, 120 deletions
diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c index ae36070..a6611a7 100644 --- a/sys/netipsec/ipsec_output.c +++ b/sys/netipsec/ipsec_output.c @@ -158,6 +158,8 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) tdbi->spi = sav->spi; m_tag_prepend(m, mtag); + key_sa_recordxfer(sav, m); /* record data transfer */ + /* * If there's another (bundled) SA to apply, do so. * Note that this puts a burden on the kernel stack size. @@ -202,7 +204,6 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) goto bad; } } - key_sa_recordxfer(sav, m); /* record data transfer */ /* * We're done with IPsec processing, transmit the packet using the diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index 34e8c41..9927509 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -2835,7 +2835,6 @@ key_cleansav(struct secasvar *sav) sav->tdb_xform->xf_zeroize(sav); sav->tdb_xform = NULL; } else { - KASSERT(sav->iv == NULL, ("iv but no xform")); if (sav->key_auth != NULL) bzero(sav->key_auth->key_data, _KEYLEN(sav->key_auth)); if (sav->key_enc != NULL) @@ -3013,7 +3012,6 @@ key_setsaval(struct secasvar *sav, struct mbuf *m, sav->key_enc = NULL; sav->sched = NULL; sav->schedlen = 0; - sav->iv = NULL; sav->lft_c = NULL; sav->lft_h = NULL; sav->lft_s = NULL; diff --git a/sys/netipsec/key_debug.c b/sys/netipsec/key_debug.c index 97ac061..b5bdb0e 100644 --- a/sys/netipsec/key_debug.c +++ b/sys/netipsec/key_debug.c @@ -577,11 +577,6 @@ kdebug_secasv(struct secasvar *sav) kdebug_sadb_key((struct sadb_ext *)sav->key_auth); if (sav->key_enc != NULL) kdebug_sadb_key((struct sadb_ext *)sav->key_enc); - if (sav->iv != NULL) { - printf(" iv="); - ipsec_hexdump(sav->iv, sav->ivlen ? sav->ivlen : 8); - printf("\n"); - } if (sav->replay != NULL) kdebug_secreplay(sav->replay); diff --git a/sys/netipsec/keydb.h b/sys/netipsec/keydb.h index 15dbc9c..3fe28eb 100644 --- a/sys/netipsec/keydb.h +++ b/sys/netipsec/keydb.h @@ -122,10 +122,10 @@ struct secasvar { struct seckey *key_auth; /* Key for Authentication */ struct seckey *key_enc; /* Key for Encryption */ - caddr_t iv; /* Initilization Vector */ u_int ivlen; /* length of IV */ void *sched; /* intermediate encryption key */ size_t schedlen; + uint64_t cntr; /* counter for GCM and CTR */ struct secreplay *replay; /* replay prevention */ time_t created; /* for lifetime */ @@ -163,6 +163,12 @@ struct secasvar { #define SECASVAR_UNLOCK(_sav) mtx_unlock(&(_sav)->lock) #define SECASVAR_LOCK_DESTROY(_sav) mtx_destroy(&(_sav)->lock) #define SECASVAR_LOCK_ASSERT(_sav) mtx_assert(&(_sav)->lock, MA_OWNED) +#define SAV_ISGCM(_sav) \ + ((_sav)->alg_enc == SADB_X_EALG_AESGCM8 || \ + (_sav)->alg_enc == SADB_X_EALG_AESGCM12 || \ + (_sav)->alg_enc == SADB_X_EALG_AESGCM16) +#define SAV_ISCTR(_sav) ((_sav)->alg_enc == SADB_X_EALG_AESCTR) +#define SAV_ISCTRORGCM(_sav) (SAV_ISCTR((_sav)) || SAV_ISGCM((_sav))) /* replay prevention */ struct secreplay { diff --git a/sys/netipsec/xform.h b/sys/netipsec/xform.h index 132717f..fee457b 100644 --- a/sys/netipsec/xform.h +++ b/sys/netipsec/xform.h @@ -105,6 +105,7 @@ struct xformsw { #ifdef _KERNEL extern void xform_register(struct xformsw*); extern int xform_init(struct secasvar *sav, int xftype); +extern int xform_ah_authsize(struct auth_hash *esph); struct cryptoini; diff --git a/sys/netipsec/xform_ah.c b/sys/netipsec/xform_ah.c index 0710578..350a735 100644 --- a/sys/netipsec/xform_ah.c +++ b/sys/netipsec/xform_ah.c @@ -85,8 +85,8 @@ * Return authenticator size in bytes, based on a field in the * algorithm descriptor. */ -#define AUTHSIZE(sav) \ - ((sav->flags & SADB_X_EXT_OLD) ? 16 : (sav)->tdb_authalgxform->hashsize) +#define AUTHSIZE(sav) ((sav->flags & SADB_X_EXT_OLD) ? 16 : \ + xform_ah_authsize((sav)->tdb_authalgxform)) 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 */ @@ -112,6 +112,35 @@ 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*); +int +xform_ah_authsize(struct auth_hash *esph) +{ + int alen; + + if (esph == NULL) + return 0; + + switch (esph->type) { + case CRYPTO_SHA2_256_HMAC: + case CRYPTO_SHA2_384_HMAC: + case CRYPTO_SHA2_512_HMAC: + alen = esph->hashsize / 2; /* RFC4868 2.3 */ + break; + + case CRYPTO_AES_128_NIST_GMAC: + case CRYPTO_AES_192_NIST_GMAC: + case CRYPTO_AES_256_NIST_GMAC: + alen = esph->hashsize; + break; + + default: + alen = AH_HMAC_HASHLEN; + break; + } + + return alen; +} + /* * NB: this is public for use by the PF_KEY support. */ @@ -748,7 +777,7 @@ ah_input_cb(struct cryptop *crp) /* Verify authenticator. */ ptr = (caddr_t) (tc + 1); - if (bcmp(ptr + skip + rplen, calc, authsize)) { + if (timingsafe_bcmp(ptr + skip + rplen, calc, authsize)) { DPRINTF(("%s: authentication hash mismatch for packet " "in SA %s/%08lx\n", __func__, ipsec_address(&saidx->dst, buf, sizeof(buf)), diff --git a/sys/netipsec/xform_esp.c b/sys/netipsec/xform_esp.c index e0dc2b2..a48c038 100644 --- a/sys/netipsec/xform_esp.c +++ b/sys/netipsec/xform_esp.c @@ -48,6 +48,8 @@ #include <sys/random.h> #include <sys/rwlock.h> #include <sys/sysctl.h> +#include <sys/mutex.h> +#include <machine/atomic.h> #include <net/if.h> #include <net/vnet.h> @@ -115,8 +117,6 @@ esp_algorithm_lookup(int alg) return &enc_xform_blf; case SADB_X_EALG_CAST128CBC: return &enc_xform_cast5; - case SADB_X_EALG_SKIPJACK: - return &enc_xform_skipjack; case SADB_EALG_NULL: return &enc_xform_null; case SADB_X_EALG_CAMELLIACBC: @@ -184,12 +184,14 @@ esp_init(struct secasvar *sav, struct xformsw *xsp) __func__, txform->name)); return EINVAL; } - if ((sav->flags&(SADB_X_EXT_OLD|SADB_X_EXT_IV4B)) == SADB_X_EXT_IV4B) { + if ((sav->flags & (SADB_X_EXT_OLD | SADB_X_EXT_IV4B)) == + SADB_X_EXT_IV4B) { DPRINTF(("%s: 4-byte IV not supported with protocol\n", __func__)); return EINVAL; } - keylen = _KEYLEN(sav->key_enc); + /* subtract off the salt, RFC4106, 8.1 and RFC3686, 5.1 */ + keylen = _KEYLEN(sav->key_enc) - SAV_ISCTRORGCM(sav) * 4; if (txform->minkey > keylen || keylen > txform->maxkey) { DPRINTF(("%s: invalid key length %u, must be in the range " "[%u..%u] for algorithm %s\n", __func__, @@ -204,9 +206,10 @@ esp_init(struct secasvar *sav, struct xformsw *xsp) * the ESP header will be processed incorrectly. The * compromise is to force it to zero here. */ - sav->ivlen = (txform == &enc_xform_null ? 0 : txform->ivsize); - sav->iv = (caddr_t) malloc(sav->ivlen, M_XDATA, M_WAITOK); - key_randomfill(sav->iv, sav->ivlen); /*XXX*/ + if (SAV_ISCTRORGCM(sav)) + sav->ivlen = 8; /* RFC4106 3.1 and RFC3686 3.1 */ + else + sav->ivlen = (txform == &enc_xform_null ? 0 : txform->ivsize); /* * Setup AH-related state. @@ -228,15 +231,15 @@ esp_init(struct secasvar *sav, struct xformsw *xsp) */ if (sav->alg_enc == SADB_X_EALG_AESGCM16) { switch (keylen) { - case AES_128_HMAC_KEY_LEN: + case AES_128_GMAC_KEY_LEN: sav->alg_auth = SADB_X_AALG_AES128GMAC; sav->tdb_authalgxform = &auth_hash_nist_gmac_aes_128; break; - case AES_192_HMAC_KEY_LEN: + case AES_192_GMAC_KEY_LEN: sav->alg_auth = SADB_X_AALG_AES192GMAC; sav->tdb_authalgxform = &auth_hash_nist_gmac_aes_192; break; - case AES_256_HMAC_KEY_LEN: + case AES_256_GMAC_KEY_LEN: sav->alg_auth = SADB_X_AALG_AES256GMAC; sav->tdb_authalgxform = &auth_hash_nist_gmac_aes_256; break; @@ -248,19 +251,15 @@ esp_init(struct secasvar *sav, struct xformsw *xsp) } bzero(&cria, sizeof(cria)); cria.cri_alg = sav->tdb_authalgxform->type; - cria.cri_klen = _KEYBITS(sav->key_enc) + 4; cria.cri_key = sav->key_enc->key_data; + cria.cri_klen = _KEYBITS(sav->key_enc) - SAV_ISGCM(sav) * 32; } /* Initialize crypto session. */ - bzero(&crie, sizeof (crie)); + bzero(&crie, sizeof(crie)); crie.cri_alg = sav->tdb_encalgxform->type; - crie.cri_klen = _KEYBITS(sav->key_enc); crie.cri_key = sav->key_enc->key_data; - if (sav->alg_enc == SADB_X_EALG_AESGCM16) - arc4rand(crie.cri_iv, sav->ivlen, 0); - - /* XXX Rounds ? */ + crie.cri_klen = _KEYBITS(sav->key_enc) - SAV_ISCTRORGCM(sav) * 32; if (sav->tdb_authalgxform && sav->tdb_encalgxform) { /* init both auth & enc */ @@ -293,10 +292,6 @@ esp_zeroize(struct secasvar *sav) if (sav->key_enc) bzero(sav->key_enc->key_data, _KEYLEN(sav->key_enc)); - if (sav->iv) { - free(sav->iv, M_XDATA); - sav->iv = NULL; - } sav->tdb_encalgxform = NULL; sav->tdb_xform = NULL; return error; @@ -312,6 +307,7 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) struct auth_hash *esph; struct enc_xform *espx; struct tdb_crypto *tc; + uint8_t *ivp; int plen, alen, hlen; struct newesp *esp; struct cryptodesc *crde; @@ -320,7 +316,6 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) IPSEC_ASSERT(sav != NULL, ("null SA")); IPSEC_ASSERT(sav->tdb_encalgxform != NULL, ("null encoding xform")); - alen = 0; /* Valid IP Packet length ? */ if ( (skip&3) || (m->m_pkthdr.len&3) ){ DPRINTF(("%s: misaligned packet, skip %u pkt len %u", @@ -335,13 +330,13 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) esph = sav->tdb_authalgxform; espx = sav->tdb_encalgxform; - /* Determine the ESP header length */ + /* Determine the ESP header and auth length */ if (sav->flags & SADB_X_EXT_OLD) hlen = sizeof (struct esp) + sav->ivlen; else hlen = sizeof (struct newesp) + sav->ivlen; - /* Authenticator hash size */ - alen = esph ? esph->hashsize : 0; + + alen = xform_ah_authsize(esph); /* * Verify payload length is multiple of encryption algorithm @@ -353,15 +348,13 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) */ plen = m->m_pkthdr.len - (skip + hlen + alen); if ((plen & (espx->blocksize - 1)) || (plen <= 0)) { - if (!espx || sav->alg_enc != SADB_X_EALG_AESGCM16) { - DPRINTF(("%s: payload of %d octets not a multiple of %d octets," - " SA %s/%08lx\n", __func__, - plen, espx->blocksize, ipsec_address(&sav->sah->saidx.dst, - buf, sizeof(buf)), (u_long) ntohl(sav->spi))); - ESPSTAT_INC(esps_badilen); - m_freem(m); - return EINVAL; - } + DPRINTF(("%s: payload of %d octets not a multiple of %d octets," + " SA %s/%08lx\n", __func__, plen, espx->blocksize, + ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), + (u_long)ntohl(sav->spi))); + ESPSTAT_INC(esps_badilen); + m_freem(m); + return EINVAL; } /* @@ -407,20 +400,13 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) /* Authentication descriptor */ crda->crd_skip = skip; - if (espx && espx->type == CRYPTO_AES_NIST_GCM_16) - crda->crd_len = hlen - sav->ivlen; + if (SAV_ISGCM(sav)) + crda->crd_len = 8; /* RFC4106 5, SPI + SN */ else crda->crd_len = m->m_pkthdr.len - (skip + alen); crda->crd_inject = m->m_pkthdr.len - alen; crda->crd_alg = esph->type; - if (espx && (espx->type == CRYPTO_AES_NIST_GCM_16)) { - crda->crd_key = sav->key_enc->key_data; - crda->crd_klen = _KEYBITS(sav->key_enc); - } else { - crda->crd_key = sav->key_auth->key_data; - crda->crd_klen = _KEYBITS(sav->key_auth); - } /* Copy the authenticator */ m_copydata(m, m->m_pkthdr.len - alen, alen, @@ -455,13 +441,26 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen); crde->crd_inject = skip + hlen - sav->ivlen; - crde->crd_alg = espx->type; - crde->crd_key = sav->key_enc->key_data; - crde->crd_klen = _KEYBITS(sav->key_enc); - if (espx && (espx->type == CRYPTO_AES_NIST_GCM_16)) + if (SAV_ISCTRORGCM(sav)) { + ivp = &crde->crd_iv[0]; + + /* GCM IV Format: RFC4106 4 */ + /* CTR IV Format: RFC3686 4 */ + /* Salt is last four bytes of key, RFC4106 8.1 */ + /* Nonce is last four bytes of key, RFC3686 5.1 */ + memcpy(ivp, sav->key_enc->key_data + + _KEYLEN(sav->key_enc) - 4, 4); + + if (SAV_ISCTR(sav)) { + /* Initial block counter is 1, RFC3686 4 */ + be32enc(&ivp[sav->ivlen + 4], 1); + } + + m_copydata(m, skip + hlen - sav->ivlen, sav->ivlen, &ivp[4]); crde->crd_flags |= CRD_F_IV_EXPLICIT; + } - /* XXX Rounds ? */ + crde->crd_alg = espx->type; return (crypto_dispatch(crp)); } @@ -530,14 +529,14 @@ esp_input_cb(struct cryptop *crp) /* If authentication was performed, check now. */ if (esph != NULL) { - alen = esph->hashsize; + alen = xform_ah_authsize(esph); AHSTAT_INC(ahs_hist[sav->alg_auth]); /* Copy the authenticator from the packet */ m_copydata(m, m->m_pkthdr.len - alen, alen, aalg); ptr = (caddr_t) (tc + 1); /* Verify authenticator */ - if (bcmp(ptr, aalg, alen) != 0) { + if (timingsafe_bcmp(ptr, aalg, alen) != 0) { DPRINTF(("%s: authentication hash mismatch for " "packet in SA %s/%08lx\n", __func__, ipsec_address(&saidx->dst, buf, sizeof(buf)), @@ -667,6 +666,8 @@ esp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp, char buf[INET6_ADDRSTRLEN]; struct enc_xform *espx; struct auth_hash *esph; + uint8_t *ivp; + uint64_t cntr; int hlen, rlen, padding, blks, alen, i, roff; struct mbuf *mo = (struct mbuf *) NULL; struct tdb_crypto *tc; @@ -692,18 +693,14 @@ esp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp, rlen = m->m_pkthdr.len - skip; /* Raw payload length. */ /* - * NB: The null encoding transform has a blocksize of 4 - * so that headers are properly aligned. + * RFC4303 2.4 Requires 4 byte alignment. */ - blks = espx->ivsize; /* IV blocksize */ + blks = MAX(4, espx->blocksize); /* Cipher blocksize */ /* XXX clamp padding length a la KAME??? */ padding = ((blks - ((rlen + 2) % blks)) % blks) + 2; - if (esph) - alen = esph->hashsize; - else - alen = 0; + alen = xform_ah_authsize(esph); ESPSTAT_INC(esps_output); @@ -822,7 +819,7 @@ esp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp, m_copyback(m, protoff, sizeof(u_int8_t), (u_char *) &prot); /* Get crypto descriptors. */ - crp = crypto_getreq(esph && espx ? 2 : 1); + crp = crypto_getreq(esph != NULL ? 2 : 1); if (crp == NULL) { DPRINTF(("%s: failed to acquire crypto descriptors\n", __func__)); @@ -831,29 +828,9 @@ esp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp, goto bad; } - if (espx) { - crde = crp->crp_desc; - crda = crde->crd_next; - - /* Encryption descriptor. */ - crde->crd_skip = skip + hlen; - crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen); - crde->crd_flags = CRD_F_ENCRYPT; - crde->crd_inject = skip + hlen - sav->ivlen; - - /* Encryption operation. */ - crde->crd_alg = espx->type; - crde->crd_key = sav->key_enc->key_data; - crde->crd_klen = _KEYBITS(sav->key_enc); - if (espx->type == CRYPTO_AES_NIST_GCM_16) - crde->crd_flags |= CRD_F_IV_EXPLICIT; - /* XXX Rounds ? */ - } else - crda = crp->crp_desc; - /* IPsec-specific opaque crypto info. */ tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto), - M_XDATA, M_NOWAIT|M_ZERO); + M_XDATA, M_NOWAIT|M_ZERO); if (tc == NULL) { crypto_freereq(crp); DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__)); @@ -862,6 +839,40 @@ esp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp, goto bad; } + crde = crp->crp_desc; + crda = crde->crd_next; + + /* Encryption descriptor. */ + crde->crd_skip = skip + hlen; + crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen); + crde->crd_flags = CRD_F_ENCRYPT; + crde->crd_inject = skip + hlen - sav->ivlen; + + /* Encryption operation. */ + crde->crd_alg = espx->type; + if (SAV_ISCTRORGCM(sav)) { + ivp = &crde->crd_iv[0]; + + /* GCM IV Format: RFC4106 4 */ + /* CTR IV Format: RFC3686 4 */ + /* Salt is last four bytes of key, RFC4106 8.1 */ + /* Nonce is last four bytes of key, RFC3686 5.1 */ + memcpy(ivp, sav->key_enc->key_data + + _KEYLEN(sav->key_enc) - 4, 4); + SECASVAR_LOCK(sav); + cntr = sav->cntr++; + SECASVAR_UNLOCK(sav); + be64enc(&ivp[4], cntr); + + if (SAV_ISCTR(sav)) { + /* Initial block counter is 1, RFC3686 4 */ + be32enc(&ivp[sav->ivlen + 4], 1); + } + + m_copyback(m, skip + hlen - sav->ivlen, sav->ivlen, &ivp[4]); + crde->crd_flags |= CRD_F_IV_EXPLICIT|CRD_F_IV_PRESENT; + } + /* Callback parameters */ tc->tc_isr = isr; KEY_ADDREFSA(sav); @@ -880,23 +891,13 @@ esp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp, if (esph) { /* Authentication descriptor. */ + crda->crd_alg = esph->type; crda->crd_skip = skip; - if (espx && espx->type == CRYPTO_AES_NIST_GCM_16) - crda->crd_len = hlen - sav->ivlen; + if (SAV_ISGCM(sav)) + crda->crd_len = 8; /* RFC4106 5, SPI + SN */ else crda->crd_len = m->m_pkthdr.len - (skip + alen); crda->crd_inject = m->m_pkthdr.len - alen; - - /* Authentication operation. */ - crda->crd_alg = esph->type; - if (espx && espx->type == CRYPTO_AES_NIST_GCM_16) { - crda->crd_key = sav->key_enc->key_data; - crda->crd_klen = _KEYBITS(sav->key_enc); - } else { - crda->crd_key = sav->key_auth->key_data; - crda->crd_klen = _KEYBITS(sav->key_auth); - } - } return crypto_dispatch(crp); @@ -927,7 +928,8 @@ esp_output_cb(struct cryptop *crp) IPSEC_ASSERT(isr->sp != NULL, ("NULL isr->sp")); IPSECREQUEST_LOCK(isr); sav = tc->tc_sav; - /* With the isr lock released SA pointer can be updated. */ + + /* With the isr lock released, SA pointer may have changed. */ if (sav != isr->sav) { ESPSTAT_INC(esps_notdb); DPRINTF(("%s: SA gone during crypto (SA %s/%08lx proto %u)\n", @@ -983,21 +985,7 @@ esp_output_cb(struct cryptop *crp) if (esph != NULL) { 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; - case CRYPTO_AES_128_NIST_GMAC: - case CRYPTO_AES_192_NIST_GMAC: - case CRYPTO_AES_256_NIST_GMAC: - alen = esph->hashsize; - break; - default: - alen = AH_HMAC_HASHLEN; - break; - } + alen = xform_ah_authsize(esph); m_copyback(m, m->m_pkthdr.len - alen, alen, ipseczeroes); } |