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[] = {