Re: [PATCH] crypto: testmgr - test the shash API

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 28 May 2019 at 18:42, Eric Biggers <ebiggers@xxxxxxxxxx> wrote:
>
> From: Eric Biggers <ebiggers@xxxxxxxxxx>
>
> For hash algorithms implemented using the "shash" algorithm type, test
> both the ahash and shash APIs, not just the ahash API.
>
> Testing the ahash API already tests the shash API indirectly, which is
> normally good enough.  However, there have been corner cases where there
> have been shash bugs that don't get exposed through the ahash API.  So,
> update testmgr to test the shash API too.
>
> This would have detected the arm64 SHA-1 and SHA-2 bugs for which fixes
> were just sent out (https://patchwork.kernel.org/patch/10964843/ and
> https://patchwork.kernel.org/patch/10965089/):
>
>     alg: shash: sha1-ce test failed (wrong result) on test vector 0, cfg="init+finup aligned buffer"
>     alg: shash: sha224-ce test failed (wrong result) on test vector 0, cfg="init+finup aligned buffer"
>     alg: shash: sha256-ce test failed (wrong result) on test vector 0, cfg="init+finup aligned buffer"
>
> This also would have detected the bugs fixed by commit 307508d10729
> ("crypto: crct10dif-generic - fix use via crypto_shash_digest()") and
> commit dec3d0b1071a
> ("crypto: x86/crct10dif-pcl - fix use via crypto_shash_digest()").
>
> Signed-off-by: Eric Biggers <ebiggers@xxxxxxxxxx>

Acked-by: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>

> ---
>  crypto/testmgr.c | 402 +++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 335 insertions(+), 67 deletions(-)
>
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index c9e67c2bd7257..a347be1423239 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -1037,6 +1037,205 @@ static void crypto_reenable_simd_for_test(void)
>  }
>  #endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
>
> +static int build_hash_sglist(struct test_sglist *tsgl,
> +                            const struct hash_testvec *vec,
> +                            const struct testvec_config *cfg,
> +                            unsigned int alignmask,
> +                            const struct test_sg_division *divs[XBUFSIZE])
> +{
> +       struct kvec kv;
> +       struct iov_iter input;
> +
> +       kv.iov_base = (void *)vec->plaintext;
> +       kv.iov_len = vec->psize;
> +       iov_iter_kvec(&input, WRITE, &kv, 1, vec->psize);
> +       return build_test_sglist(tsgl, cfg->src_divs, alignmask, vec->psize,
> +                                &input, divs);
> +}
> +
> +static int check_hash_result(const char *type,
> +                            const u8 *result, unsigned int digestsize,
> +                            const struct hash_testvec *vec,
> +                            const char *vec_name,
> +                            const char *driver,
> +                            const struct testvec_config *cfg)
> +{
> +       if (memcmp(result, vec->digest, digestsize) != 0) {
> +               pr_err("alg: %s: %s test failed (wrong result) on test vector %s, cfg=\"%s\"\n",
> +                      type, driver, vec_name, cfg->name);
> +               return -EINVAL;
> +       }
> +       if (!testmgr_is_poison(&result[digestsize], TESTMGR_POISON_LEN)) {
> +               pr_err("alg: %s: %s overran result buffer on test vector %s, cfg=\"%s\"\n",
> +                      type, driver, vec_name, cfg->name);
> +               return -EOVERFLOW;
> +       }
> +       return 0;
> +}
> +
> +static inline int check_shash_op(const char *op, int err,
> +                                const char *driver, const char *vec_name,
> +                                const struct testvec_config *cfg)
> +{
> +       if (err)
> +               pr_err("alg: shash: %s %s() failed with err %d on test vector %s, cfg=\"%s\"\n",
> +                      driver, op, err, vec_name, cfg->name);
> +       return err;
> +}
> +
> +static inline const void *sg_data(struct scatterlist *sg)
> +{
> +       return page_address(sg_page(sg)) + sg->offset;
> +}
> +
> +/* Test one hash test vector in one configuration, using the shash API */
> +static int test_shash_vec_cfg(const char *driver,
> +                             const struct hash_testvec *vec,
> +                             const char *vec_name,
> +                             const struct testvec_config *cfg,
> +                             struct shash_desc *desc,
> +                             struct test_sglist *tsgl,
> +                             u8 *hashstate)
> +{
> +       struct crypto_shash *tfm = desc->tfm;
> +       const unsigned int alignmask = crypto_shash_alignmask(tfm);
> +       const unsigned int digestsize = crypto_shash_digestsize(tfm);
> +       const unsigned int statesize = crypto_shash_statesize(tfm);
> +       const struct test_sg_division *divs[XBUFSIZE];
> +       unsigned int i;
> +       u8 result[HASH_MAX_DIGESTSIZE + TESTMGR_POISON_LEN];
> +       int err;
> +
> +       /* Set the key, if specified */
> +       if (vec->ksize) {
> +               err = crypto_shash_setkey(tfm, vec->key, vec->ksize);
> +               if (err) {
> +                       if (err == vec->setkey_error)
> +                               return 0;
> +                       pr_err("alg: shash: %s setkey failed on test vector %s; expected_error=%d, actual_error=%d, flags=%#x\n",
> +                              driver, vec_name, vec->setkey_error, err,
> +                              crypto_shash_get_flags(tfm));
> +                       return err;
> +               }
> +               if (vec->setkey_error) {
> +                       pr_err("alg: shash: %s setkey unexpectedly succeeded on test vector %s; expected_error=%d\n",
> +                              driver, vec_name, vec->setkey_error);
> +                       return -EINVAL;
> +               }
> +       }
> +
> +       /* Build the scatterlist for the source data */
> +       err = build_hash_sglist(tsgl, vec, cfg, alignmask, divs);
> +       if (err) {
> +               pr_err("alg: shash: %s: error preparing scatterlist for test vector %s, cfg=\"%s\"\n",
> +                      driver, vec_name, cfg->name);
> +               return err;
> +       }
> +
> +       /* Do the actual hashing */
> +
> +       testmgr_poison(desc->__ctx, crypto_shash_descsize(tfm));
> +       testmgr_poison(result, digestsize + TESTMGR_POISON_LEN);
> +
> +       if (cfg->finalization_type == FINALIZATION_TYPE_DIGEST ||
> +           vec->digest_error) {
> +               /* Just using digest() */
> +               if (tsgl->nents != 1)
> +                       return 0;
> +               if (cfg->nosimd)
> +                       crypto_disable_simd_for_test();
> +               err = crypto_shash_digest(desc, sg_data(&tsgl->sgl[0]),
> +                                         tsgl->sgl[0].length, result);
> +               if (cfg->nosimd)
> +                       crypto_reenable_simd_for_test();
> +               if (err) {
> +                       if (err == vec->digest_error)
> +                               return 0;
> +                       pr_err("alg: shash: %s digest() failed on test vector %s; expected_error=%d, actual_error=%d, cfg=\"%s\"\n",
> +                              driver, vec_name, vec->digest_error, err,
> +                              cfg->name);
> +                       return err;
> +               }
> +               if (vec->digest_error) {
> +                       pr_err("alg: shash: %s digest() unexpectedly succeeded on test vector %s; expected_error=%d, cfg=\"%s\"\n",
> +                              driver, vec_name, vec->digest_error, cfg->name);
> +                       return -EINVAL;
> +               }
> +               goto result_ready;
> +       }
> +
> +       /* Using init(), zero or more update(), then final() or finup() */
> +
> +       if (cfg->nosimd)
> +               crypto_disable_simd_for_test();
> +       err = crypto_shash_init(desc);
> +       if (cfg->nosimd)
> +               crypto_reenable_simd_for_test();
> +       err = check_shash_op("init", err, driver, vec_name, cfg);
> +       if (err)
> +               return err;
> +
> +       for (i = 0; i < tsgl->nents; i++) {
> +               if (i + 1 == tsgl->nents &&
> +                   cfg->finalization_type == FINALIZATION_TYPE_FINUP) {
> +                       if (divs[i]->nosimd)
> +                               crypto_disable_simd_for_test();
> +                       err = crypto_shash_finup(desc, sg_data(&tsgl->sgl[i]),
> +                                                tsgl->sgl[i].length, result);
> +                       if (divs[i]->nosimd)
> +                               crypto_reenable_simd_for_test();
> +                       err = check_shash_op("finup", err, driver, vec_name,
> +                                            cfg);
> +                       if (err)
> +                               return err;
> +                       goto result_ready;
> +               }
> +               if (divs[i]->nosimd)
> +                       crypto_disable_simd_for_test();
> +               err = crypto_shash_update(desc, sg_data(&tsgl->sgl[i]),
> +                                         tsgl->sgl[i].length);
> +               if (divs[i]->nosimd)
> +                       crypto_reenable_simd_for_test();
> +               err = check_shash_op("update", err, driver, vec_name, cfg);
> +               if (err)
> +                       return err;
> +               if (divs[i]->flush_type == FLUSH_TYPE_REIMPORT) {
> +                       /* Test ->export() and ->import() */
> +                       testmgr_poison(hashstate + statesize,
> +                                      TESTMGR_POISON_LEN);
> +                       err = crypto_shash_export(desc, hashstate);
> +                       err = check_shash_op("export", err, driver, vec_name,
> +                                            cfg);
> +                       if (err)
> +                               return err;
> +                       if (!testmgr_is_poison(hashstate + statesize,
> +                                              TESTMGR_POISON_LEN)) {
> +                               pr_err("alg: shash: %s export() overran state buffer on test vector %s, cfg=\"%s\"\n",
> +                                      driver, vec_name, cfg->name);
> +                               return -EOVERFLOW;
> +                       }
> +                       testmgr_poison(desc->__ctx, crypto_shash_descsize(tfm));
> +                       err = crypto_shash_import(desc, hashstate);
> +                       err = check_shash_op("import", err, driver, vec_name,
> +                                            cfg);
> +                       if (err)
> +                               return err;
> +               }
> +       }
> +
> +       if (cfg->nosimd)
> +               crypto_disable_simd_for_test();
> +       err = crypto_shash_final(desc, result);
> +       if (cfg->nosimd)
> +               crypto_reenable_simd_for_test();
> +       err = check_shash_op("final", err, driver, vec_name, cfg);
> +       if (err)
> +               return err;
> +result_ready:
> +       return check_hash_result("shash", result, digestsize, vec, vec_name,
> +                                driver, cfg);
> +}
> +
>  static int do_ahash_op(int (*op)(struct ahash_request *req),
>                        struct ahash_request *req,
>                        struct crypto_wait *wait, bool nosimd)
> @@ -1054,31 +1253,32 @@ static int do_ahash_op(int (*op)(struct ahash_request *req),
>         return crypto_wait_req(err, wait);
>  }
>
> -static int check_nonfinal_hash_op(const char *op, int err,
> -                                 u8 *result, unsigned int digestsize,
> -                                 const char *driver, const char *vec_name,
> -                                 const struct testvec_config *cfg)
> +static int check_nonfinal_ahash_op(const char *op, int err,
> +                                  u8 *result, unsigned int digestsize,
> +                                  const char *driver, const char *vec_name,
> +                                  const struct testvec_config *cfg)
>  {
>         if (err) {
> -               pr_err("alg: hash: %s %s() failed with err %d on test vector %s, cfg=\"%s\"\n",
> +               pr_err("alg: ahash: %s %s() failed with err %d on test vector %s, cfg=\"%s\"\n",
>                        driver, op, err, vec_name, cfg->name);
>                 return err;
>         }
>         if (!testmgr_is_poison(result, digestsize)) {
> -               pr_err("alg: hash: %s %s() used result buffer on test vector %s, cfg=\"%s\"\n",
> +               pr_err("alg: ahash: %s %s() used result buffer on test vector %s, cfg=\"%s\"\n",
>                        driver, op, vec_name, cfg->name);
>                 return -EINVAL;
>         }
>         return 0;
>  }
>
> -static int test_hash_vec_cfg(const char *driver,
> -                            const struct hash_testvec *vec,
> -                            const char *vec_name,
> -                            const struct testvec_config *cfg,
> -                            struct ahash_request *req,
> -                            struct test_sglist *tsgl,
> -                            u8 *hashstate)
> +/* Test one hash test vector in one configuration, using the ahash API */
> +static int test_ahash_vec_cfg(const char *driver,
> +                             const struct hash_testvec *vec,
> +                             const char *vec_name,
> +                             const struct testvec_config *cfg,
> +                             struct ahash_request *req,
> +                             struct test_sglist *tsgl,
> +                             u8 *hashstate)
>  {
>         struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
>         const unsigned int alignmask = crypto_ahash_alignmask(tfm);
> @@ -1087,8 +1287,6 @@ static int test_hash_vec_cfg(const char *driver,
>         const u32 req_flags = CRYPTO_TFM_REQ_MAY_BACKLOG | cfg->req_flags;
>         const struct test_sg_division *divs[XBUFSIZE];
>         DECLARE_CRYPTO_WAIT(wait);
> -       struct kvec _input;
> -       struct iov_iter input;
>         unsigned int i;
>         struct scatterlist *pending_sgl;
>         unsigned int pending_len;
> @@ -1101,26 +1299,22 @@ static int test_hash_vec_cfg(const char *driver,
>                 if (err) {
>                         if (err == vec->setkey_error)
>                                 return 0;
> -                       pr_err("alg: hash: %s setkey failed on test vector %s; expected_error=%d, actual_error=%d, flags=%#x\n",
> +                       pr_err("alg: ahash: %s setkey failed on test vector %s; expected_error=%d, actual_error=%d, flags=%#x\n",
>                                driver, vec_name, vec->setkey_error, err,
>                                crypto_ahash_get_flags(tfm));
>                         return err;
>                 }
>                 if (vec->setkey_error) {
> -                       pr_err("alg: hash: %s setkey unexpectedly succeeded on test vector %s; expected_error=%d\n",
> +                       pr_err("alg: ahash: %s setkey unexpectedly succeeded on test vector %s; expected_error=%d\n",
>                                driver, vec_name, vec->setkey_error);
>                         return -EINVAL;
>                 }
>         }
>
>         /* Build the scatterlist for the source data */
> -       _input.iov_base = (void *)vec->plaintext;
> -       _input.iov_len = vec->psize;
> -       iov_iter_kvec(&input, WRITE, &_input, 1, vec->psize);
> -       err = build_test_sglist(tsgl, cfg->src_divs, alignmask, vec->psize,
> -                               &input, divs);
> +       err = build_hash_sglist(tsgl, vec, cfg, alignmask, divs);
>         if (err) {
> -               pr_err("alg: hash: %s: error preparing scatterlist for test vector %s, cfg=\"%s\"\n",
> +               pr_err("alg: ahash: %s: error preparing scatterlist for test vector %s, cfg=\"%s\"\n",
>                        driver, vec_name, cfg->name);
>                 return err;
>         }
> @@ -1140,13 +1334,13 @@ static int test_hash_vec_cfg(const char *driver,
>                 if (err) {
>                         if (err == vec->digest_error)
>                                 return 0;
> -                       pr_err("alg: hash: %s digest() failed on test vector %s; expected_error=%d, actual_error=%d, cfg=\"%s\"\n",
> +                       pr_err("alg: ahash: %s digest() failed on test vector %s; expected_error=%d, actual_error=%d, cfg=\"%s\"\n",
>                                driver, vec_name, vec->digest_error, err,
>                                cfg->name);
>                         return err;
>                 }
>                 if (vec->digest_error) {
> -                       pr_err("alg: hash: %s digest() unexpectedly succeeded on test vector %s; expected_error=%d, cfg=\"%s\"\n",
> +                       pr_err("alg: ahash: %s digest() unexpectedly succeeded on test vector %s; expected_error=%d, cfg=\"%s\"\n",
>                                driver, vec_name, vec->digest_error, cfg->name);
>                         return -EINVAL;
>                 }
> @@ -1158,8 +1352,8 @@ static int test_hash_vec_cfg(const char *driver,
>         ahash_request_set_callback(req, req_flags, crypto_req_done, &wait);
>         ahash_request_set_crypt(req, NULL, result, 0);
>         err = do_ahash_op(crypto_ahash_init, req, &wait, cfg->nosimd);
> -       err = check_nonfinal_hash_op("init", err, result, digestsize,
> -                                    driver, vec_name, cfg);
> +       err = check_nonfinal_ahash_op("init", err, result, digestsize,
> +                                     driver, vec_name, cfg);
>         if (err)
>                 return err;
>
> @@ -1175,9 +1369,9 @@ static int test_hash_vec_cfg(const char *driver,
>                                                 pending_len);
>                         err = do_ahash_op(crypto_ahash_update, req, &wait,
>                                           divs[i]->nosimd);
> -                       err = check_nonfinal_hash_op("update", err,
> -                                                    result, digestsize,
> -                                                    driver, vec_name, cfg);
> +                       err = check_nonfinal_ahash_op("update", err,
> +                                                     result, digestsize,
> +                                                     driver, vec_name, cfg);
>                         if (err)
>                                 return err;
>                         pending_sgl = NULL;
> @@ -1188,23 +1382,23 @@ static int test_hash_vec_cfg(const char *driver,
>                         testmgr_poison(hashstate + statesize,
>                                        TESTMGR_POISON_LEN);
>                         err = crypto_ahash_export(req, hashstate);
> -                       err = check_nonfinal_hash_op("export", err,
> -                                                    result, digestsize,
> -                                                    driver, vec_name, cfg);
> +                       err = check_nonfinal_ahash_op("export", err,
> +                                                     result, digestsize,
> +                                                     driver, vec_name, cfg);
>                         if (err)
>                                 return err;
>                         if (!testmgr_is_poison(hashstate + statesize,
>                                                TESTMGR_POISON_LEN)) {
> -                               pr_err("alg: hash: %s export() overran state buffer on test vector %s, cfg=\"%s\"\n",
> +                               pr_err("alg: ahash: %s export() overran state buffer on test vector %s, cfg=\"%s\"\n",
>                                        driver, vec_name, cfg->name);
>                                 return -EOVERFLOW;
>                         }
>
>                         testmgr_poison(req->__ctx, crypto_ahash_reqsize(tfm));
>                         err = crypto_ahash_import(req, hashstate);
> -                       err = check_nonfinal_hash_op("import", err,
> -                                                    result, digestsize,
> -                                                    driver, vec_name, cfg);
> +                       err = check_nonfinal_ahash_op("import", err,
> +                                                     result, digestsize,
> +                                                     driver, vec_name, cfg);
>                         if (err)
>                                 return err;
>                 }
> @@ -1218,13 +1412,13 @@ static int test_hash_vec_cfg(const char *driver,
>         if (cfg->finalization_type == FINALIZATION_TYPE_FINAL) {
>                 /* finish with update() and final() */
>                 err = do_ahash_op(crypto_ahash_update, req, &wait, cfg->nosimd);
> -               err = check_nonfinal_hash_op("update", err, result, digestsize,
> -                                            driver, vec_name, cfg);
> +               err = check_nonfinal_ahash_op("update", err, result, digestsize,
> +                                             driver, vec_name, cfg);
>                 if (err)
>                         return err;
>                 err = do_ahash_op(crypto_ahash_final, req, &wait, cfg->nosimd);
>                 if (err) {
> -                       pr_err("alg: hash: %s final() failed with err %d on test vector %s, cfg=\"%s\"\n",
> +                       pr_err("alg: ahash: %s final() failed with err %d on test vector %s, cfg=\"%s\"\n",
>                                driver, err, vec_name, cfg->name);
>                         return err;
>                 }
> @@ -1232,31 +1426,49 @@ static int test_hash_vec_cfg(const char *driver,
>                 /* finish with finup() */
>                 err = do_ahash_op(crypto_ahash_finup, req, &wait, cfg->nosimd);
>                 if (err) {
> -                       pr_err("alg: hash: %s finup() failed with err %d on test vector %s, cfg=\"%s\"\n",
> +                       pr_err("alg: ahash: %s finup() failed with err %d on test vector %s, cfg=\"%s\"\n",
>                                driver, err, vec_name, cfg->name);
>                         return err;
>                 }
>         }
>
>  result_ready:
> -       /* Check that the algorithm produced the correct digest */
> -       if (memcmp(result, vec->digest, digestsize) != 0) {
> -               pr_err("alg: hash: %s test failed (wrong result) on test vector %s, cfg=\"%s\"\n",
> -                      driver, vec_name, cfg->name);
> -               return -EINVAL;
> -       }
> -       if (!testmgr_is_poison(&result[digestsize], TESTMGR_POISON_LEN)) {
> -               pr_err("alg: hash: %s overran result buffer on test vector %s, cfg=\"%s\"\n",
> -                      driver, vec_name, cfg->name);
> -               return -EOVERFLOW;
> +       return check_hash_result("ahash", result, digestsize, vec, vec_name,
> +                                driver, cfg);
> +}
> +
> +static int test_hash_vec_cfg(const char *driver,
> +                            const struct hash_testvec *vec,
> +                            const char *vec_name,
> +                            const struct testvec_config *cfg,
> +                            struct ahash_request *req,
> +                            struct shash_desc *desc,
> +                            struct test_sglist *tsgl,
> +                            u8 *hashstate)
> +{
> +       int err;
> +
> +       /*
> +        * For algorithms implemented as "shash", most bugs will be detected by
> +        * both the shash and ahash tests.  Test the shash API first so that the
> +        * failures involve less indirection, so are easier to debug.
> +        */
> +
> +       if (desc) {
> +               err = test_shash_vec_cfg(driver, vec, vec_name, cfg, desc, tsgl,
> +                                        hashstate);
> +               if (err)
> +                       return err;
>         }
>
> -       return 0;
> +       return test_ahash_vec_cfg(driver, vec, vec_name, cfg, req, tsgl,
> +                                 hashstate);
>  }
>
>  static int test_hash_vec(const char *driver, const struct hash_testvec *vec,
>                          unsigned int vec_num, struct ahash_request *req,
> -                        struct test_sglist *tsgl, u8 *hashstate)
> +                        struct shash_desc *desc, struct test_sglist *tsgl,
> +                        u8 *hashstate)
>  {
>         char vec_name[16];
>         unsigned int i;
> @@ -1267,7 +1479,7 @@ static int test_hash_vec(const char *driver, const struct hash_testvec *vec,
>         for (i = 0; i < ARRAY_SIZE(default_hash_testvec_configs); i++) {
>                 err = test_hash_vec_cfg(driver, vec, vec_name,
>                                         &default_hash_testvec_configs[i],
> -                                       req, tsgl, hashstate);
> +                                       req, desc, tsgl, hashstate);
>                 if (err)
>                         return err;
>         }
> @@ -1281,7 +1493,7 @@ static int test_hash_vec(const char *driver, const struct hash_testvec *vec,
>                         generate_random_testvec_config(&cfg, cfgname,
>                                                        sizeof(cfgname));
>                         err = test_hash_vec_cfg(driver, vec, vec_name, &cfg,
> -                                               req, tsgl, hashstate);
> +                                               req, desc, tsgl, hashstate);
>                         if (err)
>                                 return err;
>                 }
> @@ -1343,6 +1555,7 @@ static int test_hash_vs_generic_impl(const char *driver,
>                                      const char *generic_driver,
>                                      unsigned int maxkeysize,
>                                      struct ahash_request *req,
> +                                    struct shash_desc *desc,
>                                      struct test_sglist *tsgl,
>                                      u8 *hashstate)
>  {
> @@ -1423,7 +1636,7 @@ static int test_hash_vs_generic_impl(const char *driver,
>                 generate_random_testvec_config(&cfg, cfgname, sizeof(cfgname));
>
>                 err = test_hash_vec_cfg(driver, &vec, vec_name, &cfg,
> -                                       req, tsgl, hashstate);
> +                                       req, desc, tsgl, hashstate);
>                 if (err)
>                         goto out;
>                 cond_resched();
> @@ -1441,6 +1654,7 @@ static int test_hash_vs_generic_impl(const char *driver,
>                                      const char *generic_driver,
>                                      unsigned int maxkeysize,
>                                      struct ahash_request *req,
> +                                    struct shash_desc *desc,
>                                      struct test_sglist *tsgl,
>                                      u8 *hashstate)
>  {
> @@ -1448,26 +1662,67 @@ static int test_hash_vs_generic_impl(const char *driver,
>  }
>  #endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
>
> +static int alloc_shash(const char *driver, u32 type, u32 mask,
> +                      struct crypto_shash **tfm_ret,
> +                      struct shash_desc **desc_ret)
> +{
> +       struct crypto_shash *tfm;
> +       struct shash_desc *desc;
> +
> +       tfm = crypto_alloc_shash(driver, type, mask);
> +       if (IS_ERR(tfm)) {
> +               if (PTR_ERR(tfm) == -ENOENT) {
> +                       /*
> +                        * This algorithm is only available through the ahash
> +                        * API, not the shash API, so skip the shash tests.
> +                        */
> +                       return 0;
> +               }
> +               pr_err("alg: hash: failed to allocate shash transform for %s: %ld\n",
> +                      driver, PTR_ERR(tfm));
> +               return PTR_ERR(tfm);
> +       }
> +
> +       desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
> +       if (!desc) {
> +               crypto_free_shash(tfm);
> +               return -ENOMEM;
> +       }
> +       desc->tfm = tfm;
> +
> +       *tfm_ret = tfm;
> +       *desc_ret = desc;
> +       return 0;
> +}
> +
>  static int __alg_test_hash(const struct hash_testvec *vecs,
>                            unsigned int num_vecs, const char *driver,
>                            u32 type, u32 mask,
>                            const char *generic_driver, unsigned int maxkeysize)
>  {
> -       struct crypto_ahash *tfm;
> +       struct crypto_ahash *atfm = NULL;
>         struct ahash_request *req = NULL;
> +       struct crypto_shash *stfm = NULL;
> +       struct shash_desc *desc = NULL;
>         struct test_sglist *tsgl = NULL;
>         u8 *hashstate = NULL;
> +       unsigned int statesize;
>         unsigned int i;
>         int err;
>
> -       tfm = crypto_alloc_ahash(driver, type, mask);
> -       if (IS_ERR(tfm)) {
> +       /*
> +        * Always test the ahash API.  This works regardless of whether the
> +        * algorithm is implemented as ahash or shash.
> +        */
> +
> +       atfm = crypto_alloc_ahash(driver, type, mask);
> +       if (IS_ERR(atfm)) {
>                 pr_err("alg: hash: failed to allocate transform for %s: %ld\n",
> -                      driver, PTR_ERR(tfm));
> -               return PTR_ERR(tfm);
> +                      driver, PTR_ERR(atfm));
> +               return PTR_ERR(atfm);
>         }
>
> -       req = ahash_request_alloc(tfm, GFP_KERNEL);
> +       req = ahash_request_alloc(atfm, GFP_KERNEL);
>         if (!req) {
>                 pr_err("alg: hash: failed to allocate request for %s\n",
>                        driver);
> @@ -1475,6 +1730,14 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
>                 goto out;
>         }
>
> +       /*
> +        * If available also test the shash API, to cover corner cases that may
> +        * be missed by testing the ahash API only.
> +        */
> +       err = alloc_shash(driver, type, mask, &stfm, &desc);
> +       if (err)
> +               goto out;
> +
>         tsgl = kmalloc(sizeof(*tsgl), GFP_KERNEL);
>         if (!tsgl || init_test_sglist(tsgl) != 0) {
>                 pr_err("alg: hash: failed to allocate test buffers for %s\n",
> @@ -1485,8 +1748,10 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
>                 goto out;
>         }
>
> -       hashstate = kmalloc(crypto_ahash_statesize(tfm) + TESTMGR_POISON_LEN,
> -                           GFP_KERNEL);
> +       statesize = crypto_ahash_statesize(atfm);
> +       if (stfm)
> +               statesize = max(statesize, crypto_shash_statesize(stfm));
> +       hashstate = kmalloc(statesize + TESTMGR_POISON_LEN, GFP_KERNEL);
>         if (!hashstate) {
>                 pr_err("alg: hash: failed to allocate hash state buffer for %s\n",
>                        driver);
> @@ -1495,20 +1760,23 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
>         }
>
>         for (i = 0; i < num_vecs; i++) {
> -               err = test_hash_vec(driver, &vecs[i], i, req, tsgl, hashstate);
> +               err = test_hash_vec(driver, &vecs[i], i, req, desc, tsgl,
> +                                   hashstate);
>                 if (err)
>                         goto out;
>         }
>         err = test_hash_vs_generic_impl(driver, generic_driver, maxkeysize, req,
> -                                       tsgl, hashstate);
> +                                       desc, tsgl, hashstate);
>  out:
>         kfree(hashstate);
>         if (tsgl) {
>                 destroy_test_sglist(tsgl);
>                 kfree(tsgl);
>         }
> +       kfree(desc);
> +       crypto_free_shash(stfm);
>         ahash_request_free(req);
> -       crypto_free_ahash(tfm);
> +       crypto_free_ahash(atfm);
>         return err;
>  }
>
> --
> 2.21.0
>



[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux