diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-11-11 13:20:20 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-11-11 13:27:24 +0100 |
commit | 12a28f4fa86e8420bdaeafba0fddfbd028a446ee (patch) | |
tree | e0cacf49eb66762e2bf36b17265d70925db8fb4a | |
parent | 60004868649f8731603ed2803b1fb1336e5f42b1 (diff) | |
download | gnutls-12a28f4fa86e8420bdaeafba0fddfbd028a446ee.tar.gz |
Added gnutls_x509_privkey_verify_params() which verifies the parameters of a private key. Added test case for private key generation.
-rw-r--r-- | lib/crypto-backend.h | 17 | ||||
-rw-r--r-- | lib/gnutls_errors.c | 2 | ||||
-rw-r--r-- | lib/gnutls_pk.c | 35 | ||||
-rw-r--r-- | lib/gnutls_pk.h | 3 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 1 | ||||
-rw-r--r-- | lib/includes/gnutls/x509.h | 1 | ||||
-rw-r--r-- | lib/libgnutls.map | 1 | ||||
-rw-r--r-- | lib/nettle/pk.c | 203 | ||||
-rw-r--r-- | lib/x509/privkey.c | 28 | ||||
-rw-r--r-- | src/certtool.c | 9 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/keygen.c | 102 |
12 files changed, 355 insertions, 49 deletions
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h index 389e025c67..ed89deb39d 100644 --- a/lib/crypto-backend.h +++ b/lib/crypto-backend.h @@ -255,6 +255,21 @@ #define ECC_Y 7 #define ECC_K 8 +#define DSA_P 0 +#define DSA_Q 1 +#define DSA_G 2 +#define DSA_Y 3 +#define DSA_X 4 + +#define RSA_MODULUS 0 +#define RSA_PUB 1 +#define RSA_PRIV 2 +#define RSA_PRIME1 3 +#define RSA_PRIME2 4 +#define RSA_COEF 5 +#define RSA_E1 6 +#define RSA_E2 7 + /** * gnutls_direction_t: * @GNUTLS_IMPORT: Import direction. @@ -286,6 +301,8 @@ int (*verify) (gnutls_pk_algorithm_t, const gnutls_datum_t * data, const gnutls_datum_t * signature, const gnutls_pk_params_st * pub); + int (*verify_params) (gnutls_pk_algorithm_t, + const gnutls_pk_params_st * pub); int (*generate) (gnutls_pk_algorithm_t, unsigned int nbits, gnutls_pk_params_st *); /* this function should convert params to ones suitable diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index 0084a88da8..b978d1d247 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -176,6 +176,8 @@ static const gnutls_error_entry error_algorithms[] = { ERROR_ENTRY (N_("The cookie was bad."), GNUTLS_E_BAD_COOKIE, 1), ERROR_ENTRY (N_("An illegal parameter has been received."), GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 1), + ERROR_ENTRY (N_("An illegal parameter was found."), + GNUTLS_E_ILLEGAL_PARAMETER, 1), ERROR_ENTRY (N_("Error while reading file."), GNUTLS_E_FILE_ERROR, 1), ERROR_ENTRY (N_("ASN1 parser: Element was not found."), diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c index e80c38092a..59eb9478c5 100644 --- a/lib/gnutls_pk.c +++ b/lib/gnutls_pk.c @@ -489,41 +489,6 @@ gnutls_pk_params_release (gnutls_pk_params_st * p) } int -_gnutls_calc_rsa_exp (gnutls_pk_params_st* params) -{ - bigint_t tmp = _gnutls_mpi_alloc_like (params->params[0]); - - if (params->params_nr < RSA_PRIVATE_PARAMS - 2) - { - gnutls_assert (); - return GNUTLS_E_INTERNAL_ERROR; - } - - if (tmp == NULL) - { - gnutls_assert (); - return GNUTLS_E_MEMORY_ERROR; - } - - /* [6] = d % p-1, [7] = d % q-1 */ - _gnutls_mpi_sub_ui (tmp, params->params[3], 1); - params->params[6] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp); - - _gnutls_mpi_sub_ui (tmp, params->params[4], 1); - params->params[7] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp); - - _gnutls_mpi_release (&tmp); - - if (params->params[7] == NULL || params->params[6] == NULL) - { - gnutls_assert (); - return GNUTLS_E_MEMORY_ERROR; - } - - return 0; -} - -int _gnutls_pk_get_hash_algorithm (gnutls_pk_algorithm_t pk, gnutls_pk_params_st* params, gnutls_digest_algorithm_t * dig, diff --git a/lib/gnutls_pk.h b/lib/gnutls_pk.h index 6c192da471..26a91acc30 100644 --- a/lib/gnutls_pk.h +++ b/lib/gnutls_pk.h @@ -30,6 +30,7 @@ extern gnutls_crypto_pk_st _gnutls_pk_ops; #define _gnutls_pk_decrypt( algo, ciphertext, plaintext, params) _gnutls_pk_ops.decrypt( algo, ciphertext, plaintext, params) #define _gnutls_pk_sign( algo, sig, data, params) _gnutls_pk_ops.sign( algo, sig, data, params) #define _gnutls_pk_verify( algo, data, sig, params) _gnutls_pk_ops.verify( algo, data, sig, params) +#define _gnutls_pk_verify_params( algo, params) _gnutls_pk_ops.verify_params( algo, params) #define _gnutls_pk_derive( algo, out, pub, priv) _gnutls_pk_ops.derive( algo, out, pub, priv) #define _gnutls_pk_generate( algo, bits, priv) _gnutls_pk_ops.generate( algo, bits, priv) @@ -65,8 +66,6 @@ int _gnutls_decode_ber_rs (const gnutls_datum_t * sig_value, bigint_t * r, bigint_t * s); -int _gnutls_calc_rsa_exp (gnutls_pk_params_st*); - int _gnutls_pk_get_hash_algorithm (gnutls_pk_algorithm_t pk, gnutls_pk_params_st*, gnutls_digest_algorithm_t * dig, diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 77dd47ef08..f6395e203e 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1793,6 +1793,7 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session); #define GNUTLS_E_ECC_UNSUPPORTED_CURVE -322 #define GNUTLS_E_PKCS11_REQUESTED_OBJECT_NOT_AVAILBLE -323 #define GNUTLS_E_CERTIFICATE_LIST_UNSORTED -324 +#define GNUTLS_E_ILLEGAL_PARAMETER -325 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250 diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h index 55fdd317c9..2ade033d95 100644 --- a/lib/includes/gnutls/x509.h +++ b/lib/includes/gnutls/x509.h @@ -735,6 +735,7 @@ extern "C" int gnutls_x509_privkey_generate (gnutls_x509_privkey_t key, gnutls_pk_algorithm_t algo, unsigned int bits, unsigned int flags); + int gnutls_x509_privkey_verify_params (gnutls_x509_privkey_t key); int gnutls_x509_privkey_export (gnutls_x509_privkey_t key, gnutls_x509_crt_fmt_t format, diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 813a3cda8e..807c94ec6c 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -724,6 +724,7 @@ GNUTLS_3_0_0 { gnutls_srp_3072_group_prime; gnutls_srp_4096_group_generator; gnutls_srp_4096_group_prime; + gnutls_x509_privkey_verify_params; } GNUTLS_2_12; GNUTLS_PRIVATE { diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c index c56288ed17..5221aa66f0 100644 --- a/lib/nettle/pk.c +++ b/lib/nettle/pk.c @@ -136,7 +136,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo, gnutls_datum_t * o out->data = NULL; if (is_supported_curve(curve) == 0) - return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES); + return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); _ecc_params_to_pubkey(pub, &ecc_pub); _ecc_params_to_privkey(priv, &ecc_priv); @@ -792,7 +792,7 @@ rsa_fail: st = _gnutls_ecc_curve_get_params(level); if (st == NULL) - return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES); + return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); tls_ecc_set.size = st->size; tls_ecc_set.prime = st->prime; @@ -855,6 +855,194 @@ fail: return ret; } +static int +wrap_nettle_pk_verify_params (gnutls_pk_algorithm_t algo, + const gnutls_pk_params_st * params) +{ + int ret; + + switch (algo) + { + case GNUTLS_PK_RSA: + { + bigint_t t1 = NULL, t2 = NULL; + + if (params->params_nr != RSA_PRIVATE_PARAMS) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + t1 = _gnutls_mpi_new (256); + if (t1 == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + _gnutls_mpi_mulm (t1, params->params[RSA_PRIME1], params->params[RSA_PRIME2], params->params[RSA_MODULUS]); + if (_gnutls_mpi_cmp_ui(t1, 0) != 0) + { + ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + goto rsa_cleanup; + } + + mpz_invert (TOMPZ(t1), TOMPZ (params->params[RSA_PRIME2]), TOMPZ (params->params[RSA_PRIME1])); + if (_gnutls_mpi_cmp(t1, params->params[RSA_COEF]) != 0) + { + ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + goto rsa_cleanup; + } + + /* [RSA_PRIME1] = d % p-1, [RSA_PRIME2] = d % q-1 */ + _gnutls_mpi_sub_ui (t1, params->params[RSA_PRIME1], 1); + t2 = _gnutls_mpi_mod (params->params[RSA_PRIV], t1); + if (t2 == NULL) + { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto rsa_cleanup; + } + + if (_gnutls_mpi_cmp(params->params[RSA_E1], t2) != 0) + { + ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + goto rsa_cleanup; + } + + _gnutls_mpi_sub_ui (t1, params->params[RSA_PRIME2], 1); + _gnutls_mpi_release(&t2); + + t2 = _gnutls_mpi_mod (params->params[RSA_PRIV], t1); + if (t2 == NULL) + { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto rsa_cleanup; + } + + if (_gnutls_mpi_cmp(params->params[RSA_E2], t2) != 0) + { + ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + goto rsa_cleanup; + } + + ret = 0; + +rsa_cleanup: + _gnutls_mpi_release(&t1); + _gnutls_mpi_release(&t2); + } + + break; + case GNUTLS_PK_DSA: + { + bigint_t t1 = NULL; + + if (params->params_nr != DSA_PRIVATE_PARAMS) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + t1 = _gnutls_mpi_new (256); + if (t1 == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + _gnutls_mpi_powm (t1, params->params[DSA_G], params->params[DSA_X], params->params[DSA_P]); + + if (_gnutls_mpi_cmp(t1, params->params[DSA_Y]) != 0) + { + ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + goto dsa_cleanup; + } + + ret = 0; + +dsa_cleanup: + _gnutls_mpi_release(&t1); + } + + break; + case GNUTLS_PK_ECC: + { + int curve = params->flags; + ecc_key ecc_priv; + ecc_point *R; + ecc_point zero; + + if (params->params_nr != ECC_PRIVATE_PARAMS) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + if (is_supported_curve(curve) == 0) + return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); + + _ecc_params_to_privkey(params, &ecc_priv); + R = ecc_new_point(); + + /* verify that x,y lie on the curve */ + ret = ecc_projective_check_point(&ecc_priv.pubkey, TOMPZ(params->params[ECC_B]), params->params[ECC_PRIME]); + if (ret != 0) + { + ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + goto ecc_cleanup; + } + + memcpy(&zero.x, ecc_priv.Gx, sizeof(mpz_t)); + memcpy(&zero.y, ecc_priv.Gy, sizeof(mpz_t)); + memcpy(&zero.z, ecc_priv.pubkey.z, sizeof(mpz_t)); /* z = 1 */ + + /* verify that k*(Gx,Gy)=(x,y) */ + ret = ecc_mulmod(ecc_priv.k, &zero, R, TOMPZ(params->params[ECC_A]), TOMPZ(params->params[ECC_PRIME]), 1); + if (ret != 0) + { + ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + goto ecc_cleanup; + } + + if (mpz_cmp(ecc_priv.pubkey.x, R->x) != 0 || mpz_cmp(ecc_priv.pubkey.y, R->y) != 0) + { + ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + goto ecc_cleanup; + } + + ret = 0; + +ecc_cleanup: + _ecc_params_clear(&ecc_priv); + ecc_del_point(R); + } + break; + default: + ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + + return ret; +} + +static int calc_rsa_exp (gnutls_pk_params_st* params) +{ + bigint_t tmp = _gnutls_mpi_alloc_like (params->params[0]); + + if (params->params_nr < RSA_PRIVATE_PARAMS - 2) + { + gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + if (tmp == NULL) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + /* [6] = d % p-1, [7] = d % q-1 */ + _gnutls_mpi_sub_ui (tmp, params->params[3], 1); + params->params[6] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp); + + _gnutls_mpi_sub_ui (tmp, params->params[4], 1); + params->params[7] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp); + + _gnutls_mpi_release (&tmp); + + if (params->params[7] == NULL || params->params[6] == NULL) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + return 0; +} + static int wrap_nettle_pk_fixup (gnutls_pk_algorithm_t algo, @@ -870,14 +1058,14 @@ wrap_nettle_pk_fixup (gnutls_pk_algorithm_t algo, * old but it seemed some of the shipped example private * keys were as old. */ - mpz_invert (TOMPZ (params->params[5]), - TOMPZ (params->params[4]), TOMPZ (params->params[3])); + mpz_invert (TOMPZ (params->params[RSA_COEF]), + TOMPZ (params->params[RSA_PRIME2]), TOMPZ (params->params[RSA_PRIME1])); /* calculate exp1 [6] and exp2 [7] */ - _gnutls_mpi_release (¶ms->params[6]); - _gnutls_mpi_release (¶ms->params[7]); + _gnutls_mpi_release (¶ms->params[RSA_E1]); + _gnutls_mpi_release (¶ms->params[RSA_E2]); - result = _gnutls_calc_rsa_exp (params); + result = calc_rsa_exp (params); if (result < 0) { gnutls_assert (); @@ -896,6 +1084,7 @@ gnutls_crypto_pk_st _gnutls_pk_ops = { .decrypt = _wrap_nettle_pk_decrypt, .sign = _wrap_nettle_pk_sign, .verify = _wrap_nettle_pk_verify, + .verify_params = wrap_nettle_pk_verify_params, .generate = wrap_nettle_pk_generate_params, .pk_fixup_private_params = wrap_nettle_pk_fixup, .derive = _wrap_nettle_pk_derive, diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c index 75e59bd497..8e42dd4c17 100644 --- a/lib/x509/privkey.c +++ b/lib/x509/privkey.c @@ -1306,12 +1306,10 @@ gnutls_x509_privkey_export_dsa_raw (gnutls_x509_privkey_t key, return 0; } - - /** * gnutls_x509_privkey_generate: * @key: should contain a #gnutls_x509_privkey_t structure - * @algo: is one of RSA or DSA. + * @algo: is one of the algorithms in #gnutls_pk_algorithm_t. * @bits: the size of the modulus * @flags: unused for now. Must be 0. * @@ -1366,6 +1364,30 @@ cleanup: } /** + * gnutls_x509_privkey_verify_params: + * @key: should contain a #gnutls_x509_privkey_t structure + * + * This function will verify the private key parameters. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + **/ +int +gnutls_x509_privkey_verify_params (gnutls_x509_privkey_t key) +{ + int ret; + + ret = _gnutls_pk_verify_params (key->pk_algorithm, &key->params); + if (ret < 0) + { + gnutls_assert (); + return ret; + } + + return 0; +} + +/** * gnutls_x509_privkey_get_key_id: * @key: Holds the key * @flags: should be 0 for now diff --git a/src/certtool.c b/src/certtool.c index d60f5eb7c4..1988aff0a4 100644 --- a/src/certtool.c +++ b/src/certtool.c @@ -222,6 +222,10 @@ generate_private_key_int (void) if (ret < 0) error (EXIT_FAILURE, 0, "privkey_generate: %s", gnutls_strerror (ret)); + ret = gnutls_x509_privkey_verify_params (key); + if (ret < 0) + error (EXIT_FAILURE, 0, "privkey_verify_params: %s", gnutls_strerror (ret)); + return key; } @@ -1737,9 +1741,12 @@ privkey_info (void) if (ret < 0) error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret)); - privkey_info_int (key); + ret = gnutls_x509_privkey_verify_params (key); + if (ret < 0) + fprintf (outfile, "\n** Private key parameters validation failed **\n\n"); + if (info.fix_key != 0) { ret = gnutls_x509_privkey_fix (key); diff --git a/tests/Makefile.am b/tests/Makefile.am index 13b8f7c87e..00d17be95d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -64,7 +64,7 @@ ctests = mini-deflate simple gc set_pkcs12_cred certder certuniqueid \ crq_apis init_roundtrip pkcs12_s2k_pem dn2 mini-eagain \ nul-in-x509-names x509_altname pkcs12_encode mini-x509 \ mini-x509-rehandshake rng-fork mini-eagain-dtls cipher-test \ - x509cert x509cert-tl infoaccess #gendh + x509cert x509cert-tl infoaccess keygen #gendh #gendh is out because it is too slow in valgrind if ENABLE_OPENSSL diff --git a/tests/keygen.c b/tests/keygen.c new file mode 100644 index 0000000000..aa6365ed2f --- /dev/null +++ b/tests/keygen.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + * + * Author: David Marín Carreño + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "utils.h" + +static void +tls_log_func (int level, const char *str) +{ + fprintf (stderr, "%s |<%d>| %s", "crq_key_id", level, str); +} + +void +doit (void) +{ + gnutls_x509_privkey_t pkey; + int ret, algorithm, i; + + ret = gnutls_global_init (); + if (ret < 0) + fail ("gnutls_global_init: %d\n", ret); + + gnutls_global_set_log_function (tls_log_func); + if (debug) + gnutls_global_set_log_level (4711); + + for (i = 0; i < 2; i++) + { + for (algorithm = GNUTLS_PK_RSA; algorithm <= GNUTLS_PK_ECC; + algorithm++) + { + if (algorithm == GNUTLS_PK_DH) + continue; + + ret = gnutls_x509_privkey_init (&pkey); + if (ret < 0) + { + fail ("gnutls_x509_privkey_init: %d\n", ret); + } + + ret = + gnutls_x509_privkey_generate (pkey, algorithm, + gnutls_sec_param_to_pk_bits + (algorithm, + GNUTLS_SEC_PARAM_NORMAL), + 0); + if (ret < 0) + { + fail ("gnutls_x509_privkey_generate (%s): %s (%d)\n", + gnutls_pk_algorithm_get_name (algorithm), + gnutls_strerror (ret), ret); + } + else if (debug) + { + success ("Key[%s] generation ok: %d\n", + gnutls_pk_algorithm_get_name (algorithm), + ret); + } + + ret = gnutls_x509_privkey_verify_params (pkey); + if (ret < 0) + { + fail ("gnutls_x509_privkey_generate (%s): %s (%d)\n", + gnutls_pk_algorithm_get_name (algorithm), + gnutls_strerror (ret), ret); + } + + gnutls_x509_privkey_deinit (pkey); + } + } + + gnutls_global_deinit (); +} |