Skip to contentSkip to conversation

crypto: algif_aead, ccm - stabilize IV handling for async CCM requests

PATCH In review Ren Wei 2 participants 2 messages Apr 18 1 message not in the archive Crypto API

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

Ren Wei

author
#1 lore raw

PATCH 1/1 crypto: algif_aead, ccm - stabilize IV handling for async CCM requests

From: Douya Le <[email protected]>

AF_ALG AEAD AIO requests currently use the socket-wide IV buffer during request processing. For async CCM requests, later socket activity can update that shared state before the original request has fully completed, which can lead to inconsistent IV handling.

Fix this in two places:

- snapshot the IV into per-request storage in algif_aead before submitting an async AEAD operation, so in-flight requests no longer depend on mutable socket state;
- make CCM keep a private IV copy for authentication, separate from the working IV that is consumed by the CTR walk.

Together these changes make async CCM IV handling stable without changing normal AF_ALG or CCM behaviour.

---
 crypto/algif_aead.c | 10 ++++++++--
 crypto/ccm.c        | 19 ++++++++++++-------
 2 files changed, 20 insertions(+), 9 deletions(-)
crypto/algif_aead.c +8 -2
index f8bd45f7dc83..cb651ab58d62 100644
@@ -72,8 +72,10 @@
 	struct af_alg_ctx *ctx = ask->private;
 	struct crypto_aead *tfm = pask->private;
 	unsigned int as = crypto_aead_authsize(tfm);
+	unsigned int ivsize = crypto_aead_ivsize(tfm);
 	struct af_alg_async_req *areq;
 	struct scatterlist *rsgl_src, *tsgl_src = NULL;
+	void *iv;
 	int err = 0;
 	size_t used = 0;		/* [in]  TX bufs to be en/decrypted */
 	size_t outlen = 0;		/* [out] RX bufs produced by kernel */
@@ -125,10 +127,14 @@
 
 	/* Allocate cipher request for current operation. */
 	areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) +
-				     crypto_aead_reqsize(tfm));
+				     crypto_aead_reqsize(tfm) + ivsize);
 	if (IS_ERR(areq))
 		return PTR_ERR(areq);
 
+	iv = (u8 *)aead_request_ctx(&areq->cra_u.aead_req) +
+	     crypto_aead_reqsize(tfm);
+	memcpy(iv, ctx->iv, ivsize);
+
 	/* convert iovecs of output buffers into RX SGL */
 	err = af_alg_get_rsgl(sk, msg, flags, areq, outlen, &usedpages);
 	if (err)
@@ -187,7 +193,7 @@
 
 	/* Initialize the crypto operation */
 	aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src,
-			       areq->first_rsgl.sgl.sgt.sgl, used, ctx->iv);
+			       areq->first_rsgl.sgl.sgt.sgl, used, iv);
 	aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen);
 	aead_request_set_tfm(&areq->cra_u.aead_req, tfm);
 
crypto/ccm.c +12 -7
index 2ae929ffdef8..d409324dec29 100644
@@ -42,6 +42,7 @@
 	u8 odata[16];
 	u8 idata[16];
 	u8 auth_tag[16];
+	u8 iv[16];
 	u32 flags;
 	struct scatterlist src[3];
 	struct scatterlist dst[3];
@@ -121,17 +122,17 @@
 	return 0;
 }
 
-static int format_input(u8 *info, struct aead_request *req,
+static int format_input(u8 *info, const u8 *iv, struct aead_request *req,
 			unsigned int cryptlen)
 {
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
-	unsigned int lp = req->iv[0];
+	unsigned int lp = iv[0];
 	unsigned int l = lp + 1;
 	unsigned int m;
 
 	m = crypto_aead_authsize(aead);
 
-	memcpy(info, req->iv, 16);
+	memcpy(info, iv, 16);
 
 	/* format control info per RFC 3610 and
 	 * NIST Special Publication 800-38C
@@ -176,7 +177,7 @@
 	int ilen, err;
 
 	/* format control data for input */
-	err = format_input(odata, req, cryptlen);
+	err = format_input(odata, pctx->iv, req, cryptlen);
 	if (err)
 		goto out;
 
@@ -248,9 +249,11 @@
 {
 	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
 	struct scatterlist *sg;
-	u8 *iv = req->iv;
+	u8 *iv = pctx->iv;
 	int err;
 
+	memcpy(iv, req->iv, sizeof(pctx->iv));
+
 	err = crypto_ccm_check_iv(iv);
 	if (err)
 		return err;
@@ -288,7 +291,7 @@
 	struct scatterlist *dst;
 	unsigned int cryptlen = req->cryptlen;
 	u8 *odata = pctx->odata;
-	u8 *iv = req->iv;
+	u8 *iv = pctx->idata;
 	int err;
 
 	err = crypto_ccm_init_crypt(req, odata);
@@ -303,6 +306,8 @@
 	if (req->src != req->dst)
 		dst = pctx->dst;
 
+	memcpy(iv, pctx->iv, 16);
+
 	skcipher_request_set_tfm(skreq, ctx->ctr);
 	skcipher_request_set_callback(skreq, pctx->flags,
 				      crypto_ccm_encrypt_done, req);
@@ -365,7 +370,7 @@
 	if (req->src != req->dst)
 		dst = pctx->dst;
 
-	memcpy(iv, req->iv, 16);
+	memcpy(iv, pctx->iv, 16);
 
 	skcipher_request_set_tfm(skreq, ctx->ctr);
 	skcipher_request_set_callback(skreq, pctx->flags,

--
2.43.0

maintainer
#2 lore raw
Quoted 29 lines · Ren Wei

From: Douya Le <[email protected]>

AF_ALG AEAD AIO requests currently use the socket-wide IV buffer during request processing. For async CCM requests, later socket activity can update that shared state before the original request has fully completed, which can lead to inconsistent IV handling.

Fix this in two places:

- snapshot the IV into per-request storage in algif_aead before submitting an async AEAD operation, so in-flight requests no longer depend on mutable socket state;
- make CCM keep a private IV copy for authentication, separate from the working IV that is consumed by the CTR walk.

Together these changes make async CCM IV handling stable without changing normal AF_ALG or CCM behaviour.

Quoted 4 lines
---
 crypto/algif_aead.c | 10 ++++++++--
 crypto/ccm.c        | 19 ++++++++++++-------
 2 files changed, 20 insertions(+), 9 deletions(-)

Thanks, your fix looks good to me. But please split into two patches.

Thanks,

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt