diff mbox series

[v43,01/15] Linux Random Number Generator

Message ID 4641592.OV4Wx5bFTl@positron.chronox.de (mailing list archive)
State Not Applicable
Delegated to: Herbert Xu
Headers show
Series /dev/random - a new approach | expand

Commit Message

Stephan Mueller Nov. 21, 2021, 4:40 p.m. UTC
In an effort to provide a flexible implementation for a random number
generator that also delivers entropy during early boot time, allows
replacement of the deterministic random number generation mechanism,
implement the various components in separate code for easier
maintenance, and provide compliance to SP800-90[A|B|C], introduce
the Linux Random Number Generator (LRNG) framework.

The LRNG framework provides a flexible random number generator which
allows developers and system integrators to achieve different goals
by ensuring that each solution establishes a secure state.

The general design is as follows. Additional implementation details
are given in [1]. The LRNG consists of the following components:

1. The LRNG implements a DRNG. The DRNG always generates the
requested amount of output. When using the SP800-90A terminology
it operates without prediction resistance. The DRNG maintains a counter
of how many bytes were generated since last re-seed and a timer of the
elapsed time since last re-seed. If either the counter or the timer reaches
a threshold, the DRNG is seeded from the entropy pool.

In case the Linux kernel detects a NUMA system, one DRNG instance per NUMA
node is maintained.

2. The DRNG is seeded by concatenating the data from the following sources
   which deliver data and are credited with entropy if enabled:

(a) the output of the IRQ per-CPU entropy pools,

(b) the auxiliary entropy pool,

(c) the Jitter RNG if available and enabled, and

(d) the CPU-based noise source such as Intel RDSEED.

The entropy estimate of the data of all noise sources are added to
form the entropy estimate of the data used to seed the DRNG with.
The LRNG ensures, however, that the DRNG after seeding is at
maximum the security strength of the DRNG.

The LRNG is designed such that none of these noise sources can dominate
the other noise sources to provide seed data to the DRNG during due to
the following:

(a) During boot time, the amount of received entropy at the different
entropy sources are the trigger points to (re)seed the DRNG.

(b) At runtime, the available entropy from the slow noise source is
concatenated with a pre-defined amount of data from the fast noise
sources. In addition, each DRNG reseed operation triggers external
noise source providers to deliver one block of data.

3. The IRQ entropy pool collects noise data from interrupt timing.
Any data received by the LRNG from the interrupt noise sources is
inserted into a per-CPU entropy pool using a hash operation that can
be changed during runtime. Per default, SHA-256 is used.

 (a) When an interrupt occurs, the 8 least significant bits of the
 high-resolution time stamp divided by the greatest common divisor (GCD)
 is mixed into the per-CPU entropy pool. This time stamp is credited with
 heuristically implied entropy.

 (b) HID event data like the key stroke or the mouse coordinates are
 mixed into the per-CPU entropy pool. This data is not credited with
 entropy by the LRNG.

5. Any data provided from user space by either writing to /dev/random,
/dev/urandom or the IOCTL of RNDADDENTROPY on both device files
are always injected into the auxiliary pool. Also, device drivers may
provide data that is mixed into an auxiliary pool using the same hash
that is used to process the per-CPU entropy pool. This data is not
credited with entropy by the LRNG.

In addition, when a hardware random number generator covered by the
Linux kernel HW generator framework wants to deliver random numbers,
it is injected into the auxiliary pool as well. HW generator noise source
is handled separately from the other noise source due to the fact that
the HW generator framework may decide by itself when to deliver data
whereas the other noise sources always requested for data driven by the
LRNG operation. Similarly any user space provided data is inserted into
the entropy pool.

When seed data for the DRNG is to be generated, all per-CPU
entropy pools are hashed. The message digest forms the data used for
seeding the DRNG.

To speed up the interrupt handling code of the LRNG, the time stamp
collected for an interrupt event is divided by the greatest common
divisor to eliminate fixed low bits and then truncated to the 8 least
significant bits. 1024 truncated time stamps are concatenated and then
jointly inserted into the per-CPU entropy pool. During boot time,
until the fully seeded stage is reached, each time stamp with its
32 least significant bits is are concatenated. When 1024/32 = 32 such
events are received, they are injected into the per-CPU entropy pool.

The LRNG allows the DRNG mechanism to be changed at runtime. Per default,
a ChaCha20-based DRNG is used. The ChaCha20-DRNG implemented for the
LRNG is also provided as a stand-alone user space deterministic random
number generator. The LRNG also offers an SP800-90A DRBG based on the
Linux kernel crypto API DRBG implementation.

The processing of entropic data from the noise source before injecting
them into the DRNG is performed with the following mathematical
operations:

1. Truncation: The received time stamps divided by the GCD are
truncated to 8 least significant bits (or 32 least significant bits
during boot time)

2. Concatenation: The received and truncated time stamps as well as
auxiliary 32 bit words are concatenated to fill the per-CPU data
array that is capable of holding 64 8-bit words.

3. Hashing: A set of concatenated time stamp data received from the
interrupts are hashed together with the current existing per-CPU
entropy pool state. The resulting message digest is the new per-CPU
entropy pool state.

4. Hashing: When new data is added to the auxiliary pool, the data
is hashed together with the auxiliary pool to form a new auxiliary
pool state.

5. Hashing: A message digest of all per-CPU entropy pools and the
is calculated which forms the new auxiliary pool state.

6. Truncation: The most-significant bits (MSB) defined by the
requested number of bits (commonly equal to the security strength
of the DRBG) or the entropy available transported with the buffer
(which is the minimum of the message digest size and the available
entropy in all entropy pools and the auxiliary pool), whatever is
smaller, are obtained from the slow noise source output buffer.

7. Concatenation: The temporary seed buffer used to seed the DRNG
is a concatenation of the slow noise source buffer, the Jitter RNG
output, the CPU noise source output, and the current time.

The DRNG always tries to seed itself with 256 bits of entropy, except
during boot. In any case, if the noise sources cannot deliver that
amount, the available entropy is used and the DRNG keeps track on how
much entropy it was seeded with. The entropy implied by the LRNG
available in the entropy pool may be too conservative. To ensure
that during boot time all available entropy from the entropy pool is
transferred to the DRNG, the hash_df function always generates 256
data bits during boot to seed the DRNG. During boot, the DRNG is
seeded as follows:

1. The DRNG is reseeded from the entropy sources if the entropy sources
collectively have at least 32 bits of entropy. The goal of this step is
to ensure that the DRNG receives some initial entropy as early as
possible.

2. The DRNG is reseeded from the entropy sources if all entropy sources
collectively can provide at least 128 bits of entropy.

3. The DRNG is reseeded from the entropy sources if all entropy sources
collectively can provide at least 256 bits.

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.

Before the DRNG is seeded with 256 bits of entropy in step 3,
requests of random data from /dev/random and the getrandom system
call are not processed.

The reseeding of the DRNG always ensures that all entropy sources
collectively can deliver at least 128 entropy bits during runtime once
the DRNG is fully seeded.

The DRNG operates as deterministic random number generator with the
following properties:

* The maximum number of random bytes that can be generated with one
DRNG generate operation is limited to 4096 bytes. When longer random
numbers are requested, multiple DRNG generate operations are performed.
The ChaCha20 DRNG as well as the SP800-90A DRBGs implement an update of
their state after completing a generate request for backtracking
resistance.

* The DRNG is reseeded with whatever entropy is available -
in the worst case where no additional entropy can be provided by the
entropy sources, the DRNG is not re-seeded and continues its operation
to try to reseed again after again the expiry of one of these thresholds:

 - If the last reseeding of the DRNG is more than 600 seconds
   ago, or

 - 2^20 DRNG generate operations are performed, whatever comes first, or

 - the DRNG is forced to reseed before the next generation of
   random numbers if data has been injected into the LRNG by writing data
   into /dev/random or /dev/urandom.

 - If the DRNG was not successfully reseeded after 2^30 generate requests,
   the DRNG reverts back to an unseeded stage implying that the blocking
   interfaces of /dev/random and getrandom will block again.

The chosen values prevent high-volume requests from user space to cause
frequent reseeding operations which drag down the performance of the
DRNG.

With the automatic reseeding after 600 seconds, the LRNG is triggered
to reseed itself before the first request after a suspend that put the
hardware to sleep for longer than 600 seconds.

To support smaller devices including IoT environments, this patch
allows reducing the runtime memory footprint of the LRNG at compile
time by selecting smaller collection data sizes.

When selecting the compilation of a kernel for a small environment,
prevent the allocation of a buffer up to 4096 bytes to serve user space
requests. In this case, the stack variable of 64 bytes is used to serve
all user space requests.

The LRNG has the following properties:

* internal noise source: interrupts timing with fast boot time seeding

* high performance of interrupt handling code: The LRNG impact on the
interrupt handling has been reduced to a minimum. On one example
system, the LRNG interrupt handling code in its fastest configuration
executes within an average 55 cycles whereas the existing
/dev/random on the same device takes about 97 cycles when measuring
the execution time of add_interrupt_randomness().

* use of almost never contended lock for hashing operation to collect
  raw entropy supporting concurrency-free use of massive parallel
  systems - worst case rate of contention is the number of DRNG
  reseeds, usually: number of NUMA nodes contentions per 5 minutes.

* use of standalone ChaCha20 based RNG with the option to use a
  different DRNG selectable at compile time

* instantiate one DRNG per NUMA node

* support for runtime switchable output DRNGs

* use of runtime-switchable hash for conditioning implementation
following widely accepted approach

* compile-time selectable collection size

* support of small systems by allowing the reduction of the
runtime memory needs

Further details including the rationale for the design choices and
properties of the LRNG together with testing is provided at [1].
In addition, the documentation explains the conducted regression
tests to verify that the LRNG is API and ABI compatible with the
existing /dev/random implementation.

Note, this patch covers the entropy sources manager, the API
implementation, the built-in ChaCha20 DRNG and the auxiliary entropy
pool.

[1] https://www.chronox.de/lrng.html

CC: Torsten Duwe <duwe@lst.de>
CC: "Eric W. Biederman" <ebiederm@xmission.com>
CC: "Alexander E. Patrakov" <patrakov@gmail.com>
CC: "Ahmed S. Darwish" <darwish.07@gmail.com>
CC: "Theodore Y. Ts'o" <tytso@mit.edu>
CC: Willy Tarreau <w@1wt.eu>
CC: Matthew Garrett <mjg59@srcf.ucam.org>
CC: Vito Caputo <vcaputo@pengaru.com>
CC: Andreas Dilger <adilger.kernel@dilger.ca>
CC: Jan Kara <jack@suse.cz>
CC: Ray Strode <rstrode@redhat.com>
CC: William Jon McCann <mccann@jhu.edu>
CC: zhangjs <zachary@baishancloud.com>
CC: Andy Lutomirski <luto@kernel.org>
CC: Florian Weimer <fweimer@redhat.com>
CC: Lennart Poettering <mzxreary@0pointer.de>
CC: Nicolai Stange <nstange@suse.de>
Reviewed-by: Alexander Lobakin <alobakin@pm.me>
Tested-by: Alexander Lobakin <alobakin@pm.me>
Mathematical aspects Reviewed-by: "Peter, Matthias" <matthias.peter@bsi.bund.de>
Reviewed-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>
Reviewed-by: Roman Drahtmueller <draht@schaltsekun.de>
Tested-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>
Tested-by: Neil Horman <nhorman@redhat.com>
Tested-by: Jirka Hladky <jhladky@redhat.com>
Reviewed-by: Jirka Hladky <jhladky@redhat.com>
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 MAINTAINERS                         |   7 +
 drivers/char/Kconfig                |   2 +
 drivers/char/Makefile               |   9 +-
 drivers/char/lrng/Kconfig           |  58 +++
 drivers/char/lrng/Makefile          |   8 +
 drivers/char/lrng/lrng_aux.c        | 136 ++++++
 drivers/char/lrng/lrng_chacha20.c   | 321 ++++++++++++++
 drivers/char/lrng/lrng_chacha20.h   |  25 ++
 drivers/char/lrng/lrng_drng.c       | 451 +++++++++++++++++++
 drivers/char/lrng/lrng_es_aux.c     | 294 +++++++++++++
 drivers/char/lrng/lrng_es_mgr.c     | 373 ++++++++++++++++
 drivers/char/lrng/lrng_interfaces.c | 656 ++++++++++++++++++++++++++++
 drivers/char/lrng/lrng_internal.h   | 485 ++++++++++++++++++++
 include/linux/lrng.h                |  81 ++++
 14 files changed, 2905 insertions(+), 1 deletion(-)
 create mode 100644 drivers/char/lrng/Kconfig
 create mode 100644 drivers/char/lrng/Makefile
 create mode 100644 drivers/char/lrng/lrng_aux.c
 create mode 100644 drivers/char/lrng/lrng_chacha20.c
 create mode 100644 drivers/char/lrng/lrng_chacha20.h
 create mode 100644 drivers/char/lrng/lrng_drng.c
 create mode 100644 drivers/char/lrng/lrng_es_aux.c
 create mode 100644 drivers/char/lrng/lrng_es_mgr.c
 create mode 100644 drivers/char/lrng/lrng_interfaces.c
 create mode 100644 drivers/char/lrng/lrng_internal.h
 create mode 100644 include/linux/lrng.h

Comments

Joe Perches Nov. 21, 2021, 5:23 p.m. UTC | #1
On Sun, 2021-11-21 at 17:40 +0100, Stephan Müller wrote:
> In an effort to provide a flexible implementation for a random number
> generator that also delivers entropy during early boot time, allows
> replacement of the deterministic random number generation mechanism,
> implement the various components in separate code for easier
> maintenance, and provide compliance to SP800-90[A|B|C], introduce
> the Linux Random Number Generator (LRNG) framework.
[]
> diff --git a/MAINTAINERS b/MAINTAINERS
[]
> @@ -10817,6 +10817,13 @@ F:	Documentation/litmus-tests/
>  F:	Documentation/memory-barriers.txt
>  F:	tools/memory-model/
>  
> +LINUX RANDOM NUMBER GENERATOR (LRNG) DRIVER
> +M:	Stephan Mueller <smueller@chronox.de>
> +S:	Maintained
> +W:	https://www.chronox.de/lrng.html
> +F:	drivers/char/lrng/*

Are you specifically intending _not_ to maintain any files in
any possible subdirectories of this directory?

If not, this should be

F:	drivers/char/lrng/

> +F:	include/linux/lrng.h
> +

Trivia and additionally: 

Maybe run the patch series through scripts/checkpatch.pl --strict and
see if you want to change anything.
Jason A. Donenfeld Nov. 21, 2021, 10:42 p.m. UTC | #2
Hi Stephan,

You've posted it again, and yet I still believe this is not the
correct design or direction. I do not think the explicit goal of
extended configurability ("flexibility") or the explicit goal of being
FIPS compatible represent good directions, and I think this introduces
new problems rather than solving any existing ones. While there are
ways the current RNG could or even should be improved -- or rewritten
-- this approach is still not that, no matter how many times you post
it. It is almost as though you hope this somehow gets accepted through
a general apathy that might develop by the 1000th revision, when
cranks like me and others no longer have the motivation to keep
responding with the same thing. But here we are again.

My own experience pushing something that didn't have substantial
enough buy-in from existing maintainers (the Zinc crypto library)
ultimately led me to stop pushing in order to not alienate folks, step
back, and listen a bit. Eventually somebody reached out to work with
me (Ard) and we submitted a good compromise collaboration that we all
generally felt better about. In this case, your cryptographic design
tastes are sufficiently divergent from mine that I'm not sure how far
such a thing would go, but it also seems to me that continually
pushing the same thing over and over isn't winning you any points here
either. Submission by attrition is not an outcome anybody should want.

Sorry to be so blunt. It's just that my, "I don't like this" is the
same as it was the last time, and I'm not aware of anything
significant in that area changing this time.

Jason
Stephan Mueller Nov. 22, 2021, 5:34 a.m. UTC | #3
Am Sonntag, 21. November 2021, 23:42:33 CET schrieb Jason A. Donenfeld:

Hi Jason,

> Hi Stephan,
> 
> You've posted it again, and yet I still believe this is not the
> correct design or direction. I do not think the explicit goal of
> extended configurability ("flexibility") or the explicit goal of being
> FIPS compatible represent good directions, and I think this introduces
> new problems rather than solving any existing ones.

The members from the Linux distributions that are on copy on this may tell you 
a different story. They all developed their own downstream patches to somehow 
add the flexibility that is needed for them. So, we have a great deal of 
fragmentation at the resting-foundation of Linux cryptography.

Then the implementation of the flexibility in the LRNG is done such that 
irrespecitve of which options are selected, the LRNG operates always at a 
secure state.


> While there are
> ways the current RNG could or even should be improved -- or rewritten
> -- this approach is still not that, no matter how many times you post
> it. It is almost as though you hope this somehow gets accepted through
> a general apathy that might develop by the 1000th revision, when
> cranks like me and others no longer have the motivation to keep
> responding with the same thing. But here we are again.
> 
> My own experience pushing something that didn't have substantial
> enough buy-in from existing maintainers (the Zinc crypto library)
> ultimately led me to stop pushing in order to not alienate folks, step
> back, and listen a bit. Eventually somebody reached out to work with
> me (Ard) and we submitted a good compromise collaboration that we all
> generally felt better about. In this case, your cryptographic design
> tastes are sufficiently divergent from mine that I'm not sure how far
> such a thing would go, but it also seems to me that continually
> pushing the same thing over and over isn't winning you any points here
> either. Submission by attrition is not an outcome anybody should want.
> 
> Sorry to be so blunt. It's just that my, "I don't like this" is the
> same as it was the last time, and I'm not aware of anything
> significant in that area changing this time.

I have received numerous technical comments from various Linux developers. All 
were integrated. None of these comments hinted to requestes in changing the 
design.

That said, even when you refer to already suggested architectural differnces, 
I yet have to first receive them,
> 
> Jason


Ciao
Stephan
Greg KH Nov. 22, 2021, 6:02 a.m. UTC | #4
On Mon, Nov 22, 2021 at 06:34:43AM +0100, Stephan Mueller wrote:
> Am Sonntag, 21. November 2021, 23:42:33 CET schrieb Jason A. Donenfeld:
> 
> Hi Jason,
> 
> > Hi Stephan,
> > 
> > You've posted it again, and yet I still believe this is not the
> > correct design or direction. I do not think the explicit goal of
> > extended configurability ("flexibility") or the explicit goal of being
> > FIPS compatible represent good directions, and I think this introduces
> > new problems rather than solving any existing ones.
> 
> The members from the Linux distributions that are on copy on this may tell you 
> a different story. They all developed their own downstream patches to somehow 
> add the flexibility that is needed for them. So, we have a great deal of 
> fragmentation at the resting-foundation of Linux cryptography.

What distros specifically have patches in their kernels that do
different things to the random code path?  Do you have pointers to those
patches anywhere?  Why have the distros not submitted their changes
upstream?

thanks,

greg k-h
Stephan Mueller Nov. 22, 2021, 6:42 a.m. UTC | #5
Am Montag, 22. November 2021, 07:02:14 CET schrieb Greg Kroah-Hartman:

Hi Greg,

> On Mon, Nov 22, 2021 at 06:34:43AM +0100, Stephan Mueller wrote:
> > Am Sonntag, 21. November 2021, 23:42:33 CET schrieb Jason A. Donenfeld:
> > 
> > Hi Jason,
> > 
> > > Hi Stephan,
> > > 
> > > You've posted it again, and yet I still believe this is not the
> > > correct design or direction. I do not think the explicit goal of
> > > extended configurability ("flexibility") or the explicit goal of being
> > > FIPS compatible represent good directions, and I think this introduces
> > > new problems rather than solving any existing ones.
> > 
> > The members from the Linux distributions that are on copy on this may tell
> > you a different story. They all developed their own downstream patches to
> > somehow add the flexibility that is needed for them. So, we have a great
> > deal of fragmentation at the resting-foundation of Linux cryptography.
> 
> What distros specifically have patches in their kernels that do
> different things to the random code path?  Do you have pointers to those
> patches anywhere?  Why have the distros not submitted their changes
> upstream?

I will leave the representatives from the distros to chime in and point to 
these patches.

Yet, these changes are commonly a band-aid only that have some additional 
drawbacks. Bottom line, there is no appropriate way with the current code to 
allow vendors what they want to achieve. One hint to what changes vendors are 
attempting can be found in [1] slide 20.

[1] https://www.chronox.de/lrng/doc/lrng_presentation_v43.pdf
> 
> thanks,
> 
> greg k-h


Ciao
Stephan
Greg KH Nov. 22, 2021, 6:55 a.m. UTC | #6
On Mon, Nov 22, 2021 at 07:42:02AM +0100, Stephan Mueller wrote:
> Am Montag, 22. November 2021, 07:02:14 CET schrieb Greg Kroah-Hartman:
> 
> Hi Greg,
> 
> > On Mon, Nov 22, 2021 at 06:34:43AM +0100, Stephan Mueller wrote:
> > > Am Sonntag, 21. November 2021, 23:42:33 CET schrieb Jason A. Donenfeld:
> > > 
> > > Hi Jason,
> > > 
> > > > Hi Stephan,
> > > > 
> > > > You've posted it again, and yet I still believe this is not the
> > > > correct design or direction. I do not think the explicit goal of
> > > > extended configurability ("flexibility") or the explicit goal of being
> > > > FIPS compatible represent good directions, and I think this introduces
> > > > new problems rather than solving any existing ones.
> > > 
> > > The members from the Linux distributions that are on copy on this may tell
> > > you a different story. They all developed their own downstream patches to
> > > somehow add the flexibility that is needed for them. So, we have a great
> > > deal of fragmentation at the resting-foundation of Linux cryptography.
> > 
> > What distros specifically have patches in their kernels that do
> > different things to the random code path?  Do you have pointers to those
> > patches anywhere?  Why have the distros not submitted their changes
> > upstream?
> 
> I will leave the representatives from the distros to chime in and point to 
> these patches.

Then why not work with the distros to get these changes merged into the
kernel tree?  They know that keeping things out-of-the-tree costs them
time and money, so why are they keeping them there?

I recommend getting the distros to chime in on what their requirements
are for the random code would probably be best as they are the ones that
take on the "random fips requirement of the day" more than anyone else.

> Yet, these changes are commonly a band-aid only that have some additional 
> drawbacks. Bottom line, there is no appropriate way with the current code to 
> allow vendors what they want to achieve. One hint to what changes vendors are 
> attempting can be found in [1] slide 20.

What exactly do vendors "want to achieve"?  Where are they saying this?

> [1] https://www.chronox.de/lrng/doc/lrng_presentation_v43.pdf

I see nothing on that slide that mentions actual requirements other than
"the current code does not match this random government regulation".

Please provide valid reasons, from distros.

thanks,

greg k-h
kernel test robot Nov. 22, 2021, 10:33 a.m. UTC | #7
Hi "Stephan,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on char-misc/char-misc-testing]
[also build test ERROR on herbert-cryptodev-2.6/master herbert-crypto-2.6/master v5.16-rc2 next-20211118]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Stephan-M-ller/dev-random-a-new-approach/20211122-005114
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git f4d77525679e289d4976ca03b620ac4cc5403205
config: mips-allmodconfig (attached as .config)
compiler: mips-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/dccd6203b45303ba2985de5a22238809655b48c4
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Stephan-M-ller/dev-random-a-new-approach/20211122-005114
        git checkout dccd6203b45303ba2985de5a22238809655b48c4
        # save the attached .config to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=mips SHELL=/bin/bash drivers/char/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/char/lrng/lrng_chacha20.c:32:8: error: structure variable 'chacha20' with 'latent_entropy' attribute has a non-integer field 'block'
      32 | struct chacha20_state chacha20 __latent_entropy;
         |        ^~~~~~~~~~~~~~


vim +32 drivers/char/lrng/lrng_chacha20.c

    26	
    27	/*
    28	 * Have a static memory blocks for the ChaCha20 DRNG instance to avoid calling
    29	 * kmalloc too early in the boot cycle. For subsequent allocation requests,
    30	 * such as per-NUMA-node DRNG instances, kmalloc will be used.
    31	 */
  > 32	struct chacha20_state chacha20 __latent_entropy;
    33	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Stephan Mueller Nov. 22, 2021, 11:47 a.m. UTC | #8
Am Montag, 22. November 2021, 11:33:26 CET schrieb kernel test robot:

Hi,

> All errors (new ones prefixed by >>):
> >> drivers/char/lrng/lrng_chacha20.c:32:8: error: structure variable
> >> 'chacha20' with 'latent_entropy' attribute has a non-integer field
> >> 'block'
>       32 | struct chacha20_state chacha20 __latent_entropy;
> 
>          |        ^~~~~~~~~~~~~~
> 
> vim +32 drivers/char/lrng/lrng_chacha20.c

Thanks for the notification.

I think this is a false-positive discussed before. __latent_entropy is 
seemingly allowed for an entire linear buffer as seen in the declaration of 
the variable input_pool_data in driver/char/random.c which is an array of u32.

The struct chacha20_state is a linear buffer of u32 words. 

struct chacha20_block {
        u32 constants[4];
        union {
                u32 u[CHACHA_KEY_SIZE_WORDS];
                u8  b[CHACHA_KEY_SIZE];
        } key;
        u32 counter;
        u32 nonce[3];
};

Therefore it should be identical to the aforementioned example. The 
__latent_entropy marker therefore seems to be appropriate for this structure.

Ciao
Stephan
Simo Sorce Nov. 22, 2021, 2:59 p.m. UTC | #9
Jason,
have you previously produced a list of reasoned concerns with this
patchset and direction?

This specific email is not really useful to me to understand the
concerns as it does not contain actionable suggestion or critique.

I personally find the direction fine, and with my distribution hat on I
can say that FIPS is essential for us and any design must include an
option to be FIPS certifiable.

As NIST keeps improving their testing capabilities and rigorous
cryptographic design of the CSPRNGs as well as entropy sources the
kernel must also adapt.

Stephan is providing a path forward, and I haven't seen any other
proposal, let alone code, that provide improvements in this area.
I am pretty sure the design can be improved if there is detailed and
actionable feedback on what to change.

I hope the path forward can be one of collaboration rather then mere
opposition.

HTH,
Simo.

On Sun, 2021-11-21 at 23:42 +0100, Jason A. Donenfeld wrote:
> Hi Stephan,
> 
> You've posted it again, and yet I still believe this is not the
> correct design or direction. I do not think the explicit goal of
> extended configurability ("flexibility") or the explicit goal of being
> FIPS compatible represent good directions, and I think this introduces
> new problems rather than solving any existing ones. While there are
> ways the current RNG could or even should be improved -- or rewritten
> -- this approach is still not that, no matter how many times you post
> it. It is almost as though you hope this somehow gets accepted through
> a general apathy that might develop by the 1000th revision, when
> cranks like me and others no longer have the motivation to keep
> responding with the same thing. But here we are again.
> 
> My own experience pushing something that didn't have substantial
> enough buy-in from existing maintainers (the Zinc crypto library)
> ultimately led me to stop pushing in order to not alienate folks, step
> back, and listen a bit. Eventually somebody reached out to work with
> me (Ard) and we submitted a good compromise collaboration that we all
> generally felt better about. In this case, your cryptographic design
> tastes are sufficiently divergent from mine that I'm not sure how far
> such a thing would go, but it also seems to me that continually
> pushing the same thing over and over isn't winning you any points here
> either. Submission by attrition is not an outcome anybody should want.
> 
> Sorry to be so blunt. It's just that my, "I don't like this" is the
> same as it was the last time, and I'm not aware of anything
> significant in that area changing this time.
> 
> Jason
>
Simo Sorce Nov. 22, 2021, 3:09 p.m. UTC | #10
On Mon, 2021-11-22 at 07:55 +0100, Greg Kroah-Hartman wrote:
> On Mon, Nov 22, 2021 at 07:42:02AM +0100, Stephan Mueller wrote:
> > Am Montag, 22. November 2021, 07:02:14 CET schrieb Greg Kroah-Hartman:
> > 
> > Hi Greg,
> > 
> > > On Mon, Nov 22, 2021 at 06:34:43AM +0100, Stephan Mueller wrote:
> > > > Am Sonntag, 21. November 2021, 23:42:33 CET schrieb Jason A. Donenfeld:
> > > > 
> > > > Hi Jason,
> > > > 
> > > > > Hi Stephan,
> > > > > 
> > > > > You've posted it again, and yet I still believe this is not the
> > > > > correct design or direction. I do not think the explicit goal of
> > > > > extended configurability ("flexibility") or the explicit goal of being
> > > > > FIPS compatible represent good directions, and I think this introduces
> > > > > new problems rather than solving any existing ones.
> > > > 
> > > > The members from the Linux distributions that are on copy on this may tell
> > > > you a different story. They all developed their own downstream patches to
> > > > somehow add the flexibility that is needed for them. So, we have a great
> > > > deal of fragmentation at the resting-foundation of Linux cryptography.
> > > 
> > > What distros specifically have patches in their kernels that do
> > > different things to the random code path?  Do you have pointers to those
> > > patches anywhere?  Why have the distros not submitted their changes
> > > upstream?
> > 
> > I will leave the representatives from the distros to chime in and point to 
> > these patches.
> 
> Then why not work with the distros to get these changes merged into the
> kernel tree?  They know that keeping things out-of-the-tree costs them
> time and money, so why are they keeping them there?

I can speak for my distro.
We have not proposed them because they are hacks, we know they are
hacks, and we know they are not the long term solution.
Yet we have no better way (in our products, today) so far to deal with
these issues because what is needed is an effort like LRNG (does not
have to be this specific implementation), because hacks will not cut it
in the long term.

> I recommend getting the distros to chime in on what their requirements
> are for the random code would probably be best as they are the ones that
> take on the "random fips requirement of the day" more than anyone else.

Greg,
I think you can takes Stephan's introduction and supporting material
from this patchset to see what are the requirements. These patches have
not been maturing in a void, but Stephan basically distilled
discussions between multiple vendors as well as regulatory bodies (as
you can see he has reviews from BSI and NIST requirements are also
fully represented here).

He addressed a few aspects I can mention but are not the only ones:
performance (esp on NUMA systems), not blocking at boot due to lack of
entropy, NIST/BSI conformance, flexibility so that future regulatory
requirements can be easily integrated and upstreamed.


> > Yet, these changes are commonly a band-aid only that have some additional 
> > drawbacks. Bottom line, there is no appropriate way with the current code to 
> > allow vendors what they want to achieve. One hint to what changes vendors are 
> > attempting can be found in [1] slide 20.
> 
> What exactly do vendors "want to achieve"?  Where are they saying this?
> 
> > [1] https://www.chronox.de/lrng/doc/lrng_presentation_v43.pdf
> 
> I see nothing on that slide that mentions actual requirements other than
> "the current code does not match this random government regulation".
> 
> Please provide valid reasons, from distros.
> 

Please let me know in what format you want to see these requirements,
and I will work with other to provide them.

Simo.


> thanks,
> 
> greg k-h
>
John Haxby Nov. 22, 2021, 4:56 p.m. UTC | #11
> On 22 Nov 2021, at 06:02, Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
> 
> On Mon, Nov 22, 2021 at 06:34:43AM +0100, Stephan Mueller wrote:
>> Am Sonntag, 21. November 2021, 23:42:33 CET schrieb Jason A. Donenfeld:
>> 
>> Hi Jason,
>> 
>>> Hi Stephan,
>>> 
>>> You've posted it again, and yet I still believe this is not the
>>> correct design or direction. I do not think the explicit goal of
>>> extended configurability ("flexibility") or the explicit goal of being
>>> FIPS compatible represent good directions, and I think this introduces
>>> new problems rather than solving any existing ones.
>> 
>> The members from the Linux distributions that are on copy on this may tell you
>> a different story. They all developed their own downstream patches to somehow
>> add the flexibility that is needed for them. So, we have a great deal of
>> fragmentation at the resting-foundation of Linux cryptography.
> 
> What distros specifically have patches in their kernels that do
> different things to the random code path?  Do you have pointers to those
> patches anywhere?  Why have the distros not submitted their changes
> upstream?
> 

We (Oracle) are carrying such a patch at the moment.  We want this patch to be a temporary workaround simply to get FIPS certification in the current kernel.

We're carrying this patch simply because the certification requirements changed and this was the quickest and easiest way to workaround today's problem.  It won't fix tomorrow's problem and next time we, and others, attempt FIPS certification then we, and others, will need a different /dev/random because neither the old one nor our quick and dirty workaround will actually be acceptable.

The commit we're carrying at the moment is here: https://github.com/oracle/linux-uek/commit/5ebe83413c7573d566e581461bc95f9f139c5d4d -- you'll notice that we have a different RNG in fips mode compared to normal mode.

We really don't want to have to work out a new hack for future FIPS certifications and I'm sure no other distros want to do that either.

Personally, I'd far rather have any fips-certifiable /dev/random drivers be in mainline where everyone gets the same thing.  I don't like carrying out-of-tree patches like this, it's not healthy.

jch


> thanks,
> 
> greg k-h
Jeffrey Walton Nov. 22, 2021, 9:06 p.m. UTC | #12
On Mon, Nov 22, 2021 at 10:10 AM Simo Sorce <simo@redhat.com> wrote:
>
> On Mon, 2021-11-22 at 07:55 +0100, Greg Kroah-Hartman wrote:
> > On Mon, Nov 22, 2021 at 07:42:02AM +0100, Stephan Mueller wrote:
> > > ...
> > > I will leave the representatives from the distros to chime in and point to
> > > these patches.
> >
> > Then why not work with the distros to get these changes merged into the
> > kernel tree?  They know that keeping things out-of-the-tree costs them
> > time and money, so why are they keeping them there?
>
> I can speak for my distro.
> We have not proposed them because they are hacks, we know they are
> hacks, and we know they are not the long term solution.
> Yet we have no better way (in our products, today) so far to deal with
> these issues because what is needed is an effort like LRNG (does not
> have to be this specific implementation), because hacks will not cut it
> in the long term.

Kernel support for FIPS validated crypto would be very useful, IMHO.

Currently most folks I know and consult with use CentOS because CentOS
is free and includes the FIPS canister for OpenSSL. Several folks I
know and consult with don't have a solution because they use Debian
derivatives, like Ubuntu. They use Ubuntu because Ubuntu offers the
image processing packages they need out of the box.

Moving the validated crypto into the kernel would be useful since all
distros can provide it without the need for one-off patches.

What I am less clear about.... NIST is only one standard body, and not
everyone trusts the US. There are other bodies that should probably be
represented, like KISA. So the big question becomes, how does the
kernel offer "approved" crypto for different consumers? (where
"approved" means blessed by some agency like NIST or KISA).

Jeff
Stephan Mueller Nov. 23, 2021, 5:38 a.m. UTC | #13
Am Montag, 22. November 2021, 22:06:55 CET schrieb Jeffrey Walton:

Hi Jeffrey,

> On Mon, Nov 22, 2021 at 10:10 AM Simo Sorce <simo@redhat.com> wrote:
> > On Mon, 2021-11-22 at 07:55 +0100, Greg Kroah-Hartman wrote:
> > > On Mon, Nov 22, 2021 at 07:42:02AM +0100, Stephan Mueller wrote:
> > > > ...
> > > > I will leave the representatives from the distros to chime in and
> > > > point to
> > > > these patches.
> > > 
> > > Then why not work with the distros to get these changes merged into the
> > > kernel tree?  They know that keeping things out-of-the-tree costs them
> > > time and money, so why are they keeping them there?
> > 
> > I can speak for my distro.
> > We have not proposed them because they are hacks, we know they are
> > hacks, and we know they are not the long term solution.
> > Yet we have no better way (in our products, today) so far to deal with
> > these issues because what is needed is an effort like LRNG (does not
> > have to be this specific implementation), because hacks will not cut it
> > in the long term.
> 
> Kernel support for FIPS validated crypto would be very useful, IMHO.
> 
> Currently most folks I know and consult with use CentOS because CentOS
> is free and includes the FIPS canister for OpenSSL. Several folks I
> know and consult with don't have a solution because they use Debian
> derivatives, like Ubuntu. They use Ubuntu because Ubuntu offers the
> image processing packages they need out of the box.
> 
> Moving the validated crypto into the kernel would be useful since all
> distros can provide it without the need for one-off patches.
> 
> What I am less clear about.... NIST is only one standard body, and not
> everyone trusts the US. There are other bodies that should probably be
> represented, like KISA. So the big question becomes, how does the
> kernel offer "approved" crypto for different consumers? (where
> "approved" means blessed by some agency like NIST or KISA).

