Commit 9112ff5e authored by Wenkai Lin's avatar Wenkai Lin Committed by Weili Qian
Browse files

crypto: hisilicon/sec2 - fix for aead invalid authsize

driver inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IBATCK


CVE: NA

----------------------------------------------------------------------

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: 2f072d75 ("crypto: hisilicon - Add aead support on SEC2")
Signed-off-by: default avatarWenkai Lin <linwenkai6@hisilicon.com>
Signed-off-by: default avatarJiangShui Yang <yangjiangshui@h-partners.com>
parent d71a71d7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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 */
@@ -90,7 +91,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;
};
+33 −31
Original line number Diff line number Diff line
@@ -1118,10 +1118,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;
}

static int sec_aead_fallback_setkey(struct sec_auth_ctx *a_ctx,
@@ -1158,13 +1155,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);
@@ -1189,6 +1180,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:
@@ -1882,8 +1879,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);
@@ -1892,11 +1891,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;
@@ -1906,6 +1914,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);
}
@@ -1932,7 +1941,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;
}
@@ -2192,15 +2200,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;
	}

@@ -2246,7 +2254,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;
		}
	}
@@ -2274,16 +2282,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;
@@ -2310,6 +2311,7 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt)
	struct sec_req *req = aead_request_ctx(a_req);
	struct sec_ctx *ctx = crypto_aead_ctx(tfm);
	int ret;
	req->aead_req.fallback = false;

	req->flag = a_req->base.flags;
	req->aead_req.aead_req = a_req;
@@ -2319,7 +2321,7 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt)

	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;
	}