]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
crypto: hisilicon/sec2 - fix for aead invalid authsize
authorWenkai Lin <linwenkai6@hisilicon.com>
Fri, 13 Dec 2024 09:13:35 +0000 (17:13 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Sat, 21 Dec 2024 14:46:24 +0000 (22:46 +0800)
When the digest alg is HMAC-SHAx or another, the authsize may be less
than 4 bytes and mac_len of the BD is set to zero, the hardware considers
it a BD configuration error and reports a ras error, so the sec driver
needs to switch to software calculation in this case, this patch add a
check for it and remove unnecessary check that has been done by crypto.

Fixes: 2f072d75d1ab ("crypto: hisilicon - Add aead support on SEC2")
Signed-off-by: Wenkai Lin <linwenkai6@hisilicon.com>
Signed-off-by: Chenghai Huang <huangchenghai2@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/hisilicon/sec2/sec.h
drivers/crypto/hisilicon/sec2/sec_crypto.c

index 70c3bdedb6baf65d75743a76849b9e631aa92b26..4b99702308228717731969933055bf5f39b09925 100644 (file)
@@ -37,6 +37,7 @@ struct sec_aead_req {
        u8 *a_ivin;
        dma_addr_t a_ivin_dma;
        struct aead_request *aead_req;
+       bool fallback;
 };
 
 /* SEC request of Crypto */
@@ -91,7 +92,6 @@ struct sec_auth_ctx {
        u8 *a_key;
        u8 a_key_len;
        u8 a_alg;
-       bool fallback;
        struct crypto_shash *hash_tfm;
        struct crypto_aead *fallback_aead_tfm;
 };
index 8db995279545cdee3869643a936119b0978a3b9c..66bc07da9eb6f7ae3983991505f3f954219c4e31 100644 (file)
@@ -1119,10 +1119,7 @@ static int sec_aead_setauthsize(struct crypto_aead *aead, unsigned int authsize)
        struct sec_ctx *ctx = crypto_tfm_ctx(tfm);
        struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
 
-       if (unlikely(a_ctx->fallback_aead_tfm))
-               return crypto_aead_setauthsize(a_ctx->fallback_aead_tfm, authsize);
-
-       return 0;
+       return crypto_aead_setauthsize(a_ctx->fallback_aead_tfm, authsize);
 }
 
 static int sec_aead_fallback_setkey(struct sec_auth_ctx *a_ctx,
@@ -1159,13 +1156,7 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
                }
                memcpy(c_ctx->c_key, key, keylen);
 
-               if (unlikely(a_ctx->fallback_aead_tfm)) {
-                       ret = sec_aead_fallback_setkey(a_ctx, tfm, key, keylen);
-                       if (ret)
-                               return ret;
-               }
-
-               return 0;
+               return sec_aead_fallback_setkey(a_ctx, tfm, key, keylen);
        }
 
        ret = crypto_authenc_extractkeys(&keys, key, keylen);
@@ -1190,6 +1181,12 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
                goto bad_key;
        }
 
+       ret = sec_aead_fallback_setkey(a_ctx, tfm, key, keylen);
+       if (ret) {
+               dev_err(dev, "set sec fallback key err!\n");
+               goto bad_key;
+       }
+
        return 0;
 
 bad_key:
@@ -1917,8 +1914,10 @@ static void sec_aead_exit(struct crypto_aead *tfm)
 
 static int sec_aead_ctx_init(struct crypto_aead *tfm, const char *hash_name)
 {
+       struct aead_alg *alg = crypto_aead_alg(tfm);
        struct sec_ctx *ctx = crypto_aead_ctx(tfm);
-       struct sec_auth_ctx *auth_ctx = &ctx->a_ctx;
+       struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+       const char *aead_name = alg->base.cra_name;
        int ret;
 
        ret = sec_aead_init(tfm);
@@ -1927,11 +1926,20 @@ static int sec_aead_ctx_init(struct crypto_aead *tfm, const char *hash_name)
                return ret;
        }
 
