]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - crypto/testmgr.c
Merge branch 'for-4.8/core' of git://git.kernel.dk/linux-block
[karo-tx-linux.git] / crypto / testmgr.c
index 7d4acc4492338921dd1307c1cc4d4a252130b36a..5c9d5a5e7b65182ed1f78b5c0332c5c9b2a328c1 100644 (file)
 #include <crypto/rng.h>
 #include <crypto/drbg.h>
 #include <crypto/akcipher.h>
+#include <crypto/kpp.h>
 
 #include "internal.h"
 
+static bool notests;
+module_param(notests, bool, 0644);
+MODULE_PARM_DESC(notests, "disable crypto self-tests");
+
 #ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
 
 /* a perfect nop */
@@ -116,6 +121,11 @@ struct akcipher_test_suite {
        unsigned int count;
 };
 
+struct kpp_test_suite {
+       struct kpp_testvec *vecs;
+       unsigned int count;
+};
+
 struct alg_test_desc {
        const char *alg;
        int (*test)(const struct alg_test_desc *desc, const char *driver,
@@ -130,6 +140,7 @@ struct alg_test_desc {
                struct cprng_test_suite cprng;
                struct drbg_test_suite drbg;
                struct akcipher_test_suite akcipher;
+               struct kpp_test_suite kpp;
        } suite;
 };
 
@@ -1773,8 +1784,135 @@ static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver,
 
 }
 