IMHO that is where the flexibility of the LRNG comes in. I am currently in 
discussion with the German BSI on their requirements and these requirements 
can be covered by a few extra lines since it only affects a different initial 
seeding of the DRNG.

In any case, the LRNG supports other approaches by:

- select one or more entropy sources (or provide one from external) that are 
considered appropriate

- if needed, adjust the initial seeding operation

- if needed, adjust the crypto primitives that are in use.

Ciao
Stephan
> 
> Jeff


Ciao
Stephan
Chen, Rong A Nov. 25, 2021, 5:25 a.m. UTC | #14
On 11/22/2021 7:47 PM, Stephan Mueller wrote:
> Am Montag, 22. November 2021, 11:33:26 CET schrieb kernel test robot:
> 
> Hi,
> 
>> All errors (new ones prefixed by >>):
>>>> drivers/char/lrng/lrng_chacha20.c:32:8: error: structure variable
>>>> 'chacha20' with 'latent_entropy' attribute has a non-integer field
>>>> 'block'
>>        32 | struct chacha20_state chacha20 __latent_entropy;
>>
>>           |        ^~~~~~~~~~~~~~
>>
>> vim +32 drivers/char/lrng/lrng_chacha20.c
> 
> Thanks for the notification.
> 
> I think this is a false-positive discussed before. __latent_entropy is
> seemingly allowed for an entire linear buffer as seen in the declaration of
> the variable input_pool_data in driver/char/random.c which is an array of u32.
> 
> The struct chacha20_state is a linear buffer of u32 words.
> 
> struct chacha20_block {
>          u32 constants[4];
>          union {
>                  u32 u[CHACHA_KEY_SIZE_WORDS];
>                  u8  b[CHACHA_KEY_SIZE];
>          } key;
>          u32 counter;
>          u32 nonce[3];
> };
> 
> Therefore it should be identical to the aforementioned example. The
> __latent_entropy marker therefore seems to be appropriate for this structure.
> 
> Ciao
> Stephan
> 
> 

Hi Stephan,

Thanks for the explanation, we'll add the error to the ignore list.

Best Regards,
Rong Chen
Greg KH Nov. 26, 2021, 3:40 p.m. UTC | #15
On Mon, Nov 22, 2021 at 04:56:24PM +0000, John Haxby wrote:
> 
> 
> > On 22 Nov 2021, at 06:02, Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
> > 
> > On Mon, Nov 22, 2021 at 06:34:43AM +0100, Stephan Mueller wrote:
> >> Am Sonntag, 21. November 2021, 23:42:33 CET schrieb Jason A. Donenfeld:
> >> 
> >> Hi Jason,
> >> 
> >>> Hi Stephan,
> >>> 
> >>> You've posted it again, and yet I still believe this is not the
> >>> correct design or direction. I do not think the explicit goal of
> >>> extended configurability ("flexibility") or the explicit goal of being
> >>> FIPS compatible represent good directions, and I think this introduces
> >>> new problems rather than solving any existing ones.
> >> 
> >> The members from the Linux distributions that are on copy on this may tell you
> >> a different story. They all developed their own downstream patches to somehow
> >> add the flexibility that is needed for them. So, we have a great deal of
> >> fragmentation at the resting-foundation of Linux cryptography.
> > 
> > What distros specifically have patches in their kernels that do
> > different things to the random code path?  Do you have pointers to those
> > patches anywhere?  Why have the distros not submitted their changes
> > upstream?
> > 
> 
> We (Oracle) are carrying such a patch at the moment.  We want this
> patch to be a temporary workaround simply to get FIPS certification in
> the current kernel.
> 
> We're carrying this patch simply because the certification
> requirements changed and this was the quickest and easiest way to
> workaround today's problem.  It won't fix tomorrow's problem and next
> time we, and others, attempt FIPS certification then we, and others,
> will need a different /dev/random because neither the old one nor our
> quick and dirty workaround will actually be acceptable.
> 
> The commit we're carrying at the moment is here:
> https://github.com/oracle/linux-uek/commit/5ebe83413c7573d566e581461bc95f9f139c5d4d
> -- you'll notice that we have a different RNG in fips mode compared to
> normal mode.

Now that's a much smaller and simpler and easier to understand change,
compared to "rewrite the whole random number generator".

Why not work to get FIPS support merged properly upstream?  I know there
are many people working to get FIPS certification, and while the
requirements seem to constantly change and are vague and random, it
would be great to stop duplicating all of this effort all the time.

> We really don't want to have to work out a new hack for future FIPS
> certifications and I'm sure no other distros want to do that either.

Great, why not work to solve this within what we have?

Remember, wholesale replacement is NOT how kernel development happens.
It's incremental evolution based on external need.  It's not a "kill the
existing code and replace it from scratch" process.

> Personally, I'd far rather have any fips-certifiable /dev/random
> drivers be in mainline where everyone gets the same thing.  I don't
> like carrying out-of-tree patches like this, it's not healthy.

Great, please work to make this happen within what we have today.

But adding a stand-alone separate random subsystem just for this is not
a good idea and is one huge reason why this patch set keeps being
ignored by the kernel developers.

thanks,

greg k-h
Greg KH Nov. 26, 2021, 3:42 p.m. UTC | #16
On Mon, Nov 22, 2021 at 10:09:05AM -0500, Simo Sorce wrote:
> On Mon, 2021-11-22 at 07:55 +0100, Greg Kroah-Hartman wrote:
> > On Mon, Nov 22, 2021 at 07:42:02AM +0100, Stephan Mueller wrote:
> > > Am Montag, 22. November 2021, 07:02:14 CET schrieb Greg Kroah-Hartman:
> > > 
> > > Hi Greg,
> > > 
> > > > On Mon, Nov 22, 2021 at 06:34:43AM +0100, Stephan Mueller wrote:
> > > > > Am Sonntag, 21. November 2021, 23:42:33 CET schrieb Jason A. Donenfeld:
> > > > > 
> > > > > Hi Jason,
> > > > > 
> > > > > > Hi Stephan,
> > > > > > 
> > > > > > You've posted it again, and yet I still believe this is not the
> > > > > > correct design or direction. I do not think the explicit goal of
> > > > > > extended configurability ("flexibility") or the explicit goal of being
> > > > > > FIPS compatible represent good directions, and I think this introduces
> > > > > > new problems rather than solving any existing ones.
> > > > > 
> > > > > The members from the Linux distributions that are on copy on this may tell
> > > > > you a different story. They all developed their own downstream patches to
> > > > > somehow add the flexibility that is needed for them. So, we have a great
> > > > > deal of fragmentation at the resting-foundation of Linux cryptography.
> > > > 
> > > > What distros specifically have patches in their kernels that do
> > > > different things to the random code path?  Do you have pointers to those
> > > > patches anywhere?  Why have the distros not submitted their changes
> > > > upstream?
> > > 
> > > I will leave the representatives from the distros to chime in and point to 
> > > these patches.
> > 
> > Then why not work with the distros to get these changes merged into the
> > kernel tree?  They know that keeping things out-of-the-tree costs them
> > time and money, so why are they keeping them there?
> 
> I can speak for my distro.
> We have not proposed them because they are hacks, we know they are
> hacks, and we know they are not the long term solution.

Hacks that work today are the step toward a real solution.

So please, propose them and we can evolve from that.

> Yet we have no better way (in our products, today) so far to deal with
> these issues because what is needed is an effort like LRNG (does not
> have to be this specific implementation), because hacks will not cut it
> in the long term.

So you want to ship this separate driver instead?  Great, but as I said
elsewhere, doing a wholesale replacement is almost never the right thing
to do.

Work off of those known-working-and-certified hacks.  Submit them and
let's go from there please.

thanks,

greg k-h
Greg KH Nov. 26, 2021, 3:44 p.m. UTC | #17
On Mon, Nov 22, 2021 at 09:59:01AM -0500, Simo Sorce wrote:
> Jason,
> have you previously produced a list of reasoned concerns with this
> patchset and direction?
> 
> This specific email is not really useful to me to understand the
> concerns as it does not contain actionable suggestion or critique.
> 
> I personally find the direction fine, and with my distribution hat on I
> can say that FIPS is essential for us and any design must include an
> option to be FIPS certifiable.
> 
> As NIST keeps improving their testing capabilities and rigorous
> cryptographic design of the CSPRNGs as well as entropy sources the
> kernel must also adapt.
> 
> Stephan is providing a path forward, and I haven't seen any other
> proposal, let alone code, that provide improvements in this area.
> I am pretty sure the design can be improved if there is detailed and
> actionable feedback on what to change.
> 
> I hope the path forward can be one of collaboration rather then mere
> opposition.

Replacement of the existing code to cut over to the new one is not
collaboration, it's the exact opposite.

Submitting patches to the existing codebase to implement the
"requirements" is the proper way forward, why has that never been done.

Remember, evolution is the correct way of kernel development, not
intelligent design :)

thanks,

greg k-h
Stephan Mueller Nov. 26, 2021, 4:15 p.m. UTC | #18
Am Freitag, 26. November 2021, 16:44:17 CET schrieb Greg Kroah-Hartman:

Hi Greg,

> On Mon, Nov 22, 2021 at 09:59:01AM -0500, Simo Sorce wrote:
> > Jason,
> > have you previously produced a list of reasoned concerns with this
> > patchset and direction?
> > 
> > This specific email is not really useful to me to understand the
> > concerns as it does not contain actionable suggestion or critique.
> > 
> > I personally find the direction fine, and with my distribution hat on I
> > can say that FIPS is essential for us and any design must include an
> > option to be FIPS certifiable.
> > 
> > As NIST keeps improving their testing capabilities and rigorous
> > cryptographic design of the CSPRNGs as well as entropy sources the
> > kernel must also adapt.
> > 
> > Stephan is providing a path forward, and I haven't seen any other
> > proposal, let alone code, that provide improvements in this area.
> > I am pretty sure the design can be improved if there is detailed and
> > actionable feedback on what to change.
> > 
> > I hope the path forward can be one of collaboration rather then mere
> > opposition.
> 
> Replacement of the existing code to cut over to the new one is not
> collaboration, it's the exact opposite.
> 
> Submitting patches to the existing codebase to implement the
> "requirements" is the proper way forward, why has that never been done.

It has been attempted by Nikolai Stange without avail - no comments were 
received, let alone it was integrated.
> 
> Remember, evolution is the correct way of kernel development, not
> intelligent design :)
> 
> thanks,
> 
> greg k-h


Ciao
Stephan
Greg KH Nov. 26, 2021, 4:22 p.m. UTC | #19
On Fri, Nov 26, 2021 at 05:15:59PM +0100, Stephan Mueller wrote:
> Am Freitag, 26. November 2021, 16:44:17 CET schrieb Greg Kroah-Hartman:
> 
> Hi Greg,
> 
> > On Mon, Nov 22, 2021 at 09:59:01AM -0500, Simo Sorce wrote:
> > > Jason,
> > > have you previously produced a list of reasoned concerns with this
> > > patchset and direction?
> > > 
> > > This specific email is not really useful to me to understand the
> > > concerns as it does not contain actionable suggestion or critique.
> > > 
> > > I personally find the direction fine, and with my distribution hat on I
> > > can say that FIPS is essential for us and any design must include an
> > > option to be FIPS certifiable.
> > > 
> > > As NIST keeps improving their testing capabilities and rigorous
> > > cryptographic design of the CSPRNGs as well as entropy sources the
> > > kernel must also adapt.
> > > 
> > > Stephan is providing a path forward, and I haven't seen any other
> > > proposal, let alone code, that provide improvements in this area.
> > > I am pretty sure the design can be improved if there is detailed and
> > > actionable feedback on what to change.
> > > 
> > > I hope the path forward can be one of collaboration rather then mere
> > > opposition.
> > 
> > Replacement of the existing code to cut over to the new one is not
> > collaboration, it's the exact opposite.
> > 
> > Submitting patches to the existing codebase to implement the
> > "requirements" is the proper way forward, why has that never been done.
> 
> It has been attempted by Nikolai Stange without avail - no comments were 
> received, let alone it was integrated.

Links to the patches and discussion please?

thanks,

greg k-h
Stephan Mueller Nov. 29, 2021, 3:31 p.m. UTC | #20
Am Freitag, 26. November 2021, 17:22:14 CET schrieb Greg Kroah-Hartman:

Hi Greg,

> On Fri, Nov 26, 2021 at 05:15:59PM +0100, Stephan Mueller wrote:
> > Am Freitag, 26. November 2021, 16:44:17 CET schrieb Greg Kroah-Hartman:
> > 
> > Hi Greg,
> > 
> > > On Mon, Nov 22, 2021 at 09:59:01AM -0500, Simo Sorce wrote:
> > > > Jason,
> > > > have you previously produced a list of reasoned concerns with this
> > > > patchset and direction?
> > > > 
> > > > This specific email is not really useful to me to understand the
> > > > concerns as it does not contain actionable suggestion or critique.
> > > > 
> > > > I personally find the direction fine, and with my distribution hat on
> > > > I
> > > > can say that FIPS is essential for us and any design must include an
> > > > option to be FIPS certifiable.
> > > > 
> > > > As NIST keeps improving their testing capabilities and rigorous
> > > > cryptographic design of the CSPRNGs as well as entropy sources the
> > > > kernel must also adapt.
> > > > 
> > > > Stephan is providing a path forward, and I haven't seen any other
> > > > proposal, let alone code, that provide improvements in this area.
> > > > I am pretty sure the design can be improved if there is detailed and
> > > > actionable feedback on what to change.
> > > > 
> > > > I hope the path forward can be one of collaboration rather then mere
> > > > opposition.
> > > 
> > > Replacement of the existing code to cut over to the new one is not
> > > collaboration, it's the exact opposite.
> > > 
> > > Submitting patches to the existing codebase to implement the
> > > "requirements" is the proper way forward, why has that never been done.
> > 
> > It has been attempted by Nikolai Stange without avail - no comments were
> > received, let alone it was integrated.
> 
> Links to the patches and discussion please?

Please consider https://lkml.org/lkml/2020/9/21/157

One side note: the LRNG patch set does not replace random.c, but provides an 
additional implementation that can be selected at compile time. I am under the 
impression that is an equal approach considering other areas of the kernel 
like file systems, memory allocators, and similar.

Thanks
Stephan
Greg KH Nov. 29, 2021, 4:25 p.m. UTC | #21
On Mon, Nov 29, 2021 at 04:31:59PM +0100, Stephan Mueller wrote:
> Am Freitag, 26. November 2021, 17:22:14 CET schrieb Greg Kroah-Hartman:
> 
> Hi Greg,
> 
> > On Fri, Nov 26, 2021 at 05:15:59PM +0100, Stephan Mueller wrote:
> > > Am Freitag, 26. November 2021, 16:44:17 CET schrieb Greg Kroah-Hartman:
> > > 
> > > Hi Greg,
> > > 
> > > > On Mon, Nov 22, 2021 at 09:59:01AM -0500, Simo Sorce wrote:
> > > > > Jason,
> > > > > have you previously produced a list of reasoned concerns with this
> > > > > patchset and direction?
> > > > > 
> > > > > This specific email is not really useful to me to understand the
> > > > > concerns as it does not contain actionable suggestion or critique.
> > > > > 
> > > > > I personally find the direction fine, and with my distribution hat on
> > > > > I
> > > > > can say that FIPS is essential for us and any design must include an
> > > > > option to be FIPS certifiable.
> > > > > 
> > > > > As NIST keeps improving their testing capabilities and rigorous
> > > > > cryptographic design of the CSPRNGs as well as entropy sources the
> > > > > kernel must also adapt.
> > > > > 
> > > > > Stephan is providing a path forward, and I haven't seen any other
> > > > > proposal, let alone code, that provide improvements in this area.
> > > > > I am pretty sure the design can be improved if there is detailed and
> > > > > actionable feedback on what to change.
> > > > > 
> > > > > I hope the path forward can be one of collaboration rather then mere
> > > > > opposition.
> > > > 
> > > > Replacement of the existing code to cut over to the new one is not
> > > > collaboration, it's the exact opposite.
> > > > 
> > > > Submitting patches to the existing codebase to implement the
> > > > "requirements" is the proper way forward, why has that never been done.
> > > 
> > > It has been attempted by Nikolai Stange without avail - no comments were
> > > received, let alone it was integrated.
> > 
> > Links to the patches and discussion please?
> 
> Please consider https://lkml.org/lkml/2020/9/21/157

That's a load of patches, some of them seem sane, what ever happened to
them?  Seems like the conversation got derailed by people with email
server issues that prevented them from participating in public :(

But that patch set is a nice way to do this, incremental changes working
with the existing codebase, not trying to ignore the current code and
create a separate implementation.

Also, minor note, please use lore.kernel.org links, we don't have any
control over lkml.org, nor can we take patches out of that site with any
of our normal tools.

> One side note: the LRNG patch set does not replace random.c, but provides an 
> additional implementation that can be selected at compile time. I am under the 
> impression that is an equal approach considering other areas of the kernel 
> like file systems, memory allocators, and similar.

Sometimes, yes, it is valid to have different implementations for things
that do different things in the same area (like filesystems), but for a
core function of the kernel, so far the existing random maintainer has
not wanted to have multiple implementations.  Same goes for other parts
of the kernel, it's not specific only to this one very tiny driver.

As a counterpoint, we do not allow duplicate drivers that control the
same hardware types in the tree.  We have tried that in the past and it
was a nightmare to support and maintain and just caused massive user
confusion as well.  One can argue that the random driver is in this same
category.

thanks,

greg k-h
Stephan Mueller Nov. 29, 2021, 4:50 p.m. UTC | #22
Am Montag, 29. November 2021, 17:25:24 CET schrieb Greg Kroah-Hartman:

Hi Greg,

> > > 
> > > Links to the patches and discussion please?
> > 
> > Please consider https://lkml.org/lkml/2020/9/21/157
> 
> That's a load of patches, some of them seem sane, what ever happened to
> them? 

Nothing was discussed, nothing was picked up.

> Seems like the conversation got derailed by people with email
> server issues that prevented them from participating in public :(
> 
> But that patch set is a nice way to do this, incremental changes working
> with the existing codebase, not trying to ignore the current code and
> create a separate implementation.
> 
> Also, minor note, please use lore.kernel.org links, we don't have any
> control over lkml.org, nor can we take patches out of that site with any
> of our normal tools.

Apologies, will do for the next time.


Ciao
Stephan
Sandy Harris Nov. 30, 2021, 2:55 a.m. UTC | #23
Chen, Rong A <rong.a.chen@intel.com> wrote:

> On 11/22/2021 7:47 PM, Stephan Mueller wrote:

> > Thanks for the notification.
> >
> > I think this is a false-positive discussed before. __latent_entropy is
> > seemingly allowed for an entire linear buffer as seen in the declaration of
> > the variable input_pool_data in driver/char/random.c which is an array of u32.
> >
> > The struct chacha20_state is a linear buffer of u32 words.
> >
> > struct chacha20_block {
> >          u32 constants[4];
> >          union {
> >                  u32 u[CHACHA_KEY_SIZE_WORDS];
> >                  u8  b[CHACHA_KEY_SIZE];
> >          } key;
> >          u32 counter;
> >          u32 nonce[3];
> > };
> >
> > Therefore it should be identical to the aforementioned example.

No. It is a struct & there's no guarantee all compilers will lay
it out as you  expect. There might even be a gap in the layout
since nonce[] has an odd number of elements.

>> The __latent_entropy marker therefore seems to be appropriate for this structure.

First, this is completely unnecessary since the input pool is marked for
latent entropy & changes there will affect the chacha context.

Also, if I'm reading the docs right, the __latent_entropy attribute
on a data structure only gets it initialised somewhat randomly.
If you want a continuous effect at runtime, then you need to
make the code mix the latent_entropy global variable into the
data structure.
Stephan Mueller Nov. 30, 2021, 6:06 a.m. UTC | #24
Am Dienstag, 30. November 2021, 03:55:12 CET schrieb Sandy Harris:

Hi Sandy,

> Chen, Rong A <rong.a.chen@intel.com> wrote:
> > On 11/22/2021 7:47 PM, Stephan Mueller wrote:
> > > Thanks for the notification.
> > > 
> > > I think this is a false-positive discussed before. __latent_entropy is
> > > seemingly allowed for an entire linear buffer as seen in the declaration
> > > of
> > > the variable input_pool_data in driver/char/random.c which is an array
> > > of u32.
> > > 
> > > The struct chacha20_state is a linear buffer of u32 words.
> > > 
> > > struct chacha20_block {
> > > 
> > >          u32 constants[4];
> > >          union {
> > >          
> > >                  u32 u[CHACHA_KEY_SIZE_WORDS];
> > >                  u8  b[CHACHA_KEY_SIZE];
> > >          
> > >          } key;
> > >          u32 counter;
> > >          u32 nonce[3];
> > > 
> > > };
> > > 
> > > Therefore it should be identical to the aforementioned example.
> 
> No. It is a struct & there's no guarantee all compilers will lay
> it out as you  expect. There might even be a gap in the layout
> since nonce[] has an odd number of elements.
> 
> >> The __latent_entropy marker therefore seems to be appropriate for this
> >> structure.
> First, this is completely unnecessary since the input pool is marked for
> latent entropy & changes there will affect the chacha context.
> 
> Also, if I'm reading the docs right, the __latent_entropy attribute
> on a data structure only gets it initialised somewhat randomly.
> If you want a continuous effect at runtime, then you need to
> make the code mix the latent_entropy global variable into the
> data structure.

Thank you very much for your explanation. I will change my code accordingly.

Note, the LRNG does not have an input_pool.

Ciao
Stephan
Sandy Harris Nov. 30, 2021, 7:32 a.m. UTC | #25
On Mon, Nov 22, 2021 at 11:02 PM Simo Sorce <simo@redhat.com> wrote:

> ... with my distribution hat on I
> can say that FIPS is essential for us and any design must include an
> option to be FIPS certifiable.

I think I understand Ted's objections & I'm inclined to agree with
them. See also this comment from Jon Callas:

" The NIST AES_CTR_DRBG is mostly-okay. It's got a few issues
" (see <https://eprint.iacr.org/2020/619.pdf>), but you can get
" around them. I don't like that it takes a simple concept (a good block
" cipher is a good PRP/PRF) and throws enough scaffolding around it
" to make it hard to understand. I understand the reasons .., it just
" bugs me.

That said, people do want compliance with FIPS or various other
standards. That raises a number of questions.

One is for Stephan: would you care to submit patches for the
current driver that ONLY make it FIPS (and/or European standards)
compliant? No jitter, no stuff to allow different crypto, no choice to
replace the driver, ..., just FIPS. Some of those might be good
ideas, but they would not belong in a FIPS patch.

I think that would have a much better chance of acceptance
than your patches to date.

There are also more general questions:

The FIPS requirements for a deterministic RNG include a
whole rat's nest of extras, notably various self-tests, which
Stephan's patches might deal with. Or do any of the vendors
have patches for that?

FIPS defines DRNGs using either a block cipher or a hash,
but we use a stream cipher. According to Wikipedia, several
of the *BSD distros do the same.
https://en.wikipedia.org/wiki/Salsa20#ChaCha20_adoption
This seems reasonable to me, but could we persuade NIST
to add that option? I've added John Kelsey (one of the FIPS
authors) to the cc list in hopes of that.

Failing that, the Blake hash function is based on Chacha
https://en.wikipedia.org/wiki/BLAKE_(hash_function)
Should we use that to get a more easily certified DRNG?
Would that be as fast as Chacha alone?

The FIPS also require that all the entropy inputs to the
DRNG be certified. I think we have a problem there.

I suspect that many of the random number instructions
enabled by CONFIG_ARCH_RANDOM or the hardware
RNGs enabled by CONFIG_HW_RANDOM could be
certified, but that would need to be done by the vendors
and the costs might be substantial. Are any already
certified? Is there any vendor interest?

Apart from those, the current driver gets entropy in
several places. The comments have:

 * The current exported interfaces for gathering environmental noise
 * from the devices are:
 *
 *    void add_device_randomness(const void *buf, unsigned int size);
 *     void add_input_randomness(unsigned int type, unsigned int code,
 *                                unsigned int value);
 *    void add_interrupt_randomness(int irq, int irq_flags);
 *     void add_disk_randomness(struct gendisk *disk);
 *
 * add_device_randomness() is for adding data to the random pool that
 * is likely to differ between two devices (or possibly even per boot).
 * This would be things like MAC addresses or serial numbers, ...
 *
 * add_input_randomness() uses the input layer interrupt timing, as well as
 * the event type information from the hardware.
 *
 * add_interrupt_randomness() uses the interrupt timing as random
 * inputs to the entropy pool. Using the cycle counters and the irq source
 * as inputs, it feeds the randomness roughly once a second.
 *
 * add_disk_randomness() uses what amounts to the seek time of block
 * layer request events, ... Note that high-speed solid state drives with
 * very low seek times do not make for good sources of entropy, ...

I think we should eliminate add_disk_randomness() since it does
not work well on current hardware. Also, FIPS requires that
entropy sources be independent & add_interrupt_randomness()
depends on the same disk events so these sources may not be.

A similar argument could be made for getting rid of
add_input_randomness() but that would lose the event
type information. Does that matter?

The current driver also uses other sources, at least
fast_mix(), add_timer_randomness(), random_get_entropy()
and the gcc latent entropy plugin. Could/should those be
simplified to get more easily audited or certified code?

The driver also allows input of external data which is
mixed into the pool & provides an ioctl to let a user
with root privileges change the pool's entropy estimate.
Do either of those violate the FIPS requirement that
only certified entropy sources be used? I'd be happy
to lose the ioctl (or better, all the entropy estimation
machinery) but those have been part of the system
for decades. I'd definitely want to keep the option to
use external inputs.
Greg KH Nov. 30, 2021, 7:55 a.m. UTC | #26
On Tue, Nov 30, 2021 at 03:32:38PM +0800, Sandy Harris wrote:
> I think we should eliminate add_disk_randomness() since it does
> not work well on current hardware. Also, FIPS requires that
> entropy sources be independent & add_interrupt_randomness()
> depends on the same disk events so these sources may not be.

This whole "may not be" guessing game when it comes to FIPS
certification is a huge problem.  I have heard of different vendors
getting different feedback and different implementations "passing" in
different ways that totally contradict each other.  It seems that there
is a whole certification industry built up that you can use to try to
pass these tests, but those tests are different depending on the vendor
you use for this, making a total mess.

So perhaps getting solid answers, and having the FIPS people actually
implement (or at least review) the changes and submit them (this is all
open for everyone to see and work on), would be the best thing as that
would at least let us know that this is what they require.

Otherwise, it's a total guess as you state many times in this email, and
that is going to get us nowhere fast as the "requirements" end up
contradicting themselves all the time.

Also, why does any of this have to be in the kernel at all?  If FIPS
requires a deterministic random number generator that will not allow
entropy to be acquired from hardware or external inputs, why does the
kernel care at all?  Just write a fips_random.so library and get it
certified and have any userspace code that cares about such a crazy
thing to use that instead.

thanks,

greg k-h
Stephan Mueller Nov. 30, 2021, 8:56 a.m. UTC | #27
Am Dienstag, 30. November 2021, 08:55:53 CET schrieb Greg Kroah-Hartman:

Hi Greg,

> On Tue, Nov 30, 2021 at 03:32:38PM +0800, Sandy Harris wrote:
> > I think we should eliminate add_disk_randomness() since it does
> > not work well on current hardware. Also, FIPS requires that
> > entropy sources be independent & add_interrupt_randomness()
> > depends on the same disk events so these sources may not be.
> 
> This whole "may not be" guessing game when it comes to FIPS
> certification is a huge problem.  I have heard of different vendors
> getting different feedback and different implementations "passing" in
> different ways that totally contradict each other.  It seems that there
> is a whole certification industry built up that you can use to try to
> pass these tests, but those tests are different depending on the vendor
> you use for this, making a total mess.
> 
> So perhaps getting solid answers, and having the FIPS people actually
> implement (or at least review) the changes and submit them (this is all
> open for everyone to see and work on), would be the best thing as that
> would at least let us know that this is what they require.

Just as a note: I am working as FIPS tester. I am part of the NIST entropy 
working group which oversees the entropy related requirements. The LRNG's FIPS 
compliant implementation is directly based on those requirements. The LRNG was 
even reviewed by NIST personnel who mentioned that they do not see any 
contradiction to the specification. Finally, we are pursuing to get a separate 
ENT validation from NIST for the LRNG which would indicate that the LRNG meets 
all their requirements.

Besides, the LRNG can be configured to have no FIPS bits included at all as 
documented in the patches and in the separately provided documentation. Yet, 
it offers a streamlined conditioning operation and a combination of different 
entropy source data which is obvious to not destroy entropy.

Ciao
Stephan
Greg KH Nov. 30, 2021, 9:12 a.m. UTC | #28
On Tue, Nov 30, 2021 at 09:56:41AM +0100, Stephan Mueller wrote:
> Am Dienstag, 30. November 2021, 08:55:53 CET schrieb Greg Kroah-Hartman:
> 
> Hi Greg,
> 
> > On Tue, Nov 30, 2021 at 03:32:38PM +0800, Sandy Harris wrote:
> > > I think we should eliminate add_disk_randomness() since it does
> > > not work well on current hardware. Also, FIPS requires that
> > > entropy sources be independent & add_interrupt_randomness()
> > > depends on the same disk events so these sources may not be.
> > 
> > This whole "may not be" guessing game when it comes to FIPS
> > certification is a huge problem.  I have heard of different vendors
> > getting different feedback and different implementations "passing" in
> > different ways that totally contradict each other.  It seems that there
> > is a whole certification industry built up that you can use to try to
> > pass these tests, but those tests are different depending on the vendor
> > you use for this, making a total mess.
> > 
> > So perhaps getting solid answers, and having the FIPS people actually
> > implement (or at least review) the changes and submit them (this is all
> > open for everyone to see and work on), would be the best thing as that
> > would at least let us know that this is what they require.
> 
> Just as a note: I am working as FIPS tester. I am part of the NIST entropy 
> working group which oversees the entropy related requirements. The LRNG's FIPS 
> compliant implementation is directly based on those requirements. The LRNG was 
> even reviewed by NIST personnel who mentioned that they do not see any 
> contradiction to the specification. Finally, we are pursuing to get a separate 
> ENT validation from NIST for the LRNG which would indicate that the LRNG meets 
> all their requirements.

That's great, so you would be one of the best people to help submit
changes to the existing code to have it be compliant, instead of
replacing it entirely :)

thanks,

greg k-h
Jeffrey Walton Nov. 30, 2021, 12:24 p.m. UTC | #29
On Mon, Nov 29, 2021 at 6:07 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> ...
> Sometimes, yes, it is valid to have different implementations for things
> that do different things in the same area (like filesystems), but for a
> core function of the kernel, so far the existing random maintainer has
> not wanted to have multiple implementations.  Same goes for other parts
> of the kernel, it's not specific only to this one very tiny driver.
>
> As a counterpoint, we do not allow duplicate drivers that control the
> same hardware types in the tree.  We have tried that in the past and it
> was a nightmare to support and maintain and just caused massive user
> confusion as well.  One can argue that the random driver is in this same
> category.

I think an argument could be made that they are different drivers
since they have different requirements and security goals. I don't
think it matters where the requirements came from, whether it was ad
hoc from the developer, NIST, KISA, CRYPTREC, NESSIE, or another
organization.

Maybe the problem is with the name of the driver? Perhaps the current
driver should be named random-linux, Stephan's driver should be named
random-nist, and the driver should be wired up based on a user's
selection. That should sidestep the problems associated with the
"duplicate drivers" policy.

Jeff
Greg KH Nov. 30, 2021, 2:04 p.m. UTC | #30
On Tue, Nov 30, 2021 at 07:24:15AM -0500, Jeffrey Walton wrote:
> On Mon, Nov 29, 2021 at 6:07 PM Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> > ...
> > Sometimes, yes, it is valid to have different implementations for things
> > that do different things in the same area (like filesystems), but for a
> > core function of the kernel, so far the existing random maintainer has
> > not wanted to have multiple implementations.  Same goes for other parts
> > of the kernel, it's not specific only to this one very tiny driver.
> >
> > As a counterpoint, we do not allow duplicate drivers that control the
> > same hardware types in the tree.  We have tried that in the past and it
> > was a nightmare to support and maintain and just caused massive user
> > confusion as well.  One can argue that the random driver is in this same
> > category.
> 
> I think an argument could be made that they are different drivers
> since they have different requirements and security goals. I don't
> think it matters where the requirements came from, whether it was ad
> hoc from the developer, NIST, KISA, CRYPTREC, NESSIE, or another
> organization.
> 
> Maybe the problem is with the name of the driver? Perhaps the current
> driver should be named random-linux, Stephan's driver should be named
> random-nist, and the driver should be wired up based on a user's
> selection. That should sidestep the problems associated with the
> "duplicate drivers" policy.

The "problem" here is that the drivers/char/random.c file has three users,
the userspace /dev/random and syscall api, the in-kernel "here's some
entropy for the random core to use" api, and the in-kernel "give me some
random data" api.

Odds are, you REALLY do not want the in-kernel calls to be pulling from
the "random-government-crippled-specification" implementation, right?

Again, just try evolving the existing code to meet the needs that you
all have, stop trying to do wholesale reimplementations.  Those never
succeed, and it's pretty obvious that no one wants a "plugin a random
random driver" interface, right?

thanks,

greg k-h
Simo Sorce Nov. 30, 2021, 2:31 p.m. UTC | #31
On Tue, 2021-11-30 at 15:04 +0100, Greg Kroah-Hartman wrote:
> On Tue, Nov 30, 2021 at 07:24:15AM -0500, Jeffrey Walton wrote:
> > On Mon, Nov 29, 2021 at 6:07 PM Greg Kroah-Hartman
> > <gregkh@linuxfoundation.org> wrote:
> > > ...
> > > Sometimes, yes, it is valid to have different implementations for things
> > > that do different things in the same area (like filesystems), but for a
> > > core function of the kernel, so far the existing random maintainer has
> > > not wanted to have multiple implementations.  Same goes for other parts
> > > of the kernel, it's not specific only to this one very tiny driver.
> > > 
> > > As a counterpoint, we do not allow duplicate drivers that control the
> > > same hardware types in the tree.  We have tried that in the past and it
> > > was a nightmare to support and maintain and just caused massive user
> > > confusion as well.  One can argue that the random driver is in this same
> > > category.
> > 
> > I think an argument could be made that they are different drivers
> > since they have different requirements and security goals. I don't
> > think it matters where the requirements came from, whether it was ad
> > hoc from the developer, NIST, KISA, CRYPTREC, NESSIE, or another
> > organization.
> > 
> > Maybe the problem is with the name of the driver? Perhaps the current
> > driver should be named random-linux, Stephan's driver should be named
> > random-nist, and the driver should be wired up based on a user's
> > selection. That should sidestep the problems associated with the
> > "duplicate drivers" policy.
> 
> The "problem" here is that the drivers/char/random.c file has three users,
> the userspace /dev/random and syscall api, the in-kernel "here's some
> entropy for the random core to use" api, and the in-kernel "give me some
> random data" api.
> 
> Odds are, you REALLY do not want the in-kernel calls to be pulling from
> the "random-government-crippled-specification" implementation, right?

You really *do* want that.
When our customers are mandated to use FIPS certified cryptography,
they want to use it for kernel cryptography as well, and in general
they want to use a certified randomness source as well.

I do not get why you call the implementation crippled? The
specification is quite thorough and provides well reasoned requirements
as well as self-test that insure coding mistakes won't end up returning
non-random values.

I understand the mistrust vs gov agencies due to past mishaps like the
Dual-DRBG thing, but we are not talking about something like that in
this case. NIST is not mandating any specific algorithmic
implementation, the requirement set forth allow to use a variety of
different algorithms so that everyone can choose what they think is
sane.

