crypto: qce - Schedule fallback aead algorithm
authorThara Gopinath <thara.gopinath@linaro.org>
Thu, 29 Apr 2021 15:07:07 +0000 (11:07 -0400)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 14 May 2021 11:07:56 +0000 (19:07 +0800)
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 <thara.gopinath@linaro.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/qce/aead.c
drivers/crypto/qce/aead.h

index ef66ae2..6d06a19 100644 (file)
@@ -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);
        }
 
        /*
@@ -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;
@@ -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)
@@ -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;
@@ -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)
@@ -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;
@@ -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;
index 3d1f203..efb8477 100644 (file)
@@ -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 {
@@ -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)