-static int do_test_rsa(struct crypto_akcipher *tfm,
-                      struct akcipher_testvec *vecs)
+static int do_test_kpp(struct crypto_kpp *tfm, struct kpp_testvec *vec,
+                      const char *alg)
+{
+       struct kpp_request *req;
+       void *input_buf = NULL;
+       void *output_buf = NULL;
+       struct tcrypt_result result;
+       unsigned int out_len_max;
+       int err = -ENOMEM;
+       struct scatterlist src, dst;
+
+       req = kpp_request_alloc(tfm, GFP_KERNEL);
+       if (!req)
+               return err;
+
+       init_completion(&result.completion);
+
+       err = crypto_kpp_set_secret(tfm, vec->secret, vec->secret_size);
+       if (err < 0)
+               goto free_req;
+
+       out_len_max = crypto_kpp_maxsize(tfm);
+       output_buf = kzalloc(out_len_max, GFP_KERNEL);
+       if (!output_buf) {
+               err = -ENOMEM;
+               goto free_req;
+       }
+
+       /* Use appropriate parameter as base */
+       kpp_request_set_input(req, NULL, 0);
+       sg_init_one(&dst, output_buf, out_len_max);
+       kpp_request_set_output(req, &dst, out_len_max);
+       kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                tcrypt_complete, &result);
+
+       /* Compute public key */
+       err = wait_async_op(&result, crypto_kpp_generate_public_key(req));
+       if (err) {
+               pr_err("alg: %s: generate public key test failed. err %d\n",
+                      alg, err);
+               goto free_output;
+       }
+       /* Verify calculated public key */
+       if (memcmp(vec->expected_a_public, sg_virt(req->dst),
+                  vec->expected_a_public_size)) {
+               pr_err("alg: %s: generate public key test failed. Invalid output\n",
+                      alg);
+               err = -EINVAL;
+               goto free_output;
+       }
+
+       /* Calculate shared secret key by using counter part (b) public key. */
+       input_buf = kzalloc(vec->b_public_size, GFP_KERNEL);
+       if (!input_buf) {
+               err = -ENOMEM;
+               goto free_output;
+       }
+
+       memcpy(input_buf, vec->b_public, vec->b_public_size);
+       sg_init_one(&src, input_buf, vec->b_public_size);
+       sg_init_one(&dst, output_buf, out_len_max);
+       kpp_request_set_input(req, &src, vec->b_public_size);
+       kpp_request_set_output(req, &dst, out_len_max);
+       kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                tcrypt_complete, &result);
+       err = wait_async_op(&result, crypto_kpp_compute_shared_secret(req));
+       if (err) {
+               pr_err("alg: %s: compute shard secret test failed. err %d\n",
+                      alg, err);
+               goto free_all;
+       }
+       /*
+        * verify shared secret from which the user will derive
+        * secret key by executing whatever hash it has chosen
+        */
+       if (memcmp(vec->expected_ss, sg_virt(req->dst),
+                  vec->expected_ss_size)) {
+               pr_err("alg: %s: compute shared secret test failed. Invalid output\n",
+                      alg);
+               err = -EINVAL;
+       }
+
+free_all:
+       kfree(input_buf);
+free_output:
+       kfree(output_buf);
+free_req:
+       kpp_request_free(req);
+       return err;
+}
+
+static int test_kpp(struct crypto_kpp *tfm, const char *alg,
+                   struct kpp_testvec *vecs, unsigned int tcount)
+{
+       int ret, i;
+
+       for (i = 0; i < tcount; i++) {
+               ret = do_test_kpp(tfm, vecs++, alg);
+               if (ret) {
+                       pr_err("alg: %s: test failed on vector %d, err=%d\n",
+                              alg, i + 1, ret);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int alg_test_kpp(const struct alg_test_desc *desc, const char *driver,
+                       u32 type, u32 mask)
+{
+       struct crypto_kpp *tfm;
+       int err = 0;
+
+       tfm = crypto_alloc_kpp(driver, type | CRYPTO_ALG_INTERNAL, mask);
+       if (IS_ERR(tfm)) {
+               pr_err("alg: kpp: Failed to load tfm for %s: %ld\n",
+                      driver, PTR_ERR(tfm));
+               return PTR_ERR(tfm);
+       }
+       if (desc->suite.kpp.vecs)
+               err = test_kpp(tfm, desc->alg, desc->suite.kpp.vecs,
+                              desc->suite.kpp.count);
+
+       crypto_free_kpp(tfm);
+       return err;
+}
+
+static int test_akcipher_one(struct crypto_akcipher *tfm,
+                            struct akcipher_testvec *vecs)
 {
        char *xbuf[XBUFSIZE];
        struct akcipher_request *req;
@@ -1803,6 +1941,7 @@ static int do_test_rsa(struct crypto_akcipher *tfm,
        if (err)
                goto free_req;
 
+       err = -ENOMEM;
        out_len_max = crypto_akcipher_maxsize(tfm);
        outbuf_enc = kzalloc(out_len_max, GFP_KERNEL);
        if (!outbuf_enc)
@@ -1825,17 +1964,18 @@ static int do_test_rsa(struct crypto_akcipher *tfm,
        /* Run RSA encrypt - c = m^e mod n;*/
        err = wait_async_op(&result, crypto_akcipher_encrypt(req));
        if (err) {
-               pr_err("alg: rsa: encrypt test failed. err %d\n", err);
+               pr_err("alg: akcipher: encrypt test failed. err %d\n", err);
                goto free_all;
        }
        if (req->dst_len != vecs->c_size) {
-               pr_err("alg: rsa: encrypt test failed. Invalid output len\n");
+               pr_err("alg: akcipher: encrypt test failed. Invalid output len\n");
                err = -EINVAL;
                goto free_all;
        }
        /* verify that encrypted message is equal to expected */
        if (memcmp(vecs->c, outbuf_enc, vecs->c_size)) {
-               pr_err("alg: rsa: encrypt test failed. Invalid output\n");
+               pr_err("alg: akcipher: encrypt test failed. Invalid output\n");
+               hexdump(outbuf_enc, vecs->c_size);
                err = -EINVAL;
                goto free_all;
        }
@@ -1863,18 +2003,22 @@ static int do_test_rsa(struct crypto_akcipher *tfm,
        /* Run RSA decrypt - m = c^d mod n;*/
        err = wait_async_op(&result, crypto_akcipher_decrypt(req));
        if (err) {
-               pr_err("alg: rsa: decrypt test failed. err %d\n", err);
+               pr_err("alg: akcipher: decrypt test failed. err %d\n", err);
                goto free_all;
        }
        out_len = req->dst_len;
-       if (out_len != vecs->m_size) {
-               pr_err("alg: rsa: decrypt test failed. Invalid output len\n");
+       if (out_len < vecs->m_size) {
+               pr_err("alg: akcipher: decrypt test failed. "
+                      "Invalid output len %u\n", out_len);
                err = -EINVAL;
                goto free_all;
        }
        /* verify that decrypted message is equal to the original msg */
-       if (memcmp(vecs->m, outbuf_dec, vecs->m_size)) {
-               pr_err("alg: rsa: decrypt test failed. Invalid output\n");
+       if (memchr_inv(outbuf_dec, 0, out_len - vecs->m_size) ||
+           memcmp(vecs->m, outbuf_dec + out_len - vecs->m_size,
+                  vecs->m_size)) {
+               pr_err("alg: akcipher: decrypt test failed. Invalid output\n");
+               hexdump(outbuf_dec, out_len);
                err = -EINVAL;
        }
 free_all:
@@ -1887,28 +2031,22 @@ free_xbuf:
        return err;
 }
 
-static int test_rsa(struct crypto_akcipher *tfm, struct akcipher_testvec *vecs,
-                   unsigned int tcount)
+static int test_akcipher(struct crypto_akcipher *tfm, const char *alg,
+                        struct akcipher_testvec *vecs, unsigned int tcount)
 {
+       const char *algo =
+               crypto_tfm_alg_driver_name(crypto_akcipher_tfm(tfm));
        int ret, i;
 
        for (i = 0; i < tcount; i++) {
-               ret = do_test_rsa(tfm, vecs++);
-               if (ret) {
-                       pr_err("alg: rsa: test failed on vector %d, err=%d\n",
-                              i + 1, ret);
-                       return ret;
-               }
-       }
-       return 0;
-}
-
-static int test_akcipher(struct crypto_akcipher *tfm, const char *alg,
-                        struct akcipher_testvec *vecs, unsigned int tcount)
-{
-       if (strncmp(alg, "rsa", 3) == 0)
-               return test_rsa(tfm, vecs, tcount);
+               ret = test_akcipher_one(tfm, vecs++);
+               if (!ret)
+                       continue;
 
+               pr_err("alg: akcipher: test %d failed for %s, err=%d\n",
+                      i + 1, algo, ret);
+               return ret;
+       }
        return 0;
 }
 
@@ -2724,6 +2862,16 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "dh",
+               .test = alg_test_kpp,
+               .fips_allowed = 1,
+               .suite = {
+                       .kpp = {
+                               .vecs = dh_tv_template,
+                               .count = DH_TEST_VECTORS
+                       }
+               }
        }, {
                .alg = "digest_null",
                .test = alg_test_null,
@@ -3152,6 +3300,16 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "ecdh",
+               .test = alg_test_kpp,
+               .fips_allowed = 1,
+               .suite = {
+                       .kpp = {
+                               .vecs = ecdh_tv_template,
+                               .count = ECDH_TEST_VECTORS
+                       }
+               }
        }, {
                .alg = "gcm(aes)",
                .test = alg_test_aead,
@@ -3244,6 +3402,46 @@ static const struct alg_test_desc alg_test_descs[] = {
                                .count = HMAC_SHA256_TEST_VECTORS
                        }
                }
+       }, {
+               .alg = "hmac(sha3-224)",
+               .test = alg_test_hash,
+               .fips_allowed = 1,
+               .suite = {
+                       .hash = {
+                               .vecs = hmac_sha3_224_tv_template,
+                               .count = HMAC_SHA3_224_TEST_VECTORS
+                       }
+               }
+       }, {
+               .alg = "hmac(sha3-256)",
+               .test = alg_test_hash,
+               .fips_allowed = 1,
+               .suite = {
+                       .hash = {
+                               .vecs = hmac_sha3_256_tv_template,
+                               .count = HMAC_SHA3_256_TEST_VECTORS
+                       }
+               }
+       }, {
+               .alg = "hmac(sha3-384)",
+               .test = alg_test_hash,
+               .fips_allowed = 1,
+               .suite = {
+                       .hash = {
+                               .vecs = hmac_sha3_384_tv_template,
+                               .count = HMAC_SHA3_384_TEST_VECTORS
+                       }
+               }
+       }, {
+               .alg = "hmac(sha3-512)",
+               .test = alg_test_hash,
+               .fips_allowed = 1,
+               .suite = {
+                       .hash = {
+                               .vecs = hmac_sha3_512_tv_template,
+                               .count = HMAC_SHA3_512_TEST_VECTORS
+                       }
+               }
        }, {
                .alg = "hmac(sha384)",
                .test = alg_test_hash,
@@ -3654,6 +3852,46 @@ static const struct alg_test_desc alg_test_descs[] = {
                                .count = SHA256_TEST_VECTORS
                        }
                }
+       }, {
+               .alg = "sha3-224",
+               .test = alg_test_hash,
+               .fips_allowed = 1,
+               .suite = {
+                       .hash = {
+                               .vecs = sha3_224_tv_template,
+                               .count = SHA3_224_TEST_VECTORS
+                       }
+               }
+       }, {
+               .alg = "sha3-256",
+               .test = alg_test_hash,
+               .fips_allowed = 1,
+               .suite = {
+                       .hash = {
+                               .vecs = sha3_256_tv_template,
+                               .count = SHA3_256_TEST_VECTORS
+                       }
+               }
+       }, {
+               .alg = "sha3-384",
+               .test = alg_test_hash,
+               .fips_allowed = 1,
+               .suite = {
+                       .hash = {
+                               .vecs = sha3_384_tv_template,
+                               .count = SHA3_384_TEST_VECTORS
+                       }
+               }
+       }, {
+               .alg = "sha3-512",
+               .test = alg_test_hash,
+               .fips_allowed = 1,
+               .suite = {
+                       .hash = {
+                               .vecs = sha3_512_tv_template,
+                               .count = SHA3_512_TEST_VECTORS
+                       }
+               }
        }, {
                .alg = "sha384",
                .test = alg_test_hash,
@@ -3885,6 +4123,11 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
        int j;
        int rc;
 
+       if (!fips_enabled && notests) {
+               printk_once(KERN_INFO "alg: self-tests disabled\n");
+               return 0;
+       }
+
        alg_test_descs_check_order();
 
        if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) {