> Again, just try evolving the existing code to meet the needs that you
> all have, stop trying to do wholesale reimplementations.  Those never
> succeed, and it's pretty obvious that no one wants a "plugin a random
> random driver" interface, right?

I think one of the issues is that the number of changes required
against the current random driver amount essentially to a re-
implementation. Sure, you can do it as a series of patches that
transform the current code in something completely different.

And the main question here is, how can we get there, in any case, if
the maintainer of the random device doesn't even participate in
discussions, does not pick obvious bug fixes and is simply not engaging
at all?

Your plan requires an active maintainer that guides these changes and
interact with the people proposing them to negotiate the best outcome.
But that is not happening so that road seem blocked at the moment.

HTH,
Simo.
Jeffrey Walton Nov. 30, 2021, 3:13 p.m. UTC | #32
On Tue, Nov 30, 2021 at 9:04 AM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> On Tue, Nov 30, 2021 at 07:24:15AM -0500, Jeffrey Walton wrote:
> > On Mon, Nov 29, 2021 at 6:07 PM Greg Kroah-Hartman
> > <gregkh@linuxfoundation.org> wrote:
> > > ...
> > > Sometimes, yes, it is valid to have different implementations for things
> > > that do different things in the same area (like filesystems), but for a
> > > core function of the kernel, so far the existing random maintainer has
> > > not wanted to have multiple implementations.  Same goes for other parts
> > > of the kernel, it's not specific only to this one very tiny driver.
> > >
> > > As a counterpoint, we do not allow duplicate drivers that control the
> > > same hardware types in the tree.  We have tried that in the past and it
> > > was a nightmare to support and maintain and just caused massive user
> > > confusion as well.  One can argue that the random driver is in this same
> > > category.
> >
> > I think an argument could be made that they are different drivers
> > since they have different requirements and security goals. I don't
> > think it matters where the requirements came from, whether it was ad
> > hoc from the developer, NIST, KISA, CRYPTREC, NESSIE, or another
> > organization.
> >
> > Maybe the problem is with the name of the driver? Perhaps the current
> > driver should be named random-linux, Stephan's driver should be named
> > random-nist, and the driver should be wired up based on a user's
> > selection. That should sidestep the problems associated with the
> > "duplicate drivers" policy.
>
> The "problem" here is that the drivers/char/random.c file has three users,
> the userspace /dev/random and syscall api, the in-kernel "here's some
> entropy for the random core to use" api, and the in-kernel "give me some
> random data" api.
>
> Odds are, you REALLY do not want the in-kernel calls to be pulling from
> the "random-government-crippled-specification" implementation, right?

It's not a question of whether some folks want it or not. They have to
accept it due to policy. They have no choice in the matter.

I hope I don't sound argumentative. It's not my intention. But I know
what it's like to have to comply with policies, even ones I don't
like.

Jeff
Greg KH Nov. 30, 2021, 3:39 p.m. UTC | #33
On Tue, Nov 30, 2021 at 10:13:26AM -0500, Jeffrey Walton wrote:
> On Tue, Nov 30, 2021 at 9:04 AM Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> >
> > On Tue, Nov 30, 2021 at 07:24:15AM -0500, Jeffrey Walton wrote:
> > > On Mon, Nov 29, 2021 at 6:07 PM Greg Kroah-Hartman
> > > <gregkh@linuxfoundation.org> wrote:
> > > > ...
> > > > Sometimes, yes, it is valid to have different implementations for things
> > > > that do different things in the same area (like filesystems), but for a
> > > > core function of the kernel, so far the existing random maintainer has
> > > > not wanted to have multiple implementations.  Same goes for other parts
> > > > of the kernel, it's not specific only to this one very tiny driver.
> > > >
> > > > As a counterpoint, we do not allow duplicate drivers that control the
> > > > same hardware types in the tree.  We have tried that in the past and it
> > > > was a nightmare to support and maintain and just caused massive user
> > > > confusion as well.  One can argue that the random driver is in this same
> > > > category.
> > >
> > > I think an argument could be made that they are different drivers
> > > since they have different requirements and security goals. I don't
> > > think it matters where the requirements came from, whether it was ad
> > > hoc from the developer, NIST, KISA, CRYPTREC, NESSIE, or another
> > > organization.
> > >
> > > Maybe the problem is with the name of the driver? Perhaps the current
> > > driver should be named random-linux, Stephan's driver should be named
> > > random-nist, and the driver should be wired up based on a user's
> > > selection. That should sidestep the problems associated with the
> > > "duplicate drivers" policy.
> >
> > The "problem" here is that the drivers/char/random.c file has three users,
> > the userspace /dev/random and syscall api, the in-kernel "here's some
> > entropy for the random core to use" api, and the in-kernel "give me some
> > random data" api.
> >
> > Odds are, you REALLY do not want the in-kernel calls to be pulling from
> > the "random-government-crippled-specification" implementation, right?
> 
> It's not a question of whether some folks want it or not. They have to
> accept it due to policy. They have no choice in the matter.

I strongly doubt that policy dictates all of the current calls to
get_random_*() require that they return data that is dictated by that
policy.  If so, that's not a valid specification for a variety of
reasons (i.e. it will break other specification requirements...)

thanks,

greg k-h
Greg KH Nov. 30, 2021, 3:45 p.m. UTC | #34
On Tue, Nov 30, 2021 at 09:31:09AM -0500, Simo Sorce wrote:
> On Tue, 2021-11-30 at 15:04 +0100, Greg Kroah-Hartman wrote:
> > On Tue, Nov 30, 2021 at 07:24:15AM -0500, Jeffrey Walton wrote:
> > > On Mon, Nov 29, 2021 at 6:07 PM Greg Kroah-Hartman
> > > <gregkh@linuxfoundation.org> wrote:
> > > > ...
> > > > Sometimes, yes, it is valid to have different implementations for things
> > > > that do different things in the same area (like filesystems), but for a
> > > > core function of the kernel, so far the existing random maintainer has
> > > > not wanted to have multiple implementations.  Same goes for other parts
> > > > of the kernel, it's not specific only to this one very tiny driver.
> > > > 
> > > > As a counterpoint, we do not allow duplicate drivers that control the
> > > > same hardware types in the tree.  We have tried that in the past and it
> > > > was a nightmare to support and maintain and just caused massive user
> > > > confusion as well.  One can argue that the random driver is in this same
> > > > category.
> > > 
> > > I think an argument could be made that they are different drivers
> > > since they have different requirements and security goals. I don't
> > > think it matters where the requirements came from, whether it was ad
> > > hoc from the developer, NIST, KISA, CRYPTREC, NESSIE, or another
> > > organization.
> > > 
> > > Maybe the problem is with the name of the driver? Perhaps the current
> > > driver should be named random-linux, Stephan's driver should be named
> > > random-nist, and the driver should be wired up based on a user's
> > > selection. That should sidestep the problems associated with the
> > > "duplicate drivers" policy.
> > 
> > The "problem" here is that the drivers/char/random.c file has three users,
> > the userspace /dev/random and syscall api, the in-kernel "here's some
> > entropy for the random core to use" api, and the in-kernel "give me some
> > random data" api.
> > 
> > Odds are, you REALLY do not want the in-kernel calls to be pulling from
> > the "random-government-crippled-specification" implementation, right?
> 
> You really *do* want that.
> When our customers are mandated to use FIPS certified cryptography,
> they want to use it for kernel cryptography as well, and in general
> they want to use a certified randomness source as well.

There are huge numbers of internal kernel calls that use random data for
non-crypto things.

> I do not get why you call the implementation crippled? The
> specification is quite thorough and provides well reasoned requirements
> as well as self-test that insure coding mistakes won't end up returning
> non-random values.

Which specification are you talking about exactly?  There are loads of
different ones it seems that people wish to follow, so it's hard to
claim that they all are sane :)

> I understand the mistrust vs gov agencies due to past mishaps like the
> Dual-DRBG thing, but we are not talking about something like that in
> this case. NIST is not mandating any specific algorithmic
> implementation, the requirement set forth allow to use a variety of
> different algorithms so that everyone can choose what they think is
> sane.
> 
> > Again, just try evolving the existing code to meet the needs that you
> > all have, stop trying to do wholesale reimplementations.  Those never
> > succeed, and it's pretty obvious that no one wants a "plugin a random
> > random driver" interface, right?
> 
> I think one of the issues is that the number of changes required
> against the current random driver amount essentially to a re-
> implementation. Sure, you can do it as a series of patches that
> transform the current code in something completely different.

That is how kernel development works, it is nothing new.

> And the main question here is, how can we get there, in any case, if
> the maintainer of the random device doesn't even participate in
> discussions, does not pick obvious bug fixes and is simply not engaging
> at all?

What obvious bug fixes have been dropped?

> Your plan requires an active maintainer that guides these changes and
> interact with the people proposing them to negotiate the best outcome.
> But that is not happening so that road seem blocked at the moment.

We need working patches that fit with the kernel development model first
before people can start blaming maintainers :)

I see almost 300 changes accepted for this tiny random.c file over the
years we have had git (17 years).  I think that's a very large number of
changes for a 2300 line file that is relied upon by everyone.


thanks,

greg k-h
Willy Tarreau Nov. 30, 2021, 5:05 p.m. UTC | #35
On Tue, Nov 30, 2021 at 04:45:44PM +0100, Greg Kroah-Hartman wrote:
> On Tue, Nov 30, 2021 at 09:31:09AM -0500, Simo Sorce wrote:
> > On Tue, 2021-11-30 at 15:04 +0100, Greg Kroah-Hartman wrote:
> > > Odds are, you REALLY do not want the in-kernel calls to be pulling from
> > > the "random-government-crippled-specification" implementation, right?
> > 
> > You really *do* want that.
> > When our customers are mandated to use FIPS certified cryptography,
> > they want to use it for kernel cryptography as well, and in general
> > they want to use a certified randomness source as well.
> 
> There are huge numbers of internal kernel calls that use random data for
> non-crypto things.

I think the confusion comes from the use of cryptography to hide the
internal state and provide non-predictable sequences, and not from the
use of this source to perform cryptography elsewhere. But crypto here,
when used, is not a goal but a means. We could call this a "reduction"
function or a "whitening" function. Its importance solely depends on
how much we want to protect the internal state from being guessed, which
first comes back to how long the knowledge of this internal state is
useful. If we'd mix completely independent and unpredictable sources
like cosmic microwave background noise and sea-level beta radiations,
these are constantly renewed, their knowledge doesn't bring anything
and there's no need for crypto to protect them. That's not necessarily
what we're using and we have to deal with more durable source whose
disclosure could have more impact for some time frame, thus would need
some protection.

As such there is probably a broad spectrum between "we must use strong
cryptography on this source hence abide with authorities' decisions" and
"we just need this short-lived state not to be trivially guessable till
the next call". In this case do we *really* care about what crypto
functions are used to hide the internal state ? I guess not really, and
that could possibly be configurable at run time. After all, in practice
the jitter entropy and other sources might add sufficient uncertainty
to complicate analysis of even a weak algorithm and render the internal
state hardly guessable.

> > Your plan requires an active maintainer that guides these changes and
> > interact with the people proposing them to negotiate the best outcome.
> > But that is not happening so that road seem blocked at the moment.
> 
> We need working patches that fit with the kernel development model first
> before people can start blaming maintainers :)
> 
> I see almost 300 changes accepted for this tiny random.c file over the
> years we have had git (17 years).  I think that's a very large number of
> changes for a 2300 line file that is relied upon by everyone.

I'm also having some concerns about this. It seems to me that it's always
difficult to *simplify* what we have and that each time we try to replace
something in that area we end up with multiple versions. Look at the recent
prandom32 stuff for example. We got a new algo used for IP IDs, in a rush,
hoping to generalize it to replace the existing Tausworthe one. I had a look
a few months ago to try to finish the job... hundreds of callers that make
use of the internal state for unit tests :-(  Basically unfeasible without
breaking lots of driver I have no idea how to test. So by trying to replace
something we just ended up with two implementations (and if I remember well
there were already a few more, mostly variants of the former).

A replacement ought to be an observation, a conclusion of a work well done,
not a goal. If the changes manage to move everyone in the right direction
and at the end everything is seamlessly replaced for good, that's awesome.
But changing for changing is hard. And if we end up with build time options
to decide between one solution and the other, we fragment the testability :-/

Just my two cents,
Willy
Simo Sorce Nov. 30, 2021, 5:08 p.m. UTC | #36
On Tue, 2021-11-30 at 16:45 +0100, Greg Kroah-Hartman wrote:
> On Tue, Nov 30, 2021 at 09:31:09AM -0500, Simo Sorce wrote:
> > On Tue, 2021-11-30 at 15:04 +0100, Greg Kroah-Hartman wrote:
> > > On Tue, Nov 30, 2021 at 07:24:15AM -0500, Jeffrey Walton wrote:
> > > > On Mon, Nov 29, 2021 at 6:07 PM Greg Kroah-Hartman
> > > > <gregkh@linuxfoundation.org> wrote:
> > > > > ...
> > > > > Sometimes, yes, it is valid to have different implementations for things
> > > > > that do different things in the same area (like filesystems), but for a
> > > > > core function of the kernel, so far the existing random maintainer has
> > > > > not wanted to have multiple implementations.  Same goes for other parts
> > > > > of the kernel, it's not specific only to this one very tiny driver.
> > > > > 
> > > > > As a counterpoint, we do not allow duplicate drivers that control the
> > > > > same hardware types in the tree.  We have tried that in the past and it
> > > > > was a nightmare to support and maintain and just caused massive user
> > > > > confusion as well.  One can argue that the random driver is in this same
> > > > > category.
> > > > 
> > > > I think an argument could be made that they are different drivers
> > > > since they have different requirements and security goals. I don't
> > > > think it matters where the requirements came from, whether it was ad
> > > > hoc from the developer, NIST, KISA, CRYPTREC, NESSIE, or another
> > > > organization.
> > > > 
> > > > Maybe the problem is with the name of the driver? Perhaps the current
> > > > driver should be named random-linux, Stephan's driver should be named
> > > > random-nist, and the driver should be wired up based on a user's
> > > > selection. That should sidestep the problems associated with the
> > > > "duplicate drivers" policy.
> > > 
> > > The "problem" here is that the drivers/char/random.c file has three users,
> > > the userspace /dev/random and syscall api, the in-kernel "here's some
> > > entropy for the random core to use" api, and the in-kernel "give me some
> > > random data" api.
> > > 
> > > Odds are, you REALLY do not want the in-kernel calls to be pulling from
> > > the "random-government-crippled-specification" implementation, right?
> > 
> > You really *do* want that.
> > When our customers are mandated to use FIPS certified cryptography,
> > they want to use it for kernel cryptography as well, and in general
> > they want to use a certified randomness source as well.
> 
> There are huge numbers of internal kernel calls that use random data for
> non-crypto things.

Sure, but it makes little sense to use different random implementations
unless there are specific issues in terms of performance. It is also
not always easy to establish if a certain use of random numbers is
actually security relevant, may be context dependent, so it is
generally safer to just use the certified implementation for everything
if possible.

> > I do not get why you call the implementation crippled? The
> > specification is quite thorough and provides well reasoned requirements
> > as well as self-test that insure coding mistakes won't end up returning
> > non-random values.
> 
> Which specification are you talking about exactly?  There are loads of
> different ones it seems that people wish to follow, so it's hard to
> claim that they all are sane :)

Well, given I am interested primarily in FIPS certifications I was
referring specifically to SP800-90A/B/C:
https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final
https://csrc.nist.gov/publications/detail/sp/800-90b/final
https://csrc.nist.gov/publications/detail/sp/800-90c/draft

> > I understand the mistrust vs gov agencies due to past mishaps like the
> > Dual-DRBG thing, but we are not talking about something like that in
> > this case. NIST is not mandating any specific algorithmic
> > implementation, the requirement set forth allow to use a variety of
> > different algorithms so that everyone can choose what they think is
> > sane.
> > 
> > > Again, just try evolving the existing code to meet the needs that you
> > > all have, stop trying to do wholesale reimplementations.  Those never
> > > succeed, and it's pretty obvious that no one wants a "plugin a random
> > > random driver" interface, right?
> > 
> > I think one of the issues is that the number of changes required
> > against the current random driver amount essentially to a re-
> > implementation. Sure, you can do it as a series of patches that
> > transform the current code in something completely different.
> 
> That is how kernel development works, it is nothing new.
> 
> > And the main question here is, how can we get there, in any case, if
> > the maintainer of the random device doesn't even participate in
> > discussions, does not pick obvious bug fixes and is simply not engaging
> > at all?
> 
> What obvious bug fixes have been dropped?

Stephan posted you the link a few days ago for one of the examples.
If you look at the last year you also will see that multiple patches
have gone in w/o the maintainer interacting, which is fine for obvious
stuff, but does not work for stuff that requires more feedback.

> > Your plan requires an active maintainer that guides these changes and
> > interact with the people proposing them to negotiate the best outcome.
> > But that is not happening so that road seem blocked at the moment.
> 
> We need working patches that fit with the kernel development model first
> before people can start blaming maintainers :)

This is a Catch-22, the maintainer is mum in what would be acceptable,
and whenever there are patches sent, there is no feedback on whether
they are acceptable or not. It's not like I like blaming anyone, but it
would be nice to have at least one word that gives a direction to
follow that the maintainer is willing to then engage with and review or
at least accept with proper third party review.

> I see almost 300 changes accepted for this tiny random.c file over the
> years we have had git (17 years).  I think that's a very large number of
> changes for a 2300 line file that is relied upon by everyone.

Seem like a lot more are desired too :-)

Simo.
Eric Biggers Nov. 30, 2021, 6:15 p.m. UTC | #37
On Tue, Nov 30, 2021 at 04:45:44PM +0100, Greg Kroah-Hartman wrote:
> > And the main question here is, how can we get there, in any case, if
> > the maintainer of the random device doesn't even participate in
> > discussions, does not pick obvious bug fixes and is simply not engaging
> > at all?
> 
> What obvious bug fixes have been dropped?
> 

The RNDRESEEDCRNG ioctl was totally broken, and I sent out a patch to fix it
which was ignored for months:
https://lore.kernel.org/linux-crypto/20200916041908.66649-1-ebiggers@kernel.org/

Reminders didn't help:

First ping: https://lore.kernel.org/linux-crypto/20201007035021.GB912@sol.localdomain/
Second ping: https://lore.kernel.org/linux-crypto/20201026163343.GA858@sol.localdomain/
Third ping: https://lore.kernel.org/linux-crypto/X7gQXgoXHHEr6HXC@sol.localdomain/
Fourth ping: https://lore.kernel.org/linux-crypto/X%2FNkrKpaIBTjQzbv@sol.localdomain/
Resent to Andrew Morton: https://lore.kernel.org/linux-crypto/20210112192818.69921-1-ebiggers@kernel.org/
Pinged Andrew: https://lore.kernel.org/linux-crypto/YBiEJ9Md60HjAWJg@sol.localdomain/

Finally *you* took the patch: https://lore.kernel.org/linux-crypto/YBwZ1a0VIdpTDNuD@kroah.com/

Here's another random.c bug fix which was ignored, this one for 6 months before
Herbert Xu finally took it through the crypto tree:
https://lore.kernel.org/linux-crypto/20210322051347.266831-1-ebiggers@kernel.org/

Here's a dead code cleanup which was ignored for 6 months before being taken by
Herbert Xu through the crypto tree:
https://lore.kernel.org/linux-crypto/20200916043652.96640-1-ebiggers@kernel.org/

Here's a patch to random.c which was taken by the arm64 maintainers due to being
ignored by the random.c maintainer:
https://lore.kernel.org/lkml/20201105152944.16953-1-ardb@kernel.org/

So unfortunately, as far as I can tell, Ted is not maintaining random.c anymore.  

- Eric
Jason A. Donenfeld Nov. 30, 2021, 6:39 p.m. UTC | #38
On Tue, Nov 30, 2021 at 1:16 PM Eric Biggers <ebiggers@kernel.org> wrote:
> So unfortunately, as far as I can tell, Ted is not maintaining random.c anymore.

I am happy to step up here. Feel free to CC me on random.c fixes and
I'll review them promptly.

Jason
Simo Sorce Nov. 30, 2021, 7:41 p.m. UTC | #39
On Tue, 2021-11-30 at 13:39 -0500, Jason A. Donenfeld wrote:
> On Tue, Nov 30, 2021 at 1:16 PM Eric Biggers <ebiggers@kernel.org> wrote:
> > So unfortunately, as far as I can tell, Ted is not maintaining random.c anymore.
> 
> I am happy to step up here. Feel free to CC me on random.c fixes and
> I'll review them promptly.

Jason,
are you also volunteering to review the patches needed to reach
compliance with the NIST documents I mentioned in the thread?

Simo.
Jason A. Donenfeld Dec. 1, 2021, 4:02 p.m. UTC | #40
Hi Simo,

I think various folks have said this during the various discussions on this
topic over the years, in addition to myself, but I suppose I'll reiterate my
general views on FIPS in this context.

FIPS is about compliance and certification. From a cryptographic point of
view, there might be some good ideas, some dated ideas, some superfluous but
harmless ideas, and so forth. But the reason that you want it for your
customers is because you think your product will become more valuable or
useful to customers if it checks that green compliance checkbox. I don't think
we disagree about this being the motivation.

Now typically the kernel interoperates with lots of things and implements many
different specifications. It supports scores of network protocols, IPsec
cipher suites, USB quirks, SCSI hacks, you name it. The implementation of
these drivers is always up to the author and hopefully kernel developers at
large do the best job they can with the implementation, but the hardware or
protocol they're interfacing with is not up to the author, by virtue of it
being external to the kernel. It's not like instantiating IPsec with single
DES and MD4, or SM3 and SM4, etc. is so great, and it's not like the
compendium of brilliant hacks in drivers/usb/host/pci-quirks.c is so great
either. But these things all exist to talk to something *outside* of the
kernel, and so we grit our teeth, and as I said, do the best we can to
implement it well.

But the RNG isn't like that. In fact, the RNG is logically *required* to be
not anything like that: it returns random bytes, and they must not have any
distinguishing quality with other random bytes; otherwise we have a serious
problem that needs fixing. And so, we carry things out according to the usual
kernel developer mindset: we implement it as best as we can, using the best
algorithms we can find, in a way most suitable for the kernel.

Then FIPS comes along and starts dictating things about *how* we implement it,
and those things it dictates might not be exactly the same as what we would
would be doing when doing best that we can, using the best algorithms we can
find, and in the most suitable way for the kernel. And so it would seem that
the goal of implementing the RNG as best as we can might potentially be at
odds with the goal of getting that green compliance checkbox, because that
checkbox oversteps its bounds a bit.

That's not to say, of course, that we shouldn't accept input on how we
implement our algorithms from elsewhere. On the contrary, I think random.c has
a *lot* to gain from incorporating newer ideas, and that the formalism and
guidance from academic cryptographers is less "academic" than it once was and
much more real world, implementable, and suitable for our uses. But, again,
incorporating new ideas and accepting input on how to improve our code is very
much not the same thing as following the FIPS laundry list for that green
compliance checkbox. Maybe some parts do overlap -- and I'd love patches that
improve the code alongside compelling cryptographic arguments -- but, again,
we're talking about compliance here, and not a more welcome, "hey check out
this document I found with a bunch of great ideas we should implement."

I would like the kernel to have an excellent CSPRNG, from a cryptographic
point of view, from a performance point of view, from an API point of view. I
think these motivations are consistent with how the kernel is generally
developed. And I think front loading the motivations with an external
compliance goal greatly deviates and even detracts from the way the kernel is
generally developed.

Now the above is somewhat negative on FIPS, but the question can still be
posed: does FIPS have a path forward in the RNG in the kernel? It's obviously
not a resounding "yes", but I don't think it's a totally certain "no" either.
It might be possible to find some wiggle room. I'm not saying that it is
certainly possible to do that, but it might be.

Specifically, I think that if you change your perspective from, "how can we
change the algorithms of the RNG to be FIPS" to "how can we bend FIPS within
its limits so that having what customers want would minimally impact the
quality of the RNG implementation or introduce undue maintenance burdens."
This means: not refactoring the RNG into some large abstraction layer that's
pluggable and supports multiple different implementations, not rewriting the
world in a massive patchset, not adding clutter. Instead, perhaps there's a
very, very minimal set of things that can be done that would be considerably
less controversial. That will probably require from you and other FIPS
enthusiasts some study and discussion at what the truly most minimal set of
things required are to get you that green compliance checkbox. And hey --
maybe it's still way too much and it doesn't work out here. But maybe it's not
that much, or, as Greg suggested, maybe it winds up that your needs are
actually satisfied just fine by something in userspace or userspace-adjacent.

So I don't know whether the FIPS has a path forward here, but if it does, I
think the above is the general shape it would take. And in the mean time, I'm
of course open to reviewing patches that improve the RNG in a cryptographic or
algorithmic sense, rather than a purely compliance one.

Hopefully that helps you understand more about where we're coming from.

Regards,
Jason
Simo Sorce Dec. 1, 2021, 5:19 p.m. UTC | #41
Hi Jason,
thanks for your reply, I appreciate when there is a clear exchange of
ideas.

Comment inline.

On Wed, 2021-12-01 at 11:02 -0500, Jason A. Donenfeld wrote:
> Hi Simo,
> 
> I think various folks have said this during the various discussions on this
> topic over the years, in addition to myself, but I suppose I'll reiterate my
> general views on FIPS in this context.
> 
> FIPS is about compliance and certification. From a cryptographic point of
> view, there might be some good ideas, some dated ideas, some superfluous but
> harmless ideas, and so forth. But the reason that you want it for your
> customers is because you think your product will become more valuable or
> useful to customers if it checks that green compliance checkbox. I don't think
> we disagree about this being the motivation.

I have to say that although there is clearly a great deal of "because
we need the certification" I do not fully agree that FIPS is just a
checkbox to be ticked for me. Of course for customers that do not care
that much it is, and it is a required one. However having worked a lot
on this I can tell you there is actually real cryptographic value in
the requirements FIPS introduced over the years. If anything my
complaint is that the list of accepted constructs is restrictive, but
other than that most of the requirements have real world sense, and the
certification process do uncover issue that otherwise would linger as
the testing is rather thorough.

> Now typically the kernel interoperates with lots of things and implements many
> different specifications. It supports scores of network protocols, IPsec
> cipher suites, USB quirks, SCSI hacks, you name it. The implementation of
> these drivers is always up to the author and hopefully kernel developers at
> large do the best job they can with the implementation, but the hardware or
> protocol they're interfacing with is not up to the author, by virtue of it
> being external to the kernel. It's not like instantiating IPsec with single
> DES and MD4, or SM3 and SM4, etc. is so great, and it's not like the
> compendium of brilliant hacks in drivers/usb/host/pci-quirks.c is so great
> either. But these things all exist to talk to something *outside* of the
> kernel, and so we grit our teeth, and as I said, do the best we can to
> implement it well.
> 
> But the RNG isn't like that. In fact, the RNG is logically *required* to be
> not anything like that: it returns random bytes, and they must not have any
> distinguishing quality with other random bytes; otherwise we have a serious
> problem that needs fixing. And so, we carry things out according to the usual
> kernel developer mindset: we implement it as best as we can, using the best
> algorithms we can find, in a way most suitable for the kernel.
> 
> Then FIPS comes along and starts dictating things about *how* we implement it,
> and those things it dictates might not be exactly the same as what we would
> would be doing when doing best that we can, using the best algorithms we can
> find, and in the most suitable way for the kernel. And so it would seem that
> the goal of implementing the RNG as best as we can might potentially be at
> odds with the goal of getting that green compliance checkbox, because that
> checkbox oversteps its bounds a bit.

Well I think most of the requirements are sane practices, hopefully
controversial stuff will be minimal. I fully believe we can work to
have the best we can as well as having it FIPS compliant, because the
intent of FIPS requirements here is exactly to have the best guarantees
for randomness.

> That's not to say, of course, that we shouldn't accept input on how we
> implement our algorithms from elsewhere. On the contrary, I think random.c has
> a *lot* to gain from incorporating newer ideas, and that the formalism and
> guidance from academic cryptographers is less "academic" than it once was and
> much more real world, implementable, and suitable for our uses. But, again,
> incorporating new ideas and accepting input on how to improve our code is very
> much not the same thing as following the FIPS laundry list for that green
> compliance checkbox. Maybe some parts do overlap -- and I'd love patches that
> improve the code alongside compelling cryptographic arguments -- but, again,
> we're talking about compliance here, and not a more welcome, "hey check out
> this document I found with a bunch of great ideas we should implement."

I happen to think quite a few of the requirements are actually good
ideas to implement to improve the guarantees of randomness, but there
may definitely be contentious ideas of what is "good" and what is an 
"arbitrary request".

> I would like the kernel to have an excellent CSPRNG, from a cryptographic
> point of view, from a performance point of view, from an API point of view. I
> think these motivations are consistent with how the kernel is generally
> developed. And I think front loading the motivations with an external
> compliance goal greatly deviates and even detracts from the way the kernel is
> generally developed.

I would agree is compliance meant arbitrary/capricious requirements.
Hopefully most of the requirements are reasonable and we can find a
reasonable way to fulfill them.

> Now the above is somewhat negative on FIPS, but the question can still be
> posed: does FIPS have a path forward in the RNG in the kernel? It's obviously
> not a resounding "yes", but I don't think it's a totally certain "no" either.
> It might be possible to find some wiggle room. I'm not saying that it is
> certainly possible to do that, but it might be.
> 
> Specifically, I think that if you change your perspective from, "how can we
> change the algorithms of the RNG to be FIPS" to "how can we bend FIPS within
> its limits so that having what customers want would minimally impact the
> quality of the RNG implementation or introduce undue maintenance burdens."

We always operate with this mindset to be quite frank. The kernel is
just one of many crypto modules we certify, and we always try to find
the least invasive options in all the crypto modules we certify. We
also normally try to get all changes upstream because we think they are
a benefit to everyone.

> This means: not refactoring the RNG into some large abstraction layer that's
> pluggable and supports multiple different implementations, not rewriting the
> world in a massive patchset, not adding clutter.

I think the reason to propose this is to deal with cases where the
kernel community and the FIPS requirement diverge. A pluggable system
allows to provide a downstream module and in general will provide clear
entry-points where to apply downstream patches that minimally deviate
from the general structure.

Unfortunately, regardless of what the kernel community find of its
liking we have a business need to provide FIPS certifications to our
customers. So for us it is also a matter of pragmatically reducing to
the maximum extent possible any necessary deviation from upstream
kernels.

>  Instead, perhaps there's a
> very, very minimal set of things that can be done that would be considerably
> less controversial. That will probably require from you and other FIPS
> enthusiasts some study and discussion at what the truly most minimal set of
> things required are to get you that green compliance checkbox.

As long as there is actual feedback and a willingness to reach a
compromise on both sides when a change does not materially cause
issues, I think this is certainly reasonable.

>  And hey --
> maybe it's still way too much and it doesn't work out here. But maybe it's not
> that much, or, as Greg suggested, maybe it winds up that your needs are
> actually satisfied just fine by something in userspace or userspace-adjacent.

Unfortunately userspace is not an option for kernel's own cryptography.

> So I don't know whether the FIPS has a path forward here, but if it does, I
> think the above is the general shape it would take. And in the mean time, I'm
> of course open to reviewing patches that improve the RNG in a cryptographic or
> algorithmic sense, rather than a purely compliance one.

Hopefully we can take both into account.

> Hopefully that helps you understand more about where we're coming from.

It does,
thanks.

Simo.
Boris Krasnovskiy Dec. 1, 2021, 5:55 p.m. UTC | #42
Hi Jason, Greg,

a lot of the issues LRNG address are related to RNG and FIPS on embedded/IoT devices.

The problem we have is that /dev/random as it stands today in many cases does not generate enough entropy to support cryptography on embedded/IoT devices. Embedded devices in most cases have limited interrupt and IO activity, they do have in many cases aggressive power management where device is up and running few seconds at a time and fallbacks into suspend mode, this is done to preserve power (battery and otherwise), and now such operation even the legal mandate in EU (we are going green).

What options do we have here:

Use hardware random number if CPU supports it. Yes, some people do not trust it, but it's better than nothing. /dev/random currently does not allow to mix in Hardware RNG unless quality parameter is set, and none of the kernel Hardware RNG have it set out of the box.

Not all CPUs have hardware RNG to use or have non-compliant Hardware RNG (which is after 90C was adopted most of the older ones, 90C requires runtime test on raw entropy which is not exposed outside of the IC), what to do now? This is one of the areas where Jitter RNG comes in. It has fast entropy collection, meets FIPS requirements and could be run on any CPU, provided it has High Resolution Timer, does not require storing seed on the file system that is prohibited by FIPS. There is no option as of today to mix in or flood Jitter entropy into /dev/random inside kernel.

I am aware that there are userspace daemons that take entropy from Hardware RNG or Jitter and feed into /dev/random, but is it really the best approach?
Now let get into FIPS on such systems.

I hoped I explained earlier why existing /dev/random is unusable.
If userspace solution to /dev/random is used, one has to demonstrate that entropy fed by userspace daemon floods /dev/random to the point where other sources of entropy statistically does not matter. That increases cost of FIPS certification by about 30% last time we checked.

This is why it would help a lot if one can choose from kernel configuration which RNG is appropriate for the system at hand, and this exactly what LRNG does.

Thank you,
Boris
THIS MESSAGE, ANY ATTACHMENT(S), AND THE INFORMATION CONTAINED HEREIN MAY BE PROPRIETARY TO LAIRD CONNECTIVITY, INC. AND/OR ANOTHER PARTY, AND MAY FURTHER BE INTENDED TO BE KEPT CONFIDENTIAL. IF YOU ARE NOT THE INTENDED RECIPIENT, PLEASE DELETE THE EMAIL AND ANY ATTACHMENTS, AND IMMEDIATELY NOTIFY THE SENDER BY RETURN EMAIL. THIS MESSAGE AND ITS CONTENTS ARE THE PROPERTY OF LAIRD CONNECTIVITY, INC. AND MAY NOT BE REPRODUCED OR USED WITHOUT THE EXPRESS WRITTEN CONSENT OF LAIRD CONNECTIVITY, INC.
Greg KH Dec. 1, 2021, 6:05 p.m. UTC | #43
On Wed, Dec 01, 2021 at 05:55:32PM +0000, Boris Krasnovskiy wrote:
> THIS MESSAGE, ANY ATTACHMENT(S), AND THE INFORMATION CONTAINED HEREIN MAY BE PROPRIETARY TO LAIRD CONNECTIVITY, INC. AND/OR ANOTHER PARTY, AND MAY FURTHER BE INTENDED TO BE KEPT CONFIDENTIAL. IF YOU ARE NOT THE INTENDED RECIPIENT, PLEASE DELETE THE EMAIL AND ANY ATTACHMENTS, AND IMMEDIATELY NOTIFY THE SENDER BY RETURN EMAIL. THIS MESSAGE AND ITS CONTENTS ARE THE PROPERTY OF LAIRD CONNECTIVITY, INC. AND MAY NOT BE REPRODUCED OR USED WITHOUT THE EXPRESS WRITTEN CONSENT OF LAIRD CONNECTIVITY, INC.

Now deleted.
Greg KH Dec. 1, 2021, 6:05 p.m. UTC | #44
On Wed, Dec 01, 2021 at 05:19:37PM +0000, Boris Krasnovskiy wrote:
> THIS MESSAGE, ANY ATTACHMENT(S), AND THE INFORMATION CONTAINED HEREIN MAY BE PROPRIETARY TO LAIRD CONNECTIVITY, INC. AND/OR ANOTHER PARTY, AND MAY FURTHER BE INTENDED TO BE KEPT CONFIDENTIAL. IF YOU ARE NOT THE INTENDED RECIPIENT, PLEASE DELETE THE EMAIL AND ANY ATTACHMENTS, AND IMMEDIATELY NOTIFY THE SENDER BY RETURN EMAIL. THIS MESSAGE AND ITS CONTENTS ARE THE PROPERTY OF LAIRD CONNECTIVITY, INC. AND MAY NOT BE REPRODUCED OR USED WITHOUT THE EXPRESS WRITTEN CONSENT OF LAIRD CONNECTIVITY, INC.

