From: Nikos Mavrogiannopoulos Date: Sun, 30 May 2010 22:52:27 +0000 (+0200) Subject: Added gnutls_pubkey_get_preferred_hash_algorithm() and gnutls_x509_crt_get_preferred_... X-Git-Tag: gnutls_2_11_3~204 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5eeabed81dbfe7a2e4089e612db5c61e60edeb91;p=thirdparty%2Fgnutls.git Added gnutls_pubkey_get_preferred_hash_algorithm() and gnutls_x509_crt_get_preferred_hash_algorithm() to allow determining the hash algorithm to use during signing. This is needed in the case of DSA that uses specific versions of SHA depending on the size of the parameters. --- diff --git a/NEWS b/NEWS index c92fae870f..3d947da787 100644 --- a/NEWS +++ b/NEWS @@ -43,6 +43,8 @@ pkcs11:token=Root%20CA%20Certificates;serial=1%3AROOTS%3ADEFAULT;model=1%2E0;man gnutls_certificate_set_server_retrieve_function: DEPRECATED gnutls_certificate_set_client_retrieve_function: DEPRECATED gnutls_sign_callback_set: DEPRECATED +gnutls_pubkey_get_preferred_hash_algorithm: ADDED +gnutls_x509_crt_get_preferred_hash_algorithm: ADDED gnutls_x509_privkey_export_rsa_raw2: ADDED gnutls_rnd: ADDED gnutls_sec_param_to_pk_bits: ADDED diff --git a/lib/gnutls_pubkey.c b/lib/gnutls_pubkey.c index 543a8d3443..4303ca76a2 100644 --- a/lib/gnutls_pubkey.c +++ b/lib/gnutls_pubkey.c @@ -183,6 +183,40 @@ int gnutls_pubkey_import_x509(gnutls_pubkey_t key, gnutls_x509_crt_t crt, return 0; } +/** + * gnutls_pubkey_get_preferred_hash_algorithm: + * @key: Holds the certificate + * @hash: The result of the call with the hash algorithm used for signature + * + * This function will read the certifcate and return the appropriate digest + * algorithm to use for signing with this certificate. Some certificates (i.e. + * DSA might not be able to sign without the preferred algorithm). + * + * Returns: the 0 if the hash algorithm is found. A negative value is + * returned on error. + * + * Since: 2.11.0 + **/ +int +gnutls_pubkey_get_preferred_hash_algorithm (gnutls_pubkey_t key, + gnutls_digest_algorithm_t * hash) +{ + int ret; + + if (key == NULL) + { + gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = _gnutls_x509_verify_algorithm ((gnutls_mac_algorithm_t *) hash, + NULL, key->pk_algorithm, + key->params, key->params_size); + + return ret; +} + + /** * gnutls_pubkey_import_pkcs11: * @key: The public key diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h index 5e14890672..4731faa656 100644 --- a/lib/includes/gnutls/abstract.h +++ b/lib/includes/gnutls/abstract.h @@ -23,6 +23,9 @@ int gnutls_pubkey_import_openpgp(gnutls_pubkey_t pkey, gnutls_openpgp_keyid_t keyid, unsigned int flags); +int gnutls_pubkey_get_preferred_hash_algorithm (gnutls_pubkey_t key, + gnutls_digest_algorithm_t * hash); + int gnutls_pubkey_get_pk_rsa_raw (gnutls_pubkey_t crt, gnutls_datum_t * m, gnutls_datum_t * e); int gnutls_pubkey_get_pk_dsa_raw (gnutls_pubkey_t crt, diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h index 308e7057be..b605870a0a 100644 --- a/lib/includes/gnutls/x509.h +++ b/lib/includes/gnutls/x509.h @@ -139,6 +139,8 @@ extern "C" unsigned int flags, unsigned char *output_data, size_t * output_data_size); + int gnutls_x509_crt_get_preferred_hash_algorithm (gnutls_x509_crt_t crt, + gnutls_digest_algorithm_t * hash); int gnutls_x509_crt_set_authority_key_id (gnutls_x509_crt_t cert, const void *id, size_t id_size); diff --git a/lib/libgnutls.map b/lib/libgnutls.map index ffd44429e0..bd71a9125a 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -672,6 +672,8 @@ GNUTLS_2_11 gnutls_pkcs11_copy_x509_privkey; gnutls_pkcs11_delete_url; gnutls_x509_privkey_export_rsa_raw2; + gnutls_pubkey_get_preferred_hash_algorithm; + gnutls_x509_crt_get_preferred_hash_algorithm; gnutls_sec_param_to_pk_bits; gnutls_sec_param_get_name; diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c index 7de84d22bc..2b8e213829 100644 --- a/lib/x509/privkey.c +++ b/lib/x509/privkey.c @@ -1624,6 +1624,9 @@ cleanup: * *@signature_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER will * be returned. * + * Use gnutls_x509_crt_get_preferred_hash_algorithm() to determine + * the hash algorithm. + * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ @@ -1734,6 +1737,9 @@ gnutls_x509_privkey_sign_hash (gnutls_x509_privkey_t key, * *@signature_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER will * be returned. * + * Use gnutls_x509_crt_get_preferred_hash_algorithm() to determine + * the hash algorithm. + * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ diff --git a/lib/x509/verify.c b/lib/x509/verify.c index 81beea04aa..4f992eb27f 100644 --- a/lib/x509/verify.c +++ b/lib/x509/verify.c @@ -875,6 +875,10 @@ gnutls_digest_algorithm_t _gnutls_dsa_q_to_hash(bigint_t q) } } +/* This will return the appropriate hash to verify the given signature. + * If signature is NULL it will return an (or the) appropriate hash for + * the given parameters. + */ int _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * hash, const gnutls_datum_t * signature, @@ -896,6 +900,9 @@ _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * hash, ret = 0; break; case GNUTLS_PK_RSA: + if (signature == NULL) /* return a sensible algorithm */ + return GNUTLS_DIG_SHA256; + ret = _gnutls_pkcs1_rsa_decrypt (&decrypted, signature, issuer_params, issuer_params_size, 1); diff --git a/lib/x509/x509.c b/lib/x509/x509.c index 0a4229cdef..d6dddb2491 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -465,7 +465,8 @@ gnutls_x509_crt_get_dn_oid (gnutls_x509_crt_t cert, * @cert: should contain a #gnutls_x509_crt_t structure * * This function will return a value of the #gnutls_sign_algorithm_t - * enumeration that is the signature algorithm. + * enumeration that is the signature algorithm that has been used to + * sign this certificate. * * Returns: a #gnutls_sign_algorithm_t value, or a negative value on * error. @@ -2532,6 +2533,57 @@ gnutls_x509_crt_get_verify_algorithm (gnutls_x509_crt_t crt, return ret; } +/** + * gnutls_x509_crt_get_preferred_hash_algorithm: + * @crt: Holds the certificate + * @hash: The result of the call with the hash algorithm used for signature + * + * This function will read the certifcate and return the appropriate digest + * algorithm to use for signing with this certificate. Some certificates (i.e. + * DSA might not be able to sign without the preferred algorithm). + * + * Returns: the 0 if the hash algorithm is found. A negative value is + * returned on error. + * + * Since: 2.11.0 + **/ +int +gnutls_x509_crt_get_preferred_hash_algorithm (gnutls_x509_crt_t crt, + gnutls_digest_algorithm_t * hash) +{ + bigint_t issuer_params[MAX_PUBLIC_PARAMS_SIZE]; + int issuer_params_size; + int ret, i; + + if (crt == NULL) + { + gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + issuer_params_size = MAX_PUBLIC_PARAMS_SIZE; + ret = + _gnutls_x509_crt_get_mpis (crt, issuer_params, + &issuer_params_size); + if (ret < 0) + { + gnutls_assert (); + return ret; + } + + ret = _gnutls_x509_verify_algorithm ((gnutls_mac_algorithm_t *) hash, + NULL, gnutls_x509_crt_get_pk_algorithm (crt, NULL), + issuer_params, issuer_params_size); + + /* release allocated mpis */ + for (i = 0; i < issuer_params_size; i++) + { + _gnutls_mpi_release (&issuer_params[i]); + } + + return ret; +} + /** * gnutls_x509_crt_verify_data: * @crt: Holds the certificate diff --git a/src/certtool.c b/src/certtool.c index 7a2a864d55..020a56879d 100644 --- a/src/certtool.c +++ b/src/certtool.c @@ -75,11 +75,10 @@ static void print_certificate_info (gnutls_x509_crt_t crt, FILE * out, unsigned static void print_hex_datum (gnutls_datum_t * dat); - static gaainfo info; FILE *outfile; FILE *infile; -gnutls_digest_algorithm_t dig = GNUTLS_DIG_SHA1; +gnutls_digest_algorithm_t default_dig; /* non interactive operation if set */ @@ -698,8 +697,27 @@ generate_crl (gnutls_x509_crt_t ca_crt) return crl; } -void -generate_self_signed (void) +static gnutls_digest_algorithm_t get_dig(gnutls_x509_crt crt) +{ +gnutls_digest_algorithm_t dig; +int result; + + if (default_dig != GNUTLS_DIG_UNKNOWN) + dig = default_dig; + else + { + result = gnutls_x509_crt_get_preferred_hash_algorithm(crt, &dig); + if (result < 0) + { + error (EXIT_FAILURE, 0, "crl_preferred_hash_algorithm: %s", + gnutls_strerror (result)); + } + } + + return dig; +} + +void generate_self_signed (void) { gnutls_x509_crt_t crt; gnutls_x509_privkey_t key; @@ -729,7 +747,7 @@ generate_self_signed (void) fprintf (stderr, "\n\nSigning certificate...\n"); - result = gnutls_x509_crt_sign2 (crt, crt, key, dig, 0); + result = gnutls_x509_crt_sign2 (crt, crt, key, get_dig(crt), 0); if (result < 0) error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result)); @@ -771,7 +789,7 @@ generate_signed_certificate (void) fprintf (stderr, "\n\nSigning certificate...\n"); - result = gnutls_x509_crt_sign2 (crt, ca_crt, ca_key, dig, 0); + result = gnutls_x509_crt_sign2 (crt, ca_crt, ca_key, get_dig(ca_crt), 0); if (result < 0) error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result)); @@ -805,7 +823,7 @@ generate_proxy_certificate (void) fprintf (stderr, "\n\nSigning certificate...\n"); - result = gnutls_x509_crt_sign2 (crt, eecrt, eekey, dig, 0); + result = gnutls_x509_crt_sign2 (crt, eecrt, eekey, get_dig(eecrt), 0); if (result < 0) error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result)); @@ -874,7 +892,7 @@ update_signed_certificate (void) fprintf (stderr, "\n\nSigning certificate...\n"); - result = gnutls_x509_crt_sign2 (crt, ca_crt, ca_key, dig, 0); + result = gnutls_x509_crt_sign2 (crt, ca_crt, ca_key, get_dig(ca_crt), 0); if (result < 0) error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result)); @@ -949,24 +967,30 @@ gaa_parser (int argc, char **argv) else info.outcert_format = GNUTLS_X509_FMT_PEM; + default_dig = GNUTLS_DIG_UNKNOWN; if (info.hash != NULL) { + fprintf(stderr, "Warning: It is suggested that you do not use this parameter unless you know what you are doing. " + "It is not always possible to set specific algorithms, for example DSA keys are unable to use any algorithm and " + "thus using the defaults is highly recommended!\n"); + sleep(2); + if (strcasecmp (info.hash, "md5") == 0) { fprintf (stderr, "Warning: MD5 is broken, and should not be used any more for digital signatures.\n"); - dig = GNUTLS_DIG_MD5; + default_dig = GNUTLS_DIG_MD5; } else if (strcasecmp (info.hash, "sha1") == 0) - dig = GNUTLS_DIG_SHA1; + default_dig = GNUTLS_DIG_SHA1; else if (strcasecmp (info.hash, "sha256") == 0) - dig = GNUTLS_DIG_SHA256; + default_dig = GNUTLS_DIG_SHA256; else if (strcasecmp (info.hash, "sha384") == 0) - dig = GNUTLS_DIG_SHA384; + default_dig = GNUTLS_DIG_SHA384; else if (strcasecmp (info.hash, "sha512") == 0) - dig = GNUTLS_DIG_SHA512; + default_dig = GNUTLS_DIG_SHA512; else if (strcasecmp (info.hash, "rmd160") == 0) - dig = GNUTLS_DIG_RMD160; + default_dig = GNUTLS_DIG_RMD160; else error (EXIT_FAILURE, 0, "invalid hash: %s", info.hash); }