From: Neil Horman <nhorman@redhat.com> Date: Fri, 23 Jan 2009 13:46:13 -0500 Subject: [crypto] bugfixes to ansi_cprng for fips compliance Message-id: 20090123184613.GG24153@hmsendeavour.rdu.redhat.com O-Subject: [RHEL5.4 PATCH] crypto: backport a few bugfixes to ansi_cprng for fips compliance Bugzilla: 481175 469437 RH-Acked-by: Jarod Wilson <jarod@redhat.com> Hey all- Below is a patch to backport a few upstream fixes to the ansi_cprng to bring it into fips compliance. Specifically Allow the DT value of a cprng instance to be specified when reseeding Upstream commit 2566578a6feb9d9e39da41326afe8ed6022db3c5 Force a panic if the continuous cprng self test fails awaiting upstream review/acceptance Set the NEED_RESET flag on a newly allocated instance of cprng awaiting upstream rewview/acceptance Neil diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 246a1ba..c858f4f 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -132,10 +132,20 @@ static int _get_more_prng_bytes(struct prng_context *ctx) */ if (!memcmp(ctx->rand_data, ctx->last_rand_data, DEFAULT_BLK_SZ)) { - printk(KERN_ERR - "ctx %p Failed repetition check!\n", - ctx); - ctx->flags |= PRNG_NEED_RESET; + if (fips_enabled) { + /* FIPS 140-2 requires that we disable + * further use of crypto code if we fail + * this test, easiest way to do that + * is panic the box + */ + panic("cprng %p failed continuity test", + ctx); + } else { + printk(KERN_ERR + "ctx %p Failed repetition check!\n", + ctx); + ctx->flags |= PRNG_NEED_RESET; + } return -EINVAL; } memcpy(ctx->last_rand_data, ctx->rand_data, @@ -338,7 +348,16 @@ static int cprng_init(struct ncrypto_tfm *tfm) spin_lock_init(&ctx->prng_lock); - return reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL); + if (reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL) < 0) + return -EINVAL; + + /* + * after allocation, we should always force the user to reset + * so they don't inadvertently use the insecure default values + * without specifying them intentially + */ + ctx->flags |= PRNG_NEED_RESET; + return 0; } static void cprng_exit(struct ncrypto_tfm *tfm) @@ -354,15 +373,25 @@ static int cprng_get_random(struct crypto_rng *tfm, u8 *rdata, return get_prng_bytes(rdata, dlen, prng); } +/* + * This is the cprng_registered reset method the seed value is + * interpreted as the tuple { V KEY DT} + * V and KEY are required during reset, and DT is optional, detected + * as being present by testing the length of the seed + */ static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) { struct prng_context *prng = crypto_rng_ctx(tfm); - u8 *key = seed + DEFAULT_PRNG_KSZ; + u8 *key = seed + DEFAULT_BLK_SZ; + u8 *dt = NULL; if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ) return -EINVAL; - reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, NULL); + if (slen >= (2 * DEFAULT_BLK_SZ + DEFAULT_PRNG_KSZ)) + dt = key + DEFAULT_PRNG_KSZ; + + reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, dt); if (prng->flags & PRNG_NEED_RESET) return -EINVAL; @@ -394,7 +423,7 @@ static int __init prng_mod_init(void) alg->rng_make_random = cprng_get_random; alg->rng_reset = cprng_reset; - alg->seedsize = DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ; + alg->seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ; ret = ncrypto_register_alg(&rng_alg);