From patchwork Wed Jan 26 07:03:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 12724646 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 20BF4C63686 for ; Wed, 26 Jan 2022 07:07:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237569AbiAZHHa (ORCPT ); Wed, 26 Jan 2022 02:07:30 -0500 Received: from mo4-p02-ob.smtp.rzone.de ([85.215.255.82]:42143 "EHLO mo4-p02-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237567AbiAZHH2 (ORCPT ); Wed, 26 Jan 2022 02:07:28 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1643180842; s=strato-dkim-0002; d=chronox.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=cCB2fmWYlFXySacF9soKSUtojjqAlOvUGhKoMAxqYXc=; b=BhsCb0RTCBiflBUJpMt7fPjZTD2EK4KSJztPk9G9ZNCBSR7aY6vIRXnI/OUoePUGco 9L5G9wGHJjvVWmCnCVy195E7dTCPSRsI9oAkmXhnyYLEO3cpg4iYEz1TzCaA6MT/iCvD CnDJJsyVSOxr5oQW+CBpa7yi+NmKuW3oEoEZpLINiXPgnE6h6ypNskLkuXGVrTI2msOd ELapUM0agsgat//q5GbUr8Kk6PE2v2Y27iB3TFZCUBNR0CR7UgIWXoWNhTp1LxR14Uo7 gL7IVf3TNBtcY5SSVZu++Q3zFDAvUzmLYnZVq9IXqdUzCRFpxOzOD4E1QhKP2mkS0k91 idTQ== Authentication-Results: strato.com; dkim=none X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvScdWrN" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 47.38.0 DYNA|AUTH) with ESMTPSA id v5f65ay0Q77MiuS (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 26 Jan 2022 08:07:22 +0100 (CET) From: Stephan =?iso-8859-1?q?M=FCller?= To: herbert@gondor.apana.org.au Cc: linux-crypto@vger.kernel.org, simo@redhat.com, Nicolai Stange Subject: [PATCH 1/7] crypto: DRBG - remove internal reseeding operation Date: Wed, 26 Jan 2022 08:03:16 +0100 Message-ID: <2450379.h6RI2rZIcs@positron.chronox.de> In-Reply-To: <2486550.t9SDvczpPo@positron.chronox.de> References: <2486550.t9SDvczpPo@positron.chronox.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The DRBG's internal seeding support is completely removed. When initializing the DRBG, it is now completely unseeded. The caller must provide the seed data and perform the reseeding as needed using the standard API of crypto_rng_reset. The seeding and reseeding is a security-critical task which is provided with a separate framework, the entropy source and DRNG manager (ESDM). When using the ESDM, the DRBG may be integrated to offer a fully seeded DRBG. The output of the ESDM in this case is generated from the DRBG, but the ESDM ensures the DRBG is appropriately seeded and reseeded. The change removes the "prediction resistance" variants of the DRBG. Those variants would cause the DRBG to constantly reseed from the entropy sources. As the seeding is appropriately performed by the ESDM, the prediction resistance variants are not needed. Due to the limitations of the kernel crypto API RNG framework, adding a personalization string is not supported during initial seeding. In addition, providing an additional information string during reseeding is not supported by the DRBG. If a user wants to still apply either string, the caller must concatenate it to the seed that is submitted to the DRBG. Yet, using an additional information string during the generation of random numbers is supported. The patch implies that the DRBG fully complies with the kernel crypto API RNG framework interfaces. All auxiliary interfaces are removed. The change also simplifies the drbg_instantiate function: the resolution of the coreref is now performed in the drbg_instantiate function as it is only needed during initial seeding. Subsequent reseeding operations flowing through this function do not need to perform this resolution. The DRBG code now rejects the initial instantiation with an empty seed buffer. An empty seed buffer during initial instantiation implies that the DRBG will not be seeded and does not have any internal state based on seed. Thus, a crypto_rng_reset(tfm, NULL, 0) immediately after an crypto_alloc_rng() will now fail. In addition, the patch removes FIPS 140-2 continuous test as its more sane equivalent is handled by the ESDM by applying a proper health test to the entropy sources that deliver entropy. The change is validated with the NIST ACVP reference implementation. The testing covered: - Hash DRBG with SHA-1, SHA-256, SHA-384, SHA-512 - HMAC DRBG with SHA-1, SHA-256, SHA-384, SHA-512 - CTR DRBG with AES-128, AES-192, AES-256 - reseeding, but without additional information - no reseeding, but with additional information Signed-off-by: Stephan Mueller Reported-by: kernel test robot --- crypto/algif_rng.c | 3 +- crypto/drbg.c | 640 ++++++++--------------------------------- crypto/testmgr.c | 96 +------ crypto/testmgr.h | 641 +----------------------------------------- include/crypto/drbg.h | 84 ------ 5 files changed, 140 insertions(+), 1324 deletions(-) diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c index 407408c43730..b204f1427542 100644 --- a/crypto/algif_rng.c +++ b/crypto/algif_rng.c @@ -305,7 +305,8 @@ static int __maybe_unused rng_setentropy(void *private, sockptr_t entropy, return PTR_ERR(kentropy); } - crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len); + if (crypto_rng_alg(pctx->drng)->set_ent) + crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len); /* * Since rng doesn't perform any memory management for the entropy * buffer, save kentropy pointer to pctx now to free it after use. diff --git a/crypto/drbg.c b/crypto/drbg.c index 177983b6ae38..67d9fef1af2a 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -7,7 +7,7 @@ * * HMAC DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores * * with and without prediction resistance * - * Copyright Stephan Mueller , 2014 + * Copyright Stephan Mueller , 2014 - 2022 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -43,10 +43,10 @@ * * DRBG Usage * ========== - * The SP 800-90A DRBG allows the user to specify a personalization string - * for initialization as well as an additional information string for each - * random number request. The following code fragments show how a caller - * uses the kernel crypto API to use the full functionality of the DRBG. + * The SP 800-90A DRBG allows the user to specify an additional information + * string for each random number request. The following code fragments show how + * a caller uses the kernel crypto API to use the full functionality of the + * DRBG. * * Usage without any additional data * --------------------------------- @@ -55,25 +55,22 @@ * char data[DATALEN]; * * drng = crypto_alloc_rng(drng_name, 0, 0); + * // The reset initializes the DRBG with the provided seed string + * err = crypto_rng_reset(drng, &seed, strlen(seed)); * err = crypto_rng_get_bytes(drng, &data, DATALEN); * crypto_free_rng(drng); * * * Usage with personalization string during initialization * ------------------------------------------------------- - * struct crypto_rng *drng; - * int err; - * char data[DATALEN]; - * struct drbg_string pers; - * char personalization[11] = "some-string"; + * This is not supported internally. If you want to use a personalization + * string during seeding, concatenate it at the end of the seed. * - * drbg_string_fill(&pers, personalization, strlen(personalization)); - * drng = crypto_alloc_rng(drng_name, 0, 0); - * // The reset completely re-initializes the DRBG with the provided - * // personalization string - * err = crypto_rng_reset(drng, &personalization, strlen(personalization)); - * err = crypto_rng_get_bytes(drng, &data, DATALEN); - * crypto_free_rng(drng); + * + * Usage with additional information during reseeding + * -------------------------------------------------- + * This is not supported internally. If you want to use an additional + * string during reseeding, concatenate it at the end of the reseed. * * * Usage with additional information string during random number request @@ -81,20 +78,17 @@ * struct crypto_rng *drng; * int err; * char data[DATALEN]; + * char addtlbuf[ADDTLLEN]; * char addtl_string[11] = "some-string"; - * string drbg_string addtl; * * drbg_string_fill(&addtl, addtl_string, strlen(addtl_string)); * drng = crypto_alloc_rng(drng_name, 0, 0); + * // The reset initializes the DRBG with the provided seed string + * err = crypto_rng_reset(drng, &seed, strlen(seed)); * // The following call is a wrapper to crypto_rng_get_bytes() and returns * // the same error codes. - * err = crypto_drbg_get_bytes_addtl(drng, &data, DATALEN, &addtl); + * err = crypto_rng_generate(drng, addtlbuf, ADDTLLEN, &data, DATALEN, &addtl); * crypto_free_rng(drng); - * - * - * Usage with personalization and additional information strings - * ------------------------------------------------------------- - * Just mix both scenarios above. */ #include @@ -221,57 +215,6 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags) } } -/* - * FIPS 140-2 continuous self test for the noise source - * The test is performed on the noise source input data. Thus, the function - * implicitly knows the size of the buffer to be equal to the security - * strength. - * - * Note, this function disregards the nonce trailing the entropy data during - * initial seeding. - * - * drbg->drbg_mutex must have been taken. - * - * @drbg DRBG handle - * @entropy buffer of seed data to be checked - * - * return: - * 0 on success - * -EAGAIN on when the CTRNG is not yet primed - * < 0 on error - */ -static int drbg_fips_continuous_test(struct drbg_state *drbg, - const unsigned char *entropy) -{ - unsigned short entropylen = drbg_sec_strength(drbg->core->flags); - int ret = 0; - - if (!IS_ENABLED(CONFIG_CRYPTO_FIPS)) - return 0; - - /* skip test if we test the overall system */ - if (list_empty(&drbg->test_data.list)) - return 0; - /* only perform test in FIPS mode */ - if (!fips_enabled) - return 0; - - if (!drbg->fips_primed) { - /* Priming of FIPS test */ - memcpy(drbg->prev, entropy, entropylen); - drbg->fips_primed = true; - /* priming: another round is needed */ - return -EAGAIN; - } - ret = memcmp(drbg->prev, entropy, entropylen); - if (!ret) - panic("DRBG continuous self test failed\n"); - memcpy(drbg->prev, entropy, entropylen); - - /* the test shall pass when the two values are not equal */ - return 0; -} - /* * Convert an integer into a byte representation of this integer. * The byte representation is big-endian @@ -298,11 +241,8 @@ static inline void drbg_cpu_to_be32(__u32 val, unsigned char *buf) #ifdef CONFIG_CRYPTO_DRBG_CTR #define CRYPTO_DRBG_CTR_STRING "CTR " -MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes256"); MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes256"); -MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes192"); MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes192"); -MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes128"); MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes128"); static void drbg_kcapi_symsetkey(struct drbg_state *drbg, @@ -642,13 +582,9 @@ static int drbg_fini_hash_kernel(struct drbg_state *drbg); #ifdef CONFIG_CRYPTO_DRBG_HMAC #define CRYPTO_DRBG_HMAC_STRING "HMAC " -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha384"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha384"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha256"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha256"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha1"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha1"); /* update function of HMAC DRBG as defined in 10.1.2.2 */ @@ -762,13 +698,9 @@ static const struct drbg_state_ops drbg_hmac_ops = { #ifdef CONFIG_CRYPTO_DRBG_HASH #define CRYPTO_DRBG_HASH_STRING "HASH " -MODULE_ALIAS_CRYPTO("drbg_pr_sha512"); MODULE_ALIAS_CRYPTO("drbg_nopr_sha512"); -MODULE_ALIAS_CRYPTO("drbg_pr_sha384"); MODULE_ALIAS_CRYPTO("drbg_nopr_sha384"); -MODULE_ALIAS_CRYPTO("drbg_pr_sha256"); MODULE_ALIAS_CRYPTO("drbg_nopr_sha256"); -MODULE_ALIAS_CRYPTO("drbg_pr_sha1"); MODULE_ALIAS_CRYPTO("drbg_nopr_sha1"); /* @@ -1036,221 +968,6 @@ static const struct drbg_state_ops drbg_hash_ops = { * Functions common for DRBG implementations ******************************************************************/ -static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, - int reseed, enum drbg_seed_state new_seed_state) -{ - int ret = drbg->d_ops->update(drbg, seed, reseed); - - if (ret) - return ret; - - drbg->seeded = new_seed_state; - drbg->last_seed_time = jiffies; - /* 10.1.1.2 / 10.1.1.3 step 5 */ - drbg->reseed_ctr = 1; - - switch (drbg->seeded) { - case DRBG_SEED_STATE_UNSEEDED: - /* Impossible, but handle it to silence compiler warnings. */ - fallthrough; - case DRBG_SEED_STATE_PARTIAL: - /* - * Require frequent reseeds until the seed source is - * fully initialized. - */ - drbg->reseed_threshold = 50; - break; - - case DRBG_SEED_STATE_FULL: - /* - * Seed source has become fully initialized, frequent - * reseeds no longer required. - */ - drbg->reseed_threshold = drbg_max_requests(drbg); - break; - } - - return ret; -} - -static inline int drbg_get_random_bytes(struct drbg_state *drbg, - unsigned char *entropy, - unsigned int entropylen) -{ - int ret; - - do { - get_random_bytes(entropy, entropylen); - ret = drbg_fips_continuous_test(drbg, entropy); - if (ret && ret != -EAGAIN) - return ret; - } while (ret); - - return 0; -} - -static int drbg_seed_from_random(struct drbg_state *drbg) -{ - struct drbg_string data; - LIST_HEAD(seedlist); - unsigned int entropylen = drbg_sec_strength(drbg->core->flags); - unsigned char entropy[32]; - int ret; - - BUG_ON(!entropylen); - BUG_ON(entropylen > sizeof(entropy)); - - drbg_string_fill(&data, entropy, entropylen); - list_add_tail(&data.list, &seedlist); - - ret = drbg_get_random_bytes(drbg, entropy, entropylen); - if (ret) - goto out; - - ret = __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); - -out: - memzero_explicit(entropy, entropylen); - return ret; -} - -static bool drbg_nopr_reseed_interval_elapsed(struct drbg_state *drbg) -{ - unsigned long next_reseed; - - /* Don't ever reseed from get_random_bytes() in test mode. */ - if (list_empty(&drbg->test_data.list)) - return false; - - /* - * Obtain fresh entropy for the nopr DRBGs after 300s have - * elapsed in order to still achieve sort of partial - * prediction resistance over the time domain at least. Note - * that the period of 300s has been chosen to match the - * CRNG_RESEED_INTERVAL of the get_random_bytes()' chacha - * rngs. - */ - next_reseed = drbg->last_seed_time + 300 * HZ; - return time_after(jiffies, next_reseed); -} - -/* - * Seeding or reseeding of the DRBG - * - * @drbg: DRBG state struct - * @pers: personalization / additional information buffer - * @reseed: 0 for initial seed process, 1 for reseeding - * - * return: - * 0 on success - * error value otherwise - */ -static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, - bool reseed) -{ - int ret; - unsigned char entropy[((32 + 16) * 2)]; - unsigned int entropylen = drbg_sec_strength(drbg->core->flags); - struct drbg_string data1; - LIST_HEAD(seedlist); - enum drbg_seed_state new_seed_state = DRBG_SEED_STATE_FULL; - - /* 9.1 / 9.2 / 9.3.1 step 3 */ - if (pers && pers->len > (drbg_max_addtl(drbg))) { - pr_devel("DRBG: personalization string too long %zu\n", - pers->len); - return -EINVAL; - } - - if (list_empty(&drbg->test_data.list)) { - drbg_string_fill(&data1, drbg->test_data.buf, - drbg->test_data.len); - pr_devel("DRBG: using test entropy\n"); - } else { - /* - * Gather entropy equal to the security strength of the DRBG. - * With a derivation function, a nonce is required in addition - * to the entropy. A nonce must be at least 1/2 of the security - * strength of the DRBG in size. Thus, entropy + nonce is 3/2 - * of the strength. The consideration of a nonce is only - * applicable during initial seeding. - */ - BUG_ON(!entropylen); - if (!reseed) - entropylen = ((entropylen + 1) / 2) * 3; - BUG_ON((entropylen * 2) > sizeof(entropy)); - - /* Get seed from in-kernel /dev/urandom */ - if (!rng_is_initialized()) - new_seed_state = DRBG_SEED_STATE_PARTIAL; - - ret = drbg_get_random_bytes(drbg, entropy, entropylen); - if (ret) - goto out; - - if (!drbg->jent) { - drbg_string_fill(&data1, entropy, entropylen); - pr_devel("DRBG: (re)seeding with %u bytes of entropy\n", - entropylen); - } else { - /* - * Get seed from Jitter RNG, failures are - * fatal only in FIPS mode. - */ - ret = crypto_rng_get_bytes(drbg->jent, - entropy + entropylen, - entropylen); - if (fips_enabled && ret) { - pr_devel("DRBG: jent failed with %d\n", ret); - - /* - * Do not treat the transient failure of the - * Jitter RNG as an error that needs to be - * reported. The combined number of the - * maximum reseed threshold times the maximum - * number of Jitter RNG transient errors is - * less than the reseed threshold required by - * SP800-90A allowing us to treat the - * transient errors as such. - * - * However, we mandate that at least the first - * seeding operation must succeed with the - * Jitter RNG. - */ - if (!reseed || ret != -EAGAIN) - goto out; - } - - drbg_string_fill(&data1, entropy, entropylen * 2); - pr_devel("DRBG: (re)seeding with %u bytes of entropy\n", - entropylen * 2); - } - } - list_add_tail(&data1.list, &seedlist); - - /* - * concatenation of entropy with personalization str / addtl input) - * the variable pers is directly handed in by the caller, so check its - * contents whether it is appropriate - */ - if (pers && pers->buf && 0 < pers->len) { - list_add_tail(&pers->list, &seedlist); - pr_devel("DRBG: using personalization string\n"); - } - - if (!reseed) { - memset(drbg->V, 0, drbg_statelen(drbg)); - memset(drbg->C, 0, drbg_statelen(drbg)); - } - - ret = __drbg_seed(drbg, &seedlist, reseed, new_seed_state); - -out: - memzero_explicit(entropy, entropylen * 2); - - return ret; -} - /* Free all substructures in a DRBG state without the DRBG state structure */ static inline void drbg_dealloc_state(struct drbg_state *drbg) { @@ -1267,11 +984,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) drbg->reseed_ctr = 0; drbg->d_ops = NULL; drbg->core = NULL; - if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) { - kfree_sensitive(drbg->prev); - drbg->prev = NULL; - drbg->fips_primed = false; - } } /* @@ -1314,12 +1026,14 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) goto fini; } drbg->V = PTR_ALIGN(drbg->Vbuf, ret + 1); + memset(drbg->V, 0, drbg_statelen(drbg)); drbg->Cbuf = kmalloc(drbg_statelen(drbg) + ret, GFP_KERNEL); if (!drbg->Cbuf) { ret = -ENOMEM; goto fini; } drbg->C = PTR_ALIGN(drbg->Cbuf, ret + 1); + memset(drbg->C, 0, drbg_statelen(drbg)); /* scratchpad is only generated for CTR and Hash */ if (drbg->core->flags & DRBG_HMAC) sb_size = 0; @@ -1341,16 +1055,6 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) drbg->scratchpad = PTR_ALIGN(drbg->scratchpadbuf, ret + 1); } - if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) { - drbg->prev = kzalloc(drbg_sec_strength(drbg->core->flags), - GFP_KERNEL); - if (!drbg->prev) { - ret = -ENOMEM; - goto fini; - } - drbg->fips_primed = false; - } - return 0; fini: @@ -1419,40 +1123,18 @@ static int drbg_generate(struct drbg_state *drbg, /* 9.3.1 step 5 is implicit with the chosen DRBG */ /* - * 9.3.1 step 6 and 9 supplemented by 9.3.2 step c is implemented - * here. The spec is a bit convoluted here, we make it simpler. + * 9.3.1 step 6 and 9 supplemented by 9.3.2 step c - the reseeding if + * too much data is pulled - is not implemented here but must be + * provided by the caller (e.g. the ESDM). */ - if (drbg->reseed_threshold < drbg->reseed_ctr) - drbg->seeded = DRBG_SEED_STATE_UNSEEDED; - - if (drbg->pr || drbg->seeded == DRBG_SEED_STATE_UNSEEDED) { - pr_devel("DRBG: reseeding before generation (prediction " - "resistance: %s, state %s)\n", - drbg->pr ? "true" : "false", - (drbg->seeded == DRBG_SEED_STATE_FULL ? - "seeded" : "unseeded")); - /* 9.3.1 steps 7.1 through 7.3 */ - len = drbg_seed(drbg, addtl, true); - if (len) - goto err; - /* 9.3.1 step 7.4 */ - addtl = NULL; - } else if (rng_is_initialized() && - (drbg->seeded == DRBG_SEED_STATE_PARTIAL || - drbg_nopr_reseed_interval_elapsed(drbg))) { - len = drbg_seed_from_random(drbg); - if (len) - goto err; - } if (addtl && 0 < addtl->len) list_add_tail(&addtl->list, &addtllist); /* 9.3.1 step 8 and 10 */ len = drbg->d_ops->generate(drbg, buf, buflen, &addtllist); - /* 10.1.1.4 step 6, 10.1.2.5 step 7, 10.2.1.5.2 step 7 */ drbg->reseed_ctr++; - if (0 >= len) + if (len < 0) goto err; /* @@ -1475,14 +1157,14 @@ static int drbg_generate(struct drbg_state *drbg, int err = 0; pr_devel("DRBG: start to perform self test\n"); if (drbg->core->flags & DRBG_HMAC) - err = alg_test("drbg_pr_hmac_sha256", - "drbg_pr_hmac_sha256", 0, 0); + err = alg_test("drbg_nopr_hmac_sha256", + "drbg_nopr_hmac_sha256", 0, 0); else if (drbg->core->flags & DRBG_CTR) - err = alg_test("drbg_pr_ctr_aes128", - "drbg_pr_ctr_aes128", 0, 0); + err = alg_test("drbg_nopr_ctr_aes128", + "drbg_nopr_ctr_aes128", 0, 0); else - err = alg_test("drbg_pr_sha256", - "drbg_pr_sha256", 0, 0); + err = alg_test("drbg_nopr_sha256", + "drbg_nopr_sha256", 0, 0); if (err) { pr_err("DRBG: periodical self test failed\n"); /* @@ -1535,96 +1217,123 @@ static int drbg_generate_long(struct drbg_state *drbg, return 0; } -static int drbg_prepare_hrng(struct drbg_state *drbg) +/* + * Seeding or reseeding of the DRBG + * + * @drbg: DRBG state struct + * @pers: personalization / additional information buffer + * @reseed: 0 for initial seed process, 1 for reseeding + * + * return: + * 0 on success + * error value otherwise + */ +static int drbg_seed(struct drbg_state *drbg, struct list_head *seed, + int reseed) { - /* We do not need an HRNG in test mode. */ - if (list_empty(&drbg->test_data.list)) - return 0; + int ret = drbg->d_ops->update(drbg, seed, reseed); - drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0); - if (IS_ERR(drbg->jent)) { - const int err = PTR_ERR(drbg->jent); + if (ret) + return ret; - drbg->jent = NULL; - if (fips_enabled || err != -ENOENT) - return err; - pr_info("DRBG: Continuing without Jitter RNG\n"); - } + /* 10.1.1.2 / 10.1.1.3 step 5 */ + drbg->reseed_ctr = 1; - return 0; + return ret; +} + +/* + * Look up the DRBG flags by given kernel crypto API cra_name + * The code uses the drbg_cores definition to do this + * + * @cra_name kernel crypto API cra_name + * @coreref reference to integer which is filled with the pointer to + * the applicable core + */ +static inline int drbg_convert_tfm_core(const char *cra_driver_name, + int *coreref) +{ + int i = 0, len = 0; + + len = strlen(cra_driver_name); + if (len < 10) + return -ENOENT; + len -= 10; + + /* disassemble the name */ + if (memcmp(cra_driver_name, "drbg_nopr_", 10)) + return -ENOENT; + + /* remove the first part */ + for (i = 0; ARRAY_SIZE(drbg_cores) > i; i++) { + if (!memcmp(cra_driver_name + 10, drbg_cores[i].cra_name, + len)) { + *coreref = i; + return 0; + } + } + return -ENOENT; } /* * DRBG instantiation function as required by SP800-90A - this function - * sets up the DRBG handle, performs the initial seeding and all sanity - * checks required by SP800-90A + * sets up the DRBG handle if needed and seeds the DRBG with entropy. If the + * DRBG is already instantiated, the DRBG is simply reseeded. * - * @drbg memory of state -- if NULL, new memory is allocated - * @pers Personalization string that is mixed into state, may be NULL -- note - * the entropy is pulled by the DRBG internally unconditionally - * as defined in SP800-90A. The additional input is mixed into - * the state in addition to the pulled entropy. - * @coreref reference to core - * @pr prediction resistance enabled + * @tfm: tfm cipher handle with DRBG state (may be uninitialized) + * @seed: buffer with the entropy data to (re)seed the DRBG + * @slen: length of seed buffer * * return * 0 on success * error value otherwise */ -static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, - int coreref, bool pr) +static int drbg_instantiate(struct crypto_rng *tfm, + const u8 *seed, unsigned int slen) { + struct drbg_state *drbg = crypto_rng_ctx(tfm); + struct drbg_string seeddata; + LIST_HEAD(seedlist); int ret; bool reseed = true; - pr_devel("DRBG: Initializing DRBG core %d with prediction resistance " - "%s\n", coreref, pr ? "enabled" : "disabled"); + drbg_string_fill(&seeddata, seed, slen); + list_add_tail(&seeddata.list, &seedlist); + mutex_lock(&drbg->drbg_mutex); /* 9.1 step 1 is implicit with the selected DRBG type */ - - /* - * 9.1 step 2 is implicit as caller can select prediction resistance - * and the flag is copied into drbg->flags -- - * all DRBG types support prediction resistance - */ - + /* 9.1 step 2 is implicit as no prediction resistance is supported */ /* 9.1 step 4 is implicit in drbg_sec_strength */ if (!drbg->core) { + struct crypto_tfm *tfm_base = crypto_rng_tfm(tfm); + int coreref = 0; + + if (!slen) { + pr_warn("DRBG: initial seed missing\n"); + return -EINVAL; + } + + pr_devel("DRBG: Initializing DRBG core %d\n", coreref); + ret = drbg_convert_tfm_core( + crypto_tfm_alg_driver_name(tfm_base), &coreref); + if (ret) + return ret; drbg->core = &drbg_cores[coreref]; - drbg->pr = pr; - drbg->seeded = DRBG_SEED_STATE_UNSEEDED; - drbg->last_seed_time = 0; - drbg->reseed_threshold = drbg_max_requests(drbg); ret = drbg_alloc_state(drbg); if (ret) goto unlock; - ret = drbg_prepare_hrng(drbg); - if (ret) - goto free_everything; - reseed = false; } - ret = drbg_seed(drbg, pers, reseed); - - if (ret && !reseed) - goto free_everything; - - mutex_unlock(&drbg->drbg_mutex); - return ret; + ret = drbg_seed(drbg, &seedlist, reseed); unlock: mutex_unlock(&drbg->drbg_mutex); return ret; - -free_everything: - mutex_unlock(&drbg->drbg_mutex); - drbg_uninstantiate(drbg); - return ret; } /* @@ -1638,34 +1347,12 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, */ static int drbg_uninstantiate(struct drbg_state *drbg) { - if (!IS_ERR_OR_NULL(drbg->jent)) - crypto_free_rng(drbg->jent); - drbg->jent = NULL; - if (drbg->d_ops) drbg->d_ops->crypto_fini(drbg); drbg_dealloc_state(drbg); - /* no scrubbing of test_data -- this shall survive an uninstantiate */ return 0; } -/* - * Helper function for setting the test data in the DRBG - * - * @drbg DRBG state handle - * @data test data - * @len test data length - */ -static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, - const u8 *data, unsigned int len) -{ - struct drbg_state *drbg = crypto_rng_ctx(tfm); - - mutex_lock(&drbg->drbg_mutex); - drbg_string_fill(&drbg->test_data, data, len); - mutex_unlock(&drbg->drbg_mutex); -} - /*************************************************************** * Kernel crypto API cipher invocations requested by DRBG ***************************************************************/ @@ -1884,46 +1571,6 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg, * Kernel crypto API interface to register DRBG ***************************************************************/ -/* - * Look up the DRBG flags by given kernel crypto API cra_name - * The code uses the drbg_cores definition to do this - * - * @cra_name kernel crypto API cra_name - * @coreref reference to integer which is filled with the pointer to - * the applicable core - * @pr reference for setting prediction resistance - * - * return: flags - */ -static inline void drbg_convert_tfm_core(const char *cra_driver_name, - int *coreref, bool *pr) -{ - int i = 0; - size_t start = 0; - int len = 0; - - *pr = true; - /* disassemble the names */ - if (!memcmp(cra_driver_name, "drbg_nopr_", 10)) { - start = 10; - *pr = false; - } else if (!memcmp(cra_driver_name, "drbg_pr_", 8)) { - start = 8; - } else { - return; - } - - /* remove the first part */ - len = strlen(cra_driver_name) - start; - for (i = 0; ARRAY_SIZE(drbg_cores) > i; i++) { - if (!memcmp(cra_driver_name + start, drbg_cores[i].cra_name, - len)) { - *coreref = i; - return; - } - } -} - static int drbg_kcapi_init(struct crypto_tfm *tfm) { struct drbg_state *drbg = crypto_tfm_ctx(tfm); @@ -1970,21 +1617,7 @@ static int drbg_kcapi_random(struct crypto_rng *tfm, static int drbg_kcapi_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) { - struct drbg_state *drbg = crypto_rng_ctx(tfm); - struct crypto_tfm *tfm_base = crypto_rng_tfm(tfm); - bool pr = false; - struct drbg_string string; - struct drbg_string *seed_string = NULL; - int coreref = 0; - - drbg_convert_tfm_core(crypto_tfm_alg_driver_name(tfm_base), &coreref, - &pr); - if (0 < slen) { - drbg_string_fill(&string, seed, slen); - seed_string = &string; - } - - return drbg_instantiate(drbg, seed_string, coreref, pr); + return drbg_instantiate(tfm, seed, slen); } /*************************************************************** @@ -2007,9 +1640,7 @@ static inline int __init drbg_healthcheck_sanity(void) #define OUTBUFLEN 16 unsigned char buf[OUTBUFLEN]; struct drbg_state *drbg = NULL; - int ret; int rc = -EFAULT; - bool pr = false; int coreref = 0; struct drbg_string addtl; size_t max_addtllen, max_request_bytes; @@ -2019,12 +1650,14 @@ static inline int __init drbg_healthcheck_sanity(void) return 0; #ifdef CONFIG_CRYPTO_DRBG_CTR - drbg_convert_tfm_core("drbg_nopr_ctr_aes128", &coreref, &pr); + rc = drbg_convert_tfm_core("drbg_nopr_ctr_aes128", &coreref); #elif defined CONFIG_CRYPTO_DRBG_HASH - drbg_convert_tfm_core("drbg_nopr_sha256", &coreref, &pr); + rc = drbg_convert_tfm_core("drbg_nopr_sha256", &coreref); #else - drbg_convert_tfm_core("drbg_nopr_hmac_sha256", &coreref, &pr); + rc = drbg_convert_tfm_core("drbg_nopr_hmac_sha256", &coreref); #endif + if (rc) + return rc; drbg = kzalloc(sizeof(struct drbg_state), GFP_KERNEL); if (!drbg) @@ -2032,7 +1665,6 @@ static inline int __init drbg_healthcheck_sanity(void) mutex_init(&drbg->drbg_mutex); drbg->core = &drbg_cores[coreref]; - drbg->reseed_threshold = drbg_max_requests(drbg); /* * if the following tests fail, it is likely that there is a buffer @@ -2052,9 +1684,6 @@ static inline int __init drbg_healthcheck_sanity(void) len = drbg_generate(drbg, buf, (max_request_bytes + 1), NULL); BUG_ON(0 < len); - /* overflow max addtllen with personalization string */ - ret = drbg_seed(drbg, &addtl, false); - BUG_ON(0 == ret); /* all tests passed */ rc = 0; @@ -2065,7 +1694,7 @@ static inline int __init drbg_healthcheck_sanity(void) return rc; } -static struct rng_alg drbg_algs[22]; +static struct rng_alg drbg_algs[11]; /* * Fill the array drbg_algs used to register the different DRBGs @@ -2073,20 +1702,13 @@ static struct rng_alg drbg_algs[22]; * from drbg_cores[] is used. */ static inline void __init drbg_fill_array(struct rng_alg *alg, - const struct drbg_core *core, int pr) + const struct drbg_core *core) { - int pos = 0; static int priority = 200; memcpy(alg->base.cra_name, "stdrng", 6); - if (pr) { - memcpy(alg->base.cra_driver_name, "drbg_pr_", 8); - pos = 8; - } else { - memcpy(alg->base.cra_driver_name, "drbg_nopr_", 10); - pos = 10; - } - memcpy(alg->base.cra_driver_name + pos, core->cra_name, + memcpy(alg->base.cra_driver_name, "drbg_nopr_", 10); + memcpy(alg->base.cra_driver_name + 10, core->cra_name, strlen(core->cra_name)); alg->base.cra_priority = priority; @@ -2105,41 +1727,29 @@ static inline void __init drbg_fill_array(struct rng_alg *alg, alg->base.cra_exit = drbg_kcapi_cleanup; alg->generate = drbg_kcapi_random; alg->seed = drbg_kcapi_seed; - alg->set_ent = drbg_kcapi_set_entropy; alg->seedsize = 0; } static int __init drbg_init(void) { - unsigned int i = 0; /* pointer to drbg_algs */ - unsigned int j = 0; /* pointer to drbg_cores */ + unsigned int i; int ret; ret = drbg_healthcheck_sanity(); if (ret) return ret; - if (ARRAY_SIZE(drbg_cores) * 2 > ARRAY_SIZE(drbg_algs)) { - pr_info("DRBG: Cannot register all DRBG types" - "(slots needed: %zu, slots available: %zu)\n", - ARRAY_SIZE(drbg_cores) * 2, ARRAY_SIZE(drbg_algs)); - return -EFAULT; - } + BUILD_BUG_ON(ARRAY_SIZE(drbg_cores) != ARRAY_SIZE(drbg_algs)); /* - * each DRBG definition can be used with PR and without PR, thus - * we instantiate each DRBG in drbg_cores[] twice. - * * As the order of placing them into the drbg_algs array matters * (the later DRBGs receive a higher cra_priority) we register the * prediction resistance DRBGs first as the should not be too * interesting. */ - for (j = 0; ARRAY_SIZE(drbg_cores) > j; j++, i++) - drbg_fill_array(&drbg_algs[i], &drbg_cores[j], 1); - for (j = 0; ARRAY_SIZE(drbg_cores) > j; j++, i++) - drbg_fill_array(&drbg_algs[i], &drbg_cores[j], 0); - return crypto_register_rngs(drbg_algs, (ARRAY_SIZE(drbg_cores) * 2)); + for (i = 0; i < ARRAY_SIZE(drbg_cores); i++) + drbg_fill_array(&drbg_algs[i], &drbg_cores[i]); + return crypto_register_rngs(drbg_algs, ARRAY_SIZE(drbg_cores)); } static void __exit drbg_exit(void) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 5831d4bbc64f..2ce698eb14b6 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -3635,13 +3635,11 @@ static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver, } -static int drbg_cavs_test(const struct drbg_testvec *test, int pr, +static int drbg_cavs_test(const struct drbg_testvec *test, const char *driver, u32 type, u32 mask) { int ret = -EAGAIN; struct crypto_rng *drng; - struct drbg_test_data test_data; - struct drbg_string addtl, pers, testentropy; unsigned char *buf = kzalloc(test->expectedlen, GFP_KERNEL); if (!buf) @@ -3655,47 +3653,29 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr, return -ENOMEM; } - test_data.testentropy = &testentropy; - drbg_string_fill(&testentropy, test->entropy, test->entropylen); - drbg_string_fill(&pers, test->pers, test->perslen); - ret = crypto_drbg_reset_test(drng, &pers, &test_data); + ret = crypto_rng_reset(drng, test->entropy, test->entropylen); if (ret) { printk(KERN_ERR "alg: drbg: Failed to reset rng\n"); goto outbuf; } - drbg_string_fill(&addtl, test->addtla, test->addtllen); - if (pr) { - drbg_string_fill(&testentropy, test->entpra, test->entprlen); - ret = crypto_drbg_get_bytes_addtl_test(drng, - buf, test->expectedlen, &addtl, &test_data); - } else { - ret = crypto_drbg_get_bytes_addtl(drng, - buf, test->expectedlen, &addtl); - } + ret = crypto_rng_generate(drng, test->addtla, test->addtllen, + buf, test->expectedlen); + if (ret < 0) { printk(KERN_ERR "alg: drbg: could not obtain random data for " "driver %s\n", driver); goto outbuf; } - drbg_string_fill(&addtl, test->addtlb, test->addtllen); - if (pr) { - drbg_string_fill(&testentropy, test->entprb, test->entprlen); - ret = crypto_drbg_get_bytes_addtl_test(drng, - buf, test->expectedlen, &addtl, &test_data); - } else { - ret = crypto_drbg_get_bytes_addtl(drng, - buf, test->expectedlen, &addtl); - } + ret = crypto_rng_generate(drng, test->addtlb, test->addtllen, + buf, test->expectedlen); if (ret < 0) { printk(KERN_ERR "alg: drbg: could not obtain random data for " "driver %s\n", driver); goto outbuf; } - ret = memcmp(test->expected, buf, test->expectedlen); - outbuf: crypto_free_rng(drng); kfree_sensitive(buf); @@ -3707,16 +3687,12 @@ static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask) { int err = 0; - int pr = 0; int i = 0; const struct drbg_testvec *template = desc->suite.drbg.vecs; unsigned int tcount = desc->suite.drbg.count; - if (0 == memcmp(driver, "drbg_pr_", 8)) - pr = 1; - for (i = 0; i < tcount; i++) { - err = drbg_cavs_test(&template[i], pr, driver, type, mask); + err = drbg_cavs_test(&template[i], driver, type, mask); if (err) { printk(KERN_ERR "alg: drbg: Test %d failed for %s\n", i, driver); @@ -4725,62 +4701,6 @@ static const struct alg_test_desc alg_test_descs[] = { .alg = "drbg_nopr_sha512", .fips_allowed = 1, .test = alg_test_null, - }, { - .alg = "drbg_pr_ctr_aes128", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_ctr_aes128_tv_template) - } - }, { - /* covered by drbg_pr_ctr_aes128 test */ - .alg = "drbg_pr_ctr_aes192", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_ctr_aes256", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_hmac_sha1", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_hmac_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_hmac_sha256_tv_template) - } - }, { - /* covered by drbg_pr_hmac_sha256 test */ - .alg = "drbg_pr_hmac_sha384", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_hmac_sha512", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "drbg_pr_sha1", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_sha256_tv_template) - } - }, { - /* covered by drbg_pr_sha256 test */ - .alg = "drbg_pr_sha384", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_sha512", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "ecb(aes)", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index a253d66ba1c1..99a422816377 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -134,14 +134,9 @@ struct cprng_testvec { struct drbg_testvec { const unsigned char *entropy; size_t entropylen; - const unsigned char *entpra; - const unsigned char *entprb; - size_t entprlen; const unsigned char *addtla; const unsigned char *addtlb; size_t addtllen; - const unsigned char *pers; - size_t perslen; const unsigned char *expected; size_t expectedlen; }; @@ -21440,453 +21435,13 @@ static const struct cprng_testvec ansi_cprng_aes_tv_template[] = { }, }; -/* - * SP800-90A DRBG Test vectors from - * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip - * - * Test vectors for DRBG with prediction resistance. All types of DRBGs - * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and - * w/o personalization string, w/ and w/o additional input string). - */ -static const struct drbg_testvec drbg_pr_sha256_tv_template[] = { - { - .entropy = (unsigned char *) - "\x72\x88\x4c\xcd\x6c\x85\x57\x70\xf7\x0b\x8b\x86" - "\xc1\xeb\xd2\x4e\x36\x14\xab\x18\xc4\x9c\xc9\xcf" - "\x1a\xe8\xf7\x7b\x02\x49\x73\xd7\xf1\x42\x7d\xc6" - "\x3f\x29\x2d\xec\xd3\x66\x51\x3f\x1d\x8d\x5b\x4e", - .entropylen = 48, - .entpra = (unsigned char *) - "\x38\x9c\x91\xfa\xc2\xa3\x46\x89\x56\x08\x3f\x62" - "\x73\xd5\x22\xa9\x29\x63\x3a\x1d\xe5\x5d\x5e\x4f" - "\x67\xb0\x67\x7a\x5e\x9e\x0c\x62", - .entprb = (unsigned char *) - "\xb2\x8f\x36\xb2\xf6\x8d\x39\x13\xfa\x6c\x66\xcf" - "\x62\x8a\x7e\x8c\x12\x33\x71\x9c\x69\xe4\xa5\xf0" - "\x8c\xee\xeb\x9c\xf5\x31\x98\x31", - .entprlen = 32, - .expected = (unsigned char *) - "\x52\x7b\xa3\xad\x71\x77\xa4\x49\x42\x04\x61\xc7" - "\xf0\xaf\xa5\xfd\xd3\xb3\x0d\x6a\x61\xba\x35\x49" - "\xbb\xaa\xaf\xe4\x25\x7d\xb5\x48\xaf\x5c\x18\x3d" - "\x33\x8d\x9d\x45\xdf\x98\xd5\x94\xa8\xda\x92\xfe" - "\xc4\x3c\x94\x2a\xcf\x7f\x7b\xf2\xeb\x28\xa9\xf1" - "\xe0\x86\x30\xa8\xfe\xf2\x48\x90\x91\x0c\x75\xb5" - "\x3c\x00\xf0\x4d\x09\x4f\x40\xa7\xa2\x8c\x52\xdf" - "\x52\xef\x17\xbf\x3d\xd1\xa2\x31\xb4\xb8\xdc\xe6" - "\x5b\x0d\x1f\x78\x36\xb4\xe6\x4b\xa7\x11\x25\xd5" - "\x94\xc6\x97\x36\xab\xf0\xe5\x31\x28\x6a\xbb\xce" - "\x30\x81\xa6\x8f\x27\x14\xf8\x1c", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x5d\xf2\x14\xbc\xf6\xb5\x4e\x0b\xf0\x0d\x6f\x2d" - "\xe2\x01\x66\x7b\xd0\xa4\x73\xa4\x21\xdd\xb0\xc0" - "\x51\x79\x09\xf4\xea\xa9\x08\xfa\xa6\x67\xe0\xe1" - "\xd1\x88\xa8\xad\xee\x69\x74\xb3\x55\x06\x9b\xf6", - .entropylen = 48, - .entpra = (unsigned char *) - "\xef\x48\x06\xa2\xc2\x45\xf1\x44\xfa\x34\x2c\xeb" - "\x8d\x78\x3c\x09\x8f\x34\x72\x20\xf2\xe7\xfd\x13" - "\x76\x0a\xf6\xdc\x3c\xf5\xc0\x15", - .entprb = (unsigned char *) - "\x4b\xbe\xe5\x24\xed\x6a\x2d\x0c\xdb\x73\x5e\x09" - "\xf9\xad\x67\x7c\x51\x47\x8b\x6b\x30\x2a\xc6\xde" - "\x76\xaa\x55\x04\x8b\x0a\x72\x95", - .entprlen = 32, - .expected = (unsigned char *) - "\x3b\x14\x71\x99\xa1\xda\xa0\x42\xe6\xc8\x85\x32" - "\x70\x20\x32\x53\x9a\xbe\xd1\x1e\x15\xef\xfb\x4c" - "\x25\x6e\x19\x3a\xf0\xb9\xcb\xde\xf0\x3b\xc6\x18" - "\x4d\x85\x5a\x9b\xf1\xe3\xc2\x23\x03\x93\x08\xdb" - "\xa7\x07\x4b\x33\x78\x40\x4d\xeb\x24\xf5\x6e\x81" - "\x4a\x1b\x6e\xa3\x94\x52\x43\xb0\xaf\x2e\x21\xf4" - "\x42\x46\x8e\x90\xed\x34\x21\x75\xea\xda\x67\xb6" - "\xe4\xf6\xff\xc6\x31\x6c\x9a\x5a\xdb\xb3\x97\x13" - "\x09\xd3\x20\x98\x33\x2d\x6d\xd7\xb5\x6a\xa8\xa9" - "\x9a\x5b\xd6\x87\x52\xa1\x89\x2b\x4b\x9c\x64\x60" - "\x50\x47\xa3\x63\x81\x16\xaf\x19", - .expectedlen = 128, - .addtla = (unsigned char *) - "\xbe\x13\xdb\x2a\xe9\xa8\xfe\x09\x97\xe1\xce\x5d" - "\xe8\xbb\xc0\x7c\x4f\xcb\x62\x19\x3f\x0f\xd2\xad" - "\xa9\xd0\x1d\x59\x02\xc4\xff\x70", - .addtlb = (unsigned char *) - "\x6f\x96\x13\xe2\xa7\xf5\x6c\xfe\xdf\x66\xe3\x31" - "\x63\x76\xbf\x20\x27\x06\x49\xf1\xf3\x01\x77\x41" - "\x9f\xeb\xe4\x38\xfe\x67\x00\xcd", - .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xc6\x1c\xaf\x83\xa2\x56\x38\xf9\xb0\xbc\xd9\x85" - "\xf5\x2e\xc4\x46\x9c\xe1\xb9\x40\x98\x70\x10\x72" - "\xd7\x7d\x15\x85\xa1\x83\x5a\x97\xdf\xc8\xa8\xe8" - "\x03\x4c\xcb\x70\x35\x8b\x90\x94\x46\x8a\x6e\xa1", - .entropylen = 48, - .entpra = (unsigned char *) - "\xc9\x05\xa4\xcf\x28\x80\x4b\x93\x0f\x8b\xc6\xf9" - "\x09\x41\x58\x74\xe9\xec\x28\xc7\x53\x0a\x73\x60" - "\xba\x0a\xde\x57\x5b\x4b\x9f\x29", - .entprb = (unsigned char *) - "\x4f\x31\xd2\xeb\xac\xfa\xa8\xe2\x01\x7d\xf3\xbd" - "\x42\xbd\x20\xa0\x30\x65\x74\xd5\x5d\xd2\xad\xa4" - "\xa9\xeb\x1f\x4d\xf6\xfd\xb8\x26", - .entprlen = 32, - .expected = (unsigned char *) - "\xf6\x13\x05\xcb\x83\x60\x16\x42\x49\x1d\xc6\x25" - "\x3b\x8c\x31\xa3\xbe\x8b\xbd\x1c\xe2\xec\x1d\xde" - "\xbb\xbf\xa1\xac\xa8\x9f\x50\xce\x69\xce\xef\xd5" - "\xd6\xf2\xef\x6a\xf7\x81\x38\xdf\xbc\xa7\x5a\xb9" - "\xb2\x42\x65\xab\xe4\x86\x8d\x2d\x9d\x59\x99\x2c" - "\x5a\x0d\x71\x55\x98\xa4\x45\xc2\x8d\xdb\x05\x5e" - "\x50\x21\xf7\xcd\xe8\x98\x43\xce\x57\x74\x63\x4c" - "\xf3\xb1\xa5\x14\x1e\x9e\x01\xeb\x54\xd9\x56\xae" - "\xbd\xb6\x6f\x1a\x47\x6b\x3b\x44\xe4\xa2\xe9\x3c" - "\x6c\x83\x12\x30\xb8\x78\x7f\x8e\x54\x82\xd4\xfe" - "\x90\x35\x0d\x4c\x4d\x85\xe7\x13", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xa5\xbf\xac\x4f\x71\xa1\xbb\x67\x94\xc6\x50\xc7" - "\x2a\x45\x9e\x10\xa8\xed\xf7\x52\x4f\xfe\x21\x90" - "\xa4\x1b\xe1\xe2\x53\xcc\x61\x47", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\xb6\xc1\x8d\xdf\x99\x54\xbe\x95\x10\x48\xd9\xf6" - "\xd7\x48\xa8\x73\x2d\x74\xde\x1e\xde\x57\x7e\xf4" - "\x7b\x7b\x64\xef\x88\x7a\xa8\x10\x4b\xe1\xc1\x87" - "\xbb\x0b\xe1\x39\x39\x50\xaf\x68\x9c\xa2\xbf\x5e", - .entropylen = 48, - .entpra = (unsigned char *) - "\xdc\x81\x0a\x01\x58\xa7\x2e\xce\xee\x48\x8c\x7c" - "\x77\x9e\x3c\xf1\x17\x24\x7a\xbb\xab\x9f\xca\x12" - "\x19\xaf\x97\x2d\x5f\xf9\xff\xfc", - .entprb = (unsigned char *) - "\xaf\xfc\x4f\x98\x8b\x93\x95\xc1\xb5\x8b\x7f\x73" - "\x6d\xa6\xbe\x6d\x33\xeb\x2c\x82\xb1\xaf\xc1\xb6" - "\xb6\x05\xe2\x44\xaa\xfd\xe7\xdb", - .entprlen = 32, - .expected = (unsigned char *) - "\x51\x79\xde\x1c\x0f\x58\xf3\xf4\xc9\x57\x2e\x31" - "\xa7\x09\xa1\x53\x64\x63\xa2\xc5\x1d\x84\x88\x65" - "\x01\x1b\xc6\x16\x3c\x49\x5b\x42\x8e\x53\xf5\x18" - "\xad\x94\x12\x0d\x4f\x55\xcc\x45\x5c\x98\x0f\x42" - "\x28\x2f\x47\x11\xf9\xc4\x01\x97\x6b\xa0\x94\x50" - "\xa9\xd1\x5e\x06\x54\x3f\xdf\xbb\xc4\x98\xee\x8b" - "\xba\xa9\xfa\x49\xee\x1d\xdc\xfb\x50\xf6\x51\x9f" - "\x6c\x4a\x9a\x6f\x63\xa2\x7d\xad\xaf\x3a\x24\xa0" - "\xd9\x9f\x07\xeb\x15\xee\x26\xe0\xd5\x63\x39\xda" - "\x3c\x59\xd6\x33\x6c\x02\xe8\x05\x71\x46\x68\x44" - "\x63\x4a\x68\x72\xe9\xf5\x55\xfe", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x15\x20\x2f\xf6\x98\x28\x63\xa2\xc4\x4e\xbb\x6c" - "\xb2\x25\x92\x61\x79\xc9\x22\xc4\x61\x54\x96\xff" - "\x4a\x85\xca\x80\xfe\x0d\x1c\xd0", - .addtlb = (unsigned char *) - "\xde\x29\x8e\x03\x42\x61\xa3\x28\x5e\xc8\x80\xc2" - "\x6d\xbf\xad\x13\xe1\x8d\x2a\xc7\xe8\xc7\x18\x89" - "\x42\x58\x9e\xd6\xcc\xad\x7b\x1e", - .addtllen = 32, - .pers = (unsigned char *) - "\x84\xc3\x73\x9e\xce\xb3\xbc\x89\xf7\x62\xb3\xe1" - "\xd7\x48\x45\x8a\xa9\xcc\xe9\xed\xd5\x81\x84\x52" - "\x82\x4c\xdc\x19\xb8\xf8\x92\x5c", - .perslen = 32, - }, -}; - -static const struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { - { - .entropy = (unsigned char *) - "\x99\x69\xe5\x4b\x47\x03\xff\x31\x78\x5b\x87\x9a" - "\x7e\x5c\x0e\xae\x0d\x3e\x30\x95\x59\xe9\xfe\x96" - "\xb0\x67\x6d\x49\xd5\x91\xea\x4d\x07\xd2\x0d\x46" - "\xd0\x64\x75\x7d\x30\x23\xca\xc2\x37\x61\x27\xab", - .entropylen = 48, - .entpra = (unsigned char *) - "\xc6\x0f\x29\x99\x10\x0f\x73\x8c\x10\xf7\x47\x92" - "\x67\x6a\x3f\xc4\xa2\x62\xd1\x37\x21\x79\x80\x46" - "\xe2\x9a\x29\x51\x81\x56\x9f\x54", - .entprb = (unsigned char *) - "\xc1\x1d\x45\x24\xc9\x07\x1b\xd3\x09\x60\x15\xfc" - "\xf7\xbc\x24\xa6\x07\xf2\x2f\xa0\x65\xc9\x37\x65" - "\x8a\x2a\x77\xa8\x69\x90\x89\xf4", - .entprlen = 32, - .expected = (unsigned char *) - "\xab\xc0\x15\x85\x60\x94\x80\x3a\x93\x8d\xff\xd2" - "\x0d\xa9\x48\x43\x87\x0e\xf9\x35\xb8\x2c\xfe\xc1" - "\x77\x06\xb8\xf5\x51\xb8\x38\x50\x44\x23\x5d\xd4" - "\x4b\x59\x9f\x94\xb3\x9b\xe7\x8d\xd4\x76\xe0\xcf" - "\x11\x30\x9c\x99\x5a\x73\x34\xe0\xa7\x8b\x37\xbc" - "\x95\x86\x23\x50\x86\xfa\x3b\x63\x7b\xa9\x1c\xf8" - "\xfb\x65\xef\xa2\x2a\x58\x9c\x13\x75\x31\xaa\x7b" - "\x2d\x4e\x26\x07\xaa\xc2\x72\x92\xb0\x1c\x69\x8e" - "\x6e\x01\xae\x67\x9e\xb8\x7c\x01\xa8\x9c\x74\x22" - "\xd4\x37\x2d\x6d\x75\x4a\xba\xbb\x4b\xf8\x96\xfc" - "\xb1\xcd\x09\xd6\x92\xd0\x28\x3f", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xb9\x1f\xe9\xef\xdd\x9b\x7d\x20\xb6\xec\xe0\x2f" - "\xdb\x76\x24\xce\x41\xc8\x3a\x4a\x12\x7f\x3e\x2f" - "\xae\x05\x99\xea\xb5\x06\x71\x0d\x0c\x4c\xb4\x05" - "\x26\xc6\xbd\xf5\x7f\x2a\x3d\xf2\xb5\x49\x7b\xda", - .entropylen = 48, - .entpra = (unsigned char *) - "\xef\x67\x50\x9c\xa7\x7d\xdf\xb7\x2d\x81\x01\xa4" - "\x62\x81\x6a\x69\x5b\xb3\x37\x45\xa7\x34\x8e\x26" - "\x46\xd9\x26\xa2\x19\xd4\x94\x43", - .entprb = (unsigned char *) - "\x97\x75\x53\x53\xba\xb4\xa6\xb2\x91\x60\x71\x79" - "\xd1\x6b\x4a\x24\x9a\x34\x66\xcc\x33\xab\x07\x98" - "\x51\x78\x72\xb2\x79\xfd\x2c\xff", - .entprlen = 32, - .expected = (unsigned char *) - "\x9c\xdc\x63\x8a\x19\x23\x22\x66\x0c\xc5\xb9\xd7" - "\xfb\x2a\xb0\x31\xe3\x8a\x36\xa8\x5a\xa8\x14\xda" - "\x1e\xa9\xcc\xfe\xb8\x26\x44\x83\x9f\xf6\xff\xaa" - "\xc8\x98\xb8\x30\x35\x3b\x3d\x36\xd2\x49\xd4\x40" - "\x62\x0a\x65\x10\x76\x55\xef\xc0\x95\x9c\xa7\xda" - "\x3f\xcf\xb7\x7b\xc6\xe1\x28\x52\xfc\x0c\xe2\x37" - "\x0d\x83\xa7\x51\x4b\x31\x47\x3c\xe1\x3c\xae\x70" - "\x01\xc8\xa3\xd3\xc2\xac\x77\x9c\xd1\x68\x77\x9b" - "\x58\x27\x3b\xa5\x0f\xc2\x7a\x8b\x04\x65\x62\xd5" - "\xe8\xd6\xfe\x2a\xaf\xd3\xd3\xfe\xbd\x18\xfb\xcd" - "\xcd\x66\xb5\x01\x69\x66\xa0\x3c", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x17\xc1\x56\xcb\xcc\x50\xd6\x03\x7d\x45\x76\xa3" - "\x75\x76\xc1\x4a\x66\x1b\x2e\xdf\xb0\x2e\x7d\x56" - "\x6d\x99\x3b\xc6\x58\xda\x03\xf6", - .addtlb = (unsigned char *) - "\x7c\x7b\x4a\x4b\x32\x5e\x6f\x67\x34\xf5\x21\x4c" - "\xf9\x96\xf9\xbf\x1c\x8c\x81\xd3\x9b\x60\x6a\x44" - "\xc6\x03\xa2\xfb\x13\x20\x19\xb7", - .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x13\x54\x96\xfc\x1b\x7d\x28\xf3\x18\xc9\xa7\x89" - "\xb6\xb3\xc8\x72\xac\x00\xd4\x59\x36\x25\x05\xaf" - "\xa5\xdb\x96\xcb\x3c\x58\x46\x87\xa5\xaa\xbf\x20" - "\x3b\xfe\x23\x0e\xd1\xc7\x41\x0f\x3f\xc9\xb3\x67", - .entropylen = 48, - .entpra = (unsigned char *) - "\xe2\xbd\xb7\x48\x08\x06\xf3\xe1\x93\x3c\xac\x79" - "\xa7\x2b\x11\xda\xe3\x2e\xe1\x91\xa5\x02\x19\x57" - "\x20\x28\xad\xf2\x60\xd7\xcd\x45", - .entprb = (unsigned char *) - "\x8b\xd4\x69\xfc\xff\x59\x95\x95\xc6\x51\xde\x71" - "\x68\x5f\xfc\xf9\x4a\xab\xec\x5a\xcb\xbe\xd3\x66" - "\x1f\xfa\x74\xd3\xac\xa6\x74\x60", - .entprlen = 32, - .expected = (unsigned char *) - "\x1f\x9e\xaf\xe4\xd2\x46\xb7\x47\x41\x4c\x65\x99" - "\x01\xe9\x3b\xbb\x83\x0c\x0a\xb0\xc1\x3a\xe2\xb3" - "\x31\x4e\xeb\x93\x73\xee\x0b\x26\xc2\x63\xa5\x75" - "\x45\x99\xd4\x5c\x9f\xa1\xd4\x45\x87\x6b\x20\x61" - "\x40\xea\x78\xa5\x32\xdf\x9e\x66\x17\xaf\xb1\x88" - "\x9e\x2e\x23\xdd\xc1\xda\x13\x97\x88\xa5\xb6\x5e" - "\x90\x14\x4e\xef\x13\xab\x5c\xd9\x2c\x97\x9e\x7c" - "\xd7\xf8\xce\xea\x81\xf5\xcd\x71\x15\x49\x44\xce" - "\x83\xb6\x05\xfb\x7d\x30\xb5\x57\x2c\x31\x4f\xfc" - "\xfe\x80\xb6\xc0\x13\x0c\x5b\x9b\x2e\x8f\x3d\xfc" - "\xc2\xa3\x0c\x11\x1b\x80\x5f\xf3", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\x64\xb6\xfc\x60\xbc\x61\x76\x23\x6d\x3f\x4a\x0f" - "\xe1\xb4\xd5\x20\x9e\x70\xdd\x03\x53\x6d\xbf\xce" - "\xcd\x56\x80\xbc\xb8\x15\xc8\xaa", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\xc7\xcc\xbc\x67\x7e\x21\x66\x1e\x27\x2b\x63\xdd" - "\x3a\x78\xdc\xdf\x66\x6d\x3f\x24\xae\xcf\x37\x01" - "\xa9\x0d\x89\x8a\xa7\xdc\x81\x58\xae\xb2\x10\x15" - "\x7e\x18\x44\x6d\x13\xea\xdf\x37\x85\xfe\x81\xfb", - .entropylen = 48, - .entpra = (unsigned char *) - "\x7b\xa1\x91\x5b\x3c\x04\xc4\x1b\x1d\x19\x2f\x1a" - "\x18\x81\x60\x3c\x6c\x62\x91\xb7\xe9\xf5\xcb\x96" - "\xbb\x81\x6a\xcc\xb5\xae\x55\xb6", - .entprb = (unsigned char *) - "\x99\x2c\xc7\x78\x7e\x3b\x88\x12\xef\xbe\xd3\xd2" - "\x7d\x2a\xa5\x86\xda\x8d\x58\x73\x4a\x0a\xb2\x2e" - "\xbb\x4c\x7e\xe3\x9a\xb6\x81\xc1", - .entprlen = 32, - .expected = (unsigned char *) - "\x95\x6f\x95\xfc\x3b\xb7\xfe\x3e\xd0\x4e\x1a\x14" - "\x6c\x34\x7f\x7b\x1d\x0d\x63\x5e\x48\x9c\x69\xe6" - "\x46\x07\xd2\x87\xf3\x86\x52\x3d\x98\x27\x5e\xd7" - "\x54\xe7\x75\x50\x4f\xfb\x4d\xfd\xac\x2f\x4b\x77" - "\xcf\x9e\x8e\xcc\x16\xa2\x24\xcd\x53\xde\x3e\xc5" - "\x55\x5d\xd5\x26\x3f\x89\xdf\xca\x8b\x4e\x1e\xb6" - "\x88\x78\x63\x5c\xa2\x63\x98\x4e\x6f\x25\x59\xb1" - "\x5f\x2b\x23\xb0\x4b\xa5\x18\x5d\xc2\x15\x74\x40" - "\x59\x4c\xb4\x1e\xcf\x9a\x36\xfd\x43\xe2\x03\xb8" - "\x59\x91\x30\x89\x2a\xc8\x5a\x43\x23\x7c\x73\x72" - "\xda\x3f\xad\x2b\xba\x00\x6b\xd1", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x18\xe8\x17\xff\xef\x39\xc7\x41\x5c\x73\x03\x03" - "\xf6\x3d\xe8\x5f\xc8\xab\xe4\xab\x0f\xad\xe8\xd6" - "\x86\x88\x55\x28\xc1\x69\xdd\x76", - .addtlb = (unsigned char *) - "\xac\x07\xfc\xbe\x87\x0e\xd3\xea\x1f\x7e\xb8\xe7" - "\x9d\xec\xe8\xe7\xbc\xf3\x18\x25\x77\x35\x4a\xaa" - "\x00\x99\x2a\xdd\x0a\x00\x50\x82", - .addtllen = 32, - .pers = (unsigned char *) - "\xbc\x55\xab\x3c\xf6\x52\xb0\x11\x3d\x7b\x90\xb8" - "\x24\xc9\x26\x4e\x5a\x1e\x77\x0d\x3d\x58\x4a\xda" - "\xd1\x81\xe9\xf8\xeb\x30\x8f\x6f", - .perslen = 32, - }, -}; - -static const struct drbg_testvec drbg_pr_ctr_aes128_tv_template[] = { - { - .entropy = (unsigned char *) - "\xd1\x44\xc6\x61\x81\x6d\xca\x9d\x15\x28\x8a\x42" - "\x94\xd7\x28\x9c\x43\x77\x19\x29\x1a\x6d\xc3\xa2", - .entropylen = 24, - .entpra = (unsigned char *) - "\x96\xd8\x9e\x45\x32\xc9\xd2\x08\x7a\x6d\x97\x15" - "\xb4\xec\x80\xb1", - .entprb = (unsigned char *) - "\x8b\xb6\x72\xb5\x24\x0b\x98\x65\x95\x95\xe9\xc9" - "\x28\x07\xeb\xc2", - .entprlen = 16, - .expected = (unsigned char *) - "\x70\x19\xd0\x4c\x45\x78\xd6\x68\xa9\x9a\xaa\xfe" - "\xc1\xdf\x27\x9a\x1c\x0d\x0d\xf7\x24\x75\x46\xcc" - "\x77\x6b\xdf\x89\xc6\x94\xdc\x74\x50\x10\x70\x18" - "\x9b\xdc\x96\xb4\x89\x23\x40\x1a\xce\x09\x87\xce" - "\xd2\xf3\xd5\xe4\x51\x67\x74\x11\x5a\xcc\x8b\x3b" - "\x8a\xf1\x23\xa8", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x8e\x83\xe0\xeb\x37\xea\x3e\x53\x5e\x17\x6e\x77" - "\xbd\xb1\x53\x90\xfc\xdc\xc1\x3c\x9a\x88\x22\x94", - .entropylen = 24, - .entpra = (unsigned char *) - "\x6a\x85\xe7\x37\xc8\xf1\x04\x31\x98\x4f\xc8\x73" - "\x67\xd1\x08\xf8", - .entprb = (unsigned char *) - "\xd7\xa4\x68\xe2\x12\x74\xc3\xd9\xf1\xb7\x05\xbc" - "\xd4\xba\x04\x58", - .entprlen = 16, - .expected = (unsigned char *) - "\x78\xd6\xa6\x70\xff\xd1\x82\xf5\xa2\x88\x7f\x6d" - "\x3d\x8c\x39\xb1\xa8\xcb\x2c\x91\xab\x14\x7e\xbc" - "\x95\x45\x9f\x24\xb8\x20\xac\x21\x23\xdb\x72\xd7" - "\x12\x8d\x48\x95\xf3\x19\x0c\x43\xc6\x19\x45\xfc" - "\x8b\xac\x40\x29\x73\x00\x03\x45\x5e\x12\xff\x0c" - "\xc1\x02\x41\x82", - .expectedlen = 64, - .addtla = (unsigned char *) - "\xa2\xd9\x38\xcf\x8b\x29\x67\x5b\x65\x62\x6f\xe8" - "\xeb\xb3\x01\x76", - .addtlb = (unsigned char *) - "\x59\x63\x1e\x81\x8a\x14\xa8\xbb\xa1\xb8\x41\x25" - "\xd0\x7f\xcc\x43", - .addtllen = 16, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x04\xd9\x49\xa6\xdc\xe8\x6e\xbb\xf1\x08\x77\x2b" - "\x9e\x08\xca\x92\x65\x16\xda\x99\xa2\x59\xf3\xe8", - .entropylen = 24, - .entpra = (unsigned char *) - "\x38\x7e\x3f\x6b\x51\x70\x7b\x20\xec\x53\xd0\x66" - "\xc3\x0f\xe3\xb0", - .entprb = (unsigned char *) - "\xe0\x86\xa6\xaa\x5f\x72\x2f\xad\xf7\xef\x06\xb8" - "\xd6\x9c\x9d\xe8", - .entprlen = 16, - .expected = (unsigned char *) - "\xc9\x0a\xaf\x85\x89\x71\x44\x66\x4f\x25\x0b\x2b" - "\xde\xd8\xfa\xff\x52\x5a\x1b\x32\x5e\x41\x7a\x10" - "\x1f\xef\x1e\x62\x23\xe9\x20\x30\xc9\x0d\xad\x69" - "\xb4\x9c\x5b\xf4\x87\x42\xd5\xae\x5e\x5e\x43\xcc" - "\xd9\xfd\x0b\x93\x4a\xe3\xd4\x06\x37\x36\x0f\x3f" - "\x72\x82\x0c\xcf", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xbf\xa4\x9a\x8f\x7b\xd8\xb1\x7a\x9d\xfa\x45\xed" - "\x21\x52\xb3\xad", - .perslen = 16, - }, { - .entropy = (unsigned char *) - "\x92\x89\x8f\x31\xfa\x1c\xff\x6d\x18\x2f\x26\x06" - "\x43\xdf\xf8\x18\xc2\xa4\xd9\x72\xc3\xb9\xb6\x97", - .entropylen = 24, - .entpra = (unsigned char *) - "\x20\x72\x8a\x06\xf8\x6f\x8d\xd4\x41\xe2\x72\xb7" - "\xc4\x2c\xe8\x10", - .entprb = (unsigned char *) - "\x3d\xb0\xf0\x94\xf3\x05\x50\x33\x17\x86\x3e\x22" - "\x08\xf7\xa5\x01", - .entprlen = 16, - .expected = (unsigned char *) - "\x5a\x35\x39\x87\x0f\x4d\x22\xa4\x09\x24\xee\x71" - "\xc9\x6f\xac\x72\x0a\xd6\xf0\x88\x82\xd0\x83\x28" - "\x73\xec\x3f\x93\xd8\xab\x45\x23\xf0\x7e\xac\x45" - "\x14\x5e\x93\x9f\xb1\xd6\x76\x43\x3d\xb6\xe8\x08" - "\x88\xf6\xda\x89\x08\x77\x42\xfe\x1a\xf4\x3f\xc4" - "\x23\xc5\x1f\x68", - .expectedlen = 64, - .addtla = (unsigned char *) - "\x1a\x40\xfa\xe3\xcc\x6c\x7c\xa0\xf8\xda\xba\x59" - "\x23\x6d\xad\x1d", - .addtlb = (unsigned char *) - "\x9f\x72\x76\x6c\xc7\x46\xe5\xed\x2e\x53\x20\x12" - "\xbc\x59\x31\x8c", - .addtllen = 16, - .pers = (unsigned char *) - "\xea\x65\xee\x60\x26\x4e\x7e\xb6\x0e\x82\x68\xc4" - "\x37\x3c\x5c\x0b", - .perslen = 16, - }, -}; - /* * SP800-90A DRBG Test vectors from * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip * * Test vectors for DRBG without prediction resistance. All types of DRBGs - * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and - * w/o personalization string, w/ and w/o additional input string). + * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and w/o + * additional input string). */ static const struct drbg_testvec drbg_nopr_sha256_tv_template[] = { { @@ -21912,8 +21467,6 @@ static const struct drbg_testvec drbg_nopr_sha256_tv_template[] = { .addtla = NULL, .addtlb = NULL, .addtllen = 0, - .pers = NULL, - .perslen = 0, }, { .entropy = (unsigned char *) "\x73\xd3\xfb\xa3\x94\x5f\x2b\x5f\xb9\x8f\xf6\x9c" @@ -21943,71 +21496,7 @@ static const struct drbg_testvec drbg_nopr_sha256_tv_template[] = { "\x6f\x8c\x55\x1c\x44\xd1\xce\x6f\x28\xcc\xa4\x4d" "\xa8\xc0\x85\xd1\x5a\x0c\x59\x40", .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x2a\x85\xa9\x8b\xd0\xda\x83\xd6\xad\xab\x9f\xbb" - "\x54\x31\x15\x95\x1c\x4d\x49\x9f\x6a\x15\xf6\xe4" - "\x15\x50\x88\x06\x29\x0d\xed\x8d\xb9\x6f\x96\xe1" - "\x83\x9f\xf7\x88\xda\x84\xbf\x44\x28\xd9\x1d\xaa", - .entropylen = 48, - .expected = (unsigned char *) - "\x2d\x55\xde\xc9\xed\x05\x47\x07\x3d\x04\xfc\x28" - "\x0f\x92\xf0\x4d\xd8\x00\x32\x47\x0a\x1b\x1c\x4b" - "\xef\xd9\x97\xa1\x17\x67\xda\x26\x6c\xfe\x76\x46" - "\x6f\xbc\x6d\x82\x4e\x83\x8a\x98\x66\x6c\x01\xb6" - "\xe6\x64\xe0\x08\x10\x6f\xd3\x5d\x90\xe7\x0d\x72" - "\xa6\xa7\xe3\xbb\x98\x11\x12\x56\x23\xc2\x6d\xd1" - "\xc8\xa8\x7a\x39\xf3\x34\xe3\xb8\xf8\x66\x00\x77" - "\x7d\xcf\x3c\x3e\xfa\xc9\x0f\xaf\xe0\x24\xfa\xe9" - "\x84\xf9\x6a\x01\xf6\x35\xdb\x5c\xab\x2a\xef\x4e" - "\xac\xab\x55\xb8\x9b\xef\x98\x68\xaf\x51\xd8\x16" - "\xa5\x5e\xae\xf9\x1e\xd2\xdb\xe6", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xa8\x80\xec\x98\x30\x98\x15\xd2\xc6\xc4\x68\xf1" - "\x3a\x1c\xbf\xce\x6a\x40\x14\xeb\x36\x99\x53\xda" - "\x57\x6b\xce\xa4\x1c\x66\x3d\xbc", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\x69\xed\x82\xa9\xc5\x7b\xbf\xe5\x1d\x2f\xcb\x7a" - "\xd3\x50\x7d\x96\xb4\xb9\x2b\x50\x77\x51\x27\x74" - "\x33\x74\xba\xf1\x30\xdf\x8e\xdf\x87\x1d\x87\xbc" - "\x96\xb2\xc3\xa7\xed\x60\x5e\x61\x4e\x51\x29\x1a", - .entropylen = 48, - .expected = (unsigned char *) - "\xa5\x71\x24\x31\x11\xfe\x13\xe1\xa8\x24\x12\xfb" - "\x37\xa1\x27\xa5\xab\x77\xa1\x9f\xae\x8f\xaf\x13" - "\x93\xf7\x53\x85\x91\xb6\x1b\xab\xd4\x6b\xea\xb6" - "\xef\xda\x4c\x90\x6e\xef\x5f\xde\xe1\xc7\x10\x36" - "\xd5\x67\xbd\x14\xb6\x89\x21\x0c\xc9\x92\x65\x64" - "\xd0\xf3\x23\xe0\x7f\xd1\xe8\x75\xc2\x85\x06\xea" - "\xca\xc0\xcb\x79\x2d\x29\x82\xfc\xaa\x9a\xc6\x95" - "\x7e\xdc\x88\x65\xba\xec\x0e\x16\x87\xec\xa3\x9e" - "\xd8\x8c\x80\xab\x3a\x64\xe0\xcb\x0e\x45\x98\xdd" - "\x7c\x6c\x6c\x26\x11\x13\xc8\xce\xa9\x47\xa6\x06" - "\x57\xa2\x66\xbb\x2d\x7f\xf3\xc1", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x74\xd3\x6d\xda\xe8\xd6\x86\x5f\x63\x01\xfd\xf2" - "\x7d\x06\x29\x6d\x94\xd1\x66\xf0\xd2\x72\x67\x4e" - "\x77\xc5\x3d\x9e\x03\xe3\xa5\x78", - .addtlb = (unsigned char *) - "\xf6\xb6\x3d\xf0\x7c\x26\x04\xc5\x8b\xcd\x3e\x6a" - "\x9f\x9c\x3a\x2e\xdb\x47\x87\xe5\x8e\x00\x5e\x2b" - "\x74\x7f\xa6\xf6\x80\xcd\x9b\x21", - .addtllen = 32, - .pers = (unsigned char *) - "\x74\xa6\xe0\x08\xf9\x27\xee\x1d\x6e\x3c\x28\x20" - "\x87\xdd\xd7\x54\x31\x47\x78\x4b\xe5\x6d\xa3\x73" - "\xa9\x65\xb1\x10\xc1\xdc\x77\x7c", - .perslen = 32, - }, + } }; static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { @@ -22034,8 +21523,6 @@ static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { .addtla = NULL, .addtlb = NULL, .addtllen = 0, - .pers = NULL, - .perslen = 0, }, { .entropy = (unsigned char *) "\xf9\x7a\x3c\xfd\x91\xfa\xa0\x46\xb9\xe6\x1b\x94" @@ -22065,71 +21552,7 @@ static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { "\x1d\x74\x49\xfe\x75\x06\x26\x82\xe8\x9c\x57\x14" "\x40\xc0\xc9\xb5\x2c\x42\xa6\xe0", .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x8d\xf0\x13\xb4\xd1\x03\x52\x30\x73\x91\x7d\xdf" - "\x6a\x86\x97\x93\x05\x9e\x99\x43\xfc\x86\x54\x54" - "\x9e\x7a\xb2\x2f\x7c\x29\xf1\x22\xda\x26\x25\xaf" - "\x2d\xdd\x4a\xbc\xce\x3c\xf4\xfa\x46\x59\xd8\x4e", - .entropylen = 48, - .expected = (unsigned char *) - "\xb9\x1c\xba\x4c\xc8\x4f\xa2\x5d\xf8\x61\x0b\x81" - "\xb6\x41\x40\x27\x68\xa2\x09\x72\x34\x93\x2e\x37" - "\xd5\x90\xb1\x15\x4c\xbd\x23\xf9\x74\x52\xe3\x10" - "\xe2\x91\xc4\x51\x46\x14\x7f\x0d\xa2\xd8\x17\x61" - "\xfe\x90\xfb\xa6\x4f\x94\x41\x9c\x0f\x66\x2b\x28" - "\xc1\xed\x94\xda\x48\x7b\xb7\xe7\x3e\xec\x79\x8f" - "\xbc\xf9\x81\xb7\x91\xd1\xbe\x4f\x17\x7a\x89\x07" - "\xaa\x3c\x40\x16\x43\xa5\xb6\x2b\x87\xb8\x9d\x66" - "\xb3\xa6\x0e\x40\xd4\xa8\xe4\xe9\xd8\x2a\xf6\xd2" - "\x70\x0e\x6f\x53\x5c\xdb\x51\xf7\x5c\x32\x17\x29" - "\x10\x37\x41\x03\x0c\xcc\x3a\x56", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xb5\x71\xe6\x6d\x7c\x33\x8b\xc0\x7b\x76\xad\x37" - "\x57\xbb\x2f\x94\x52\xbf\x7e\x07\x43\x7a\xe8\x58" - "\x1c\xe7\xbc\x7c\x3a\xc6\x51\xa9", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\xc2\xa5\x66\xa9\xa1\x81\x7b\x15\xc5\xc3\xb7\x78" - "\x17\x7a\xc8\x7c\x24\xe7\x97\xbe\x0a\x84\x5f\x11" - "\xc2\xfe\x39\x9d\xd3\x77\x32\xf2\xcb\x18\x94\xeb" - "\x2b\x97\xb3\xc5\x6e\x62\x83\x29\x51\x6f\x86\xec", - .entropylen = 48, - .expected = (unsigned char *) - "\xb3\xa3\x69\x8d\x77\x76\x99\xa0\xdd\x9f\xa3\xf0" - "\xa9\xfa\x57\x83\x2d\x3c\xef\xac\x5d\xf2\x44\x37" - "\xc6\xd7\x3a\x0f\xe4\x10\x40\xf1\x72\x90\x38\xae" - "\xf1\xe9\x26\x35\x2e\xa5\x9d\xe1\x20\xbf\xb7\xb0" - "\x73\x18\x3a\x34\x10\x6e\xfe\xd6\x27\x8f\xf8\xad" - "\x84\x4b\xa0\x44\x81\x15\xdf\xdd\xf3\x31\x9a\x82" - "\xde\x6b\xb1\x1d\x80\xbd\x87\x1a\x9a\xcd\x35\xc7" - "\x36\x45\xe1\x27\x0f\xb9\xfe\x4f\xa8\x8e\xc0\xe4" - "\x65\x40\x9e\xa0\xcb\xa8\x09\xfe\x2f\x45\xe0\x49" - "\x43\xa2\xe3\x96\xbb\xb7\xdd\x2f\x4e\x07\x95\x30" - "\x35\x24\xcc\x9c\xc5\xea\x54\xa1", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x41\x3d\xd8\x3f\xe5\x68\x35\xab\xd4\x78\xcb\x96" - "\x93\xd6\x76\x35\x90\x1c\x40\x23\x9a\x26\x64\x62" - "\xd3\x13\x3b\x83\xe4\x9c\x82\x0b", - .addtlb = (unsigned char *) - "\xd5\xc4\xa7\x1f\x9d\x6d\x95\xa1\xbe\xdf\x0b\xd2" - "\x24\x7c\x27\x7d\x1f\x84\xa4\xe5\x7a\x4a\x88\x25" - "\xb8\x2a\x2d\x09\x7d\xe6\x3e\xf1", - .addtllen = 32, - .pers = (unsigned char *) - "\x13\xce\x4d\x8d\xd2\xdb\x97\x96\xf9\x41\x56\xc8" - "\xe8\xf0\x76\x9b\x0a\xa1\xc8\x2c\x13\x23\xb6\x15" - "\x36\x60\x3b\xca\x37\xc9\xee\x29", - .perslen = 32, - }, + } }; /* Test vector obtained during NIST ACVP testing */ @@ -22176,8 +21599,6 @@ static const struct drbg_testvec drbg_nopr_hmac_sha512_tv_template[] = { "\x2D\x1E\x22\x2A\xBD\x8B\x05\x6F\xA3\xFC\xBF\x16" "\xED\xAA\x75\x8D\x73\x9A\xF6\xEC", .addtllen = 32, - .pers = NULL, - .perslen = 0, } }; @@ -22200,8 +21621,6 @@ static const struct drbg_testvec drbg_nopr_ctr_aes192_tv_template[] = { .addtla = NULL, .addtlb = NULL, .addtllen = 0, - .pers = NULL, - .perslen = 0, }, }; @@ -22224,8 +21643,6 @@ static const struct drbg_testvec drbg_nopr_ctr_aes256_tv_template[] = { .addtla = NULL, .addtlb = NULL, .addtllen = 0, - .pers = NULL, - .perslen = 0, }, }; @@ -22246,8 +21663,6 @@ static const struct drbg_testvec drbg_nopr_ctr_aes128_tv_template[] = { .addtla = NULL, .addtlb = NULL, .addtllen = 0, - .pers = NULL, - .perslen = 0, }, { .entropy = (unsigned char *) "\x71\xbd\xce\x35\x42\x7d\x20\xbf\x58\xcf\x17\x74" @@ -22268,53 +21683,7 @@ static const struct drbg_testvec drbg_nopr_ctr_aes128_tv_template[] = { "\xe3\x18\x83\xd9\x4b\x5e\xc4\xcc\xaa\x61\x2f\xbb" "\x4a\x55\xd1\xc6", .addtllen = 16, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xca\x4b\x1e\xfa\x75\xbd\x69\x36\x38\x73\xb8\xf9" - "\xdb\x4d\x35\x0e\x47\xbf\x6c\x37\x72\xfd\xf7\xa9", - .entropylen = 24, - .expected = (unsigned char *) - "\x59\xc3\x19\x79\x1b\xb1\xf3\x0e\xe9\x34\xae\x6e" - "\x8b\x1f\xad\x1f\x74\xca\x25\x45\x68\xb8\x7f\x75" - "\x12\xf8\xf2\xab\x4c\x23\x01\x03\x05\xe1\x70\xee" - "\x75\xd8\xcb\xeb\x23\x4c\x7a\x23\x6e\x12\x27\xdb" - "\x6f\x7a\xac\x3c\x44\xb7\x87\x4b\x65\x56\x74\x45" - "\x34\x30\x0c\x3d", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xeb\xaa\x60\x2c\x4d\xbe\x33\xff\x1b\xef\xbf\x0a" - "\x0b\xc6\x97\x54", - .perslen = 16, - }, { - .entropy = (unsigned char *) - "\xc0\x70\x1f\x92\x50\x75\x8f\xcd\xf2\xbe\x73\x98" - "\x80\xdb\x66\xeb\x14\x68\xb4\xa5\x87\x9c\x2d\xa6", - .entropylen = 24, - .expected = (unsigned char *) - "\x97\xc0\xc0\xe5\xa0\xcc\xf2\x4f\x33\x63\x48\x8a" - "\xdb\x13\x0a\x35\x89\xbf\x80\x65\x62\xee\x13\x95" - "\x7c\x33\xd3\x7d\xf4\x07\x77\x7a\x2b\x65\x0b\x5f" - "\x45\x5c\x13\xf1\x90\x77\x7f\xc5\x04\x3f\xcc\x1a" - "\x38\xf8\xcd\x1b\xbb\xd5\x57\xd1\x4a\x4c\x2e\x8a" - "\x2b\x49\x1e\x5c", - .expectedlen = 64, - .addtla = (unsigned char *) - "\xf9\x01\xf8\x16\x7a\x1d\xff\xde\x8e\x3c\x83\xe2" - "\x44\x85\xe7\xfe", - .addtlb = (unsigned char *) - "\x17\x1c\x09\x38\xc2\x38\x9f\x97\x87\x60\x55\xb4" - "\x82\x16\x62\x7f", - .addtllen = 16, - .pers = (unsigned char *) - "\x80\x08\xae\xe8\xe9\x69\x40\xc5\x08\x73\xc7\x9f" - "\x8e\xcf\xe0\x02", - .perslen = 16, - }, + } }; /* Cast5 test vectors from RFC 2144 */ diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h index af5ad51d3eef..58787575d220 100644 --- a/include/crypto/drbg.h +++ b/include/crypto/drbg.h @@ -101,10 +101,6 @@ struct drbg_state_ops { }; -struct drbg_test_data { - struct drbg_string *testentropy; /* TEST PARAMETER: test entropy */ -}; - enum drbg_seed_state { DRBG_SEED_STATE_UNSEEDED, DRBG_SEED_STATE_PARTIAL, /* Seeded with !rng_is_initialized() */ @@ -120,7 +116,6 @@ struct drbg_state { unsigned char *Cbuf; /* Number of RNG requests since last reseed -- 10.1.1.1 1c) */ size_t reseed_ctr; - size_t reseed_threshold; /* some memory the DRBG can use for its operation */ unsigned char *scratchpad; unsigned char *scratchpadbuf; @@ -133,15 +128,8 @@ struct drbg_state { struct crypto_wait ctr_wait; /* CTR mode async wait obj */ struct scatterlist sg_in, sg_out; /* CTR mode SGLs */ - enum drbg_seed_state seeded; /* DRBG fully seeded? */ - unsigned long last_seed_time; - bool pr; /* Prediction resistance enabled? */ - bool fips_primed; /* Continuous test primed? */ - unsigned char *prev; /* FIPS 140-2 continuous test value */ - struct crypto_rng *jent; const struct drbg_state_ops *d_ops; const struct drbg_core *core; - struct drbg_string test_data; }; static inline __u8 drbg_statelen(struct drbg_state *drbg) @@ -192,78 +180,6 @@ static inline size_t drbg_max_requests(struct drbg_state *drbg) return (1<<20); } -/* - * This is a wrapper to the kernel crypto API function of - * crypto_rng_generate() to allow the caller to provide additional data. - * - * @drng DRBG handle -- see crypto_rng_get_bytes - * @outbuf output buffer -- see crypto_rng_get_bytes - * @outlen length of output buffer -- see crypto_rng_get_bytes - * @addtl_input additional information string input buffer - * @addtllen length of additional information string buffer - * - * return - * see crypto_rng_get_bytes - */ -static inline int crypto_drbg_get_bytes_addtl(struct crypto_rng *drng, - unsigned char *outbuf, unsigned int outlen, - struct drbg_string *addtl) -{ - return crypto_rng_generate(drng, addtl->buf, addtl->len, - outbuf, outlen); -} - -/* - * TEST code - * - * This is a wrapper to the kernel crypto API function of - * crypto_rng_generate() to allow the caller to provide additional data and - * allow furnishing of test_data - * - * @drng DRBG handle -- see crypto_rng_get_bytes - * @outbuf output buffer -- see crypto_rng_get_bytes - * @outlen length of output buffer -- see crypto_rng_get_bytes - * @addtl_input additional information string input buffer - * @addtllen length of additional information string buffer - * @test_data filled test data - * - * return - * see crypto_rng_get_bytes - */ -static inline int crypto_drbg_get_bytes_addtl_test(struct crypto_rng *drng, - unsigned char *outbuf, unsigned int outlen, - struct drbg_string *addtl, - struct drbg_test_data *test_data) -{ - crypto_rng_set_entropy(drng, test_data->testentropy->buf, - test_data->testentropy->len); - return crypto_rng_generate(drng, addtl->buf, addtl->len, - outbuf, outlen); -} - -/* - * TEST code - * - * This is a wrapper to the kernel crypto API function of - * crypto_rng_reset() to allow the caller to provide test_data - * - * @drng DRBG handle -- see crypto_rng_reset - * @pers personalization string input buffer - * @perslen length of additional information string buffer - * @test_data filled test data - * - * return - * see crypto_rng_reset - */ -static inline int crypto_drbg_reset_test(struct crypto_rng *drng, - struct drbg_string *pers, - struct drbg_test_data *test_data) -{ - crypto_rng_set_entropy(drng, test_data->testentropy->buf, - test_data->testentropy->len); - return crypto_rng_reset(drng, pers->buf, pers->len); -} - /* DRBG type flags */ #define DRBG_CTR ((drbg_flag_t)1<<0) #define DRBG_HMAC ((drbg_flag_t)1<<1) From patchwork Wed Jan 26 07:03:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 12724643 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A3A58C63682 for ; Wed, 26 Jan 2022 07:07:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237571AbiAZHH3 (ORCPT ); Wed, 26 Jan 2022 02:07:29 -0500 Received: from mo4-p02-ob.smtp.rzone.de ([81.169.146.171]:35719 "EHLO mo4-p02-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237568AbiAZHH1 (ORCPT ); Wed, 26 Jan 2022 02:07:27 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1643180841; s=strato-dkim-0002; d=chronox.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=ZQa8P93DtFLN6+4nH7jW0EHewAPOjepwRaiJ8WzIXws=; b=XPP9f6e0cCx6MwnBcD/cKjyhO31Kenlv06tI2Yof1Gfr/YODuTSePmRJJevxIq3G+k WLG4utZEleCRjs746Qgu+G+nxORIdZy2Js8nrYh60PTMUdDmDx8IgOHl2EUR7VVy4djH KltfoEw7tlDa4QaV5s1Gc5bNtu2PwijHPYHbPeIPsYiFNMQBi9qKgAOypTFAvt1SNLj5 Q7qYpIwkPwAwukPgZNajuEGaoy672K6DGx0Yzkoj5VyzF+4dO/FbYs9g4dDoKjP7xtv+ cqNpTyjyjtoc/WVv8f4x++powiEOXVqHPLivkipwi43i1d+8Ott80NKpwt9Q4huzoIWq mQsA== Authentication-Results: strato.com; dkim=none X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvScdWrN" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 47.38.0 DYNA|AUTH) with ESMTPSA id v5f65ay0Q77LiuR (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 26 Jan 2022 08:07:21 +0100 (CET) From: Stephan =?iso-8859-1?q?M=FCller?= To: herbert@gondor.apana.org.au Cc: linux-crypto@vger.kernel.org, simo@redhat.com, Nicolai Stange , Elena Petrova Subject: [PATCH 2/7] crypto: AF_ALG - remove ALG_SET_DRBG_ENTROPY interface Date: Wed, 26 Jan 2022 08:03:43 +0100 Message-ID: <2434090.Hq7AAxBmiT@positron.chronox.de> In-Reply-To: <2486550.t9SDvczpPo@positron.chronox.de> References: <2486550.t9SDvczpPo@positron.chronox.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The ALG_SET_DRBG_ENTROPY was added to test the DRBG implementation provided with the kernel crypto API. This interface was used to set a "test entropy" string to bypass the DRBG-internal seeding mechanism. Since the DRBG-internal seeding mechanism is completely removed, the special bypass is not needed any more. The entropy string for the DRBG can be set with the crypto_rng_reset() function that is invoked with the ALG_SET_KEY interface. The change enables the sendmsg implementation in AF_ALG RNG for a general use. The sendmsg allows user space to set the input data to the crypto_rng_generate function call. The change still allows the full testing of the DRBG which was verified with libkcapi version 1.5.0 covering the following aspects: - Hash DRBG with SHA-1, SHA-256, SHA-384, SHA-512 - HMAC DRBG with SHA-1, SHA-256, SHA-384, SHA-512 - CTR DRBG with AES-128, AES-192, AES-256 - reseeding, but without additional information - no reseeding, but with additional information The limitation of the test is defined with algif_rng.c:MAXSIZE which restricts the allowed output size for testing to 128 bytes. CC: Elena Petrova Signed-off-by: Stephan Mueller --- crypto/Kconfig | 9 ----- crypto/af_alg.c | 7 ---- crypto/algif_rng.c | 75 +---------------------------------- include/crypto/if_alg.h | 1 - include/crypto/internal/rng.h | 6 --- include/crypto/rng.h | 4 -- include/uapi/linux/if_alg.h | 2 +- 7 files changed, 3 insertions(+), 101 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 442765219c37..a0de01ab6f0c 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1879,15 +1879,6 @@ config CRYPTO_USER_API_RNG This option enables the user-spaces interface for random number generator algorithms. -config CRYPTO_USER_API_RNG_CAVP - bool "Enable CAVP testing of DRBG" - depends on CRYPTO_USER_API_RNG && CRYPTO_DRBG - help - This option enables extra API for CAVP testing via the user-space - interface: resetting of DRBG entropy, and providing Additional Data. - This should only be enabled for CAVP testing. You should say - no unless you know what this is. - config CRYPTO_USER_API_AEAD tristate "User-space interface for AEAD cipher algorithms" depends on NET diff --git a/crypto/af_alg.c b/crypto/af_alg.c index e1ea18536a5f..6e5222fd10e2 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -259,13 +259,6 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, goto unlock; err = type->setauthsize(ask->private, optlen); break; - case ALG_SET_DRBG_ENTROPY: - if (sock->state == SS_CONNECTED) - goto unlock; - if (!type->setentropy) - goto unlock; - - err = type->setentropy(ask->private, optval, optlen); } unlock: diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c index b204f1427542..4fade9456990 100644 --- a/crypto/algif_rng.c +++ b/crypto/algif_rng.c @@ -110,16 +110,6 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); struct rng_ctx *ctx = ask->private; - - return _rng_recvmsg(ctx->drng, msg, len, NULL, 0); -} - -static int rng_test_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, - int flags) -{ - struct sock *sk = sock->sk; - struct alg_sock *ask = alg_sk(sk); - struct rng_ctx *ctx = ask->private; int ret; lock_sock(sock->sk); @@ -130,7 +120,7 @@ static int rng_test_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, return ret; } -static int rng_test_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) +static int rng_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) { int err; struct alg_sock *ask = alg_sk(sock->sk); @@ -173,30 +163,11 @@ static struct proto_ops algif_rng_ops = { .mmap = sock_no_mmap, .bind = sock_no_bind, .accept = sock_no_accept, - .sendmsg = sock_no_sendmsg, .sendpage = sock_no_sendpage, .release = af_alg_release, .recvmsg = rng_recvmsg, -}; - -static struct proto_ops __maybe_unused algif_rng_test_ops = { - .family = PF_ALG, - - .connect = sock_no_connect, - .socketpair = sock_no_socketpair, - .getname = sock_no_getname, - .ioctl = sock_no_ioctl, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .mmap = sock_no_mmap, - .bind = sock_no_bind, - .accept = sock_no_accept, - .sendpage = sock_no_sendpage, - - .release = af_alg_release, - .recvmsg = rng_test_recvmsg, - .sendmsg = rng_test_sendmsg, + .sendmsg = rng_sendmsg, }; static void *rng_bind(const char *name, u32 type, u32 mask) @@ -225,7 +196,6 @@ static void rng_release(void *private) if (unlikely(!pctx)) return; crypto_free_rng(pctx->drng); - kfree_sensitive(pctx->entropy); kfree_sensitive(pctx); } @@ -264,13 +234,6 @@ static int rng_accept_parent(void *private, struct sock *sk) ask->private = ctx; sk->sk_destruct = rng_sock_destruct; - /* - * Non NULL pctx->entropy means that CAVP test has been initiated on - * this socket, replace proto_ops algif_rng_ops with algif_rng_test_ops. - */ - if (IS_ENABLED(CONFIG_CRYPTO_USER_API_RNG_CAVP) && pctx->entropy) - sk->sk_socket->ops = &algif_rng_test_ops; - return 0; } @@ -284,45 +247,11 @@ static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen) return crypto_rng_reset(pctx->drng, seed, seedlen); } -static int __maybe_unused rng_setentropy(void *private, sockptr_t entropy, - unsigned int len) -{ - struct rng_parent_ctx *pctx = private; - u8 *kentropy = NULL; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (pctx->entropy) - return -EINVAL; - - if (len > MAXSIZE) - return -EMSGSIZE; - - if (len) { - kentropy = memdup_sockptr(entropy, len); - if (IS_ERR(kentropy)) - return PTR_ERR(kentropy); - } - - if (crypto_rng_alg(pctx->drng)->set_ent) - crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len); - /* - * Since rng doesn't perform any memory management for the entropy - * buffer, save kentropy pointer to pctx now to free it after use. - */ - pctx->entropy = kentropy; - return 0; -} - static const struct af_alg_type algif_type_rng = { .bind = rng_bind, .release = rng_release, .accept = rng_accept_parent, .setkey = rng_setkey, -#ifdef CONFIG_CRYPTO_USER_API_RNG_CAVP - .setentropy = rng_setentropy, -#endif .ops = &algif_rng_ops, .name = "rng", .owner = THIS_MODULE diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index a5db86670bdf..ee6412314f8f 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -46,7 +46,6 @@ struct af_alg_type { void *(*bind)(const char *name, u32 type, u32 mask); void (*release)(void *private); int (*setkey)(void *private, const u8 *key, unsigned int keylen); - int (*setentropy)(void *private, sockptr_t entropy, unsigned int len); int (*accept)(void *private, struct sock *sk); int (*accept_nokey)(void *private, struct sock *sk); int (*setauthsize)(void *private, unsigned int authsize); diff --git a/include/crypto/internal/rng.h b/include/crypto/internal/rng.h index e0711b6a597f..bf6da44f9e82 100644 --- a/include/crypto/internal/rng.h +++ b/include/crypto/internal/rng.h @@ -31,10 +31,4 @@ static inline void *crypto_rng_ctx(struct crypto_rng *tfm) return crypto_tfm_ctx(&tfm->base); } -static inline void crypto_rng_set_entropy(struct crypto_rng *tfm, - const u8 *data, unsigned int len) -{ - crypto_rng_alg(tfm)->set_ent(tfm, data, len); -} - #endif diff --git a/include/crypto/rng.h b/include/crypto/rng.h index 17bb3673d3c1..85312ea12274 100644 --- a/include/crypto/rng.h +++ b/include/crypto/rng.h @@ -28,8 +28,6 @@ struct crypto_rng; * up a new state, the seed must be provided by the * consumer while invoking this function. The required * size of the seed is defined with @seedsize . - * @set_ent: Set entropy that would otherwise be obtained from - * entropy source. Internal use only. * @seedsize: The seed size required for a random number generator * initialization defined with this variable. Some * random number generators does not require a seed @@ -43,8 +41,6 @@ struct rng_alg { const u8 *src, unsigned int slen, u8 *dst, unsigned int dlen); int (*seed)(struct crypto_rng *tfm, const u8 *seed, unsigned int slen); - void (*set_ent)(struct crypto_rng *tfm, const u8 *data, - unsigned int len); unsigned int seedsize; diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h index dc52a11ba6d1..e8d676350c8f 100644 --- a/include/uapi/linux/if_alg.h +++ b/include/uapi/linux/if_alg.h @@ -51,7 +51,7 @@ struct af_alg_iv { #define ALG_SET_OP 3 #define ALG_SET_AEAD_ASSOCLEN 4 #define ALG_SET_AEAD_AUTHSIZE 5 -#define ALG_SET_DRBG_ENTROPY 6 +#define ALG_SET_DRBG_ENTROPY 6 /* Not implemented any more */ /* Operations */ #define ALG_OP_DECRYPT 0 From patchwork Wed Jan 26 07:04:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 12724645 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1AB3DC63684 for ; Wed, 26 Jan 2022 07:07:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237560AbiAZHH2 (ORCPT ); Wed, 26 Jan 2022 02:07:28 -0500 Received: from mo4-p01-ob.smtp.rzone.de ([81.169.146.165]:42959 "EHLO mo4-p01-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237561AbiAZHH0 (ORCPT ); Wed, 26 Jan 2022 02:07:26 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1643180841; s=strato-dkim-0002; d=chronox.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=Tb+/R4VeZRchDqAEt0T0RO2auPARtJChbG6noS5Z9qM=; b=FjLW6l/aYQDmbAVsgRh5zI7DZun6YlmF3FOtkHGxbMTl8psUPYz98icadl8NGI3Beg PaakFlwNDw4sxz8IZH+LJff1m/3OQHhZeucqiQAW2QjUIF1GXilckJXL5hdW7aqiH4XE /XCV+Qu3KBO61KvVfZNccqPOawvJpv2S/+ysx/fIL869d9Qt6S/oSCksmypS6NyEOFvf DCEdTVOFUfPr0fczGFvUDVoPDGCXRls+6LLvNQnfoAUReXvrvry+9az2tAGtZB20uvye URUipSCj9cG0P8DRm8+njsW8eapBmni//qQciBf5Lj2oAnXqnP0fE/Uzp5JVIxKqGFT2 fvPw== Authentication-Results: strato.com; dkim=none X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvScdWrN" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 47.38.0 DYNA|AUTH) with ESMTPSA id v5f65ay0Q77KiuQ (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 26 Jan 2022 08:07:20 +0100 (CET) From: Stephan =?iso-8859-1?q?M=FCller?= To: herbert@gondor.apana.org.au Cc: linux-crypto@vger.kernel.org, simo@redhat.com, Nicolai Stange Subject: [PATCH 3/7] crypto: Entropy Source and DRNG Manager Date: Wed, 26 Jan 2022 08:04:03 +0100 Message-ID: <9995914.tdPhlSkOF2@positron.chronox.de> In-Reply-To: <2486550.t9SDvczpPo@positron.chronox.de> References: <2486550.t9SDvczpPo@positron.chronox.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The kernel crypto API contains deterministic random number generators (DRNG) which a caller must seed and reseed. The task of seeding a DRNG is a non-trivial task requiring the consideration of a significant number of aspects. The Entropy Source and DRNG Manager (ESDM) fills that gap to transparently seed and reseed DRNGs. A user of the ESDM obtains random numbers from an appropriately seeded and initialized DRNG. Further, the ESDM controls various entropy sources guaranteeing that they are properly initialized and managed. The ESDM consists of two main parts: - The entropy source (ES) manager implemented in esdm_es_mgr.c controls the available entropy sources including pulling appropritate amount of data from them for the DRNG manager. - The DRNG manager provided with esdm_drng_mgr.c controls the DRNG(s) and ensures proper seeding and reseeding. The entropy source manager controls the entropy sources registered in the esdm_es array. The entropy sources provide a function pointer data structure that is used to obtain the services from it. The ES manager triggers the initial seeding of the DRNGs during boot time in three stages: 1. The DRNG is seeded from the entropy sources if all entropy sources collectively have at least 32 bits of entropy available. The goal of this step is to ensure that the DRNG receive some initial entropy as early as possible. 2. The DRNG is reseeded from the entropy sources if all entropy sources collectively have at least 128 bits of entropy available. 3. The DRNG is reseeded from the entropy sources if all entropy sources collectively have at least 256 bits of entropy available. At the time of the reseeding steps, the DRNG requests as much entropy as is available in order to skip certain steps and reach the seeding level of 256 bits. This may imply that one or more of the aforementioned steps are skipped. In all listed steps, the DRNG is (re)seeded with a number of random bytes from the entropy pool that is at most the amount of entropy present in the entropy pool. This means that for example when the entropy pool contains 128 or more bits of entropy, the DRNG is seeded with that amount of entropy as well. Entropy sources (ES) inform the ES manager when new entropy has been collected using the esdm_es_add_entropy() function. That function schedules a DRNG (re)seed with the DRNG manager. When the DRNG manager requests entropy data, the function esdm_fill_seed_buffer fills the seed buffer by iterating through all available ES. The output of all entropy sources is concatenated with each other. Further, the seed buffer contains the amount of entropy each entropy credits its data. Finally a time stamp is added. The ES trigger such (re)seeding events only as long as not all DRNGs are fully seeded with 256 bits of entropy. Once that seeding level is reached, the triggers are not further processed. The DRNG manager initializes the initial DRNG instance during late stage of the kernel boot process before user space is triggered. The DRNG is seeded at the following occasions: - when the DRNG is initialized, the available amount of entropy is used, - during boot time until the DRNG is fully initialized, the reaching of the aforementioned seeding steps of 32/128/256 bits of entropy trigger a reseed of the DRNG. - at runtime after the elapse of 600 seconds since the last seeding, the DRNG reseeding flag is raised - at runtime when more than 2^20 generate operations were performed by the given DRNG since last reseeding, the reseeding flag is raised Raising the reseeding flag implies that the DRNG is seeded in process context the next time a caller requests random numbers. At runtime, the DRNG manager requires at least 128 bits of entropy from the entropy sources (or 256 bits when the FIPS mode is active to be SP800-90C compliant). It may be possible that the entropy sources may not deliver that amount. The DRNG is reseeded with the available amount of entropy and continues to operate. Yet, when after 2^30 generate requests since the last seeding with 128 bits (or 256 bits in FIPS mode) the DRNG cannot be seeded with 128 bits (or 256 bits), the DRNG becomes unseeded which means it will not produce random numbers until it is fully reseeded again. To support the DRNG manager, a DRNG implementation is provided with esdm_drng_kcapi.c. It uses the kernel crypto API RNG framework and allows the specification of the used DRNG with the kernel command line option of esdm_drng_kcapi.drng_name. If no reference is given, the default is the SP800-90A DRBG. In case the chosen DRNG requires the seed to have a certain length, a hash is used bring the entropy buffer into the proper size. In addition, the DRNG manager controls the message digest implementation offered to entropy sources when they want to perform a conditioning operation. As entropy sources may require the conditioning operation at any time, the default is a SHA-256 software hash implementation that neither sleeps nor does it need any memory allocation operation. Therefore, this hash is available even for the earliest kernel operations. The initial drop of the ESDM includes the entropy source of the "auxiliary" pool. This entropy source must always be present. It is an entropy pool that is based on the state of a message digest. Every insertion of data is a hash update operation. In order to obtain data, a hash final operation is performed. The purpose of this auxiliary pool is twofold: - Provide a general interface to inject an arbitrary amount of data from any external source. When providing such data, the caller may specify the amount of entropy it contains. - The auxiliary pool also provides the backtracking resistance for all entropy sources. Once a seed buffer is filled from all entropy sources it is re-inserted into the auxiliary pool at the same time it is used for seeding the DRNG. Naturally, the insertion of the seed buffer into the auxiliary pool is not credited with any entropy. If enabled during compile time with the option of CONFIG_CRYPTO_ESDM_OVERSAMPLE_ENTROPY_SOURCES, the entropy source oversampling is activated. However, this oversampling is only enforced if the kernel is booted with fips=1. The oversampling pulls 128 more bits of entropy than originally requested. This implies that when 256 bits of entropy are requested for a (re)seed of a DRNG, the ES are queried for 384 bits. This oversampling complies with SP800-90C. Signed-off-by: Stephan Mueller --- crypto/Kconfig | 2 + crypto/Makefile | 1 + crypto/esdm/Kconfig | 79 +++++++ crypto/esdm/Makefile | 10 + crypto/esdm/esdm_definitions.h | 141 ++++++++++++ crypto/esdm/esdm_drng_kcapi.c | 201 +++++++++++++++++ crypto/esdm/esdm_drng_kcapi.h | 13 ++ crypto/esdm/esdm_drng_mgr.c | 398 +++++++++++++++++++++++++++++++++ crypto/esdm/esdm_drng_mgr.h | 85 +++++++ crypto/esdm/esdm_es_aux.c | 332 +++++++++++++++++++++++++++ crypto/esdm/esdm_es_aux.h | 44 ++++ crypto/esdm/esdm_es_mgr.c | 364 ++++++++++++++++++++++++++++++ crypto/esdm/esdm_es_mgr.h | 46 ++++ crypto/esdm/esdm_es_mgr_cb.h | 67 ++++++ crypto/esdm/esdm_sha.h | 14 ++ crypto/esdm/esdm_sha256.c | 72 ++++++ include/crypto/esdm.h | 115 ++++++++++ 17 files changed, 1984 insertions(+) create mode 100644 crypto/esdm/Kconfig create mode 100644 crypto/esdm/Makefile create mode 100644 crypto/esdm/esdm_definitions.h create mode 100644 crypto/esdm/esdm_drng_kcapi.c create mode 100644 crypto/esdm/esdm_drng_kcapi.h create mode 100644 crypto/esdm/esdm_drng_mgr.c create mode 100644 crypto/esdm/esdm_drng_mgr.h create mode 100644 crypto/esdm/esdm_es_aux.c create mode 100644 crypto/esdm/esdm_es_aux.h create mode 100644 crypto/esdm/esdm_es_mgr.c create mode 100644 crypto/esdm/esdm_es_mgr.h create mode 100644 crypto/esdm/esdm_es_mgr_cb.h create mode 100644 crypto/esdm/esdm_sha.h create mode 100644 crypto/esdm/esdm_sha256.c create mode 100644 include/crypto/esdm.h diff --git a/crypto/Kconfig b/crypto/Kconfig index a0de01ab6f0c..91f5ed9aab4f 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1790,6 +1790,8 @@ config CRYPTO_ZSTD comment "Random Number Generation" +source "crypto/esdm/Kconfig" + config CRYPTO_ANSI_CPRNG tristate "Pseudo Random Number Generation for Cryptographic modules" select CRYPTO_AES diff --git a/crypto/Makefile b/crypto/Makefile index d76bff8d0ffd..2b9aadbb5c69 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -159,6 +159,7 @@ obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o obj-$(CONFIG_CRYPTO_XXHASH) += xxhash_generic.o obj-$(CONFIG_CRYPTO_842) += 842.o obj-$(CONFIG_CRYPTO_RNG2) += rng.o +obj-$(CONFIG_CRYPTO_ESDM) += esdm/ obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o obj-$(CONFIG_CRYPTO_DRBG) += drbg.o obj-$(CONFIG_CRYPTO_JITTERENTROPY) += jitterentropy_rng.o diff --git a/crypto/esdm/Kconfig b/crypto/esdm/Kconfig new file mode 100644 index 000000000000..1351d4d146dc --- /dev/null +++ b/crypto/esdm/Kconfig @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Entropy Source and DRNG Manager configuration +# + +config CRYPTO_ESDM + bool "ESDM Implementation" + default n + select CRYPTO_LIB_SHA256 if CRYPTO + help + The Entropy Source and DRNG Manager (ESDM) generates entropy + from different entropy sources. Each entropy source can + be enabled and configured independently. The interrupt + entropy source can be configured to be SP800-90B compliant. + The entire ESDM can be configured to be SP800-90C compliant. + Runtime-switchable cryptographic support is available. + The ESDM delivers significant entropy during boot. + + The ESDM also provides compliance to SP800-90A/B/C. + +menu "Entropy Source and DRNG Manager Configuration" + depends on CRYPTO_ESDM + +if CRYPTO_ESDM + +config CRYPTO_ESDM_SHA256 + bool + default y if CRYPTO_LIB_SHA256 + +menu "Specific DRNG seeding strategies" + +config CRYPTO_ESDM_OVERSAMPLE_ENTROPY_SOURCES + bool "Oversample entropy sources" + default n + help + When enabling this option, the entropy sources are + over-sampled with the following approach: First, the + the entropy sources are requested to provide 64 bits more + entropy than the size of the entropy buffer. For example, + if the entropy buffer is 256 bits, 320 bits of entropy + is requested to fill that buffer. + + Second, the seed operation of the deterministic RNG + requests 128 bits more data from each entropy source than + the security strength of the DRNG during initialization. + A prerequisite for this operation is that the digest size + of the used hash must be at least equally large to generate + that buffer. If the prerequisite is not met, this + oversampling is not applied. + + This strategy is intended to offset the asymptotic entropy + increase to reach full entropy in a buffer. + + The strategy is consistent with the requirements in + NIST SP800-90C and is only enforced with fips=1. + + If unsure, say N. + +config CRYPTO_ESDM_OVERSAMPLE_ES_BITS + int + default 0 if !CRYPTO_ESDM_OVERSAMPLE_ENTROPY_SOURCES + default 64 if CRYPTO_ESDM_OVERSAMPLE_ENTROPY_SOURCES + +config CRYPTO_ESDM_SEED_BUFFER_INIT_ADD_BITS + int + default 0 if !CRYPTO_ESDM_OVERSAMPLE_ENTROPY_SOURCES + default 128 if CRYPTO_ESDM_OVERSAMPLE_ENTROPY_SOURCES + +endmenu # "Specific DRNG seeding strategies" + +config CRYPTO_ESDM_DRNG_KCAPI + bool + depends on CRYPTO + select CRYPTO_RNG + default y + +endif # CRYPTO_ESDM + +endmenu # CRYPTO_ESDM diff --git a/crypto/esdm/Makefile b/crypto/esdm/Makefile new file mode 100644 index 000000000000..24dc7af234b6 --- /dev/null +++ b/crypto/esdm/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the Entropy Source and DRNG Manager. +# + +obj-y += esdm_es_mgr.o esdm_drng_mgr.o \ + esdm_es_aux.o +obj-$(CONFIG_CRYPTO_ESDM_SHA256) += esdm_sha256.o + +obj-$(CONFIG_CRYPTO_ESDM_DRNG_KCAPI) += esdm_drng_kcapi.o diff --git a/crypto/esdm/esdm_definitions.h b/crypto/esdm/esdm_definitions.h new file mode 100644 index 000000000000..e4c5bf5f757c --- /dev/null +++ b/crypto/esdm/esdm_definitions.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2022, Stephan Mueller + */ + +#ifndef _ESDM_DEFINITIONS_H +#define _ESDM_DEFINITIONS_H + +#include +#include +#include + +/*************************** General ESDM parameter ***************************/ + +/* Security strength of ESDM -- this must match DRNG security strength */ +#define ESDM_DRNG_SECURITY_STRENGTH_BYTES 32 +#define ESDM_DRNG_SECURITY_STRENGTH_BITS (ESDM_DRNG_SECURITY_STRENGTH_BYTES * 8) +#define ESDM_DRNG_INIT_SEED_SIZE_BITS \ + (ESDM_DRNG_SECURITY_STRENGTH_BITS + \ + CONFIG_CRYPTO_ESDM_SEED_BUFFER_INIT_ADD_BITS) +#define ESDM_DRNG_INIT_SEED_SIZE_BYTES (ESDM_DRNG_INIT_SEED_SIZE_BITS >> 3) + +/* + * SP800-90A defines a maximum request size of 1<<16 bytes. The given value is + * considered a safer margin. + * + * This value is allowed to be changed. + */ +#define ESDM_DRNG_MAX_REQSIZE (1<<12) + +/* + * SP800-90A defines a maximum number of requests between reseeds of 2^48. + * The given value is considered a much safer margin, balancing requests for + * frequent reseeds with the need to conserve entropy. This value MUST NOT be + * larger than INT_MAX because it is used in an atomic_t. + * + * This value is allowed to be changed. + */ +#define ESDM_DRNG_RESEED_THRESH (1<<20) + +/* + * Maximum DRNG generation operations without reseed having full entropy + * This value defines the absolute maximum value of DRNG generation operations + * without a reseed holding full entropy. ESDM_DRNG_RESEED_THRESH is the + * threshold when a new reseed is attempted. But it is possible that this fails + * to deliver full entropy. In this case the DRNG will continue to provide data + * even though it was not reseeded with full entropy. To avoid in the extreme + * case that no reseed is performed for too long, this threshold is enforced. + * If that absolute low value is reached, the ESDM is marked as not operational. + * + * This value is allowed to be changed. + */ +#define ESDM_DRNG_MAX_WITHOUT_RESEED (1<<30) + +/* + * Min required seed entropy is 128 bits covering the minimum entropy + * requirement of SP800-131A and the German BSI's TR02102. + * + * This value is allowed to be changed. + */ +#define ESDM_FULL_SEED_ENTROPY_BITS ESDM_DRNG_SECURITY_STRENGTH_BITS +#define ESDM_MIN_SEED_ENTROPY_BITS 128 +#define ESDM_INIT_ENTROPY_BITS 32 + +/* + * Wakeup value + * + * This value is allowed to be changed but must not be larger than the + * digest size of the hash operation used update the aux_pool. + */ +#ifdef CONFIG_CRYPTO_ESDM_SHA256 +# define ESDM_ATOMIC_DIGEST_SIZE SHA256_DIGEST_SIZE +#else +# define ESDM_ATOMIC_DIGEST_SIZE SHA1_DIGEST_SIZE +#endif +#define ESDM_WRITE_WAKEUP_ENTROPY ESDM_ATOMIC_DIGEST_SIZE + +/* + * If the switching support is configured, we must provide support up to + * the largest digest size. Without switching support, we know it is only + * the built-in digest size. + */ +#ifdef CONFIG_CRYPTO_ESDM_CRYPTO_SWITCH +# define ESDM_MAX_DIGESTSIZE 64 +#else +# define ESDM_MAX_DIGESTSIZE ESDM_ATOMIC_DIGEST_SIZE +#endif + +/* + * Oversampling factor of timer-based events to obtain + * ESDM_DRNG_SECURITY_STRENGTH_BYTES. This factor is used when a + * high-resolution time stamp is not available. In this case, jiffies and + * register contents are used to fill the entropy pool. These noise sources + * are much less entropic than the high-resolution timer. The entropy content + * is the entropy content assumed with ESDM_[IRQ|SCHED]_ENTROPY_BITS divided by + * ESDM_ES_OVERSAMPLING_FACTOR. + * + * This value is allowed to be changed. + */ +#define ESDM_ES_OVERSAMPLING_FACTOR 10 + +/* Alignmask that is intended to be identical to CRYPTO_MINALIGN */ +#define ESDM_KCAPI_ALIGN ARCH_KMALLOC_MINALIGN + +/* + * This definition must provide a buffer that is equal to SHASH_DESC_ON_STACK + * as it will be casted into a struct shash_desc. + */ +#define ESDM_POOL_SIZE (sizeof(struct shash_desc) + HASH_MAX_DESCSIZE) + +/****************************** Helper code ***********************************/ + +static inline u32 esdm_fast_noise_entropylevel(u32 ent_bits, u32 requested_bits) +{ + /* Obtain entropy statement */ + ent_bits = ent_bits * requested_bits / ESDM_DRNG_SECURITY_STRENGTH_BITS; + /* Cap entropy to buffer size in bits */ + ent_bits = min_t(u32, ent_bits, requested_bits); + return ent_bits; +} + +/* Convert entropy in bits into nr. of events with the same entropy content. */ +static inline u32 esdm_entropy_to_data(u32 entropy_bits, u32 entropy_rate) +{ + return ((entropy_bits * entropy_rate) / + ESDM_DRNG_SECURITY_STRENGTH_BITS); +} + +/* Convert number of events into entropy value. */ +static inline u32 esdm_data_to_entropy(u32 irqnum, u32 entropy_rate) +{ + return ((irqnum * ESDM_DRNG_SECURITY_STRENGTH_BITS) / + entropy_rate); +} + +static inline u32 atomic_read_u32(atomic_t *v) +{ + return (u32)atomic_read(v); +} + +#endif /* _ESDM_DEFINITIONS_H */ diff --git a/crypto/esdm/esdm_drng_kcapi.c b/crypto/esdm/esdm_drng_kcapi.c new file mode 100644 index 000000000000..ae8d2be91b37 --- /dev/null +++ b/crypto/esdm/esdm_drng_kcapi.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Backend for the ESDM providing the cryptographic primitives using the + * kernel crypto API. + * + * Copyright (C) 2022, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#include "esdm_drng_kcapi.h" + +static char *drng_name = +#ifdef CONFIG_CRYPTO_DRBG_CTR + /* CTR_DRBG with AES-256 using derivation function */ + "drbg_nopr_ctr_aes256"; +#elif defined CONFIG_CRYPTO_DRBG_HMAC + /* HMAC_DRBG with SHA-512 */ + "drbg_nopr_hmac_sha512"; +#elif defined CONFIG_CRYPTO_DRBG_HASH + /* Hash_DRBG with SHA-512 using derivation function */ + "drbg_nopr_sha512"; +#else + NULL; +#endif +module_param(drng_name, charp, 0444); +MODULE_PARM_DESC(drng_name, "Kernel crypto API name of DRNG"); + +static char *seed_hash = NULL; +module_param(seed_hash, charp, 0444); +MODULE_PARM_DESC(seed_hash, + "Kernel crypto API name of hash with output size equal to seedsize of DRNG to bring seed string to the size required by the DRNG"); + +struct esdm_drng_info { + struct crypto_rng *kcapi_rng; + struct crypto_shash *hash_tfm; +}; + +static int esdm_kcapi_drng_seed_helper(void *drng, const u8 *inbuf, + u32 inbuflen) +{ + struct esdm_drng_info *esdm_drng_info = (struct esdm_drng_info *)drng; + struct crypto_rng *kcapi_rng = esdm_drng_info->kcapi_rng; + struct crypto_shash *hash_tfm = esdm_drng_info->hash_tfm; + SHASH_DESC_ON_STACK(shash, hash_tfm); + u32 digestsize; + u8 digest[HASH_MAX_DIGESTSIZE] __aligned(8); + int ret; + + if (!hash_tfm) + return crypto_rng_reset(kcapi_rng, inbuf, inbuflen); + + shash->tfm = hash_tfm; + digestsize = crypto_shash_digestsize(hash_tfm); + + ret = crypto_shash_digest(shash, inbuf, inbuflen, digest); + shash_desc_zero(shash); + if (ret) + return ret; + + ret = crypto_rng_reset(kcapi_rng, digest, digestsize); + if (ret) + return ret; + + memzero_explicit(digest, digestsize); + return 0; +} + +static int esdm_kcapi_drng_generate_helper(void *drng, u8 *outbuf, + u32 outbuflen) +{ + struct esdm_drng_info *esdm_drng_info = (struct esdm_drng_info *)drng; + struct crypto_rng *kcapi_rng = esdm_drng_info->kcapi_rng; + int ret = crypto_rng_get_bytes(kcapi_rng, outbuf, outbuflen); + + if (ret < 0) + return ret; + + return outbuflen; +} + +static void *esdm_kcapi_drng_alloc(u32 sec_strength) +{ + struct esdm_drng_info *esdm_drng_info; + struct crypto_rng *kcapi_rng; + u32 time = random_get_entropy(); + int seedsize, rv; + void *ret = ERR_PTR(-ENOMEM); + + if (!drng_name) { + pr_err("DRNG name missing\n"); + return ERR_PTR(-EINVAL); + } + + if (!memcmp(drng_name, "stdrng", 6) || + !memcmp(drng_name, "jitterentropy_rng", 17)) { + pr_err("Refusing to load the requested random number generator\n"); + return ERR_PTR(-EINVAL); + } + + esdm_drng_info = kzalloc(sizeof(*esdm_drng_info), GFP_KERNEL); + if (!esdm_drng_info) + return ERR_PTR(-ENOMEM); + + kcapi_rng = crypto_alloc_rng(drng_name, 0, 0); + if (IS_ERR(kcapi_rng)) { + pr_err("DRNG %s cannot be allocated\n", drng_name); + ret = ERR_CAST(kcapi_rng); + goto free; + } + + esdm_drng_info->kcapi_rng = kcapi_rng; + + seedsize = crypto_rng_seedsize(kcapi_rng); + if (seedsize) { + struct crypto_shash *hash_tfm; + + if (!seed_hash) { + switch (seedsize) { + case 32: + seed_hash = "sha256"; + break; + case 48: + seed_hash = "sha384"; + break; + case 64: + seed_hash = "sha512"; + break; + default: + pr_err("Seed size %d cannot be processed\n", + seedsize); + goto dealloc; + } + } + + hash_tfm = crypto_alloc_shash(seed_hash, 0, 0); + if (IS_ERR(hash_tfm)) { + ret = ERR_CAST(hash_tfm); + goto dealloc; + } + + if (seedsize != crypto_shash_digestsize(hash_tfm)) { + pr_err("Seed hash output size not equal to DRNG seed size\n"); + crypto_free_shash(hash_tfm); + ret = ERR_PTR(-EINVAL); + goto dealloc; + } + + esdm_drng_info->hash_tfm = hash_tfm; + + pr_info("Seed hash %s allocated\n", seed_hash); + } + + rv = esdm_kcapi_drng_seed_helper(esdm_drng_info, (u8 *)(&time), + sizeof(time)); + if (rv) { + ret = ERR_PTR(rv); + goto dealloc; + } + + pr_info("Kernel crypto API DRNG %s allocated\n", drng_name); + + return esdm_drng_info; + +dealloc: + crypto_free_rng(kcapi_rng); +free: + kfree(esdm_drng_info); + return ret; +} + +static void esdm_kcapi_drng_dealloc(void *drng) +{ + struct esdm_drng_info *esdm_drng_info = (struct esdm_drng_info *)drng; + struct crypto_rng *kcapi_rng = esdm_drng_info->kcapi_rng; + + crypto_free_rng(kcapi_rng); + if (esdm_drng_info->hash_tfm) + crypto_free_shash(esdm_drng_info->hash_tfm); + kfree(esdm_drng_info); + pr_info("DRNG %s deallocated\n", drng_name); +} + +static const char *esdm_kcapi_drng_name(void) +{ + return drng_name; +} + +const struct esdm_drng_cb esdm_kcapi_drng_cb = { + .drng_name = esdm_kcapi_drng_name, + .drng_alloc = esdm_kcapi_drng_alloc, + .drng_dealloc = esdm_kcapi_drng_dealloc, + .drng_seed = esdm_kcapi_drng_seed_helper, + .drng_generate = esdm_kcapi_drng_generate_helper, +}; diff --git a/crypto/esdm/esdm_drng_kcapi.h b/crypto/esdm/esdm_drng_kcapi.h new file mode 100644 index 000000000000..0950a15fdfaa --- /dev/null +++ b/crypto/esdm/esdm_drng_kcapi.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * ESDM kernel crypto API DRNG definition + * + * Copyright (C) 2022, Stephan Mueller + */ + +#ifndef _ESDM_KCAPI_DRNG_H +#define _ESDM_KCAPI_DRNG_H + +extern const struct esdm_drng_cb esdm_kcapi_drng_cb; + +#endif /* _ESDM_KCAPI_DRNG_H */ diff --git a/crypto/esdm/esdm_drng_mgr.c b/crypto/esdm/esdm_drng_mgr.c new file mode 100644 index 000000000000..53b683b7ac05 --- /dev/null +++ b/crypto/esdm/esdm_drng_mgr.c @@ -0,0 +1,398 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * ESDM DRNG management + * + * Copyright (C) 2022, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#include "esdm_drng_kcapi.h" +#include "esdm_drng_mgr.h" +#include "esdm_es_aux.h" +#include "esdm_es_mgr.h" +#include "esdm_sha.h" + +/* + * Maximum number of seconds between DRNG reseed intervals of the DRNG. Note, + * this is enforced with the next request of random numbers from the + * DRNG. Setting this value to zero implies a reseeding attempt before every + * generated random number. + */ +int esdm_drng_reseed_max_time = 600; + +/* + * Is ESDM for general-purpose use (i.e. is at least the esdm_drng_init + * fully allocated)? + */ +static atomic_t esdm_avail = ATOMIC_INIT(0); + +/* + * Default hash callback that provides the crypto primitive right from the + * kernel start. It must not perform any memory allocation operation, but + * simply perform the hash calculation. + */ +const struct esdm_hash_cb *esdm_default_hash_cb = &esdm_sha_hash_cb; + +/* + * Default DRNG callback that provides the crypto primitive which is + * allocated either during late kernel boot stage. So, it is permissible for + * the callback to perform memory allocation operations. + */ +const struct esdm_drng_cb *esdm_default_drng_cb = &esdm_kcapi_drng_cb; + +/* DRNG for non-atomic use cases */ +static struct esdm_drng esdm_drng_init = { + ESDM_DRNG_STATE_INIT(esdm_drng_init, NULL, NULL, NULL, + &esdm_sha_hash_cb), + .lock = __MUTEX_INITIALIZER(esdm_drng_init.lock), +}; + +static u32 max_wo_reseed = ESDM_DRNG_MAX_WITHOUT_RESEED; +#ifdef CONFIG_CRYPTO_ESDM_RUNTIME_MAX_WO_RESEED_CONFIG +module_param(max_wo_reseed, uint, 0444); +MODULE_PARM_DESC(max_wo_reseed, + "Maximum number of DRNG generate operation without full reseed\n"); +#endif + +/* Wait queue to wait until the ESDM is initialized - can freely be used */ +DECLARE_WAIT_QUEUE_HEAD(esdm_init_wait); + +/********************************** Helper ************************************/ + +bool esdm_get_available(void) +{ + return likely(atomic_read(&esdm_avail)); +} + +struct esdm_drng *esdm_drng_init_instance(void) +{ + return &esdm_drng_init; +} + +struct esdm_drng *esdm_drng_node_instance(void) +{ + return esdm_drng_init_instance(); +} + +void esdm_drng_reset(struct esdm_drng *drng) +{ + atomic_set(&drng->requests, ESDM_DRNG_RESEED_THRESH); + atomic_set(&drng->requests_since_fully_seeded, 0); + drng->last_seeded = jiffies; + drng->fully_seeded = false; + drng->force_reseed = true; + pr_debug("reset DRNG\n"); +} + +/* Initialize the DRNG, except the mutex lock */ +int esdm_drng_alloc_common(struct esdm_drng *drng, + const struct esdm_drng_cb *drng_cb) +{ + if (!drng || !drng_cb) + return -EINVAL; + + drng->drng_cb = drng_cb; + drng->drng = drng_cb->drng_alloc(ESDM_DRNG_SECURITY_STRENGTH_BYTES); + if (IS_ERR(drng->drng)) + return PTR_ERR(drng->drng); + + esdm_drng_reset(drng); + return 0; +} + +/* Initialize the default DRNG during boot and perform its seeding */ +int esdm_drng_initalize(void) +{ + int ret; + + if (esdm_get_available()) + return 0; + + /* Catch programming error */ + WARN_ON(esdm_drng_init.hash_cb != esdm_default_hash_cb); + + mutex_lock(&esdm_drng_init.lock); + if (esdm_get_available()) { + mutex_unlock(&esdm_drng_init.lock); + return 0; + } + + ret = esdm_drng_alloc_common(&esdm_drng_init, esdm_default_drng_cb); + mutex_unlock(&esdm_drng_init.lock); + if (ret) + return ret; + + pr_debug("ESDM for general use is available\n"); + atomic_set(&esdm_avail, 1); + + /* Seed the DRNG with any entropy available */ + if (!esdm_pool_trylock()) { + pr_info("Initial DRNG initialized triggering first seeding\n"); + esdm_drng_seed_work(NULL); + } else { + pr_info("Initial DRNG initialized without seeding\n"); + } + + return 0; +} + +static int __init esdm_drng_make_available(void) +{ + return esdm_drng_initalize(); +} +late_initcall(esdm_drng_make_available); + +bool esdm_sp80090c_compliant(void) +{ + if (!IS_ENABLED(CONFIG_CRYPTO_ESDM_OVERSAMPLE_ENTROPY_SOURCES)) + return false; + + /* SP800-90C only requested in FIPS mode */ + return fips_enabled; +} + +/************************* Random Number Generation ***************************/ + +/* Inject a data buffer into the DRNG - caller must hold its lock */ +void esdm_drng_inject(struct esdm_drng *drng, const u8 *inbuf, u32 inbuflen, + bool fully_seeded, const char *drng_type) +{ + BUILD_BUG_ON(ESDM_DRNG_RESEED_THRESH > INT_MAX); + pr_debug("seeding %s DRNG with %u bytes\n", drng_type, inbuflen); + if (drng->drng_cb->drng_seed(drng->drng, inbuf, inbuflen) < 0) { + pr_warn("seeding of %s DRNG failed\n", drng_type); + drng->force_reseed = true; + } else { + int gc = ESDM_DRNG_RESEED_THRESH - atomic_read(&drng->requests); + + pr_debug("%s DRNG stats since last seeding: %lu secs; generate calls: %d\n", + drng_type, + (time_after(jiffies, drng->last_seeded) ? + (jiffies - drng->last_seeded) : 0) / HZ, gc); + + /* Count the numbers of generate ops since last fully seeded */ + if (fully_seeded) + atomic_set(&drng->requests_since_fully_seeded, 0); + else + atomic_add(gc, &drng->requests_since_fully_seeded); + + drng->last_seeded = jiffies; + atomic_set(&drng->requests, ESDM_DRNG_RESEED_THRESH); + drng->force_reseed = false; + + if (!drng->fully_seeded) { + drng->fully_seeded = fully_seeded; + if (drng->fully_seeded) + pr_debug("%s DRNG fully seeded\n", drng_type); + } + } +} + +/* Perform the seeding of the DRNG with data from noise source */ +static void esdm_drng_seed_es(struct esdm_drng *drng) +{ + struct entropy_buf seedbuf __aligned(ESDM_KCAPI_ALIGN); + + esdm_fill_seed_buffer(&seedbuf, + esdm_get_seed_entropy_osr(drng->fully_seeded)); + + mutex_lock(&drng->lock); + esdm_drng_inject(drng, (u8 *)&seedbuf, sizeof(seedbuf), + esdm_fully_seeded_eb(drng->fully_seeded, &seedbuf), + "regular"); + mutex_unlock(&drng->lock); + + /* Set the seeding state of the ESDM */ + esdm_init_ops(&seedbuf); + + memzero_explicit(&seedbuf, sizeof(seedbuf)); +} + +static void esdm_drng_seed(struct esdm_drng *drng) +{ + BUILD_BUG_ON(ESDM_MIN_SEED_ENTROPY_BITS > + ESDM_DRNG_SECURITY_STRENGTH_BITS); + + if (esdm_get_available()) { + /* (Re-)Seed DRNG */ + esdm_drng_seed_es(drng); + } else { + esdm_init_ops(NULL); + } +} + +static void _esdm_drng_seed_work(struct esdm_drng *drng, u32 node) +{ + pr_debug("reseed triggered by system events for DRNG on NUMA node %d\n", + node); + esdm_drng_seed(drng); + if (drng->fully_seeded) { + /* Prevent reseed storm */ + drng->last_seeded += node * 100 * HZ; + } +} + +/* + * DRNG reseed trigger: Kernel thread handler triggered by the schedule_work() + */ +void esdm_drng_seed_work(struct work_struct *dummy) +{ + if (!esdm_drng_init.fully_seeded) { + _esdm_drng_seed_work(&esdm_drng_init, 0); + goto out; + } + + esdm_pool_all_numa_nodes_seeded(true); + +out: + /* Allow the seeding operation to be called again */ + esdm_pool_unlock(); +} + +/* Force all DRNGs to reseed before next generation */ +void esdm_drng_force_reseed(void) +{ + esdm_drng_init.force_reseed = esdm_drng_init.fully_seeded; + pr_debug("force reseed of initial DRNG\n"); +} +EXPORT_SYMBOL(esdm_drng_force_reseed); + +static bool esdm_drng_must_reseed(struct esdm_drng *drng) +{ + return (atomic_dec_and_test(&drng->requests) || + drng->force_reseed || + time_after(jiffies, + drng->last_seeded + esdm_drng_reseed_max_time * HZ)); +} + +/* + * esdm_drng_get() - Get random data out of the DRNG which is reseeded + * frequently. + * + * @drng: DRNG instance + * @outbuf: buffer for storing random data + * @outbuflen: length of outbuf + * + * Return: + * * < 0 in error case (DRNG generation or update failed) + * * >=0 returning the returned number of bytes + */ +int esdm_drng_get(struct esdm_drng *drng, u8 *outbuf, u32 outbuflen) +{ + u32 processed = 0; + + if (!outbuf || !outbuflen) + return 0; + + if (!esdm_get_available()) + return -EOPNOTSUPP; + + outbuflen = min_t(size_t, outbuflen, INT_MAX); + + /* If DRNG operated without proper reseed for too long, block ESDM */ + BUILD_BUG_ON(ESDM_DRNG_MAX_WITHOUT_RESEED < ESDM_DRNG_RESEED_THRESH); + if (atomic_read_u32(&drng->requests_since_fully_seeded) > max_wo_reseed) + esdm_unset_fully_seeded(drng); + + while (outbuflen) { + u32 todo = min_t(u32, outbuflen, ESDM_DRNG_MAX_REQSIZE); + int ret; + + if (esdm_drng_must_reseed(drng)) { + if (esdm_pool_trylock()) { + drng->force_reseed = true; + } else { + esdm_drng_seed(drng); + esdm_pool_unlock(); + } + } + + mutex_lock(&drng->lock); + ret = drng->drng_cb->drng_generate(drng->drng, + outbuf + processed, todo); + mutex_unlock(&drng->lock); + if (ret <= 0) { + pr_warn("getting random data from DRNG failed (%d)\n", + ret); + return -EFAULT; + } + processed += ret; + outbuflen -= ret; + } + + return processed; +} + +int esdm_drng_get_sleep(u8 *outbuf, u32 outbuflen) +{ + struct esdm_drng *drng = &esdm_drng_init; + int ret; + + might_sleep(); + + ret = esdm_drng_initalize(); + if (ret) + return ret; + + return esdm_drng_get(drng, outbuf, outbuflen); +} + +/* Reset ESDM such that all existing entropy is gone */ +static void _esdm_reset(struct work_struct *work) +{ + mutex_lock(&esdm_drng_init.lock); + esdm_drng_reset(&esdm_drng_init); + mutex_unlock(&esdm_drng_init.lock); + + esdm_set_entropy_thresh(ESDM_INIT_ENTROPY_BITS); + + esdm_reset_state(); +} + +static DECLARE_WORK(esdm_reset_work, _esdm_reset); + +void esdm_reset(void) +{ + schedule_work(&esdm_reset_work); +} + +/******************* Generic ESDM kernel output interfaces ********************/ + +int esdm_drng_sleep_while_nonoperational(int nonblock) +{ + if (likely(!esdm_state_operational())) + return 0; + if (nonblock) + return -EAGAIN; + return wait_event_interruptible(esdm_init_wait, + esdm_state_operational()); +} + +int esdm_drng_sleep_while_non_min_seeded(void) +{ + if (likely(esdm_state_min_seeded())) + return 0; + return wait_event_interruptible(esdm_init_wait, + esdm_state_min_seeded()); +} + +void esdm_get_random_bytes_full(void *buf, int nbytes) +{ + esdm_drng_sleep_while_nonoperational(0); + esdm_drng_get_sleep((u8 *)buf, (u32)nbytes); +} +EXPORT_SYMBOL(esdm_get_random_bytes_full); + +void esdm_get_random_bytes_min(void *buf, int nbytes) +{ + esdm_drng_sleep_while_non_min_seeded(); + esdm_drng_get_sleep((u8 *)buf, (u32)nbytes); +} +EXPORT_SYMBOL(esdm_get_random_bytes_min); diff --git a/crypto/esdm/esdm_drng_mgr.h b/crypto/esdm/esdm_drng_mgr.h new file mode 100644 index 000000000000..241b94b84bf7 --- /dev/null +++ b/crypto/esdm/esdm_drng_mgr.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2022, Stephan Mueller + */ + +#ifndef _ESDM_DRNG_H +#define _ESDM_DRNG_H + +#include +#include +#include + +#include "esdm_definitions.h" + +extern struct wait_queue_head esdm_init_wait; +extern int esdm_drng_reseed_max_time; +extern struct mutex esdm_crypto_cb_update; +extern const struct esdm_drng_cb *esdm_default_drng_cb; +extern const struct esdm_hash_cb *esdm_default_hash_cb; + +/* DRNG state handle */ +struct esdm_drng { + void *drng; /* DRNG handle */ + void *hash; /* Hash handle */ + const struct esdm_drng_cb *drng_cb; /* DRNG callbacks */ + const struct esdm_hash_cb *hash_cb; /* Hash callbacks */ + atomic_t requests; /* Number of DRNG requests */ + atomic_t requests_since_fully_seeded; /* Number DRNG requests since + * last fully seeded + */ + unsigned long last_seeded; /* Last time it was seeded */ + bool fully_seeded; /* Is DRNG fully seeded? */ + bool force_reseed; /* Force a reseed */ + + rwlock_t hash_lock; /* Lock hash_cb replacement */ + /* Lock write operations on DRNG state, DRNG replacement of drng_cb */ + struct mutex lock; /* Non-atomic DRNG operation */ + spinlock_t spin_lock; /* Atomic DRNG operation */ +}; + +#define ESDM_DRNG_STATE_INIT(x, d, h, d_cb, h_cb) \ + .drng = d, \ + .hash = h, \ + .drng_cb = d_cb, \ + .hash_cb = h_cb, \ + .requests = ATOMIC_INIT(ESDM_DRNG_RESEED_THRESH),\ + .requests_since_fully_seeded = ATOMIC_INIT(0), \ + .last_seeded = 0, \ + .fully_seeded = false, \ + .force_reseed = true, \ + .hash_lock = __RW_LOCK_UNLOCKED(x.hash_lock) + +struct esdm_drng *esdm_drng_init_instance(void); +struct esdm_drng *esdm_drng_node_instance(void); + +void esdm_reset(void); +int esdm_drng_alloc_common(struct esdm_drng *drng, + const struct esdm_drng_cb *crypto_cb); +int esdm_drng_initalize(void); +bool esdm_sp80090c_compliant(void); +bool esdm_get_available(void); +void esdm_drng_reset(struct esdm_drng *drng); +void esdm_drng_inject(struct esdm_drng *drng, const u8 *inbuf, u32 inbuflen, + bool fully_seeded, const char *drng_type); +int esdm_drng_get(struct esdm_drng *drng, u8 *outbuf, u32 outbuflen); +int esdm_drng_sleep_while_nonoperational(int nonblock); +int esdm_drng_sleep_while_non_min_seeded(void); +int esdm_drng_get_sleep(u8 *outbuf, u32 outbuflen); +void esdm_drng_seed_work(struct work_struct *dummy); +void esdm_drng_force_reseed(void); + +static inline u32 esdm_compress_osr(void) +{ + return esdm_sp80090c_compliant() ? + CONFIG_CRYPTO_ESDM_OVERSAMPLE_ES_BITS : 0; +} + +static inline u32 esdm_reduce_by_osr(u32 entropy_bits) +{ + u32 osr_bits = esdm_compress_osr(); + + return (entropy_bits >= osr_bits) ? (entropy_bits - osr_bits) : 0; +} + +#endif /* _ESDM_DRNG_H */ diff --git a/crypto/esdm/esdm_es_aux.c b/crypto/esdm/esdm_es_aux.c new file mode 100644 index 000000000000..9a665eaf856b --- /dev/null +++ b/crypto/esdm/esdm_es_aux.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * ESDM Slow Entropy Source: Auxiliary entropy pool + * + * Copyright (C) 2022, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include + +#include "esdm_es_aux.h" +#include "esdm_es_mgr.h" + +/* + * This is the auxiliary pool + * + * The aux pool array is aligned to 8 bytes to comfort the kernel crypto API + * cipher implementations of the hash functions used to read the pool: for some + * accelerated implementations, we need an alignment to avoid a realignment + * which involves memcpy(). The alignment to 8 bytes should satisfy all crypto + * implementations. + */ +struct esdm_pool { + u8 aux_pool[ESDM_POOL_SIZE]; /* Aux pool: digest state */ + atomic_t aux_entropy_bits; + atomic_t digestsize; /* Digest size of used hash */ + bool initialized; /* Aux pool initialized? */ + + /* Serialize read of entropy pool and update of aux pool */ + spinlock_t lock; +}; + +static struct esdm_pool esdm_pool __aligned(ESDM_KCAPI_ALIGN) = { + .aux_entropy_bits = ATOMIC_INIT(0), + .digestsize = ATOMIC_INIT(ESDM_ATOMIC_DIGEST_SIZE), + .initialized = false, + .lock = __SPIN_LOCK_UNLOCKED(esdm_pool.lock) +}; + +/********************************** Helper ***********************************/ + +/* Entropy in bits present in aux pool */ +static u32 esdm_aux_avail_entropy(u32 __unused) +{ + /* Cap available entropy with max entropy */ + u32 avail_bits = min_t(u32, esdm_get_digestsize(), + atomic_read_u32(&esdm_pool.aux_entropy_bits)); + + /* Consider oversampling rate due to aux pool conditioning */ + return esdm_reduce_by_osr(avail_bits); +} + +/* Set the digest size of the used hash in bytes */ +static void esdm_set_digestsize(u32 digestsize) +{ + struct esdm_pool *pool = &esdm_pool; + u32 ent_bits = atomic_xchg_relaxed(&pool->aux_entropy_bits, 0), + old_digestsize = esdm_get_digestsize(); + + atomic_set(&esdm_pool.digestsize, digestsize); + + /* + * Update the write wakeup threshold which must not be larger + * than the digest size of the current conditioning hash. + */ + digestsize = esdm_reduce_by_osr(digestsize << 3); + esdm_write_wakeup_bits = digestsize; + + /* + * In case the new digest is larger than the old one, cap the available + * entropy to the old message digest used to process the existing data. + */ + ent_bits = min_t(u32, ent_bits, old_digestsize); + atomic_add(ent_bits, &pool->aux_entropy_bits); +} + +static int __init esdm_init_wakeup_bits(void) +{ + u32 digestsize = esdm_reduce_by_osr(esdm_get_digestsize()); + + esdm_write_wakeup_bits = digestsize; + return 0; +} +core_initcall(esdm_init_wakeup_bits); + +/* Obtain the digest size provided by the used hash in bits */ +u32 esdm_get_digestsize(void) +{ + return atomic_read_u32(&esdm_pool.digestsize) << 3; +} + +/* Set entropy content in user-space controllable aux pool */ +void esdm_pool_set_entropy(u32 entropy_bits) +{ + atomic_set(&esdm_pool.aux_entropy_bits, entropy_bits); +} + +static void esdm_aux_reset(void) +{ + esdm_pool_set_entropy(0); +} + +/* + * Replace old with new hash for auxiliary pool handling + * + * Assumption: the caller must guarantee that the new_cb is available during the + * entire operation (e.g. it must hold the write lock against pointer updating). + */ +static int +esdm_aux_switch_hash(struct esdm_drng *drng, int __unused, + const struct esdm_hash_cb *new_cb, void *new_hash, + const struct esdm_hash_cb *old_cb) +{ + struct esdm_drng *init_drng = esdm_drng_init_instance(); + struct esdm_pool *pool = &esdm_pool; + struct shash_desc *shash = (struct shash_desc *)pool->aux_pool; + u8 digest[ESDM_MAX_DIGESTSIZE]; + int ret; + + if (!IS_ENABLED(CONFIG_CRYPTO_ESDM_CRYPTO_SWITCH)) + return -EOPNOTSUPP; + + if (unlikely(!pool->initialized)) + return 0; + + /* We only switch if the processed DRNG is the initial DRNG. */ + if (init_drng != drng) + return 0; + + /* Get the aux pool hash with old digest ... */ + ret = old_cb->hash_final(shash, digest) ?: + /* ... re-initialize the hash with the new digest ... */ + new_cb->hash_init(shash, new_hash) ?: + /* + * ... feed the old hash into the new state. We may feed + * uninitialized memory into the new state, but this is + * considered no issue and even good as we have some more + * uncertainty here. + */ + new_cb->hash_update(shash, digest, sizeof(digest)); + if (!ret) { + esdm_set_digestsize(new_cb->hash_digestsize(new_hash)); + pr_debug("Re-initialize aux entropy pool with hash %s\n", + new_cb->hash_name()); + } + + memzero_explicit(digest, sizeof(digest)); + return ret; +} + +/* Insert data into auxiliary pool by using the hash update function. */ +static int +esdm_aux_pool_insert_locked(const u8 *inbuf, u32 inbuflen, u32 entropy_bits) +{ + struct esdm_pool *pool = &esdm_pool; + struct shash_desc *shash = (struct shash_desc *)pool->aux_pool; + struct esdm_drng *drng = esdm_drng_init_instance(); + const struct esdm_hash_cb *hash_cb; + unsigned long flags; + void *hash; + int ret; + + entropy_bits = min_t(u32, entropy_bits, inbuflen << 3); + + read_lock_irqsave(&drng->hash_lock, flags); + hash_cb = drng->hash_cb; + hash = drng->hash; + + if (unlikely(!pool->initialized)) { + ret = hash_cb->hash_init(shash, hash); + if (ret) + goto out; + pool->initialized = true; + } + + ret = hash_cb->hash_update(shash, inbuf, inbuflen); + if (ret) + goto out; + + /* + * Cap the available entropy to the hash output size compliant to + * SP800-90B section 3.1.5.1 table 1. + */ + entropy_bits += atomic_read_u32(&pool->aux_entropy_bits); + atomic_set(&pool->aux_entropy_bits, + min_t(u32, entropy_bits, + hash_cb->hash_digestsize(hash) << 3)); + +out: + read_unlock_irqrestore(&drng->hash_lock, flags); + return ret; +} + +int esdm_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits) +{ + struct esdm_pool *pool = &esdm_pool; + unsigned long flags; + int ret; + + spin_lock_irqsave(&pool->lock, flags); + ret = esdm_aux_pool_insert_locked(inbuf, inbuflen, entropy_bits); + spin_unlock_irqrestore(&pool->lock, flags); + + esdm_es_add_entropy(); + + return ret; +} +EXPORT_SYMBOL(esdm_pool_insert_aux); + +/************************* Get data from entropy pool *************************/ + +/* + * Get auxiliary entropy pool and its entropy content for seed buffer. + * Caller must hold esdm_pool.pool->lock. + * @outbuf: buffer to store data in with size requested_bits + * @requested_bits: Requested amount of entropy + * @return: amount of entropy in outbuf in bits. + */ +static u32 esdm_aux_get_pool(u8 *outbuf, u32 requested_bits) +{ + struct esdm_pool *pool = &esdm_pool; + struct shash_desc *shash = (struct shash_desc *)pool->aux_pool; + struct esdm_drng *drng = esdm_drng_init_instance(); + const struct esdm_hash_cb *hash_cb; + unsigned long flags; + void *hash; + u32 collected_ent_bits, returned_ent_bits, unused_bits = 0, + digestsize, digestsize_bits, requested_bits_osr; + u8 aux_output[ESDM_MAX_DIGESTSIZE]; + + if (unlikely(!pool->initialized)) + return 0; + + read_lock_irqsave(&drng->hash_lock, flags); + + hash_cb = drng->hash_cb; + hash = drng->hash; + digestsize = hash_cb->hash_digestsize(hash); + digestsize_bits = digestsize << 3; + + /* Cap to maximum entropy that can ever be generated with given hash */ + esdm_cap_requested(digestsize_bits, requested_bits); + + /* Ensure that no more than the size of aux_pool can be requested */ + requested_bits = min_t(u32, requested_bits, (ESDM_MAX_DIGESTSIZE << 3)); + requested_bits_osr = requested_bits + esdm_compress_osr(); + + /* Cap entropy with entropy counter from aux pool and the used digest */ + collected_ent_bits = min_t(u32, digestsize_bits, + atomic_xchg_relaxed(&pool->aux_entropy_bits, 0)); + + /* We collected too much entropy and put the overflow back */ + if (collected_ent_bits > requested_bits_osr) { + /* Amount of bits we collected too much */ + unused_bits = collected_ent_bits - requested_bits_osr; + /* Put entropy back */ + atomic_add(unused_bits, &pool->aux_entropy_bits); + /* Fix collected entropy */ + collected_ent_bits = requested_bits_osr; + } + + /* Apply oversampling: discount requested oversampling rate */ + returned_ent_bits = esdm_reduce_by_osr(collected_ent_bits); + + pr_debug("obtained %u bits by collecting %u bits of entropy from aux pool, %u bits of entropy remaining\n", + returned_ent_bits, collected_ent_bits, unused_bits); + + /* Get the digest for the aux pool to be returned to the caller ... */ + if (hash_cb->hash_final(shash, aux_output) || + /* + * ... and re-initialize the aux state. Do not add the aux pool + * digest for backward secrecy as it will be added with the + * insertion of the complete seed buffer after it has been filled. + */ + hash_cb->hash_init(shash, hash)) { + returned_ent_bits = 0; + } else { + /* + * Do not truncate the output size exactly to collected_ent_bits + * as the aux pool may contain data that is not credited with + * entropy, but we want to use them to stir the DRNG state. + */ + memcpy(outbuf, aux_output, requested_bits >> 3); + } + + read_unlock_irqrestore(&drng->hash_lock, flags); + memzero_explicit(aux_output, digestsize); + return returned_ent_bits; +} + +static void esdm_aux_get_backtrack(struct entropy_buf *eb, u32 requested_bits, + bool __unused) +{ + struct esdm_pool *pool = &esdm_pool; + unsigned long flags; + + /* Ensure aux pool extraction and backtracking op are atomic */ + spin_lock_irqsave(&pool->lock, flags); + + eb->e_bits[esdm_ext_es_aux] = esdm_aux_get_pool(eb->e[esdm_ext_es_aux], + requested_bits); + + /* Mix the extracted data back into pool for backtracking resistance */ + if (esdm_aux_pool_insert_locked((u8 *)eb, + sizeof(struct entropy_buf), 0)) + pr_warn("Backtracking resistance operation failed\n"); + + spin_unlock_irqrestore(&pool->lock, flags); +} + +static void esdm_aux_es_state(unsigned char *buf, size_t buflen) +{ + const struct esdm_drng *esdm_drng_init = esdm_drng_init_instance(); + + /* Assume the esdm_drng_init lock is taken by caller */ + snprintf(buf, buflen, + " Hash for operating entropy pool: %s\n" + " Available entropy: %u\n", + esdm_drng_init->hash_cb->hash_name(), + esdm_aux_avail_entropy(0)); +} + +struct esdm_es_cb esdm_es_aux = { + .name = "Auxiliary", + .get_ent = esdm_aux_get_backtrack, + .curr_entropy = esdm_aux_avail_entropy, + .max_entropy = esdm_get_digestsize, + .state = esdm_aux_es_state, + .reset = esdm_aux_reset, + .switch_hash = esdm_aux_switch_hash, +}; diff --git a/crypto/esdm/esdm_es_aux.h b/crypto/esdm/esdm_es_aux.h new file mode 100644 index 000000000000..fde7f34696b0 --- /dev/null +++ b/crypto/esdm/esdm_es_aux.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2022, Stephan Mueller + */ + +#ifndef _ESDM_ES_AUX_H +#define _ESDM_ES_AUX_H + +#include "esdm_drng_mgr.h" +#include "esdm_es_mgr_cb.h" + +u32 esdm_get_digestsize(void); +void esdm_pool_set_entropy(u32 entropy_bits); +int esdm_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits); + +extern struct esdm_es_cb esdm_es_aux; + +/****************************** Helper code ***********************************/ + +/* Obtain the security strength of the ESDM in bits */ +static inline u32 esdm_security_strength(void) +{ + /* + * We use a hash to read the entropy in the entropy pool. According to + * SP800-90B table 1, the entropy can be at most the digest size. + * Considering this together with the last sentence in section 3.1.5.1.2 + * the security strength of a (approved) hash is equal to its output + * size. On the other hand the entropy cannot be larger than the + * security strength of the used DRBG. + */ + return min_t(u32, ESDM_FULL_SEED_ENTROPY_BITS, esdm_get_digestsize()); +} + +static inline u32 esdm_get_seed_entropy_osr(bool fully_seeded) +{ + u32 requested_bits = esdm_security_strength(); + + /* Apply oversampling during initialization according to SP800-90C */ + if (esdm_sp80090c_compliant() && !fully_seeded) + requested_bits += CONFIG_CRYPTO_ESDM_SEED_BUFFER_INIT_ADD_BITS; + return requested_bits; +} + +#endif /* _ESDM_ES_AUX_H */ diff --git a/crypto/esdm/esdm_es_mgr.c b/crypto/esdm/esdm_es_mgr.c new file mode 100644 index 000000000000..8bdef5a934a8 --- /dev/null +++ b/crypto/esdm/esdm_es_mgr.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * ESDM Entropy sources management + * + * Copyright (C) 2022, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +#include "esdm_drng_mgr.h" +#include "esdm_es_aux.h" +#include "esdm_es_mgr.h" + +struct esdm_state { + bool perform_seedwork; /* Can seed work be performed? */ + bool esdm_operational; /* Is DRNG operational? */ + bool esdm_fully_seeded; /* Is DRNG fully seeded? */ + bool esdm_min_seeded; /* Is DRNG minimally seeded? */ + bool all_online_numa_node_seeded;/* All NUMA DRNGs seeded? */ + + /* + * To ensure that external entropy providers cannot dominate the + * internal noise sources but yet cannot be dominated by internal + * noise sources, the following booleans are intended to allow + * external to provide seed once when a DRNG reseed occurs. This + * triggering of external noise source is performed even when the + * entropy pool has sufficient entropy. + */ + + atomic_t boot_entropy_thresh; /* Reseed threshold */ + atomic_t reseed_in_progress; /* Flag for on executing reseed */ + struct work_struct esdm_seed_work; /* (re)seed work queue */ +}; + +static struct esdm_state esdm_state = { + false, false, false, false, false, + .boot_entropy_thresh = ATOMIC_INIT(ESDM_INIT_ENTROPY_BITS), + .reseed_in_progress = ATOMIC_INIT(0), +}; + +/* + * If the entropy count falls under this number of bits, then we + * should wake up processes which are selecting or polling on write + * access to /dev/random. + */ +u32 esdm_write_wakeup_bits = (ESDM_WRITE_WAKEUP_ENTROPY << 3); + +/* + * The entries must be in the same order as defined by + * enum enum esdm_external_es + */ +struct esdm_es_cb *esdm_es[] = { + &esdm_es_aux +}; + +/********************************** Helper ***********************************/ + +/* + * Reading of the ESDM pool is only allowed by one caller. The reading is + * only performed to (re)seed DRNGs. Thus, if this "lock" is already taken, + * the reseeding operation is in progress. The caller is not intended to wait + * but continue with its other operation. + */ +int esdm_pool_trylock(void) +{ + return atomic_cmpxchg(&esdm_state.reseed_in_progress, 0, 1); +} + +void esdm_pool_unlock(void) +{ + atomic_set(&esdm_state.reseed_in_progress, 0); +} + +/* Set new entropy threshold for reseeding during boot */ +void esdm_set_entropy_thresh(u32 new_entropy_bits) +{ + atomic_set(&esdm_state.boot_entropy_thresh, new_entropy_bits); +} + +/* + * Reset ESDM state - the entropy counters are reset, but the data that may + * or may not have entropy remains in the pools as this data will not hurt. + */ +void esdm_reset_state(void) +{ + u32 i; + + for_each_esdm_es(i) { + if (esdm_es[i]->reset) + esdm_es[i]->reset(); + } + esdm_state.esdm_operational = false; + esdm_state.esdm_fully_seeded = false; + esdm_state.esdm_min_seeded = false; + esdm_state.all_online_numa_node_seeded = false; + pr_debug("reset ESDM\n"); +} + +/* Set flag that all DRNGs are fully seeded */ +void esdm_pool_all_numa_nodes_seeded(bool set) +{ + esdm_state.all_online_numa_node_seeded = set; +} + +/* Return boolean whether ESDM reached minimally seed level */ +bool esdm_state_min_seeded(void) +{ + return esdm_state.esdm_min_seeded; +} + +/* Return boolean whether ESDM reached fully seed level */ +bool esdm_state_fully_seeded(void) +{ + return esdm_state.esdm_fully_seeded; +} + +/* Return boolean whether ESDM is considered fully operational */ +bool esdm_state_operational(void) +{ + return esdm_state.esdm_operational; +} + +static void esdm_init_wakeup(void) +{ + wake_up_all(&esdm_init_wait); +} + +static bool esdm_fully_seeded(bool fully_seeded, u32 collected_entropy) +{ + return (collected_entropy >= esdm_get_seed_entropy_osr(fully_seeded)); +} + +/* Policy to check whether entropy buffer contains full seeded entropy */ +bool esdm_fully_seeded_eb(bool fully_seeded, struct entropy_buf *eb) +{ + u32 i, collected_entropy = 0; + + for_each_esdm_es(i) + collected_entropy += eb->e_bits[i]; + + return esdm_fully_seeded(fully_seeded, collected_entropy); +} + +/* Mark one DRNG as not fully seeded */ +void esdm_unset_fully_seeded(struct esdm_drng *drng) +{ + drng->fully_seeded = false; + esdm_pool_all_numa_nodes_seeded(false); + + /* + * The init DRNG instance must always be fully seeded as this instance + * is the fall-back if any of the per-NUMA node DRNG instances is + * insufficiently seeded. Thus, we mark the entire ESDM as + * non-operational if the initial DRNG becomes not fully seeded. + */ + if (drng == esdm_drng_init_instance() && esdm_state_operational()) { + pr_debug("ESDM set to non-operational\n"); + esdm_state.esdm_operational = false; + esdm_state.esdm_fully_seeded = false; + + /* If sufficient entropy is available, reseed now. */ + esdm_es_add_entropy(); + } +} + +/* Policy to enable ESDM operational mode */ +static void esdm_set_operational(void) +{ + /* + * ESDM is operational if the initial DRNG is fully seeded. This state + * can only occur if either the external entropy sources provided + * sufficient entropy, or the SP800-90B startup test completed for + * the internal ES to supply also entropy data. + */ + if (esdm_state.esdm_fully_seeded) { + esdm_state.esdm_operational = true; + esdm_init_wakeup(); + pr_info("ESDM fully operational\n"); + } +} + +static u32 esdm_avail_entropy_thresh(void) +{ + u32 ent_thresh = esdm_security_strength(); + + /* + * Apply oversampling during initialization according to SP800-90C as + * we request a larger buffer from the ES. + */ + if (esdm_sp80090c_compliant() && + !esdm_state.all_online_numa_node_seeded) + ent_thresh += CONFIG_CRYPTO_ESDM_SEED_BUFFER_INIT_ADD_BITS; + + return ent_thresh; +} + +/* Available entropy in the entire ESDM considering all entropy sources */ +u32 esdm_avail_entropy(void) +{ + u32 i, ent = 0, ent_thresh = esdm_avail_entropy_thresh(); + + BUILD_BUG_ON(ARRAY_SIZE(esdm_es) != esdm_ext_es_last); + for_each_esdm_es(i) + ent += esdm_es[i]->curr_entropy(ent_thresh); + return ent; +} + +/* + * esdm_init_ops() - Set seed stages of ESDM + * + * Set the slow noise source reseed trigger threshold. The initial threshold + * is set to the minimum data size that can be read from the pool: a word. Upon + * reaching this value, the next seed threshold of 128 bits is set followed + * by 256 bits. + * + * @eb: buffer containing the size of entropy currently injected into DRNG - if + * NULL, the function obtains the available entropy from the ES. + */ +void esdm_init_ops(struct entropy_buf *eb) +{ + struct esdm_state *state = &esdm_state; + u32 i, requested_bits, seed_bits = 0; + + if (state->esdm_operational) + return; + + requested_bits = esdm_get_seed_entropy_osr( + state->all_online_numa_node_seeded); + + if (eb) { + for_each_esdm_es(i) + seed_bits += eb->e_bits[i]; + } else { + u32 ent_thresh = esdm_avail_entropy_thresh(); + + for_each_esdm_es(i) + seed_bits += esdm_es[i]->curr_entropy(ent_thresh); + } + + /* DRNG is seeded with full security strength */ + if (state->esdm_fully_seeded) { + esdm_set_operational(); + esdm_set_entropy_thresh(requested_bits); + } else if (esdm_fully_seeded(state->all_online_numa_node_seeded, + seed_bits)) { + state->esdm_fully_seeded = true; + esdm_set_operational(); + state->esdm_min_seeded = true; + pr_info("ESDM fully seeded with %u bits of entropy\n", + seed_bits); + esdm_set_entropy_thresh(requested_bits); + } else if (!state->esdm_min_seeded) { + + /* DRNG is seeded with at least 128 bits of entropy */ + if (seed_bits >= ESDM_MIN_SEED_ENTROPY_BITS) { + state->esdm_min_seeded = true; + pr_info("ESDM minimally seeded with %u bits of entropy\n", + seed_bits); + esdm_set_entropy_thresh(requested_bits); + esdm_init_wakeup(); + + /* DRNG is seeded with at least ESDM_INIT_ENTROPY_BITS bits */ + } else if (seed_bits >= ESDM_INIT_ENTROPY_BITS) { + pr_info("ESDM initial entropy level %u bits of entropy\n", + seed_bits); + esdm_set_entropy_thresh(ESDM_MIN_SEED_ENTROPY_BITS); + } + } +} + +int __init esdm_rand_initialize(void) +{ + struct seed { + ktime_t time; + unsigned long data[(ESDM_MAX_DIGESTSIZE / + sizeof(unsigned long))]; + struct new_utsname utsname; + } seed __aligned(ESDM_KCAPI_ALIGN); + unsigned int i; + + BUILD_BUG_ON(ESDM_MAX_DIGESTSIZE % sizeof(unsigned long)); + + seed.time = ktime_get_real(); + + for (i = 0; i < ARRAY_SIZE(seed.data); i++) { + if (!arch_get_random_seed_long(&(seed.data[i])) && + !arch_get_random_long(&seed.data[i])) + seed.data[i] = random_get_entropy(); + } + memcpy(&seed.utsname, utsname(), sizeof(*(utsname()))); + + esdm_pool_insert_aux((u8 *)&seed, sizeof(seed), 0); + memzero_explicit(&seed, sizeof(seed)); + + /* Initialize the seed work queue */ + INIT_WORK(&esdm_state.esdm_seed_work, esdm_drng_seed_work); + esdm_state.perform_seedwork = true; + + return 0; +} + +early_initcall(esdm_rand_initialize); + +/* Interface requesting a reseed of the DRNG */ +void esdm_es_add_entropy(void) +{ + /* + * Once all DRNGs are fully seeded, the system-triggered arrival of + * entropy will not cause any reseeding any more. + */ + if (likely(esdm_state.all_online_numa_node_seeded)) + return; + + /* Only trigger the DRNG reseed if we have collected entropy. */ + if (esdm_avail_entropy() < + atomic_read_u32(&esdm_state.boot_entropy_thresh)) + return; + + /* Ensure that the seeding only occurs once at any given time. */ + if (esdm_pool_trylock()) + return; + + /* Seed the DRNG with any available noise. */ + if (esdm_state.perform_seedwork) + schedule_work(&esdm_state.esdm_seed_work); + else + esdm_drng_seed_work(NULL); +} + +/* Fill the seed buffer with data from the noise sources */ +void esdm_fill_seed_buffer(struct entropy_buf *eb, u32 requested_bits) +{ + struct esdm_state *state = &esdm_state; + u32 i, req_ent = esdm_sp80090c_compliant() ? + esdm_security_strength() : ESDM_MIN_SEED_ENTROPY_BITS; + + /* Guarantee that requested bits is a multiple of bytes */ + BUILD_BUG_ON(ESDM_DRNG_SECURITY_STRENGTH_BITS % 8); + + /* always reseed the DRNG with the current time stamp */ + eb->now = random_get_entropy(); + + /* + * Require at least 128 bits of entropy for any reseed. If the ESDM is + * operated SP800-90C compliant we want to comply with SP800-90A section + * 9.2 mandating that DRNG is reseeded with the security strength. + */ + if (state->esdm_fully_seeded && (esdm_avail_entropy() < req_ent)) { + for_each_esdm_es(i) + eb->e_bits[i] = 0; + + return; + } + + /* Concatenate the output of the entropy sources. */ + for_each_esdm_es(i) { + esdm_es[i]->get_ent(eb, requested_bits, + state->esdm_fully_seeded); + } +} diff --git a/crypto/esdm/esdm_es_mgr.h b/crypto/esdm/esdm_es_mgr.h new file mode 100644 index 000000000000..e1b73fe618d1 --- /dev/null +++ b/crypto/esdm/esdm_es_mgr.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2022, Stephan Mueller + */ + +#ifndef _ESDM_ES_MGR_H +#define _ESDM_ES_MGR_H + +#include "esdm_es_mgr_cb.h" + +/*************************** General ESDM parameter ***************************/ + +#define ESDM_DRNG_BLOCKSIZE 64 /* Maximum of DRNG block sizes */ + +/* Helper to concatenate a macro with an integer type */ +#define ESDM_PASTER(x, y) x ## y +#define ESDM_UINT32_C(x) ESDM_PASTER(x, U) + +/************************* Entropy sources management *************************/ + +extern struct esdm_es_cb *esdm_es[]; + +#define for_each_esdm_es(ctr) \ + for ((ctr) = 0; (ctr) < esdm_ext_es_last; (ctr)++) + +bool esdm_state_min_seeded(void); +int esdm_rand_initialize(void); +bool esdm_state_operational(void); + +extern u32 esdm_write_wakeup_bits; +void esdm_set_entropy_thresh(u32 new); +u32 esdm_avail_entropy(void); +void esdm_reset_state(void); + +bool esdm_state_fully_seeded(void); + +int esdm_pool_trylock(void); +void esdm_pool_unlock(void); +void esdm_pool_all_numa_nodes_seeded(bool set); + +bool esdm_fully_seeded_eb(bool fully_seeded, struct entropy_buf *eb); +void esdm_unset_fully_seeded(struct esdm_drng *drng); +void esdm_fill_seed_buffer(struct entropy_buf *eb, u32 requested_bits); +void esdm_init_ops(struct entropy_buf *eb); + +#endif /* _ESDM_ES_MGR_H */ diff --git a/crypto/esdm/esdm_es_mgr_cb.h b/crypto/esdm/esdm_es_mgr_cb.h new file mode 100644 index 000000000000..41b39983196f --- /dev/null +++ b/crypto/esdm/esdm_es_mgr_cb.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2022, Stephan Mueller + * + * Definition of an entropy source. + */ + +#ifndef _ESDM_ES_MGR_CB_H +#define _ESDM_ES_MGR_CB_H + +#include + +#include "esdm_definitions.h" +#include "esdm_drng_mgr.h" + +enum esdm_external_es { + esdm_ext_es_aux, /* MUST BE LAST ES! */ + esdm_ext_es_last /* MUST be the last entry */ +}; + +struct entropy_buf { + u8 e[esdm_ext_es_last][ESDM_DRNG_INIT_SEED_SIZE_BYTES]; + u32 now, e_bits[esdm_ext_es_last]; +}; + +/* + * struct esdm_es_cb - callback defining an entropy source + * @name: Name of the entropy source. + * @get_ent: Fetch entropy into the entropy_buf. The ES shall only deliver + * data if its internal initialization is complete, including any + * SP800-90B startup testing or similar. + * @curr_entropy: Return amount of currently available entropy. + * @max_entropy: Maximum amount of entropy the entropy source is able to + * maintain. + * @state: Buffer with human-readable ES state. + * @reset: Reset entropy source (drop all entropy and reinitialize). + * This callback may be NULL. + * @switch_hash: callback to switch from an old hash callback definition to + * a new one. This callback may be NULL. + */ +struct esdm_es_cb { + const char *name; + void (*get_ent)(struct entropy_buf *eb, u32 requested_bits, + bool fully_seeded); + u32 (*curr_entropy)(u32 requested_bits); + u32 (*max_entropy)(void); + void (*state)(unsigned char *buf, size_t buflen); + void (*reset)(void); + int (*switch_hash)(struct esdm_drng *drng, int node, + const struct esdm_hash_cb *new_cb, void *new_hash, + const struct esdm_hash_cb *old_cb); +}; + +/* Allow entropy sources to tell the ES manager that new entropy is there */ +void esdm_es_add_entropy(void); + +/* Cap to maximum entropy that can ever be generated with given hash */ +#define esdm_cap_requested(__digestsize_bits, __requested_bits) \ + do { \ + if (__digestsize_bits < __requested_bits) { \ + pr_debug("Cannot satisfy requested entropy %u due to insufficient hash size %u\n",\ + __requested_bits, __digestsize_bits); \ + __requested_bits = __digestsize_bits; \ + } \ + } while (0) + +#endif /* _ESDM_ES_MGR_CB_H */ diff --git a/crypto/esdm/esdm_sha.h b/crypto/esdm/esdm_sha.h new file mode 100644 index 000000000000..c71662881b8d --- /dev/null +++ b/crypto/esdm/esdm_sha.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * ESDM SHA definition usable in atomic contexts right from the start of the + * kernel. + * + * Copyright (C) 2022, Stephan Mueller + */ + +#ifndef _ESDM_SHA_H +#define _ESDM_SHA_H + +extern const struct esdm_hash_cb esdm_sha_hash_cb; + +#endif /* _ESDM_SHA_H */ diff --git a/crypto/esdm/esdm_sha256.c b/crypto/esdm/esdm_sha256.c new file mode 100644 index 000000000000..030c503d09c5 --- /dev/null +++ b/crypto/esdm/esdm_sha256.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Backend for the ESDM providing the SHA-256 implementation that can be used + * without the kernel crypto API available including during early boot and in + * atomic contexts. + * + * Copyright (C) 2022, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +#include "esdm_sha.h" + +static u32 esdm_sha256_hash_digestsize(void *hash) +{ + return SHA256_DIGEST_SIZE; +} + +static int esdm_sha256_hash_init(struct shash_desc *shash, void *hash) +{ + /* + * We do not need a TFM - we only need sufficient space for + * struct sha256_state on the stack. + */ + sha256_init(shash_desc_ctx(shash)); + return 0; +} + +static int esdm_sha256_hash_update(struct shash_desc *shash, + const u8 *inbuf, u32 inbuflen) +{ + sha256_update(shash_desc_ctx(shash), inbuf, inbuflen); + return 0; +} + +static int esdm_sha256_hash_final(struct shash_desc *shash, u8 *digest) +{ + sha256_final(shash_desc_ctx(shash), digest); + return 0; +} + +static const char *esdm_sha256_hash_name(void) +{ + return "SHA-256"; +} + +static void esdm_sha256_hash_desc_zero(struct shash_desc *shash) +{ + memzero_explicit(shash_desc_ctx(shash), sizeof(struct sha256_state)); +} + +static void *esdm_sha256_hash_alloc(void) +{ + pr_info("Hash %s allocated\n", esdm_sha256_hash_name()); + return NULL; +} + +static void esdm_sha256_hash_dealloc(void *hash) { } + +const struct esdm_hash_cb esdm_sha_hash_cb = { + .hash_name = esdm_sha256_hash_name, + .hash_alloc = esdm_sha256_hash_alloc, + .hash_dealloc = esdm_sha256_hash_dealloc, + .hash_digestsize = esdm_sha256_hash_digestsize, + .hash_init = esdm_sha256_hash_init, + .hash_update = esdm_sha256_hash_update, + .hash_final = esdm_sha256_hash_final, + .hash_desc_zero = esdm_sha256_hash_desc_zero, +}; diff --git a/include/crypto/esdm.h b/include/crypto/esdm.h new file mode 100644 index 000000000000..95a12ea0356e --- /dev/null +++ b/include/crypto/esdm.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2022, Stephan Mueller + */ + +#ifndef _ESDM_H +#define _ESDM_H + +#include +#include +#include + +/* + * struct esdm_drng_cb - cryptographic callback functions defining a DRNG + * @drng_name Name of DRNG + * @drng_alloc: Allocate DRNG -- the provided integer should be used for + * sanity checks. + * return: allocated data structure or PTR_ERR on error + * @drng_dealloc: Deallocate DRNG + * @drng_seed: Seed the DRNG with data of arbitrary length drng: is + * pointer to data structure allocated with drng_alloc + * return: >= 0 on success, < 0 on error + * @drng_generate: Generate random numbers from the DRNG with arbitrary + * length + */ +struct esdm_drng_cb { + const char *(*drng_name)(void); + void *(*drng_alloc)(u32 sec_strength); + void (*drng_dealloc)(void *drng); + int (*drng_seed)(void *drng, const u8 *inbuf, u32 inbuflen); + int (*drng_generate)(void *drng, u8 *outbuf, u32 outbuflen); +}; + +/* + * struct esdm_hash_cb - cryptographic callback functions defining a hash + * @hash_name Name of Hash used for reading entropy pool arbitrary + * length + * @hash_alloc: Allocate the hash for reading the entropy pool + * return: allocated data structure (NULL is success too) + * or ERR_PTR on error + * @hash_dealloc: Deallocate Hash + * @hash_digestsize: Return the digestsize for the used hash to read out + * entropy pool + * hash: is pointer to data structure allocated with + * hash_alloc + * return: size of digest of hash in bytes + * @hash_init: Initialize hash + * hash: is pointer to data structure allocated with + * hash_alloc + * return: 0 on success, < 0 on error + * @hash_update: Update hash operation + * hash: is pointer to data structure allocated with + * hash_alloc + * return: 0 on success, < 0 on error + * @hash_final Final hash operation + * hash: is pointer to data structure allocated with + * hash_alloc + * return: 0 on success, < 0 on error + * @hash_desc_zero Zeroization of hash state buffer + * + * Assumptions: + * + * 1. Hash operation will not sleep + * 2. The hash' volatile state information is provided with *shash by caller. + */ +struct esdm_hash_cb { + const char *(*hash_name)(void); + void *(*hash_alloc)(void); + void (*hash_dealloc)(void *hash); + u32 (*hash_digestsize)(void *hash); + int (*hash_init)(struct shash_desc *shash, void *hash); + int (*hash_update)(struct shash_desc *shash, const u8 *inbuf, + u32 inbuflen); + int (*hash_final)(struct shash_desc *shash, u8 *digest); + void (*hash_desc_zero)(struct shash_desc *shash); +}; + +/* + * esdm_get_random_bytes_full() - Provider of cryptographic strong + * random numbers for kernel-internal usage from a fully initialized ESDM. + * + * This function will always return random numbers from a fully seeded and + * fully initialized ESDM. + * + * This function is appropriate only for non-atomic use cases as this + * function may sleep. It provides access to the full functionality of ESDM + * including the switchable DRNG support, that may support other DRNGs such + * as the SP800-90A DRBG. + * + * @buf: buffer to store the random bytes + * @nbytes: size of the buffer + */ +#ifdef CONFIG_CRYPTO_ESDM +void esdm_get_random_bytes_full(void *buf, int nbytes); +#endif + +/* + * esdm_get_random_bytes_min() - Provider of cryptographic strong + * random numbers for kernel-internal usage from at least a minimally seeded + * ESDM, which is not necessarily fully initialized yet (e.g. SP800-90C + * oversampling applied in FIPS mode is not applied yet). + * + * This function is appropriate only for non-atomic use cases as this + * function may sleep. It provides access to the full functionality of ESDM + * including the switchable DRNG support, that may support other DRNGs such + * as the SP800-90A DRBG. + * + * @buf: buffer to store the random bytes + * @nbytes: size of the buffer + */ +#ifdef CONFIG_CRYPTO_ESDM +void esdm_get_random_bytes_min(void *buf, int nbytes); +#endif + +#endif /* _ESDM_H */ From patchwork Wed Jan 26 07:04:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 12724640 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B39A0C2BA4C for ; Wed, 26 Jan 2022 07:07:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237564AbiAZHH0 (ORCPT ); Wed, 26 Jan 2022 02:07:26 -0500 Received: from mo4-p01-ob.smtp.rzone.de ([85.215.255.52]:32877 "EHLO mo4-p01-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229979AbiAZHHZ (ORCPT ); Wed, 26 Jan 2022 02:07:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1643180840; s=strato-dkim-0002; d=chronox.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=m+i9CLkjPEZN+mJvMVmyIOnfpp38EzSCqnnNuSmoaj4=; b=pOf8A+6pNwYueo3L0JJeQj7V3+KklzsYs5UFd7veRcFc/VHzOXOL2ZmkhudY8Q82vE aJSWsCAy+Y7UQDIFlf5u7H9euv60p/Y/1z2bu+URx3Bkv2XIc57X4xrcaoo1KpXwKdX0 Q+2tzTt8czmUDYcL/gekg9lyGqfSpTpbHgXJE96G1vIfky55m6IAaXsmWBRbWPcB0pgI tvCNvpKH444gZ/uEBGBOHyZxq4/nWv26UGmHtaQEY1YfKmLMOmjkL/qJkR4tSDzPBT86 kFiKm5HNfpL1kEuMdnpA3gVf80cGM6Cgpn83bMKMgt0Nr4salJa7Je6e96spe17eZR0D ITeg== Authentication-Results: strato.com; dkim=none X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvScdWrN" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 47.38.0 DYNA|AUTH) with ESMTPSA id v5f65ay0Q77KiuP (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 26 Jan 2022 08:07:20 +0100 (CET) From: Stephan =?iso-8859-1?q?M=FCller?= To: herbert@gondor.apana.org.au Cc: linux-crypto@vger.kernel.org, simo@redhat.com, Nicolai Stange Subject: [PATCH 4/7] crypto: move Jitter RNG header include dir Date: Wed, 26 Jan 2022 08:04:23 +0100 Message-ID: <2612341.cojqenx9y0@positron.chronox.de> In-Reply-To: <2486550.t9SDvczpPo@positron.chronox.de> References: <2486550.t9SDvczpPo@positron.chronox.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org To support the ESDM operation which uses the Jitter RNG separately from the kernel crypto API, the header file must be accessible to the ESDM code. Signed-off-by: Stephan Mueller --- crypto/jitterentropy-kcapi.c | 3 +-- crypto/jitterentropy.c | 2 +- {crypto => include/crypto/internal}/jitterentropy.h | 0 3 files changed, 2 insertions(+), 3 deletions(-) rename {crypto => include/crypto/internal}/jitterentropy.h (100%) diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c index 2d115bec15ae..40bc51f32432 100644 --- a/crypto/jitterentropy-kcapi.c +++ b/crypto/jitterentropy-kcapi.c @@ -41,10 +41,9 @@ #include #include #include +#include #include -#include "jitterentropy.h" - /*************************************************************************** * Helper function ***************************************************************************/ diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c index 93bff3213823..81b80a4d3d3a 100644 --- a/crypto/jitterentropy.c +++ b/crypto/jitterentropy.c @@ -133,7 +133,7 @@ struct rand_data { #define JENT_ENTROPY_SAFETY_FACTOR 64 #include -#include "jitterentropy.h" +#include /*************************************************************************** * Adaptive Proportion Test diff --git a/crypto/jitterentropy.h b/include/crypto/internal/jitterentropy.h similarity index 100% rename from crypto/jitterentropy.h rename to include/crypto/internal/jitterentropy.h From patchwork Wed Jan 26 07:04:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 12724642 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AD9F8C28CF5 for ; Wed, 26 Jan 2022 07:07:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237559AbiAZHH1 (ORCPT ); Wed, 26 Jan 2022 02:07:27 -0500 Received: from mo4-p01-ob.smtp.rzone.de ([85.215.255.54]:37203 "EHLO mo4-p01-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237560AbiAZHHZ (ORCPT ); Wed, 26 Jan 2022 02:07:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1643180840; s=strato-dkim-0002; d=chronox.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=5W8dF4J0+VsTtyaYaW6dTsomv2iFvEugHmuG4DR/nr8=; b=YMInTWCflU2sk4Ok8eDtpowV/5SAv/Jl9F9YUs0f/vY2hMX5Mc0uOqPBVruNdzieC3 i0xomDaRsrphO91RKqXjTObiDM1Xyull6gSPuaDJvWYPLdNOEt6+UJScMxw5pyq8THY0 mr6flCvzT2PMzRgSAcmuDdu1S2uN+Wr0QYq34vsfU0ub154U5AKpP3j2ePqXBKTgctZ6 4pPcin5eZMrIDTeKs5zryUy+ilEutoe9lnQWtq3nYBdCIRSDL3lAn8pyD3RJ/ZEJ0GIX ldIMT5tZBu0WobFapfpH6OmQUQrtfh5++2hQUKpxTsvb9yyQCYbQ/Y9ouyWG7+9eZZOD pIqQ== Authentication-Results: strato.com; dkim=none X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvScdWrN" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 47.38.0 DYNA|AUTH) with ESMTPSA id v5f65ay0Q77JiuO (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 26 Jan 2022 08:07:19 +0100 (CET) From: Stephan =?iso-8859-1?q?M=FCller?= To: herbert@gondor.apana.org.au Cc: linux-crypto@vger.kernel.org, simo@redhat.com, Nicolai Stange Subject: [PATCH 5/7] crypto: ESDM - add Jitter RNG entropy source Date: Wed, 26 Jan 2022 08:04:44 +0100 Message-ID: <5596750.E0xQCEvomI@positron.chronox.de> In-Reply-To: <2486550.t9SDvczpPo@positron.chronox.de> References: <2486550.t9SDvczpPo@positron.chronox.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The Jitter RNG entropy source provided as part of the kernel crypto API is used as a separate entropy source for the ESDM. It can be enabled at compile time together with its implied entropy rate. The entropy rate states how many bits of entropy are present in 256 bits of data from that entropy source. If a different amount of data is pulled from the entropy source, the entropy ratio is scaled accordingly. In FIPS mode, the amount of entropy is set to 256 bits considering that this entropy source is provided with an entropy analysis demonstrating its compliance with SP800-90B and thus allowing to claim full strength. When the entropy ratio is set to zero, the Jitter RNG provides data but without claiming any entropy for it. In addition, the patch offers the compile time option to allow setting the entropy rate with the kernel command line using the parameter of esdm_es_jent.jent_entropy. Signed-off-by: Stephan Mueller --- crypto/esdm/Kconfig | 45 ++++++++++++ crypto/esdm/Makefile | 2 + crypto/esdm/esdm_es_jent.c | 128 +++++++++++++++++++++++++++++++++++ crypto/esdm/esdm_es_jent.h | 17 +++++ crypto/esdm/esdm_es_mgr.c | 4 ++ crypto/esdm/esdm_es_mgr_cb.h | 3 + 6 files changed, 199 insertions(+) create mode 100644 crypto/esdm/esdm_es_jent.c create mode 100644 crypto/esdm/esdm_es_jent.h diff --git a/crypto/esdm/Kconfig b/crypto/esdm/Kconfig index 1351d4d146dc..eeef71546bc3 100644 --- a/crypto/esdm/Kconfig +++ b/crypto/esdm/Kconfig @@ -68,6 +68,51 @@ config CRYPTO_ESDM_SEED_BUFFER_INIT_ADD_BITS endmenu # "Specific DRNG seeding strategies" +menu "Entropy Source Configuration" + +config CRYPTO_ESDM_RUNTIME_ES_CONFIG + bool "Enable runtime configuration of entropy sources" + help + When enabling this option, the ESDM provides the mechanism + allowing to alter the entropy rate of each entropy source + during boot time and runtime. + + Each entropy source allows its entropy rate changed with + a kernel command line option. When not providing any + option, the default specified during kernel compilation + is applied. + +comment "Jitter RNG Entropy Source" + +config CRYPTO_ESDM_JENT + bool "Enable Jitter RNG as ESDM Seed Source" + depends on CRYPTO + select CRYPTO_JITTERENTROPY + help + The Linux RNG may use the Jitter RNG as entropy source. Enabling + this option enables the use of the Jitter RNG. Its default + entropy level is 16 bits of entropy per 256 data bits delivered + by the Jitter RNG. This entropy level can be changed at boot + time or at runtime with the esdm_base.jitterrng configuration + variable. + +config CRYPTO_ESDM_JENT_ENTROPY_RATE + int "Jitter RNG Entropy Source Entropy Rate" + depends on CRYPTO_ESDM_JENT + range 0 256 + default 16 + help + The option defines the amount of entropy the ESDM applies to 256 + bits of data obtained from the Jitter RNG entropy source. The + ESDM enforces the limit that this value must be in the range + between 0 and 256. + + When configuring this value to 0, the Jitter RNG entropy source + will provide 256 bits of data without being credited to contain + entropy. + +endmenu # "Entropy Source Configuration" + config CRYPTO_ESDM_DRNG_KCAPI bool depends on CRYPTO diff --git a/crypto/esdm/Makefile b/crypto/esdm/Makefile index 24dc7af234b6..99a86ce3e3af 100644 --- a/crypto/esdm/Makefile +++ b/crypto/esdm/Makefile @@ -8,3 +8,5 @@ obj-y += esdm_es_mgr.o esdm_drng_mgr.o \ obj-$(CONFIG_CRYPTO_ESDM_SHA256) += esdm_sha256.o obj-$(CONFIG_CRYPTO_ESDM_DRNG_KCAPI) += esdm_drng_kcapi.o + +obj-$(CONFIG_CRYPTO_ESDM_JENT) += esdm_es_jent.o diff --git a/crypto/esdm/esdm_es_jent.c b/crypto/esdm/esdm_es_jent.c new file mode 100644 index 000000000000..8cbd649e8f42 --- /dev/null +++ b/crypto/esdm/esdm_es_jent.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * ESDM Fast Entropy Source: Jitter RNG + * + * Copyright (C) 2022, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +#include "esdm_definitions.h" +#include "esdm_es_aux.h" +#include "esdm_es_jent.h" + +/* + * Estimated entropy of data is a 16th of ESDM_DRNG_SECURITY_STRENGTH_BITS. + * Albeit a full entropy assessment is provided for the noise source indicating + * that it provides high entropy rates and considering that it deactivates + * when it detects insufficient hardware, the chosen under estimation of + * entropy is considered to be acceptable to all reviewers. + */ +static u32 jent_entropy = CONFIG_CRYPTO_ESDM_JENT_ENTROPY_RATE; +#ifdef CONFIG_CRYPTO_ESDM_RUNTIME_ES_CONFIG +module_param(jent_entropy, uint, 0644); +MODULE_PARM_DESC(jent_entropy, "Entropy in bits of 256 data bits from Jitter RNG noise source"); +#endif + +static bool esdm_jent_initialized = false; +static struct rand_data *esdm_jent_state; + +static int __init esdm_jent_initialize(void) +{ + /* Initialize the Jitter RNG after the clocksources are initialized. */ + if (jent_entropy_init() || + (esdm_jent_state = jent_entropy_collector_alloc(1, 0)) == NULL) { + jent_entropy = 0; + pr_info("Jitter RNG unusable on current system\n"); + return 0; + } + esdm_jent_initialized = true; + pr_debug("Jitter RNG working on current system\n"); + + /* In FIPS mode, the Jitter RNG is defined to have full of entropy */ + if (fips_enabled) + jent_entropy = ESDM_DRNG_SECURITY_STRENGTH_BITS; + + esdm_drng_force_reseed(); + if (jent_entropy) + esdm_es_add_entropy(); + + return 0; +} +device_initcall(esdm_jent_initialize); + +static u32 esdm_jent_entropylevel(u32 requested_bits) +{ + return esdm_fast_noise_entropylevel(esdm_jent_initialized ? + jent_entropy : 0, requested_bits); +} + +static u32 esdm_jent_poolsize(void) +{ + return esdm_jent_entropylevel(esdm_security_strength()); +} + + +/* + * esdm_get_jent() - Get Jitter RNG entropy + * + * @eb: entropy buffer to store entropy + * @requested_bits: requested entropy in bits + */ +static void esdm_jent_get(struct entropy_buf *eb, u32 requested_bits, + bool __unused) +{ + int ret; + u32 ent_bits = esdm_jent_entropylevel(requested_bits); + unsigned long flags; + static DEFINE_SPINLOCK(esdm_jent_lock); + + spin_lock_irqsave(&esdm_jent_lock, flags); + + if (!esdm_jent_initialized) { + spin_unlock_irqrestore(&esdm_jent_lock, flags); + goto err; + } + + ret = jent_read_entropy(esdm_jent_state, eb->e[esdm_ext_es_jitter], + requested_bits >> 3); + spin_unlock_irqrestore(&esdm_jent_lock, flags); + + if (ret) { + pr_debug("Jitter RNG failed with %d\n", ret); + goto err; + } + + pr_debug("obtained %u bits of entropy from Jitter RNG noise source\n", + ent_bits); + + eb->e_bits[esdm_ext_es_jitter] = ent_bits; + return; + +err: + eb->e_bits[esdm_ext_es_jitter] = 0; +} + +static void esdm_jent_es_state(unsigned char *buf, size_t buflen) +{ + snprintf(buf, buflen, + " Available entropy: %u\n" + " Enabled: %s\n", + esdm_jent_poolsize(), + esdm_jent_initialized ? "true" : "false"); +} + +struct esdm_es_cb esdm_es_jent = { + .name = "JitterRNG", + .get_ent = esdm_jent_get, + .curr_entropy = esdm_jent_entropylevel, + .max_entropy = esdm_jent_poolsize, + .state = esdm_jent_es_state, + .reset = NULL, + .switch_hash = NULL, +}; diff --git a/crypto/esdm/esdm_es_jent.h b/crypto/esdm/esdm_es_jent.h new file mode 100644 index 000000000000..d6a48f267018 --- /dev/null +++ b/crypto/esdm/esdm_es_jent.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2022, Stephan Mueller + */ + +#ifndef _ESDM_ES_JENT_H +#define _ESDM_ES_JENT_H + +#include "esdm_es_mgr_cb.h" + +#ifdef CONFIG_CRYPTO_ESDM_JENT + +extern struct esdm_es_cb esdm_es_jent; + +#endif /* CONFIG_CRYPTO_ESDM_JENT */ + +#endif /* _ESDM_ES_JENT_H */ diff --git a/crypto/esdm/esdm_es_mgr.c b/crypto/esdm/esdm_es_mgr.c index 8bdef5a934a8..b7b1a4151137 100644 --- a/crypto/esdm/esdm_es_mgr.c +++ b/crypto/esdm/esdm_es_mgr.c @@ -13,6 +13,7 @@ #include "esdm_drng_mgr.h" #include "esdm_es_aux.h" +#include "esdm_es_jent.h" #include "esdm_es_mgr.h" struct esdm_state { @@ -54,6 +55,9 @@ u32 esdm_write_wakeup_bits = (ESDM_WRITE_WAKEUP_ENTROPY << 3); * enum enum esdm_external_es */ struct esdm_es_cb *esdm_es[] = { +#ifdef CONFIG_CRYPTO_ESDM_JENT + &esdm_es_jent, +#endif &esdm_es_aux }; diff --git a/crypto/esdm/esdm_es_mgr_cb.h b/crypto/esdm/esdm_es_mgr_cb.h index 41b39983196f..18f0e4317691 100644 --- a/crypto/esdm/esdm_es_mgr_cb.h +++ b/crypto/esdm/esdm_es_mgr_cb.h @@ -14,6 +14,9 @@ #include "esdm_drng_mgr.h" enum esdm_external_es { +#ifdef CONFIG_CRYPTO_ESDM_JENT + esdm_ext_es_jitter, /* Jitter RNG */ +#endif esdm_ext_es_aux, /* MUST BE LAST ES! */ esdm_ext_es_last /* MUST be the last entry */ }; From patchwork Wed Jan 26 07:05:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 12724641 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EA712C63682 for ; Wed, 26 Jan 2022 07:07:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237562AbiAZHH1 (ORCPT ); Wed, 26 Jan 2022 02:07:27 -0500 Received: from mo4-p01-ob.smtp.rzone.de ([85.215.255.52]:40413 "EHLO mo4-p01-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237559AbiAZHHZ (ORCPT ); Wed, 26 Jan 2022 02:07:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1643180839; s=strato-dkim-0002; d=chronox.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=1VapLQQk9KAoOWLbgE8//O90bixt9wVg2yiZM3bOoYI=; b=gnT0c/JnmA2GHytrDNIL+W+uN+ieUWcp/2MSrziOF+Rdu4jP0jIa4ecWumWJdtPm5/ bavnMiIBmL+gL/8EI3hw8jmagTJUiHp7sAH9Do1vQqtrB0reL9VtkNtUp/Ck4XbT7FzL pYEWZBb1LedxLFXTvOFws2sWWBFlJncM4BGZFt3AIHbiF5ec6XVdQ+T+GiydpxasX84S 7V8d/RQnjSxrYDUkP/Jcrf7mNehixit1+jtb8R+4gpKHybITO8NPzi3nI+5TmOzRbpZr cBS4wsroT5/4rAWEBtWcAu0gG12YXo1s23OSv6/AAuIhcOcrTZsr4fNJ/wCm5ebtL/cv S6dw== Authentication-Results: strato.com; dkim=none X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvScdWrN" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 47.38.0 DYNA|AUTH) with ESMTPSA id v5f65ay0Q77JiuN (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 26 Jan 2022 08:07:19 +0100 (CET) From: Stephan =?iso-8859-1?q?M=FCller?= To: herbert@gondor.apana.org.au Cc: linux-crypto@vger.kernel.org, simo@redhat.com, Nicolai Stange Subject: [PATCH 6/7] crypto: ESDM - add Kernel RNG entropy source Date: Wed, 26 Jan 2022 08:05:08 +0100 Message-ID: <274193597.ifERbkFSEj@positron.chronox.de> In-Reply-To: <2486550.t9SDvczpPo@positron.chronox.de> References: <2486550.t9SDvczpPo@positron.chronox.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The Kernel RNG entropy source is used as a separate entropy source for the ESDM. It can be enabled at compile time together with its implied entropy rate. If the FIPS mode is enabled, the entropy rate is automatically set to 0 since the entropy source is not SP800-90B compliant and thus must be considered to deliver no entropy. As long as the Kernel RNG is not fully initialized, the entropy rate is also forced to 0. The entropy rate states how many bits of entropy are present in 256 bits of data from that entropy source. If a different amount of data is pulled from the entropy source, the entropy ratio is scaled accordingly. When the entropy ratio is set to zero, the Kernel RNG provides data but without claiming any entropy for it. When the compile time switch for enabling runtime setting of the entropy rate is enabled (CONFIG_CRYPTO_ESDM_RUNTIME_ES_CONFIG), the entropy rate can be configured at the kernel command line with the option esdm_es_random.krng_entropy. If this option is not set, the default value set during compile time is used. Signed-off-by: Stephan Mueller --- crypto/esdm/Kconfig | 28 ++++++++ crypto/esdm/Makefile | 1 + crypto/esdm/esdm_es_krng.c | 120 +++++++++++++++++++++++++++++++++++ crypto/esdm/esdm_es_krng.h | 17 +++++ crypto/esdm/esdm_es_mgr.c | 4 ++ crypto/esdm/esdm_es_mgr_cb.h | 3 + 6 files changed, 173 insertions(+) create mode 100644 crypto/esdm/esdm_es_krng.c create mode 100644 crypto/esdm/esdm_es_krng.h diff --git a/crypto/esdm/Kconfig b/crypto/esdm/Kconfig index eeef71546bc3..43e11484e95c 100644 --- a/crypto/esdm/Kconfig +++ b/crypto/esdm/Kconfig @@ -111,6 +111,34 @@ config CRYPTO_ESDM_JENT_ENTROPY_RATE will provide 256 bits of data without being credited to contain entropy. +comment "Kernel RNG Entropy Source" + +config CRYPTO_ESDM_KERNEL_RNG + bool "Enable Kernel RNG as ESDM Seed Source" + help + The Linux RNG may use the kernel RNG (random.c) as entropy + source. + +config CRYPTO_ESDM_KERNEL_RNG_ENTROPY_RATE + int "Kernel RNG Entropy Source Entropy Rate" + depends on CRYPTO_ESDM_KERNEL_RNG + range 0 256 + default 256 + help + The option defines the amount of entropy the ESDM applies to 256 + bits of data obtained from the kernel RNG entropy source. The + ESDM enforces the limit that this value must be in the range + between 0 and 256. + + When configuring this value to 0, the kernel RNG entropy source + will provide 256 bits of data without being credited to contain + entropy. + + Note: This value is set to 0 automatically when booting the + kernel in FIPS mode (with fips=1 kernel command line option). + This is due to the fact that random.c is not SP800-90B + compliant. + endmenu # "Entropy Source Configuration" config CRYPTO_ESDM_DRNG_KCAPI diff --git a/crypto/esdm/Makefile b/crypto/esdm/Makefile index 99a86ce3e3af..404436de0aa2 100644 --- a/crypto/esdm/Makefile +++ b/crypto/esdm/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_CRYPTO_ESDM_SHA256) += esdm_sha256.o obj-$(CONFIG_CRYPTO_ESDM_DRNG_KCAPI) += esdm_drng_kcapi.o +obj-$(CONFIG_CRYPTO_ESDM_KERNEL_RNG) += esdm_es_krng.o obj-$(CONFIG_CRYPTO_ESDM_JENT) += esdm_es_jent.o diff --git a/crypto/esdm/esdm_es_krng.c b/crypto/esdm/esdm_es_krng.c new file mode 100644 index 000000000000..d536a9139276 --- /dev/null +++ b/crypto/esdm/esdm_es_krng.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * ESDM Fast Entropy Source: Linux kernel RNG (random.c) + * + * Copyright (C) 2022, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +#include "esdm_es_aux.h" +#include "esdm_es_krng.h" + +static u32 krng_entropy = CONFIG_CRYPTO_ESDM_KERNEL_RNG_ENTROPY_RATE; +#ifdef CONFIG_CRYPTO_ESDM_RUNTIME_ES_CONFIG +module_param(krng_entropy, uint, 0644); +MODULE_PARM_DESC(krng_entropy, "Entropy in bits of 256 data bits from the kernel RNG noise source"); +#endif + +static atomic_t esdm_krng_initial_rate = ATOMIC_INIT(0); + +static struct random_ready_callback esdm_krng_ready = { + .owner = THIS_MODULE, + .func = NULL, +}; + +static u32 esdm_krng_fips_entropylevel(u32 entropylevel) +{ + return fips_enabled ? 0 : entropylevel; +} + +static void esdm_krng_adjust_entropy(struct random_ready_callback *rdy) +{ + u32 entropylevel; + + krng_entropy = atomic_read_u32(&esdm_krng_initial_rate); + + entropylevel = esdm_krng_fips_entropylevel(krng_entropy); + pr_debug("Kernel RNG is fully seeded, setting entropy rate to %u bits of entropy\n", + entropylevel); + esdm_drng_force_reseed(); + if (entropylevel) + esdm_es_add_entropy(); +} + +static u32 esdm_krng_entropylevel(u32 requested_bits) +{ + if (esdm_krng_ready.func == NULL) { + int err; + + esdm_krng_ready.func = esdm_krng_adjust_entropy; + + err = add_random_ready_callback(&esdm_krng_ready); + switch (err) { + case 0: + atomic_set(&esdm_krng_initial_rate, krng_entropy); + krng_entropy = 0; + pr_debug("Kernel RNG is not yet seeded, setting entropy rate to 0 bits of entropy\n"); + break; + + case -EALREADY: + pr_debug("Kernel RNG is fully seeded, setting entropy rate to %u bits of entropy\n", + esdm_krng_fips_entropylevel(krng_entropy)); + break; + default: + esdm_krng_ready.func = NULL; + return 0; + } + } + + return esdm_fast_noise_entropylevel( + esdm_krng_fips_entropylevel(krng_entropy), requested_bits); +} + +static u32 esdm_krng_poolsize(void) +{ + return esdm_krng_entropylevel(esdm_security_strength()); +} + +/* + * esdm_krng_get() - Get kernel RNG entropy + * + * @eb: entropy buffer to store entropy + * @requested_bits: requested entropy in bits + */ +static void esdm_krng_get(struct entropy_buf *eb, u32 requested_bits, + bool __unused) +{ + u32 ent_bits = esdm_krng_entropylevel(requested_bits); + + get_random_bytes(eb->e[esdm_ext_es_krng], requested_bits >> 3); + + pr_debug("obtained %u bits of entropy from kernel RNG noise source\n", + ent_bits); + + eb->e_bits[esdm_ext_es_krng] = ent_bits; +} + +static void esdm_krng_es_state(unsigned char *buf, size_t buflen) +{ + snprintf(buf, buflen, + " Available entropy: %u\n" + " Entropy Rate per 256 data bits: %u\n", + esdm_krng_poolsize(), + esdm_krng_entropylevel(256)); +} + +struct esdm_es_cb esdm_es_krng = { + .name = "KernelRNG", + .get_ent = esdm_krng_get, + .curr_entropy = esdm_krng_entropylevel, + .max_entropy = esdm_krng_poolsize, + .state = esdm_krng_es_state, + .reset = NULL, + .switch_hash = NULL, +}; diff --git a/crypto/esdm/esdm_es_krng.h b/crypto/esdm/esdm_es_krng.h new file mode 100644 index 000000000000..b164594bfe79 --- /dev/null +++ b/crypto/esdm/esdm_es_krng.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2022, Stephan Mueller + */ + +#ifndef _ESDM_ES_RANDOM_H +#define _ESDM_ES_RANDOM_H + +#include "esdm_es_mgr_cb.h" + +#ifdef CONFIG_CRYPTO_ESDM_KERNEL_RNG + +extern struct esdm_es_cb esdm_es_krng; + +#endif /* CONFIG_CRYPTO_ESDM_KERNEL_RNG */ + +#endif /* _ESDM_ES_RANDOM_H */ diff --git a/crypto/esdm/esdm_es_mgr.c b/crypto/esdm/esdm_es_mgr.c index b7b1a4151137..0a65aafac8d2 100644 --- a/crypto/esdm/esdm_es_mgr.c +++ b/crypto/esdm/esdm_es_mgr.c @@ -14,6 +14,7 @@ #include "esdm_drng_mgr.h" #include "esdm_es_aux.h" #include "esdm_es_jent.h" +#include "esdm_es_krng.h" #include "esdm_es_mgr.h" struct esdm_state { @@ -57,6 +58,9 @@ u32 esdm_write_wakeup_bits = (ESDM_WRITE_WAKEUP_ENTROPY << 3); struct esdm_es_cb *esdm_es[] = { #ifdef CONFIG_CRYPTO_ESDM_JENT &esdm_es_jent, +#endif +#ifdef CONFIG_CRYPTO_ESDM_KERNEL_RNG + &esdm_es_krng, #endif &esdm_es_aux }; diff --git a/crypto/esdm/esdm_es_mgr_cb.h b/crypto/esdm/esdm_es_mgr_cb.h index 18f0e4317691..a94ad28f7d0f 100644 --- a/crypto/esdm/esdm_es_mgr_cb.h +++ b/crypto/esdm/esdm_es_mgr_cb.h @@ -16,6 +16,9 @@ enum esdm_external_es { #ifdef CONFIG_CRYPTO_ESDM_JENT esdm_ext_es_jitter, /* Jitter RNG */ +#endif +#ifdef CONFIG_CRYPTO_ESDM_KERNEL_RNG + esdm_ext_es_krng, /* random.c */ #endif esdm_ext_es_aux, /* MUST BE LAST ES! */ esdm_ext_es_last /* MUST be the last entry */ From patchwork Wed Jan 26 07:05:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 12724639 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C80E3C28CF5 for ; Wed, 26 Jan 2022 07:07:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230103AbiAZHHY (ORCPT ); Wed, 26 Jan 2022 02:07:24 -0500 Received: from mo4-p00-ob.smtp.rzone.de ([81.169.146.160]:41793 "EHLO mo4-p00-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229979AbiAZHHX (ORCPT ); Wed, 26 Jan 2022 02:07:23 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1643180839; s=strato-dkim-0002; d=chronox.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=kKMeQ4jbF2RlwL77OU3Y0p14ptPgkI8XQ+SVVGGN4cQ=; b=bRrUL/ly8ep2ngLTlSwiQF72bS8kJe6ZpTKou/po8G9gQ8BMM54iJqd1+e2Yr0708B 8Xy7TPYje/lC4QsXfmLM4MuG/vbOEPW9BrfcWnt0gqg9vsQbIRYJZZaJ0KegQWA/ce7w b9rKZPx2/w4Oxtlp+Y0T9//z6PWvKEgtF6hHe36zST1laySy45Fvt9cWsTWR3AARxsmD zXC5XAvz8+hXgXg54gOFDowybTownaua7Z7cx/OdyMlVECG1kj/7mdA1m7HawIm+6J2T YE2x9/g2zQiyeAakoXTpUwun+EkCNFmxKv/zqyeWCvrjfHTnlqPWcdAn5TN3418rxfKO zGsw== Authentication-Results: strato.com; dkim=none X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvScdWrN" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 47.38.0 DYNA|AUTH) with ESMTPSA id v5f65ay0Q77IiuM (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 26 Jan 2022 08:07:18 +0100 (CET) From: Stephan =?iso-8859-1?q?M=FCller?= To: herbert@gondor.apana.org.au Cc: linux-crypto@vger.kernel.org, simo@redhat.com, Nicolai Stange Subject: [PATCH 7/7] crypto: ESDM - add kernel crypto API RNG interface Date: Wed, 26 Jan 2022 08:05:29 +0100 Message-ID: <3328650.KVeVyVuyWN@positron.chronox.de> In-Reply-To: <2486550.t9SDvczpPo@positron.chronox.de> References: <2486550.t9SDvczpPo@positron.chronox.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The ESDM export interfaces that allow obtaining random numbers from a fully seeded DRNG as specified in crypto/esdm.h. By using the interface function esdm_get_random_bytes_full, the ESDM is registered as a random number generator with the kernel crypto API's RNG framework. This registered RNG provides random numbers from an always appropriately seeded and initialized DRNG. When a caller performs a crypto_rng_reset() call on the ESDM, the ESDM injects the provided data into the auxiliary pool and flags a reseed. This reseed is performed by the immediate subsequent DRNG generation operation. The RNG registered by the ESDM with the kernel crypto API is accessible via the name "esdm". In addition, the ESDM is registered as "stdrng" with the highest priority which implies that the kernel crypto API call of crypto_get_default_rng accesses the ESDM. The ESDM is marked as fips_allowed = 1 in the testmgr because it complies with the FIPS 140 rules as follows: - SP800-90A: The ESDM uses the kernel crypto API's DRBG and thus provides access to a fully seeded and SP800-90A DRBG. - SP800-90B: The ESDM manages entropy sources via its plugins. Currently there is no internal entropy source provided which means that the used entropy sources must provide their own SP800-90B analysis. For the Jitter RNG, a separate SP800-90B analysis is provided. The ESDM only ensures that the Jitter RNG is appropriately initialized before it is used as an entropy source. The kernel RNG (random.c) entropy source on the other hand is not SP800-90B compliant. Thus, in FIPS mode, the ESDM credits its data with zero bits of entropy. - SP800-90C: The ESDM follows the current draft of SP800-90C when compiled with the option CONFIG_CRYPTO_ESDM_OVERSAMPLE_ENTROPY_SOURCES. The DRBG is initially seeded with at least 384 bits of entropy before it is marked as fully seeded (and thus produces random numbers via the esdm_get_random_bytes_full call. Subsequent reseeds are performed with at least 256 bits of entropy. The conditioning operation performed in the auxiliary pool requires 64 more bits of entropy to be fed into the conditioner function provide the respective entropy output (e.g. 256 bits of entropy are fed into the SHA-256 conditioner resulting in the output of 192 bits of entropy provided by the entropy source to the ESDM). With the given entropy sources, the ESDM follows the RBG2(NP) construction method. Signed-off-by: Stephan Mueller --- crypto/esdm/Kconfig | 14 +++++ crypto/esdm/Makefile | 2 + crypto/esdm/esdm_drng_kcapi.c | 1 + crypto/esdm/esdm_interface_kcapi.c | 91 ++++++++++++++++++++++++++++++ crypto/testmgr.c | 8 +++ 5 files changed, 116 insertions(+) create mode 100644 crypto/esdm/esdm_interface_kcapi.c diff --git a/crypto/esdm/Kconfig b/crypto/esdm/Kconfig index 43e11484e95c..3636c1c79602 100644 --- a/crypto/esdm/Kconfig +++ b/crypto/esdm/Kconfig @@ -27,6 +27,20 @@ config CRYPTO_ESDM_SHA256 bool default y if CRYPTO_LIB_SHA256 +menu "ESDM Interfaces" + +config CRYPTO_ESDM_KCAPI_IF + tristate "Interface with Kernel Crypto API" + depends on CRYPTO_RNG + help + The ESDM can be registered with the kernel crypto API's + random number generator framework. This offers a random + number generator with the name "esdm" and a priority that + is intended to be higher than the existing RNG + implementations. + +endmenu # "ESDM Interfaces" + menu "Specific DRNG seeding strategies" config CRYPTO_ESDM_OVERSAMPLE_ENTROPY_SOURCES diff --git a/crypto/esdm/Makefile b/crypto/esdm/Makefile index 404436de0aa2..0bf8d65dd5fa 100644 --- a/crypto/esdm/Makefile +++ b/crypto/esdm/Makefile @@ -11,3 +11,5 @@ obj-$(CONFIG_CRYPTO_ESDM_DRNG_KCAPI) += esdm_drng_kcapi.o obj-$(CONFIG_CRYPTO_ESDM_KERNEL_RNG) += esdm_es_krng.o obj-$(CONFIG_CRYPTO_ESDM_JENT) += esdm_es_jent.o + +obj-$(CONFIG_CRYPTO_ESDM_KCAPI_IF) += esdm_interface_kcapi.o diff --git a/crypto/esdm/esdm_drng_kcapi.c b/crypto/esdm/esdm_drng_kcapi.c index ae8d2be91b37..03135337196b 100644 --- a/crypto/esdm/esdm_drng_kcapi.c +++ b/crypto/esdm/esdm_drng_kcapi.c @@ -99,6 +99,7 @@ static void *esdm_kcapi_drng_alloc(u32 sec_strength) } if (!memcmp(drng_name, "stdrng", 6) || + !memcmp(drng_name, "esdm", 4) || !memcmp(drng_name, "jitterentropy_rng", 17)) { pr_err("Refusing to load the requested random number generator\n"); return ERR_PTR(-EINVAL); diff --git a/crypto/esdm/esdm_interface_kcapi.c b/crypto/esdm/esdm_interface_kcapi.c new file mode 100644 index 000000000000..f2968d83c991 --- /dev/null +++ b/crypto/esdm/esdm_interface_kcapi.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * ESDM interface with the RNG framework of the kernel crypto API + * + * Copyright (C) 2022, Stephan Mueller + */ + +#include +#include +#include + +#include "esdm_drng_mgr.h" +#include "esdm_es_aux.h" + +static int esdm_kcapi_if_init(struct crypto_tfm *tfm) +{ + return 0; +} + +static void esdm_kcapi_if_cleanup(struct crypto_tfm *tfm) { } + +static int esdm_kcapi_if_reseed(const u8 *src, unsigned int slen) +{ + int ret; + + if (!slen) + return 0; + + /* Insert caller-provided data without crediting entropy */ + ret = esdm_pool_insert_aux((u8 *)src, slen, 0); + if (ret) + return ret; + + /* Make sure the new data is immediately available to DRNG */ + esdm_drng_force_reseed(); + + return 0; +} + +static int esdm_kcapi_if_random(struct crypto_rng *tfm, + const u8 *src, unsigned int slen, + u8 *rdata, unsigned int dlen) +{ + int ret = esdm_kcapi_if_reseed(src, slen); + + if (!ret) + esdm_get_random_bytes_full(rdata, dlen); + + return ret; +} + +static int esdm_kcapi_if_reset(struct crypto_rng *tfm, + const u8 *seed, unsigned int slen) +{ + return esdm_kcapi_if_reseed(seed, slen); +} + +static struct rng_alg esdm_alg = { + .generate = esdm_kcapi_if_random, + .seed = esdm_kcapi_if_reset, + .seedsize = 0, + .base = { + .cra_name = "stdrng", + .cra_driver_name = "esdm", + .cra_priority = 500, + .cra_ctxsize = 0, + .cra_module = THIS_MODULE, + .cra_init = esdm_kcapi_if_init, + .cra_exit = esdm_kcapi_if_cleanup, + + } +}; + +static int __init esdm_kcapi_if_mod_init(void) +{ + return crypto_register_rng(&esdm_alg); +} + +static void __exit esdm_kcapi_if_mod_exit(void) +{ + crypto_unregister_rng(&esdm_alg); +} + +module_init(esdm_kcapi_if_mod_init); +module_exit(esdm_kcapi_if_mod_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Stephan Mueller "); +MODULE_DESCRIPTION("Entropy Source and DRNG Manager kernel crypto API RNG framework interface"); +MODULE_ALIAS_CRYPTO("esdm"); +MODULE_ALIAS_CRYPTO("stdrng"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 2ce698eb14b6..0865105f9377 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4878,6 +4878,14 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .akcipher = __VECS(ecrdsa_tv_template) } + }, { + .alg = "esdm", + .test = alg_test_null, +#ifdef CONFIG_CRYPTO_ESDM_OVERSAMPLE_ENTROPY_SOURCES + .fips_allowed = 1, +#else + .fips_allowed = 0, +#endif }, { .alg = "essiv(authenc(hmac(sha256),cbc(aes)),sha256)", .test = alg_test_aead,