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 |
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.
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
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
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
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
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
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
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
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 >
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 >
> 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
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
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
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
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
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
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
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
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
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
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
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
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.
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
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.
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
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
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
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
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
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.
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
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
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
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
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.
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
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
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.
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
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.
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.
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.
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.
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.
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?
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
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
> 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
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.
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
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
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
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
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.
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
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
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
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 >
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
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
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/
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
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
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
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
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.
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
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
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; }
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/
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/
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
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
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.
(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.
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
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
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
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
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 --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 */