Now deleted.
Jason A. Donenfeld Dec. 1, 2021, 6:24 p.m. UTC | #45
On Wed, Dec 1, 2021 at 12:19 PM Simo Sorce <simo@redhat.com> wrote:
> that much it is, and it is a required one. However having worked a lot
> on this I can tell you there is actually real cryptographic value in
> the requirements FIPS introduced over the years
> Well I think most of the requirements are sane practices, hopefully
> controversial stuff will be minimal.
> I happen to think quite a few of the requirements are actually good
> ideas to implement to improve the guarantees of randomness

If you think there are good ways to improve the RNG, of course send
patches for this, justifying why, taking into account recent research
into the topic you wish to patch, etc. Don't write, "because FIPS";
instead argue rationale for each patch. And if you _do_ feel the need
to appeal to authority, perhaps links to the various eprint papers you
consulted would be worthwhile. Preferably you're able to do this in a
small, incremental way, with small standalone patchsets, instead of
gigantic series.
Jason A. Donenfeld Dec. 1, 2021, 6:29 p.m. UTC | #46
On Wed, Dec 1, 2021 at 12:19 PM Simo Sorce <simo@redhat.com> wrote:
> Unfortunately userspace is not an option for kernel's own cryptography.

I'm actually sort of curious to learn which specific uses of
get_random_bytes you're concerned about. ECC keygen? What else?
Jeffrey Walton Dec. 2, 2021, 12:24 a.m. UTC | #47
On Wed, Dec 1, 2021 at 1:25 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>
> On Wed, Dec 1, 2021 at 12:19 PM Simo Sorce <simo@redhat.com> wrote:
> > that much it is, and it is a required one. However having worked a lot
> > on this I can tell you there is actually real cryptographic value in
> > the requirements FIPS introduced over the years
> > Well I think most of the requirements are sane practices, hopefully
> > controversial stuff will be minimal.
> > I happen to think quite a few of the requirements are actually good
> > ideas to implement to improve the guarantees of randomness
>
> If you think there are good ways to improve the RNG, of course send
> patches for this, justifying why, taking into account recent research
> into the topic you wish to patch, etc. Don't write, "because FIPS";
> instead argue rationale for each patch. And if you _do_ feel the need
> to appeal to authority, perhaps links to the various eprint papers you
> consulted would be worthwhile. Preferably you're able to do this in a
> small, incremental way, with small standalone patchsets, instead of
> gigantic series.

I may be parsing things incorrectly, but you seem to be rejecting the
NIST requirements, and then positioning your personal opinion as
superior. It sounds like one authority is being replaced by another.
Perhaps I am missing something.

I am also guessing you've never read the relevant NIST documents. The
documents state the security goals and provide the steps to achieve
them in an implementation.

Jeff
Greg KH Dec. 2, 2021, 7:12 a.m. UTC | #48
On Wed, Dec 01, 2021 at 07:24:43PM -0500, Jeffrey Walton wrote:
> On Wed, Dec 1, 2021 at 1:25 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> >
> > On Wed, Dec 1, 2021 at 12:19 PM Simo Sorce <simo@redhat.com> wrote:
> > > that much it is, and it is a required one. However having worked a lot
> > > on this I can tell you there is actually real cryptographic value in
> > > the requirements FIPS introduced over the years
> > > Well I think most of the requirements are sane practices, hopefully
> > > controversial stuff will be minimal.
> > > I happen to think quite a few of the requirements are actually good
> > > ideas to implement to improve the guarantees of randomness
> >
> > If you think there are good ways to improve the RNG, of course send
> > patches for this, justifying why, taking into account recent research
> > into the topic you wish to patch, etc. Don't write, "because FIPS";
> > instead argue rationale for each patch. And if you _do_ feel the need
> > to appeal to authority, perhaps links to the various eprint papers you
> > consulted would be worthwhile. Preferably you're able to do this in a
> > small, incremental way, with small standalone patchsets, instead of
> > gigantic series.
> 
> I may be parsing things incorrectly, but you seem to be rejecting the
> NIST requirements, and then positioning your personal opinion as
> superior. It sounds like one authority is being replaced by another.
> Perhaps I am missing something.
> 
> I am also guessing you've never read the relevant NIST documents. The
> documents state the security goals and provide the steps to achieve
> them in an implementation.

Ok, I think this thread has gone on long enough without any real
patches.

Please, if you want to support NIST, or any other type of thing, submit
patches that implement what you think will help achieve this.  Absent of
that, we have no idea what NIST or any other random document aims to
require or wish.

thanks,

greg k-h
John Haxby Dec. 2, 2021, 3:50 p.m. UTC | #49
> On 2 Dec 2021, at 07:12, Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
> 
> On Wed, Dec 01, 2021 at 07:24:43PM -0500, Jeffrey Walton wrote:
>> On Wed, Dec 1, 2021 at 1:25 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>>> 
>>> On Wed, Dec 1, 2021 at 12:19 PM Simo Sorce <simo@redhat.com> wrote:
>>>> that much it is, and it is a required one. However having worked a lot
>>>> on this I can tell you there is actually real cryptographic value in
>>>> the requirements FIPS introduced over the years
>>>> Well I think most of the requirements are sane practices, hopefully
>>>> controversial stuff will be minimal.
>>>> I happen to think quite a few of the requirements are actually good
>>>> ideas to implement to improve the guarantees of randomness
>>> 
>>> If you think there are good ways to improve the RNG, of course send
>>> patches for this, justifying why, taking into account recent research
>>> into the topic you wish to patch, etc. Don't write, "because FIPS";
>>> instead argue rationale for each patch. And if you _do_ feel the need
>>> to appeal to authority, perhaps links to the various eprint papers you
>>> consulted would be worthwhile. Preferably you're able to do this in a
>>> small, incremental way, with small standalone patchsets, instead of
>>> gigantic series.
>> 
>> I may be parsing things incorrectly, but you seem to be rejecting the
>> NIST requirements, and then positioning your personal opinion as
>> superior. It sounds like one authority is being replaced by another.
>> Perhaps I am missing something.
>> 
>> I am also guessing you've never read the relevant NIST documents. The
>> documents state the security goals and provide the steps to achieve
>> them in an implementation.
> 
> Ok, I think this thread has gone on long enough without any real
> patches.
> 
> Please, if you want to support NIST, or any other type of thing, submit
> patches that implement what you think will help achieve this.  Absent of
> that, we have no idea what NIST or any other random document aims to
> require or wish.


Part of the problem here is that NIST (and the concomitant fips certification) is a moving target.   A couple of years ago, we were fine. Today's requirements are different, tomorrow's will be different again.  Today's requirements being different are what resulted in the small patch I mentioned earlier.

You suggested, Greg, that I submit that and see what happens.   I can take a hint :) so I'm working on that as a possible way forward to decouple things a bit without too much churn.

jch



> 
> thanks,
> 
> greg k-h
Sandy Harris Dec. 4, 2021, 9:53 a.m. UTC | #50
Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:

> Also, why does any of this have to be in the kernel at all?

The kernel has had random(4) since Ted invented it sometime in
the 90s. There's no question it's a good idea; that's why all the BSDs
& some others have copied it. The only questions here are whether
it could be made FIPS compliant & whether it should be.

> If FIPS requires a deterministic random number generator
> that will not allow entropy to be acquired from hardware
> or external inputs,

It doesn't require that at all; in fact their DRNG design
requires an external source of random bits. However, it
requires that the source be certified & that would be a
problem for us. Intel & others might be able to get their
random number instructions certified and vendors of
crypto or SOC chips might get theirs certified, but the
kernel community could not do that.

I think the kernel's entropy collection routines are good
enough that they could, in principle, be certified, but
that would involve some work & considerable money.

> why does the
> kernel care at all?  Just write a fips_random.so library and get it
> certified and have any userspace code that cares about such a crazy
> thing to use that instead.

That does not solve the problem. The library would
also need a certified source of random inputs, so
to get it certified you'd have to get something else
certified first -- random(4), an instruction or a hardware
rng.
Marcelo Henrique Cerri Dec. 10, 2021, 1:43 a.m. UTC | #51
On Wed, Dec 01, 2021 at 11:02:38AM -0500, Jason A. Donenfeld wrote:
> Hi Simo,
> 
> I think various folks have said this during the various discussions on this
> topic over the years, in addition to myself, but I suppose I'll reiterate my
> general views on FIPS in this context.
> 
> FIPS is about compliance and certification. From a cryptographic point of
> view, there might be some good ideas, some dated ideas, some superfluous but
> harmless ideas, and so forth. But the reason that you want it for your
> customers is because you think your product will become more valuable or
> useful to customers if it checks that green compliance checkbox. I don't think
> we disagree about this being the motivation.
> 
> Now typically the kernel interoperates with lots of things and implements many
> different specifications. It supports scores of network protocols, IPsec
> cipher suites, USB quirks, SCSI hacks, you name it. The implementation of
> these drivers is always up to the author and hopefully kernel developers at
> large do the best job they can with the implementation, but the hardware or
> protocol they're interfacing with is not up to the author, by virtue of it
> being external to the kernel. It's not like instantiating IPsec with single
> DES and MD4, or SM3 and SM4, etc. is so great, and it's not like the
> compendium of brilliant hacks in drivers/usb/host/pci-quirks.c is so great
> either. But these things all exist to talk to something *outside* of the
> kernel, and so we grit our teeth, and as I said, do the best we can to
> implement it well.
> 
> But the RNG isn't like that. In fact, the RNG is logically *required* to be
> not anything like that: it returns random bytes, and they must not have any
> distinguishing quality with other random bytes; otherwise we have a serious
> problem that needs fixing. And so, we carry things out according to the usual
> kernel developer mindset: we implement it as best as we can, using the best
> algorithms we can find, in a way most suitable for the kernel.
> 
> Then FIPS comes along and starts dictating things about *how* we implement it,
> and those things it dictates might not be exactly the same as what we would
> would be doing when doing best that we can, using the best algorithms we can
> find, and in the most suitable way for the kernel. And so it would seem that
> the goal of implementing the RNG as best as we can might potentially be at
> odds with the goal of getting that green compliance checkbox, because that
> checkbox oversteps its bounds a bit.
> 
> That's not to say, of course, that we shouldn't accept input on how we
> implement our algorithms from elsewhere. On the contrary, I think random.c has
> a *lot* to gain from incorporating newer ideas, and that the formalism and
> guidance from academic cryptographers is less "academic" than it once was and
> much more real world, implementable, and suitable for our uses. But, again,
> incorporating new ideas and accepting input on how to improve our code is very
> much not the same thing as following the FIPS laundry list for that green
> compliance checkbox. Maybe some parts do overlap -- and I'd love patches that
> improve the code alongside compelling cryptographic arguments -- but, again,
> we're talking about compliance here, and not a more welcome, "hey check out
> this document I found with a bunch of great ideas we should implement."
> 
> I would like the kernel to have an excellent CSPRNG, from a cryptographic
> point of view, from a performance point of view, from an API point of view. I
> think these motivations are consistent with how the kernel is generally
> developed. And I think front loading the motivations with an external
> compliance goal greatly deviates and even detracts from the way the kernel is
> generally developed.
> 
> Now the above is somewhat negative on FIPS, but the question can still be
> posed: does FIPS have a path forward in the RNG in the kernel? It's obviously
> not a resounding "yes", but I don't think it's a totally certain "no" either.
> It might be possible to find some wiggle room. I'm not saying that it is
> certainly possible to do that, but it might be.
> 
> Specifically, I think that if you change your perspective from, "how can we
> change the algorithms of the RNG to be FIPS" to "how can we bend FIPS within
> its limits so that having what customers want would minimally impact the
> quality of the RNG implementation or introduce undue maintenance burdens."
> This means: not refactoring the RNG into some large abstraction layer that's
> pluggable and supports multiple different implementations, not rewriting the
> world in a massive patchset, not adding clutter. Instead, perhaps there's a
> very, very minimal set of things that can be done that would be considerably
> less controversial. That will probably require from you and other FIPS
> enthusiasts some study and discussion at what the truly most minimal set of
> things required are to get you that green compliance checkbox. And hey --
> maybe it's still way too much and it doesn't work out here. But maybe it's not
> that much, or, as Greg suggested, maybe it winds up that your needs are
> actually satisfied just fine by something in userspace or userspace-adjacent.
> 
> So I don't know whether the FIPS has a path forward here, but if it does, I
> think the above is the general shape it would take. And in the mean time, I'm
> of course open to reviewing patches that improve the RNG in a cryptographic or
> algorithmic sense, rather than a purely compliance one.

Hi, Jason. How do you think we could approach that then?

Are you willing to discuss the FIPS 140-3 requirements that random.c
doesn't currently meet so we can dive deeper on how we could implement
them in a way that would improve the kernel other then simply
providing compliance to FIPS?

I believe that several requirements would be beneficial to random.c
(ie, health test, oversampling, entropy data collection). But so far
we lack proper direction on how to proceed and it would be better for
us to have a clear notion of what could be accepted before putting
more effort on yet another patch set.

I believe all the distros are interested in making progress on that,
but without a general guidance it makes very hard for us to
collaborate and we end up in the current situation in which each
distro is carrying its own "hack", as Simo mentioned before. Canonical
is in the same situation as the other distros and we are carrying an
workaround to wire up the crypto DRBG to random.c in order to archive
compliance.

We could also concentrate all the discussion in the linux-crypto
mailing list to facilitate this process, since right now I believe the
MAINTAINERS file doesn't have a specific mailing list associate to
random.c

> 
> Hopefully that helps you understand more about where we're coming from.
> 
> Regards,
> Jason
Greg KH Dec. 10, 2021, 6:46 a.m. UTC | #52
On Thu, Dec 09, 2021 at 10:43:37PM -0300, Marcelo Henrique Cerri wrote:
> Hi, Jason. How do you think we could approach that then?
> 
> Are you willing to discuss the FIPS 140-3 requirements that random.c
> doesn't currently meet so we can dive deeper on how we could implement
> them in a way that would improve the kernel other then simply
> providing compliance to FIPS?

Discussing things doesn't usually work well.  Let's see some working
patches first, that solve problems that you have with the current random
code, and we can go from there.

Again, like any other kernel patch submission, nothing new here at all.

> I believe all the distros are interested in making progress on that,
> but without a general guidance it makes very hard for us to
> collaborate and we end up in the current situation in which each
> distro is carrying its own "hack", as Simo mentioned before. Canonical
> is in the same situation as the other distros and we are carrying an
> workaround to wire up the crypto DRBG to random.c in order to archive
> compliance.

If everyone seems to think their patches are hacks, and are not worthy
of being submitted, then why do they think that somehow they are viable
for their users that are actually using them?

{sigh}

greg k-h
Marcelo Henrique Cerri Dec. 10, 2021, 9:30 a.m. UTC | #53
On Fri, Dec 10, 2021 at 07:46:24AM +0100, Greg Kroah-Hartman wrote:
> On Thu, Dec 09, 2021 at 10:43:37PM -0300, Marcelo Henrique Cerri wrote:
> > Hi, Jason. How do you think we could approach that then?
> > 
> > Are you willing to discuss the FIPS 140-3 requirements that random.c
> > doesn't currently meet so we can dive deeper on how we could implement
> > them in a way that would improve the kernel other then simply
> > providing compliance to FIPS?
> 
> Discussing things doesn't usually work well.  Let's see some working
> patches first, that solve problems that you have with the current random
> code, and we can go from there.
> 
> Again, like any other kernel patch submission, nothing new here at all.

Hi, Greg. I understand your point but we had plenty of patch
submissions already from Stephan, Nicolai and others and that didn't
work. So I am expecting that anybody taking over as the random.c
maintainer can at least provide some direction on that.

> 
> > I believe all the distros are interested in making progress on that,
> > but without a general guidance it makes very hard for us to
> > collaborate and we end up in the current situation in which each
> > distro is carrying its own "hack", as Simo mentioned before. Canonical
> > is in the same situation as the other distros and we are carrying an
> > workaround to wire up the crypto DRBG to random.c in order to archive
> > compliance.
> 
> If everyone seems to think their patches are hacks, and are not worthy
> of being submitted, then why do they think that somehow they are viable
> for their users that are actually using them?

Because although some people dislike it, FIPS is still a requirement
for many users. That's the reality and that will not change just
because there are some resistance against it.

The patches that distros are carrying are hacks because they try to
minimize risks while keeping the code as close as possible to
upstream. But that has several drawbacks, such as performance, limited
entropy sources an so on, that to me makes them not suitable for
upstream.

> 
> {sigh}
> 
> greg k-h
Greg KH Dec. 10, 2021, 9:48 a.m. UTC | #54
On Fri, Dec 10, 2021 at 06:30:03AM -0300, Marcelo Henrique Cerri wrote:
> On Fri, Dec 10, 2021 at 07:46:24AM +0100, Greg Kroah-Hartman wrote:
> > On Thu, Dec 09, 2021 at 10:43:37PM -0300, Marcelo Henrique Cerri wrote:
> > > Hi, Jason. How do you think we could approach that then?
> > > 
> > > Are you willing to discuss the FIPS 140-3 requirements that random.c
> > > doesn't currently meet so we can dive deeper on how we could implement
> > > them in a way that would improve the kernel other then simply
> > > providing compliance to FIPS?
> > 
> > Discussing things doesn't usually work well.  Let's see some working
> > patches first, that solve problems that you have with the current random
> > code, and we can go from there.
> > 
> > Again, like any other kernel patch submission, nothing new here at all.
> 
> Hi, Greg. I understand your point but we had plenty of patch
> submissions already from Stephan, Nicolai and others and that didn't
> work. So I am expecting that anybody taking over as the random.c
> maintainer can at least provide some direction on that.

Then submit patches to be reviewed!  This patch series was commented on
why it is not acceptable, so it's done with for now.

We can't go back in time and dig up old patch series to be reviewed now
unless they are actually refreshed and resubmitted.

Why isn't anyone doing that?

> > > I believe all the distros are interested in making progress on that,
> > > but without a general guidance it makes very hard for us to
> > > collaborate and we end up in the current situation in which each
> > > distro is carrying its own "hack", as Simo mentioned before. Canonical
> > > is in the same situation as the other distros and we are carrying an
> > > workaround to wire up the crypto DRBG to random.c in order to archive
> > > compliance.
> > 
> > If everyone seems to think their patches are hacks, and are not worthy
> > of being submitted, then why do they think that somehow they are viable
> > for their users that are actually using them?
> 
> Because although some people dislike it, FIPS is still a requirement
> for many users. That's the reality and that will not change just
> because there are some resistance against it.
> 
> The patches that distros are carrying are hacks because they try to
> minimize risks while keeping the code as close as possible to
> upstream. But that has several drawbacks, such as performance, limited
> entropy sources an so on, that to me makes them not suitable for
> upstream.

In other words, "the hacks we made to the random code are so bad we do
not want to submit them upstream for everyone to review as our names
would be on them and we would have to justify them to the world"?  :)

Given that there are no patches here to review by anyone, why is this
email thread still persisting?

Again, the only way forward is to submit changes that meet our
well-documented development process.  There's nothing "special" about
this very tiny .c file that is any different than the other 30 million
lines of kernel code we support that warrants a different process at
all.

greg k-h
Simo Sorce Dec. 10, 2021, 5:02 p.m. UTC | #55
On Fri, 2021-12-10 at 10:48 +0100, Greg Kroah-Hartman wrote:
> On Fri, Dec 10, 2021 at 06:30:03AM -0300, Marcelo Henrique Cerri wrote:
> > On Fri, Dec 10, 2021 at 07:46:24AM +0100, Greg Kroah-Hartman wrote:
> > > On Thu, Dec 09, 2021 at 10:43:37PM -0300, Marcelo Henrique Cerri wrote:
> > > > Hi, Jason. How do you think we could approach that then?
> > > > 
> > > > Are you willing to discuss the FIPS 140-3 requirements that random.c
> > > > doesn't currently meet so we can dive deeper on how we could implement
> > > > them in a way that would improve the kernel other then simply
> > > > providing compliance to FIPS?
> > > 
> > > Discussing things doesn't usually work well.  Let's see some working
> > > patches first, that solve problems that you have with the current random
> > > code, and we can go from there.
> > > 
> > > Again, like any other kernel patch submission, nothing new here at all.
> > 
> > Hi, Greg. I understand your point but we had plenty of patch
> > submissions already from Stephan, Nicolai and others and that didn't
> > work. So I am expecting that anybody taking over as the random.c
> > maintainer can at least provide some direction on that.
> 
> Then submit patches to be reviewed!  This patch series was commented on
> why it is not acceptable, so it's done with for now.
> 
> We can't go back in time and dig up old patch series to be reviewed now
> unless they are actually refreshed and resubmitted.
> 
> Why isn't anyone doing that?

I think people would at least like to know they are not spending a
bunch of time and work to have another patch series go into the void,
or be rejected again, *after* all the hard work is done, without a
foreword of what is acceptable.

> 
> > > > I believe all the distros are interested in making progress on that,
> > > > but without a general guidance it makes very hard for us to
> > > > collaborate and we end up in the current situation in which each
> > > > distro is carrying its own "hack", as Simo mentioned before. Canonical
> > > > is in the same situation as the other distros and we are carrying an
> > > > workaround to wire up the crypto DRBG to random.c in order to archive
> > > > compliance.
> > > 
> > > If everyone seems to think their patches are hacks, and are not worthy
> > > of being submitted, then why do they think that somehow they are viable
> > > for their users that are actually using them?
> > 
> > Because although some people dislike it, FIPS is still a requirement
> > for many users. That's the reality and that will not change just
> > because there are some resistance against it.
> > 
> > The patches that distros are carrying are hacks because they try to
> > minimize risks while keeping the code as close as possible to
> > upstream. But that has several drawbacks, such as performance, limited
> > entropy sources an so on, that to me makes them not suitable for
> > upstream.
> 
> In other words, "the hacks we made to the random code are so bad we do
> not want to submit them upstream for everyone to review as our names
> would be on them and we would have to justify them to the world"?  :)

Our patches are all public in our respective tress, with names and all.
The hacks are not necessarily *bad*, but they are changes made because
we could not put in what we think would be a better solution. They can
definitely be sent upstream.

> Given that there are no patches here to review by anyone, why is this
> email thread still persisting?

There is a will and a need to "improve" things, but given past absence
of feedback, people are trying to understand if there is any point in
trying to submit patches. Patches are work, and people like to know
they are not wasting their time completely before committing many more
hours.

> Again, the only way forward is to submit changes that meet our
> well-documented development process.  There's nothing "special" about
> this very tiny .c file that is any different than the other 30 million
> lines of kernel code we support that warrants a different process at
> all.

This very thread shows that there is an issue, people are not asking
for exceptions to the process, they are only asking for direction from
the maintainer so they can work productively and get some result, that
is all the "special" there is here.

Simo.
Willy Tarreau Dec. 11, 2021, 7:06 a.m. UTC | #56
On Fri, Dec 10, 2021 at 12:02:35PM -0500, Simo Sorce wrote:
> On Fri, 2021-12-10 at 10:48 +0100, Greg Kroah-Hartman wrote:
> > Given that there are no patches here to review by anyone, why is this
> > email thread still persisting?
> 
> There is a will and a need to "improve" things, but given past absence
> of feedback, people are trying to understand if there is any point in
> trying to submit patches. Patches are work, and people like to know
> they are not wasting their time completely before committing many more
> hours.

It is obviously natural to think this way, but you can also understand
that reviewing patches is extremely time consuming. And it's extremely
difficult to review a patch series which says "replace all that
infrastructure with a new one", especially when the motivations are
"comply with this or that standard" without the benefits being obvious
at all for those having to review those patches. And keep in mind that
those who you expect to review the code will have to maintain it, so if
the benefit is not obvious, why would they take the risk of breaking
something that's been working well enough or that has been easy enough
to improve or fix over time ?

My feeling from the beginning is that nobody felt brave enough to go
through these series because of this.

The normal way to propose changes is to say "some of our customers ask
for FIPS, we've looked at *what is missing* to accomplish that, first
it suggests/requires/mandates properties X, Y and Z which are currently
not supported, so these patches improve the current code by adding such
properties". And you don't patch "for FIPS", you patch to make the
existing code evolve to support such missing properties or features,
till the point you figure that nothing is missing anymore, and you can
tell your customers "now we comply with FIPS". And if it takes several
versions to reach that point, no problem, because each version continues
to work like before, possibly better, possibly not.

It's not different from supporting a new hardware. You don't bring in
a big patch series implementing all of the machine's device drivers in
an isolated area specific to that device. Instead you bring the various
parts this machine relies on (serial, pcie, usb, network etc), possibly
by improving existing drivers that are already very close or share some
common parts, and at the end you figure you have everything you need
and then you can proudly say "now we fully support this device".

This way of proceeding incrementally allows submitters not to waste
time coding for nothing, and those reviewing changes to make sure
they're not breaking everything, or to ask for some changes to stay
safe.

But this does mean that a list of incremental changes/additions has to
be established on the submitter's side, not a list of replacements.
Sometimes it is required to replace a part, but the justification has
to be technical, not "this part doesn't meet standard X or Y, let's
reinvent it". And such replacements need to be minimal so that it's
obvious they continue to provide exactly the same services and it's
almost impossible that a bisect lands on such a patch when something
stops working (i.e. if it happens it's just a coding bug and not a
design mistake).

> > Again, the only way forward is to submit changes that meet our
> > well-documented development process.  There's nothing "special" about
> > this very tiny .c file that is any different than the other 30 million
> > lines of kernel code we support that warrants a different process at
> > all.
> 
> This very thread shows that there is an issue, people are not asking
> for exceptions to the process, they are only asking for direction from
> the maintainer so they can work productively and get some result, that
> is all the "special" there is here.

At least it's visible in this very thread's subject that it's addressed
in a special way: "/dev/random - a new approach", i.e. "trash all what
we have and restart from scratch". This is exactly what is causing the
problem from the beginning in my opinion. But at this point I think
that Jason, Greg and others have already been saying it, so I'll stop.

Hoping this helps,

Willy
Stephan Mueller Dec. 11, 2021, 8:09 a.m. UTC | #57
Am Samstag, 11. Dezember 2021, 08:06:10 CET schrieb Willy Tarreau:

Hi Willy,

> On Fri, Dec 10, 2021 at 12:02:35PM -0500, Simo Sorce wrote:
> > On Fri, 2021-12-10 at 10:48 +0100, Greg Kroah-Hartman wrote:
> > > Given that there are no patches here to review by anyone, why is this
> > > email thread still persisting?
> > 
> > There is a will and a need to "improve" things, but given past absence
> > of feedback, people are trying to understand if there is any point in
> > trying to submit patches. Patches are work, and people like to know
> > they are not wasting their time completely before committing many more
> > hours.
> 
> It is obviously natural to think this way, but you can also understand
> that reviewing patches is extremely time consuming. And it's extremely
> difficult to review a patch series which says "replace all that
> infrastructure with a new one", especially when the motivations are
> "comply with this or that standard" without the benefits being obvious
> at all for those having to review those patches.

I am so surprised by such statements. Patch 00/15 lists in a bullet list the 
significant benefits of the LRNG. But seemingly nobody reads the introduction 
with its concise bullet list or the documentation. The FIPS bits are a tiny 
aspect of the whole effort (which even can be completely compiled out based on 
config options), the more significant aspects that have nothing to do with 
FIPS and benefit all are testability, performance, use of contemporary 
cryptography, and flexibility.

> But this does mean that a list of incremental changes/additions has to
> be established on the submitter's side, not a list of replacements.

Before I started the endeavor of the stand-alone patch of the LRNG, I 
developed cleanup patches to random.c in 2014 and 2015. I got massively 
discouraged to continue working on random.c as I did not get feedback from the 
maintainer. Some patches were taken, some were not without a comment... 

Ciao
Stephan
Willy Tarreau Dec. 11, 2021, 8:57 a.m. UTC | #58
Hi Stephan,

On Sat, Dec 11, 2021 at 09:09:55AM +0100, Stephan Müller wrote:
> > It is obviously natural to think this way, but you can also understand
> > that reviewing patches is extremely time consuming. And it's extremely
> > difficult to review a patch series which says "replace all that
> > infrastructure with a new one", especially when the motivations are
> > "comply with this or that standard" without the benefits being obvious
> > at all for those having to review those patches.
> 
> I am so surprised by such statements. Patch 00/15 lists in a bullet list the 
> significant benefits of the LRNG. But seemingly nobody reads the introduction 
> with its concise bullet list or the documentation. The FIPS bits are a tiny 
> aspect of the whole effort (which even can be completely compiled out based on 
> config options), the more significant aspects that have nothing to do with 
> FIPS and benefit all are testability, performance, use of contemporary 
> cryptography, and flexibility.

But this is where the problem is. You're not proposing to improve the
current one but to replace it. Who has enough energy to review some new
code that claims to be compatible with older one ? It requires to perform
a mental "diff" which is extremely complicated. There are possibly corner
cases in the current code that nobody knows about and that some code
currently relies on. Who wlil detect that you're not going to break them
with a fresh new implementation ?

Incremental changes allow to focus on the changes. You don't need to
know how everything else works, just that the modifications do not
break the part they are inserted into. This makes a huge difference,
and this is why everyone constantly insists on seeing small incremental
changes. Sometimes you'll notice that you can even see review from
different people for very close parts in the same file.

> > But this does mean that a list of incremental changes/additions has to
> > be established on the submitter's side, not a list of replacements.
> 
> Before I started the endeavor of the stand-alone patch of the LRNG, I 
> developed cleanup patches to random.c in 2014 and 2015. I got massively 
> discouraged to continue working on random.c as I did not get feedback from the 
> maintainer. Some patches were taken, some were not without a comment... 

We all know that this is extremely irritating. It happens everywhere and
in every project. Sometimes lack of time, lost messages, flipped priorities,
or lack of interest, or a combination of all of this. I do it myself from
time to time by accident and I really feel bad when this happens. That's
not much different than when you're reminding a coworker that you need
their help and they forget because of other priorities. And this must
never discourage one from pinging again and asking why there's no
response. But one thing is certain to me, it's that if a maintainer,
for any reason, doesn't respond to tiny patches to their code, there's
hardly any chance to see a response to a whole replacement.

Here Jason offered to invest time reviewing changes. If you have changes
to propose, why not try ? And even if it takes one year to get everything
done, who cares ? You seem to have been working on this for 7 years
already, it might be worth trying another approach.

Regards,
Willy
Marcelo Henrique Cerri Jan. 10, 2022, 1:23 p.m. UTC | #59
On Thu, Dec 09, 2021 at 10:43:37PM -0300, Marcelo Henrique Cerri wrote:
> On Wed, Dec 01, 2021 at 11:02:38AM -0500, Jason A. Donenfeld wrote:
> > Hi Simo,
> > 
> > I think various folks have said this during the various discussions on this
> > topic over the years, in addition to myself, but I suppose I'll reiterate my
> > general views on FIPS in this context.
> > 
> > FIPS is about compliance and certification. From a cryptographic point of
> > view, there might be some good ideas, some dated ideas, some superfluous but
> > harmless ideas, and so forth. But the reason that you want it for your
> > customers is because you think your product will become more valuable or
> > useful to customers if it checks that green compliance checkbox. I don't think
> > we disagree about this being the motivation.
> > 
> > Now typically the kernel interoperates with lots of things and implements many
> > different specifications. It supports scores of network protocols, IPsec
> > cipher suites, USB quirks, SCSI hacks, you name it. The implementation of
> > these drivers is always up to the author and hopefully kernel developers at
> > large do the best job they can with the implementation, but the hardware or
> > protocol they're interfacing with is not up to the author, by virtue of it
> > being external to the kernel. It's not like instantiating IPsec with single
> > DES and MD4, or SM3 and SM4, etc. is so great, and it's not like the
> > compendium of brilliant hacks in drivers/usb/host/pci-quirks.c is so great
> > either. But these things all exist to talk to something *outside* of the
> > kernel, and so we grit our teeth, and as I said, do the best we can to
> > implement it well.
> > 
> > But the RNG isn't like that. In fact, the RNG is logically *required* to be
> > not anything like that: it returns random bytes, and they must not have any
> > distinguishing quality with other random bytes; otherwise we have a serious
> > problem that needs fixing. And so, we carry things out according to the usual
> > kernel developer mindset: we implement it as best as we can, using the best
> > algorithms we can find, in a way most suitable for the kernel.
> > 
> > Then FIPS comes along and starts dictating things about *how* we implement it,
> > and those things it dictates might not be exactly the same as what we would
> > would be doing when doing best that we can, using the best algorithms we can
> > find, and in the most suitable way for the kernel. And so it would seem that
> > the goal of implementing the RNG as best as we can might potentially be at
> > odds with the goal of getting that green compliance checkbox, because that
> > checkbox oversteps its bounds a bit.
> > 
> > That's not to say, of course, that we shouldn't accept input on how we
> > implement our algorithms from elsewhere. On the contrary, I think random.c has
> > a *lot* to gain from incorporating newer ideas, and that the formalism and
> > guidance from academic cryptographers is less "academic" than it once was and
> > much more real world, implementable, and suitable for our uses. But, again,
> > incorporating new ideas and accepting input on how to improve our code is very
> > much not the same thing as following the FIPS laundry list for that green
> > compliance checkbox. Maybe some parts do overlap -- and I'd love patches that
> > improve the code alongside compelling cryptographic arguments -- but, again,
> > we're talking about compliance here, and not a more welcome, "hey check out
> > this document I found with a bunch of great ideas we should implement."
> > 
> > I would like the kernel to have an excellent CSPRNG, from a cryptographic
> > point of view, from a performance point of view, from an API point of view. I
> > think these motivations are consistent with how the kernel is generally
> > developed. And I think front loading the motivations with an external
> > compliance goal greatly deviates and even detracts from the way the kernel is
> > generally developed.
> > 
> > Now the above is somewhat negative on FIPS, but the question can still be
> > posed: does FIPS have a path forward in the RNG in the kernel? It's obviously
> > not a resounding "yes", but I don't think it's a totally certain "no" either.
> > It might be possible to find some wiggle room. I'm not saying that it is
> > certainly possible to do that, but it might be.
> > 
> > Specifically, I think that if you change your perspective from, "how can we
> > change the algorithms of the RNG to be FIPS" to "how can we bend FIPS within
> > its limits so that having what customers want would minimally impact the
> > quality of the RNG implementation or introduce undue maintenance burdens."
> > This means: not refactoring the RNG into some large abstraction layer that's
> > pluggable and supports multiple different implementations, not rewriting the
> > world in a massive patchset, not adding clutter. Instead, perhaps there's a
> > very, very minimal set of things that can be done that would be considerably
> > less controversial. That will probably require from you and other FIPS
> > enthusiasts some study and discussion at what the truly most minimal set of
> > things required are to get you that green compliance checkbox. And hey --
> > maybe it's still way too much and it doesn't work out here. But maybe it's not
> > that much, or, as Greg suggested, maybe it winds up that your needs are
> > actually satisfied just fine by something in userspace or userspace-adjacent.
> > 
> > So I don't know whether the FIPS has a path forward here, but if it does, I
> > think the above is the general shape it would take. And in the mean time, I'm
> > of course open to reviewing patches that improve the RNG in a cryptographic or
> > algorithmic sense, rather than a purely compliance one.
> 
> Hi, Jason. How do you think we could approach that then?
> 
> Are you willing to discuss the FIPS 140-3 requirements that random.c
> doesn't currently meet so we can dive deeper on how we could implement
> them in a way that would improve the kernel other then simply
> providing compliance to FIPS?
> 
> I believe that several requirements would be beneficial to random.c
> (ie, health test, oversampling, entropy data collection). But so far
> we lack proper direction on how to proceed and it would be better for
> us to have a clear notion of what could be accepted before putting
> more effort on yet another patch set.
> 
> I believe all the distros are interested in making progress on that,
> but without a general guidance it makes very hard for us to
> collaborate and we end up in the current situation in which each
> distro is carrying its own "hack", as Simo mentioned before. Canonical
> is in the same situation as the other distros and we are carrying an
> workaround to wire up the crypto DRBG to random.c in order to archive
> compliance.
>

Hoping that might help with the discussion and to explain why I do
consider those solutions a "hack", that's the patch we've been using
so far to achieve SP 800-90B compliance:

https://kernel.ubuntu.com/~mhcerri/0001-UBUNTU-SAUCE-random-Use-Crypto-API-DRBG-for-urandom-.patch


