net: remove mm.h inclusion from netdevice.h
[linux-2.6.git] / crypto / testmgr.c
index 308d9cf..b6b93d4 100644 (file)
@@ -6,6 +6,13 @@
  * Copyright (c) 2007 Nokia Siemens Networks
  * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
  *
+ * Updated RFC4106 AES-GCM testing.
+ *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com)
+ *             Adrian Hoban <adrian.hoban@intel.com>
+ *             Gabriele Paoloni <gabriele.paoloni@intel.com>
+ *             Tadeusz Struk (tadeusz.struk@intel.com)
+ *    Copyright (c) 2010, Intel Corporation.
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * Software Foundation; either version 2 of the License, or (at your option)
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <crypto/rng.h>
 
 #include "internal.h"
+
+#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
+
+/* a perfect nop */
+int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
+{
+       return 0;
+}
+
+#else
+
 #include "testmgr.h"
 
 /*
@@ -72,29 +91,41 @@ struct comp_test_suite {
        } comp, decomp;
 };
 
+struct pcomp_test_suite {
+       struct {
+               struct pcomp_testvec *vecs;
+               unsigned int count;
+       } comp, decomp;
+};
+
 struct hash_test_suite {
        struct hash_testvec *vecs;
        unsigned int count;
 };
 
+struct cprng_test_suite {
+       struct cprng_testvec *vecs;
+       unsigned int count;
+};
+
 struct alg_test_desc {
        const char *alg;
        int (*test)(const struct alg_test_desc *desc, const char *driver,
                    u32 type, u32 mask);
+       int fips_allowed;       /* set if alg is allowed in fips mode */
 
        union {
                struct aead_test_suite aead;
                struct cipher_test_suite cipher;
                struct comp_test_suite comp;
+               struct pcomp_test_suite pcomp;
                struct hash_test_suite hash;
+               struct cprng_test_suite cprng;
        } suite;
 };
 
 static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 };
 
-static char *xbuf[XBUFSIZE];
-static char *axbuf[XBUFSIZE];
-
 static void hexdump(unsigned char *buf, unsigned int len)
 {
        print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
@@ -113,8 +144,48 @@ static void tcrypt_complete(struct crypto_async_request *req, int err)
        complete(&res->completion);
 }
 
+static int testmgr_alloc_buf(char *buf[XBUFSIZE])
+{
+       int i;
+
+       for (i = 0; i < XBUFSIZE; i++) {
+               buf[i] = (void *)__get_free_page(GFP_KERNEL);
+               if (!buf[i])
+                       goto err_free_buf;
+       }
+
+       return 0;
+
+err_free_buf:
+       while (i-- > 0)
+               free_page((unsigned long)buf[i]);
+
+       return -ENOMEM;
+}
+
+static void testmgr_free_buf(char *buf[XBUFSIZE])
+{
+       int i;
+
+       for (i = 0; i < XBUFSIZE; i++)
+               free_page((unsigned long)buf[i]);
+}
+
+static int do_one_async_hash_op(struct ahash_request *req,
+                               struct tcrypt_result *tr,
+                               int ret)
+{
+       if (ret == -EINPROGRESS || ret == -EBUSY) {
+               ret = wait_for_completion_interruptible(&tr->completion);
+               if (!ret)
+                       ret = tr->err;
+               INIT_COMPLETION(tr->completion);
+       }
+       return ret;
+}
+
 static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
-                    unsigned int tcount)
+                    unsigned int tcount, bool use_digest)
 {
        const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm));
        unsigned int i, j, k, temp;
@@ -122,8 +193,12 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
        char result[64];
        struct ahash_request *req;
        struct tcrypt_result tresult;
-       int ret;
        void *hash_buff;
+       char *xbuf[XBUFSIZE];
+       int ret = -ENOMEM;
+
+       if (testmgr_alloc_buf(xbuf))
+               goto out_nobuf;
 
        init_completion(&tresult.completion);
 
@@ -131,13 +206,17 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
        if (!req) {
                printk(KERN_ERR "alg: hash: Failed to allocate request for "
                       "%s\n", algo);
-               ret = -ENOMEM;
                goto out_noreq;
        }
        ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
                                   tcrypt_complete, &tresult);
 
+       j = 0;
        for (i = 0; i < tcount; i++) {
+               if (template[i].np)
+                       continue;
+
+               j++;
                memset(result, 0, 64);
 
                hash_buff = xbuf[0];
@@ -151,36 +230,49 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
                                                  template[i].ksize);
                        if (ret) {
                                printk(KERN_ERR "alg: hash: setkey failed on "
-                                      "test %d for %s: ret=%d\n", i + 1, algo,
+                                      "test %d for %s: ret=%d\n", j, algo,
                                       -ret);
                                goto out;
                        }
                }
 
                ahash_request_set_crypt(req, sg, result, template[i].psize);
