Skip to content

Commit

Permalink
esp4: Add support for IPsec extended sequence numbers
Browse files Browse the repository at this point in the history
This patch adds IPsec extended sequence numbers support to esp4.
We use the authencesn crypto algorithm to handle esp with separate
encryption/authentication algorithms.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Steffen Klassert authored and David S. Miller committed Mar 14, 2011
1 parent 1ce3644 commit 0dc49e9
Showing 1 changed file with 82 additions and 18 deletions.
100 changes: 82 additions & 18 deletions net/ipv4/esp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@ static u32 esp4_get_mtu(struct xfrm_state *x, int mtu);
*
* TODO: Use spare space in skb for this where possible.
*/
static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags)
static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int seqhilen)
{
unsigned int len;

len = crypto_aead_ivsize(aead);
len = seqhilen;

len += crypto_aead_ivsize(aead);

if (len) {
len += crypto_aead_alignmask(aead) &
~(crypto_tfm_ctx_alignment() - 1);
Expand All @@ -52,10 +55,15 @@ static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags)
return kmalloc(len, GFP_ATOMIC);
}

static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp)
static inline __be32 *esp_tmp_seqhi(void *tmp)
{
return PTR_ALIGN((__be32 *)tmp, __alignof__(__be32));
}
static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp, int seqhilen)
{
return crypto_aead_ivsize(aead) ?
PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp;
PTR_ALIGN((u8 *)tmp + seqhilen,
crypto_aead_alignmask(aead) + 1) : tmp + seqhilen;
}

static inline struct aead_givcrypt_request *esp_tmp_givreq(
Expand Down Expand Up @@ -122,6 +130,10 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
int plen;
int tfclen;
int nfrags;
int assoclen;
int sglists;
int seqhilen;
__be32 *seqhi;

/* skb is pure payload to encrypt */

Expand Down Expand Up @@ -151,14 +163,25 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
goto error;
nfrags = err;

tmp = esp_alloc_tmp(aead, nfrags + 1);
assoclen = sizeof(*esph);
sglists = 1;
seqhilen = 0;

if (x->props.flags & XFRM_STATE_ESN) {
sglists += 2;
seqhilen += sizeof(__be32);
assoclen += seqhilen;
}

tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
if (!tmp)
goto error;

iv = esp_tmp_iv(aead, tmp);
seqhi = esp_tmp_seqhi(tmp);
iv = esp_tmp_iv(aead, tmp, seqhilen);
req = esp_tmp_givreq(aead, iv);
asg = esp_givreq_sg(aead, req);
sg = asg + 1;
sg = asg + sglists;

/* Fill padding... */
tail = skb_tail_pointer(trailer);
Expand Down Expand Up @@ -221,11 +244,19 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
skb_to_sgvec(skb, sg,
esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
clen + alen);
sg_init_one(asg, esph, sizeof(*esph));

if ((x->props.flags & XFRM_STATE_ESN)) {
sg_init_table(asg, 3);
sg_set_buf(asg, &esph->spi, sizeof(__be32));
*seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
sg_set_buf(asg + 1, seqhi, seqhilen);
sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32));
} else
sg_init_one(asg, esph, sizeof(*esph));

aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
aead_givcrypt_set_assoc(req, asg, sizeof(*esph));
aead_givcrypt_set_assoc(req, asg, assoclen);
aead_givcrypt_set_giv(req, esph->enc_data,
XFRM_SKB_CB(skb)->seq.output.low);

Expand Down Expand Up @@ -346,6 +377,10 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
struct sk_buff *trailer;
int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead);
int nfrags;
int assoclen;
int sglists;
int seqhilen;
__be32 *seqhi;
void *tmp;
u8 *iv;
struct scatterlist *sg;
Expand All @@ -362,16 +397,27 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
goto out;
nfrags = err;

assoclen = sizeof(*esph);
sglists = 1;
seqhilen = 0;

if (x->props.flags & XFRM_STATE_ESN) {
sglists += 2;
seqhilen += sizeof(__be32);
assoclen += seqhilen;
}

err = -ENOMEM;
tmp = esp_alloc_tmp(aead, nfrags + 1);
tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
if (!tmp)
goto out;

ESP_SKB_CB(skb)->tmp = tmp;
iv = esp_tmp_iv(aead, tmp);
seqhi = esp_tmp_seqhi(tmp);
iv = esp_tmp_iv(aead, tmp, seqhilen);
req = esp_tmp_req(aead, iv);
asg = esp_req_sg(aead, req);
sg = asg + 1;
sg = asg + sglists;

skb->ip_summed = CHECKSUM_NONE;

Expand All @@ -382,11 +428,19 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)

sg_init_table(sg, nfrags);
skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
sg_init_one(asg, esph, sizeof(*esph));

if ((x->props.flags & XFRM_STATE_ESN)) {
sg_init_table(asg, 3);
sg_set_buf(asg, &esph->spi, sizeof(__be32));
*seqhi = XFRM_SKB_CB(skb)->seq.input.hi;
sg_set_buf(asg + 1, seqhi, seqhilen);
sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32));
} else
sg_init_one(asg, esph, sizeof(*esph));

aead_request_set_callback(req, 0, esp_input_done, skb);
aead_request_set_crypt(req, sg, sg, elen, iv);
aead_request_set_assoc(req, asg, sizeof(*esph));
aead_request_set_assoc(req, asg, assoclen);

err = crypto_aead_decrypt(req);
if (err == -EINPROGRESS)
Expand Down Expand Up @@ -500,10 +554,20 @@ static int esp_init_authenc(struct xfrm_state *x)
goto error;

err = -ENAMETOOLONG;
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
goto error;

if ((x->props.flags & XFRM_STATE_ESN)) {
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
"authencesn(%s,%s)",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
goto error;
} else {
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
"authenc(%s,%s)",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
goto error;
}

aead = crypto_alloc_aead(authenc_name, 0, 0);
err = PTR_ERR(aead);
Expand Down

0 comments on commit 0dc49e9

Please sign in to comment.