]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
crypto-tester: Add facility to test KDFs
authorTobias Brunner <tobias@strongswan.org>
Thu, 10 Feb 2022 17:30:50 +0000 (18:30 +0100)
committerTobias Brunner <tobias@strongswan.org>
Thu, 14 Apr 2022 16:54:24 +0000 (18:54 +0200)
src/libstrongswan/crypto/crypto_factory.c
src/libstrongswan/crypto/crypto_tester.c
src/libstrongswan/crypto/crypto_tester.h
src/libstrongswan/tests/suites/test_vectors.c

index 3fce7b72b77f796dcf2c9648deab5c16dc93d702..c4c045175c7912889571cd92faea0f11cfb50d36 100644 (file)
@@ -368,6 +368,20 @@ METHOD(crypto_factory_t, create_kdf, kdf_t*,
        {
                if (entry->algo == algo)
                {
+                       if (this->test_on_create)
+                       {
+                               kdf_test_args_t test_args = {};
+
+                               va_start(test_args.args, algo);
+                               if (!this->tester->test_kdf(this->tester, algo,
+                                                                                       entry->create_kdf, &test_args, NULL,
+                                                                                       default_plugin_name))
+                               {
+                                       va_end(test_args.args);
+                                       continue;
+                               }
+                               va_end(test_args.args);
+                       }
                        va_start(args, algo);
                        kdf = entry->create_kdf(algo, args);
                        va_end(args);
@@ -787,8 +801,17 @@ METHOD(crypto_factory_t, add_kdf, bool,
        private_crypto_factory_t *this, key_derivation_function_t algo,
        const char *plugin_name, kdf_constructor_t create)
 {
-       add_entry(this, this->kdfs, algo, plugin_name, 0, create);
-       return TRUE;
+       u_int speed = 0;
+
+       if (!this->test_on_add ||
+               this->tester->test_kdf(this->tester, algo, create, NULL,
+                                                          this->bench ? &speed : NULL, plugin_name))
+       {
+               add_entry(this, this->kdfs, algo, plugin_name, 0, create);
+               return TRUE;
+       }
+       this->test_failures++;
+       return FALSE;
 }
 
 METHOD(crypto_factory_t, remove_kdf, void,
@@ -1255,6 +1278,8 @@ METHOD(crypto_factory_t, add_test_vector, void,
                        return this->tester->add_prf_vector(this->tester, vector);
                case EXTENDED_OUTPUT_FUNCTION:
                        return this->tester->add_xof_vector(this->tester, vector);
+               case KEY_DERIVATION_FUNCTION:
+                       return this->tester->add_kdf_vector(this->tester, vector);
                case DETERMINISTIC_RANDOM_BIT_GENERATOR:
                        return this->tester->add_drbg_vector(this->tester, vector);
                case RANDOM_NUMBER_GENERATOR:
@@ -1318,6 +1343,10 @@ METHOD(enumerator_t, verify_enumerate, bool,
                        *valid = this->tester->test_xof(this->tester, entry->algo,
                                                        entry->create_xof, NULL, entry->plugin_name);
                        break;
+               case KEY_DERIVATION_FUNCTION:
+                       *valid = this->tester->test_kdf(this->tester, entry->algo,
+                                                       entry->create_kdf, NULL, NULL, entry->plugin_name);
+                       break;
                case DETERMINISTIC_RANDOM_BIT_GENERATOR:
                        *valid = this->tester->test_drbg(this->tester, entry->algo,
                                                        entry->create_drbg, NULL, entry->plugin_name);
@@ -1373,6 +1402,9 @@ METHOD(crypto_factory_t, create_verify_enumerator, enumerator_t*,
                case EXTENDED_OUTPUT_FUNCTION:
                        inner = this->xofs->create_enumerator(this->xofs);
                        break;
+               case KEY_DERIVATION_FUNCTION:
+                       inner = this->kdfs->create_enumerator(this->kdfs);
+                       break;
                case DETERMINISTIC_RANDOM_BIT_GENERATOR:
                        inner = this->drbgs->create_enumerator(this->drbgs);
                        break;
index 04ed2288c0d17f982bc721d74fbe3cd8cb575d4f..5fd7d2ba9bf0f163b0beebff425a497b5ab7b83b 100644 (file)
@@ -69,6 +69,11 @@ struct private_crypto_tester_t {
         */
        linked_list_t *xof;
 
+       /**
+        * List of KDF test vectors
+        */
+       linked_list_t *kdf;
+
        /**
         * List of DRBG test vectors
         */
@@ -1186,6 +1191,185 @@ failure:
        return !failed;
 }
 
+
+
+/**
+ * Create a KDF using the given arguments
+ */
+static kdf_t *create_kdf_args(kdf_constructor_t create,
+                                                         key_derivation_function_t alg, ...)
+{
+       va_list args;
+       kdf_t *kdf;
+
+       va_start(args, alg);
+       kdf = create(alg, args);
+       va_end(args);
+       return kdf;
+}
+
+/**
+ * Create a KDF using arguments from the given test vector
+ */
+static kdf_t *create_kdf_vector(kdf_constructor_t create,
+                                                               key_derivation_function_t alg,
+                                                               kdf_test_vector_t *vector)
+{
+       switch (alg)
+       {
+               case KDF_PRF_PLUS:
+                       return create_kdf_args(create, alg, vector->arg.prf);
+               case KDF_UNDEFINED:
+                       break;
+       }
+       return NULL;
+}
+
+/**
+ * Check if the given test vector applies to the passed arguments
+ */
+static bool kdf_vector_applies(key_derivation_function_t alg,
+                                                          kdf_test_args_t *args, kdf_test_vector_t *vector)
+{
+       bool applies = FALSE;
+
+       switch (alg)
+       {
+               case KDF_PRF_PLUS:
+               {
+                       pseudo_random_function_t prf;
+                       VA_ARGS_VGET(args->args, prf);
+                       applies = (prf == vector->arg.prf);
+                       break;
+               }
+               case KDF_UNDEFINED:
+                       break;
+       }
+       return applies;
+}
+
+METHOD(crypto_tester_t, test_kdf, bool,
+       private_crypto_tester_t *this, key_derivation_function_t alg,
+       kdf_constructor_t create, kdf_test_args_t *args, u_int *speed,
+       const char *plugin_name)
+{
+       enumerator_t *enumerator;
+       kdf_test_vector_t *vector;
+       va_list copy;
+       bool failed = FALSE;
+       u_int tested = 0, construction_failed = 0;
+
+       enumerator = this->kdf->create_enumerator(this->kdf);
+       while (enumerator->enumerate(enumerator, &vector))
+       {
+               kdf_t *kdf;
+               chunk_t out = chunk_empty;
+
+               if (vector->alg != alg ||
+                       (args && !kdf_vector_applies(alg, args, vector)))
+               {
+                       continue;
+               }
+
+               tested++;
+               failed = TRUE;
+               if (args)
+               {
+                       va_copy(copy, args->args);
+                       kdf = create(alg, copy);
+                       va_end(copy);
+               }
+               else
+               {
+                       kdf = create_kdf_vector(create, alg, vector);
+               }
+               if (!kdf)
+               {
+                       if (args)
+                       {
+                               DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
+                                        key_derivation_function_names, alg, plugin_name);
+                               break;
+                       }
+                       /* while there could be a problem, the constructor might just not
+                        * be able to create an instance for this test vector, we check
+                        * for that at the end */
+                       construction_failed++;
+                       failed = FALSE;
+                       continue;
+               }
+
+               if (vector->key.len &&
+                       !kdf->set_param(kdf, KDF_PARAM_KEY, vector->key))
+               {
+                       goto failure;
+               }
+               if (vector->salt.len &&
+                       !kdf->set_param(kdf, KDF_PARAM_SALT, vector->salt))
+               {
+                       goto failure;
+               }
+               /* allocated bytes */
+               if (!kdf->allocate_bytes(kdf, vector->out.len, &out))
+               {
+                       goto failure;
+               }
+               if (!chunk_equals(out, vector->out))
+               {
+                       goto failure;
+               }
+               /* bytes to existing buffer */
+               memset(out.ptr, 0, out.len);
+               if (!kdf->get_bytes(kdf, out.len, out.ptr))
+               {
+                       goto failure;
+               }
+               if (!chunk_equals(out, vector->out))
+               {
+                       goto failure;
+               }
+
+               failed = FALSE;
+failure:
+               kdf->destroy(kdf);
+               chunk_free(&out);
+               if (failed)
+               {
+                       DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+                                key_derivation_function_names, alg, plugin_name,
+                                get_name(vector));
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       if (!tested)
+       {
+               DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
+                        this->required ? "disabled" : "enabled ",
+                        key_derivation_function_names, alg, plugin_name);
+               return !this->required;
+       }
+       tested -= construction_failed;
+       if (!tested)
+       {
+               DBG1(DBG_LIB, "%s %N[%s]: unable to apply any available test vectors",
+                        this->required ? "disabled" : "enabled ",
+                        key_derivation_function_names, alg, plugin_name);
+               return !this->required;
+       }
+       if (!failed)
+       {
+               if (speed)
+               {
+                       DBG2(DBG_LIB, "benchmarking for %N is currently not supported",
+                                key_derivation_function_names, alg);
+               }
+               DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
+                        key_derivation_function_names, alg, plugin_name, tested);
+       }
+       return !failed;
+}
+
 /**
  * Benchmark a DRBG
  */
@@ -1622,6 +1806,12 @@ METHOD(crypto_tester_t, add_xof_vector, void,
        this->xof->insert_last(this->xof, vector);
 }
 
+METHOD(crypto_tester_t, add_kdf_vector, void,
+       private_crypto_tester_t *this, kdf_test_vector_t *vector)
+{
+       this->kdf->insert_last(this->kdf, vector);
+}
+
 METHOD(crypto_tester_t, add_drbg_vector, void,
        private_crypto_tester_t *this, drbg_test_vector_t *vector)
 {
@@ -1649,6 +1839,7 @@ METHOD(crypto_tester_t, destroy, void,
        this->hasher->destroy(this->hasher);
        this->prf->destroy(this->prf);
        this->xof->destroy(this->xof);
+       this->kdf->destroy(this->kdf);
        this->drbg->destroy(this->drbg);
        this->rng->destroy(this->rng);
        this->dh->destroy(this->dh);
@@ -1670,6 +1861,7 @@ crypto_tester_t *crypto_tester_create()
                        .test_hasher = _test_hasher,
                        .test_prf = _test_prf,
                        .test_xof = _test_xof,
+                       .test_kdf = _test_kdf,
                        .test_drbg = _test_drbg,
                        .test_rng = _test_rng,
                        .test_dh = _test_dh,
@@ -1679,6 +1871,7 @@ crypto_tester_t *crypto_tester_create()
                        .add_hasher_vector = _add_hasher_vector,
                        .add_prf_vector = _add_prf_vector,
                        .add_xof_vector = _add_xof_vector,
+                       .add_kdf_vector = _add_kdf_vector,
                        .add_drbg_vector = _add_drbg_vector,
                        .add_rng_vector = _add_rng_vector,
                        .add_dh_vector = _add_dh_vector,
@@ -1690,6 +1883,7 @@ crypto_tester_t *crypto_tester_create()
                .hasher = linked_list_create(),
                .prf = linked_list_create(),
                .xof = linked_list_create(),
+               .kdf = linked_list_create(),
                .drbg = linked_list_create(),
                .rng = linked_list_create(),
                .dh = linked_list_create(),
index 04de7915810b0e2ccf70640d623c07fdb6d98592..4e4e623034a8f9eba8a9804778df4384f68b349b 100644 (file)
@@ -32,6 +32,8 @@ typedef struct signer_test_vector_t signer_test_vector_t;
 typedef struct hasher_test_vector_t hasher_test_vector_t;
 typedef struct prf_test_vector_t prf_test_vector_t;
 typedef struct xof_test_vector_t xof_test_vector_t;
+typedef struct kdf_test_vector_t kdf_test_vector_t;
+typedef struct kdf_test_args_t kdf_test_args_t;
 typedef struct drbg_test_vector_t drbg_test_vector_t;
 typedef struct rng_test_vector_t rng_test_vector_t;
 typedef struct dh_test_vector_t dh_test_vector_t;
@@ -130,6 +132,26 @@ struct xof_test_vector_t {
        u_char *out;
 };
 
+struct kdf_test_vector_t {
+       /** kdf algorithm this test vector tests */
+       key_derivation_function_t alg;
+       /** argument passed to constructor, type depends on alg */
+       union {
+               pseudo_random_function_t prf;
+       } arg;
+       /** optional key */
+       chunk_t key;
+       /** optional salt */
+       chunk_t salt;
+       /** expected output */
+       chunk_t out;
+};
+
+struct kdf_test_args_t {
+       /** the arguments used to construct the KDF */
+       va_list args;
+};
+
 struct drbg_test_vector_t {
        /** drbg type this test vector tests */
        drbg_type_t type;
@@ -256,6 +278,22 @@ struct crypto_tester_t {
        bool (*test_xof)(crypto_tester_t *this, ext_out_function_t alg,
                                         xof_constructor_t create,
                                         u_int *speed, const char *plugin_name);
+       /**
+        * Test a KDF algorithm.
+        *
+        * If constructor arguments are passed, only matching test vectors are
+        * tried. Otherwise, all are tried and implementations are allowed to fail
+        * construction with unsupported arguments.
+        *
+        * @param alg                   algorithm to test
+        * @param create                constructor function for the XOF
+        * @param args                  optional arguments to pass to constructor
+        * @param speed                 speed test result, NULL to omit
+        * @return                              TRUE if test passed
+        */
+       bool (*test_kdf)(crypto_tester_t *this, key_derivation_function_t alg,
+                                        kdf_constructor_t create, kdf_test_args_t *args,
+                                        u_int *speed, const char *plugin_name);
        /**
         * Test a DRBG type.
         *
@@ -332,6 +370,13 @@ struct crypto_tester_t {
         */
        void (*add_xof_vector)(crypto_tester_t *this, xof_test_vector_t *vector);
 
+       /**
+        * Add a test vector to test a KDF.
+        *
+        * @param vector                pointer to test vector
+        */
+       void (*add_kdf_vector)(crypto_tester_t *this, kdf_test_vector_t *vector);
+
        /**
         * Add a test vector to test a DRBG.
         *
index 0cc862fe67d14bc3685d95fddeec5ade50948334..78428e065c672802aa939ab932ee08e5edb1ab03 100644 (file)
@@ -29,6 +29,7 @@ static transform_type_t tfs[] = {
        HASH_ALGORITHM,
        PSEUDO_RANDOM_FUNCTION,
        EXTENDED_OUTPUT_FUNCTION,
+       KEY_DERIVATION_FUNCTION,
        DETERMINISTIC_RANDOM_BIT_GENERATOR,
        RANDOM_NUMBER_GENERATOR,
        DIFFIE_HELLMAN_GROUP,