-               ret = crypto_ahash_digest(req);
-               switch (ret) {
-               case 0:
-                       break;
-               case -EINPROGRESS:
-               case -EBUSY:
-                       ret = wait_for_completion_interruptible(
-                               &tresult.completion);
-                       if (!ret && !(ret = tresult.err)) {
-                               INIT_COMPLETION(tresult.completion);
-                               break;
+               if (use_digest) {
+                       ret = do_one_async_hash_op(req, &tresult,
+                                                  crypto_ahash_digest(req));
+                       if (ret) {
+                               pr_err("alg: hash: digest failed on test %d "
+                                      "for %s: ret=%d\n", j, algo, -ret);
+                               goto out;
+                       }
+               } else {
+                       ret = do_one_async_hash_op(req, &tresult,
+                                                  crypto_ahash_init(req));
+                       if (ret) {
+                               pr_err("alt: hash: init failed on test %d "
+                                      "for %s: ret=%d\n", j, algo, -ret);
+                               goto out;
+                       }
+                       ret = do_one_async_hash_op(req, &tresult,
+                                                  crypto_ahash_update(req));
+                       if (ret) {
+                               pr_err("alt: hash: update failed on test %d "
+                                      "for %s: ret=%d\n", j, algo, -ret);
+                               goto out;
+                       }
+                       ret = do_one_async_hash_op(req, &tresult,
+                                                  crypto_ahash_final(req));
+                       if (ret) {
+                               pr_err("alt: hash: final failed on test %d "
+                                      "for %s: ret=%d\n", j, algo, -ret);
+                               goto out;
                        }
-                       /* fall through */
-               default:
-                       printk(KERN_ERR "alg: hash: digest failed on test %d "
-                              "for %s: ret=%d\n", i + 1, algo, -ret);
-                       goto out;
                }
 
                if (memcmp(result, template[i].digest,
                           crypto_ahash_digestsize(tfm))) {
                        printk(KERN_ERR "alg: hash: Test %d failed for %s\n",
-                              i + 1, algo);
+                              j, algo);
                        hexdump(result, crypto_ahash_digestsize(tfm));
                        ret = -EINVAL;
                        goto out;
@@ -195,7 +287,11 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
 
                        temp = 0;
                        sg_init_table(sg, template[i].np);
+                       ret = -EINVAL;
                        for (k = 0; k < template[i].np; k++) {
+                               if (WARN_ON(offset_in_page(IDX[k]) +
+                                           template[i].tap[k] > PAGE_SIZE))
+                                       goto out;
                                sg_set_buf(&sg[k],
                                           memcpy(xbuf[IDX[k] >> PAGE_SHIFT] +
                                                  offset_in_page(IDX[k]),
@@ -257,6 +353,8 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
 out:
        ahash_request_free(req);
 out_noreq:
+       testmgr_free_buf(xbuf);
+out_nobuf:
        return ret;
 }
 
@@ -265,7 +363,7 @@ static int test_aead(struct crypto_aead *tfm, int enc,
 {
        const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm));
        unsigned int i, j, k, n, temp;
-       int ret = 0;
+       int ret = -ENOMEM;
        char *q;
        char *key;
        struct aead_request *req;
@@ -277,6 +375,13 @@ static int test_aead(struct crypto_aead *tfm, int enc,
        void *input;
        void *assoc;
        char iv[MAX_IVLEN];
+       char *xbuf[XBUFSIZE];
+       char *axbuf[XBUFSIZE];
+
+       if (testmgr_alloc_buf(xbuf))
+               goto out_noxbuf;
+       if (testmgr_alloc_buf(axbuf))
+               goto out_noaxbuf;
 
        if (enc == ENCRYPT)
                e = "encryption";
@@ -289,7 +394,6 @@ static int test_aead(struct crypto_aead *tfm, int enc,
        if (!req) {
                printk(KERN_ERR "alg: aead: Failed to allocate request for "
                       "%s\n", algo);
-               ret = -ENOMEM;
                goto out;
        }
 
@@ -306,6 +410,11 @@ static int test_aead(struct crypto_aead *tfm, int enc,
                        input = xbuf[0];
                        assoc = axbuf[0];
 
+                       ret = -EINVAL;
+                       if (WARN_ON(template[i].ilen > PAGE_SIZE ||
+                                   template[i].alen > PAGE_SIZE))
+                               goto out;
+
                        memcpy(input, template[i].input, template[i].ilen);
                        memcpy(assoc, template[i].assoc, template[i].alen);
                        if (template[i].iv)
@@ -355,6 +464,16 @@ static int test_aead(struct crypto_aead *tfm, int enc,
 
                        switch (ret) {
                        case 0:
+                               if (template[i].novrfy) {
+                                       /* verification was supposed to fail */
+                                       printk(KERN_ERR "alg: aead: %s failed "
+                                              "on test %d for %s: ret was 0, "
+                                              "expected -EBADMSG\n",
+                                              e, j, algo);
+                                       /* so really, we got a bad message */
+                                       ret = -EBADMSG;
+                                       goto out;
+                               }
                                break;
                        case -EINPROGRESS:
                        case -EBUSY:
@@ -364,6 +483,10 @@ static int test_aead(struct crypto_aead *tfm, int enc,
                                        INIT_COMPLETION(result.completion);
                                        break;
                                }
+                       case -EBADMSG:
+                               if (template[i].novrfy)
+                                       /* verification failure was expected */
+                                       continue;
                                /* fall through */
                        default:
                                printk(KERN_ERR "alg: aead: %s failed on test "
@@ -451,7 +574,11 @@ static int test_aead(struct crypto_aead *tfm, int enc,
                        }
 
                        sg_init_table(asg, template[i].anp);
+                       ret = -EINVAL;
                        for (k = 0, temp = 0; k < template[i].anp; k++) {
+                               if (WARN_ON(offset_in_page(IDX[k]) +
+                                           template[i].atap[k] > PAGE_SIZE))
+                                       goto out;
                                sg_set_buf(&asg[k],
                                           memcpy(axbuf[IDX[k] >> PAGE_SHIFT] +
                                                  offset_in_page(IDX[k]),
@@ -473,6 +600,16 @@ static int test_aead(struct crypto_aead *tfm, int enc,
 
                        switch (ret) {
                        case 0:
+                               if (template[i].novrfy) {
+                                       /* verification was supposed to fail */
+                                       printk(KERN_ERR "alg: aead: %s failed "
+                                              "on chunk test %d for %s: ret "
+                                              "was 0, expected -EBADMSG\n",
+                                              e, j, algo);
+                                       /* so really, we got a bad message */
+                                       ret = -EBADMSG;
+                                       goto out;
+                               }
                                break;
                        case -EINPROGRESS:
                        case -EBUSY:
@@ -482,6 +619,10 @@ static int test_aead(struct crypto_aead *tfm, int enc,
                                        INIT_COMPLETION(result.completion);
                                        break;
                                }
+                       case -EBADMSG:
+                               if (template[i].novrfy)
+                                       /* verification failure was expected */
+                                       continue;
                                /* fall through */
                        default:
                                printk(KERN_ERR "alg: aead: %s failed on "
@@ -538,6 +679,10 @@ static int test_aead(struct crypto_aead *tfm, int enc,
 
 out:
        aead_request_free(req);
+       testmgr_free_buf(axbuf);
+out_noaxbuf:
+       testmgr_free_buf(xbuf);
+out_noxbuf:
        return ret;
 }
 
@@ -546,10 +691,14 @@ static int test_cipher(struct crypto_cipher *tfm, int enc,
 {
        const char *algo = crypto_tfm_alg_driver_name(crypto_cipher_tfm(tfm));
        unsigned int i, j, k;
-       int ret;
        char *q;
        const char *e;
        void *data;
+       char *xbuf[XBUFSIZE];
+       int ret = -ENOMEM;
+
+       if (testmgr_alloc_buf(xbuf))
+               goto out_nobuf;
 
        if (enc == ENCRYPT)
                e = "encryption";
@@ -563,6 +712,10 @@ static int test_cipher(struct crypto_cipher *tfm, int enc,
 
                j++;
 
+               ret = -EINVAL;
+               if (WARN_ON(template[i].ilen > PAGE_SIZE))
+                       goto out;
+
                data = xbuf[0];
                memcpy(data, template[i].input, template[i].ilen);
 
@@ -603,6 +756,8 @@ static int test_cipher(struct crypto_cipher *tfm, int enc,
        ret = 0;
 
 out:
+       testmgr_free_buf(xbuf);
+out_nobuf:
        return ret;
 }
 
@@ -612,7 +767,6 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
        const char *algo =
                crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm));
        unsigned int i, j, k, n, temp;
-       int ret;
        char *q;
        struct ablkcipher_request *req;
        struct scatterlist sg[8];
@@ -620,6 +774,11 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
        struct tcrypt_result result;
        void *data;
        char iv[MAX_IVLEN];
+       char *xbuf[XBUFSIZE];
+       int ret = -ENOMEM;
+
+       if (testmgr_alloc_buf(xbuf))
+               goto out_nobuf;
 
        if (enc == ENCRYPT)
                e = "encryption";
@@ -632,7 +791,6 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
        if (!req) {
                printk(KERN_ERR "alg: skcipher: Failed to allocate request "
                       "for %s\n", algo);
-               ret = -ENOMEM;
                goto out;
        }
 
@@ -649,6 +807,10 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
                if (!(template[i].np)) {
                        j++;
 
+                       ret = -EINVAL;
+                       if (WARN_ON(template[i].ilen > PAGE_SIZE))
+                               goto out;
+
                        data = xbuf[0];
                        memcpy(data, template[i].input, template[i].ilen);
 
@@ -817,6 +979,8 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
 
 out:
        ablkcipher_request_free(req);
+       testmgr_free_buf(xbuf);
+out_nobuf:
        return ret;
 }
 
@@ -829,7 +993,8 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate,
        int ret;
 
        for (i = 0; i < ctcount; i++) {
-               int ilen, dlen = COMP_BUF_SIZE;
+               int ilen;
+               unsigned int dlen = COMP_BUF_SIZE;
 
                memset(result, 0, sizeof (result));
 
@@ -843,6 +1008,14 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate,
                        goto out;
                }
 
+               if (dlen != ctemplate[i].outlen) {
+                       printk(KERN_ERR "alg: comp: Compression test %d "
+                              "failed for %s: output len = %d\n", i + 1, algo,
+                              dlen);
+                       ret = -EINVAL;
+                       goto out;
+               }
+
                if (memcmp(result, ctemplate[i].output, dlen)) {
                        printk(KERN_ERR "alg: comp: Compression test %d "
                               "failed for %s\n", i + 1, algo);
@@ -853,7 +1026,8 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate,
        }
 
        for (i = 0; i < dtcount; i++) {
-               int ilen, ret, dlen = COMP_BUF_SIZE;
+               int ilen;
+               unsigned int dlen = COMP_BUF_SIZE;
 
                memset(result, 0, sizeof (result));
 
@@ -867,6 +1041,14 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate,
                        goto out;
                }
 
+               if (dlen != dtemplate[i].outlen) {
+                       printk(KERN_ERR "alg: comp: Decompression test %d "
+                              "failed for %s: output len = %d\n", i + 1, algo,
+                              dlen);
+                       ret = -EINVAL;
+                       goto out;
+               }
+
                if (memcmp(result, dtemplate[i].output, dlen)) {
                        printk(KERN_ERR "alg: comp: Decompression test %d "
                               "failed for %s\n", i + 1, algo);
@@ -882,6 +1064,244 @@ out:
        return ret;
 }
 
+static int test_pcomp(struct crypto_pcomp *tfm,
+                     struct pcomp_testvec *ctemplate,
+                     struct pcomp_testvec *dtemplate, int ctcount,
+                     int dtcount)
+{
+       const char *algo = crypto_tfm_alg_driver_name(crypto_pcomp_tfm(tfm));
+       unsigned int i;
+       char result[COMP_BUF_SIZE];
+       int res;
+
+       for (i = 0; i < ctcount; i++) {
+               struct comp_request req;
+               unsigned int produced = 0;
+
+               res = crypto_compress_setup(tfm, ctemplate[i].params,
+                                           ctemplate[i].paramsize);
+               if (res) {
+                       pr_err("alg: pcomp: compression setup failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
+               }
+
+               res = crypto_compress_init(tfm);
+               if (res) {
+                       pr_err("alg: pcomp: compression init failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
+               }
+
+               memset(result, 0, sizeof(result));
+
+               req.next_in = ctemplate[i].input;
+               req.avail_in = ctemplate[i].inlen / 2;
+               req.next_out = result;
+               req.avail_out = ctemplate[i].outlen / 2;
+
+               res = crypto_compress_update(tfm, &req);
+               if (res < 0 && (res != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: compression update failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
+               }
+               if (res > 0)
+                       produced += res;
+
+               /* Add remaining input data */
+               req.avail_in += (ctemplate[i].inlen + 1) / 2;
+
+               res = crypto_compress_update(tfm, &req);
+               if (res < 0 && (res != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: compression update failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
+               }
+               if (res > 0)
+                       produced += res;
+
+               /* Provide remaining output space */
+               req.avail_out += COMP_BUF_SIZE - ctemplate[i].outlen / 2;
+
+               res = crypto_compress_final(tfm, &req);
+               if (res < 0) {
+                       pr_err("alg: pcomp: compression final failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
+               }
+               produced += res;
+
+               if (COMP_BUF_SIZE - req.avail_out != ctemplate[i].outlen) {
+                       pr_err("alg: comp: Compression test %d failed for %s: "
+                              "output len = %d (expected %d)\n", i + 1, algo,
+                              COMP_BUF_SIZE - req.avail_out,
+                              ctemplate[i].outlen);
+                       return -EINVAL;
+               }
+
+               if (produced != ctemplate[i].outlen) {
+                       pr_err("alg: comp: Compression test %d failed for %s: "
+                              "returned len = %u (expected %d)\n", i + 1,
+                              algo, produced, ctemplate[i].outlen);
+                       return -EINVAL;
+               }
+
+               if (memcmp(result, ctemplate[i].output, ctemplate[i].outlen)) {
+                       pr_err("alg: pcomp: Compression test %d failed for "
+                              "%s\n", i + 1, algo);
+                       hexdump(result, ctemplate[i].outlen);
+                       return -EINVAL;
+               }
+       }
+
+       for (i = 0; i < dtcount; i++) {
+               struct comp_request req;
+               unsigned int produced = 0;
+
+               res = crypto_decompress_setup(tfm, dtemplate[i].params,
+                                             dtemplate[i].paramsize);
+               if (res) {
+                       pr_err("alg: pcomp: decompression setup failed on "
+                              "test %d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
+               }
+
+               res = crypto_decompress_init(tfm);
+               if (res) {
+                       pr_err("alg: pcomp: decompression init failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
+               }
+
+               memset(result, 0, sizeof(result));
+
+               req.next_in = dtemplate[i].input;
+               req.avail_in = dtemplate[i].inlen / 2;
+               req.next_out = result;
+               req.avail_out = dtemplate[i].outlen / 2;
+
+               res = crypto_decompress_update(tfm, &req);
+               if (res < 0 && (res != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: decompression update failed on "
+                              "test %d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
+               }
+               if (res > 0)
+                       produced += res;
+
+               /* Add remaining input data */
+               req.avail_in += (dtemplate[i].inlen + 1) / 2;
+
+               res = crypto_decompress_update(tfm, &req);
+               if (res < 0 && (res != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: decompression update failed on "
+                              "test %d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
+               }
+               if (res > 0)
+                       produced += res;
+
+               /* Provide remaining output space */
+               req.avail_out += COMP_BUF_SIZE - dtemplate[i].outlen / 2;
+
+               res = crypto_decompress_final(tfm, &req);
+               if (res < 0 && (res != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: decompression final failed on "
+                              "test %d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
+               }
+               if (res > 0)
+                       produced += res;
+
+               if (COMP_BUF_SIZE - req.avail_out != dtemplate[i].outlen) {
+                       pr_err("alg: comp: Decompression test %d failed for "
+                              "%s: output len = %d (expected %d)\n", i + 1,
+                              algo, COMP_BUF_SIZE - req.avail_out,
+                              dtemplate[i].outlen);
+                       return -EINVAL;
+               }
+
+               if (produced != dtemplate[i].outlen) {
+                       pr_err("alg: comp: Decompression test %d failed for "
+                              "%s: returned len = %u (expected %d)\n", i + 1,
+                              algo, produced, dtemplate[i].outlen);
+                       return -EINVAL;
+               }
+
+               if (memcmp(result, dtemplate[i].output, dtemplate[i].outlen)) {
+                       pr_err("alg: pcomp: Decompression test %d failed for "
+                              "%s\n", i + 1, algo);
+                       hexdump(result, dtemplate[i].outlen);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+
+static int test_cprng(struct crypto_rng *tfm, struct cprng_testvec *template,
+                     unsigned int tcount)
+{
+       const char *algo = crypto_tfm_alg_driver_name(crypto_rng_tfm(tfm));
+       int err = 0, i, j, seedsize;
+       u8 *seed;
+       char result[32];
+
+       seedsize = crypto_rng_seedsize(tfm);
+
+       seed = kmalloc(seedsize, GFP_KERNEL);
+       if (!seed) {
+               printk(KERN_ERR "alg: cprng: Failed to allocate seed space "
+                      "for %s\n", algo);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < tcount; i++) {
+               memset(result, 0, 32);
+
+               memcpy(seed, template[i].v, template[i].vlen);
+               memcpy(seed + template[i].vlen, template[i].key,
+                      template[i].klen);
+               memcpy(seed + template[i].vlen + template[i].klen,
+                      template[i].dt, template[i].dtlen);
+
+               err = crypto_rng_reset(tfm, seed, seedsize);
+               if (err) {
+                       printk(KERN_ERR "alg: cprng: Failed to reset rng "
+                              "for %s\n", algo);
+                       goto out;
+               }
+
+               for (j = 0; j < template[i].loops; j++) {
+                       err = crypto_rng_get_bytes(tfm, result,
+                                                  template[i].rlen);
+                       if (err != template[i].rlen) {
+                               printk(KERN_ERR "alg: cprng: Failed to obtain "
+                                      "the correct amount of random data for "
+                                      "%s (requested %d, got %d)\n", algo,
+                                      template[i].rlen, err);
+                               goto out;
+                       }
+               }
+
+               err = memcmp(result, template[i].result,
+                            template[i].rlen);
+               if (err) {
+                       printk(KERN_ERR "alg: cprng: Test %d failed for %s\n",
+                              i, algo);
+                       hexdump(result, template[i].rlen);
+                       err = -EINVAL;
+                       goto out;
+               }
+       }
+
+out:
+       kfree(seed);
+       return err;
+}
+
 static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
                         u32 type, u32 mask)
 {
@@ -991,6 +1411,28 @@ static int alg_test_comp(const struct alg_test_desc *desc, const char *driver,
        return err;
 }
 
+static int alg_test_pcomp(const struct alg_test_desc *desc, const char *driver,
+                         u32 type, u32 mask)
+{
+       struct crypto_pcomp *tfm;
+       int err;
+
+       tfm = crypto_alloc_pcomp(driver, type, mask);
+       if (IS_ERR(tfm)) {
+               pr_err("alg: pcomp: Failed to load transform for %s: %ld\n",
+                      driver, PTR_ERR(tfm));
+               return PTR_ERR(tfm);
+       }
+
+       err = test_pcomp(tfm, desc->suite.pcomp.comp.vecs,
+                        desc->suite.pcomp.decomp.vecs,
+                        desc->suite.pcomp.comp.count,
+                        desc->suite.pcomp.decomp.count);
+
+       crypto_free_pcomp(tfm);
+       return err;
+}
+
 static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
                         u32 type, u32 mask)
 {
@@ -1004,17 +1446,146 @@ static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
                return PTR_ERR(tfm);
        }
 
-       err = test_hash(tfm, desc->suite.hash.vecs, desc->suite.hash.count);
+       err = test_hash(tfm, desc->suite.hash.vecs,
+                       desc->suite.hash.count, true);
+       if (!err)
+               err = test_hash(tfm, desc->suite.hash.vecs,
+                               desc->suite.hash.count, false);
 
        crypto_free_ahash(tfm);
        return err;
 }
 
+static int alg_test_crc32c(const struct alg_test_desc *desc,
+                          const char *driver, u32 type, u32 mask)
+{
+       struct crypto_shash *tfm;
+       u32 val;
+       int err;
+
+       err = alg_test_hash(desc, driver, type, mask);
+       if (err)
+               goto out;
+
+       tfm = crypto_alloc_shash(driver, type, mask);
+       if (IS_ERR(tfm)) {
+               printk(KERN_ERR "alg: crc32c: Failed to load transform for %s: "
+                      "%ld\n", driver, PTR_ERR(tfm));
+               err = PTR_ERR(tfm);
+               goto out;
+       }
+
+       do {
+               struct {
+                       struct shash_desc shash;
+                       char ctx[crypto_shash_descsize(tfm)];
+               } sdesc;
+
+               sdesc.shash.tfm = tfm;
+               sdesc.shash.flags = 0;
+
+               *(u32 *)sdesc.ctx = le32_to_cpu(420553207);
+               err = crypto_shash_final(&sdesc.shash, (u8 *)&val);
+               if (err) {
+                       printk(KERN_ERR "alg: crc32c: Operation failed for "
+                              "%s: %d\n", driver, err);
+                       break;
+               }
+
+               if (val != ~420553207) {
+                       printk(KERN_ERR "alg: crc32c: Test failed for %s: "
+                              "%d\n", driver, val);
+                       err = -EINVAL;
+               }
+       } while (0);
+
+       crypto_free_shash(tfm);
+
+out:
+       return err;
+}
+
+static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver,
+                         u32 type, u32 mask)
+{
+       struct crypto_rng *rng;
+       int err;
+
+       rng = crypto_alloc_rng(driver, type, mask);
+       if (IS_ERR(rng)) {
+               printk(KERN_ERR "alg: cprng: Failed to load transform for %s: "
+                      "%ld\n", driver, PTR_ERR(rng));
+               return PTR_ERR(rng);
+       }
+
+       err = test_cprng(rng, desc->suite.cprng.vecs, desc->suite.cprng.count);
+
+       crypto_free_rng(rng);
+
+       return err;
+}
+
+static int alg_test_null(const struct alg_test_desc *desc,
+                            const char *driver, u32 type, u32 mask)
+{
+       return 0;
+}
+
 /* Please keep this list sorted by algorithm name. */
 static const struct alg_test_desc alg_test_descs[] = {
        {
+               .alg = "__driver-cbc-aes-aesni",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
+       }, {
+               .alg = "__driver-ecb-aes-aesni",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
+       }, {
+               .alg = "__ghash-pclmulqdqni",
+               .test = alg_test_null,
+               .suite = {
+                       .hash = {
+                               .vecs = NULL,
+                               .count = 0
+                       }
+               }
+       }, {
+               .alg = "ansi_cprng",
+               .test = alg_test_cprng,
+               .fips_allowed = 1,
+               .suite = {
+                       .cprng = {
+                               .vecs = ansi_cprng_aes_tv_template,
+                               .count = ANSI_CPRNG_AES_TEST_VECTORS
+                       }
+               }
+       }, {
                .alg = "cbc(aes)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1090,6 +1661,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "cbc(des3_ede)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1120,6 +1692,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "ccm(aes)",
                .test = alg_test_aead,
+               .fips_allowed = 1,
                .suite = {
                        .aead = {
                                .enc = {
@@ -1134,7 +1707,8 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "crc32c",
-               .test = alg_test_hash,
+               .test = alg_test_crc32c,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = crc32c_tv_template,
@@ -1142,6 +1716,46 @@ static const struct alg_test_desc alg_test_descs[] = {
                        }
                }
        }, {
+               .alg = "cryptd(__driver-ecb-aes-aesni)",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
+       }, {
+               .alg = "cryptd(__ghash-pclmulqdqni)",
+               .test = alg_test_null,
+               .suite = {
+                       .hash = {
+                               .vecs = NULL,
+                               .count = 0
+                       }
+               }
+       }, {
+               .alg = "ctr(aes)",
+               .test = alg_test_skcipher,
+               .fips_allowed = 1,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = aes_ctr_enc_tv_template,
+                                       .count = AES_CTR_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = aes_ctr_dec_tv_template,
+                                       .count = AES_CTR_DEC_TEST_VECTORS
+                               }
+                       }
+               }
+       }, {
                .alg = "cts(cbc(aes))",
                .test = alg_test_skcipher,
                .suite = {
@@ -1172,8 +1786,24 @@ static const struct alg_test_desc alg_test_descs[] = {
                        }
                }
        }, {
+               .alg = "ecb(__aes-aesni)",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
+       }, {
                .alg = "ecb(aes)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1279,6 +1909,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "ecb(des)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1294,6 +1925,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "ecb(des3_ede)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1429,6 +2061,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "gcm(aes)",
                .test = alg_test_aead,
+               .fips_allowed = 1,
                .suite = {
                        .aead = {
                                .enc = {
@@ -1442,6 +2075,16 @@ static const struct alg_test_desc alg_test_descs[] = {
                        }
                }
        }, {
+               .alg = "ghash",
+               .test = alg_test_hash,
+               .fips_allowed = 1,
+               .suite = {
+                       .hash = {
+                               .vecs = ghash_tv_template,
+                               .count = GHASH_TEST_VECTORS
+                       }
+               }
+       }, {
                .alg = "hmac(md5)",
                .test = alg_test_hash,
                .suite = {
@@ -1471,6 +2114,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "hmac(sha1)",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = hmac_sha1_tv_template,
@@ -1480,6 +2124,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "hmac(sha224)",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = hmac_sha224_tv_template,
@@ -1489,6 +2134,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "hmac(sha256)",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = hmac_sha256_tv_template,
@@ -1498,6 +2144,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "hmac(sha384)",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = hmac_sha384_tv_template,
@@ -1507,6 +2154,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "hmac(sha512)",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = hmac_sha512_tv_template,
@@ -1571,6 +2219,22 @@ static const struct alg_test_desc alg_test_descs[] = {
                        }
                }
        }, {
+               .alg = "ofb(aes)",
+               .test = alg_test_skcipher,
+               .fips_allowed = 1,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = aes_ofb_enc_tv_template,
+                                       .count = AES_OFB_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = aes_ofb_dec_tv_template,
+                                       .count = AES_OFB_DEC_TEST_VECTORS
+                               }
+                       }
+               }
+       }, {
                .alg = "pcbc(fcrypt)",
                .test = alg_test_skcipher,
                .suite = {
@@ -1588,15 +2252,49 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "rfc3686(ctr(aes))",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
-                                       .vecs = aes_ctr_enc_tv_template,
-                                       .count = AES_CTR_ENC_TEST_VECTORS
+                                       .vecs = aes_ctr_rfc3686_enc_tv_template,
+                                       .count = AES_CTR_3686_ENC_TEST_VECTORS
                                },
                                .dec = {
-                                       .vecs = aes_ctr_dec_tv_template,
-                                       .count = AES_CTR_DEC_TEST_VECTORS
+                                       .vecs = aes_ctr_rfc3686_dec_tv_template,
+                                       .count = AES_CTR_3686_DEC_TEST_VECTORS
+                               }
+                       }
+               }
+       }, {
+               .alg = "rfc4106(gcm(aes))",
+               .test = alg_test_aead,
+               .suite = {
+                       .aead = {
+                               .enc = {
+                                       .vecs = aes_gcm_rfc4106_enc_tv_template,
+                                       .count = AES_GCM_4106_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = aes_gcm_rfc4106_dec_tv_template,
+                                       .count = AES_GCM_4106_DEC_TEST_VECTORS
+                               }
+                       }
+               }
+       }, {
+
+
+               .alg = "rfc4309(ccm(aes))",
+               .test = alg_test_aead,
+               .fips_allowed = 1,
+               .suite = {
+                       .aead = {
+                               .enc = {
+                                       .vecs = aes_ccm_rfc4309_enc_tv_template,
+                                       .count = AES_CCM_4309_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = aes_ccm_rfc4309_dec_tv_template,
+                                       .count = AES_CCM_4309_DEC_TEST_VECTORS
                                }
                        }
                }
@@ -1650,6 +2348,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "sha1",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = sha1_tv_template,
@@ -1659,6 +2358,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "sha224",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = sha224_tv_template,
@@ -1668,6 +2368,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "sha256",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = sha256_tv_template,
@@ -1677,6 +2378,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "sha384",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = sha384_tv_template,
@@ -1686,6 +2388,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "sha512",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = sha512_tv_template,
@@ -1720,6 +2423,15 @@ static const struct alg_test_desc alg_test_descs[] = {
                        }
                }
        }, {
+               .alg = "vmac(aes)",
+               .test = alg_test_hash,
+               .suite = {
+                       .hash = {
+                               .vecs = aes_vmac128_tv_template,
+                               .count = VMAC_AES_TEST_VECTORS
+                       }
+               }
+       }, {
                .alg = "wp256",
                .test = alg_test_hash,
                .suite = {
@@ -1758,6 +2470,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "xts(aes)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1770,6 +2483,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "zlib",
+               .test = alg_test_pcomp,
+               .suite = {
+                       .pcomp = {
+                               .comp = {
+                                       .vecs = zlib_comp_tv_template,
+                                       .count = ZLIB_COMP_TEST_VECTORS
+                               },
+                               .decomp = {
+                                       .vecs = zlib_decomp_tv_template,
+                                       .count = ZLIB_DECOMP_TEST_VECTORS
+                               }
+                       }
+               }
        }
 };
 
@@ -1801,6 +2529,7 @@ static int alg_find_test(const char *alg)
 int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
 {
        int i;
+       int j;
        int rc;
 
        if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) {
@@ -1814,60 +2543,47 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
                if (i < 0)
                        goto notest;
 
-               return alg_test_cipher(alg_test_descs + i, driver, type, mask);
+               if (fips_enabled && !alg_test_descs[i].fips_allowed)
+                       goto non_fips_alg;
+
+               rc = alg_test_cipher(alg_test_descs + i, driver, type, mask);
+               goto test_done;
        }
 
        i = alg_find_test(alg);
-       if (i < 0)
+       j = alg_find_test(driver);
+       if (i < 0 && j < 0)
                goto notest;
 
-       rc = alg_test_descs[i].test(alg_test_descs + i, driver,
-                                     type, mask);
+       if (fips_enabled && ((i >= 0 && !alg_test_descs[i].fips_allowed) ||
+                            (j >= 0 && !alg_test_descs[j].fips_allowed)))
+               goto non_fips_alg;
+
+       rc = 0;
+       if (i >= 0)
+               rc |= alg_test_descs[i].test(alg_test_descs + i, driver,
+                                            type, mask);
+       if (j >= 0)
+               rc |= alg_test_descs[j].test(alg_test_descs + j, driver,
+                                            type, mask);
+
+test_done:
        if (fips_enabled && rc)
                panic("%s: %s alg self test failed in fips mode!\n", driver, alg);
 
+       if (fips_enabled && !rc)
+               printk(KERN_INFO "alg: self-tests for %s (%s) passed\n",
+                      driver, alg);
+
        return rc;
 
 notest:
        printk(KERN_INFO "alg: No test for %s (%s)\n", alg, driver);
        return 0;
+non_fips_alg:
+       return -EINVAL;
 }
-EXPORT_SYMBOL_GPL(alg_test);
-
-int __init testmgr_init(void)
-{
-       int i;
-
-       for (i = 0; i < XBUFSIZE; i++) {
-               xbuf[i] = (void *)__get_free_page(GFP_KERNEL);
-               if (!xbuf[i])
-                       goto err_free_xbuf;
-       }
-
-       for (i = 0; i < XBUFSIZE; i++) {
-               axbuf[i] = (void *)__get_free_page(GFP_KERNEL);
-               if (!axbuf[i])
-                       goto err_free_axbuf;
-       }
 
-       return 0;
+#endif /* CONFIG_CRYPTO_MANAGER_DISABLE_TESTS */
 
-err_free_axbuf:
-       for (i = 0; i < XBUFSIZE && axbuf[i]; i++)
-               free_page((unsigned long)axbuf[i]);
-err_free_xbuf:
-       for (i = 0; i < XBUFSIZE && xbuf[i]; i++)
-               free_page((unsigned long)xbuf[i]);
-
-       return -ENOMEM;
-}
-
-void testmgr_exit(void)
-{
-       int i;
-
-       for (i = 0; i < XBUFSIZE; i++)
-               free_page((unsigned long)axbuf[i]);
-       for (i = 0; i < XBUFSIZE; i++)
-               free_page((unsigned long)xbuf[i]);
-}
+EXPORT_SYMBOL_GPL(alg_test);