From: Nikos Mavrogiannopoulos Date: Thu, 28 Nov 2013 12:41:21 +0000 (+0100) Subject: DH key exchange uses the _gnutls_pk_derive and _gnutls_pk_generate_key functions. X-Git-Tag: gnutls_3_3_0pre0~520^2~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5d8cb9bfb11d4eeeaf1e6a7fe783605b19dc1481;p=thirdparty%2Fgnutls.git DH key exchange uses the _gnutls_pk_derive and _gnutls_pk_generate_key functions. This allows handling DH key generation in the crypto backend files. --- diff --git a/lib/auth/anon.c b/lib/auth/anon.c index 54548300eb..f8b9f0ecb5 100644 --- a/lib/auth/anon.c +++ b/lib/auth/anon.c @@ -96,9 +96,12 @@ gen_anon_server_kx(gnutls_session_t session, gnutls_buffer_st * data) _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(); } diff --git a/lib/auth/dh_common.c b/lib/auth/dh_common.c index 5cc0d4cec0..434515af20 100644 --- a/lib/auth/dh_common.c +++ b/lib/auth/dh_common.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -60,7 +61,10 @@ _gnutls_proc_dh_common_client_kx(gnutls_session_t session, 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]); @@ -74,43 +78,37 @@ _gnutls_proc_dh_common_client_kx(gnutls_session_t session, _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, @@ -124,62 +122,47 @@ _gnutls_gen_dh_common_client_kx_int(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; @@ -188,11 +171,32 @@ _gnutls_gen_dh_common_client_kx_int(gnutls_session_t session, 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, @@ -205,6 +209,8 @@ _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; @@ -240,14 +246,17 @@ _gnutls_proc_dh_common_server_kx(gnutls_session_t session, 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) { @@ -255,20 +264,19 @@ _gnutls_proc_dh_common_server_kx(gnutls_session_t session, 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; @@ -278,45 +286,41 @@ _gnutls_proc_dh_common_server_kx(gnutls_session_t session, 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; } diff --git a/lib/auth/dh_common.h b/lib/auth/dh_common.h index 8bfaaaecff..016588062c 100644 --- a/lib/auth/dh_common.h +++ b/lib/auth/dh_common.h @@ -34,6 +34,8 @@ typedef struct { } 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); @@ -42,8 +44,7 @@ int _gnutls_proc_dh_common_client_kx(gnutls_session_t session, 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); diff --git a/lib/auth/dhe.c b/lib/auth/dhe.c index 546194cdca..6b96f5cad5 100644 --- a/lib/auth/dhe.c +++ b/lib/auth/dhe.c @@ -119,9 +119,12 @@ gen_dhe_server_kx(gnutls_session_t session, gnutls_buffer_st * data) _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; diff --git a/lib/auth/dhe_psk.c b/lib/auth/dhe_psk.c index a6edffa0b4..66e741c9e3 100644 --- a/lib/auth/dhe_psk.c +++ b/lib/auth/dhe_psk.c @@ -222,9 +222,12 @@ gen_dhe_psk_server_kx(gnutls_session_t session, gnutls_buffer_st * data) 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(); diff --git a/lib/auth/srp.c b/lib/auth/srp.c index 520f906cd7..702b94052c 100644 --- a/lib/auth/srp.c +++ b/lib/auth/srp.c @@ -57,10 +57,10 @@ const mod_auth_st srp_auth_struct = { #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 @@ -309,7 +309,7 @@ _gnutls_gen_srp_client_kx(gnutls_session_t session, 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) { @@ -384,7 +384,7 @@ _gnutls_proc_srp_client_kx(gnutls_session_t session, uint8_t * data, 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) { diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h index e273c0da32..a497f56146 100644 --- a/lib/crypto-backend.h +++ b/lib/crypto-backend.h @@ -196,6 +196,7 @@ void gnutls_pk_params_init(gnutls_pk_params_st * p); /* 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 @@ -204,6 +205,7 @@ void gnutls_pk_params_init(gnutls_pk_params_st * p); /* 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 @@ -241,6 +243,8 @@ void gnutls_pk_params_init(gnutls_pk_params_st * p); * [3] is y (public key) * [4] is x (private key only) * + * DH: as DSA + * * ECC: * [0] is prime * [1] is order @@ -263,6 +267,12 @@ void gnutls_pk_params_init(gnutls_pk_params_st * p); #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 diff --git a/lib/gnutls_dh.c b/lib/gnutls_dh.c index da40cffe34..8cffe92e0e 100644 --- a/lib/gnutls_dh.c +++ b/lib/gnutls_dh.c @@ -24,134 +24,6 @@ #include #include - -/* - --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. diff --git a/lib/gnutls_dh.h b/lib/gnutls_dh.h index fec2ec8282..7bc7bec125 100644 --- a/lib/gnutls_dh.h +++ b/lib/gnutls_dh.h @@ -24,10 +24,6 @@ #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, diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 21d2fc938b..1304b8ff67 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -381,12 +381,15 @@ struct gnutls_key_st { /* 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; diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index 3afec2f8e3..7fae162c72 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -467,13 +467,15 @@ void gnutls_deinit(gnutls_session_t session) _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); @@ -486,7 +488,6 @@ void gnutls_deinit(gnutls_session_t session) 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); diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c index 5e9c4f5695..c9591496a0 100644 --- a/lib/nettle/pk.c +++ b/lib/nettle/pk.c @@ -81,12 +81,14 @@ static void _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 @@ -165,6 +167,11 @@ ecc_shared_secret(struct ecc_scalar *private_key, 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, @@ -173,6 +180,60 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo, 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; @@ -442,8 +503,8 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo, 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; } @@ -792,6 +853,9 @@ wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo, 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 */ , @@ -807,19 +871,33 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo, 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);