File libgcrypt-fips_handle_priming_error_in_drbg.patch of Package libgcrypt.2574

Index: libgcrypt-1.6.1/random/drbg.c
===================================================================
--- libgcrypt-1.6.1.orig/random/drbg.c	2015-02-18 15:27:34.802215070 +0100
+++ libgcrypt-1.6.1/random/drbg.c	2015-02-18 15:27:35.054217426 +0100
@@ -329,8 +329,9 @@ gcry_drbg_sec_strength (u32 flags)
  * @buf output buffer of random data to be checked
  *
  * return:
- *	false on error
- * 	true on success
+ *      0 on error
+ *      1 on success
+ *      -1 if generator is not primed and needs additional round
  */
 static gpg_err_code_t
 gcry_drbg_fips_continuous_test (struct gcry_drbg_state *drbg,
@@ -349,7 +350,7 @@ gcry_drbg_fips_continuous_test (struct g
       memcpy (drbg->prev, buf, gcry_drbg_blocklen (drbg));
       drbg->fips_primed = 1;
       /* return false due to priming, i.e. another round is needed */
-      return 0;
+      return -1;
     }
   ret = memcmp (drbg->prev, buf, gcry_drbg_blocklen (drbg));
   memcpy (drbg->prev, buf, gcry_drbg_blocklen (drbg));
@@ -782,6 +783,7 @@ gcry_drbg_ctr_generate (struct gcry_drbg
 			struct gcry_drbg_string *addtl)
 {
   gpg_err_code_t ret = 0;
+  gpg_err_code_t rret = 0;
   unsigned int len = 0;
   struct gcry_drbg_string data;
   unsigned char prefix = DRBG_PREFIX1;
@@ -809,12 +811,19 @@ gcry_drbg_ctr_generate (struct gcry_drbg
 	goto out;
       outlen = (gcry_drbg_blocklen (drbg) < (buflen - len)) ?
 	gcry_drbg_blocklen (drbg) : (buflen - len);
-      if (!gcry_drbg_fips_continuous_test (drbg, drbg->scratchpad))
+      rret = gcry_drbg_fips_continuous_test (drbg, drbg->scratchpad);
+      if (rret == -1)
 	{
+          /* discard first block of unprimed generator */
 	  /* 10.2.1.5.2 step 6 */
 	  gcry_drbg_add_buf (drbg->V, gcry_drbg_blocklen (drbg), &prefix, 1);
 	  continue;
 	}
+      else if (!rret)
+        {
+          ret = gpg_error(fips_not_operational());
+          goto out;
+        }
       /* 10.2.1.5.2 step 4.3 */
       memcpy (buf + len, drbg->scratchpad, outlen);
       len += outlen;
@@ -897,6 +906,7 @@ gcry_drbg_hmac_generate (struct gcry_drb
 			 unsigned int buflen, struct gcry_drbg_string *addtl)
 {
   gpg_err_code_t ret = 0;
+  gpg_err_code_t rret = 0;
   unsigned int len = 0;
   struct gcry_drbg_string data;
 
@@ -919,8 +929,11 @@ gcry_drbg_hmac_generate (struct gcry_drb
 	return ret;
       outlen = (gcry_drbg_blocklen (drbg) < (buflen - len)) ?
 	gcry_drbg_blocklen (drbg) : (buflen - len);
-      if (!gcry_drbg_fips_continuous_test (drbg, drbg->V))
-	continue;
+      rret = gcry_drbg_fips_continuous_test (drbg, drbg->V);
+      if (rret == -1)
+        continue; /* discard first block of unprimed generator */
+      else if (!rret)
+        return gpg_error(fips_not_operational());
 
       /* 10.1.2.5 step 4.2 */
       memcpy (buf + len, drbg->V, outlen);
@@ -1093,6 +1106,7 @@ gcry_drbg_hash_hashgen (struct gcry_drbg
 			unsigned char *buf, unsigned int buflen)
 {
   gpg_err_code_t ret = 0;
+  gpg_err_code_t rret = 0;
   unsigned int len = 0;
   unsigned char *src = drbg->scratchpad;
   unsigned char *dst = drbg->scratchpad + gcry_drbg_statelen (drbg);
@@ -1116,11 +1130,18 @@ gcry_drbg_hash_hashgen (struct gcry_drbg
 	goto out;
       outlen = (gcry_drbg_blocklen (drbg) < (buflen - len)) ?
 	gcry_drbg_blocklen (drbg) : (buflen - len);
-      if (!gcry_drbg_fips_continuous_test (drbg, dst))
+      rret = gcry_drbg_fips_continuous_test (drbg, dst);
+      if (rret == -1)
 	{
+          /* discard first block of unprimed generator */
 	  gcry_drbg_add_buf (src, gcry_drbg_statelen (drbg), &prefix, 1);
 	  continue;
 	}
+      else if (!rret)
+        {
+          ret = gpg_error(fips_not_operational());
+          goto out;
+        }
       /* 10.1.1.4 step hashgen 4.2 */
       memcpy (buf + len, dst, outlen);
       len += outlen;