File libgcrypt-fips_handle_priming_error_in_drbg.patch of Package libgcrypt.25806
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;