> We could also concentrate all the discussion in the linux-crypto
> mailing list to facilitate this process, since right now I believe the
> MAINTAINERS file doesn't have a specific mailing list associate to
> random.c
> 
> > 
> > Hopefully that helps you understand more about where we're coming from.
> > 
> > Regards,
> > Jason
> 
> -- 
> Regards,
> Marcelo
>
Jason A. Donenfeld Jan. 10, 2022, 2:11 p.m. UTC | #60
Hi Marcelo,

On Mon, Jan 10, 2022 at 2:24 PM Marcelo Henrique Cerri
<marcelo.cerri@canonical.com> wrote:
> Hoping that might help with the discussion and to explain why I do
> consider those solutions a "hack", that's the patch we've been using
> so far to achieve SP 800-90B compliance:
>
> https://kernel.ubuntu.com/~mhcerri/0001-UBUNTU-SAUCE-random-Use-Crypto-API-DRBG-for-urandom-.patch

Thanks for sending this in response to my request for it in our private thread.

Just to confirm, this little patch here gives you FIPS certification?

Jason
Theodore Ts'o Jan. 10, 2022, 2:29 p.m. UTC | #61
On Mon, Jan 10, 2022 at 03:11:46PM +0100, Jason A. Donenfeld wrote:
> On Mon, Jan 10, 2022 at 2:24 PM Marcelo Henrique Cerri
> <marcelo.cerri@canonical.com> wrote:
> > Hoping that might help with the discussion and to explain why I do
> > consider those solutions a "hack", that's the patch we've been using
> > so far to achieve SP 800-90B compliance:
> >
> > https://kernel.ubuntu.com/~mhcerri/0001-UBUNTU-SAUCE-random-Use-Crypto-API-DRBG-for-urandom-.patch
> 
> Thanks for sending this in response to my request for it in our private thread.
> 
> Just to confirm, this little patch here gives you FIPS certification?

There might be some FIPS certification labs that might be willing to
be taken in by the jitterentropy story, but when I've had private
communications from people who are familiar with the Intel
microarchitecture saying that jitterentropy is mostly "security by
obscurity", I'd be strongly opposed to replacing the current scheme
with something which is purely jitteretropy.

Perhaps an build-time option where one of the seeds into the CRNG is
"jitterentropy", but we keep everything else.  That way, jitterentropy
can still be TSA-style "security theatre", but we're not utterly
dependant on the "the CPU microarchitecture is SOOOOOOO complicated,
it *must* be unpredictable".

						- Ted
Jason A. Donenfeld Jan. 10, 2022, 2:38 p.m. UTC | #62
Hi Ted,

On Mon, Jan 10, 2022 at 3:31 PM Theodore Ts'o <tytso@mit.edu> wrote:
> There might be some FIPS certification labs that might be willing to
> be taken in by the jitterentropy story, but when I've had private
> communications from people who are familiar with the Intel
> microarchitecture saying that jitterentropy is mostly "security by
> obscurity", I'd be strongly opposed to replacing the current scheme
> with something which is purely jitteretropy.
>
> Perhaps an build-time option where one of the seeds into the CRNG is
> "jitterentropy", but we keep everything else.  That way, jitterentropy
> can still be TSA-style "security theatre", but we're not utterly
> dependant on the "the CPU microarchitecture is SOOOOOOO complicated,
> it *must* be unpredictable".

Yea, I'm not really compelled by it as something real that we'd
actually want to have for something serious. Keep in mind: this thread
isn't really about cryptography, but just about compliance nonsense.
BUT, if it turns out that the path to these people getting their green
compliance checkbox stamp isn't actually thousands of lines of new
code, but rather some glue bridging the /dev/urandom / getrandom(2)
API into the blah cryptoapi thing, that's... interesting news to me.
I'm not even saying, at this stage anyhow, that I want to do this, but
I do find it a very interesting data point. As I wrote in [1]:

> Specifically, I think that if you change your perspective from, "how can we
> change the algorithms of the RNG to be FIPS" to "how can we bend FIPS within
> its limits so that having what customers want would minimally impact the
> quality of the RNG implementation or introduce undue maintenance burdens."

We're now starting to get some idea about how this FIPS stuff bends.

Jason

[1] https://lore.kernel.org/lkml/CAHmME9qP9eYfPH+8eRvpx_tW8iAtDc-byVMvh4tFL_cABdsiOA@mail.gmail.com/
Marcelo Henrique Cerri Jan. 10, 2022, 3:07 p.m. UTC | #63
On Mon, Jan 10, 2022 at 09:29:04AM -0500, Theodore Ts'o wrote:
> On Mon, Jan 10, 2022 at 03:11:46PM +0100, Jason A. Donenfeld wrote:
> > On Mon, Jan 10, 2022 at 2:24 PM Marcelo Henrique Cerri
> > <marcelo.cerri@canonical.com> wrote:
> > > Hoping that might help with the discussion and to explain why I do
> > > consider those solutions a "hack", that's the patch we've been using
> > > so far to achieve SP 800-90B compliance:
> > >
> > > https://kernel.ubuntu.com/~mhcerri/0001-UBUNTU-SAUCE-random-Use-Crypto-API-DRBG-for-urandom-.patch
> > 
> > Thanks for sending this in response to my request for it in our private thread.

No problem. And sorry for the delay.

> > 
> > Just to confirm, this little patch here gives you FIPS certification?

It does because it basically replaces everything in random.c (for
urandom in this case) with the Crypto API DRBG, which is
compliant. Although it might be wiser to replace both urandom and
random in this case.

> 
> There might be some FIPS certification labs that might be willing to
> be taken in by the jitterentropy story, but when I've had private
> communications from people who are familiar with the Intel
> microarchitecture saying that jitterentropy is mostly "security by
> obscurity", I'd be strongly opposed to replacing the current scheme
> with something which is purely jitteretropy.
> 
> Perhaps an build-time option where one of the seeds into the CRNG is
> "jitterentropy", but we keep everything else.  That way, jitterentropy
> can still be TSA-style "security theatre", but we're not utterly
> dependant on the "the CPU microarchitecture is SOOOOOOO complicated,
> it *must* be unpredictable".
>

Hi, Theodore.

I might be missing something, but the Crypto API DRBG is seeded by
jitterentropy_rng and by get_random_bytes(), their outputs are both
concatenated and used as the seed. So I don't think that should be a
concern, right?


> 						- Ted
Theodore Ts'o Jan. 10, 2022, 5:38 p.m. UTC | #64
On Mon, Jan 10, 2022 at 03:38:08PM +0100, Jason A. Donenfeld wrote:
> 
> Yea, I'm not really compelled by it as something real that we'd
> actually want to have for something serious. Keep in mind: this thread
> isn't really about cryptography, but just about compliance nonsense.
> BUT, if it turns out that the path to these people getting their green
> compliance checkbox stamp isn't actually thousands of lines of new
> code, but rather some glue bridging the /dev/urandom / getrandom(2)
> API into the blah cryptoapi thing, that's... interesting news to me.
> I'm not even saying, at this stage anyhow, that I want to do this, but
> I do find it a very interesting data point.

The last time I had the displeasure of looking into the FIPS
certification, which granted, was over a decade ago when I was in
IBM's Linux Technology Center, what I learned was it all depends on
the FIPS certification lab.  NIST writes the documentation, but what
really matters is the FIPS certification lab that a hardware or
software vendor pays $$$$ to in order to get the magic certificate
which allows you to sell into *some* government contracts.  (When I
had to go through the all of the nonsense to get a TS/SCI clearance to
support the real-time kernel for all of the IBM servers for the
DDG/1000 Zumwalt Class destroyer, they didn't care about getting FIPS
certified.  I've also seen tighter security measures for computer
rooms at NYC financial companies than at a Top Secret machine root at
said defense contractor.  Go figure....)

The other thing I learned for those customers who *did* care, was that
the only thing that got certified was a specific binary image.  If you
replace the kernel or OpenSSL library with, say, a bugfixed version
that fixed an actively exploited zero day, *boom*, that would break
the certification and the system would no longer be FIPS certified.

Some FIPS labs would allow you to certify the "cryptographic core" of
the OpenSSL library, which the OpenSSL library would then dlopen, and
so as long as the bugfix was in, say, the ASN.1 parser, and you didn't
need to change the "cryptographic core" it was OK --- and you just
needed to hope that there weren't any bugs in the cryptographic core,
since then you wouldn't be allowed to fix it --- since FIPS compliance
was more important than, say, the *actual* security of the system in
question.

So yeah, as I said, it's all about TSA-style security theatre, and
when I worked for IBM and there was millions of dollars on the line, I
might have cared.  For upstream development, (and blessedly, this is
not something that my current employer has needed to worry about) I
care far less about it.

If we want to add a CONFIG_RANDOM_SECURITY_THEATRE build option which
diverts getrandom and /dev/urandom to use crypto/drbg, I'm going to
think it's a waste of time, and there are some things about
crypto/drbg that I'm not psyched about such as the fact that only
reseed after 2**20 calls to drbg_generate(), and the drbg statemachine
will initialize itself from get_random_bytes() in early boot, when the
CRNG is least likely to be securely initialized.  So **I** wouldn't
want to use it for my own personal security, but if it allows Ubuntu
to sell into the US govnerment market, my only hope is that this
wouldn't be inflicted on all of their customers, but only those US
Government customers who care (and as near as I can tell, this is
*not* all USG customers).

> > Specifically, I think that if you change your perspective from, "how can we
> > change the algorithms of the RNG to be FIPS" to "how can we bend FIPS within
> > its limits so that having what customers want would minimally impact the
> > quality of the RNG implementation or introduce undue maintenance burdens."
> 
> We're now starting to get some idea about how this FIPS stuff bends.

Well, if we optionally (if jitterentropy_rng is compiled in), we would
periodically pull from it as one additional entropy source into the
input_pool, it won't do any harm --- other than the CPU overhead
consumed by jitterentropy, of course.  Maybe that would make some
people happy, including some FIPS Labs?

I've also seen some FIPS certifications which didn't care about what
the kernel did, but only cared about what was in the OpenSSL library.
(Which is where the story about segregating out the cryptographic core
so that you could actually patch most zero-days without having to go
back to the FIPS certification lab, pay $$$, and wait months for the
updated binary to be certified.)

So I suspect that there will be a lot of anecdotal evidence, but the
only thing we can probably say with any amount of certainity is Your
Mileage May Vary.

Cheers,

						- Ted
Eric Biggers Jan. 10, 2022, 6:29 p.m. UTC | #65
On Mon, Jan 10, 2022 at 12:38:00PM -0500, Theodore Ts'o wrote:
> If we want to add a CONFIG_RANDOM_SECURITY_THEATRE build option which
> diverts getrandom and /dev/urandom to use crypto/drbg, I'm going to
> think it's a waste of time, and there are some things about
> crypto/drbg that I'm not psyched about such as the fact that only
> reseed after 2**20 calls to drbg_generate(), and the drbg statemachine
> will initialize itself from get_random_bytes() in early boot, when the
> CRNG is least likely to be securely initialized.  So **I** wouldn't
> want to use it for my own personal security, but if it allows Ubuntu
> to sell into the US govnerment market, my only hope is that this
> wouldn't be inflicted on all of their customers, but only those US
> Government customers who care (and as near as I can tell, this is
> *not* all USG customers).
> 

So just a few thoughts:

Ubuntu, Red Hat, and Oracle all have patches which do this.  They differ
slightly; e.g., Ubuntu's patch only changes /dev/urandom while the others change
/dev/random and getrandom() too.  But the idea is the same: the userspace
interfaces to the RNG are changed to get output from a SP800-90A DRBG
(crypto/drbg.c) rather than the Linux RNG directly.  The SP800-90A DRBG in turn
is seeded from from two entropy sources combined: the Linux RNG
(get_random_bytes()) and jitterentropy (crypto/jitterentropy.c).

My understanding (and I could be totally wrong -- I am still trying to reverse
engineer all the requirements for this certification stuff) is that the reason
that these distros need this is they are certifying the whole kernel image as a
FIPS cryptographic module, and that implies that cryptographic random numbers
must conform to the SP800-90{A-C} documents.  The problem is that ChaCha20 isn't
considered an approved DRBG algorithm, nor do Linux's entropy sources have
SP800-90B continuous health-tests.  Therefore, get_random_bytes() is considered
to provide no entropy.  crypto/drbg.c works around this by using an approved
DRBG algorithm and by using jitterentropy which has SP800-90B tests.

I think the reason people are considering this to be a hack is because on paper
it ignores Linux's main RNG.  It's still *used* as an extra entropy input, but
on paper it's credited with no entropy.  That seems a bit odd.

However, even Stephan's patchset has the same issues, IIUC.  Stephan's patchset
still keeps get_random_bytes() using ChaCha20, and it provides an option to
layer crypto/drbg.c on top of it for userspace output.  So I'm not sure how much
of a hack it really is, if the supposed non-hack is basically the same.

Now, the idea of certifying the whole kernel as a FIPS cryptographic module is
stupid, given that it prevents the kernel from being updated to fix security
vulnerabilities.  However, I've been told that essentially the same RNG issues
also arise for NIAP certification of mobile devices
(https://www.niap-ccevs.org/MMO/PP/PP_MDF_V3.2.pdf), which looks at entropy
system-wide.  NIAP similarly doesn't consider ChaCha20 to be an allowed DRBG
algorithm, so they consider the entropy to be constantly depleting, and it "runs
out".  (There have been devices that passed NIAP despite this, but I've been
told that this was an oversight.)  Wiring up /dev/{u,}random and getrandom() to
crypto/drbg.c would avoid this issue too.

So again, I could be totally wrong, as I am trying to reverse engineer the
requirements here --- but to me it seems that a small patch to provide an option
to use crypto/drbg.c could solve both the FIPS and NIAP certification problems.

If Stephan could elaborate on what his patchset does that is better (as far as
certification is concerned, at least -- I know his patchset has some other
advantages such as eliminating non-cryptographic entropy processing), that would
be helpful to illuminate anything I may be missing.

- Eric
Jason A. Donenfeld Jan. 10, 2022, 6:44 p.m. UTC | #66
On Mon, Jan 10, 2022 at 4:08 PM Marcelo Henrique Cerri
<marcelo.cerri@canonical.com> wrote:
> > Just to confirm, this little patch here gives you FIPS certification?
> It does

On Mon, Jan 10, 2022 at 7:29 PM Eric Biggers <ebiggers@kernel.org> wrote:
> Now, the idea of certifying the whole kernel as a FIPS cryptographic module is
> stupid

Alright, so if that's the case, then what you ostensibly want is:
a) Some cryptoapi users to use crypto_rng_get_bytes, as they already
do now. (In a private thread with Simo, I pointed out a missing place
and encouraged him to send a patch for that but none has arrived.)
b) Userspace to use some other RNG.

(a) is basically already done.

(b) can be accomplished in userspace by just (i) disabling getrandom()
(making it return ENOSYS), and then (ii) replacing the /dev/urandom
path with a CUSE device or similar.

I suppose (b.i) might be able to be done with some bpf seccomp cgroup
situation. Or, if that's problematic, somebody could propose a
"disable getrandom(2)" cmdline option. That doesn't seem very hard.
And (b.ii) could use combined inputs from /dev/urandom and whatever
FIPSy userspace jitter entropy daemon you have.

In order to prevent the actual security from regressing on this, all
you have to do is ensure that you're always using at least 32 bytes
from the kernel's real /dev/urandom, and then whatever you add on top
of that becomes just for the certification aspect. As your various
green compliance checkboxes change over time and per region, you can
just swap out the extra-paper-pushing-bytes-on-top with whatever the
particular requirements of a certification body are. And you get to do
this all in userspace.

Marcelo/Simo - could you tell me what you find deficient about that
plan? It strikes me that this would give you maximum flexibility and
pretty much accomplish the goals?

Thanks,
Jason
Simo Sorce Jan. 10, 2022, 7:41 p.m. UTC | #67
On Mon, 2022-01-10 at 19:44 +0100, Jason A. Donenfeld wrote:
> On Mon, Jan 10, 2022 at 4:08 PM Marcelo Henrique Cerri
> <marcelo.cerri@canonical.com> wrote:
> > > Just to confirm, this little patch here gives you FIPS certification?
> > It does
> 
> On Mon, Jan 10, 2022 at 7:29 PM Eric Biggers <ebiggers@kernel.org> wrote:
> > Now, the idea of certifying the whole kernel as a FIPS cryptographic module is
> > stupid

Not that it is not the whole kernel, but a "module boundary" is drawn
around the crypto API and vicinity.
It would be really nice if this whole "boundary" could be built as a
single binary module to be loaded in the kernel in fips mode. That way
we could update the rest of the kernel w/o rebuilding the module, but
we are not there.

Rebuilding the kernel does technically invalidate certification however
NIST themselves tells people to care first about the security of the
systems as long as the vendor is undergoing or promising certification
of the patched kernel.

There is an assumption of good faith.

> Alright, so if that's the case, then what you ostensibly want is:
> a) Some cryptoapi users to use crypto_rng_get_bytes, as they already
> do now. (In a private thread with Simo, I pointed out a missing place
> and encouraged him to send a patch for that but none has arrived.)

I noted your point, just haven' had time to act on it.

> b) Userspace to use some other RNG.
> 
> (a) is basically already done.
> 
> (b) can be accomplished in userspace by just (i) disabling getrandom()
> (making it return ENOSYS), and then (ii) replacing the /dev/urandom
> path with a CUSE device or similar.

While this is technically possible it is not very helpful, as it
requires downstream patching of userspace programs, most of which do
not have either runtime nor compile time switches to change the used
random device.

> I suppose (b.i) might be able to be done with some bpf seccomp cgroup
> situation. Or, if that's problematic, somebody could propose a
> "disable getrandom(2)" cmdline option. That doesn't seem very hard.
> And (b.ii) could use combined inputs from /dev/urandom and whatever
> FIPSy userspace jitter entropy daemon you have.

It is simply easier to just patch /dev/[u]random/getrandom() to use a
certified DRBG in FIPS mode, although we also considered all the
options you mentioned we couldn't really find a good reason to add 
more work, and make a more complicated solution when it is simple to
wire up the correct DRBG to the random device userspace applications
use and is the de facto standard API for obtaining good random numbers.

> In order to prevent the actual security from regressing on this, all
> you have to do is ensure that you're always using at least 32 bytes
> from the kernel's real /dev/urandom, and then whatever you add on top
> of that becomes just for the certification aspect. As your various
> green compliance checkboxes change over time and per region, you can
> just swap out the extra-paper-pushing-bytes-on-top with whatever the
> particular requirements of a certification body are. And you get to do
> this all in userspace.

You can do the whole jitterbug in userspace, but that is simply not
efficient and too disruptive (the above patching of all downstream
usage).

> 
> Marcelo/Simo - could you tell me what you find deficient about that
> plan? It strikes me that this would give you maximum flexibility and
> pretty much accomplish the goals?

My goal is to deviate as little as possible both in kernel and user-
space from what upstreams do. Creating new interfaces is easy, making 
people use them is almost impossible. Witness the process in getting
people to use getrandom() 


Let me also add that NIST requirements are not capricious, they are
written by people that study entropy sources and random generation as
their job and know what they are doing, I err on the side of giving
them credit. The requirements set by the various 90A/90B/90C documents
are about raising the bar, to guarantee that random number generators
are actually "certifiably" good. There are entropy assessment performed
by the labs as part of the certification process to insure the random
source is a good source and does produce output that passes randomness
tests.  I personally think the kernel would benefit from implementing
those "checkboxes", it is basically like implementing a sane CI/CD and
testing environment.

To answer to Ted,
every certification program necessarily requires a certain amount of
bureaucracy, especially when governments are involved, but that doesn't
mean that it's all security theater.

The FIPS certification process has changed over the years as well not
just the requirements. Until a few years ago the requirement to use
FIPS certified cryptography could be waived, and because very few
consumer programs were certified a lot of agencies considered it just a
burden and didn't care much. That has changed, it is now required as a
matter of law for most government agencies, and the waiver process has
been discontinued. So we really need to provide FIPS certification to
our public sector customers, moreover various other security standards
now reference FIPS standards, so it is extending beyond government
agencies and their contractors.

FIPS is painful for us undergoing certification, but as a program it
also does have positive effects. We scrutinize all cryptographic
modules a lot more than we used to, we have a lot more testing than we
used to and a lot more confidence in the solidity of the provided
cryptography in the Linux world also thanks to this scrutiny. I wish
the certification process was less painful for sure, but I believe it
does add value when done sensibly.

Simo.
Theodore Ts'o Jan. 10, 2022, 7:49 p.m. UTC | #68
On Mon, Jan 10, 2022 at 07:44:23PM +0100, Jason A. Donenfeld wrote:
> b) Userspace to use some other RNG.
> 
> (b) can be accomplished in userspace by just (i) disabling getrandom()
> (making it return ENOSYS), and then (ii) replacing the /dev/urandom
> path with a CUSE device or similar.

I don't think you even need to do this.  In general, you need FIPS
certification for some specific use cases / application.  For example,
if you're going for PCI compliance, then you might only need FIPS
compliance for your OpenSSL library.  What the FIPS certification lab
might consider acceptable for its entropy for its DRBG is an
interesting question.  For some, simply having the OpenSSL library use
RDSEED or RDRAND might be sufficient.  Or it could talk to an actual
physical RNG device.

So disabling getrandom() is probably not necessary, just so long as
you can demonstrate that the FIPS cryptographic module --- i.e., the
OpenSSL library --- is getting its entropy from an acceptable source.

I suspect what's actually going on is that some enterprise customers
have FIPS complaince on a check-off list, and they aren't actually
getting a formal FIPS certification.  Or they only need something to
wave under the noses of their PCI certification company, and so the
question is what makes them happy.

Going into the details of whether ChaCha20 is blessed by FIPS is
probably more into technical weeds than most of the people who *say*
they want FIPS certification actually will go.  After all, the
in-kernel DRBG is using as its "entropy source" the timing
instructions from a bunch of x86 assembly instructions which is
**soooo** complicated that people are willing to drink from the snake
oil and claim that it is secure.  Is it really?  Has FIPS said that
it's OK?  Not any more than they've said anything about ChaCha20!

And this is why some FIPS certification have gotten by just *fine*
with a pure userspace OpenSSL library as their FIPS cryptographic
module.  Where you draw the line between a "blessed" entropy source
and one that's just hand-waving is really at the discretion of the
certification lab.

Personally, if I was doing something that I really, *really* wanted to
be secure, I'd be mixing in several hardware RNG's.  Given that most
server and client platforms have a TPM, or some other hardened
security module, using that is probably the best bet of I was
architecting some that *really* needed to be secure.  But of course,
we're not talking about real security in this thread; we're talking
about whatever security theater will make the FIPS certification labs,
and the people who say they want FIPS on their check-off list, happy.  :-)

    	       	       	    	      	       - Ted
Eric Biggers Jan. 10, 2022, 8:05 p.m. UTC | #69
On Mon, Jan 10, 2022 at 02:41:33PM -0500, Simo Sorce wrote:
> On Mon, 2022-01-10 at 19:44 +0100, Jason A. Donenfeld wrote:
> > On Mon, Jan 10, 2022 at 4:08 PM Marcelo Henrique Cerri
> > <marcelo.cerri@canonical.com> wrote:
> > > > Just to confirm, this little patch here gives you FIPS certification?
> > > It does
> > 
> > On Mon, Jan 10, 2022 at 7:29 PM Eric Biggers <ebiggers@kernel.org> wrote:
> > > Now, the idea of certifying the whole kernel as a FIPS cryptographic module is
> > > stupid
> 
> Not that it is not the whole kernel, but a "module boundary" is drawn
> around the crypto API and vicinity.
> It would be really nice if this whole "boundary" could be built as a
> single binary module to be loaded in the kernel in fips mode. That way
> we could update the rest of the kernel w/o rebuilding the module, but
> we are not there.

FWIW, the "FIPS module as a loadable kernel module" approach was implemented in
the Android kernel; grep for "fips140" in branch "android13-5.10" of
https://android.googlesource.com/kernel/common.  It's a lot of work for nothing
IMO, but the FIPS certification lab being used is happy with the approach.
Note that random.c is outside of the FIPS module with this approach.

- Eric
Jason A. Donenfeld Jan. 10, 2022, 9:38 p.m. UTC | #70
Just in case you were curious...

On Mon, Jan 10, 2022 at 07:44:23PM +0100, Jason A. Donenfeld wrote:
> (b) can be accomplished in userspace by just (i) disabling getrandom()
> (making it return ENOSYS), and then (ii) replacing the /dev/urandom
> path with a CUSE device or similar.
> 
> I suppose (b.i) might be able to be done with some bpf seccomp cgroup
> situation. Or, if that's problematic, somebody could propose a
> "disable getrandom(2)" cmdline option. That doesn't seem very hard.
> And (b.ii) could use combined inputs from /dev/urandom and whatever
> FIPSy userspace jitter entropy daemon you have.

The below took all of 5 minutes to write. Should be easy to tweak this
for whatever flavors required.

====

/* Copyright (C) 2022 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
 *
 * Usage:
 *   # gcc -O2 jrandom.c `pkg-config fuse3 --cflags --libs` -o jrandom
 *   # ./jrandom
 *   # chmod 666 /dev/jrandom
 *   # ln -sf jrandom /dev/urandom
 *   # ln -sf jrandom /dev/random
 */


#define FUSE_USE_VERSION 31

#include <cuse_lowlevel.h>
#include <fuse_opt.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if_alg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

static int rng;

static void fipsrng_open(fuse_req_t req, struct fuse_file_info *fi)
{
	fuse_reply_open(req, fi);
}

static void fipsrng_read(fuse_req_t req, size_t size, off_t off,
			 struct fuse_file_info *fi)
{
	char random[128];
	ssize_t ret_bytes;

	if (size > sizeof(random))
		size = sizeof(random);

	ret_bytes = read(rng, random, size);
	if (ret_bytes < 0)
		fuse_reply_err(req, errno);
	else
		fuse_reply_buf(req, random, ret_bytes);
}

static void fipsrng_write(fuse_req_t req, const char *buf, size_t size,
			  off_t off, struct fuse_file_info *fi)
{
	/* Swallow it, we don't care. */
	fuse_reply_write(req, size);
}

static void fipsrng_ioctl(fuse_req_t req, int cmd, void *arg,
			  struct fuse_file_info *fi, unsigned flags,
			  const void *in_buf, size_t in_bufsz, size_t out_bufsz)
{
	/* TODO: implement the various RNG ioctls */
	fuse_reply_err(req, ENOSYS);
}

static const struct cuse_lowlevel_ops fipsrng_clop = {
	.open		= fipsrng_open,
	.read		= fipsrng_read,
	.write		= fipsrng_write,
	.ioctl		= fipsrng_ioctl,
};

int main(int argc, char **argv)
{
	static const struct sockaddr_alg sa = {
		.salg_family = AF_ALG,
		.salg_type = "rng",
		.salg_name = "jitterentropy_rng"
	};
	static const char *dev_info_argv[] = { "DEVNAME=jrandom" };
	static const struct cuse_info ci = {
		.dev_info_argc = 1,
		.dev_info_argv = dev_info_argv,
		.flags = CUSE_UNRESTRICTED_IOCTL
	};
	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
	int ret = 1, afalg;

	if (fuse_opt_parse(&args, NULL, NULL, NULL)) {
		fprintf(stderr, "failed to parse options\n");
		goto out;
	}

	afalg = socket(AF_ALG, SOCK_SEQPACKET, 0);
	if (afalg < 0) {
		perror("socket(AF_ALG)");
		goto out;
	}
	if (bind(afalg, (const struct sockaddr *)&sa, sizeof(sa)) < 0) {
		perror("bind(\"rng\", \"jitterentropy_rng\")");
		goto out;
	}
	rng = accept(afalg, NULL, 0);
	if (rng < 0) {
		perror("accept()");
		goto out;
	}
	ret = cuse_lowlevel_main(args.argc, args.argv, &ci, &fipsrng_clop, NULL);
out:
	fuse_opt_free_args(&args);
	return ret;
}
Jason A. Donenfeld Jan. 10, 2022, 10:19 p.m. UTC | #71
On Mon, Jan 10, 2022 at 9:18 PM Theodore Ts'o <tytso@mit.edu> wrote:
> In general, you need FIPS
> certification for some specific use cases / application.  For example,
> if you're going for PCI compliance, then you might only need FIPS
> compliance for your OpenSSL library.  What the FIPS certification lab
> might consider acceptable for its entropy for its DRBG is an
> interesting question.  For some, simply having the OpenSSL library use
> RDSEED or RDRAND might be sufficient.  Or it could talk to an actual
> physical RNG device.
>
> So disabling getrandom() is probably not necessary, just so long as
> you can demonstrate that the FIPS cryptographic module --- i.e., the
> OpenSSL library --- is getting its entropy from an acceptable source.

I don't know exactly what these people think they want, but what you
say seems probably correct.

> I suspect what's actually going on is that some enterprise customers
> have FIPS complaince on a check-off list, and they aren't actually
> getting a formal FIPS certification.  Or they only need something to
> wave under the noses of their PCI certification company, and so the
> question is what makes them happy.

Right.

> And this is why some FIPS certification have gotten by just *fine*
> with a pure userspace OpenSSL library as their FIPS cryptographic
> module.  Where you draw the line between a "blessed" entropy source
> and one that's just hand-waving is really at the discretion of the
> certification lab.

Hah, probably correct.

So, seen this way, and combined with the solution provided at [1] (or
similar) for people who think they need something there, it seems like
the FIPS people can likely get what they need without really needing
to involve the kernel anyway.

Jason

[1] https://lore.kernel.org/lkml/YdynXjhhuQfbYuSb@zx2c4.com/
Andy Lutomirski Jan. 11, 2022, 1:44 a.m. UTC | #72
On Mon, Jan 10, 2022, at 2:19 PM, Jason A. Donenfeld wrote:
> On Mon, Jan 10, 2022 at 9:18 PM Theodore Ts'o <tytso@mit.edu> wrote:
>> In general, you need FIPS
>> certification for some specific use cases / application.  For example,
>> if you're going for PCI compliance, then you might only need FIPS
>> compliance for your OpenSSL library.  What the FIPS certification lab
>> might consider acceptable for its entropy for its DRBG is an
>> interesting question.  For some, simply having the OpenSSL library use
>> RDSEED or RDRAND might be sufficient.  Or it could talk to an actual
>> physical RNG device.
>>
>> So disabling getrandom() is probably not necessary, just so long as
>> you can demonstrate that the FIPS cryptographic module --- i.e., the
>> OpenSSL library --- is getting its entropy from an acceptable source.
>
> I don't know exactly what these people think they want, but what you
> say seems probably correct.
>
>> I suspect what's actually going on is that some enterprise customers
>> have FIPS complaince on a check-off list, and they aren't actually
>> getting a formal FIPS certification.  Or they only need something to
>> wave under the noses of their PCI certification company, and so the
>> question is what makes them happy.
>
> Right.
>
>> And this is why some FIPS certification have gotten by just *fine*
>> with a pure userspace OpenSSL library as their FIPS cryptographic
>> module.  Where you draw the line between a "blessed" entropy source
>> and one that's just hand-waving is really at the discretion of the
>> certification lab.
>
> Hah, probably correct.
>
> So, seen this way, and combined with the solution provided at [1] (or
> similar) for people who think they need something there, it seems like
> the FIPS people can likely get what they need without really needing
> to involve the kernel anyway.

Hmm, cute, but I think we can do a bit better. After all, this hack involves trusting a whole lot of code that is *not* intended for secrets to avoid having side channels.

So let’s solve it for real.  Have a driver (in a module) that exposes a /dev/urandom compatible interface to the CryptoAPI DRBG.  We can do a really nice job of it, and maybe it’ll be 100 lines of code.  People can do whatever they like with it in their container manager or boot scripts. And if it has a problem (where it’s *less* secure than the real urandom), we can say “I told you so”.

We can go one step farther: add an LSM hook to getrandom().  Then someone can hack up a fips_t policy for SELinux that turns off getrandom.

>
> Jason
>
> [1] https://lore.kernel.org/lkml/YdynXjhhuQfbYuSb@zx2c4.com/
Theodore Ts'o Jan. 11, 2022, 3:10 a.m. UTC | #73
On Mon, Jan 10, 2022 at 05:44:03PM -0800, Andy Lutomirski wrote:
> 
> So let’s solve it for real.  Have a driver (in a module) that
> exposes a /dev/urandom compatible interface to the CryptoAPI DRBG.
> We can do a really nice job of it, and maybe it’ll be 100 lines of
> code.  People can do whatever they like with it in their container
> manager or boot scripts. And if it has a problem (where it’s *less*
> secure than the real urandom), we can say “I told you so”.
> 
> We can go one step farther: add an LSM hook to getrandom().  Then
> someone can hack up a fips_t policy for SELinux that turns off
> getrandom.

These are both dangerous.  The first means creating a new device node
which effectively is /dev/drbg-random which could be bind mounted or
mknod'ed to be /dev/urandom.  But if the user boots a kernel that
doesn't support this new device node, it will mean opening
/dev/urandom will get ENODEV.

Similarly, getrandom(2) never fails.  By allowing a SELinux policy to
force it to fail with ENOSYS, or some other error, it means exposing
userspace code to a failure path that may not be as well tested.
Sure, *sane* code might fall back to opening /dev/urandom; but the
whole point of getrandom(2) was that it was a dumb, stupid interface
interface that could be safely used by application programmers.  Not
paranoid OS crypto engineers that carefully check the error returns of
all system calls, with appropriate fallbacks and making sure that code
always "fails safe".

Right now, the enterprise distros are doing their own thing, and quite
frankly, I don't see a problem with that.  If it turns out DRBG is
less secure (and there are some things that fill me with disquiet),
then let them take the economic consequences, since they are the ones
who are doing this for the economic advantages of trying to claim FIPS
compliance.

If we must support this in the upstream kernel, then configure it via
CONFIG_RANDOM_SECURITY_THEATRE which redirects getrandom(2) and
/dev/[u]random to DRBG.  I'd prefer that it be possible for someone to
put "random_security_theatre=0" on the boot command line which would
disable redirecting the interfaces to DRBG so if it turns out that
DRBG *is* less secure, we can give advice on how to turn it off
without requiring a patched kernel.  :-)

						- Ted
Willy Tarreau Jan. 11, 2022, 4:04 a.m. UTC | #74
On Mon, Jan 10, 2022 at 10:10:15PM -0500, Theodore Ts'o wrote:
> If we must support this in the upstream kernel, then configure it via
> CONFIG_RANDOM_SECURITY_THEATRE which redirects getrandom(2) and
> /dev/[u]random to DRBG.  I'd prefer that it be possible for someone to
> put "random_security_theatre=0" on the boot command line which would
> disable redirecting the interfaces to DRBG so if it turns out that
> DRBG *is* less secure, we can give advice on how to turn it off
> without requiring a patched kernel.  :-)

In this case, why not do it the other way around ? Instead of having
yet-another config option, just indicate that fips-like randoms are
enabled at boot via "random_security_theatre=1". Distros have their
solution which can even be documented for their customers and that's
done. Nobody uses it by default, the name is discouraging enough, but
for those who know they want it, it's easy to turn it on, and at the
same time it delivers them the reminder about what all this really is.

Willy
Matthew Garrett Jan. 11, 2022, 4:13 a.m. UTC | #75
On Mon, Jan 10, 2022 at 10:10:15PM -0500, Theodore Ts'o wrote:

> Right now, the enterprise distros are doing their own thing, and quite
> frankly, I don't see a problem with that.  If it turns out DRBG is
> less secure (and there are some things that fill me with disquiet),
> then let them take the economic consequences, since they are the ones
> who are doing this for the economic advantages of trying to claim FIPS
> compliance.

The goal is to identify a solution that avoids the enterprise kernels 
needing to do their own thing. They're in a position to globally 
LD_PRELOAD something to thunk getrandom() to improve compatibility if 
they want to, and they're also able to define the expected level of 
breakage if you enable FIPS mode. An approach that allows a single 
kernel to provide different policies in different contexts (eg, 
different namespaces could have different device nodes providing 
/dev/random) makes it easier to configure that based on customer 
requirements.

