crypto-tester: Support testing DH groups using DH test vectors
authorMartin Willi <martin@revosec.ch>
Thu, 9 Apr 2015 08:47:03 +0000 (10:47 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 15 Apr 2015 12:37:38 +0000 (14:37 +0200)
src/libstrongswan/crypto/crypto_factory.c
src/libstrongswan/crypto/crypto_tester.c
src/libstrongswan/crypto/crypto_tester.h

index 1bc1ac7..76bfeb2 100644 (file)
@@ -377,6 +377,12 @@ METHOD(crypto_factory_t, create_dh, diffie_hellman_t*,
        {
                if (entry->algo == group)
                {
+                       if (this->test_on_create && group != MODP_CUSTOM &&
+                               !this->tester->test_dh(this->tester, group,
+                                                               entry->create_dh, NULL, default_plugin_name))
+                       {
+                               continue;
+                       }
                        diffie_hellman = entry->create_dh(group, g, p);
                        if (diffie_hellman)
                        {
@@ -692,8 +698,17 @@ METHOD(crypto_factory_t, add_dh, bool,
        private_crypto_factory_t *this, diffie_hellman_group_t group,
        const char *plugin_name, dh_constructor_t create)
 {
-       add_entry(this, this->dhs, group, plugin_name, 0, create);
-       return TRUE;
+       u_int speed = 0;
+
+       if (!this->test_on_add ||
+               this->tester->test_dh(this->tester, group, create,
+                                                         this->bench ? &speed : NULL, plugin_name))
+       {
+               add_entry(this, this->dhs, group, plugin_name, 0, create);
+               return TRUE;
+       }
+       this->test_failures++;
+       return FALSE;
 }
 
 METHOD(crypto_factory_t, remove_dh, void,
@@ -892,6 +907,8 @@ METHOD(crypto_factory_t, add_test_vector, void,
                        return this->tester->add_prf_vector(this->tester, vector);
                case RANDOM_NUMBER_GENERATOR:
                        return this->tester->add_rng_vector(this->tester, vector);
+               case DIFFIE_HELLMAN_GROUP:
+                       return this->tester->add_dh_vector(this->tester, vector);
                default:
                        DBG1(DBG_LIB, "%N test vectors not supported, ignored",
                                 transform_type_names, type);
@@ -1016,6 +1033,7 @@ static u_int verify_registered_algorithms(crypto_factory_t *factory)
        TEST_ALGORITHMS(hasher);
        TEST_ALGORITHMS(prf);
        TEST_ALGORITHMS(rng);
+       TEST_ALGORITHMS(dh);
        this->lock->unlock(this->lock);
        return failures;
 }
index 20f64c3..5607d35 100644 (file)
@@ -68,6 +68,11 @@ struct private_crypto_tester_t {
        linked_list_t *rng;
 
        /**
+        * List of Diffie-Hellman test vectors
+        */
+       linked_list_t *dh;
+
+       /**
         * Is a test vector required to pass a test?
         */
        bool required;
@@ -1155,6 +1160,154 @@ failure:
        return !failed;
 }
 
+/**
+ * Benchmark a DH backend
+ */
+static u_int bench_dh(private_crypto_tester_t *this,
+                                         diffie_hellman_group_t group, dh_constructor_t create)
+{
+       chunk_t pub = chunk_empty, shared = chunk_empty;
+       diffie_hellman_t *dh;
+       struct timespec start;
+       u_int runs;
+
+       runs = 0;
+       start_timing(&start);
+       while (end_timing(&start) < this->bench_time)
+       {
+               dh = create(group);
+               if (!dh)
+               {
+                       return 0;
+               }
+               if (dh->get_my_public_value(dh, &pub) &&
+                       dh->set_other_public_value(dh, pub) &&
+                       dh->get_shared_secret(dh, &shared))
+               {
+                       runs++;
+               }
+               chunk_free(&pub);
+               chunk_free(&shared);
+               dh->destroy(dh);
+       }
+       return runs;
+}
+
+METHOD(crypto_tester_t, test_dh, bool,
+       private_crypto_tester_t *this, diffie_hellman_group_t group,
+       dh_constructor_t create, u_int *speed, const char *plugin_name)
+{
+       enumerator_t *enumerator;
+       dh_test_vector_t *v;
+       bool failed = FALSE;
+       u_int tested = 0;
+
+       enumerator = this->dh->create_enumerator(this->dh);
+       while (enumerator->enumerate(enumerator, &v))
+       {
+               diffie_hellman_t *a, *b;
+               chunk_t apub, bpub, asec, bsec;
+
+               if (v->group != group)
+               {
+                       continue;
+               }
+
+               a = create(group);
+               b = create(group);
+               if (!a || !b)
+               {
+                       DESTROY_IF(a);
+                       DESTROY_IF(b);
+                       failed = TRUE;
+                       tested++;
+                       DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
+                                diffie_hellman_group_names, group, plugin_name);
+                       break;
+               }
+
+               if (!a->set_private_value || !b->set_private_value)
+               {       /* does not support testing */
+                       a->destroy(a);
+                       b->destroy(b);
+                       continue;
+               }
+               failed = TRUE;
+               tested++;
+
+               apub = bpub = asec = bsec = chunk_empty;
+
+               if (!a->set_private_value(a, chunk_create(v->priv_a, v->priv_len)) ||
+                       !b->set_private_value(b, chunk_create(v->priv_b, v->priv_len)))
+               {
+                       goto failure;
+               }
+               if (!a->get_my_public_value(a, &apub) ||
+                       !chunk_equals(apub, chunk_create(v->pub_a, v->pub_len)))
+               {
+                       goto failure;
+               }
+               if (!b->get_my_public_value(b, &bpub) ||
+                       !chunk_equals(bpub, chunk_create(v->pub_b, v->pub_len)))
+               {
+                       goto failure;
+               }
+               if (!a->set_other_public_value(a, bpub) ||
+                       !b->set_other_public_value(b, apub))
+               {
+                       goto failure;
+               }
+               if (!a->get_shared_secret(a, &asec) ||
+                       !chunk_equals(asec, chunk_create(v->shared, v->shared_len)))
+               {
+                       goto failure;
+               }
+               if (!b->get_shared_secret(b, &bsec) ||
+                       !chunk_equals(bsec, chunk_create(v->shared, v->shared_len)))
+               {
+                       goto failure;
+               }
+
+               failed = FALSE;
+failure:
+               a->destroy(a);
+               b->destroy(b);
+               chunk_free(&apub);
+               chunk_free(&bpub);
+               chunk_free(&asec);
+               chunk_free(&bsec);
+               if (failed)
+               {
+                       DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+                                diffie_hellman_group_names, group, plugin_name, get_name(v));
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       if (!tested)
+       {
+               DBG1(DBG_LIB, "%s %N[%s]: no test vectors found / untestable",
+                        this->required ? "disabled" : "enabled ",
+                        diffie_hellman_group_names, group, plugin_name);
+               return !this->required;
+       }
+       if (!failed)
+       {
+               if (speed)
+               {
+                       *speed = bench_dh(this, group, create);
+                       DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
+                                diffie_hellman_group_names, group, plugin_name, tested, *speed);
+               }
+               else
+               {
+                       DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
+                                diffie_hellman_group_names, group, plugin_name, tested);
+               }
+       }
+       return !failed;
+}
+
 METHOD(crypto_tester_t, add_crypter_vector, void,
        private_crypto_tester_t *this, crypter_test_vector_t *vector)
 {
@@ -1191,6 +1344,12 @@ METHOD(crypto_tester_t, add_rng_vector, void,
        this->rng->insert_last(this->rng, vector);
 }
 
+METHOD(crypto_tester_t, add_dh_vector, void,
+       private_crypto_tester_t *this, dh_test_vector_t *vector)
+{
+       this->dh->insert_last(this->dh, vector);
+}
+
 METHOD(crypto_tester_t, destroy, void,
        private_crypto_tester_t *this)
 {
@@ -1200,6 +1359,7 @@ METHOD(crypto_tester_t, destroy, void,
        this->hasher->destroy(this->hasher);
        this->prf->destroy(this->prf);
        this->rng->destroy(this->rng);
+       this->dh->destroy(this->dh);
        free(this);
 }
 
@@ -1218,12 +1378,14 @@ crypto_tester_t *crypto_tester_create()
                        .test_hasher = _test_hasher,
                        .test_prf = _test_prf,
                        .test_rng = _test_rng,
+                       .test_dh = _test_dh,
                        .add_crypter_vector = _add_crypter_vector,
                        .add_aead_vector = _add_aead_vector,
                        .add_signer_vector = _add_signer_vector,
                        .add_hasher_vector = _add_hasher_vector,
                        .add_prf_vector = _add_prf_vector,
                        .add_rng_vector = _add_rng_vector,
+                       .add_dh_vector = _add_dh_vector,
                        .destroy = _destroy,
                },
                .crypter = linked_list_create(),
@@ -1232,6 +1394,7 @@ crypto_tester_t *crypto_tester_create()
                .hasher = linked_list_create(),
                .prf = linked_list_create(),
                .rng = linked_list_create(),
+               .dh = linked_list_create(),
 
                .required = lib->settings->get_bool(lib->settings,
                                                                "%s.crypto_test.required", FALSE, lib->ns),
index add3b1c..6cc9b0d 100644 (file)
@@ -31,6 +31,7 @@ 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 rng_test_vector_t rng_test_vector_t;
+typedef struct dh_test_vector_t dh_test_vector_t;
 
 struct crypter_test_vector_t {
        /** encryption algorithm this vector tests */
@@ -129,6 +130,27 @@ struct rng_test_vector_t {
        void *user;
 };
 
+struct dh_test_vector_t {
+       /** diffie hellman group to test */
+       diffie_hellman_group_t group;
+       /** private value of alice */
+       u_char *priv_a;
+       /** private value of bob */
+       u_char *priv_b;
+       /** length of private values */
+       size_t priv_len;
+       /** expected public value of alice */
+       u_char *pub_a;
+       /** expected public value of bob */
+       u_char *pub_b;
+       /** size of public values */
+       size_t pub_len;
+       /** expected shared secret */
+       u_char *shared;
+       /** size of shared secret */
+       size_t shared_len;
+};
+
 /**
  * Cryptographic primitive testing framework.
  */
@@ -206,6 +228,18 @@ struct crypto_tester_t {
                                         rng_constructor_t create,
                                         u_int *speed, const char *plugin_name);
        /**
+        * Test a Diffie-Hellman implementation.
+        *
+        * @param group                 group to test
+        * @param create                constructor function for the DH backend
+        * @param speed                 speeed test result, NULL to omit
+        * @return                              TRUE if test passed
+        */
+       bool (*test_dh)(crypto_tester_t *this, diffie_hellman_group_t group,
+                                       dh_constructor_t create,
+                                       u_int *speed, const char *plugin_name);
+
+       /**
         * Add a test vector to test a crypter.
         *
         * @param vector                pointer to test vector
@@ -248,6 +282,13 @@ struct crypto_tester_t {
        void (*add_rng_vector)(crypto_tester_t *this, rng_test_vector_t *vector);
 
        /**
+        * Add a test vector to test a Diffie-Hellman backend.
+        *
+        * @param vector                pointer to test vector
+        */
+       void (*add_dh_vector)(crypto_tester_t *this, dh_test_vector_t *vector);
+
+       /**
         * Destroy a crypto_tester_t.
         */
        void (*destroy)(crypto_tester_t *this);