commit bda121ef22285edfd93f42669dcf09abd6424faa
Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
Date:   Thu Mar 26 20:36:49 2009 +0200

    Applied patch by Cedric Bail to add functions gnutls_x509_crt_verify_hash() and gnutls_x509_crt_get_sig_algorithm().

Index: gnutls-2.4.1/includes/gnutls/x509.h
===================================================================
--- gnutls-2.4.1.orig/includes/gnutls/x509.h	2015-03-24 22:47:25.270443138 +0100
+++ gnutls-2.4.1/includes/gnutls/x509.h	2015-03-24 22:47:29.002496931 +0100
@@ -605,6 +605,14 @@ extern "C"
 				   unsigned int flags,
 				   const gnutls_datum_t * data,
 				   const gnutls_datum_t * signature);
+  int gnutls_x509_crt_verify_hash (gnutls_x509_crt_t crt,
+				   unsigned int flags,
+				   const gnutls_datum_t * hash,
+				   const gnutls_datum_t * signature);
+
+  int gnutls_x509_crt_get_sig_algorithm(gnutls_digest_algorithm_t *hash,
+					 const gnutls_x509_crt_t crt,
+					 const gnutls_datum_t * signature);
 
   int gnutls_x509_privkey_sign_hash (gnutls_x509_privkey_t key,
 				     const gnutls_datum_t * hash,
Index: gnutls-2.4.1/lib/x509/verify.c
===================================================================
--- gnutls-2.4.1.orig/lib/x509/verify.c	2015-03-24 22:47:25.271443152 +0100
+++ gnutls-2.4.1/lib/x509/verify.c	2015-03-24 22:49:28.725206363 +0100
@@ -315,7 +315,7 @@ _gnutls_verify_certificate2 (gnutls_x509
     }
 
   ret =
-    _gnutls_x509_verify_signature (&cert_signed_data, &cert_signature,
+    _gnutls_x509_verify_signature (&cert_signed_data, NULL, &cert_signature,
 				   issuer);
   if (ret < 0)
     {
@@ -550,12 +550,13 @@ decode_ber_digest_info (const gnutls_dat
  */
 static int
 _pkcs1_rsa_verify_sig (const gnutls_datum_t * text,
+		       const gnutls_datum_t * prehash,
 		       const gnutls_datum_t * signature, mpi_t * params,
 		       int params_len)
 {
   gnutls_mac_algorithm_t hash = GNUTLS_MAC_UNKNOWN;
   int ret;
-  opaque digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE];
+  opaque digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE], *cmp;
   int digest_size;
   digest_hd_st hd;
   gnutls_datum_t decrypted;
@@ -588,17 +589,32 @@ _pkcs1_rsa_verify_sig (const gnutls_datu
       return GNUTLS_E_ASN1_GENERIC_ERROR;
     }
 
-  ret = _gnutls_hash_init (&hd, hash);
-  if (ret < 0)
+  if (prehash && prehash->data && prehash->size == digest_size)
     {
-      gnutls_assert ();
-      return ret;
+       cmp = prehash->data;
     }
+  else
+    {
+       if (!text)
+	 {
+	    gnutls_assert ();
+	    return GNUTLS_E_INVALID_REQUEST;
+	 }
+
+       ret = _gnutls_hash_init (&hd, hash);
+       if (ret < 0)
+	 {
+	    gnutls_assert ();
+	    return ret;
+	 }
+
+       _gnutls_hash (&hd, text->data, text->size);
+       _gnutls_hash_deinit (&hd, md);
 
-  _gnutls_hash (&hd, text->data, text->size);
-  _gnutls_hash_deinit (&hd, md);
+       cmp = &md;
+    }
 
-  if (memcmp (md, digest, digest_size) != 0)
+  if (memcmp (cmp, digest, digest_size) != 0)
     {
       gnutls_assert ();
       return GNUTLS_E_PK_SIG_VERIFY_FAILED;
@@ -611,6 +627,7 @@ _pkcs1_rsa_verify_sig (const gnutls_datu
  */
 static int
 dsa_verify_sig (const gnutls_datum_t * text,
+		const gnutls_datum_t * hash,
 		const gnutls_datum_t * signature, mpi_t * params,
 		int params_len)
 {
@@ -619,18 +636,25 @@ dsa_verify_sig (const gnutls_datum_t * t
   gnutls_datum_t digest;
   digest_hd_st hd;
 
-  ret = _gnutls_hash_init (&hd, GNUTLS_MAC_SHA1);
-  if (ret < 0)
+  if (hash && hash->data && hash->size == 20)
     {
-      gnutls_assert ();
-      return ret;
+       digest = *hash;
     }
+  else
+    {
+       ret = _gnutls_hash_init (&hd, GNUTLS_MAC_SHA1);
+       if (ret < 0)
+	 {
+	    gnutls_assert ();
+	    return ret;
+	 }
 
-  _gnutls_hash (&hd, text->data, text->size);
-  _gnutls_hash_deinit (&hd, _digest);
+       _gnutls_hash (&hd, text->data, text->size);
+       _gnutls_hash_deinit (&hd, _digest);
 
-  digest.data = _digest;
-  digest.size = 20;
+       digest.data = _digest;
+       digest.size = 20;
+    }
 
   ret = _gnutls_dsa_verify (&digest, signature, params, params_len);
 
@@ -642,6 +666,7 @@ dsa_verify_sig (const gnutls_datum_t * t
  */
 static int
 verify_sig (const gnutls_datum_t * tbs,
+	    const gnutls_datum_t * hash,
 	    const gnutls_datum_t * signature,
 	    gnutls_pk_algorithm_t pk, mpi_t * issuer_params,
 	    int issuer_params_size)
@@ -652,7 +677,7 @@ verify_sig (const gnutls_datum_t * tbs,
     case GNUTLS_PK_RSA:
 
       if (_pkcs1_rsa_verify_sig
-	  (tbs, signature, issuer_params, issuer_params_size) != 0)
+	  (tbs, hash, signature, issuer_params, issuer_params_size) != 0)
 	{
 	  gnutls_assert ();
 	  return 0;
@@ -663,7 +688,7 @@ verify_sig (const gnutls_datum_t * tbs,
 
     case GNUTLS_PK_DSA:
       if (dsa_verify_sig
-	  (tbs, signature, issuer_params, issuer_params_size) != 0)
+	  (tbs, hash, signature, issuer_params, issuer_params_size) != 0)
 	{
 	  gnutls_assert ();
 	  return 0;
@@ -678,6 +703,66 @@ verify_sig (const gnutls_datum_t * tbs,
     }
 }
 
+int
+_gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t *hash,
+			       const gnutls_datum_t * signature,
+			       const gnutls_x509_crt_t issuer)
+{
+  bigint_t issuer_params[MAX_PUBLIC_PARAMS_SIZE];
+  opaque digest[MAX_HASH_SIZE];
+  gnutls_datum_t decrypted;
+  int issuer_params_size;
+  int digest_size;
+  int ret;
+
+  switch (gnutls_x509_crt_get_pk_algorithm (issuer, NULL))
+    {
+    case GNUTLS_PK_DSA:
+      if (hash) *hash = GNUTLS_MAC_SHA1;
+      return 0;
+
+    case GNUTLS_PK_RSA:
+      issuer_params_size = MAX_PUBLIC_PARAMS_SIZE;
+      ret = _gnutls_x509_crt_get_mpis (issuer, issuer_params, &issuer_params_size);
+      if (ret < 0)
+	{
+	   gnutls_assert ();
+	   return ret;
+	}
+
+      ret =
+	_gnutls_pkcs1_rsa_decrypt (&decrypted, signature,
+				   issuer_params, issuer_params_size, 1);
+      if (ret < 0)
+	{
+	   gnutls_assert ();
+	   return ret;
+	}
+
+      digest_size = sizeof (digest);
+      if ((ret =
+	   decode_ber_digest_info (&decrypted, hash, digest, &digest_size)) != 0)
+	{
+	   gnutls_assert ();
+	   _gnutls_free_datum (&decrypted);
+	   return ret;
+	}
+
+      _gnutls_free_datum (&decrypted);
+      if (digest_size != _gnutls_hash_get_algo_len (*hash))
+	{
+	   gnutls_assert ();
+	   return GNUTLS_E_ASN1_GENERIC_ERROR;
+	}
+
+      return 0;
+
+    default:
+      gnutls_assert ();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+}
+
 /* verifies if the certificate is properly signed.
  * returns 0 on failure and 1 on success.
  * 
@@ -686,6 +771,7 @@ verify_sig (const gnutls_datum_t * tbs,
  */
 int
 _gnutls_x509_verify_signature (const gnutls_datum_t * tbs,
+			       const gnutls_datum_t * hash,
 			       const gnutls_datum_t * signature,
 			       gnutls_x509_crt_t issuer)
 {
@@ -704,7 +790,7 @@ _gnutls_x509_verify_signature (const gnu
     }
 
   ret =
-    verify_sig (tbs, signature,
+    verify_sig (tbs, hash, signature,
 		gnutls_x509_crt_get_pk_algorithm (issuer, NULL),
 		issuer_params, issuer_params_size);
   if (ret < 0)
@@ -735,7 +821,7 @@ _gnutls_x509_privkey_verify_signature (c
 {
   int ret;
 
-  ret = verify_sig (tbs, signature, issuer->pk_algorithm,
+  ret = verify_sig (tbs, NULL, signature, issuer->pk_algorithm,
 		    issuer->params, issuer->params_size);
   if (ret < 0)
     {
@@ -1020,7 +1106,7 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t c
     }
 
   ret =
-    _gnutls_x509_verify_signature (&crl_signed_data, &crl_signature, issuer);
+    _gnutls_x509_verify_signature (&crl_signed_data, NULL, &crl_signature, issuer);
   if (ret < 0)
     {
       gnutls_assert ();
Index: gnutls-2.4.1/lib/x509/x509.c
===================================================================
--- gnutls-2.4.1.orig/lib/x509/x509.c	2015-03-24 22:47:25.272443166 +0100
+++ gnutls-2.4.1/lib/x509/x509.c	2015-03-24 22:47:29.003496911 +0100
@@ -2305,6 +2305,32 @@ gnutls_x509_crt_check_revocation (gnutls
 }
 
 /**
+  * gnutls_x509_crt_get_sig_algorithm - This function will return the hash algorithm used during signature.
+  * @hash: The result of the call with the hash algorithm used for signature
+  * @crt: Holds the certificate
+  * @signature: contains the signature
+  *
+  * This function will read the certifcate and the signed data to
+  * determine the hash algorithm used to generate the signature.
+  *
+  * Returns: 0 if the hash algorithm was found. A negative value is
+  * returned on error.
+  **/
+int
+gnutls_x509_crt_get_sig_algorithm(gnutls_digest_algorithm_t *hash,
+				   const gnutls_x509_crt_t crt,
+				   const gnutls_datum_t * signature)
+{
+   if (crt == NULL)
+     {
+       gnutls_assert ();
+       return GNUTLS_E_INVALID_REQUEST;
+     }
+
+   return _gnutls_x509_verify_algorithm(hash, signature, crt);
+}
+
+/**
   * gnutls_x509_crt_verify_data - This function will verify the given signed data.
   * @crt: Holds the certificate
   * @flags: should be 0 for now
@@ -2330,7 +2356,43 @@ gnutls_x509_crt_verify_data (gnutls_x509
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  result = _gnutls_x509_verify_signature (data, signature, crt);
+  result = _gnutls_x509_verify_signature (data, NULL, signature, crt);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return 0;
+    }
+
+  return result;
+}
+
+/**
+  * gnutls_x509_crt_verify_data - This function will verify the given signed data.
+  * @crt: Holds the certificate
+  * @flags: should be 0 for now
+  * @hash: holds the hash digest to be verified
+  * @signature: contains the signature
+  *
+  * This function will verify the given signed digest, using the
+  * parameters from the certificate.
+  *
+  * Returns: In case of a verification failure 0 is returned, and 1 on
+  * success.
+  **/
+int
+gnutls_x509_crt_verify_hash (gnutls_x509_crt_t crt, unsigned int flags,
+			     const gnutls_datum_t * hash,
+			     const gnutls_datum_t * signature)
+{
+  int result;
+
+  if (crt == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  result = _gnutls_x509_verify_signature (NULL, hash, signature, crt);
   if (result < 0)
     {
       gnutls_assert ();
Index: gnutls-2.4.1/lib/x509/x509_int.h
===================================================================
--- gnutls-2.4.1.orig/lib/x509/x509_int.h	2015-03-24 22:47:25.272443166 +0100
+++ gnutls-2.4.1/lib/x509/x509_int.h	2015-03-24 22:47:29.003496911 +0100
@@ -167,7 +167,11 @@ int _gnutls_dsa_generate_params (mpi_t *
 /* verify.c */
 int gnutls_x509_crt_is_issuer (gnutls_x509_crt_t cert,
 			       gnutls_x509_crt_t issuer);
+int _gnutls_x509_verify_algorithm(gnutls_mac_algorithm_t *hash,
+				  const gnutls_datum_t * signature,
+				  const gnutls_x509_crt_t crt);
 int _gnutls_x509_verify_signature (const gnutls_datum_t * tbs,
+				   const gnutls_datum_t * hash,
 				   const gnutls_datum_t * signature,
 				   gnutls_x509_crt_t issuer);
 int _gnutls_x509_privkey_verify_signature (const gnutls_datum_t * tbs,