> If we must support this in the upstream kernel, then configure it via
> CONFIG_RANDOM_SECURITY_THEATRE which redirects getrandom(2) and
> /dev/[u]random to DRBG.  I'd prefer that it be possible for someone to
> put "random_security_theatre=0" on the boot command line which would
> disable redirecting the interfaces to DRBG so if it turns out that
> DRBG *is* less secure, we can give advice on how to turn it off
> without requiring a patched kernel.  :-)

The majority of enterprise customers don't need FIPS compliance, so all 
that would happen in that case is that the vendors would flip the sense 
of that config option and the docs for enterprise distros and mainline 
would be out of sync. I understand that this is a situation where a 
niche case is making life miserable for everyone else, and I understand 
that this is a hole that the enterprise world has dug for itself, but 
where there are people expressing a real tangible use case that exists 
for reasons outside their control, it really feels like we should try to 
find a solution that works for everyone.
Alexander Patrakov Jan. 11, 2022, 10:01 a.m. UTC | #76
(resending without HTML this time, sorry for a possible duplicate)
вт, 11 янв. 2022 г. в 09:13, Matthew Garrett <mjg59@srcf.ucam.org>:
> The goal is to identify a solution that avoids the enterprise kernels
> needing to do their own thing. They're in a position to globally
> LD_PRELOAD something to thunk getrandom() to improve compatibility if
> they want to, and they're also able to define the expected level of
> breakage if you enable FIPS mode. An approach that allows a single
> kernel to provide different policies in different contexts (eg,
> different namespaces could have different device nodes providing
> /dev/random) makes it easier to configure that based on customer
> requirements.

LD_PRELOAD is not a solution because of containers (that need to be
modified to make use of the preloadable library) and statically-linked
binaries.
Jason A. Donenfeld Jan. 11, 2022, 1:06 p.m. UTC | #77
Hi Andy,

On Tue, Jan 11, 2022 at 2:44 AM Andy Lutomirski <luto@kernel.org> wrote:
> So let’s solve it for real.  Have a driver (in a module) that

Um, let's not. This really isn't something the kernel needs to solve
here at all. There's a viable userspace solution. I see that the
discussion of something finally slightly technical (as opposed to just
compliance BS) has nerd sniped you a bit, but keep in mind what the
actual overall picture is. This isn't something that needs to be done.
My little CUSE thing (which I'm happy to develop out a bit more, even)
has the intent of fulfilling a compliance checkbox and nothing more.

Jason
Jason A. Donenfeld Jan. 11, 2022, 1:16 p.m. UTC | #78
Hi Ted,

On Tue, Jan 11, 2022 at 4:12 AM Theodore Ts'o <tytso@mit.edu> wrote:
> These are both dangerous.  The first means creating a new device node
> which effectively is /dev/drbg-random which could be bind mounted or
> mknod'ed to be /dev/urandom.  But if the user boots a kernel that
> doesn't support this new device node, it will mean opening
> /dev/urandom will get ENODEV.
>
> Similarly, getrandom(2) never fails.  By allowing a SELinux policy to
> force it to fail with ENOSYS, or some other error, it means exposing
> userspace code to a failure path that may not be as well tested.
> Sure, *sane* code might fall back to opening /dev/urandom; but the
> whole point of getrandom(2) was that it was a dumb, stupid interface
> interface that could be safely used by application programmers.  Not
> paranoid OS crypto engineers that carefully check the error returns of
> all system calls, with appropriate fallbacks and making sure that code
> always "fails safe".
>
> Right now, the enterprise distros are doing their own thing, and quite
> frankly, I don't see a problem with that.

I agree with you. I think enterprise distros ought to keep doing their
own thing here, and there's a clear solution that does this in
userspace, and also a pretty non-invasive patch from Marcelo to patch
the crap into the kernel need be.

I spent some time reading about FIPS certification, compliance, and
the requirements of various customers. One thing in particular leapt
out at me, which I think you've been saying over and over in this
thread but I didn't fully understand until this morning:

The goal is generally to have particular pieces of software or
particular solutions FIPS certified. And to do this, they start from
the top of the stack and move onward down. Most OSS software out there
today isn't really FIPS ready and oftentimes a full solution needs
modifications in one place or another. Other times, it's enough to
plug in the right userspace crypto libraries. And I noticed in looking
at things that are FIPS certified that random number generation tends
to go through a userspace abstraction layer. And, it looks like these
abstraction layers all have FIPS-able RNG hooks. You mentioned OpenSSL
earlier, and it looks like even libgcrypt and wolfSSL have an
abstraction layer for this.

In other words, it's not even so clear that people who need FIPS
compliance really need /dev/urandom and such to be FIPS compliant as
part of that. And the ones who think they do for whatever security
theater nonsense can happily load up that CUSE thing I made, apply a
deliberately-downstream patch, or whatever other clever solution.

So indeed it really doesn't seem like this is something the kernel
needs to be doing.

Jason
Andy Lutomirski Jan. 11, 2022, 3:10 p.m. UTC | #79
On Tue, Jan 11, 2022, at 5:06 AM, Jason A. Donenfeld wrote:
> Hi Andy,
>
> On Tue, Jan 11, 2022 at 2:44 AM Andy Lutomirski <luto@kernel.org> wrote:
>> So let’s solve it for real.  Have a driver (in a module) that
>
> Um, let's not. This really isn't something the kernel needs to solve
> here at all. There's a viable userspace solution. I see that the
> discussion of something finally slightly technical (as opposed to just
> compliance BS) has nerd sniped you a bit, but keep in mind what the
> actual overall picture is. This isn't something that needs to be done.
> My little CUSE thing (which I'm happy to develop out a bit more, even)
> has the intent of fulfilling a compliance checkbox and nothing more.
>


Can you develop your CUSE thing enough that it’s credibly safe against side channels?  If so, fine.

I admit this is all rather absurd. FIPS aware userspace can do whatever it wants, and
It should be aware that /dev/urandom IS NOT FIPS.  What’s the problem?  rand(3) isn’t FIPS either, but no one puts person-years of effort into trying to paint it FIPS-colored
Theodore Ts'o Jan. 11, 2022, 4:08 p.m. UTC | #80
On Tue, Jan 11, 2022 at 02:16:30PM +0100, Jason A. Donenfeld wrote:
> I spent some time reading about FIPS certification, compliance, and
> the requirements of various customers. One thing in particular leapt
> out at me, which I think you've been saying over and over in this
> thread but I didn't fully understand until this morning:
> 
> The goal is generally to have particular pieces of software or
> particular solutions FIPS certified. And to do this, they start from
> the top of the stack and move onward down. Most OSS software out there
> today isn't really FIPS ready and oftentimes a full solution needs
> modifications in one place or another. Other times, it's enough to
> plug in the right userspace crypto libraries. And I noticed in looking
> at things that are FIPS certified that random number generation tends
> to go through a userspace abstraction layer. And, it looks like these
> abstraction layers all have FIPS-able RNG hooks. You mentioned OpenSSL
> earlier, and it looks like even libgcrypt and wolfSSL have an
> abstraction layer for this.

I know this thread is about security theatre, not real security, but
there's an even more important reason why the FIPS cryptographic
module should be as high in the stack as possible (e.g., in
userspace).  Let's consider as, Albert Einstein would put it, the
following gedanken experiment:

Let's presume that in 2008, there was a FIPS-140 certified OS
designating the Linux kernel as the "cryptographic module", and so
/dev/urandom was hacked to be "FIPS certified".  Huzzah!  Now let's
assume that OS was using Ubuntu, which, being derived from Debian, was
subject to a distribution "value add" where in blind obedience to a
valgrind warning, there was a distro-level change which resulted in
OpenSSL on Debian and Debian derivitives generating extremely
predictable keys[1].  This caused fairly massive security problems for
any use of OpenSSL, including ssh, certificate generation, etc. ---
despite the FIPS 140 certification of the OS.  Oops!

[1] https://en.wikinews.org/wiki/Predictable_random_number_generator_discovered_in_the_Debian_version_of_OpenSSL

It might be *cheaper* to claim that your OS is FIPS 140 certified by
hacking /dev/urandom.  Otherwise, you might have to have a responsible
security engineer audit the various userspace cryptographic libraries,
and that would be way more expensive.  It's much easier for a product
manager to say, "my work here is done" after applying a patch to the
Linux kernel for /dev/urandom, and not bothering to get an engineer to
certify the rest of the cryptographic stack.

And, if enterprise customers just care that an enterprise distro can
claim "FIPS 140 compliance", and they can push that claim of FIPS
compliance to the PCI certification authorities, they're happy.  So
ultimately, this is really an economic requirement, not a security
requirement.  And given that enterprise distros are the ones getting
paid $$$ in order to claim FIPS 140 compliance, then from an upstream
perspective, if our gaols is to optimzie the speed of getrandom(2) and
/dev/urandom, and to encourage application programmers to do the right
thing --- and *not* security theare for the sake of economic goals, we
should make technical decisions accordingly.

Cheers,

					- Ted
Matthew Garrett Jan. 11, 2022, 5:10 p.m. UTC | #81
On Tue, Jan 11, 2022 at 02:57:54PM +0500, Alexander E. Patrakov wrote:

> LD_PRELOAD is not a solution because of containers and statically-linked
> binaries.

No, it doesn't solve all problems, but the question is whether it needs 
to. We're talking about the scenario where:

a) a customer requires FIPS compliance, and
b) the customer has an app that calls getrandom() and doesn't fallback, 
and
c) they're doing so with statically linked binaries or container 
infrastructure that doesn't allow injection of other libraries

How common is this? Does the kernel need to solve this scenario?
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index c79388b78818..ea4f88da1601 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10817,6 +10817,13 @@  F:	Documentation/litmus-tests/
 F:	Documentation/memory-barriers.txt
 F:	tools/memory-model/
 
