]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - crypto/testmgr.c
Merge tag 'riscv-for-linus-5.6-mw0' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / crypto / testmgr.c
index 82513b6b0abd0f43b146b26e1b1f0272ae2df503..88f33c0efb2331a0922e10e8d017597a49ccc52c 100644 (file)
@@ -82,6 +82,19 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
 struct aead_test_suite {
        const struct aead_testvec *vecs;
        unsigned int count;
+
+       /*
+        * Set if trying to decrypt an inauthentic ciphertext with this
+        * algorithm might result in EINVAL rather than EBADMSG, due to other
+        * validation the algorithm does on the inputs such as length checks.
+        */
+       unsigned int einval_allowed : 1;
+
+       /*
+        * Set if the algorithm intentionally ignores the last 8 bytes of the
+        * AAD buffer during decryption.
+        */
+       unsigned int esp_aad : 1;
 };
 
 struct cipher_test_suite {
@@ -259,6 +272,9 @@ struct test_sg_division {
  *            where 0 is aligned to a 2*(MAX_ALGAPI_ALIGNMASK+1) byte boundary
  * @iv_offset_relative_to_alignmask: if true, add the algorithm's alignmask to
  *                                  the @iv_offset
+ * @key_offset: misalignment of the key, where 0 is default alignment
+ * @key_offset_relative_to_alignmask: if true, add the algorithm's alignmask to
+ *                                   the @key_offset
  * @finalization_type: what finalization function to use for hashes
  * @nosimd: execute with SIMD disabled?  Requires !CRYPTO_TFM_REQ_MAY_SLEEP.
  */
@@ -269,7 +285,9 @@ struct testvec_config {
        struct test_sg_division src_divs[XBUFSIZE];
        struct test_sg_division dst_divs[XBUFSIZE];
        unsigned int iv_offset;
+       unsigned int key_offset;
        bool iv_offset_relative_to_alignmask;
+       bool key_offset_relative_to_alignmask;
        enum finalization_type finalization_type;
        bool nosimd;
 };
@@ -297,6 +315,7 @@ static const struct testvec_config default_cipher_testvec_configs[] = {
                .name = "unaligned buffer, offset=1",
                .src_divs = { { .proportion_of_total = 10000, .offset = 1 } },
                .iv_offset = 1,
+               .key_offset = 1,
        }, {
                .name = "buffer aligned only to alignmask",
                .src_divs = {
@@ -308,6 +327,8 @@ static const struct testvec_config default_cipher_testvec_configs[] = {
                },
                .iv_offset = 1,
                .iv_offset_relative_to_alignmask = true,
+               .key_offset = 1,
+               .key_offset_relative_to_alignmask = true,
        }, {
                .name = "two even aligned splits",
                .src_divs = {
@@ -323,6 +344,7 @@ static const struct testvec_config default_cipher_testvec_configs[] = {
                        { .proportion_of_total = 4800, .offset = 18 },
                },
                .iv_offset = 3,
+               .key_offset = 3,
        }, {
                .name = "misaligned splits crossing pages, inplace",
                .inplace = true,
@@ -355,6 +377,7 @@ static const struct testvec_config default_hash_testvec_configs[] = {
                .name = "init+update+final misaligned buffer",
                .src_divs = { { .proportion_of_total = 10000, .offset = 1 } },
                .finalization_type = FINALIZATION_TYPE_FINAL,
+               .key_offset = 1,
        }, {
                .name = "digest buffer aligned only to alignmask",
                .src_divs = {
@@ -365,6 +388,8 @@ static const struct testvec_config default_hash_testvec_configs[] = {
                        },
                },
                .finalization_type = FINALIZATION_TYPE_DIGEST,
+               .key_offset = 1,
+               .key_offset_relative_to_alignmask = true,
        }, {
                .name = "init+update+update+final two even splits",
                .src_divs = {
@@ -740,6 +765,49 @@ static int build_cipher_test_sglists(struct cipher_test_sglists *tsgls,
                                 alignmask, dst_total_len, NULL, NULL);
 }
 
+/*
+ * Support for testing passing a misaligned key to setkey():
+ *
+ * If cfg->key_offset is set, copy the key into a new buffer at that offset,
+ * optionally adding alignmask.  Else, just use the key directly.
+ */
+static int prepare_keybuf(const u8 *key, unsigned int ksize,
+                         const struct testvec_config *cfg,
+                         unsigned int alignmask,
+                         const u8 **keybuf_ret, const u8 **keyptr_ret)
+{
+       unsigned int key_offset = cfg->key_offset;
+       u8 *keybuf = NULL, *keyptr = (u8 *)key;
+
+       if (key_offset != 0) {
+               if (cfg->key_offset_relative_to_alignmask)
+                       key_offset += alignmask;
+               keybuf = kmalloc(key_offset + ksize, GFP_KERNEL);
+               if (!keybuf)
+                       return -ENOMEM;
+               keyptr = keybuf + key_offset;
+               memcpy(keyptr, key, ksize);
+       }
+       *keybuf_ret = keybuf;
+       *keyptr_ret = keyptr;
+       return 0;
+}
+
+/* Like setkey_f(tfm, key, ksize), but sometimes misalign the key */
+#define do_setkey(setkey_f, tfm, key, ksize, cfg, alignmask)           \
+({                                                                     \
+       const u8 *keybuf, *keyptr;                                      \
+       int err;                                                        \
+                                                                       \
+       err = prepare_keybuf((key), (ksize), (cfg), (alignmask),        \
+                            &keybuf, &keyptr);                         \
+       if (err == 0) {                                                 \
+               err = setkey_f((tfm), keyptr, (ksize));                 \
+               kfree(keybuf);                                          \
+       }                                                               \
+       err;                                                            \
+})
+
 #ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
 
 /* Generate a random length in range [0, max_len], but prefer smaller values */
@@ -759,27 +827,39 @@ static unsigned int generate_random_length(unsigned int max_len)
        }
 }
 
-/* Sometimes make some random changes to the given data buffer */
-static void mutate_buffer(u8 *buf, size_t count)
+/* Flip a random bit in the given nonempty data buffer */
+static void flip_random_bit(u8 *buf, size_t size)
+{
+       size_t bitpos;
+
+       bitpos = prandom_u32() % (size * 8);
+       buf[bitpos / 8] ^= 1 << (bitpos % 8);
+}
+
+/* Flip a random byte in the given nonempty data buffer */
+static void flip_random_byte(u8 *buf, size_t size)
+{
+       buf[prandom_u32() % size] ^= 0xff;
+}
+
+/* Sometimes make some random changes to the given nonempty data buffer */
+static void mutate_buffer(u8 *buf, size_t size)
 {
        size_t num_flips;
        size_t i;
-       size_t pos;
 
        /* Sometimes flip some bits */
        if (prandom_u32() % 4 == 0) {
-               num_flips = min_t(size_t, 1 << (prandom_u32() % 8), count * 8);
-               for (i = 0; i < num_flips; i++) {
-                       pos = prandom_u32() % (count * 8);
-                       buf[pos / 8] ^= 1 << (pos % 8);
-               }
+               num_flips = min_t(size_t, 1 << (prandom_u32() % 8), size * 8);
+               for (i = 0; i < num_flips; i++)
+                       flip_random_bit(buf, size);
        }
 
        /* Sometimes flip some bytes */
        if (prandom_u32() % 4 == 0) {
-               num_flips = min_t(size_t, 1 << (prandom_u32() % 8), count);
+               num_flips = min_t(size_t, 1 << (prandom_u32() % 8), size);
                for (i = 0; i < num_flips; i++)
-                       buf[prandom_u32() % count] ^= 0xff;
+                       flip_random_byte(buf, size);
        }
 }
 
@@ -966,6 +1046,11 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
                p += scnprintf(p, end - p, " iv_offset=%u", cfg->iv_offset);
        }
 
+       if (prandom_u32() % 2 == 0) {
+               cfg->key_offset = 1 + (prandom_u32() % MAX_ALGAPI_ALIGNMASK);
+               p += scnprintf(p, end - p, " key_offset=%u", cfg->key_offset);
+       }
+
        WARN_ON_ONCE(!valid_testvec_config(cfg));
 }
 
@@ -1103,7 +1188,8 @@ static int test_shash_vec_cfg(const char *driver,
 
        /* Set the key, if specified */
        if (vec->ksize) {
-               err = crypto_shash_setkey(tfm, vec->key, vec->ksize);
+               err = do_setkey(crypto_shash_setkey, tfm, vec->key, vec->ksize,
+                               cfg, alignmask);
                if (err) {
                        if (err == vec->setkey_error)
                                return 0;
@@ -1290,7 +1376,8 @@ static int test_ahash_vec_cfg(const char *driver,
 
        /* Set the key, if specified */
        if (vec->ksize) {
-               err = crypto_ahash_setkey(tfm, vec->key, vec->ksize);
+               err = do_setkey(crypto_ahash_setkey, tfm, vec->key, vec->ksize,
+                               cfg, alignmask);
                if (err) {
                        if (err == vec->setkey_error)
                                return 0;
@@ -1853,7 +1940,6 @@ static int test_aead_vec_cfg(const char *driver, int enc,
                 cfg->iv_offset +
                 (cfg->iv_offset_relative_to_alignmask ? alignmask : 0);
        struct kvec input[2];
-       int expected_error;
        int err;
 
        /* Set the key */
@@ -1861,7 +1947,9 @@ static int test_aead_vec_cfg(const char *driver, int enc,
                crypto_aead_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
        else
                crypto_aead_clear_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
-       err = crypto_aead_setkey(tfm, vec->key, vec->klen);
+
+       err = do_setkey(crypto_aead_setkey, tfm, vec->key, vec->klen,
+                       cfg, alignmask);
        if (err && err != vec->setkey_error) {
                pr_err("alg: aead: %s setkey failed on test vector %s; expected_error=%d, actual_error=%d, flags=%#x\n",
                       driver, vec_name, vec->setkey_error, err,
@@ -1972,20 +2060,31 @@ static int test_aead_vec_cfg(const char *driver, int enc,
                return -EINVAL;
        }
 
-       /* Check for success or failure */
-       expected_error = vec->novrfy ? -EBADMSG : vec->crypt_error;
-       if (err) {
-               if (err == expected_error)
-                       return 0;
-               pr_err("alg: aead: %s %s failed on test vector %s; expected_error=%d, actual_error=%d, cfg=\"%s\"\n",
-                      driver, op, vec_name, expected_error, err, cfg->name);
-               return err;
-       }
-       if (expected_error) {
-               pr_err("alg: aead: %s %s unexpectedly succeeded on test vector %s; expected_error=%d, cfg=\"%s\"\n",
+       /* Check for unexpected success or failure, or wrong error code */
+       if ((err == 0 && vec->novrfy) ||
+           (err != vec->crypt_error && !(err == -EBADMSG && vec->novrfy))) {
+               char expected_error[32];
+
+               if (vec->novrfy &&
+                   vec->crypt_error != 0 && vec->crypt_error != -EBADMSG)
+                       sprintf(expected_error, "-EBADMSG or %d",
+                               vec->crypt_error);
+               else if (vec->novrfy)
+                       sprintf(expected_error, "-EBADMSG");
+               else
+                       sprintf(expected_error, "%d", vec->crypt_error);
+               if (err) {
+                       pr_err("alg: aead: %s %s failed on test vector %s; expected_error=%s, actual_error=%d, cfg=\"%s\"\n",
+                              driver, op, vec_name, expected_error, err,
+                              cfg->name);
+                       return err;
+               }
+               pr_err("alg: aead: %s %s unexpectedly succeeded on test vector %s; expected_error=%s, cfg=\"%s\"\n",
                       driver, op, vec_name, expected_error, cfg->name);
                return -EINVAL;
        }
+       if (err) /* Expectedly failed. */
+               return 0;
 
        /* Check for the correct output (ciphertext or plaintext) */
        err = verify_correct_output(&tsgls->dst, enc ? vec->ctext : vec->ptext,
@@ -2047,25 +2146,129 @@ static int test_aead_vec(const char *driver, int enc,
 }
 
 #ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
+
+struct aead_extra_tests_ctx {
+       struct aead_request *req;
+       struct crypto_aead *tfm;
+       const char *driver;
+       const struct alg_test_desc *test_desc;
+       struct cipher_test_sglists *tsgls;
+       unsigned int maxdatasize;
+       unsigned int maxkeysize;
+
+       struct aead_testvec vec;
+       char vec_name[64];
+       char cfgname[TESTVEC_CONFIG_NAMELEN];
+       struct testvec_config cfg;
+};
+
 /*
- * Generate an AEAD test vector from the given implementation.
- * Assumes the buffers in 'vec' were already allocated.
+ * Make at least one random change to a (ciphertext, AAD) pair.  "Ciphertext"
+ * here means the full ciphertext including the authentication tag.  The
+ * authentication tag (and hence also the ciphertext) is assumed to be nonempty.
+ */
+static void mutate_aead_message(struct aead_testvec *vec, bool esp_aad)
+{
+       const unsigned int aad_tail_size = esp_aad ? 8 : 0;
+       const unsigned int authsize = vec->clen - vec->plen;
+
+       if (prandom_u32() % 2 == 0 && vec->alen > aad_tail_size) {
+                /* Mutate the AAD */
+               flip_random_bit((u8 *)vec->assoc, vec->alen - aad_tail_size);
+               if (prandom_u32() % 2 == 0)
+                       return;
+       }
+       if (prandom_u32() % 2 == 0) {
+               /* Mutate auth tag (assuming it's at the end of ciphertext) */
+               flip_random_bit((u8 *)vec->ctext + vec->plen, authsize);
+       } else {
+               /* Mutate any part of the ciphertext */
+               flip_random_bit((u8 *)vec->ctext, vec->clen);
+       }
+}
+
+/*
+ * Minimum authentication tag size in bytes at which we assume that we can
+ * reliably generate inauthentic messages, i.e. not generate an authentic
+ * message by chance.
+ */
+#define MIN_COLLISION_FREE_AUTHSIZE 8
+
+static void generate_aead_message(struct aead_request *req,
+                                 const struct aead_test_suite *suite,
+                                 struct aead_testvec *vec,
+                                 bool prefer_inauthentic)
+{
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       const unsigned int ivsize = crypto_aead_ivsize(tfm);
+       const unsigned int authsize = vec->clen - vec->plen;
+       const bool inauthentic = (authsize >= MIN_COLLISION_FREE_AUTHSIZE) &&
+                                (prefer_inauthentic || prandom_u32() % 4 == 0);
+
+       /* Generate the AAD. */
+       generate_random_bytes((u8 *)vec->assoc, vec->alen);
+
+       if (inauthentic && prandom_u32() % 2 == 0) {
+               /* Generate a random ciphertext. */
+               generate_random_bytes((u8 *)vec->ctext, vec->clen);
+       } else {
+               int i = 0;
+               struct scatterlist src[2], dst;
+               u8 iv[MAX_IVLEN];
+               DECLARE_CRYPTO_WAIT(wait);
+
+               /* Generate a random plaintext and encrypt it. */
+               sg_init_table(src, 2);
+               if (vec->alen)
+                       sg_set_buf(&src[i++], vec->assoc, vec->alen);
+               if (vec->plen) {
+                       generate_random_bytes((u8 *)vec->ptext, vec->plen);
+                       sg_set_buf(&src[i++], vec->ptext, vec->plen);
+               }
+               sg_init_one(&dst, vec->ctext, vec->alen + vec->clen);
+               memcpy(iv, vec->iv, ivsize);
+               aead_request_set_callback(req, 0, crypto_req_done, &wait);
+               aead_request_set_crypt(req, src, &dst, vec->plen, iv);
+               aead_request_set_ad(req, vec->alen);
+               vec->crypt_error = crypto_wait_req(crypto_aead_encrypt(req),
+                                                  &wait);
+               /* If encryption failed, we're done. */
+               if (vec->crypt_error != 0)
+                       return;
+               memmove((u8 *)vec->ctext, vec->ctext + vec->alen, vec->clen);
+               if (!inauthentic)
+                       return;
+               /*
+                * Mutate the authentic (ciphertext, AAD) pair to get an
+                * inauthentic one.
+                */
+               mutate_aead_message(vec, suite->esp_aad);
+       }
+       vec->novrfy = 1;
+       if (suite->einval_allowed)
+               vec->crypt_error = -EINVAL;
+}
+
+/*
+ * Generate an AEAD test vector 'vec' using the implementation specified by
+ * 'req'.  The buffers in 'vec' must already be allocated.
+ *
+ * If 'prefer_inauthentic' is true, then this function will generate inauthentic
+ * test vectors (i.e. vectors with 'vec->novrfy=1') more often.
  */
 static void generate_random_aead_testvec(struct aead_request *req,
                                         struct aead_testvec *vec,
+                                        const struct aead_test_suite *suite,
                                         unsigned int maxkeysize,
                                         unsigned int maxdatasize,
-                                        char *name, size_t max_namelen)
+                                        char *name, size_t max_namelen,
+                                        bool prefer_inauthentic)
 {
        struct crypto_aead *tfm = crypto_aead_reqtfm(req);
        const unsigned int ivsize = crypto_aead_ivsize(tfm);
-       unsigned int maxauthsize = crypto_aead_alg(tfm)->maxauthsize;
+       const unsigned int maxauthsize = crypto_aead_maxauthsize(tfm);
        unsigned int authsize;
        unsigned int total_len;
-       int i;
-       struct scatterlist src[2], dst;
-       u8 iv[MAX_IVLEN];
-       DECLARE_CRYPTO_WAIT(wait);
 
        /* Key: length in [0, maxkeysize], but usually choose maxkeysize */
        vec->klen = maxkeysize;
@@ -2081,81 +2284,101 @@ static void generate_random_aead_testvec(struct aead_request *req,
        authsize = maxauthsize;
        if (prandom_u32() % 4 == 0)
                authsize = prandom_u32() % (maxauthsize + 1);
+       if (prefer_inauthentic && authsize < MIN_COLLISION_FREE_AUTHSIZE)
+               authsize = MIN_COLLISION_FREE_AUTHSIZE;
        if (WARN_ON(authsize > maxdatasize))
                authsize = maxdatasize;
        maxdatasize -= authsize;
        vec->setauthsize_error = crypto_aead_setauthsize(tfm, authsize);
 
-       /* Plaintext and associated data */
+       /* AAD, plaintext, and ciphertext lengths */
        total_len = generate_random_length(maxdatasize);
        if (prandom_u32() % 4 == 0)
                vec->alen = 0;
        else
                vec->alen = generate_random_length(total_len);
        vec->plen = total_len - vec->alen;
-       generate_random_bytes((u8 *)vec->assoc, vec->alen);
-       generate_random_bytes((u8 *)vec->ptext, vec->plen);
-
        vec->clen = vec->plen + authsize;
 
        /*
-        * If the key or authentication tag size couldn't be set, no need to
-        * continue to encrypt.
+        * Generate the AAD, plaintext, and ciphertext.  Not applicable if the
+        * key or the authentication tag size couldn't be set.
         */
-       if (vec->setkey_error || vec->setauthsize_error)
-               goto done;
-
-       /* Ciphertext */
-       sg_init_table(src, 2);
-       i = 0;
-       if (vec->alen)
-               sg_set_buf(&src[i++], vec->assoc, vec->alen);
-       if (vec->plen)
-               sg_set_buf(&src[i++], vec->ptext, vec->plen);
-       sg_init_one(&dst, vec->ctext, vec->alen + vec->clen);
-       memcpy(iv, vec->iv, ivsize);
-       aead_request_set_callback(req, 0, crypto_req_done, &wait);
-       aead_request_set_crypt(req, src, &dst, vec->plen, iv);
-       aead_request_set_ad(req, vec->alen);
-       vec->crypt_error = crypto_wait_req(crypto_aead_encrypt(req), &wait);
-       if (vec->crypt_error == 0)
-               memmove((u8 *)vec->ctext, vec->ctext + vec->alen, vec->clen);
-done:
+       vec->novrfy = 0;
+       vec->crypt_error = 0;
+       if (vec->setkey_error == 0 && vec->setauthsize_error == 0)
+               generate_aead_message(req, suite, vec, prefer_inauthentic);
        snprintf(name, max_namelen,
-                "\"random: alen=%u plen=%u authsize=%u klen=%u\"",
-                vec->alen, vec->plen, authsize, vec->klen);
+                "\"random: alen=%u plen=%u authsize=%u klen=%u novrfy=%d\"",
+                vec->alen, vec->plen, authsize, vec->klen, vec->novrfy);
+}
+
+static void try_to_generate_inauthentic_testvec(
+                                       struct aead_extra_tests_ctx *ctx)
+{
+       int i;
+
+       for (i = 0; i < 10; i++) {
+               generate_random_aead_testvec(ctx->req, &ctx->vec,
+                                            &ctx->test_desc->suite.aead,
+                                            ctx->maxkeysize, ctx->maxdatasize,
+                                            ctx->vec_name,
+                                            sizeof(ctx->vec_name), true);
+               if (ctx->vec.novrfy)
+                       return;
+       }
 }
 
 /*
- * Test the AEAD algorithm represented by @req against the corresponding generic
- * implementation, if one is available.
+ * Generate inauthentic test vectors (i.e. ciphertext, AAD pairs that aren't the
+ * result of an encryption with the key) and verify that decryption fails.
  */
-static int test_aead_vs_generic_impl(const char *driver,
-                                    const struct alg_test_desc *test_desc,
-                                    struct aead_request *req,
-                                    struct cipher_test_sglists *tsgls)
+static int test_aead_inauthentic_inputs(struct aead_extra_tests_ctx *ctx)
 {
-       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
-       const unsigned int ivsize = crypto_aead_ivsize(tfm);
-       const unsigned int maxauthsize = crypto_aead_alg(tfm)->maxauthsize;
-       const unsigned int blocksize = crypto_aead_blocksize(tfm);
-       const unsigned int maxdatasize = (2 * PAGE_SIZE) - TESTMGR_POISON_LEN;
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < fuzz_iterations * 8; i++) {
+               /*
+                * Since this part of the tests isn't comparing the
+                * implementation to another, there's no point in testing any
+                * test vectors other than inauthentic ones (vec.novrfy=1) here.
+                *
+                * If we're having trouble generating such a test vector, e.g.
+                * if the algorithm keeps rejecting the generated keys, don't
+                * retry forever; just continue on.
+                */
+               try_to_generate_inauthentic_testvec(ctx);
+               if (ctx->vec.novrfy) {
+                       generate_random_testvec_config(&ctx->cfg, ctx->cfgname,
+                                                      sizeof(ctx->cfgname));
+                       err = test_aead_vec_cfg(ctx->driver, DECRYPT, &ctx->vec,
+                                               ctx->vec_name, &ctx->cfg,
+                                               ctx->req, ctx->tsgls);
+                       if (err)
+                               return err;
+               }
+               cond_resched();
+       }
+       return 0;
+}
+
+/*
+ * Test the AEAD algorithm against the corresponding generic implementation, if
+ * one is available.
+ */
+static int test_aead_vs_generic_impl(struct aead_extra_tests_ctx *ctx)
+{
+       struct crypto_aead *tfm = ctx->tfm;
        const char *algname = crypto_aead_alg(tfm)->base.cra_name;
-       const char *generic_driver = test_desc->generic_driver;
+       const char *driver = ctx->driver;
+       const char *generic_driver = ctx->test_desc->generic_driver;
        char _generic_driver[CRYPTO_MAX_ALG_NAME];
        struct crypto_aead *generic_tfm = NULL;
        struct aead_request *generic_req = NULL;
-       unsigned int maxkeysize;
        unsigned int i;
-       struct aead_testvec vec = { 0 };
-       char vec_name[64];
-       struct testvec_config *cfg;
-       char cfgname[TESTVEC_CONFIG_NAMELEN];
        int err;
 
-       if (noextratests)
-               return 0;
-
        if (!generic_driver) { /* Use default naming convention? */
                err = build_generic_driver_name(algname, _generic_driver);
                if (err)
@@ -2179,12 +2402,6 @@ static int test_aead_vs_generic_impl(const char *driver,
                return err;
        }
 
-       cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
-       if (!cfg) {
-               err = -ENOMEM;
-               goto out;
-       }
-
        generic_req = aead_request_alloc(generic_tfm, GFP_KERNEL);
        if (!generic_req) {
                err = -ENOMEM;
@@ -2193,24 +2410,27 @@ static int test_aead_vs_generic_impl(const char *driver,
 
        /* Check the algorithm properties for consistency. */
 
-       if (maxauthsize != crypto_aead_alg(generic_tfm)->maxauthsize) {
+       if (crypto_aead_maxauthsize(tfm) !=
+           crypto_aead_maxauthsize(generic_tfm)) {
                pr_err("alg: aead: maxauthsize for %s (%u) doesn't match generic impl (%u)\n",
-                      driver, maxauthsize,
-                      crypto_aead_alg(generic_tfm)->maxauthsize);
+                      driver, crypto_aead_maxauthsize(tfm),
+                      crypto_aead_maxauthsize(generic_tfm));
                err = -EINVAL;
                goto out;
        }
 
-       if (ivsize != crypto_aead_ivsize(generic_tfm)) {
+       if (crypto_aead_ivsize(tfm) != crypto_aead_ivsize(generic_tfm)) {
                pr_err("alg: aead: ivsize for %s (%u) doesn't match generic impl (%u)\n",
-                      driver, ivsize, crypto_aead_ivsize(generic_tfm));
+                      driver, crypto_aead_ivsize(tfm),
+                      crypto_aead_ivsize(generic_tfm));
                err = -EINVAL;
                goto out;
        }
 
-       if (blocksize != crypto_aead_blocksize(generic_tfm)) {
+       if (crypto_aead_blocksize(tfm) != crypto_aead_blocksize(generic_tfm)) {
                pr_err("alg: aead: blocksize for %s (%u) doesn't match generic impl (%u)\n",
-                      driver, blocksize, crypto_aead_blocksize(generic_tfm));
+                      driver, crypto_aead_blocksize(tfm),
+                      crypto_aead_blocksize(generic_tfm));
                err = -EINVAL;
                goto out;
        }
@@ -2219,55 +2439,93 @@ static int test_aead_vs_generic_impl(const char *driver,
         * Now generate test vectors using the generic implementation, and test
         * the other implementation against them.
         */
+       for (i = 0; i < fuzz_iterations * 8; i++) {
+               generate_random_aead_testvec(generic_req, &ctx->vec,
+                                            &ctx->test_desc->suite.aead,
+                                            ctx->maxkeysize, ctx->maxdatasize,
+                                            ctx->vec_name,
+                                            sizeof(ctx->vec_name), false);
+               generate_random_testvec_config(&ctx->cfg, ctx->cfgname,
+                                              sizeof(ctx->cfgname));
+               if (!ctx->vec.novrfy) {
+                       err = test_aead_vec_cfg(driver, ENCRYPT, &ctx->vec,
+                                               ctx->vec_name, &ctx->cfg,
+                                               ctx->req, ctx->tsgls);
+                       if (err)
+                               goto out;
+               }
+               if (ctx->vec.crypt_error == 0 || ctx->vec.novrfy) {
+                       err = test_aead_vec_cfg(driver, DECRYPT, &ctx->vec,
+                                               ctx->vec_name, &ctx->cfg,
+                                               ctx->req, ctx->tsgls);
+                       if (err)
+                               goto out;
+               }
+               cond_resched();
+       }
+       err = 0;
+out:
+       crypto_free_aead(generic_tfm);
+       aead_request_free(generic_req);
+       return err;
+}
 
-       maxkeysize = 0;
-       for (i = 0; i < test_desc->suite.aead.count; i++)
-               maxkeysize = max_t(unsigned int, maxkeysize,
-                                  test_desc->suite.aead.vecs[i].klen);
+static int test_aead_extra(const char *driver,
+                          const struct alg_test_desc *test_desc,
+                          struct aead_request *req,
+                          struct cipher_test_sglists *tsgls)
+{
+       struct aead_extra_tests_ctx *ctx;
+       unsigned int i;
+       int err;
 
-       vec.key = kmalloc(maxkeysize, GFP_KERNEL);
-       vec.iv = kmalloc(ivsize, GFP_KERNEL);
-       vec.assoc = kmalloc(maxdatasize, GFP_KERNEL);
-       vec.ptext = kmalloc(maxdatasize, GFP_KERNEL);
-       vec.ctext = kmalloc(maxdatasize, GFP_KERNEL);
-       if (!vec.key || !vec.iv || !vec.assoc || !vec.ptext || !vec.ctext) {
+       if (noextratests)
+               return 0;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+       ctx->req = req;
+       ctx->tfm = crypto_aead_reqtfm(req);
+       ctx->driver = driver;
+       ctx->test_desc = test_desc;
+       ctx->tsgls = tsgls;
+       ctx->maxdatasize = (2 * PAGE_SIZE) - TESTMGR_POISON_LEN;
+       ctx->maxkeysize = 0;
+       for (i = 0; i < test_desc->suite.aead.count; i++)
+               ctx->maxkeysize = max_t(unsigned int, ctx->maxkeysize,
+                                       test_desc->suite.aead.vecs[i].klen);
+
+       ctx->vec.key = kmalloc(ctx->maxkeysize, GFP_KERNEL);
+       ctx->vec.iv = kmalloc(crypto_aead_ivsize(ctx->tfm), GFP_KERNEL);
+       ctx->vec.assoc = kmalloc(ctx->maxdatasize, GFP_KERNEL);
+       ctx->vec.ptext = kmalloc(ctx->maxdatasize, GFP_KERNEL);
+       ctx->vec.ctext = kmalloc(ctx->maxdatasize, GFP_KERNEL);
+       if (!ctx->vec.key || !ctx->vec.iv || !ctx->vec.assoc ||
+           !ctx->vec.ptext || !ctx->vec.ctext) {
                err = -ENOMEM;
                goto out;
        }
 
-       for (i = 0; i < fuzz_iterations * 8; i++) {
-               generate_random_aead_testvec(generic_req, &vec,
-                                            maxkeysize, maxdatasize,
-                                            vec_name, sizeof(vec_name));
-               generate_random_testvec_config(cfg, cfgname, sizeof(cfgname));
+       err = test_aead_inauthentic_inputs(ctx);
+       if (err)
+               goto out;
 
-               err = test_aead_vec_cfg(driver, ENCRYPT, &vec, vec_name, cfg,
-                                       req, tsgls);
-               if (err)
-                       goto out;
-               err = test_aead_vec_cfg(driver, DECRYPT, &vec, vec_name, cfg,
-                                       req, tsgls);
-               if (err)
-                       goto out;
-               cond_resched();
-       }
-       err = 0;
+       err = test_aead_vs_generic_impl(ctx);
 out:
-       kfree(cfg);
-       kfree(vec.key);
-       kfree(vec.iv);
-       kfree(vec.assoc);
-       kfree(vec.ptext);
-       kfree(vec.ctext);
-       crypto_free_aead(generic_tfm);
-       aead_request_free(generic_req);
+       kfree(ctx->vec.key);
+       kfree(ctx->vec.iv);
+       kfree(ctx->vec.assoc);
+       kfree(ctx->vec.ptext);
+       kfree(ctx->vec.ctext);
+       kfree(ctx);
        return err;
 }
 #else /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
-static int test_aead_vs_generic_impl(const char *driver,
-                                    const struct alg_test_desc *test_desc,
-                                    struct aead_request *req,
-                                    struct cipher_test_sglists *tsgls)
+static int test_aead_extra(const char *driver,
+                          const struct alg_test_desc *test_desc,
+                          struct aead_request *req,
+                          struct cipher_test_sglists *tsgls)
 {
        return 0;
 }
@@ -2336,7 +2594,7 @@ static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
        if (err)
                goto out;
 
-       err = test_aead_vs_generic_impl(driver, desc, req, tsgls);
+       err = test_aead_extra(driver, desc, req, tsgls);
 out:
        free_cipher_test_sglists(tsgls);
        aead_request_free(req);
@@ -2457,7 +2715,8 @@ static int test_skcipher_vec_cfg(const char *driver, int enc,
        else
                crypto_skcipher_clear_flags(tfm,
                                            CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
-       err = crypto_skcipher_setkey(tfm, vec->key, vec->klen);
+       err = do_setkey(crypto_skcipher_setkey, tfm, vec->key, vec->klen,
+                       cfg, alignmask);
        if (err) {
                if (err == vec->setkey_error)
                        return 0;
@@ -2647,7 +2906,7 @@ static void generate_random_cipher_testvec(struct skcipher_request *req,
                                           char *name, size_t max_namelen)
 {
        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
-       const unsigned int maxkeysize = tfm->keysize;
+       const unsigned int maxkeysize = crypto_skcipher_max_keysize(tfm);
        const unsigned int ivsize = crypto_skcipher_ivsize(tfm);
        struct scatterlist src, dst;
        u8 iv[MAX_IVLEN];
@@ -2678,6 +2937,15 @@ static void generate_random_cipher_testvec(struct skcipher_request *req,
        skcipher_request_set_callback(req, 0, crypto_req_done, &wait);
        skcipher_request_set_crypt(req, &src, &dst, vec->len, iv);
        vec->crypt_error = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
+       if (vec->crypt_error != 0) {
+               /*
+                * The only acceptable error here is for an invalid length, so
+                * skcipher decryption should fail with the same error too.
+                * We'll test for this.  But to keep the API usage well-defined,
+                * explicitly initialize the ciphertext buffer too.
+                */
+               memset((u8 *)vec->ctext, 0, vec->len);
+       }
 done:
        snprintf(name, max_namelen, "\"random: len=%u klen=%u\"",
                 vec->len, vec->klen);
@@ -2693,6 +2961,7 @@ static int test_skcipher_vs_generic_impl(const char *driver,
                                         struct cipher_test_sglists *tsgls)
 {
        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const unsigned int maxkeysize = crypto_skcipher_max_keysize(tfm);
        const unsigned int ivsize = crypto_skcipher_ivsize(tfm);
        const unsigned int blocksize = crypto_skcipher_blocksize(tfm);
        const unsigned int maxdatasize = (2 * PAGE_SIZE) - TESTMGR_POISON_LEN;
@@ -2751,9 +3020,19 @@ static int test_skcipher_vs_generic_impl(const char *driver,
 
        /* Check the algorithm properties for consistency. */
 
-       if (tfm->keysize != generic_tfm->keysize) {
+       if (crypto_skcipher_min_keysize(tfm) !=
+           crypto_skcipher_min_keysize(generic_tfm)) {
+               pr_err("alg: skcipher: min keysize for %s (%u) doesn't match generic impl (%u)\n",
+                      driver, crypto_skcipher_min_keysize(tfm),
+                      crypto_skcipher_min_keysize(generic_tfm));
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (maxkeysize != crypto_skcipher_max_keysize(generic_tfm)) {
                pr_err("alg: skcipher: max keysize for %s (%u) doesn't match generic impl (%u)\n",
-                      driver, tfm->keysize, generic_tfm->keysize);
+                      driver, maxkeysize,
+                      crypto_skcipher_max_keysize(generic_tfm));
                err = -EINVAL;
                goto out;
        }
@@ -2778,7 +3057,7 @@ static int test_skcipher_vs_generic_impl(const char *driver,
         * the other implementation against them.
         */
 
-       vec.key = kmalloc(tfm->keysize, GFP_KERNEL);
+       vec.key = kmalloc(maxkeysize, GFP_KERNEL);
        vec.iv = kmalloc(ivsize, GFP_KERNEL);
        vec.ptext = kmalloc(maxdatasize, GFP_KERNEL);
        vec.ctext = kmalloc(maxdatasize, GFP_KERNEL);
@@ -3862,7 +4141,8 @@ static int alg_test_null(const struct alg_test_desc *desc,
        return 0;
 }
 
-#define __VECS(tv)     { .vecs = tv, .count = ARRAY_SIZE(tv) }
+#define ____VECS(tv)   .vecs = tv, .count = ARRAY_SIZE(tv)
+#define __VECS(tv)     { ____VECS(tv) }
 
 /* Please keep this list sorted by algorithm name. */
 static const struct alg_test_desc alg_test_descs[] = {
@@ -4168,7 +4448,10 @@ static const struct alg_test_desc alg_test_descs[] = {
                .test = alg_test_aead,
                .fips_allowed = 1,
                .suite = {
-                       .aead = __VECS(aes_ccm_tv_template)
+                       .aead = {
+                               ____VECS(aes_ccm_tv_template),
+                               .einval_allowed = 1,
+                       }
                }
        }, {
                .alg = "cfb(aes)",
@@ -4916,7 +5199,11 @@ static const struct alg_test_desc alg_test_descs[] = {
                .test = alg_test_aead,
                .fips_allowed = 1,
                .suite = {
-                       .aead = __VECS(aes_gcm_rfc4106_tv_template)
+                       .aead = {
+                               ____VECS(aes_gcm_rfc4106_tv_template),
+                               .einval_allowed = 1,
+                               .esp_aad = 1,
+                       }
                }
        }, {
                .alg = "rfc4309(ccm(aes))",
@@ -4924,14 +5211,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                .test = alg_test_aead,
                .fips_allowed = 1,
                .suite = {
-                       .aead = __VECS(aes_ccm_rfc4309_tv_template)
+                       .aead = {
+                               ____VECS(aes_ccm_rfc4309_tv_template),
+                               .einval_allowed = 1,
+                               .esp_aad = 1,
+                       }
                }
        }, {
                .alg = "rfc4543(gcm(aes))",
                .generic_driver = "rfc4543(gcm_base(ctr(aes-generic),ghash-generic))",
                .test = alg_test_aead,
                .suite = {
-                       .aead = __VECS(aes_gcm_rfc4543_tv_template)
+                       .aead = {
+                               ____VECS(aes_gcm_rfc4543_tv_template),
+                               .einval_allowed = 1,
+                       }
                }
        }, {
                .alg = "rfc7539(chacha20,poly1305)",
@@ -4943,7 +5237,11 @@ static const struct alg_test_desc alg_test_descs[] = {
                .alg = "rfc7539esp(chacha20,poly1305)",
                .test = alg_test_aead,
                .suite = {
-                       .aead = __VECS(rfc7539esp_tv_template)
+                       .aead = {
+                               ____VECS(rfc7539esp_tv_template),
+                               .einval_allowed = 1,
+                               .esp_aad = 1,
+                       }
                }
        }, {
                .alg = "rmd128",