gmp: Move shared secret calculation to get_shared_secret()

This avoids doing costly operations when just setting the public key.
For the same reason the optional extended public key check is moved.
This commit is contained in:
Tobias Brunner
2022-06-29 10:28:50 +02:00
parent 0351b5af3b
commit 0e82d5cc2c
@@ -97,56 +97,30 @@ METHOD(key_exchange_t, set_public_key, bool,
mpz_init(p_min_1); mpz_init(p_min_1);
mpz_sub_ui(p_min_1, this->p, 1); mpz_sub_ui(p_min_1, this->p, 1);
/* this->computed is not reset in order to prevent reuse of this DH
* instance (see below) */
mpz_import(this->yb, value.len, 1, 1, 1, 0, value.ptr); mpz_import(this->yb, value.len, 1, 1, 1, 0, value.ptr);
/* check public value: /* check that the public value y satisfies 1 < y < p-1.
* 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1 * according to RFC 6989, section 2.1, this is enough for the common safe-
* 2. a public value larger or equal the modulus is invalid */ * prime DH groups (i.e. with q=(p-1)/2 being prime), only for those with
if (mpz_cmp_ui(this->yb, 1) > 0 && * small subgroups (22, 23, 24) does the RFC require the extended test but
mpz_cmp(this->yb, p_min_1) < 0) * only if private keys are reused. we never do that anyway and it's
* explicitly prevented in this implementation. so the extended test, which
* optionally happens in get_shared_secret(), is really only useful for full
* NIST SP 800-56A compliance, which only allows the partial check for
* safe-prime groups.
*/
if (mpz_cmp_ui(this->yb, 1) <= 0 ||
mpz_cmp(this->yb, p_min_1) >= 0)
{ {
#ifdef EXTENDED_DH_TEST DBG1(DBG_LIB, "public DH value verification failed: "
/* 3. test if y ^ q mod p = 1, where q = (p - 1)/2. */ "y <= 1 || y >= p - 1");
mpz_t q, one; mpz_clear(p_min_1);
diffie_hellman_params_t *params; return FALSE;
mpz_init(q);
mpz_init(one);
params = diffie_hellman_get_params(this->group);
if (!params->subgroup.len)
{
mpz_fdiv_q_2exp(q, p_min_1, 1);
}
else
{
mpz_import(q, params->subgroup.len, 1, 1, 1, 0, params->subgroup.ptr);
}
mpz_powm(one, this->yb, q, this->p);
mpz_clear(q);
if (mpz_cmp_ui(one, 1) == 0)
{
mpz_powm(this->zz, this->yb, this->xa, this->p);
this->computed = TRUE;
}
else
{
DBG1(DBG_LIB, "public DH value verification failed:"
" y ^ q mod p != 1");
}
mpz_clear(one);
#else
mpz_powm(this->zz, this->yb, this->xa, this->p);
this->computed = TRUE;
#endif
}
else
{
DBG1(DBG_LIB, "public DH value verification failed:"
" y < 2 || y > p - 1 ");
} }
mpz_clear(p_min_1); mpz_clear(p_min_1);
return this->computed; return TRUE;
} }
METHOD(key_exchange_t, get_public_key, bool, METHOD(key_exchange_t, get_public_key, bool,
@@ -175,7 +149,41 @@ METHOD(key_exchange_t, get_shared_secret, bool,
{ {
if (!this->computed) if (!this->computed)
{ {
return FALSE; #ifdef EXTENDED_DH_TEST
/* test if y ^ q mod p = 1, where q = (p - 1)/2 or the actual size of
* the subgroup. as noted above, this check is not really necessary as
* the plugin does not reuse private keys */
mpz_t q, one, p_min_1;
diffie_hellman_params_t *params;
mpz_init(q);
mpz_init(one);
params = diffie_hellman_get_params(this->group);
if (!params->subgroup.len)
{
mpz_init(p_min_1);
mpz_sub_ui(p_min_1, this->p, 1);
mpz_fdiv_q_2exp(q, p_min_1, 1);
mpz_clear(p_min_1);
}
else
{
mpz_import(q, params->subgroup.len, 1, 1, 1, 0, params->subgroup.ptr);
}
mpz_powm(one, this->yb, q, this->p);
mpz_clear(q);
if (mpz_cmp_ui(one, 1) != 0)
{
DBG1(DBG_LIB, "public DH value verification failed: "
"y ^ q mod p != 1");
mpz_clear(one);
return FALSE;
}
mpz_clear(one);
#endif
mpz_powm(this->zz, this->yb, this->xa, this->p);
this->computed = TRUE;
} }
secret->len = this->p_len; secret->len = this->p_len;
secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->zz); secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->zz);