Hi, This patch is a glue for using AES-XCBC-MAC from IPsec. This depends on the previous patch.
I have already checked the patch with TAHI test. I should have put sequence number on my patches, sorry. Signed-off-by: Kazunori MIYAZAWA <[EMAIL PROTECTED]> -- Kazunori Miyazawa
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index 6351c40..707e22a 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -285,6 +285,7 @@ struct sadb_x_sec_ctx { #define SADB_X_AALG_SHA2_384HMAC 6 #define SADB_X_AALG_SHA2_512HMAC 7 #define SADB_X_AALG_RIPEMD160HMAC 8 +#define SADB_X_AALG_AES_XCBC_MAC 9 #define SADB_X_AALG_NULL 251 /* kame */ #define SADB_AALG_MAX 251 diff --git a/include/net/ah.h b/include/net/ah.h index ceff00a..32c5496 100644 --- a/include/net/ah.h +++ b/include/net/ah.h @@ -14,13 +14,13 @@ struct ah_data int icv_full_len; int icv_trunc_len; - void (*icv)(struct ah_data*, + int (*icv)(struct ah_data*, struct sk_buff *skb, u8 *icv); struct crypto_tfm *tfm; }; -static inline void +static inline int ah_hmac_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data) { struct crypto_tfm *tfm = ahp->tfm; @@ -30,6 +30,29 @@ ah_hmac_digest(struct ah_data *ahp, stru skb_icv_walk(skb, tfm, 0, skb->len, crypto_hmac_update); crypto_hmac_final(tfm, ahp->key, &ahp->key_len, ahp->work_icv); memcpy(auth_data, ahp->work_icv, ahp->icv_trunc_len); + + return 0; } +#ifdef CONFIG_CRYPTO_XCBC +static inline int +ah_xcbc_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data) +{ + struct crypto_tfm *tfm = ahp->tfm; + int err; + + memset(auth_data, 0, ahp->icv_trunc_len); + err = crypto_xcbc_init(tfm, ahp->key, ahp->key_len); + if (err != 0) + return err; + + skb_icv_walk(skb, tfm, 0, skb->len, crypto_xcbc_update); + err = crypto_xcbc_final(tfm, ahp->key, ahp->key_len, ahp->work_icv); + if (err != 0) + return err; + memcpy(auth_data, ahp->work_icv, ahp->icv_trunc_len); + + return 0; +} +#endif #endif diff --git a/include/net/esp.h b/include/net/esp.h index 90cd94f..eb53b58 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -31,7 +31,7 @@ struct esp_data u8 *work_icv; int icv_full_len; int icv_trunc_len; - void (*icv)(struct esp_data*, + int (*icv)(struct esp_data*, struct sk_buff *skb, int offset, int len, u8 *icv); struct crypto_tfm *tfm; @@ -42,7 +42,7 @@ extern int skb_to_sgvec(struct sk_buff * extern int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer); extern void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len); -static inline void +static inline int esp_hmac_digest(struct esp_data *esp, struct sk_buff *skb, int offset, int len, u8 *auth_data) { @@ -54,6 +54,30 @@ esp_hmac_digest(struct esp_data *esp, st skb_icv_walk(skb, tfm, offset, len, crypto_hmac_update); crypto_hmac_final(tfm, esp->auth.key, &esp->auth.key_len, icv); memcpy(auth_data, icv, esp->auth.icv_trunc_len); + + return 0; } +#ifdef CONFIG_CRYPTO_XCBC +static inline int +esp_xcbc_digest(struct esp_data *esp, struct sk_buff *skb, int offset, + int len, u8 *auth_data) +{ + struct crypto_tfm *tfm = esp->auth.tfm; + char *icv = esp->auth.work_icv; + int err = 0; + + memset(auth_data, 0, esp->auth.icv_trunc_len); + err = crypto_xcbc_init(tfm, esp->auth.key, esp->auth.key_len); + if (err != 0) + return err; + skb_icv_walk(skb, tfm, offset, len, crypto_xcbc_update); + err = crypto_xcbc_final(tfm, esp->auth.key, esp->auth.key_len, icv); + if (err != 0) + return err; + memcpy(auth_data, icv, esp->auth.icv_trunc_len); + + return 0; +} +#endif #endif diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index aed537f..853079a 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -97,7 +97,9 @@ static int ah_output(struct xfrm_state * ah->reserved = 0; ah->spi = x->id.spi; ah->seq_no = htonl(++x->replay.oseq); - ahp->icv(ahp, skb, ah->auth_data); + err = ahp->icv(ahp, skb, ah->auth_data); + if (err != 0) + goto error; top_iph->tos = iph->tos; top_iph->ttl = iph->ttl; @@ -122,6 +124,7 @@ static int ah_input(struct xfrm_state *x struct ip_auth_hdr *ah; struct ah_data *ahp; char work_buf[60]; + int err = -EINVAL; if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) goto out; @@ -164,7 +167,9 @@ static int ah_input(struct xfrm_state *x memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); skb_push(skb, skb->data - skb->nh.raw); - ahp->icv(ahp, skb, ah->auth_data); + err = ahp->icv(ahp, skb, ah->auth_data); + if (err != 0) + goto out; if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { x->stats.integrity_failed++; goto out; @@ -205,6 +210,8 @@ static int ah_init_state(struct xfrm_sta { struct ah_data *ahp = NULL; struct xfrm_algo_desc *aalg_desc; + unsigned int digestsize; + u32 mode = 0; if (!x->aalg) goto error; @@ -222,26 +229,37 @@ static int ah_init_state(struct xfrm_sta memset(ahp, 0, sizeof(*ahp)); + aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); + BUG_ON(!aalg_desc); + +#ifdef CONFIG_CRYPTO_XCBC + mode = aalg_desc->desc.sadb_alg_id == SADB_X_AALG_AES_XCBC_MAC ? + CRYPTO_TFM_MODE_CBC : 0; +#endif + ahp->key = x->aalg->alg_key; ahp->key_len = (x->aalg->alg_key_len+7)/8; - ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); + ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, mode); if (!ahp->tfm) goto error; +#ifdef CONFIG_CRYPTO_XCBC + ahp->icv = !mode ? ah_hmac_digest : ah_xcbc_digest; +#else ahp->icv = ah_hmac_digest; - +#endif + digestsize = !mode ? crypto_tfm_alg_digestsize(ahp->tfm) : + crypto_tfm_alg_blocksize(ahp->tfm); + /* * Lookup the algorithm description maintained by xfrm_algo, * verify crypto transform properties, and store information * we need for AH processing. This lookup cannot fail here * after a successful crypto_alloc_tfm(). */ - aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); - BUG_ON(!aalg_desc); - if (aalg_desc->uinfo.auth.icv_fullbits/8 != - crypto_tfm_alg_digestsize(ahp->tfm)) { + if (aalg_desc->uinfo.auth.icv_fullbits/8 != digestsize) { printk(KERN_INFO "AH: %s digestsize %u != %hu\n", - x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), + x->aalg->alg_name, digestsize, aalg_desc->uinfo.auth.icv_fullbits/8); goto error; } diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 73bfcae..78a709a 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -121,8 +121,10 @@ static int esp_output(struct xfrm_state } if (esp->auth.icv_full_len) { - esp->auth.icv(esp, skb, (u8*)esph-skb->data, + err = esp->auth.icv(esp, skb, (u8*)esph-skb->data, sizeof(struct ip_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); + if (err != 0) + goto error; pskb_put(skb, trailer, alen); } @@ -161,8 +163,9 @@ static int esp_input(struct xfrm_state * if (esp->auth.icv_full_len) { u8 sum[esp->auth.icv_full_len]; u8 sum1[alen]; - - esp->auth.icv(esp, skb, 0, skb->len-alen, sum); + + if ((esp->auth.icv(esp, skb, 0, skb->len-alen, sum)) != 0) + goto out; if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) BUG(); @@ -376,22 +379,34 @@ static int esp_init_state(struct xfrm_st if (x->aalg) { struct xfrm_algo_desc *aalg_desc; + unsigned int digestsize; + u32 mode = 0; + aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); + BUG_ON(!aalg_desc); + +#ifdef CONFIG_CRYPTO_XCBC + mode = aalg_desc->desc.sadb_alg_id == SADB_X_AALG_AES_XCBC_MAC ? + CRYPTO_TFM_MODE_CBC : 0; +#endif esp->auth.key = x->aalg->alg_key; esp->auth.key_len = (x->aalg->alg_key_len+7)/8; - esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); + esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, mode); if (esp->auth.tfm == NULL) goto error; +#ifdef CONFIG_CRYPTO_XCBC + esp->auth.icv = !mode ? esp_hmac_digest : esp_xcbc_digest; +#else esp->auth.icv = esp_hmac_digest; +#endif - aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); - BUG_ON(!aalg_desc); + digestsize = !mode ? crypto_tfm_alg_digestsize(esp->auth.tfm) : + crypto_tfm_alg_blocksize(esp->auth.tfm); - if (aalg_desc->uinfo.auth.icv_fullbits/8 != - crypto_tfm_alg_digestsize(esp->auth.tfm)) { + if (aalg_desc->uinfo.auth.icv_fullbits/8 != digestsize) { NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n", x->aalg->alg_name, - crypto_tfm_alg_digestsize(esp->auth.tfm), + digestsize, aalg_desc->uinfo.auth.icv_fullbits/8); goto error; } diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 13cc7f8..700f25e 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -343,6 +343,8 @@ static int ah6_init_state(struct xfrm_st { struct ah_data *ahp = NULL; struct xfrm_algo_desc *aalg_desc; + unsigned int digestsize; + u32 mode = 0; if (!x->aalg) goto error; @@ -360,12 +362,28 @@ static int ah6_init_state(struct xfrm_st memset(ahp, 0, sizeof(*ahp)); + aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); + BUG_ON(!aalg_desc); + +#ifdef CONFIG_CRYPTO_XCBC + mode = aalg_desc->desc.sadb_alg_id == SADB_X_AALG_AES_XCBC_MAC ? + CRYPTO_TFM_MODE_CBC : 0; +#endif + printk(KERN_DEBUG "%s(x=%p) mode=%u\n", __FUNCTION__, x, mode); ahp->key = x->aalg->alg_key; ahp->key_len = (x->aalg->alg_key_len+7)/8; - ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); + ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, mode); if (!ahp->tfm) goto error; +#ifdef CONFIG_CRYPTO_XCBC + ahp->icv = !mode ? ah_hmac_digest : ah_xcbc_digest; +#else ahp->icv = ah_hmac_digest; +#endif + + + digestsize = !mode ? crypto_tfm_alg_digestsize(ahp->tfm) : + crypto_tfm_alg_blocksize(ahp->tfm); /* * Lookup the algorithm description maintained by xfrm_algo, @@ -373,13 +391,9 @@ static int ah6_init_state(struct xfrm_st * we need for AH processing. This lookup cannot fail here * after a successful crypto_alloc_tfm(). */ - aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); - BUG_ON(!aalg_desc); - - if (aalg_desc->uinfo.auth.icv_fullbits/8 != - crypto_tfm_alg_digestsize(ahp->tfm)) { + if (aalg_desc->uinfo.auth.icv_fullbits/8 != digestsize) { printk(KERN_INFO "AH: %s digestsize %u != %hu\n", - x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), + x->aalg->alg_name, digestsize, aalg_desc->uinfo.auth.icv_fullbits/8); goto error; } diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 6de8ee1..4c21a0b 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -313,22 +313,34 @@ static int esp6_init_state(struct xfrm_s if (x->aalg) { struct xfrm_algo_desc *aalg_desc; + unsigned int digestsize; + u32 mode = 0; + + aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); + BUG_ON(!aalg_desc); + +#ifdef CONFIG_CRYPTO_XCBC + mode = aalg_desc->desc.sadb_alg_id == SADB_X_AALG_AES_XCBC_MAC ? + CRYPTO_TFM_MODE_CBC : 0; +#endif esp->auth.key = x->aalg->alg_key; esp->auth.key_len = (x->aalg->alg_key_len+7)/8; - esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); + esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, mode); if (esp->auth.tfm == NULL) goto error; +#ifdef CONFIG_CRYPTO_XCBC + esp->auth.icv = !mode ? esp_hmac_digest : esp_xcbc_digest; +#else esp->auth.icv = esp_hmac_digest; - - aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); - BUG_ON(!aalg_desc); - - if (aalg_desc->uinfo.auth.icv_fullbits/8 != - crypto_tfm_alg_digestsize(esp->auth.tfm)) { +#endif + + digestsize = !mode ? crypto_tfm_alg_digestsize(esp->auth.tfm) : + crypto_tfm_alg_blocksize(esp->auth.tfm); + + if (aalg_desc->uinfo.auth.icv_fullbits/8 != digestsize) { printk(KERN_INFO "ESP: %s digestsize %u != %hu\n", - x->aalg->alg_name, - crypto_tfm_alg_digestsize(esp->auth.tfm), + x->aalg->alg_name, digestsize, aalg_desc->uinfo.auth.icv_fullbits/8); goto error; } diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 6ed3302..0d19222 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -115,6 +115,25 @@ static struct xfrm_algo_desc aalg_list[] .sadb_alg_maxbits = 160 } }, +#ifdef CONFIG_CRYPTO_XCBC +{ + .name = "aes", + + .uinfo = { + .auth = { + .icv_truncbits = 96, + .icv_fullbits = 128, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_AALG_AES_XCBC_MAC, + .sadb_alg_ivlen = 0, + .sadb_alg_minbits = 128, + .sadb_alg_maxbits = 128 + } +}, +#endif }; static struct xfrm_algo_desc ealg_list[] = {