This allows handling DH key generation in the crypto backend files.
_gnutls_dh_set_group(session, g, p);
+ ret = _gnutls_set_dh_pk_params(session, g, p, dh_params->q_bits);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
ret =
- _gnutls_dh_common_print_server_kx(session, g, p,
- dh_params->q_bits, data);
+ _gnutls_dh_common_print_server_kx(session, data);
if (ret < 0) {
gnutls_assert();
}
#include <gnutls_datum.h>
#include <gnutls_x509.h>
#include <gnutls_state.h>
+#include <gnutls_pk.h>
#include <auth/dh_common.h>
#include <algorithms.h>
#include <auth/psk.h>
size_t _n_Y;
int ret;
ssize_t data_size = _data_size;
-
+ gnutls_datum_t tmp_dh_key = {NULL, 0};
+ gnutls_pk_params_st peer_pub;
+
+ gnutls_pk_params_init(&peer_pub);
DECR_LEN(data_size, 2);
n_Y = _gnutls_read_uint16(&data[0]);
_gnutls_dh_set_peer_public(session, session->key.client_Y);
- ret =
- gnutls_calc_dh_key(&session->key.KEY, session->key.client_Y,
- session->key.dh_secret, p);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ peer_pub.params[DH_Y] = session->key.client_Y;
- _gnutls_mpi_release(&session->key.client_Y);
- zrelease_temp_mpi_key(&session->key.dh_secret);
+ /* calculate the key after calculating the message */
+ ret = _gnutls_pk_derive(GNUTLS_PK_DH, &tmp_dh_key, &session->key.dh_params, &peer_pub);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
if (psk_key == NULL) {
- ret =
- _gnutls_mpi_dprint(session->key.KEY,
- &session->key.key);
+ session->key.key.data = tmp_dh_key.data;
+ session->key.key.size = tmp_dh_key.size;
} else { /* In DHE_PSK the key is set differently */
-
- gnutls_datum_t tmp_dh_key;
- ret = _gnutls_mpi_dprint(session->key.KEY, &tmp_dh_key);
- if (ret < 0) {
- gnutls_assert();
- return ret;
- }
-
ret =
_gnutls_set_psk_session_key(session, psk_key,
&tmp_dh_key);
_gnutls_free_temp_key_datum(&tmp_dh_key);
-
}
-
- zrelease_temp_mpi_key(&session->key.KEY);
-
+
if (ret < 0) {
- return ret;
+ gnutls_assert();
+ goto error;
}
- return 0;
+ ret = 0;
+error:
+ _gnutls_mpi_release(&session->key.client_Y);
+ gnutls_pk_params_clear(&session->key.dh_params);
+
+ return ret;
}
int _gnutls_gen_dh_common_client_kx(gnutls_session_t session,
gnutls_buffer_st * data,
gnutls_datum_t * pskkey)
{
- bigint_t x = NULL, Y = NULL;
int ret;
+ gnutls_pk_params_st peer_pub;
+ gnutls_datum_t tmp_dh_key = {NULL, 0};
+
+ gnutls_pk_params_init(&peer_pub);
- ret = gnutls_calc_dh_secret(&Y, &x, session->key.client_g,
- session->key.client_p, 0);
- if (ret < 0) {
- gnutls_assert();
- goto error;
- }
+ ret =
+ _gnutls_pk_generate_keys(GNUTLS_PK_DH, 0,
+ &session->key.dh_params);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
- _gnutls_dh_set_secret_bits(session, _gnutls_mpi_get_nbits(x));
+ _gnutls_dh_set_secret_bits(session, _gnutls_mpi_get_nbits(session->key.dh_params.params[DH_X]));
- ret = _gnutls_buffer_append_mpi(data, 16, Y, 0);
+ ret = _gnutls_buffer_append_mpi(data, 16, session->key.dh_params.params[DH_Y], 0);
if (ret < 0) {
gnutls_assert();
goto error;
}
+
+ peer_pub.params[DH_Y] = session->key.client_Y;
/* calculate the key after calculating the message */
- ret =
- gnutls_calc_dh_key(&session->key.KEY, session->key.client_Y, x,
- session->key.client_p);
+ ret = _gnutls_pk_derive(GNUTLS_PK_DH, &tmp_dh_key, &session->key.dh_params, &peer_pub);
if (ret < 0) {
gnutls_assert();
goto error;
}
- /* THESE SHOULD BE DISCARDED */
- _gnutls_mpi_release(&session->key.client_Y);
- _gnutls_mpi_release(&session->key.client_p);
- _gnutls_mpi_release(&session->key.client_g);
-
if (_gnutls_cipher_suite_get_kx_algo
(session->security_parameters.cipher_suite)
!= GNUTLS_KX_DHE_PSK) {
- ret =
- _gnutls_mpi_dprint(session->key.KEY,
- &session->key.key);
+ session->key.key.data = tmp_dh_key.data;
+ session->key.key.size = tmp_dh_key.size;
} else { /* In DHE_PSK the key is set differently */
-
- gnutls_datum_t tmp_dh_key;
-
- ret = _gnutls_mpi_dprint(session->key.KEY, &tmp_dh_key);
- if (ret < 0) {
- gnutls_assert();
- goto error;
- }
-
ret =
_gnutls_set_psk_session_key(session, pskkey,
&tmp_dh_key);
_gnutls_free_temp_key_datum(&tmp_dh_key);
}
- zrelease_temp_mpi_key(&session->key.KEY);
-
if (ret < 0) {
gnutls_assert();
goto error;
ret = data->length;
error:
- zrelease_temp_mpi_key(&x);
- _gnutls_mpi_release(&Y);
+ gnutls_pk_params_clear(&session->key.dh_params);
return ret;
}
+int _gnutls_set_dh_pk_params(gnutls_session_t session, bigint_t g, bigint_t p,
+ unsigned q_bits)
+{
+ gnutls_pk_params_init(&session->key.dh_params);
+
+ session->key.dh_params.params[DH_G] = _gnutls_mpi_copy(g);
+ if (session->key.dh_params.params[DH_G] == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ session->key.dh_params.params[DH_P] = _gnutls_mpi_copy(p);
+ if (session->key.dh_params.params[DH_P] == NULL) {
+ _gnutls_mpi_release(&session->key.dh_params.params[DH_G]);
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+
+ session->key.dh_params.params_nr = 3; /* include empty q */
+ session->key.dh_params.algo = GNUTLS_PK_DH;
+ session->key.dh_params.flags = q_bits;
+
+ return 0;
+}
+
/* Returns the bytes parsed */
int
_gnutls_proc_dh_common_server_kx(gnutls_session_t session,
uint8_t *data_Y;
int i, bits, ret;
ssize_t data_size = _data_size;
+
+ gnutls_pk_params_init(&session->key.dh_params);
i = 0;
return GNUTLS_E_MPI_SCAN_FAILED;
}
- if (_gnutls_mpi_scan_nz(&session->key.client_g, data_g, _n_g) != 0) {
+ if (_gnutls_mpi_scan_nz(&session->key.dh_params.params[DH_G], data_g, _n_g) != 0) {
gnutls_assert();
return GNUTLS_E_MPI_SCAN_FAILED;
}
- if (_gnutls_mpi_scan_nz(&session->key.client_p, data_p, _n_p) != 0) {
+
+ if (_gnutls_mpi_scan_nz(&session->key.dh_params.params[DH_P], data_p, _n_p) != 0) {
gnutls_assert();
return GNUTLS_E_MPI_SCAN_FAILED;
}
+ session->key.dh_params.params_nr = 3; /* include empty q */
+ session->key.dh_params.algo = GNUTLS_PK_DH;
bits = _gnutls_dh_get_min_prime_bits(session);
if (bits < 0) {
return bits;
}
- if (_gnutls_mpi_get_nbits(session->key.client_p) < (size_t) bits) {
+ if (_gnutls_mpi_get_nbits(session->key.dh_params.params[DH_P]) < (size_t) bits) {
/* the prime used by the peer is not acceptable
*/
gnutls_assert();
_gnutls_debug_log
("Received a prime of %u bits, limit is %u\n",
- (unsigned) _gnutls_mpi_get_nbits(session->key.
- client_p),
+ (unsigned) _gnutls_mpi_get_nbits(session->key.dh_params.params[DH_P]),
(unsigned) bits);
return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
}
- _gnutls_dh_set_group(session, session->key.client_g,
- session->key.client_p);
+ _gnutls_dh_set_group(session, session->key.dh_params.params[DH_G],
+ session->key.dh_params.params[DH_P]);
_gnutls_dh_set_peer_public(session, session->key.client_Y);
ret = n_Y + n_p + n_g + 6;
int
_gnutls_dh_common_print_server_kx(gnutls_session_t session,
- bigint_t g, bigint_t p,
- unsigned int q_bits,
gnutls_buffer_st * data)
{
- bigint_t x, Y;
int ret;
+ unsigned q_bits = session->key.dh_params.flags;
/* Y=g^x mod p */
- ret = gnutls_calc_dh_secret(&Y, &x, g, p, q_bits);
- if (ret < 0) {
- gnutls_assert();
- return ret;
- }
+ ret =
+ _gnutls_pk_generate_keys(GNUTLS_PK_DH, q_bits,
+ &session->key.dh_params);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
- session->key.dh_secret = x;
- _gnutls_dh_set_secret_bits(session, _gnutls_mpi_get_nbits(x));
+ _gnutls_dh_set_secret_bits(session, _gnutls_mpi_get_nbits(session->key.dh_params.params[DH_X]));
- ret = _gnutls_buffer_append_mpi(data, 16, p, 0);
+ ret = _gnutls_buffer_append_mpi(data, 16, session->key.dh_params.params[DH_P], 0);
if (ret < 0) {
gnutls_assert();
goto cleanup;
}
- ret = _gnutls_buffer_append_mpi(data, 16, g, 0);
+ ret = _gnutls_buffer_append_mpi(data, 16, session->key.dh_params.params[DH_G], 0);
if (ret < 0) {
gnutls_assert();
goto cleanup;
}
- ret = _gnutls_buffer_append_mpi(data, 16, Y, 0);
+ ret = _gnutls_buffer_append_mpi(data, 16, session->key.dh_params.params[DH_Y], 0);
if (ret < 0) {
gnutls_assert();
goto cleanup;
}
ret = data->length;
-cleanup:
- _gnutls_mpi_release(&Y);
+cleanup:
return ret;
}
} dh_info_st;
void _gnutls_free_dh_info(dh_info_st * dh);
+int _gnutls_set_dh_pk_params(gnutls_session_t session, bigint_t g, bigint_t p,
+ unsigned q_bits);
int _gnutls_gen_dh_common_client_kx_int(gnutls_session_t,
gnutls_buffer_st *,
gnutls_datum_t * pskkey);
uint8_t * data, size_t _data_size,
bigint_t p, bigint_t g,
gnutls_datum_t * psk_key);
-int _gnutls_dh_common_print_server_kx(gnutls_session_t, bigint_t g,
- bigint_t p, unsigned int q_bits,
+int _gnutls_dh_common_print_server_kx(gnutls_session_t,
gnutls_buffer_st * data);
int _gnutls_proc_dh_common_server_kx(gnutls_session_t session,
uint8_t * data, size_t _data_size);
_gnutls_dh_set_group(session, g, p);
+ ret = _gnutls_set_dh_pk_params(session, g, p, dh_params->q_bits);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
ret =
- _gnutls_dh_common_print_server_kx(session, g, p,
- dh_params->q_bits, data);
+ _gnutls_dh_common_print_server_kx(session, data);
if (ret < 0) {
gnutls_assert();
return ret;
if (ret < 0)
return gnutls_assert_val(ret);
+ ret = _gnutls_set_dh_pk_params(session, g, p, dh_params->q_bits);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
ret =
- _gnutls_dh_common_print_server_kx(session, g, p,
- dh_params->q_bits, data);
+ _gnutls_dh_common_print_server_kx(session, data);
if (ret < 0)
gnutls_assert();
#define B session->key.B
#define _a session->key.a
#define A session->key.A
-#define N session->key.client_p
-#define G session->key.client_g
+#define N session->key.srp_p
+#define G session->key.srp_g
#define V session->key.x
-#define S session->key.KEY
+#define S session->key.srp_key
/* Checks if a%n==0,+1,-1%n which is a fatal srp error.
* Returns a proper error code in that case, and 0 when
zrelease_temp_mpi_key(&session->key.u);
zrelease_temp_mpi_key(&B);
- ret = _gnutls_mpi_dprint(session->key.KEY, &session->key.key);
+ ret = _gnutls_mpi_dprint(session->key.srp_key, &session->key.key);
zrelease_temp_mpi_key(&S);
if (ret < 0) {
zrelease_temp_mpi_key(&session->key.u);
zrelease_temp_mpi_key(&B);
- ret = _gnutls_mpi_dprint(session->key.KEY, &session->key.key);
+ ret = _gnutls_mpi_dprint(session->key.srp_key, &session->key.key);
zrelease_temp_mpi_key(&S);
if (ret < 0) {
/* parameters should not be larger than this limit */
#define DSA_PUBLIC_PARAMS 4
+#define DH_PUBLIC_PARAMS 4
#define RSA_PUBLIC_PARAMS 2
#define ECC_PUBLIC_PARAMS 2
/* parameters should not be larger than this limit */
#define DSA_PRIVATE_PARAMS 5
+#define DH_PRIVATE_PARAMS 5
#define RSA_PRIVATE_PARAMS 8
#define ECC_PRIVATE_PARAMS 3
* [3] is y (public key)
* [4] is x (private key only)
*
+ * DH: as DSA
+ *
* ECC:
* [0] is prime
* [1] is order
#define DSA_Y 3
#define DSA_X 4
+#define DH_P 0
+#define DH_Q 1
+#define DH_G 2
+#define DH_Y 3
+#define DH_X 4
+
#define RSA_MODULUS 0
#define RSA_PUB 1
#define RSA_PRIV 2
#include <gnutls_errors.h>
#include <gnutls_dh.h>
-
-/*
- --Example--
- you: X = g ^ x mod p;
- peer:Y = g ^ y mod p;
-
- your_key = Y ^ x mod p;
- his_key = X ^ y mod p;
-
-// generate our secret and the public value (X) for it
- gnutls_calc_dh_secret(&Y, &X, g, p);
-// now we can calculate the shared secret
- key = gnutls_calc_dh_key(Y, x, g, p);
- _gnutls_mpi_release(x);
- _gnutls_mpi_release(g);
-*/
-
-#define MAX_BITS 18000
-
-/* returns the public value (Y), and the secret (X).
- */
-int
-gnutls_calc_dh_secret(bigint_t * ret_y, bigint_t * ret_x, bigint_t g,
- bigint_t prime, unsigned int q_bits)
-{
- bigint_t e = NULL, x = NULL;
- unsigned int x_size;
- int ret;
-
- if (q_bits == 0) {
- x_size = _gnutls_mpi_get_nbits(prime);
- if (x_size > 0)
- x_size--;
- } else
- x_size = q_bits;
-
- if (x_size > MAX_BITS || x_size == 0) {
- gnutls_assert();
- return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
- }
-
- x = _gnutls_mpi_new(x_size + 64);
- if (x == NULL) {
- gnutls_assert();
- ret = GNUTLS_E_MEMORY_ERROR;
- goto fail;
- }
-
- e = _gnutls_mpi_alloc_like(prime);
- if (e == NULL) {
- gnutls_assert();
- ret = GNUTLS_E_MEMORY_ERROR;
- goto fail;
- }
-
- do {
- if (_gnutls_mpi_random_modp(x, prime, GNUTLS_RND_RANDOM) ==
- NULL) {
- gnutls_assert();
- ret = GNUTLS_E_INTERNAL_ERROR;
- goto fail;
- }
-
- _gnutls_mpi_powm(e, g, x, prime);
- }
- while (_gnutls_mpi_cmp_ui(e, 1) == 0);
-
- *ret_x = x;
- *ret_y = e;
-
- return 0;
-
- fail:
- if (x)
- _gnutls_mpi_release(&x);
- if (e)
- _gnutls_mpi_release(&e);
- return ret;
-
-}
-
-/* returns f^x mod prime
- */
-int
-gnutls_calc_dh_key(bigint_t * key, bigint_t f, bigint_t x, bigint_t prime)
-{
- bigint_t k, ff;
- unsigned int bits;
- int ret;
-
- ff = _gnutls_mpi_modm(NULL, f, prime);
- _gnutls_mpi_add_ui(ff, ff, 1);
-
- /* check if f==0,1,p-1.
- * or (ff=f+1) equivalently ff==1,2,p */
- if ((_gnutls_mpi_cmp_ui(ff, 2) == 0)
- || (_gnutls_mpi_cmp_ui(ff, 1) == 0)
- || (_gnutls_mpi_cmp(ff, prime) == 0)) {
- gnutls_assert();
- ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
- goto cleanup;
- }
-
- bits = _gnutls_mpi_get_nbits(prime);
- if (bits == 0 || bits > MAX_BITS) {
- gnutls_assert();
- ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
- goto cleanup;
- }
-
- k = _gnutls_mpi_alloc_like(prime);
- if (k == NULL) {
- gnutls_assert();
- ret = GNUTLS_E_MEMORY_ERROR;
- goto cleanup;
- }
-
- _gnutls_mpi_powm(k, f, x, prime);
-
- *key = k;
-
- ret = 0;
- cleanup:
- _gnutls_mpi_release(&ff);
-
- return ret;
-}
-
/*-
* _gnutls_get_dh_params - Returns the DH parameters pointer
* @dh_params: is an DH parameters structure, or NULL.
#define GNUTLS_DH_H
const bigint_t *_gnutls_dh_params_to_mpi(gnutls_dh_params_t);
-int gnutls_calc_dh_secret(bigint_t * ret_y, bigint_t * ret_x, bigint_t g,
- bigint_t, unsigned int q_bits);
-int gnutls_calc_dh_key(bigint_t * key, bigint_t f, bigint_t x,
- bigint_t prime);
gnutls_dh_params_t
_gnutls_get_dh_params(gnutls_dh_params_t dh_params,
/* For DH KX */
gnutls_datum_t key;
- bigint_t KEY;
+
+ /* For DH KX */
+ gnutls_pk_params_st dh_params;
bigint_t client_Y;
- bigint_t client_g;
- bigint_t client_p;
- bigint_t dh_secret;
/* for SRP */
+
+ bigint_t srp_key;
+ bigint_t srp_g;
+ bigint_t srp_p;
bigint_t A;
bigint_t B;
bigint_t u;
_gnutls_selected_certs_deinit(session);
gnutls_pk_params_release(&session->key.ecdh_params);
+ gnutls_pk_params_release(&session->key.dh_params);
zrelease_temp_mpi_key(&session->key.ecdh_x);
zrelease_temp_mpi_key(&session->key.ecdh_y);
- zrelease_temp_mpi_key(&session->key.KEY);
zrelease_temp_mpi_key(&session->key.client_Y);
- zrelease_temp_mpi_key(&session->key.client_p);
- zrelease_temp_mpi_key(&session->key.client_g);
+
+ zrelease_temp_mpi_key(&session->key.srp_p);
+ zrelease_temp_mpi_key(&session->key.srp_g);
+ zrelease_temp_mpi_key(&session->key.srp_key);
zrelease_temp_mpi_key(&session->key.u);
zrelease_temp_mpi_key(&session->key.a);
zrelease_temp_mpi_key(&session->key.rsa[0]);
zrelease_temp_mpi_key(&session->key.rsa[1]);
- zrelease_temp_mpi_key(&session->key.dh_secret);
_gnutls_free_temp_key_datum(&session->key.key);
gnutls_free(session);
_dsa_params_to_pubkey(const gnutls_pk_params_st * pk_params,
struct dsa_public_key *pub)
{
- memcpy(&pub->p, pk_params->params[0], sizeof(mpz_t));
- memcpy(&pub->q, pk_params->params[1], sizeof(mpz_t));
- memcpy(&pub->g, pk_params->params[2], sizeof(mpz_t));
+ memcpy(&pub->p, pk_params->params[DSA_P], sizeof(mpz_t));
+
+ if (pk_params->params[DSA_Q])
+ memcpy(&pub->q, pk_params->params[DSA_Q], sizeof(mpz_t));
+ memcpy(&pub->g, pk_params->params[DSA_G], sizeof(mpz_t));
- if (pk_params->params[3] != NULL)
- memcpy(&pub->y, pk_params->params[3], sizeof(mpz_t));
+ if (pk_params->params[DSA_Y] != NULL)
+ memcpy(&pub->y, pk_params->params[DSA_Y], sizeof(mpz_t));
}
static void
return;
}
+#define MAX_DH_BITS 16*1024
+
+/* This is used for DH or ECDH key derivation. In DH for example
+ * it is given the peers Y and our x, and calculates Y^x
+ */
static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
gnutls_datum_t * out,
const gnutls_pk_params_st * priv,
int ret;
switch (algo) {
+ case GNUTLS_PK_DH: {
+ bigint_t f, x, prime;
+ bigint_t k = NULL, ff;
+ unsigned int bits;
+
+ f = pub->params[DH_Y];
+ x = priv->params[DH_X];
+ prime = priv->params[DH_P];
+
+ ff = _gnutls_mpi_modm(NULL, f, prime);
+ _gnutls_mpi_add_ui(ff, ff, 1);
+
+ /* check if f==0,1,p-1.
+ * or (ff=f+1) equivalently ff==1,2,p */
+ if ((_gnutls_mpi_cmp_ui(ff, 2) == 0)
+ || (_gnutls_mpi_cmp_ui(ff, 1) == 0)
+ || (_gnutls_mpi_cmp(ff, prime) == 0)) {
+ gnutls_assert();
+ ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ goto dh_cleanup;
+ }
+
+ /* prevent denial of service */
+ bits = _gnutls_mpi_get_nbits(prime);
+ if (bits == 0 || bits > MAX_DH_BITS) {
+ gnutls_assert();
+ ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ goto dh_cleanup;
+ }
+
+ k = _gnutls_mpi_alloc_like(prime);
+ if (k == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto dh_cleanup;
+ }
+
+ _gnutls_mpi_powm(k, f, x, prime);
+
+ ret = _gnutls_mpi_dprint(k, out);
+ if (ret < 0) {
+ gnutls_assert();
+ goto dh_cleanup;
+ }
+
+ ret = 0;
+dh_cleanup:
+ _gnutls_mpi_release(&ff);
+ zrelease_temp_mpi_key(&k);
+ if (ret < 0)
+ goto cleanup;
+
+ break;
+ }
case GNUTLS_PK_EC:
{
struct ecc_scalar ecc_priv;
if (hash_len > vdata->size) {
gnutls_assert();
_gnutls_debug_log
- ("Security level of algorithm requires hash %s(%d) or better\n",
- _gnutls_mac_get_name(me), hash_len);
+ ("Security level of algorithm requires hash %s(%d) or better (have: %d)\n",
+ _gnutls_mac_get_name(me), hash_len, (int)vdata->size);
hash_len = vdata->size;
}
return ret;
}
+/* To generate a DH key either q must be set in the params or
+ * level should be set to the number of required bits.
+ */
static int
wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
unsigned int level /*bits */ ,
struct dsa_public_key pub;
mpz_t r;
mpz_t x, y;
+ unsigned have_q = 0;
if (algo != params->algo)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
_dsa_params_to_pubkey(params, &pub);
+
+ if (params->params[DSA_Q] != NULL)
+ have_q = 1;
+
+ if (algo == GNUTLS_PK_DSA && have_q == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
mpz_init(r);
mpz_init(x);
mpz_init(y);
- mpz_set(r, pub.q);
- mpz_sub_ui(r, r, 2);
- nettle_mpz_random(x, NULL, rnd_func, r);
- mpz_add_ui(x, x, 1);
+
+ if (have_q) {
+ mpz_set(r, pub.q);
+ mpz_sub_ui(r, r, 2);
+ nettle_mpz_random(x, NULL, rnd_func, r);
+ mpz_add_ui(x, x, 1);
+ } else {
+ if (level == 0)
+ level = mpz_sizeinbase(pub.p, 2);
+ nettle_mpz_random_size(x, NULL, rnd_func, level);
+ }
mpz_powm(y, pub.g, x, pub.p);