Skip to content

Commit

Permalink
crypto: qce - Schedule fallback aead algorithm
Browse files Browse the repository at this point in the history
Qualcomm crypto engine does not handle the following scenarios and
will issue an abort. In such cases, pass on the transformation to
a fallback algorithm.

- DES3 algorithms with all three keys same.
- AES192 algorithms.
- 0 length messages.

Signed-off-by: Thara Gopinath <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
tharagopinath authored and herbertx committed May 14, 2021
1 parent db0018a commit b51dcf0
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 11 deletions.
64 changes: 53 additions & 11 deletions drivers/crypto/qce/aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,23 @@ static int qce_aead_crypt(struct aead_request *req, int encrypt)
/* CE does not handle 0 length messages */
if (!rctx->cryptlen) {
if (!(IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags)))
return -EINVAL;
ctx->need_fallback = true;
}

/* If fallback is needed, schedule and exit */
if (ctx->need_fallback) {
/* Reset need_fallback in case the same ctx is used for another transaction */
ctx->need_fallback = false;

aead_request_set_tfm(&rctx->fallback_req, ctx->fallback);
aead_request_set_callback(&rctx->fallback_req, req->base.flags,
req->base.complete, req->base.data);
aead_request_set_crypt(&rctx->fallback_req, req->src,
req->dst, req->cryptlen, req->iv);
aead_request_set_ad(&rctx->fallback_req, req->assoclen);

return encrypt ? crypto_aead_encrypt(&rctx->fallback_req) :
crypto_aead_decrypt(&rctx->fallback_req);
}

/*
Expand Down Expand Up @@ -553,7 +569,7 @@ static int qce_aead_ccm_setkey(struct crypto_aead *tfm, const u8 *key,
memcpy(ctx->ccm4309_salt, key + keylen, QCE_CCM4309_SALT_SIZE);
}

if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256)
if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256 && keylen != AES_KEYSIZE_192)
return -EINVAL;

ctx->enc_keylen = keylen;
Expand All @@ -562,7 +578,12 @@ static int qce_aead_ccm_setkey(struct crypto_aead *tfm, const u8 *key,
memcpy(ctx->enc_key, key, keylen);
memcpy(ctx->auth_key, key, keylen);

return 0;
if (keylen == AES_KEYSIZE_192)
ctx->need_fallback = true;

return IS_CCM_RFC4309(flags) ?
crypto_aead_setkey(ctx->fallback, key, keylen + QCE_CCM4309_SALT_SIZE) :
crypto_aead_setkey(ctx->fallback, key, keylen);
}

static int qce_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
Expand Down Expand Up @@ -593,20 +614,21 @@ static int qce_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int
* The crypto engine does not support any two keys
* being the same for triple des algorithms. The
* verify_skcipher_des3_key does not check for all the
* below conditions. Return -EINVAL in case any two keys
* are the same. Revisit to see if a fallback cipher
* is needed to handle this condition.
* below conditions. Schedule fallback in this case.
*/
memcpy(_key, authenc_keys.enckey, DES3_EDE_KEY_SIZE);
if (!((_key[0] ^ _key[2]) | (_key[1] ^ _key[3])) ||
!((_key[2] ^ _key[4]) | (_key[3] ^ _key[5])) ||
!((_key[0] ^ _key[4]) | (_key[1] ^ _key[5])))
return -EINVAL;
ctx->need_fallback = true;
} else if (IS_AES(flags)) {
/* No random key sizes */
if (authenc_keys.enckeylen != AES_KEYSIZE_128 &&
authenc_keys.enckeylen != AES_KEYSIZE_192 &&
authenc_keys.enckeylen != AES_KEYSIZE_256)
return -EINVAL;
if (authenc_keys.enckeylen == AES_KEYSIZE_192)
ctx->need_fallback = true;
}

ctx->enc_keylen = authenc_keys.enckeylen;
Expand All @@ -617,7 +639,7 @@ static int qce_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int
memset(ctx->auth_key, 0, sizeof(ctx->auth_key));
memcpy(ctx->auth_key, authenc_keys.authkey, authenc_keys.authkeylen);

return 0;
return crypto_aead_setkey(ctx->fallback, key, keylen);
}

static int qce_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
Expand All @@ -632,15 +654,33 @@ static int qce_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
return -EINVAL;
}
ctx->authsize = authsize;
return 0;

return crypto_aead_setauthsize(ctx->fallback, authsize);
}

static int qce_aead_init(struct crypto_aead *tfm)
{
crypto_aead_set_reqsize(tfm, sizeof(struct qce_aead_reqctx));
struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);

ctx->need_fallback = false;
ctx->fallback = crypto_alloc_aead(crypto_tfm_alg_name(&tfm->base),
0, CRYPTO_ALG_NEED_FALLBACK);

if (IS_ERR(ctx->fallback))
return PTR_ERR(ctx->fallback);

crypto_aead_set_reqsize(tfm, sizeof(struct qce_aead_reqctx) +
crypto_aead_reqsize(ctx->fallback));
return 0;
}

static void qce_aead_exit(struct crypto_aead *tfm)
{
struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);

crypto_free_aead(ctx->fallback);
}

struct qce_aead_def {
unsigned long flags;
const char *name;
Expand Down Expand Up @@ -738,11 +778,13 @@ static int qce_aead_register_one(const struct qce_aead_def *def, struct qce_devi
alg->encrypt = qce_aead_encrypt;
alg->decrypt = qce_aead_decrypt;
alg->init = qce_aead_init;
alg->exit = qce_aead_exit;

alg->base.cra_priority = 300;
alg->base.cra_flags = CRYPTO_ALG_ASYNC |
CRYPTO_ALG_ALLOCATES_MEMORY |
CRYPTO_ALG_KERN_DRIVER_ONLY;
CRYPTO_ALG_KERN_DRIVER_ONLY |
CRYPTO_ALG_NEED_FALLBACK;
alg->base.cra_ctxsize = sizeof(struct qce_aead_ctx);
alg->base.cra_alignmask = 0;
alg->base.cra_module = THIS_MODULE;
Expand Down
3 changes: 3 additions & 0 deletions drivers/crypto/qce/aead.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ struct qce_aead_ctx {
unsigned int enc_keylen;
unsigned int auth_keylen;
unsigned int authsize;
bool need_fallback;
struct crypto_aead *fallback;
};

struct qce_aead_reqctx {
Expand All @@ -39,6 +41,7 @@ struct qce_aead_reqctx {
u8 ccm_nonce[QCE_MAX_NONCE];
u8 ccmresult_buf[QCE_BAM_BURST_SIZE];
u8 ccm_rfc4309_iv[QCE_MAX_IV_SIZE];
struct aead_request fallback_req;
};

static inline struct qce_alg_template *to_aead_tmpl(struct crypto_aead *tfm)
Expand Down

0 comments on commit b51dcf0

Please sign in to comment.