+LINUX RANDOM NUMBER GENERATOR (LRNG) DRIVER
+M:	Stephan Mueller <smueller@chronox.de>
+S:	Maintained
+W:	https://www.chronox.de/lrng.html
+F:	drivers/char/lrng/*
+F:	include/linux/lrng.h
+
 LIS3LV02D ACCELEROMETER DRIVER
 M:	Eric Piel <eric.piel@tremplin-utc.net>
 S:	Maintained
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 740811893c57..a52d575ca756 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -451,4 +451,6 @@  config RANDOM_TRUST_BOOTLOADER
 	pool. Otherwise, say N here so it will be regarded as device input that
 	only mixes the entropy pool.
 
+source "drivers/char/lrng/Kconfig"
+
 endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 264eb398fdd4..7371f7464a49 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -3,7 +3,14 @@ 
 # Makefile for the kernel character device drivers.
 #
 
-obj-y				+= mem.o random.o
+obj-y				+= mem.o
+
+ifeq ($(CONFIG_LRNG),y)
+  obj-y				+= lrng/
+else
+  obj-y				+= random.o
+endif
+
 obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
 obj-$(CONFIG_ATARI_DSP56K)	+= dsp56k.o
diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig
new file mode 100644
index 000000000000..655d873480b0
--- /dev/null
+++ b/drivers/char/lrng/Kconfig
@@ -0,0 +1,58 @@ 
+# SPDX-License-Identifier: GPL-2.0
+#
+# Linux Random Number Generator configuration
+#
+
+menuconfig LRNG
+	bool "Linux Random Number Generator"
+	select CRYPTO_LIB_SHA256 if CRYPTO
+	help
+	  The Linux Random Number Generator (LRNG) is the replacement
+	  of the existing /dev/random provided with drivers/char/random.c.
+	  It generates entropy from different noise sources and
+	  delivers significant entropy during boot.
+
+if LRNG
+
+menu "Specific DRNG seeding strategies"
+
+config LRNG_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 LRNG_OVERSAMPLE_ES_BITS
+	int
+	default 0 if !LRNG_OVERSAMPLE_ENTROPY_SOURCES
+	default 64 if LRNG_OVERSAMPLE_ENTROPY_SOURCES
+
+config LRNG_SEED_BUFFER_INIT_ADD_BITS
+	int
+	default 0 if !LRNG_OVERSAMPLE_ENTROPY_SOURCES
+	default 128 if LRNG_OVERSAMPLE_ENTROPY_SOURCES
+
+endmenu # "Specific DRNG seeding strategies"
+
+endif # LRNG
diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile
new file mode 100644
index 000000000000..6f4603f897cd
--- /dev/null
+++ b/drivers/char/lrng/Makefile
@@ -0,0 +1,8 @@ 
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Linux Random Number Generator.
+#
+
+obj-y				+= lrng_es_mgr.o lrng_aux.o \
+				   lrng_drng.o lrng_chacha20.o \
+				   lrng_interfaces.o lrng_es_aux.o
diff --git a/drivers/char/lrng/lrng_aux.c b/drivers/char/lrng/lrng_aux.c
new file mode 100644
index 000000000000..e3b994f6e4c1
--- /dev/null
+++ b/drivers/char/lrng/lrng_aux.c
@@ -0,0 +1,136 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * LRNG auxiliary interfaces
+ *
+ * Copyright (C) 2019 - 2021 Stephan Mueller <smueller@chronox.de>
+ * Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All
+ * Rights Reserved.
+ * Copyright (C) 2016 Jason Cooper <jason@lakedaemon.net>
+ */
+
+#include <linux/mm.h>
+#include <linux/random.h>
+
+#include "lrng_internal.h"
+
+struct batched_entropy {
+	union {
+		u64 entropy_u64[LRNG_DRNG_BLOCKSIZE / sizeof(u64)];
+		u32 entropy_u32[LRNG_DRNG_BLOCKSIZE / sizeof(u32)];
+	};
+	unsigned int position;
+	spinlock_t batch_lock;
+};
+
+/*
+ * Get a random word for internal kernel use only. The quality of the random
+ * number is as good as /dev/urandom, but there is no backtrack protection,
+ * with the goal of being quite fast and not depleting entropy.
+ */
+static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) = {
+	.batch_lock	= __SPIN_LOCK_UNLOCKED(batched_entropy_u64.lock),
+};
+
+u64 get_random_u64(void)
+{
+	u64 ret;
+	unsigned long flags;
+	struct batched_entropy *batch;
+
+	lrng_debug_report_seedlevel("get_random_u64");
+
+	batch = raw_cpu_ptr(&batched_entropy_u64);
+	spin_lock_irqsave(&batch->batch_lock, flags);
+	if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) {
+		lrng_drng_get_atomic((u8 *)batch->entropy_u64,
+				      LRNG_DRNG_BLOCKSIZE);
+		batch->position = 0;
+	}
+	ret = batch->entropy_u64[batch->position++];
+	spin_unlock_irqrestore(&batch->batch_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(get_random_u64);
+
+static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32) = {
+	.batch_lock	= __SPIN_LOCK_UNLOCKED(batched_entropy_u32.lock),
+};
+
+u32 get_random_u32(void)
+{
+	u32 ret;
+	unsigned long flags;
+	struct batched_entropy *batch;
+
+	lrng_debug_report_seedlevel("get_random_u32");
+
+	batch = raw_cpu_ptr(&batched_entropy_u32);
+	spin_lock_irqsave(&batch->batch_lock, flags);
+	if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) {
+		lrng_drng_get_atomic((u8 *)batch->entropy_u32,
+				      LRNG_DRNG_BLOCKSIZE);
+		batch->position = 0;
+	}
+	ret = batch->entropy_u32[batch->position++];
+	spin_unlock_irqrestore(&batch->batch_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(get_random_u32);
+
+/*
+ * It's important to invalidate all potential batched entropy that might
+ * be stored before the crng is initialized, which we can do lazily by
+ * simply resetting the counter to zero so that it's re-extracted on the
+ * next usage.
+ */
+void invalidate_batched_entropy(void)
+{
+	int cpu;
+	unsigned long flags;
+
+	for_each_possible_cpu(cpu) {
+		struct batched_entropy *batched_entropy;
+
+		batched_entropy = per_cpu_ptr(&batched_entropy_u32, cpu);
+		spin_lock_irqsave(&batched_entropy->batch_lock, flags);
+		batched_entropy->position = 0;
+		spin_unlock(&batched_entropy->batch_lock);
+
+		batched_entropy = per_cpu_ptr(&batched_entropy_u64, cpu);
+		spin_lock(&batched_entropy->batch_lock);
+		batched_entropy->position = 0;
+		spin_unlock_irqrestore(&batched_entropy->batch_lock, flags);
+	}
+}
+
+/*
+ * randomize_page - Generate a random, page aligned address
+ * @start:	The smallest acceptable address the caller will take.
+ * @range:	The size of the area, starting at @start, within which the
+ *		random address must fall.
+ *
+ * If @start + @range would overflow, @range is capped.
+ *
+ * NOTE: Historical use of randomize_range, which this replaces, presumed that
+ * @start was already page aligned.  We now align it regardless.
+ *
+ * Return: A page aligned address within [start, start + range).  On error,
+ * @start is returned.
+ */
+unsigned long randomize_page(unsigned long start, unsigned long range)
+{
+	if (!PAGE_ALIGNED(start)) {
+		range -= PAGE_ALIGN(start) - start;
+		start = PAGE_ALIGN(start);
+	}
+
+	if (start > ULONG_MAX - range)
+		range = ULONG_MAX - start;
+
+	range >>= PAGE_SHIFT;
+
+	if (range == 0)
+		return start;
+
+	return start + (get_random_long() % range << PAGE_SHIFT);
+}
diff --git a/drivers/char/lrng/lrng_chacha20.c b/drivers/char/lrng/lrng_chacha20.c
new file mode 100644
index 000000000000..51f693c2971f
--- /dev/null
+++ b/drivers/char/lrng/lrng_chacha20.c
@@ -0,0 +1,321 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * Backend for the LRNG providing the cryptographic primitives using
+ * ChaCha20 cipher implementations.
+ *
+ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <crypto/chacha.h>
+#include <linux/lrng.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+
+#include "lrng_chacha20.h"
+#include "lrng_internal.h"
+
+/******************************* ChaCha20 DRNG *******************************/
+
+#define CHACHA_BLOCK_WORDS	(CHACHA_BLOCK_SIZE / sizeof(u32))
+
+struct chacha20_state {
+	struct chacha20_block block;
+};
+
+/*
+ * Have a static memory blocks for the ChaCha20 DRNG instance to avoid calling
+ * kmalloc too early in the boot cycle. For subsequent allocation requests,
+ * such as per-NUMA-node DRNG instances, kmalloc will be used.
+ */
+struct chacha20_state chacha20 __latent_entropy;
+
+/*
+ * Update of the ChaCha20 state by either using an unused buffer part or by
+ * generating one ChaCha20 block which is half of the state of the ChaCha20.
+ * The block is XORed into the key part of the state. This shall ensure
+ * backtracking resistance as well as a proper mix of the ChaCha20 state once
+ * the key is injected.
+ */
+static void lrng_chacha20_update(struct chacha20_state *chacha20_state,
+				 __le32 *buf, u32 used_words)
+{
+	struct chacha20_block *chacha20 = &chacha20_state->block;
+	u32 i;
+	__le32 tmp[CHACHA_BLOCK_WORDS];
+
+	BUILD_BUG_ON(sizeof(struct chacha20_block) != CHACHA_BLOCK_SIZE);
+	BUILD_BUG_ON(CHACHA_BLOCK_SIZE != 2 * CHACHA_KEY_SIZE);
+
+	if (used_words > CHACHA_KEY_SIZE_WORDS) {
+		chacha20_block(&chacha20->constants[0], (u8 *)tmp);
+		for (i = 0; i < CHACHA_KEY_SIZE_WORDS; i++)
+			chacha20->key.u[i] ^= le32_to_cpu(tmp[i]);
+		memzero_explicit(tmp, sizeof(tmp));
+	} else {
+		for (i = 0; i < CHACHA_KEY_SIZE_WORDS; i++)
+			chacha20->key.u[i] ^= le32_to_cpu(buf[i + used_words]);
+	}
+
+	/* Deterministic increment of nonce as required in RFC 7539 chapter 4 */
+	chacha20->nonce[0]++;
+	if (chacha20->nonce[0] == 0) {
+		chacha20->nonce[1]++;
+		if (chacha20->nonce[1] == 0)
+			chacha20->nonce[2]++;
+	}
+
+	/* Leave counter untouched as it is start value is undefined in RFC */
+}
+
+/*
+ * Seed the ChaCha20 DRNG by injecting the input data into the key part of
+ * the ChaCha20 state. If the input data is longer than the ChaCha20 key size,
+ * perform a ChaCha20 operation after processing of key size input data.
+ * This operation shall spread out the entropy into the ChaCha20 state before
+ * new entropy is injected into the key part.
+ */
+static int lrng_cc20_drng_seed_helper(void *drng, const u8 *inbuf, u32 inbuflen)
+{
+	struct chacha20_state *chacha20_state = (struct chacha20_state *)drng;
+	struct chacha20_block *chacha20 = &chacha20_state->block;
+
+	while (inbuflen) {
+		u32 i, todo = min_t(u32, inbuflen, CHACHA_KEY_SIZE);
+
+		for (i = 0; i < todo; i++)
+			chacha20->key.b[i] ^= inbuf[i];
+
+		/* Break potential dependencies between the inbuf key blocks */
+		lrng_chacha20_update(chacha20_state, NULL,
+				     CHACHA_BLOCK_WORDS);
+		inbuf += todo;
+		inbuflen -= todo;
+	}
+
+	return 0;
+}
+
+/*
+ * Chacha20 DRNG generation of random numbers: the stream output of ChaCha20
+ * is the random number. After the completion of the generation of the
+ * stream, the entire ChaCha20 state is updated.
+ *
+ * Note, as the ChaCha20 implements a 32 bit counter, we must ensure
+ * that this function is only invoked for at most 2^32 - 1 ChaCha20 blocks
+ * before a reseed or an update happens. This is ensured by the variable
+ * outbuflen which is a 32 bit integer defining the number of bytes to be
+ * generated by the ChaCha20 DRNG. At the end of this function, an update
+ * operation is invoked which implies that the 32 bit counter will never be
+ * overflown in this implementation.
+ */
+static int lrng_cc20_drng_generate_helper(void *drng, u8 *outbuf, u32 outbuflen)
+{
+	struct chacha20_state *chacha20_state = (struct chacha20_state *)drng;
+	struct chacha20_block *chacha20 = &chacha20_state->block;
+	__le32 aligned_buf[CHACHA_BLOCK_WORDS];
+	u32 ret = outbuflen, used = CHACHA_BLOCK_WORDS;
+	int zeroize_buf = 0;
+
+	while (outbuflen >= CHACHA_BLOCK_SIZE) {
+		chacha20_block(&chacha20->constants[0], outbuf);
+		outbuf += CHACHA_BLOCK_SIZE;
+		outbuflen -= CHACHA_BLOCK_SIZE;
+	}
+
+	if (outbuflen) {
+		chacha20_block(&chacha20->constants[0], (u8 *)aligned_buf);
+		memcpy(outbuf, aligned_buf, outbuflen);
+		used = ((outbuflen + sizeof(aligned_buf[0]) - 1) /
+			sizeof(aligned_buf[0]));
+		zeroize_buf = 1;
+	}
+
+	lrng_chacha20_update(chacha20_state, aligned_buf, used);
+
+	if (zeroize_buf)
+		memzero_explicit(aligned_buf, sizeof(aligned_buf));
+
+	return ret;
+}
+
+void lrng_cc20_init_state(struct chacha20_state *state)
+{
+	lrng_cc20_init_rfc7539(&state->block);
+}
+
+/*
+ * Allocation of the DRNG state
+ */
+static void *lrng_cc20_drng_alloc(u32 sec_strength)
+{
+	struct chacha20_state *state = NULL;
+
+	if (sec_strength > CHACHA_KEY_SIZE) {
+		pr_err("Security strength of ChaCha20 DRNG (%u bits) lower than requested by LRNG (%u bits)\n",
+			CHACHA_KEY_SIZE * 8, sec_strength * 8);
+		return ERR_PTR(-EINVAL);
+	}
+	if (sec_strength < CHACHA_KEY_SIZE)
+		pr_warn("Security strength of ChaCha20 DRNG (%u bits) higher than requested by LRNG (%u bits)\n",
+			CHACHA_KEY_SIZE * 8, sec_strength * 8);
+
+	state = kmalloc(sizeof(struct chacha20_state), GFP_KERNEL);
+	if (!state)
+		return ERR_PTR(-ENOMEM);
+	pr_debug("memory for ChaCha20 core allocated\n");
+
+	lrng_cc20_init_state(state);
+
+	return state;
+}
+
+static void lrng_cc20_drng_dealloc(void *drng)
+{
+	struct chacha20_state *chacha20_state = (struct chacha20_state *)drng;
+
+	if (drng == &chacha20) {
+		memzero_explicit(chacha20_state, sizeof(*chacha20_state));
+		pr_debug("static ChaCha20 core zeroized\n");
+		return;
+	}
+
+	pr_debug("ChaCha20 core zeroized and freed\n");
+	kfree_sensitive(chacha20_state);
+}
+
+/******************************* Hash Operation *******************************/
+
+#ifdef CONFIG_CRYPTO_LIB_SHA256
+
+#include <crypto/sha2.h>
+
+static u32 lrng_cc20_hash_digestsize(void *hash)
+{
+	return SHA256_DIGEST_SIZE;
+}
+
+static int lrng_cc20_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 lrng_cc20_hash_update(struct shash_desc *shash,
+				 const u8 *inbuf, u32 inbuflen)
+{
+	sha256_update(shash_desc_ctx(shash), inbuf, inbuflen);
+	return 0;
+}
+
+static int lrng_cc20_hash_final(struct shash_desc *shash, u8 *digest)
+{
+	sha256_final(shash_desc_ctx(shash), digest);
+	return 0;
+}
+
+static const char *lrng_cc20_hash_name(void)
+{
+	return "SHA-256";
+}
+
+static void lrng_cc20_hash_desc_zero(struct shash_desc *shash)
+{
+	memzero_explicit(shash_desc_ctx(shash), sizeof(struct sha256_state));
+}
+
+#else /* CONFIG_CRYPTO_LIB_SHA256 */
+
+#include <crypto/sha1.h>
+#include <crypto/sha1_base.h>
+
+/*
+ * If the SHA-256 support is not compiled, we fall back to SHA-1 that is always
+ * compiled and present in the kernel.
+ */
+static u32 lrng_cc20_hash_digestsize(void *hash)
+{
+	return SHA1_DIGEST_SIZE;
+}
+
+static void lrng_sha1_block_fn(struct sha1_state *sctx, const u8 *src,
+			       int blocks)
+{
+	u32 temp[SHA1_WORKSPACE_WORDS];
+
+	while (blocks--) {
+		sha1_transform(sctx->state, src, temp);
+		src += SHA1_BLOCK_SIZE;
+	}
+	memzero_explicit(temp, sizeof(temp));
+}
+
+static int lrng_cc20_hash_init(struct shash_desc *shash, void *hash)
+{
+	/*
+	 * We do not need a TFM - we only need sufficient space for
+	 * struct sha1_state on the stack.
+	 */
+	sha1_base_init(shash);
+	return 0;
+}
+
+static int lrng_cc20_hash_update(struct shash_desc *shash,
+				 const u8 *inbuf, u32 inbuflen)
+{
+	return sha1_base_do_update(shash, inbuf, inbuflen, lrng_sha1_block_fn);
+}
+
+static int lrng_cc20_hash_final(struct shash_desc *shash, u8 *digest)
+{
+	return sha1_base_do_finalize(shash, lrng_sha1_block_fn) ?:
+	       sha1_base_finish(shash, digest);
+}
+
+static const char *lrng_cc20_hash_name(void)
+{
+	return "SHA-1";
+}
+
+static void lrng_cc20_hash_desc_zero(struct shash_desc *shash)
+{
+	memzero_explicit(shash_desc_ctx(shash), sizeof(struct sha1_state));
+}
+
+#endif /* CONFIG_CRYPTO_LIB_SHA256 */
+
+static void *lrng_cc20_hash_alloc(void)
+{
+	pr_info("Hash %s allocated\n", lrng_cc20_hash_name());
+	return NULL;
+}
+
+static void lrng_cc20_hash_dealloc(void *hash)
+{
+}
+
+static const char *lrng_cc20_drng_name(void)
+{
+	return "ChaCha20 DRNG";
+}
+
+const struct lrng_crypto_cb lrng_cc20_crypto_cb = {
+	.lrng_drng_name			= lrng_cc20_drng_name,
+	.lrng_hash_name			= lrng_cc20_hash_name,
+	.lrng_drng_alloc		= lrng_cc20_drng_alloc,
+	.lrng_drng_dealloc		= lrng_cc20_drng_dealloc,
+	.lrng_drng_seed_helper		= lrng_cc20_drng_seed_helper,
+	.lrng_drng_generate_helper	= lrng_cc20_drng_generate_helper,
+	.lrng_hash_alloc		= lrng_cc20_hash_alloc,
+	.lrng_hash_dealloc		= lrng_cc20_hash_dealloc,
+	.lrng_hash_digestsize		= lrng_cc20_hash_digestsize,
+	.lrng_hash_init			= lrng_cc20_hash_init,
+	.lrng_hash_update		= lrng_cc20_hash_update,
+	.lrng_hash_final		= lrng_cc20_hash_final,
+	.lrng_hash_desc_zero		= lrng_cc20_hash_desc_zero,
+};
diff --git a/drivers/char/lrng/lrng_chacha20.h b/drivers/char/lrng/lrng_chacha20.h
new file mode 100644
index 000000000000..bd0c0bee38f3
--- /dev/null
+++ b/drivers/char/lrng/lrng_chacha20.h
@@ -0,0 +1,25 @@ 
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * LRNG ChaCha20 definitions
+ *
+ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
+ */
+
+#include <crypto/chacha.h>
+
+/* State according to RFC 7539 section 2.3 */
+struct chacha20_block {
+	u32 constants[4];
+	union {
+#define CHACHA_KEY_SIZE_WORDS (CHACHA_KEY_SIZE / sizeof(u32))
+		u32 u[CHACHA_KEY_SIZE_WORDS];
+		u8  b[CHACHA_KEY_SIZE];
+	} key;
+	u32 counter;
+	u32 nonce[3];
+};
+
+static inline void lrng_cc20_init_rfc7539(struct chacha20_block *chacha20)
+{
+	chacha_init_consts(chacha20->constants);
+}
diff --git a/drivers/char/lrng/lrng_drng.c b/drivers/char/lrng/lrng_drng.c
new file mode 100644
index 000000000000..1ab533263239
--- /dev/null
+++ b/drivers/char/lrng/lrng_drng.c
@@ -0,0 +1,451 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * LRNG DRNG processing
+ *
+ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/fips.h>
+#include <linux/lrng.h>
+
+#include "lrng_internal.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 lrng_drng_reseed_max_time = 600;
+
+static atomic_t lrng_avail = ATOMIC_INIT(0);
+
+DEFINE_MUTEX(lrng_crypto_cb_update);
+
+/* DRNG for /dev/urandom, getrandom(2), get_random_bytes */
+static struct lrng_drng lrng_drng_init = {
+	.drng		= &chacha20,
+	.crypto_cb	= &lrng_cc20_crypto_cb,
+	.lock		= __MUTEX_INITIALIZER(lrng_drng_init.lock),
+	.spin_lock	= __SPIN_LOCK_UNLOCKED(lrng_drng_init.spin_lock),
+	.hash_lock	= __RW_LOCK_UNLOCKED(lrng_drng_init.hash_lock)
+};
+
+/*
+ * DRNG for get_random_bytes when called in atomic context. This
+ * DRNG will always use the ChaCha20 DRNG. It will never benefit from a
+ * DRNG switch like the "regular" DRNG. If there was no DRNG switch, the atomic
+ * DRNG is identical to the "regular" DRNG.
+ *
+ * The reason for having this is due to the fact that DRNGs other than
+ * the ChaCha20 DRNG may sleep.
+ */
+static struct lrng_drng lrng_drng_atomic = {
+	.drng		= &chacha20,
+	.crypto_cb	= &lrng_cc20_crypto_cb,
+	.spin_lock	= __SPIN_LOCK_UNLOCKED(lrng_drng_atomic.spin_lock),
+	.hash_lock	= __RW_LOCK_UNLOCKED(lrng_drng_atomic.hash_lock)
+};
+
+static u32 max_wo_reseed = LRNG_DRNG_MAX_WITHOUT_RESEED;
+#ifdef CONFIG_LRNG_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
+
+/********************************** Helper ************************************/
+
+bool lrng_get_available(void)
+{
+	return likely(atomic_read(&lrng_avail));
+}
+
+void lrng_set_available(void)
+{
+	atomic_set(&lrng_avail, 1);
+}
+
+struct lrng_drng *lrng_drng_init_instance(void)
+{
+	return &lrng_drng_init;
+}
+
+struct lrng_drng *lrng_drng_atomic_instance(void)
+{
+	return &lrng_drng_atomic;
+}
+
+void lrng_drng_reset(struct lrng_drng *drng)
+{
+	atomic_set(&drng->requests, LRNG_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 default DRNG during boot */
+static void lrng_drng_seed(struct lrng_drng *drng);
+void lrng_drngs_init_cc20(bool force_seed)
+{
+	unsigned long flags = 0;
+
+	if (lrng_get_available())
+		return;
+
+	lrng_drng_lock(&lrng_drng_init, &flags);
+	if (lrng_get_available()) {
+		lrng_drng_unlock(&lrng_drng_init, &flags);
+		if (force_seed)
+			goto seed;
+		return;
+	}
+
+	lrng_drng_reset(&lrng_drng_init);
+	lrng_cc20_init_state(&chacha20);
+	lrng_drng_unlock(&lrng_drng_init, &flags);
+
+	lrng_drng_lock(&lrng_drng_atomic, &flags);
+	lrng_drng_reset(&lrng_drng_atomic);
+	/*
+	 * We do not initialize the state of the atomic DRNG as it is identical
+	 * to the DRNG at this point.
+	 */
+	lrng_drng_unlock(&lrng_drng_atomic, &flags);
+
+	lrng_set_available();
+
+seed:
+	/* Seed the DRNG with any entropy available */
+	if (!lrng_pool_trylock()) {
+		lrng_drng_seed(&lrng_drng_init);
+		pr_info("ChaCha20 core initialized with first seeding\n");
+		lrng_pool_unlock();
+	} else {
+		pr_info("ChaCha20 core initialized without seeding\n");
+	}
+}
+
+bool lrng_sp80090c_compliant(void)
+{
+	if (!IS_ENABLED(CONFIG_LRNG_OVERSAMPLE_ENTROPY_SOURCES))
+		return false;
+
+	/* Entropy source hash must be capable of transporting enough entropy */
+	if (lrng_get_digestsize() <
+	    (lrng_security_strength() + CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS))
+		return false;
+
+	/* SP800-90C only requested in FIPS mode */
+	return fips_enabled;
+}
+
+/************************* Random Number Generation ***************************/
+
+/* Inject a data buffer into the DRNG */
+static void lrng_drng_inject(struct lrng_drng *drng,
+			     const u8 *inbuf, u32 inbuflen, bool fully_seeded)
+{
+	const char *drng_type = unlikely(drng == &lrng_drng_atomic) ?
+				"atomic" : "regular";
+	unsigned long flags = 0;
+
+	BUILD_BUG_ON(LRNG_DRNG_RESEED_THRESH > INT_MAX);
+	pr_debug("seeding %s DRNG with %u bytes\n", drng_type, inbuflen);
+	lrng_drng_lock(drng, &flags);
+	if (drng->crypto_cb->lrng_drng_seed_helper(drng->drng,
+						   inbuf, inbuflen) < 0) {
+		pr_warn("seeding of %s DRNG failed\n", drng_type);
+		drng->force_reseed = true;
+	} else {
+		int gc = LRNG_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, LRNG_DRNG_RESEED_THRESH);
+		drng->force_reseed = false;
+
+		if (!drng->fully_seeded) {
+			drng->fully_seeded = fully_seeded;
+			if (drng->fully_seeded)
+				pr_debug("DRNG fully seeded\n");
+		}
+
+		if (drng->drng == lrng_drng_atomic.drng) {
+			lrng_drng_atomic.last_seeded = jiffies;
+			atomic_set(&lrng_drng_atomic.requests,
+				   LRNG_DRNG_RESEED_THRESH);
+			lrng_drng_atomic.force_reseed = false;
+		}
+	}
+	lrng_drng_unlock(drng, &flags);
+}
+
+/*
+ * Perform the seeding of the DRNG with data from noise source
+ */
+static inline void _lrng_drng_seed(struct lrng_drng *drng)
+{
+	struct entropy_buf seedbuf __aligned(LRNG_KCAPI_ALIGN);
+
+	lrng_fill_seed_buffer(&seedbuf,
+			      lrng_get_seed_entropy_osr(drng->fully_seeded));
+	lrng_init_ops(&seedbuf);
+	lrng_drng_inject(drng, (u8 *)&seedbuf, sizeof(seedbuf),
+			 lrng_fully_seeded(drng->fully_seeded, &seedbuf));
+	memzero_explicit(&seedbuf, sizeof(seedbuf));
+}
+
+static int lrng_drng_get(struct lrng_drng *drng, u8 *outbuf, u32 outbuflen);
+static void lrng_drng_seed(struct lrng_drng *drng)
+{
+	_lrng_drng_seed(drng);
+
+	BUILD_BUG_ON(LRNG_MIN_SEED_ENTROPY_BITS >
+		     LRNG_DRNG_SECURITY_STRENGTH_BITS);
+
+	/*
+	 * Reseed atomic DRNG from current DRNG,
+	 *
+	 * We can obtain random numbers from DRNG as the lock type
+	 * chosen by lrng_drng_get is usable with the current caller.
+	 */
+	if ((drng->drng != lrng_drng_atomic.drng) &&
+	    (lrng_drng_atomic.force_reseed ||
+	     atomic_read(&lrng_drng_atomic.requests) <= 0 ||
+	     time_after(jiffies, lrng_drng_atomic.last_seeded +
+			lrng_drng_reseed_max_time * HZ))) {
+		u8 seedbuf[LRNG_DRNG_SECURITY_STRENGTH_BYTES]
+						__aligned(LRNG_KCAPI_ALIGN);
+		int ret = lrng_drng_get(drng, seedbuf, sizeof(seedbuf));
+
+		if (ret < 0) {
+			pr_warn("Error generating random numbers for atomic DRNG: %d\n",
+				ret);
+		} else {
+			lrng_drng_inject(&lrng_drng_atomic, seedbuf, ret, true);
+		}
+		memzero_explicit(&seedbuf, sizeof(seedbuf));
+	}
+}
+
+static inline void _lrng_drng_seed_work(struct lrng_drng *drng, u32 node)
+{
+	pr_debug("reseed triggered by interrupt noise source for DRNG on NUMA node %d\n",
+		 node);
+	lrng_drng_seed(drng);
+	if (drng->fully_seeded) {
+		/* Prevent reseed storm */
+		drng->last_seeded += node * 100 * HZ;
+		/* Prevent draining of pool on idle systems */
+		lrng_drng_reseed_max_time += 100;
+	}
+}
+
+/*
+ * DRNG reseed trigger: Kernel thread handler triggered by the schedule_work()
+ */
+void lrng_drng_seed_work(struct work_struct *dummy)
+{
+	struct lrng_drng **lrng_drng = lrng_drng_instances();
+	u32 node;
+
+	if (lrng_drng) {
+		for_each_online_node(node) {
+			struct lrng_drng *drng = lrng_drng[node];
+
+			if (drng && !drng->fully_seeded) {
+				_lrng_drng_seed_work(drng, node);
+				goto out;
+			}
+		}
+	} else {
+		if (!lrng_drng_init.fully_seeded) {
+			_lrng_drng_seed_work(&lrng_drng_init, 0);
+			goto out;
+		}
+	}
+
+	lrng_pool_all_numa_nodes_seeded(true);
+
+out:
+	/* Allow the seeding operation to be called again */
+	lrng_pool_unlock();
+}
+
+/* Force all DRNGs to reseed before next generation */
+void lrng_drng_force_reseed(void)
+{
+	struct lrng_drng **lrng_drng = lrng_drng_instances();
+	u32 node;
+
+	/*
+	 * If the initial DRNG is over the reseed threshold, allow a forced
+	 * reseed only for the initial DRNG as this is the fallback for all. It
+	 * must be kept seeded before all others to keep the LRNG operational.
+	 */
+	if (!lrng_drng ||
+	    (atomic_read_u32(&lrng_drng_init.requests_since_fully_seeded) >
+	     LRNG_DRNG_RESEED_THRESH)) {
+		lrng_drng_init.force_reseed = lrng_drng_init.fully_seeded;
+		pr_debug("force reseed of initial DRNG\n");
+		return;
+	}
+	for_each_online_node(node) {
+		struct lrng_drng *drng = lrng_drng[node];
+
+		if (!drng)
+			continue;
+
+		drng->force_reseed = drng->fully_seeded;
+		pr_debug("force reseed of DRNG on node %u\n", node);
+	}
+	lrng_drng_atomic.force_reseed = lrng_drng_atomic.fully_seeded;
+}
+
+/*
+ * lrng_drng_get() - Get random data out of the DRNG which is reseeded
+ * frequently.
+ *
+ * @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
+ */
+static int lrng_drng_get(struct lrng_drng *drng, u8 *outbuf, u32 outbuflen)
+{
+	unsigned long flags = 0;
+	u32 processed = 0;
+
+	if (!outbuf || !outbuflen)
+		return 0;
+
+	outbuflen = min_t(size_t, outbuflen, INT_MAX);
+
+	lrng_drngs_init_cc20(false);
+
+	/* If DRNG operated without proper reseed for too long, block LRNG */
+	BUILD_BUG_ON(LRNG_DRNG_MAX_WITHOUT_RESEED < LRNG_DRNG_RESEED_THRESH);
+	if (atomic_read_u32(&drng->requests_since_fully_seeded) > max_wo_reseed)
+		lrng_unset_fully_seeded(drng);
+
+	while (outbuflen) {
+		u32 todo = min_t(u32, outbuflen, LRNG_DRNG_MAX_REQSIZE);
+		int ret;
+
+		/* All but the atomic DRNG are seeded during generation */
+		if (atomic_dec_and_test(&drng->requests) ||
+		    drng->force_reseed ||
+		    time_after(jiffies, drng->last_seeded +
+			       lrng_drng_reseed_max_time * HZ)) {
+			if (likely(drng != &lrng_drng_atomic)) {
+				if (lrng_pool_trylock()) {
+					drng->force_reseed = true;
+				} else {
+					lrng_drng_seed(drng);
+					lrng_pool_unlock();
+				}
+			}
+		}
+
+		lrng_drng_lock(drng, &flags);
+		ret = drng->crypto_cb->lrng_drng_generate_helper(
+					drng->drng, outbuf + processed, todo);
+		lrng_drng_unlock(drng, &flags);
+		if (ret <= 0) {
+			pr_warn("getting random data from DRNG failed (%d)\n",
+				ret);
+			return -EFAULT;
+		}
+		processed += ret;
+		outbuflen -= ret;
+	}
+
+	return processed;
+}
+
+int lrng_drng_get_atomic(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_drng_get(&lrng_drng_atomic, outbuf, outbuflen);
+}
+
+int lrng_drng_get_sleep(u8 *outbuf, u32 outbuflen)
+{
+	struct lrng_drng **lrng_drng = lrng_drng_instances();
+	struct lrng_drng *drng = &lrng_drng_init;
+	int node = numa_node_id();
+
+	might_sleep();
+
+	if (lrng_drng && lrng_drng[node] && lrng_drng[node]->fully_seeded)
+		drng = lrng_drng[node];
+
+	return lrng_drng_get(drng, outbuf, outbuflen);
+}
+
+/* Reset LRNG such that all existing entropy is gone */
+static void _lrng_reset(struct work_struct *work)
+{
+	struct lrng_drng **lrng_drng = lrng_drng_instances();
+	unsigned long flags = 0;
+
+	if (!lrng_drng) {
+		lrng_drng_lock(&lrng_drng_init, &flags);
+		lrng_drng_reset(&lrng_drng_init);
+		lrng_drng_unlock(&lrng_drng_init, &flags);
+	} else {
+		u32 node;
+
+		for_each_online_node(node) {
+			struct lrng_drng *drng = lrng_drng[node];
+
+			if (!drng)
+				continue;
+			lrng_drng_lock(drng, &flags);
+			lrng_drng_reset(drng);
+			lrng_drng_unlock(drng, &flags);
+		}
+	}
+	lrng_set_entropy_thresh(LRNG_INIT_ENTROPY_BITS);
+
+	lrng_reset_state();
+}
+
+static DECLARE_WORK(lrng_reset_work, _lrng_reset);
+
+void lrng_reset(void)
+{
+	schedule_work(&lrng_reset_work);
+}
+
+/***************************** Initialize LRNG *******************************/
+
+static int __init lrng_init(void)
+{
+	lrng_drngs_init_cc20(false);
+
+	lrng_drngs_numa_alloc();
+	return 0;
+}
+
+late_initcall(lrng_init);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("Linux Random Number Generator");
diff --git a/drivers/char/lrng/lrng_es_aux.c b/drivers/char/lrng/lrng_es_aux.c
new file mode 100644
index 000000000000..cd51c7311feb
--- /dev/null
+++ b/drivers/char/lrng/lrng_es_aux.c
@@ -0,0 +1,294 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * LRNG Slow Entropy Source: Auxiliary entropy pool
+ *
+ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/lrng.h>
+
+#include "lrng_internal.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 lrng_pool {
+	u8 aux_pool[LRNG_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 lrng_pool lrng_pool __aligned(LRNG_KCAPI_ALIGN) = {
+	.aux_entropy_bits	= ATOMIC_INIT(0),
+	.digestsize		= ATOMIC_INIT(LRNG_ATOMIC_DIGEST_SIZE),
+	.initialized		= false,
+	.lock			= __SPIN_LOCK_UNLOCKED(lrng_pool.lock)
+};
+
+/********************************** Helper ***********************************/
+
+/* Entropy in bits present in aux pool */
+u32 lrng_avail_aux_entropy(void)
+{
+	/* Cap available entropy with max entropy */
+	u32 avail_bits = min_t(u32, lrng_get_digestsize(),
+			       atomic_read_u32(&lrng_pool.aux_entropy_bits));
+
+	/* Consider oversampling rate due to aux pool conditioning */
+	return lrng_reduce_by_osr(avail_bits);
+}
+
+/* Set the digest size of the used hash in bytes */
+static inline void lrng_set_digestsize(u32 digestsize)
+{
+	struct lrng_pool *pool = &lrng_pool;
+	u32 ent_bits = atomic_xchg_relaxed(&pool->aux_entropy_bits, 0),
+	    old_digestsize = lrng_get_digestsize();
+
+	atomic_set(&lrng_pool.digestsize, digestsize);
+
+	/*
+	 * Update the /proc/.../write_wakeup_threshold which must not be larger
+	 * than the digest size of the curent conditioning hash.
+	 */
+	digestsize <<= 3;
+	lrng_proc_update_max_write_thresh(digestsize);
+	if (lrng_write_wakeup_bits > digestsize)
+		lrng_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);
+}
+
+/* Obtain the digest size provided by the used hash in bits */
+u32 lrng_get_digestsize(void)
+{
+	return atomic_read_u32(&lrng_pool.digestsize) << 3;
+}
+
+/* Set entropy content in user-space controllable aux pool */
+void lrng_pool_set_entropy(u32 entropy_bits)
+{
+	atomic_set(&lrng_pool.aux_entropy_bits, entropy_bits);
+}
+
+/*
+ * 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).
+ */
+int lrng_aux_switch_hash(const struct lrng_crypto_cb *new_cb, void *new_hash,
+			 const struct lrng_crypto_cb *old_cb)
+{
+	struct lrng_pool *pool = &lrng_pool;
+	struct shash_desc *shash = (struct shash_desc *)pool->aux_pool;
+	u8 digest[LRNG_MAX_DIGESTSIZE];
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_LRNG_DRNG_SWITCH))
+		return -EOPNOTSUPP;
+
+	if (unlikely(!pool->initialized))
+		return 0;
+
+	/* Get the aux pool hash with old digest ... */
+	ret = old_cb->lrng_hash_final(shash, digest) ?:
+	      /* ... re-initialize the hash with the new digest ... */
+	      new_cb->lrng_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->lrng_hash_update(shash, digest, sizeof(digest));
+	if (!ret) {
+		lrng_set_digestsize(new_cb->lrng_hash_digestsize(new_hash));
+		pr_debug("Re-initialize aux entropy pool with hash %s\n",
+			 new_cb->lrng_hash_name());
+	}
+
+	memzero_explicit(digest, sizeof(digest));
+	return ret;
+}
+
+/* Insert data into auxiliary pool by using the hash update function. */
+static int
+lrng_pool_insert_aux_locked(const u8 *inbuf, u32 inbuflen, u32 entropy_bits)
+{
+	struct lrng_pool *pool = &lrng_pool;
+	struct shash_desc *shash = (struct shash_desc *)pool->aux_pool;
+	struct lrng_drng *drng = lrng_drng_init_instance();
+	const struct lrng_crypto_cb *crypto_cb;
+	unsigned long flags;
+	void *hash;
+	int ret;
+
+	entropy_bits = min_t(u32, entropy_bits, inbuflen << 3);
+
+	lrng_hash_lock(drng, &flags);
+
+	crypto_cb = drng->crypto_cb;
+	hash = drng->hash;
+
+	if (unlikely(!pool->initialized)) {
+		ret = crypto_cb->lrng_hash_init(shash, hash);
+		if (ret)
+			goto out;
+		pool->initialized = true;
+	}
+
+	ret = crypto_cb->lrng_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,
+			 crypto_cb->lrng_hash_digestsize(hash) << 3));
+
+out:
+	lrng_hash_unlock(drng, flags);
+	return ret;
+}
+
+int lrng_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits)
+{
+	struct lrng_pool *pool = &lrng_pool;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&pool->lock, flags);
+	ret = lrng_pool_insert_aux_locked(inbuf, inbuflen, entropy_bits);
+	spin_unlock_irqrestore(&pool->lock, flags);
+
+	lrng_pool_add_entropy();
+
+	return ret;
+}
+
+/************************* Get data from entropy pool *************************/
+
+/*
+ * Get auxiliary entropy pool and its entropy content for seed buffer.
+ * Caller must hold lrng_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 inline u32 lrng_get_aux_pool(u8 *outbuf, u32 requested_bits)
+{
+	struct lrng_pool *pool = &lrng_pool;
+	struct shash_desc *shash = (struct shash_desc *)pool->aux_pool;
+	struct lrng_drng *drng = lrng_drng_init_instance();
+	const struct lrng_crypto_cb *crypto_cb;
+	unsigned long flags;
+	void *hash;
+	u32 collected_ent_bits, returned_ent_bits, unused_bits = 0,
+	    digestsize;
+	u8 aux_output[LRNG_MAX_DIGESTSIZE];
+
+	if (unlikely(!pool->initialized))
+		return 0;
+
+	lrng_hash_lock(drng, &flags);
+
+	crypto_cb = drng->crypto_cb;
+	hash = drng->hash;
+	digestsize = crypto_cb->lrng_hash_digestsize(hash);
+
+	/* Ensure that no more than the size of aux_pool can be requested */
+	requested_bits = min_t(u32, requested_bits, (LRNG_MAX_DIGESTSIZE << 3));
+
+	/* Cap entropy with entropy counter from aux pool and the used digest */
+	collected_ent_bits = min_t(u32, digestsize << 3,
+			       atomic_xchg_relaxed(&pool->aux_entropy_bits, 0));
+
+	/* We collected too much entropy and put the overflow back */
+	if (collected_ent_bits > (requested_bits + lrng_compress_osr())) {
+		/* Amount of bits we collected too much */
+		unused_bits = collected_ent_bits - requested_bits;
+		/* Put entropy back */
+		atomic_add(unused_bits, &pool->aux_entropy_bits);
+		/* Fix collected entropy */
+		collected_ent_bits = requested_bits;
+	}
+
+	/* Apply oversampling: discount requested oversampling rate */
+	returned_ent_bits = lrng_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 (crypto_cb->lrng_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.
+	     */
+	    crypto_cb->lrng_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);
+	}
+
+	lrng_hash_unlock(drng, flags);
+	memzero_explicit(aux_output, digestsize);
+	return returned_ent_bits;
+}
+
+void lrng_get_backtrack_aux(struct entropy_buf *entropy_buf, u32 requested_bits)
+{
+	struct lrng_pool *pool = &lrng_pool;
+	unsigned long flags;
+
+	/* Ensure aux pool extraction and backtracking op are atomic */
+	spin_lock_irqsave(&pool->lock, flags);
+
+	entropy_buf->a_bits = lrng_get_aux_pool(entropy_buf->a, requested_bits);
+
+	/* Mix the extracted data back into pool for backtracking resistance */
+	if (lrng_pool_insert_aux_locked((u8 *)entropy_buf,
+					sizeof(struct entropy_buf), 0))
+		pr_warn("Backtracking resistance operation failed\n");
+
+	spin_unlock_irqrestore(&pool->lock, flags);
+}
+
+void lrng_aux_es_state(unsigned char *buf, size_t buflen)
+{
+	const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance();
+
+	/* Assume the lrng_drng_init lock is taken by caller */
+	snprintf(buf, buflen,
+		 "Auxiliary ES properties:\n"
+		 " Hash for operating entropy pool: %s\n",
+		 lrng_drng_init->crypto_cb->lrng_hash_name());
+}
diff --git a/drivers/char/lrng/lrng_es_mgr.c b/drivers/char/lrng/lrng_es_mgr.c
new file mode 100644
index 000000000000..c0025ad2b54a
--- /dev/null
+++ b/drivers/char/lrng/lrng_es_mgr.c
@@ -0,0 +1,373 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * LRNG Entropy sources management
+ *
+ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <asm/irq_regs.h>
+#include <linux/percpu.h>
+#include <linux/random.h>
+#include <linux/utsname.h>
+#include <linux/workqueue.h>
+
+#include "lrng_internal.h"
+
+struct lrng_state {
+	bool can_invalidate;		/* Can invalidate batched entropy? */
+	bool perform_seedwork;		/* Can seed work be performed? */
+	bool lrng_operational;		/* Is DRNG operational? */
+	bool lrng_fully_seeded;		/* Is DRNG fully seeded? */
+	bool lrng_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.
+	 */
+	bool lrng_seed_hw;		/* Allow HW to provide seed */
+	bool lrng_seed_user;		/* Allow user space to provide seed */
+
+	atomic_t boot_entropy_thresh;	/* Reseed threshold */
+	atomic_t reseed_in_progress;	/* Flag for on executing reseed */
+	struct work_struct lrng_seed_work;	/* (re)seed work queue */
+};
+
+static struct lrng_state lrng_state = {
+	false, false, false, false, false, false, true, true,
+	.boot_entropy_thresh	= ATOMIC_INIT(LRNG_INIT_ENTROPY_BITS),
+	.reseed_in_progress	= ATOMIC_INIT(0),
+};
+
+/********************************** Helper ***********************************/
+
+/* External entropy provider is allowed to provide seed data */
+bool lrng_state_exseed_allow(enum lrng_external_noise_source source)
+{
+	if (source == lrng_noise_source_hw)
+		return lrng_state.lrng_seed_hw;
+	return lrng_state.lrng_seed_user;
+}
+
+/* Enable / disable external entropy provider to furnish seed */
+void lrng_state_exseed_set(enum lrng_external_noise_source source, bool type)
+{
+	if (source == lrng_noise_source_hw)
+		lrng_state.lrng_seed_hw = type;
+	else
+		lrng_state.lrng_seed_user = type;
+}
+
+static inline void lrng_state_exseed_allow_all(void)
+{
+	lrng_state_exseed_set(lrng_noise_source_hw, true);
+	lrng_state_exseed_set(lrng_noise_source_user, true);
+}
+
+/*
+ * Reading of the LRNG 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 lrng_pool_trylock(void)
+{
+	return atomic_cmpxchg(&lrng_state.reseed_in_progress, 0, 1);
+}
+
+void lrng_pool_unlock(void)
+{
+	atomic_set(&lrng_state.reseed_in_progress, 0);
+}
+
+/* Set new entropy threshold for reseeding during boot */
+void lrng_set_entropy_thresh(u32 new_entropy_bits)
+{
+	atomic_set(&lrng_state.boot_entropy_thresh, new_entropy_bits);
+}
+
+/*
+ * Reset LRNG 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 lrng_reset_state(void)
+{
+	lrng_pool_set_entropy(0);
+	lrng_pcpu_reset();
+	lrng_state.lrng_operational = false;
+	lrng_state.lrng_fully_seeded = false;
+	lrng_state.lrng_min_seeded = false;
+	lrng_state.all_online_numa_node_seeded = false;
+	pr_debug("reset LRNG\n");
+}
+
+/* Set flag that all DRNGs are fully seeded */
+void lrng_pool_all_numa_nodes_seeded(bool set)
+{
+	lrng_state.all_online_numa_node_seeded = set;
+}
+
+/* Return boolean whether LRNG reached minimally seed level */
+bool lrng_state_min_seeded(void)
+{
+	return lrng_state.lrng_min_seeded;
+}
+
+/* Return boolean whether LRNG reached fully seed level */
+bool lrng_state_fully_seeded(void)
+{
+	return lrng_state.lrng_fully_seeded;
+}
+
+/* Return boolean whether LRNG is considered fully operational */
+bool lrng_state_operational(void)
+{
+	return lrng_state.lrng_operational;
+}
+
+/* Policy to check whether entropy buffer contains full seeded entropy */
+bool lrng_fully_seeded(bool fully_seeded, struct entropy_buf *eb)
+{
+	return ((eb->a_bits + eb->b_bits + eb->c_bits + eb->d_bits) >=
+		lrng_get_seed_entropy_osr(fully_seeded));
+}
+
+/* Mark one DRNG as not fully seeded */
+void lrng_unset_fully_seeded(struct lrng_drng *drng)
+{
+	drng->fully_seeded = false;
+	lrng_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 LRNG as
+	 * non-operational if the initial DRNG becomes not fully seeded.
+	 */
+	if (drng == lrng_drng_init_instance() && lrng_state_operational()) {
+		pr_debug("LRNG set to non-operational\n");
+		lrng_state.lrng_operational = false;
+		lrng_state.lrng_fully_seeded = false;
+
+		/* If sufficient entropy is available, reseed now. */
+		lrng_pool_add_entropy();
+	}
+}
+
+/* Policy to enable LRNG operational mode */
+static inline void lrng_set_operational(u32 external_es)
+{
+	/* LRNG is operational if the initial DRNG is fully seeded ... */
+	if (lrng_state.lrng_fully_seeded &&
+	    /* ... and either internal ES SP800-90B startup is complete ... */
+	    (lrng_sp80090b_startup_complete() ||
+	    /* ... or the external ES provided sufficient entropy. */
+	     (lrng_get_seed_entropy_osr(lrng_state_fully_seeded()) <=
+	      external_es))) {
+		lrng_state.lrng_operational = true;
+		lrng_process_ready_list();
+		lrng_init_wakeup();
+		pr_info("LRNG fully operational\n");
+	}
+}
+
+/* Available entropy in the entire LRNG considering all entropy sources */
+u32 lrng_avail_entropy(void)
+{
+	u32 ent_thresh = lrng_security_strength();
+
+	/*
+	 * Apply oversampling during initialization according to SP800-90C as
+	 * we request a larger buffer from the ES.
+	 */
+	if (lrng_sp80090c_compliant() &&
+	    !lrng_state.all_online_numa_node_seeded)
+		ent_thresh += CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS;
+
+	return lrng_pcpu_avail_entropy() + lrng_avail_aux_entropy() +
+	       lrng_archrandom_entropylevel(ent_thresh) +
+	       lrng_jent_entropylevel(ent_thresh);
+}
+
+/*
+ * lrng_init_ops() - Set seed stages of LRNG
+ *
+ * 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
+ */
+void lrng_init_ops(struct entropy_buf *eb)
+{
+	struct lrng_state *state = &lrng_state;
+	u32 requested_bits, seed_bits, external_es;
+
+	if (state->lrng_operational)
+		return;
+
+	requested_bits = lrng_get_seed_entropy_osr(
+					state->all_online_numa_node_seeded);
+
+	/*
+	 * Entropy provided by external entropy sources - if they provide
+	 * the requested amount of entropy, unblock the interface.
+	 */
+	external_es = eb->a_bits + eb->c_bits + eb->d_bits;
+	seed_bits = external_es + eb->b_bits;
+
+	/* DRNG is seeded with full security strength */
+	if (state->lrng_fully_seeded) {
+		lrng_set_operational(external_es);
+		lrng_set_entropy_thresh(requested_bits);
+	} else if (lrng_fully_seeded(state->all_online_numa_node_seeded, eb)) {
+		if (state->can_invalidate)
+			invalidate_batched_entropy();
+
+		state->lrng_fully_seeded = true;
+		lrng_set_operational(external_es);
+		state->lrng_min_seeded = true;
+		pr_info("LRNG fully seeded with %u bits of entropy\n",
+			seed_bits);
+		lrng_set_entropy_thresh(requested_bits);
+	} else if (!state->lrng_min_seeded) {
+
+		/* DRNG is seeded with at least 128 bits of entropy */
+		if (seed_bits >= LRNG_MIN_SEED_ENTROPY_BITS) {
+			if (state->can_invalidate)
+				invalidate_batched_entropy();
+
+			state->lrng_min_seeded = true;
+			pr_info("LRNG minimally seeded with %u bits of entropy\n",
+				seed_bits);
+			lrng_set_entropy_thresh(requested_bits);
+			lrng_init_wakeup();
+
+		/* DRNG is seeded with at least LRNG_INIT_ENTROPY_BITS bits */
+		} else if (seed_bits >= LRNG_INIT_ENTROPY_BITS) {
+			pr_info("LRNG initial entropy level %u bits of entropy\n",
+				seed_bits);
+			lrng_set_entropy_thresh(LRNG_MIN_SEED_ENTROPY_BITS);
+		}
+	}
+}
+
+int __init rand_initialize(void)
+{
+	struct seed {
+		ktime_t time;
+		unsigned long data[(LRNG_MAX_DIGESTSIZE /
+				    sizeof(unsigned long))];
+		struct new_utsname utsname;
+	} seed __aligned(LRNG_KCAPI_ALIGN);
+	unsigned int i;
+
+	BUILD_BUG_ON(LRNG_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_early(&(seed.data[i])) &&
+		    !arch_get_random_long_early(&seed.data[i]))
+			seed.data[i] = random_get_entropy();
+	}
+	memcpy(&seed.utsname, utsname(), sizeof(*(utsname())));
+
+	lrng_pool_insert_aux((u8 *)&seed, sizeof(seed), 0);
+	memzero_explicit(&seed, sizeof(seed));
+
+	/* Initialize the seed work queue */
+	INIT_WORK(&lrng_state.lrng_seed_work, lrng_drng_seed_work);
+	lrng_state.perform_seedwork = true;
+
+	lrng_drngs_init_cc20(true);
+	invalidate_batched_entropy();
+
+	lrng_state.can_invalidate = true;
+
+	return 0;
+}
+
+/* Interface requesting a reseed of the DRNG */
+void lrng_pool_add_entropy(void)
+{
+	/*
+	 * Once all DRNGs are fully seeded, the interrupt noise
+	 * sources will not trigger any reseeding any more.
+	 */
+	if (likely(lrng_state.all_online_numa_node_seeded))
+		return;
+
+	/* Only try to reseed if the DRNG is alive. */
+	if (!lrng_get_available())
+		return;
+
+	/* Only trigger the DRNG reseed if we have collected entropy. */
+	if (lrng_avail_entropy() <
+	    atomic_read_u32(&lrng_state.boot_entropy_thresh))
+		return;
+
+	/* Ensure that the seeding only occurs once at any given time. */
+	if (lrng_pool_trylock())
+		return;
+
+	/* Seed the DRNG with any available noise. */
+	if (lrng_state.perform_seedwork)
+		schedule_work(&lrng_state.lrng_seed_work);
+	else
+		lrng_drng_seed_work(NULL);
+}
+
+/* Fill the seed buffer with data from the noise sources */
+void lrng_fill_seed_buffer(struct entropy_buf *entropy_buf, u32 requested_bits)
+{
+	struct lrng_state *state = &lrng_state;
+	u32 req_ent = lrng_sp80090c_compliant() ?
+			  lrng_security_strength() : LRNG_MIN_SEED_ENTROPY_BITS;
+
+	/* Guarantee that requested bits is a multiple of bytes */
+	BUILD_BUG_ON(LRNG_DRNG_SECURITY_STRENGTH_BITS % 8);
+
+	/* always reseed the DRNG with the current time stamp */
+	entropy_buf->now = random_get_entropy();
+
+	/*
+	 * Require at least 128 bits of entropy for any reseed. If the LRNG 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->lrng_fully_seeded && (lrng_avail_entropy() < req_ent)) {
+		entropy_buf->a_bits = entropy_buf->b_bits = 0;
+		entropy_buf->c_bits = entropy_buf->d_bits = 0;
+		goto wakeup;
+	}
+
+	/* Concatenate the output of the entropy sources. */
+	entropy_buf->b_bits = lrng_pcpu_pool_hash(entropy_buf->b,
+						  requested_bits,
+						  state->lrng_fully_seeded);
+	entropy_buf->c_bits = lrng_get_arch(entropy_buf->c, requested_bits);
+	entropy_buf->d_bits = lrng_get_jent(entropy_buf->d, requested_bits);
+	lrng_get_backtrack_aux(entropy_buf, requested_bits);
+
+	/* allow external entropy provider to provide seed */
+	lrng_state_exseed_allow_all();
+
+wakeup:
+	/*
+	 * Shall we wake up user space writers? This location covers
+	 * ensures that the user space provider does not dominate the internal
+	 * noise sources since in case the first call of this function finds
+	 * sufficient entropy in the entropy pool, it will not trigger the
+	 * wakeup. This implies that when the next /dev/urandom read happens,
+	 * the entropy pool is drained.
+	 */
+	lrng_writer_wakeup();
+}
diff --git a/drivers/char/lrng/lrng_interfaces.c b/drivers/char/lrng/lrng_interfaces.c
new file mode 100644
index 000000000000..6316a534bb54
--- /dev/null
+++ b/drivers/char/lrng/lrng_interfaces.c
@@ -0,0 +1,656 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * LRNG User and kernel space interfaces
+ *
+ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/freezer.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/hw_random.h>
+#include <linux/kthread.h>
+#include <linux/poll.h>
+#include <linux/preempt.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/timex.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/random.h>
+
+#include "lrng_internal.h"
+
+/*
+ * 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 lrng_write_wakeup_bits = (LRNG_WRITE_WAKEUP_ENTROPY << 3);
+
+static LIST_HEAD(lrng_ready_list);
+static DEFINE_SPINLOCK(lrng_ready_list_lock);
+
+static DECLARE_WAIT_QUEUE_HEAD(lrng_write_wait);
+static DECLARE_WAIT_QUEUE_HEAD(lrng_init_wait);
+static struct fasync_struct *fasync;
+
+struct ctl_table random_table[];
+
+/********************************** Helper ***********************************/
+
+/* Is the DRNG seed level too low? */
+static inline bool lrng_need_entropy(void)
+{
+	return (lrng_avail_aux_entropy() < lrng_write_wakeup_bits);
+}
+
+void lrng_writer_wakeup(void)
+{
+	if (lrng_need_entropy() && wq_has_sleeper(&lrng_write_wait)) {
+		wake_up_interruptible(&lrng_write_wait);
+		kill_fasync(&fasync, SIGIO, POLL_OUT);
+	}
+}
+
+void lrng_init_wakeup(void)
+{
+	wake_up_all(&lrng_init_wait);
+	kill_fasync(&fasync, SIGIO, POLL_IN);
+}
+
+/**
+ * lrng_process_ready_list() - Ping all kernel internal callers waiting until
+ * the DRNG is completely initialized to inform that the DRNG reached that
+ * seed level.
+ *
+ * When the SP800-90B testing is enabled, the ping only happens if the SP800-90B
+ * startup health tests are completed. This implies that kernel internal
+ * callers always have an SP800-90B compliant noise source when being
+ * pinged.
+ */
+void lrng_process_ready_list(void)
+{
+	unsigned long flags;
+	struct random_ready_callback *rdy, *tmp;
+
+	if (!lrng_state_operational())
+		return;
+
+	spin_lock_irqsave(&lrng_ready_list_lock, flags);
+	list_for_each_entry_safe(rdy, tmp, &lrng_ready_list, list) {
+		struct module *owner = rdy->owner;
+
+		list_del_init(&rdy->list);
+		rdy->func(rdy);
+		module_put(owner);
+	}
+	spin_unlock_irqrestore(&lrng_ready_list_lock, flags);
+}
+
+void lrng_debug_report_seedlevel(const char *name)
+{
+#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM
+	static void *previous = NULL;
+	void *caller = (void *) _RET_IP_;
+
+	if (READ_ONCE(previous) == caller)
+		return;
+
+	if (!lrng_state_min_seeded())
+		pr_notice("%pS %s called without reaching minimally seeded level (available entropy %u)\n",
+			  caller, name, lrng_avail_entropy());
+
+	WRITE_ONCE(previous, caller);
+#endif
+}
+
+/************************ LRNG kernel input interfaces ************************/
+
+/*
+ * add_hwgenerator_randomness() - Interface for in-kernel drivers of true
+ * hardware RNGs.
+ *
+ * Those devices may produce endless random bits and will be throttled
+ * when our pool is full.
+ *
+ * @buffer: buffer holding the entropic data from HW noise sources to be used to
+ *	    insert into entropy pool.
+ * @count: length of buffer
+ * @entropy_bits: amount of entropy in buffer (value is in bits)
+ */
+void add_hwgenerator_randomness(const char *buffer, size_t count,
+				size_t entropy_bits)
+{
+	/*
+	 * Suspend writing if we are fully loaded with entropy.
+	 * We'll be woken up again once below lrng_write_wakeup_thresh,
+	 * or when the calling thread is about to terminate.
+	 */
+	wait_event_interruptible(lrng_write_wait,
+				lrng_need_entropy() ||
+				lrng_state_exseed_allow(lrng_noise_source_hw) ||
+				kthread_should_stop());
+	lrng_state_exseed_set(lrng_noise_source_hw, false);
+	lrng_pool_insert_aux(buffer, count, entropy_bits);
+}
+EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
+
+/*
+ * add_bootloader_randomness() - Handle random seed passed by bootloader.
+ *
+ * If the seed is trustworthy, it would be regarded as hardware RNGs. Otherwise
+ * it would be regarded as device data.
+ * The decision is controlled by CONFIG_RANDOM_TRUST_BOOTLOADER.
+ *
+ * @buf: buffer holding the entropic data from HW noise sources to be used to
+ *	 insert into entropy pool.
+ * @size: length of buffer
+ */
+void add_bootloader_randomness(const void *buf, unsigned int size)
+{
+	lrng_pool_insert_aux(buf, size,
+			     IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER) ?
+			     size * 8 : 0);
+}
+EXPORT_SYMBOL_GPL(add_bootloader_randomness);
+
+/*
+ * Callback for HID layer -- use the HID event values to stir the entropy pool
+ */
+void add_input_randomness(unsigned int type, unsigned int code,
+			  unsigned int value)
+{
+	static unsigned char last_value;
+
+	/* ignore autorepeat and the like */
+	if (value == last_value)
+		return;
+
+	last_value = value;
+
+	lrng_pcpu_array_add_u32((type << 4) ^ code ^ (code >> 4) ^ value);
+}
+EXPORT_SYMBOL_GPL(add_input_randomness);
+
+/*
+ * add_device_randomness() - Add device- or boot-specific data to the entropy
+ * pool to help initialize it.
+ *
+ * None of this adds any entropy; it is meant to avoid the problem of
+ * the entropy pool having similar initial state across largely
+ * identical devices.
+ *
+ * @buf: buffer holding the entropic data from HW noise sources to be used to
+ *	 insert into entropy pool.
+ * @size: length of buffer
+ */
+void add_device_randomness(const void *buf, unsigned int size)
+{
+	lrng_pool_insert_aux((u8 *)buf, size, 0);
+}
+EXPORT_SYMBOL(add_device_randomness);
+
+#ifdef CONFIG_BLOCK
+void rand_initialize_disk(struct gendisk *disk) { }
+void add_disk_randomness(struct gendisk *disk) { }
+EXPORT_SYMBOL(add_disk_randomness);
+#endif
+
+#ifndef CONFIG_LRNG_IRQ
+void add_interrupt_randomness(int irq, int irq_flg) { }
+EXPORT_SYMBOL(add_interrupt_randomness);
+#endif
+
+/*
+ * del_random_ready_callback() - Delete a previously registered readiness
+ * callback function.
+ *
+ * @rdy: callback definition that was registered initially
+ */
+void del_random_ready_callback(struct random_ready_callback *rdy)
+{
+	unsigned long flags;
+	struct module *owner = NULL;
+
+	spin_lock_irqsave(&lrng_ready_list_lock, flags);
+	if (!list_empty(&rdy->list)) {
+		list_del_init(&rdy->list);
+		owner = rdy->owner;
+	}
+	spin_unlock_irqrestore(&lrng_ready_list_lock, flags);
+
+	module_put(owner);
+}
+EXPORT_SYMBOL(del_random_ready_callback);
+
+/*
+ * add_random_ready_callback() - Add a callback function that will be invoked
+ * when the DRNG is fully initialized and seeded.
+ *
+ * @rdy: callback definition to be invoked when the LRNG is seeded
+ *
+ * Return:
+ * * 0 if callback is successfully added
+ * * -EALREADY if pool is already initialised (callback not called)
+ * * -ENOENT if module for callback is not alive
+ */
+int add_random_ready_callback(struct random_ready_callback *rdy)
+{
+	struct module *owner;
+	unsigned long flags;
+	int err = -EALREADY;
+
+	if (likely(lrng_state_operational()))
+		return err;
+
+	owner = rdy->owner;
+	if (!try_module_get(owner))
+		return -ENOENT;
+
+	spin_lock_irqsave(&lrng_ready_list_lock, flags);
+	if (lrng_state_operational())
+		goto out;
+
+	owner = NULL;
+
+	list_add(&rdy->list, &lrng_ready_list);
+	err = 0;
+
+out:
+	spin_unlock_irqrestore(&lrng_ready_list_lock, flags);
+
+	module_put(owner);
+
+	return err;
+}
+EXPORT_SYMBOL(add_random_ready_callback);
+
+/*********************** LRNG kernel output interfaces ************************/
+
+/*
+ * get_random_bytes() - Provider of cryptographic strong random numbers for
+ * kernel-internal usage.
+ *
+ * This function is appropriate for all in-kernel use cases. However,
+ * it will always use the ChaCha20 DRNG.
+ *
+ * @buf: buffer to store the random bytes
+ * @nbytes: size of the buffer
+ */
+void get_random_bytes(void *buf, int nbytes)
+{
+	lrng_drng_get_atomic((u8 *)buf, (u32)nbytes);
+	lrng_debug_report_seedlevel("get_random_bytes");
+}
+EXPORT_SYMBOL(get_random_bytes);
+
+/*
+ * get_random_bytes_full() - Provider of cryptographic strong random numbers
+ * for kernel-internal usage.
+ *
+ * This function is appropriate only for non-atomic use cases as this
+ * function may sleep. Though, it provides access to the full functionality
+ * of LRNG 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
+ */
+void get_random_bytes_full(void *buf, int nbytes)
+{
+	lrng_drng_get_sleep((u8 *)buf, (u32)nbytes);
+	lrng_debug_report_seedlevel("get_random_bytes_full");
+}
+EXPORT_SYMBOL(get_random_bytes_full);
+
+/*
+ * wait_for_random_bytes() - Wait for the LRNG to be seeded and thus
+ * guaranteed to supply cryptographically secure random numbers.
+ *
+ * This applies to: the /dev/urandom device, the get_random_bytes function,
+ * and the get_random_{u32,u64,int,long} family of functions. Using any of
+ * these functions without first calling this function forfeits the guarantee
+ * of security.
+ *
+ * Return:
+ * * 0 if the LRNG has been seeded.
+ * * -ERESTARTSYS if the function was interrupted by a signal.
+ */
+int wait_for_random_bytes(void)
+{
+	if (likely(lrng_state_min_seeded()))
+		return 0;
+	return wait_event_interruptible(lrng_init_wait,
+					lrng_state_min_seeded());
+}
+EXPORT_SYMBOL(wait_for_random_bytes);
+
+/*
+ * get_random_bytes_arch() - This function will use the architecture-specific
+ * hardware random number generator if it is available.
+ *
+ * The arch-specific hw RNG will almost certainly be faster than what we can
+ * do in software, but it is impossible to verify that it is implemented
+ * securely (as opposed, to, say, the AES encryption of a sequence number using
+ * a key known by the NSA).  So it's useful if we need the speed, but only if
+ * we're willing to trust the hardware manufacturer not to have put in a back
+ * door.
+ *
+ * @buf: buffer allocated by caller to store the random data in
+ * @nbytes: length of outbuf
+ *
+ * Return: number of bytes filled in.
+ */
+int __must_check get_random_bytes_arch(void *buf, int nbytes)
+{
+	u8 *p = buf;
+
+	while (nbytes) {
+		unsigned long v;
+		int chunk = min_t(int, nbytes, sizeof(unsigned long));
+
+		if (!arch_get_random_long(&v))
+			break;
+
+		memcpy(p, &v, chunk);
+		p += chunk;
+		nbytes -= chunk;
+	}
+
+	if (nbytes)
+		lrng_drng_get_atomic((u8 *)p, (u32)nbytes);
+
+	return nbytes;
+}
+EXPORT_SYMBOL(get_random_bytes_arch);
+
+/*
+ * Returns whether or not the LRNG has been seeded.
+ *
+ * Returns: true if the urandom pool has been seeded.
+ *          false if the urandom pool has not been seeded.
+ */
+bool rng_is_initialized(void)
+{
+	return lrng_state_operational();
+}
+EXPORT_SYMBOL(rng_is_initialized);
+
+/************************ LRNG user output interfaces *************************/
+
+static ssize_t lrng_read_common(char __user *buf, size_t nbytes)
+{
+	ssize_t ret = 0;
+	u8 tmpbuf[LRNG_DRNG_BLOCKSIZE] __aligned(LRNG_KCAPI_ALIGN);
+	u8 *tmp_large = NULL, *tmp = tmpbuf;
+	u32 tmplen = sizeof(tmpbuf);
+
+	if (nbytes == 0)
+		return 0;
+
+	/*
+	 * Satisfy large read requests -- as the common case are smaller
+	 * request sizes, such as 16 or 32 bytes, avoid a kmalloc overhead for
+	 * those by using the stack variable of tmpbuf.
+	 */
+	if (!CONFIG_BASE_SMALL && (nbytes > sizeof(tmpbuf))) {
+		tmplen = min_t(u32, nbytes, LRNG_DRNG_MAX_REQSIZE);
+		tmp_large = kmalloc(tmplen + LRNG_KCAPI_ALIGN, GFP_KERNEL);
+		if (!tmp_large)
+			tmplen = sizeof(tmpbuf);
+		else
+			tmp = PTR_ALIGN(tmp_large, LRNG_KCAPI_ALIGN);
+	}
+
+	while (nbytes) {
+		u32 todo = min_t(u32, nbytes, tmplen);
+		int rc = 0;
+
+		/* Reschedule if we received a large request. */
+		if ((tmp_large) && need_resched()) {
+			if (signal_pending(current)) {
+				if (ret == 0)
+					ret = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+		}
+
+		rc = lrng_drng_get_sleep(tmp, todo);
+		if (rc <= 0) {
+			if (rc < 0)
+				ret = rc;
+			break;
+		}
+		if (copy_to_user(buf, tmp, rc)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		nbytes -= rc;
+		buf += rc;
+		ret += rc;
+	}
+
+	/* Wipe data just returned from memory */
+	if (tmp_large)
+		kfree_sensitive(tmp_large);
+	else
+		memzero_explicit(tmpbuf, sizeof(tmpbuf));
+
+	return ret;
+}
+
+static ssize_t
+lrng_read_common_block(int nonblock, char __user *buf, size_t nbytes)
+{
+	if (nbytes == 0)
+		return 0;
+
+	if (unlikely(!lrng_state_operational())) {
+		int ret;
+
+		if (nonblock)
+			return -EAGAIN;
+
+		ret = wait_event_interruptible(lrng_init_wait,
+					       lrng_state_operational());
+		if (unlikely(ret))
+			return ret;
+	}
+
+	return lrng_read_common(buf, nbytes);
+}
+
+static ssize_t lrng_drng_read_block(struct file *file, char __user *buf,
+				     size_t nbytes, loff_t *ppos)
+{
+	return lrng_read_common_block(file->f_flags & O_NONBLOCK, buf, nbytes);
+}
+
+static __poll_t lrng_random_poll(struct file *file, poll_table *wait)
+{
+	__poll_t mask;
+
+	poll_wait(file, &lrng_init_wait, wait);
+	poll_wait(file, &lrng_write_wait, wait);
+	mask = 0;
+	if (lrng_state_operational())
+		mask |= EPOLLIN | EPOLLRDNORM;
+	if (lrng_need_entropy() ||
+	    lrng_state_exseed_allow(lrng_noise_source_user)) {
+		lrng_state_exseed_set(lrng_noise_source_user, false);
+		mask |= EPOLLOUT | EPOLLWRNORM;
+	}
+	return mask;
+}
+
+static ssize_t lrng_drng_write_common(const char __user *buffer, size_t count,
+				      u32 entropy_bits)
+{
+	ssize_t ret = 0;
+	u8 buf[64] __aligned(LRNG_KCAPI_ALIGN);
+	const char __user *p = buffer;
+	u32 orig_entropy_bits = entropy_bits;
+
+	if (!lrng_get_available())
+		return -EAGAIN;
+
+	count = min_t(size_t, count, INT_MAX);
+	while (count > 0) {
+		size_t bytes = min_t(size_t, count, sizeof(buf));
+		u32 ent = min_t(u32, bytes<<3, entropy_bits);
+
+		if (copy_from_user(&buf, p, bytes))
+			return -EFAULT;
+		/* Inject data into entropy pool */
+		lrng_pool_insert_aux(buf, bytes, ent);
+
+		count -= bytes;
+		p += bytes;
+		ret += bytes;
+		entropy_bits -= ent;
+
+		cond_resched();
+	}
+
+	/* Force reseed of DRNG during next data request. */
+	if (!orig_entropy_bits)
+		lrng_drng_force_reseed();
+
+	return ret;
+}
+
+static ssize_t lrng_drng_read(struct file *file, char __user *buf,
+			      size_t nbytes, loff_t *ppos)
+{
+	if (!lrng_state_min_seeded())
+		pr_notice_ratelimited("%s - use of insufficiently seeded DRNG (%zu bytes read)\n",
+				      current->comm, nbytes);
+	else if (!lrng_state_operational())
+		pr_debug_ratelimited("%s - use of not fully seeded DRNG (%zu bytes read)\n",
+				     current->comm, nbytes);
+
+	return lrng_read_common(buf, nbytes);
+}
+
+static ssize_t lrng_drng_write(struct file *file, const char __user *buffer,
+			       size_t count, loff_t *ppos)
+{
+	return lrng_drng_write_common(buffer, count, 0);
+}
+
+static long lrng_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+	u32 digestsize_bits;
+	int size, ent_count_bits;
+	int __user *p = (int __user *)arg;
+
+	switch (cmd) {
+	case RNDGETENTCNT:
+		ent_count_bits = lrng_avail_entropy();
+		if (put_user(ent_count_bits, p))
+			return -EFAULT;
+		return 0;
+	case RNDADDTOENTCNT:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (get_user(ent_count_bits, p))
+			return -EFAULT;
+		ent_count_bits = (int)lrng_avail_aux_entropy() + ent_count_bits;
+		if (ent_count_bits < 0)
+			ent_count_bits = 0;
+		digestsize_bits = lrng_get_digestsize();
+		if (ent_count_bits > digestsize_bits)
+			ent_count_bits = digestsize_bits;
+		lrng_pool_set_entropy(ent_count_bits);
+		return 0;
+	case RNDADDENTROPY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (get_user(ent_count_bits, p++))
+			return -EFAULT;
+		if (ent_count_bits < 0)
+			return -EINVAL;
+		if (get_user(size, p++))
+			return -EFAULT;
+		if (size < 0)
+			return -EINVAL;
+		/* there cannot be more entropy than data */
+		ent_count_bits = min(ent_count_bits, size<<3);
+		return lrng_drng_write_common((const char __user *)p, size,
+					      ent_count_bits);
+	case RNDZAPENTCNT:
+	case RNDCLEARPOOL:
+		/* Clear the entropy pool counter. */
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		lrng_pool_set_entropy(0);
+		return 0;
+	case RNDRESEEDCRNG:
+		/*
+		 * We leave the capability check here since it is present
+		 * in the upstream's RNG implementation. Yet, user space
+		 * can trigger a reseed as easy as writing into /dev/random
+		 * or /dev/urandom where no privilege is needed.
+		 */
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		/* Force a reseed of all DRNGs */
+		lrng_drng_force_reseed();
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int lrng_fasync(int fd, struct file *filp, int on)
+{
+	return fasync_helper(fd, filp, on, &fasync);
+}
+
+const struct file_operations random_fops = {
+	.read  = lrng_drng_read_block,
+	.write = lrng_drng_write,
+	.poll  = lrng_random_poll,
+	.unlocked_ioctl = lrng_ioctl,
+	.compat_ioctl = compat_ptr_ioctl,
+	.fasync = lrng_fasync,
+	.llseek = noop_llseek,
+};
+
+const struct file_operations urandom_fops = {
+	.read  = lrng_drng_read,
+	.write = lrng_drng_write,
+	.unlocked_ioctl = lrng_ioctl,
+	.compat_ioctl = compat_ptr_ioctl,
+	.fasync = lrng_fasync,
+	.llseek = noop_llseek,
+};
+
+SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
+		unsigned int, flags)
+{
+	if (flags & ~(GRND_NONBLOCK|GRND_RANDOM|GRND_INSECURE))
+		return -EINVAL;
+
+	/*
+	 * Requesting insecure and blocking randomness at the same time makes
+	 * no sense.
+	 */
+	if ((flags &
+	     (GRND_INSECURE|GRND_RANDOM)) == (GRND_INSECURE|GRND_RANDOM))
+		return -EINVAL;
+
+	if (count > INT_MAX)
+		count = INT_MAX;
+
+	if (flags & GRND_INSECURE)
+		return lrng_drng_read(NULL, buf, count, NULL);
+
+	return lrng_read_common_block(flags & GRND_NONBLOCK, buf, count);
+}
diff --git a/drivers/char/lrng/lrng_internal.h b/drivers/char/lrng/lrng_internal.h
new file mode 100644
index 000000000000..d67aa3c335b9
--- /dev/null
+++ b/drivers/char/lrng/lrng_internal.h
@@ -0,0 +1,485 @@ 
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * Copyright (C) 2018 - 2021, Stephan Mueller <smueller@chronox.de>
+ */
+
+#ifndef _LRNG_INTERNAL_H
+#define _LRNG_INTERNAL_H
+
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/rwlock.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+/*************************** General LRNG parameter ***************************/
+
+/* Security strength of LRNG -- this must match DRNG security strength */
+#define LRNG_DRNG_SECURITY_STRENGTH_BYTES 32
+#define LRNG_DRNG_SECURITY_STRENGTH_BITS (LRNG_DRNG_SECURITY_STRENGTH_BYTES * 8)
+#define LRNG_DRNG_BLOCKSIZE 64		/* Maximum of DRNG block sizes */
+#define LRNG_DRNG_INIT_SEED_SIZE_BITS (LRNG_DRNG_SECURITY_STRENGTH_BITS +      \
+				       CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS)
+#define LRNG_DRNG_INIT_SEED_SIZE_BYTES (LRNG_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 LRNG_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 LRNG_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. LRNG_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 LRNG is marked as not operational.
+ *
+ * This value is allowed to be changed.
+ */
+#define LRNG_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 LRNG_FULL_SEED_ENTROPY_BITS	LRNG_DRNG_SECURITY_STRENGTH_BITS
+#define LRNG_MIN_SEED_ENTROPY_BITS	128
+#define LRNG_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_LIB_SHA256
+# define LRNG_ATOMIC_DIGEST_SIZE	SHA256_DIGEST_SIZE
+#else
+# define LRNG_ATOMIC_DIGEST_SIZE	SHA1_DIGEST_SIZE
+#endif
+#define LRNG_WRITE_WAKEUP_ENTROPY	LRNG_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_LRNG_DRNG_SWITCH
+# define LRNG_MAX_DIGESTSIZE		64
+#else
+# define LRNG_MAX_DIGESTSIZE		LRNG_ATOMIC_DIGEST_SIZE
+#endif
+
+/*
+ * Oversampling factor of IRQ events to obtain
+ * LRNG_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 LRNG_IRQ_ENTROPY_BITS divided by
+ * LRNG_IRQ_OVERSAMPLING_FACTOR.
+ *
+ * This value is allowed to be changed.
+ */
+#define LRNG_IRQ_OVERSAMPLING_FACTOR	10
+
+/* Alignmask that is intended to be identical to CRYPTO_MINALIGN */
+#define LRNG_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 LRNG_POOL_SIZE	(sizeof(struct shash_desc) + HASH_MAX_DESCSIZE)
+
+/************************ Default DRNG implementation *************************/
+
+extern struct chacha20_state chacha20;
+extern const struct lrng_crypto_cb lrng_cc20_crypto_cb;
+void lrng_cc20_init_state(struct chacha20_state *state);
+
+/********************************** /proc *************************************/
+
+#ifdef CONFIG_SYSCTL
+void lrng_pool_inc_numa_node(void);
+void lrng_proc_update_max_write_thresh(u32 new_digestsize);
+#else
+static inline void lrng_pool_inc_numa_node(void) { }
+static inline void lrng_proc_update_max_write_thresh(u32 new_digestsize) { }
+#endif
+
+/****************************** LRNG interfaces *******************************/
+
+extern u32 lrng_write_wakeup_bits;
+extern int lrng_drng_reseed_max_time;
+
+void lrng_writer_wakeup(void);
+void lrng_init_wakeup(void);
+void lrng_debug_report_seedlevel(const char *name);
+void lrng_process_ready_list(void);
+
+/* External interface to use of the switchable DRBG inside the kernel */
+void get_random_bytes_full(void *buf, int nbytes);
+
+/************************* Jitter RNG Entropy Source **************************/
+
+#ifdef CONFIG_LRNG_JENT
+u32 lrng_get_jent(u8 *outbuf, u32 requested_bits);
+u32 lrng_jent_entropylevel(u32 requested_bits);
+void lrng_jent_es_state(unsigned char *buf, size_t buflen);
+#else /* CONFIG_LRNG_JENT */
+static inline u32 lrng_get_jent(u8 *outbuf, u32 requested_bits) { return 0; }
+static inline u32 lrng_jent_entropylevel(u32 requested_bits) { return 0; }
+static inline void lrng_jent_es_state(unsigned char *buf, size_t buflen) { }
+#endif /* CONFIG_LRNG_JENT */
+
+/************************** CPU-based Entropy Source **************************/
+
+static inline u32 lrng_fast_noise_entropylevel(u32 ent_bits, u32 requested_bits)
+{
+	/* Obtain entropy statement */
+	ent_bits = ent_bits * requested_bits / LRNG_DRNG_SECURITY_STRENGTH_BITS;
+	/* Cap entropy to buffer size in bits */
+	ent_bits = min_t(u32, ent_bits, requested_bits);
+	return ent_bits;
+}
+
+#ifdef CONFIG_LRNG_CPU
+u32 lrng_get_arch(u8 *outbuf, u32 requested_bits);
+u32 lrng_archrandom_entropylevel(u32 requested_bits);
+void lrng_arch_es_state(unsigned char *buf, size_t buflen);
+#else /* CONFIG_LRNG_CPU */
+static inline u32 lrng_get_arch(u8 *outbuf, u32 requested_bits) { return 0; }
+static inline u32 lrng_archrandom_entropylevel(u32 requested_bits) { return 0; }
+static inline void lrng_arch_es_state(unsigned char *buf, size_t buflen) { }
+#endif /* CONFIG_LRNG_CPU */
+
+/************************** Interrupt Entropy Source **************************/
+
+#ifdef CONFIG_LRNG_IRQ
+void lrng_pcpu_reset(void);
+u32 lrng_pcpu_avail_pool_size(void);
+u32 lrng_pcpu_avail_entropy(void);
+int lrng_pcpu_switch_hash(int node,
+			  const struct lrng_crypto_cb *new_cb, void *new_hash,
+			  const struct lrng_crypto_cb *old_cb);
+u32 lrng_pcpu_pool_hash(u8 *outbuf, u32 requested_bits, bool fully_seeded);
+void lrng_pcpu_array_add_u32(u32 data);
+u32 lrng_gcd_analyze(u32 *history, size_t nelem);
+void lrng_irq_es_state(unsigned char *buf, size_t buflen);
+#else /* CONFIG_LRNG_IRQ */
+static inline void lrng_pcpu_reset(void) { }
+static inline u32 lrng_pcpu_avail_pool_size(void) { return 0; }
+static inline u32 lrng_pcpu_avail_entropy(void) { return 0; }
+static inline int lrng_pcpu_switch_hash(int node,
+			  const struct lrng_crypto_cb *new_cb, void *new_hash,
+			  const struct lrng_crypto_cb *old_cb)
+{
+	return 0;
+}
+static inline u32 lrng_pcpu_pool_hash(u8 *outbuf, u32 requested_bits,
+				      bool fully_seeded)
+{
+	return 0;
+}
+static inline void lrng_pcpu_array_add_u32(u32 data) { }
+static inline void lrng_irq_es_state(unsigned char *buf, size_t buflen) { }
+#endif /* CONFIG_LRNG_IRQ */
+
+/****************************** DRNG processing *******************************/
+
+/* DRNG state handle */
+struct lrng_drng {
+	void *drng;				/* DRNG handle */
+	void *hash;				/* Hash handle */
+	const struct lrng_crypto_cb *crypto_cb;	/* Crypto 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 */
+
+	/* Lock write operations on DRNG state, DRNG replacement of crypto_cb */
+	struct mutex lock;
+	spinlock_t spin_lock;
+	/* Lock *hash replacement - always take before DRNG lock */
+	rwlock_t hash_lock;
+};
+
+extern struct mutex lrng_crypto_cb_update;
+
+struct lrng_drng *lrng_drng_init_instance(void);
+struct lrng_drng *lrng_drng_atomic_instance(void);
+
+static __always_inline bool lrng_drng_is_atomic(struct lrng_drng *drng)
+{
+	return (drng->drng == lrng_drng_atomic_instance()->drng);
+}
+
+/* Lock the DRNG */
+static __always_inline void lrng_drng_lock(struct lrng_drng *drng,
+					   unsigned long *flags)
+	__acquires(&drng->spin_lock)
+{
+	/* Use spin lock in case the atomic DRNG context is used */
+	if (lrng_drng_is_atomic(drng)) {
+		spin_lock_irqsave(&drng->spin_lock, *flags);
+
+		/*
+		 * In case a lock transition happened while we were spinning,
+		 * catch this case and use the new lock type.
+		 */
+		if (!lrng_drng_is_atomic(drng)) {
+			spin_unlock_irqrestore(&drng->spin_lock, *flags);
+			__acquire(&drng->spin_lock);
+			mutex_lock(&drng->lock);
+		}
+	} else {
+		__acquire(&drng->spin_lock);
+		mutex_lock(&drng->lock);
+	}
+}
+
+/* Unlock the DRNG */
+static __always_inline void lrng_drng_unlock(struct lrng_drng *drng,
+					     unsigned long *flags)
+	__releases(&drng->spin_lock)
+{
+	if (lrng_drng_is_atomic(drng)) {
+		spin_unlock_irqrestore(&drng->spin_lock, *flags);
+	} else {
+		mutex_unlock(&drng->lock);
+		__release(&drng->spin_lock);
+	}
+}
+
+void lrng_reset(void);
+void lrng_drngs_init_cc20(bool force_seed);
+bool lrng_sp80090c_compliant(void);
+
+static inline u32 lrng_compress_osr(void)
+{
+	return lrng_sp80090c_compliant() ?  CONFIG_LRNG_OVERSAMPLE_ES_BITS : 0;
+}
+
+static inline u32 lrng_reduce_by_osr(u32 entropy_bits)
+{
+	u32 osr_bits = lrng_compress_osr();
+	return (entropy_bits >= osr_bits) ? (entropy_bits - osr_bits) : 0;
+}
+
+bool lrng_get_available(void);
+void lrng_set_available(void);
+void lrng_drng_reset(struct lrng_drng *drng);
+int lrng_drng_get_atomic(u8 *outbuf, u32 outbuflen);
+int lrng_drng_get_sleep(u8 *outbuf, u32 outbuflen);
+void lrng_drng_force_reseed(void);
+void lrng_drng_seed_work(struct work_struct *dummy);
+
+#ifdef CONFIG_NUMA
+struct lrng_drng **lrng_drng_instances(void);
+void lrng_drngs_numa_alloc(void);
+#else	/* CONFIG_NUMA */
+static inline struct lrng_drng **lrng_drng_instances(void) { return NULL; }
+static inline void lrng_drngs_numa_alloc(void) { return; }
+#endif /* CONFIG_NUMA */
+
+/************************* Entropy sources management *************************/
+
+enum lrng_external_noise_source {
+	lrng_noise_source_hw,
+	lrng_noise_source_user
+};
+
+void lrng_set_entropy_thresh(u32 new);
+u32 lrng_avail_entropy(void);
+void lrng_reset_state(void);
+
+bool lrng_state_exseed_allow(enum lrng_external_noise_source source);
+void lrng_state_exseed_set(enum lrng_external_noise_source source, bool type);
+bool lrng_state_min_seeded(void);
+bool lrng_state_fully_seeded(void);
+bool lrng_state_operational(void);
+
+int lrng_pool_trylock(void);
+void lrng_pool_unlock(void);
+void lrng_pool_all_numa_nodes_seeded(bool set);
+void lrng_pool_add_entropy(void);
+
+struct entropy_buf {
+	u8 a[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
+	u8 b[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
+	u8 c[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
+	u8 d[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
+	u32 now, a_bits, b_bits, c_bits, d_bits;
+};
+
+bool lrng_fully_seeded(bool fully_seeded, struct entropy_buf *eb);
+void lrng_unset_fully_seeded(struct lrng_drng *drng);
+void lrng_fill_seed_buffer(struct entropy_buf *entropy_buf, u32 requested_bits);
+void lrng_init_ops(struct entropy_buf *eb);
+
+/*********************** Auxiliary Pool Entropy Source ************************/
+
+u32 lrng_avail_aux_entropy(void);
+void lrng_aux_es_state(unsigned char *buf, size_t buflen);
+u32 lrng_get_digestsize(void);
+void lrng_pool_set_entropy(u32 entropy_bits);
+int lrng_aux_switch_hash(const struct lrng_crypto_cb *new_cb, void *new_hash,
+			 const struct lrng_crypto_cb *old_cb);
+int lrng_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits);
+void lrng_get_backtrack_aux(struct entropy_buf *entropy_buf,
+			    u32 requested_bits);
+
+/* Obtain the security strength of the LRNG in bits */
+static inline u32 lrng_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, LRNG_FULL_SEED_ENTROPY_BITS, lrng_get_digestsize());
+}
+
+static inline u32 lrng_get_seed_entropy_osr(bool fully_seeded)
+{
+	u32 requested_bits = lrng_security_strength();
+
+	/* Apply oversampling during initialization according to SP800-90C */
+	if (lrng_sp80090c_compliant() && !fully_seeded)
+		requested_bits += CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS;
+	return requested_bits;
+}
+
+/************************** Health Test linking code **************************/
+
+enum lrng_health_res {
+	lrng_health_pass,		/* Health test passes on time stamp */
+	lrng_health_fail_use,		/* Time stamp unhealthy, but mix in */
+	lrng_health_fail_drop		/* Time stamp unhealthy, drop it */
+};
+
+#ifdef CONFIG_LRNG_HEALTH_TESTS
+bool lrng_sp80090b_startup_complete(void);
+bool lrng_sp80090b_compliant(void);
+
+enum lrng_health_res lrng_health_test(u32 now_time);
+void lrng_health_disable(void);
+
+#else	/* CONFIG_LRNG_HEALTH_TESTS */
+static inline bool lrng_sp80090b_startup_complete(void) { return true; }
+static inline bool lrng_sp80090b_compliant(void) { return false; }
+
+static inline enum lrng_health_res
+lrng_health_test(u32 now_time) { return lrng_health_pass; }
+static inline void lrng_health_disable(void) { }
+#endif	/* CONFIG_LRNG_HEALTH_TESTS */
+
+/****************************** Helper code ***********************************/
+
+static inline u32 atomic_read_u32(atomic_t *v)
+{
+	return (u32)atomic_read(v);
+}
+
+/******************** Crypto Primitive Switching Support **********************/
+
+#ifdef CONFIG_LRNG_DRNG_SWITCH
+static inline void lrng_hash_lock(struct lrng_drng *drng, unsigned long *flags)
+{
+	read_lock_irqsave(&drng->hash_lock, *flags);
+}
+
+static inline void lrng_hash_unlock(struct lrng_drng *drng, unsigned long flags)
+{
+	read_unlock_irqrestore(&drng->hash_lock, flags);
+}
+#else /* CONFIG_LRNG_DRNG_SWITCH */
+static inline void lrng_hash_lock(struct lrng_drng *drng, unsigned long *flags)
+{ }
+
+static inline void lrng_hash_unlock(struct lrng_drng *drng, unsigned long flags)
+{ }
+#endif /* CONFIG_LRNG_DRNG_SWITCH */
+
+/*************************** Auxiliary functions ******************************/
+
+void invalidate_batched_entropy(void);
+
+/***************************** Testing code ***********************************/
+
+#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY
+bool lrng_raw_hires_entropy_store(u32 value);
+#else	/* CONFIG_LRNG_RAW_HIRES_ENTROPY */
+static inline bool lrng_raw_hires_entropy_store(u32 value) { return false; }
+#endif	/* CONFIG_LRNG_RAW_HIRES_ENTROPY */
+
+#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY
+bool lrng_raw_jiffies_entropy_store(u32 value);
+#else	/* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */
+static inline bool lrng_raw_jiffies_entropy_store(u32 value) { return false; }
+#endif	/* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */
+
+#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY
+bool lrng_raw_irq_entropy_store(u32 value);
+#else	/* CONFIG_LRNG_RAW_IRQ_ENTROPY */
+static inline bool lrng_raw_irq_entropy_store(u32 value) { return false; }
+#endif	/* CONFIG_LRNG_RAW_IRQ_ENTROPY */
+
+#ifdef CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY
+bool lrng_raw_irqflags_entropy_store(u32 value);
+#else	/* CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY */
+static inline bool lrng_raw_irqflags_entropy_store(u32 value) { return false; }
+#endif	/* CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY */
+
+#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY
+bool lrng_raw_retip_entropy_store(u32 value);
+#else	/* CONFIG_LRNG_RAW_RETIP_ENTROPY */
+static inline bool lrng_raw_retip_entropy_store(u32 value) { return false; }
+#endif	/* CONFIG_LRNG_RAW_RETIP_ENTROPY */
+
+#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY
+bool lrng_raw_regs_entropy_store(u32 value);
+#else	/* CONFIG_LRNG_RAW_REGS_ENTROPY */
+static inline bool lrng_raw_regs_entropy_store(u32 value) { return false; }
+#endif	/* CONFIG_LRNG_RAW_REGS_ENTROPY */
+
+#ifdef CONFIG_LRNG_RAW_ARRAY
+bool lrng_raw_array_entropy_store(u32 value);
+#else	/* CONFIG_LRNG_RAW_ARRAY */
+static inline bool lrng_raw_array_entropy_store(u32 value) { return false; }
+#endif	/* CONFIG_LRNG_RAW_ARRAY */
+
+#ifdef CONFIG_LRNG_IRQ_PERF
+bool lrng_perf_time(u32 start);
+#else /* CONFIG_LRNG_IRQ_PERF */
+static inline bool lrng_perf_time(u32 start) { return false; }
+#endif /*CONFIG_LRNG_IRQ_PERF */
+
+#endif /* _LRNG_INTERNAL_H */
diff --git a/include/linux/lrng.h b/include/linux/lrng.h
new file mode 100644
index 000000000000..3e8f93b53c84
--- /dev/null
+++ b/include/linux/lrng.h
@@ -0,0 +1,81 @@ 
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * Copyright (C) 2018 - 2021, Stephan Mueller <smueller@chronox.de>
+ */
+
+#ifndef _LRNG_H
+#define _LRNG_H
+
+#include <crypto/hash.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+
+/*
+ * struct lrng_crypto_cb - cryptographic callback functions
+ * @lrng_drng_name		Name of DRNG
+ * @lrng_hash_name		Name of Hash used for reading entropy pool
+ * @lrng_drng_alloc:		Allocate DRNG -- the provided integer should be
+ *				used for sanity checks.
+ *				return: allocated data structure or PTR_ERR on
+ *					error
+ * @lrng_drng_dealloc:		Deallocate DRNG
+ * @lrng_drng_seed_helper:	Seed the DRNG with data of arbitrary length
+ *				drng: is pointer to data structure allocated
+ *				      with lrng_drng_alloc
+ *				return: >= 0 on success, < 0 on error
+ * @lrng_drng_generate_helper:	Generate random numbers from the DRNG with
+ *				arbitrary length
+ * @lrng_hash_alloc:		Allocate the hash for reading the entropy pool
+ *				return: allocated data structure (NULL is
+ *					success too) or ERR_PTR on error
+ * @lrng_hash_dealloc:		Deallocate Hash
+ * @lrng_hash_digestsize:	Return the digestsize for the used hash to read
+ *				out entropy pool
+ *				hash: is pointer to data structure allocated
+ *				      with lrng_hash_alloc
+ *				return: size of digest of hash in bytes
+ * @lrng_hash_init:		Initialize hash
+ *				hash: is pointer to data structure allocated
+ *				      with lrng_hash_alloc
+ *				return: 0 on success, < 0 on error
+ * @lrng_hash_update:		Update hash operation
+ *				hash: is pointer to data structure allocated
+ *				      with lrng_hash_alloc
+ *				return: 0 on success, < 0 on error
+ * @lrng_hash_final		Final hash operation
+ *				hash: is pointer to data structure allocated
+ *				      with lrng_hash_alloc
+ *				return: 0 on success, < 0 on error
+ * @lrng_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 lrng_crypto_cb {
+	const char *(*lrng_drng_name)(void);
+	const char *(*lrng_hash_name)(void);
+	void *(*lrng_drng_alloc)(u32 sec_strength);
+	void (*lrng_drng_dealloc)(void *drng);
+	int (*lrng_drng_seed_helper)(void *drng, const u8 *inbuf, u32 inbuflen);
+	int (*lrng_drng_generate_helper)(void *drng, u8 *outbuf, u32 outbuflen);
+	void *(*lrng_hash_alloc)(void);
+	void (*lrng_hash_dealloc)(void *hash);
+	u32 (*lrng_hash_digestsize)(void *hash);
+	int (*lrng_hash_init)(struct shash_desc *shash, void *hash);
+	int (*lrng_hash_update)(struct shash_desc *shash, const u8 *inbuf,
+				u32 inbuflen);
+	int (*lrng_hash_final)(struct shash_desc *shash, u8 *digest);
+	void (*lrng_hash_desc_zero)(struct shash_desc *shash);
+};
+
+/* Register cryptographic backend */
+#ifdef CONFIG_LRNG_DRNG_SWITCH
+int lrng_set_drng_cb(const struct lrng_crypto_cb *cb);
+#else	/* CONFIG_LRNG_DRNG_SWITCH */
+static inline int
+lrng_set_drng_cb(const struct lrng_crypto_cb *cb) { return -EOPNOTSUPP; }
+#endif	/* CONFIG_LRNG_DRNG_SWITCH */
+
+#endif /* _LRNG_H */