commit d326f81daed5a1a06476d66a81584f8c7b71141d
Author: Nikos Mavrogiannopoulos <nmav@redhat.com>
Date:   Mon Feb 23 10:03:47 2015 +0100

    Added fix for GNUTLS-SA-2015-1

Index: gnutls-2.4.1/lib/gnutls_algorithms.c
===================================================================
--- gnutls-2.4.1.orig/lib/gnutls_algorithms.c	2015-03-24 23:44:15.898841091 +0100
+++ gnutls-2.4.1/lib/gnutls_algorithms.c	2015-03-24 23:44:15.909841246 +0100
@@ -2008,6 +2008,14 @@ gnutls_sign_algorithm_get_name (gnutls_s
   return ret;
 }
 
+int
+_gnutls_sign_get_hash (gnutls_sign_algorithm_t algorithm)
+{
+  GNUTLS_SIGN_LOOP (if (p->id == algorithm) return p->mac);
+
+  return GNUTLS_MAC_UNKNOWN;
+}
+
 gnutls_sign_algorithm_t
 _gnutls_x509_oid2sign_algorithm (const char *oid)
 {
Index: gnutls-2.4.1/lib/gnutls_algorithms.h
===================================================================
--- gnutls-2.4.1.orig/lib/gnutls_algorithms.h	2015-03-24 23:40:41.938803640 +0100
+++ gnutls-2.4.1/lib/gnutls_algorithms.h	2015-03-24 23:44:15.909841246 +0100
@@ -120,6 +120,7 @@ struct gnutls_compression_entry
 typedef struct gnutls_compression_entry gnutls_compression_entry;
 
 /* Functions for sign algorithms. */
+int _gnutls_sign_get_hash (gnutls_sign_algorithm_t algorithm);
 gnutls_sign_algorithm_t _gnutls_x509_oid2sign_algorithm (const char *oid);
 gnutls_sign_algorithm_t _gnutls_x509_pk_to_sign (gnutls_pk_algorithm_t pk,
 						 gnutls_mac_algorithm_t mac);
Index: gnutls-2.4.1/lib/x509/privkey.c
===================================================================
--- gnutls-2.4.1.orig/lib/x509/privkey.c	2015-03-24 23:40:41.938803640 +0100
+++ gnutls-2.4.1/lib/x509/privkey.c	2015-03-24 23:44:15.909841246 +0100
@@ -1609,7 +1609,8 @@ gnutls_x509_privkey_verify_data (gnutls_
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  result = _gnutls_x509_privkey_verify_signature (data, signature, key);
+  result = _gnutls_x509_privkey_verify_signature (GNUTLS_MAC_UNKNOWN, data, signature, key);
+
   if (result < 0)
     {
       gnutls_assert ();
Index: gnutls-2.4.1/lib/x509/verify.c
===================================================================
--- gnutls-2.4.1.orig/lib/x509/verify.c	2015-03-24 23:44:15.885840907 +0100
+++ gnutls-2.4.1/lib/x509/verify.c	2015-03-24 23:50:53.696463828 +0100
@@ -43,12 +43,12 @@ static int _gnutls_verify_certificate2 (
 					const gnutls_x509_crt_t * trusted_cas,
 					int tcas_size, unsigned int flags,
 					unsigned int *output);
-int _gnutls_x509_verify_signature (const gnutls_datum_t * signed_data,
-				   const gnutls_datum_t * signature,
-				   gnutls_x509_crt_t issuer);
+int _gnutls_x509_verify_signature (int hashalg, const gnutls_datum_t * tbs,
+			       const gnutls_datum_t * hash,
+			       const gnutls_datum_t * signature,
+			       gnutls_x509_crt_t issuer);
 
-static
-  int is_crl_issuer (gnutls_x509_crl_t crl, gnutls_x509_crt_t issuer_cert);
+static int is_crl_issuer (gnutls_x509_crl_t crl, gnutls_x509_crt_t issuer_cert);
 static int _gnutls_verify_crl2 (gnutls_x509_crl_t crl,
 				const gnutls_x509_crt_t * trusted_cas,
 				int tcas_size, unsigned int flags,
@@ -250,6 +250,7 @@ _gnutls_verify_certificate2 (gnutls_x509
   gnutls_datum_t cert_signature = { NULL, 0 };
   gnutls_x509_crt_t issuer;
   int ret, issuer_version, result=0;
+  int sigalg, hashalg;
 
   if (output)
     *output = 0;
@@ -314,8 +315,18 @@ _gnutls_verify_certificate2 (gnutls_x509
       goto cleanup;
     }
 
+  sigalg = gnutls_x509_crt_get_signature_algorithm (cert);
+  hashalg = _gnutls_sign_get_hash(sigalg);
+
+  if (hashalg == GNUTLS_MAC_UNKNOWN)
+    {
+      gnutls_assert();
+      result = 0;
+      goto cleanup;
+    }
+
   ret =
-    _gnutls_x509_verify_signature (&cert_signed_data, NULL, &cert_signature,
+    _gnutls_x509_verify_signature (hashalg, &cert_signed_data, NULL, &cert_signature,
 				   issuer);
   if (ret < 0)
     {
@@ -338,10 +349,6 @@ _gnutls_verify_certificate2 (gnutls_x509
    */
   if (is_issuer (cert, cert) == 0)
     {
-      int sigalg;
-
-      sigalg = gnutls_x509_crt_get_signature_algorithm (cert);
-
       if (((sigalg == GNUTLS_SIGN_RSA_MD2) &&
 	   !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) ||
 	  ((sigalg == GNUTLS_SIGN_RSA_MD5) &&
@@ -549,12 +556,12 @@ decode_ber_digest_info (const gnutls_dat
  * params[1] is public key
  */
 static int
-_pkcs1_rsa_verify_sig (const gnutls_datum_t * text,
+_pkcs1_rsa_verify_sig (gnutls_mac_algorithm_t hash, 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;
+  gnutls_mac_algorithm_t phash = GNUTLS_MAC_UNKNOWN;
   int ret;
   opaque digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE], *cmp;
   int digest_size;
@@ -574,7 +581,7 @@ _pkcs1_rsa_verify_sig (const gnutls_datu
 
   digest_size = sizeof (digest);
   if ((ret =
-       decode_ber_digest_info (&decrypted, &hash, digest, &digest_size)) != 0)
+       decode_ber_digest_info (&decrypted, &phash, digest, &digest_size)) != 0)
     {
       gnutls_assert ();
       _gnutls_free_datum (&decrypted);
@@ -583,6 +590,15 @@ _pkcs1_rsa_verify_sig (const gnutls_datu
 
   _gnutls_free_datum (&decrypted);
 
+  if (hash != GNUTLS_MAC_UNKNOWN && hash != phash)
+    {
+      gnutls_assert();
+      return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+    }
+  else
+    hash = phash;
+  
+
   if (digest_size != _gnutls_hash_get_algo_len (hash))
     {
       gnutls_assert ();
@@ -665,7 +681,7 @@ dsa_verify_sig (const gnutls_datum_t * t
  * or 1 otherwise.
  */
 static int
-verify_sig (const gnutls_datum_t * tbs,
+verify_sig (int hashalg, const gnutls_datum_t * tbs,
 	    const gnutls_datum_t * hash,
 	    const gnutls_datum_t * signature,
 	    gnutls_pk_algorithm_t pk, mpi_t * issuer_params,
@@ -677,7 +693,7 @@ verify_sig (const gnutls_datum_t * tbs,
     case GNUTLS_PK_RSA:
 
       if (_pkcs1_rsa_verify_sig
-	  (tbs, hash, signature, issuer_params, issuer_params_size) != 0)
+	  (hashalg, tbs, hash, signature, issuer_params, issuer_params_size) != 0)
 	{
 	  gnutls_assert ();
 	  return 0;
@@ -708,7 +724,7 @@ _gnutls_x509_verify_algorithm (gnutls_ma
 			       const gnutls_datum_t * signature,
 			       const gnutls_x509_crt_t issuer)
 {
-  bigint_t issuer_params[MAX_PUBLIC_PARAMS_SIZE];
+  mpi_t issuer_params[MAX_PUBLIC_PARAMS_SIZE];
   opaque digest[MAX_HASH_SIZE];
   gnutls_datum_t decrypted;
   int issuer_params_size;
@@ -770,7 +786,7 @@ _gnutls_x509_verify_algorithm (gnutls_ma
  * 'signature' is the signature!
  */
 int
-_gnutls_x509_verify_signature (const gnutls_datum_t * tbs,
+_gnutls_x509_verify_signature (int hashalg, const gnutls_datum_t * tbs,
 			       const gnutls_datum_t * hash,
 			       const gnutls_datum_t * signature,
 			       gnutls_x509_crt_t issuer)
@@ -790,7 +806,7 @@ _gnutls_x509_verify_signature (const gnu
     }
 
   ret =
-    verify_sig (tbs, hash, signature,
+    verify_sig (hashalg, tbs, hash, signature,
 		gnutls_x509_crt_get_pk_algorithm (issuer, NULL),
 		issuer_params, issuer_params_size);
   if (ret < 0)
@@ -815,13 +831,13 @@ _gnutls_x509_verify_signature (const gnu
  * 'signature' is the signature!
  */
 int
-_gnutls_x509_privkey_verify_signature (const gnutls_datum_t * tbs,
+_gnutls_x509_privkey_verify_signature (int hashalg, const gnutls_datum_t * tbs,
 				       const gnutls_datum_t * signature,
 				       gnutls_x509_privkey_t issuer)
 {
   int ret;
 
-  ret = verify_sig (tbs, NULL, signature, issuer->pk_algorithm,
+  ret = verify_sig (hashalg, tbs, NULL, signature, issuer->pk_algorithm,
 		    issuer->params, issuer->params_size);
   if (ret < 0)
     {
@@ -1054,6 +1070,7 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t c
   gnutls_datum_t crl_signature = { NULL, 0 };
   gnutls_x509_crt_t issuer;
   int ret, result;
+  int sigalg, hashalg;
 
   if (output)
     *output = 0;
@@ -1095,6 +1112,7 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t c
   if (result < 0)
     {
       gnutls_assert ();
+      result = 0;
       goto cleanup;
     }
 
@@ -1102,11 +1120,21 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t c
   if (result < 0)
     {
       gnutls_assert ();
+      result = 0;
+      goto cleanup;
+    }
+
+  sigalg = gnutls_x509_crl_get_signature_algorithm (crl);
+  hashalg = _gnutls_sign_get_hash(sigalg);
+  if (hashalg == GNUTLS_MAC_UNKNOWN)
+    {
+      gnutls_assert();
+      result = 0;
       goto cleanup;
     }
 
   ret =
-    _gnutls_x509_verify_signature (&crl_signed_data, NULL, &crl_signature, issuer);
+    _gnutls_x509_verify_signature (hashalg, &crl_signed_data, NULL, &crl_signature, issuer);
   if (ret < 0)
     {
       gnutls_assert ();
@@ -1121,9 +1149,6 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t c
     }
 
   {
-    int sigalg;
-
-    sigalg = gnutls_x509_crl_get_signature_algorithm (crl);
 
     if (((sigalg == GNUTLS_SIGN_RSA_MD2) &&
 	 !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) ||
Index: gnutls-2.4.1/lib/x509/x509_int.h
===================================================================
--- gnutls-2.4.1.orig/lib/x509/x509_int.h	2015-03-24 23:44:15.886840921 +0100
+++ gnutls-2.4.1/lib/x509/x509_int.h	2015-03-24 23:44:15.910841260 +0100
@@ -170,11 +170,11 @@ int gnutls_x509_crt_is_issuer (gnutls_x5
 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,
+int _gnutls_x509_verify_signature (int sigalg, 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,
+int _gnutls_x509_privkey_verify_signature (int sigalg, const gnutls_datum_t * tbs,
 					   const gnutls_datum_t * signature,
 					   gnutls_x509_privkey_t issuer);
 
Index: gnutls-2.4.1/lib/x509/x509.c
===================================================================
--- gnutls-2.4.1.orig/lib/x509/x509.c	2015-03-24 23:44:15.897841077 +0100
+++ gnutls-2.4.1/lib/x509/x509.c	2015-03-24 23:44:15.911841275 +0100
@@ -2374,7 +2374,7 @@ gnutls_x509_crt_verify_data (gnutls_x509
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  result = _gnutls_x509_verify_signature (data, NULL, signature, crt);
+  result = _gnutls_x509_verify_signature (GNUTLS_MAC_UNKNOWN, data, NULL, signature, crt);
   if (result < 0)
     {
       gnutls_assert ();
@@ -2410,7 +2410,7 @@ gnutls_x509_crt_verify_hash (gnutls_x509
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  result = _gnutls_x509_verify_signature (NULL, hash, signature, crt);
+  result = _gnutls_x509_verify_signature (GNUTLS_MAC_UNKNOWN, NULL, hash, signature, crt);
   if (result < 0)
     {
       gnutls_assert ();