-       auth_ctx->hash_tfm = crypto_alloc_shash(hash_name, 0, 0);
-       if (IS_ERR(auth_ctx->hash_tfm)) {
+       a_ctx->hash_tfm = crypto_alloc_shash(hash_name, 0, 0);
+       if (IS_ERR(a_ctx->hash_tfm)) {
                dev_err(ctx->dev, "aead alloc shash error!\n");
                sec_aead_exit(tfm);
-               return PTR_ERR(auth_ctx->hash_tfm);
+               return PTR_ERR(a_ctx->hash_tfm);
+       }
+
+       a_ctx->fallback_aead_tfm = crypto_alloc_aead(aead_name, 0,
+                                                    CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_ASYNC);
+       if (IS_ERR(a_ctx->fallback_aead_tfm)) {
+               dev_err(ctx->dev, "aead driver alloc fallback tfm error!\n");
+               crypto_free_shash(ctx->a_ctx.hash_tfm);
+               sec_aead_exit(tfm);
+               return PTR_ERR(a_ctx->fallback_aead_tfm);
        }
 
        return 0;
@@ -1941,6 +1949,7 @@ static void sec_aead_ctx_exit(struct crypto_aead *tfm)
 {
        struct sec_ctx *ctx = crypto_aead_ctx(tfm);
 
+       crypto_free_aead(ctx->a_ctx.fallback_aead_tfm);
        crypto_free_shash(ctx->a_ctx.hash_tfm);
        sec_aead_exit(tfm);
 }
@@ -1967,7 +1976,6 @@ static int sec_aead_xcm_ctx_init(struct crypto_aead *tfm)
                sec_aead_exit(tfm);
                return PTR_ERR(a_ctx->fallback_aead_tfm);
        }
-       a_ctx->fallback = false;
 
        return 0;
 }
@@ -2226,15 +2234,15 @@ static int sec_aead_spec_check(struct sec_ctx *ctx, struct sec_req *sreq)
        struct device *dev = ctx->dev;
        int ret;
 
-       if (unlikely(req->cryptlen + req->assoclen > MAX_INPUT_DATA_LEN ||
-           req->assoclen > SEC_MAX_AAD_LEN)) {
-               dev_err(dev, "aead input spec error!\n");
+       /* Hardware does not handle cases where authsize is less than 4 bytes */
+       if (unlikely(sz < MIN_MAC_LEN)) {
+               sreq->aead_req.fallback = true;
                return -EINVAL;
        }
 
-       if (unlikely((c_mode == SEC_CMODE_GCM && sz < DES_BLOCK_SIZE) ||
-                    (c_mode == SEC_CMODE_CCM && (sz < MIN_MAC_LEN || sz & MAC_LEN_MASK)))) {
-               dev_err(dev, "aead input mac length error!\n");
+       if (unlikely(req->cryptlen + req->assoclen > MAX_INPUT_DATA_LEN ||
+           req->assoclen > SEC_MAX_AAD_LEN)) {
+               dev_err(dev, "aead input spec error!\n");
                return -EINVAL;
        }
 
@@ -2280,7 +2288,7 @@ static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
        if (ctx->sec->qm.ver == QM_HW_V2) {
                if (unlikely(!req->cryptlen || (!sreq->c_req.encrypt &&
                             req->cryptlen <= authsize))) {
-                       ctx->a_ctx.fallback = true;
+                       sreq->aead_req.fallback = true;
                        return -EINVAL;
                }
        }
@@ -2308,16 +2316,9 @@ static int sec_aead_soft_crypto(struct sec_ctx *ctx,
                                bool encrypt)
 {
        struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
-       struct device *dev = ctx->dev;
        struct aead_request *subreq;
        int ret;
 
-       /* Kunpeng920 aead mode not support input 0 size */
-       if (!a_ctx->fallback_aead_tfm) {
-               dev_err(dev, "aead fallback tfm is NULL!\n");
-               return -EINVAL;
-       }
-
        subreq = aead_request_alloc(a_ctx->fallback_aead_tfm, GFP_KERNEL);
        if (!subreq)
                return -ENOMEM;
@@ -2349,10 +2350,11 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt)
        req->aead_req.aead_req = a_req;
        req->c_req.encrypt = encrypt;
        req->ctx = ctx;
+       req->aead_req.fallback = false;
 
        ret = sec_aead_param_check(ctx, req);
        if (unlikely(ret)) {
-               if (ctx->a_ctx.fallback)
+               if (req->aead_req.fallback)
                        return sec_aead_soft_crypto(ctx, a_req, encrypt);
                return -EINVAL;
        }