diff options
-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_esp.c | 171 | ||||
-rw-r--r-- | sys/opencrypto/cryptodev.h | 10 | ||||
-rw-r--r-- | sys/opencrypto/cryptosoft.c | 8 | ||||
-rw-r--r-- | sys/opencrypto/xform.c | 13 |
7 files changed, 115 insertions, 102 deletions
diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index 025fffe4..7705a63 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -2831,7 +2831,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) @@ -3009,7 +3008,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 ecbef7d..c9365e2 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_esp.c b/sys/netipsec/xform_esp.c index 18953f9..f1c1eaf 100644 --- a/sys/netipsec/xform_esp.c +++ b/sys/netipsec/xform_esp.c @@ -46,6 +46,9 @@ #include <sys/kernel.h> #include <sys/random.h> #include <sys/sysctl.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <machine/atomic.h> #include <net/if.h> #include <net/vnet.h> @@ -180,12 +183,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__, @@ -200,9 +205,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. @@ -224,15 +230,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; @@ -244,19 +250,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 */ @@ -289,10 +291,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; @@ -308,6 +306,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; @@ -348,15 +347,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; } /* @@ -402,20 +399,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, @@ -450,13 +440,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)); } @@ -662,6 +665,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; @@ -687,10 +692,9 @@ 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; @@ -814,7 +818,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__)); @@ -823,29 +827,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__)); @@ -854,6 +838,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); @@ -872,23 +890,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); @@ -919,7 +927,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", diff --git a/sys/opencrypto/cryptodev.h b/sys/opencrypto/cryptodev.h index 5aa450f..d14fb3a 100644 --- a/sys/opencrypto/cryptodev.h +++ b/sys/opencrypto/cryptodev.h @@ -78,7 +78,7 @@ #define SHA2_512_HASH_LEN 64 #define MD5_KPDK_HASH_LEN 16 #define SHA1_KPDK_HASH_LEN 20 -#define AES_HASH_LEN 16 +#define AES_GMAC_HASH_LEN 16 /* Maximum hash algorithm result length */ #define HASH_MAX_LEN SHA2_512_HASH_LEN /* Keep this updated */ @@ -102,12 +102,12 @@ #define SHA2_256_HMAC_KEY_LEN 32 #define SHA2_384_HMAC_KEY_LEN 48 #define SHA2_512_HMAC_KEY_LEN 64 -#define AES_128_HMAC_KEY_LEN 16 -#define AES_192_HMAC_KEY_LEN 24 -#define AES_256_HMAC_KEY_LEN 32 +#define AES_128_GMAC_KEY_LEN 16 +#define AES_192_GMAC_KEY_LEN 24 +#define AES_256_GMAC_KEY_LEN 32 /* Encryption algorithm block sizes */ -#define NULL_BLOCK_LEN 4 +#define NULL_BLOCK_LEN 4 /* IPsec to maintain alignment */ #define DES_BLOCK_LEN 8 #define DES3_BLOCK_LEN 8 #define BLOWFISH_BLOCK_LEN 8 diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c index 77ab507..052916b 100644 --- a/sys/opencrypto/cryptosoft.c +++ b/sys/opencrypto/cryptosoft.c @@ -711,6 +711,7 @@ swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) struct enc_xform *txf; struct comp_algo *cxf; u_int32_t i; + int len; int error; if (sid == NULL || cri == NULL) @@ -928,6 +929,10 @@ swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) case CRYPTO_AES_256_NIST_GMAC: axf = &auth_hash_nist_gmac_aes_256; auth4common: + len = cri->cri_klen / 8; + if (len != 16 && len != 24 && len != 32) + return EINVAL; + (*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, M_NOWAIT); if ((*swd)->sw_ictx == NULL) { @@ -936,8 +941,7 @@ swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) return ENOBUFS; } axf->Init((*swd)->sw_ictx); - axf->Setkey((*swd)->sw_ictx, cri->cri_key, - cri->cri_klen / 8); + axf->Setkey((*swd)->sw_ictx, cri->cri_key, len); (*swd)->sw_axf = axf; break; diff --git a/sys/opencrypto/xform.c b/sys/opencrypto/xform.c index 9e8a1c1..cb44bfa 100644 --- a/sys/opencrypto/xform.c +++ b/sys/opencrypto/xform.c @@ -139,7 +139,7 @@ static int SHA512Update_int(void *, const u_int8_t *, u_int16_t); static u_int32_t deflate_compress(u_int8_t *, u_int32_t, u_int8_t **); static u_int32_t deflate_decompress(u_int8_t *, u_int32_t, u_int8_t **); -#define AESICM_BLOCKSIZE 16 +#define AESICM_BLOCKSIZE AES_BLOCK_LEN struct aes_icm_ctx { u_int32_t ac_ek[4*(RIJNDAEL_MAXNR + 1)]; @@ -353,7 +353,7 @@ struct auth_hash auth_hash_hmac_sha2_512 = { struct auth_hash auth_hash_nist_gmac_aes_128 = { CRYPTO_AES_128_NIST_GMAC, "GMAC-AES-128", - AES_128_HMAC_KEY_LEN, AES_HASH_LEN, sizeof(struct aes_gmac_ctx), + AES_128_GMAC_KEY_LEN, AES_GMAC_HASH_LEN, sizeof(struct aes_gmac_ctx), GMAC_BLOCK_LEN, (void (*)(void *)) AES_GMAC_Init, (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey, @@ -364,7 +364,7 @@ struct auth_hash auth_hash_nist_gmac_aes_128 = { struct auth_hash auth_hash_nist_gmac_aes_192 = { CRYPTO_AES_192_NIST_GMAC, "GMAC-AES-192", - AES_192_HMAC_KEY_LEN, AES_HASH_LEN, sizeof(struct aes_gmac_ctx), + AES_192_GMAC_KEY_LEN, AES_GMAC_HASH_LEN, sizeof(struct aes_gmac_ctx), GMAC_BLOCK_LEN, (void (*)(void *)) AES_GMAC_Init, (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey, @@ -375,7 +375,7 @@ struct auth_hash auth_hash_nist_gmac_aes_192 = { struct auth_hash auth_hash_nist_gmac_aes_256 = { CRYPTO_AES_256_NIST_GMAC, "GMAC-AES-256", - AES_256_HMAC_KEY_LEN, AES_HASH_LEN, sizeof(struct aes_gmac_ctx), + AES_256_GMAC_KEY_LEN, AES_GMAC_HASH_LEN, sizeof(struct aes_gmac_ctx), GMAC_BLOCK_LEN, (void (*)(void *)) AES_GMAC_Init, (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey, @@ -719,6 +719,9 @@ aes_icm_setkey(u_int8_t **sched, u_int8_t *key, int len) { struct aes_icm_ctx *ctx; + if (len != 16 && len != 24 && len != 32) + return EINVAL; + *sched = malloc(sizeof(struct aes_icm_ctx), M_CRYPTO_DATA, M_NOWAIT | M_ZERO); if (*sched == NULL) @@ -726,8 +729,6 @@ aes_icm_setkey(u_int8_t **sched, u_int8_t *key, int len) ctx = (struct aes_icm_ctx *)*sched; ctx->ac_nr = rijndaelKeySetupEnc(ctx->ac_ek, (u_char *)key, len * 8); - if (ctx->ac_nr == 0) - return EINVAL; return 0; } |