ARG_WITH_SET([dev-headers], [no], [install strongSwan development headers to directory.])
ARG_WITH_SET([printf-hooks], [auto], [force the use of a specific printf hook implementation (auto, builtin, glibc, vstr).])
ARG_WITH_SET([rubygemdir], ["gem environment gemdir"], [path to install ruby gems to])
+ARG_WITH_SET([testable-ke], [yes], [make key exchange implementations testable by providing a set_seed() method])
if test -n "$PKG_CONFIG"; then
systemdsystemunitdir_default=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
AC_SUBST(UNWINDLIB)
fi
+if test "x$testable_ke" = xyes; then
+ AC_DEFINE([TESTABLE_KE], [1], [Define to 1 if key exchange methods should be testable.])
+fi
+
AM_CONDITIONAL(USE_DEV_HEADERS, [test "x$dev_headers" != xno])
if test x$dev_headers = xyes; then
dev_headers="$includedir/strongswan"
return runs;
}
+#ifdef TESTABLE_KE
+
static bool test_single_ke(key_exchange_method_t method, ke_test_vector_t *v,
ke_constructor_t create)
{
chunk_free(&a_sec);
chunk_free(&b_sec);
DESTROY_IF(drbg);
+ return success;
+}
+
+#else /* TESTABLE_KE */
+
+static bool test_single_ke(key_exchange_method_t method, ke_constructor_t create)
+{
+ key_exchange_t *a = NULL, *b = NULL;
+ chunk_t a_pub, b_pub, a_sec, b_sec;
+ bool success = FALSE;
+ a_pub = b_pub = a_sec = b_sec = chunk_empty;
+ a = create(method);
+ b = create(method);
+ if (!a || !b)
+ {
+ goto failure;
+ }
+ if (!a->get_public_key(a, &a_pub) ||
+ !b->set_public_key(b, a_pub) ||
+ !b->get_shared_secret(b, &b_sec) ||
+ !b->get_public_key(b, &b_pub) ||
+ chunk_equals(a_pub, b_pub) ||
+ !a->set_public_key(a, b_pub) ||
+ !a->get_shared_secret(a, &a_sec) ||
+ !chunk_equals(a_sec, b_sec))
+ {
+ goto failure;
+ }
+ success = TRUE;
+
+failure:
+ DESTROY_IF(a);
+ DESTROY_IF(b);
+ chunk_free(&a_pub);
+ chunk_free(&b_pub);
+ chunk_free(&a_sec);
+ chunk_free(&b_sec);
return success;
}
+#endif /* TESTABLE_KE */
+
METHOD(crypto_tester_t, test_ke, bool,
private_crypto_tester_t *this, key_exchange_method_t method,
ke_constructor_t create, u_int *speed, const char *plugin_name)
{
+#ifdef TESTABLE_KE
enumerator_t *enumerator;
ke_test_vector_t *v;
bool success = TRUE;
key_exchange_method_names, method, plugin_name);
return !this->required;
}
+
if (success)
{
if (speed)
}
}
return success;
+
+#else /* TESTABLE_KE */
+
+ if (method == MODP_CUSTOM)
+ {
+ DBG1(DBG_LIB, "enabled %N[%s]: untestable",
+ key_exchange_method_names, method, plugin_name);
+ return TRUE;
+ }
+
+ if (!test_single_ke(method, create))
+ {
+ DBG1(DBG_LIB, "disabled %N[%s]: failed basic test",
+ key_exchange_method_names, method, plugin_name);
+ return FALSE;
+ }
+
+ if (speed)
+ {
+ *speed = bench_ke(this, method, create);
+ DBG1(DBG_LIB, "enabled %N[%s]: passed basic test (vector tests "
+ "disabled), %d points", key_exchange_method_names, method,
+ plugin_name, *speed);
+ }
+ else
+ {
+ DBG1(DBG_LIB, "enabled %N[%s]: passed basic test (vector tests "
+ "disabled)", key_exchange_method_names, method, plugin_name);
+ }
+ return TRUE;
+
+#endif /* TESTABLE_KE */
}
METHOD(crypto_tester_t, add_crypter_vector, void,
bool (*get_public_key)(key_exchange_t *this, chunk_t *value)
__attribute__((warn_unused_result));
+#ifdef TESTABLE_KE
+
/**
* Set a seed used for the derivation of private key material.
*
bool (*set_seed)(key_exchange_t *this, chunk_t value, drbg_t *drbg)
__attribute__((warn_unused_result));
+#endif /* TESTABLE_KE */
+
/**
* Get the key exchange method used.
*
return TRUE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_botan_diffie_hellman_t *this, chunk_t value, drbg_t *drbg)
{
return load_private_key(this, value);
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, get_shared_secret, bool,
private_botan_diffie_hellman_t *this, chunk_t *secret)
{
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.group = group,
);
+#ifdef TESTABLE_KE
+ this->public.ke.set_seed = _set_seed;
+#endif
+
if (!chunk_to_botan_mp(p, &this->p))
{
destroy(this);
return TRUE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_botan_ec_diffie_hellman_t *this, chunk_t value, drbg_t *drbg)
{
return TRUE;
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, get_shared_secret, bool,
private_botan_ec_diffie_hellman_t *this, chunk_t *secret)
{
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.group = group,
);
+#ifdef TESTABLE_KE
+ this->public.ke.set_seed = _set_seed;
+#endif
+
switch (group)
{
case ECP_256_BIT:
return this->method;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_key_exchange_t *this, chunk_t value, drbg_t *drbg)
{
return TRUE;
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, destroy, void,
private_key_exchange_t *this)
{
.get_public_key = _get_public_key,
.set_public_key = _set_public_key,
.get_shared_secret = _get_shared_secret,
- .set_seed = _set_seed,
.destroy = _destroy,
},
.method = method,
.name = strdup(name),
);
+
+#ifdef TESTABLE_KE
+ this->public.set_seed = _set_seed;
+#endif
+
return &this->public;
}
return TRUE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_diffie_hellman_t *this, chunk_t value, drbg_t *drbg)
{
return TRUE;
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, get_shared_secret, bool,
private_diffie_hellman_t *this, chunk_t *secret)
{
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
);
+#ifdef TESTABLE_KE
+ this->public.set_seed = _set_seed;
+#endif
+
if (!botan_get_rng(&rng, RNG_STRONG))
{
free(this);
return FALSE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_curve25519_dh_t *this, chunk_t value, drbg_t *drbg)
{
return this->drv->set_key(this->drv, value.ptr);
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, get_shared_secret, bool,
private_curve25519_dh_t *this, chunk_t *secret)
{
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.drv = curve25519_drv_probe(),
);
+#ifdef TESTABLE_KE
+ this->public.ke.set_seed = _set_seed;
+#endif
+
if (!this->drv)
{
free(this);
return TRUE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_gcrypt_dh_t *this, chunk_t value, drbg_t *drbg)
{
return !err;
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, get_shared_secret, bool,
private_gcrypt_dh_t *this, chunk_t *secret)
{
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.group = group,
.p_len = p.len,
);
+
+#ifdef TESTABLE_KE
+ this->public.ke.set_seed = _set_seed;
+#endif
+
err = gcry_mpi_scan(&this->p, GCRYMPI_FMT_USG, p.ptr, p.len, NULL);
if (err)
{
return TRUE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_gmp_diffie_hellman_t *this, chunk_t value, drbg_t *drbg)
{
return TRUE;
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, get_shared_secret, bool,
private_gmp_diffie_hellman_t *this, chunk_t *secret)
{
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.p_len = p.len,
);
+#ifdef TESTABLE_KE
+ this->public.ke.set_seed = _set_seed;
+#endif
+
mpz_init(this->p);
mpz_init(this->yb);
mpz_init(this->ya);
return TRUE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_key_exchange_t *this, chunk_t value, drbg_t *drbg)
{
return TRUE;
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, destroy, void,
private_key_exchange_t *this)
{
.get_public_key = _get_public_key,
.set_public_key = _set_public_key,
.get_shared_secret = _get_shared_secret,
- .set_seed = _set_seed,
.destroy = _destroy,
},
.method = method,
.H = lib->crypto->create_hasher(lib->crypto, HASH_SHA3_256),
);
+#ifdef TESTABLE_KE
+ this->public.set_seed = _set_seed;
+#endif
+
if (!this->shake128 || !this->shake256 || !this->G || !this->H)
{
destroy(this);
return TRUE;
}
+#ifdef TESTABLE_KE
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
/**
}
#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* TESTABLE_KE */
METHOD(key_exchange_t, destroy, void,
private_openssl_diffie_hellman_t *this)
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.group = group,
);
+#ifdef TESTABLE_KE
+ this->public.ke.set_seed = _set_seed;
+#endif
+
if (group == MODP_CUSTOM)
{
chunk_t g_chunk, p_chunk;
}
}
+#ifdef TESTABLE_KE
+
/**
* Parse the given private key as BIGNUM and calculate the corresponding public
* key as EC_POINT.
}
#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* TESTABLE_KE */
METHOD(key_exchange_t, destroy, void,
private_openssl_ec_diffie_hellman_t *this)
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.group = group,
);
+#ifdef TESTABLE_KE
+ this->public.ke.set_seed = _set_seed;
+#endif
+
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
this->ec_group = EC_GROUP_new_by_curve_name(curve);
this->key = EVP_EC_gen(OSSL_EC_curve_nid2name(curve));
return openssl_kem_encapsulate(this, value);
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool, private_key_exchange_t *this,
chunk_t ignore, drbg_t *seed)
{
return TRUE;
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, destroy, void, private_key_exchange_t *this)
{
EVP_PKEY_free(this->pkey);
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.group = method
);
+
+#ifdef TESTABLE_KE
+ this->public.set_seed = _set_seed;
+#endif
+
return &this->public;
}
#endif /* OPENSSL_IS_AWSLC */
return TRUE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_key_exchange_t *this, chunk_t value, drbg_t *drbg)
{
return TRUE;
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, get_shared_secret, bool,
private_key_exchange_t *this, chunk_t *secret)
{
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.ke = ke,
.key = key,
);
+
+#ifdef TESTABLE_KE
+ this->public.set_seed = _set_seed;
+#endif
+
return &this->public;
}
return TRUE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_wolfssl_diffie_hellman_t *this, chunk_t value, drbg_t *drbg)
{
return success;
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, get_method, key_exchange_method_t,
private_wolfssl_diffie_hellman_t *this)
{
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.len = p.len,
);
+#ifdef TESTABLE_KE
+ this->public.ke.set_seed = _set_seed;
+#endif
+
if (wc_InitDhKey(&this->dh) != 0)
{
free(this);
return wolfssl_mp_cat(keysize, point->x, y, chunk);
}
+METHOD(key_exchange_t, set_public_key, bool,
+ private_wolfssl_ec_diffie_hellman_t *this, chunk_t value)
+{
+ chunk_t uncomp;
+
+ if (!key_exchange_verify_pubkey(this->group, value))
+ {
+ return FALSE;
+ }
+
+ /* prepend 0x04 to indicate uncompressed point format */
+ uncomp = chunk_cata("cc", chunk_from_chars(0x04), value);
+ if (wc_ecc_import_x963_ex(uncomp.ptr, uncomp.len, &this->pubkey,
+ this->curve_id) != 0)
+ {
+ DBG1(DBG_LIB, "ECDH public value is malformed");
+ return FALSE;
+ }
+
+ if (wc_ecc_check_key(&this->pubkey) != 0)
+ {
+ DBG1(DBG_LIB, "ECDH public value is invalid");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(key_exchange_t, get_public_key, bool,
+ private_wolfssl_ec_diffie_hellman_t *this,chunk_t *value)
+{
+ return ecp2chunk(this->keysize, &this->key.pubkey, value, FALSE);
+}
+
+#ifdef TESTABLE_KE
+
/**
* Perform the elliptic curve scalar multiplication.
*/
return ret == 0;
}
-METHOD(key_exchange_t, set_public_key, bool,
- private_wolfssl_ec_diffie_hellman_t *this, chunk_t value)
-{
- chunk_t uncomp;
-
- if (!key_exchange_verify_pubkey(this->group, value))
- {
- return FALSE;
- }
-
- /* prepend 0x04 to indicate uncompressed point format */
- uncomp = chunk_cata("cc", chunk_from_chars(0x04), value);
- if (wc_ecc_import_x963_ex(uncomp.ptr, uncomp.len, &this->pubkey,
- this->curve_id) != 0)
- {
- DBG1(DBG_LIB, "ECDH public value is malformed");
- return FALSE;
- }
-
- if (wc_ecc_check_key(&this->pubkey) != 0)
- {
- DBG1(DBG_LIB, "ECDH public value is invalid");
- return FALSE;
- }
- return TRUE;
-}
-
-METHOD(key_exchange_t, get_public_key, bool,
- private_wolfssl_ec_diffie_hellman_t *this,chunk_t *value)
-{
- return ecp2chunk(this->keysize, &this->key.pubkey, value, FALSE);
-}
-
METHOD(key_exchange_t, set_seed, bool,
private_wolfssl_ec_diffie_hellman_t *this, chunk_t value, drbg_t *drbg)
{
return success;
}
+#endif /* TESTABLE_KE */
+
/**
* Derive the shared secret
*/
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
- .set_seed = _set_seed,
.get_method = _get_method,
.destroy = _destroy,
},
.group = group,
);
+#ifdef TESTABLE_KE
+ this->public.ke.set_seed = _set_seed;
+#endif
+
if (wc_ecc_init(&this->key) != 0 || wc_ecc_init(&this->pubkey) != 0)
{
DBG1(DBG_LIB, "key init failed, ecdh create failed");
return this->method;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed, bool,
private_key_exchange_t *this, chunk_t value, drbg_t *drbg)
{
return TRUE;
}
+#endif /* TESTABLE_KE */
+
METHOD(key_exchange_t, destroy, void,
private_key_exchange_t *this)
{
.get_public_key = _get_public_key,
.set_public_key = _set_public_key,
.get_shared_secret = _get_shared_secret,
- .set_seed = _set_seed,
.destroy = _destroy,
},
.method = method,
.type = type,
);
+
+#ifdef TESTABLE_KE
+ this->public.set_seed = _set_seed;
+#endif
+
return &this->public;
}
return TRUE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed_25519, bool,
private_diffie_hellman_t *this, chunk_t value, drbg_t *drbg)
{
}
return ret == 0;
}
-
+#endif /* TESTABLE_KE */
#endif /* HAVE_CURVE25519 */
#ifdef HAVE_CURVE448
return TRUE;
}
+#ifdef TESTABLE_KE
+
METHOD(key_exchange_t, set_seed_448, bool,
private_diffie_hellman_t *this, chunk_t value, drbg_t *drbg)
{
return ret == 0;
}
+#endif /* TESTABLE_KE */
#endif /* HAVE_CURVE448 */
METHOD(key_exchange_t, get_method, key_exchange_method_t,
this->public.get_shared_secret = _get_shared_secret_25519;
this->public.set_public_key = _set_public_key_25519;
this->public.get_public_key = _get_public_key_25519;
+#ifdef TESTABLE_KE
this->public.set_seed = _set_seed_25519;
+#endif
if (wc_curve25519_init(&this->key.key25519) != 0 ||
wc_curve25519_init(&this->pub.key25519) != 0)
this->public.get_shared_secret = _get_shared_secret_448;
this->public.set_public_key = _set_public_key_448;
this->public.get_public_key = _get_public_key_448;
+#ifdef TESTABLE_KE
this->public.set_seed = _set_seed_448;
+#endif
if (wc_curve448_init(&this->key.key448) != 0 ||
wc_curve448_init(&this->pub.key448) != 0)