]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added gnutls_pubkey_get_preferred_hash_algorithm() and gnutls_x509_crt_get_preferred_...
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 30 May 2010 22:52:27 +0000 (00:52 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 3 Jun 2010 17:55:02 +0000 (19:55 +0200)
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.

NEWS
lib/gnutls_pubkey.c
lib/includes/gnutls/abstract.h
lib/includes/gnutls/x509.h
lib/libgnutls.map
lib/x509/privkey.c
lib/x509/verify.c
lib/x509/x509.c
src/certtool.c

diff --git a/NEWS b/NEWS
index c92fae870f54b6312d53a8b9408097eba030b544..3d947da787a5a368b4453873acdb35de6427708c 100644 (file)
--- 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
index 543a8d3443c8aeaa5c8c887758d88c0e144eabf0..4303ca76a2d17a7aeda4fc1ca3552a622353c914 100644 (file)
@@ -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
index 5e148906728aade640066108e81cc6643b25cd3e..4731faa656debf22937edc0eda1b0f128ae26ebd 100644 (file)
@@ -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,
index 308e7057be7d771cce53d09a372f0b698233731e..b605870a0a31de27f418114e27c7102b2fdb27a3 100644 (file)
@@ -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);
index ffd44429e04e2679dff21910497315f80ad61f0e..bd71a9125a0743cb3033f00237679f606306f732 100644 (file)
@@ -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;
index 7de84d22bc22cd82fd199e1e24b5960e6a5d4fd2..2b8e21382975ad4d3cde256a267b254482e64df8 100644 (file)
@@ -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.
  **/
index 81beea04aa154d6cf0d643ac90a86164169f8af4..4f992eb27fc1f75c20dea13bf2d23d4ac9f0963a 100644 (file)
@@ -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);
index 0a4229cdef58c41fe0a6687f825942692a79b44d..d6dddb2491f063b36d7ab70b8f2ef8f81223dc86 100644 (file)
@@ -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
index 7a2a864d55aaabf5e1fa84a91bbed71fcf4ff260..020a56879df80fff8988d13935c2e148027cbc97 100644 (file)
@@ -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);
     }