diff mbox series

[v25,10/12] LRNG - add TRNG support

Message ID 5390778.VeFRgus4bQ@positron.chronox.de (mailing list archive)
State Not Applicable
Delegated to: Herbert Xu
Headers show
Series /dev/random - a new approach with full SP800-90B | expand

Commit Message

Stephan Mueller Nov. 16, 2019, 9:37 a.m. UTC
The True Random Number Generator (TRNG) provides a random number
generator with prediction resistance (SP800-90A terminology) or an NTG.1
(AIS 31 terminology).

When enabled, it obtains random numbers from the entropy pool and
maintains the information with how much entropy it was seeded with. The
TRNG only generates as much output data as it has as entropy.

The secondary DRNGs seed from the TRNG if it is present. In addition,
the /dev/random device accesses the TRNG.

If the TRNG is disabled, the secondary DRNGs seed from the entropy pool
and /dev/random behaves like getrandom(2).

The TRNG benefits from the switchable DRNG support which implies that
data provided via /dev/random is generated by the loaded DRNG.

CC: "Eric W. Biederman" <ebiederm@xmission.com>
CC: "Alexander E. Patrakov" <patrakov@gmail.com>
CC: "Ahmed S. Darwish" <darwish.07@gmail.com>
CC: "Theodore Y. Ts'o" <tytso@mit.edu>
CC: Willy Tarreau <w@1wt.eu>
CC: Matthew Garrett <mjg59@srcf.ucam.org>
CC: Vito Caputo <vcaputo@pengaru.com>
CC: Andreas Dilger <adilger.kernel@dilger.ca>
CC: Jan Kara <jack@suse.cz>
CC: Ray Strode <rstrode@redhat.com>
CC: William Jon McCann <mccann@jhu.edu>
CC: zhangjs <zachary@baishancloud.com>
CC: Andy Lutomirski <luto@kernel.org>
CC: Florian Weimer <fweimer@redhat.com>
CC: Lennart Poettering <mzxreary@0pointer.de>
CC: Nicolai Stange <nstange@suse.de>
Reviewed-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>
Reviewed-by: Roman Drahtmueller <draht@schaltsekun.de>
Tested-by: Roman Drahtmüller <draht@schaltsekun.de>
Tested-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>
Tested-by: Neil Horman <nhorman@redhat.com>
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 drivers/char/lrng/Kconfig     |  22 +++
 drivers/char/lrng/Makefile    |   1 +
 drivers/char/lrng/lrng_trng.c | 283 ++++++++++++++++++++++++++++++++++
 3 files changed, 306 insertions(+)
 create mode 100644 drivers/char/lrng/lrng_trng.c

Comments

Andy Lutomirski Nov. 16, 2019, 4:09 p.m. UTC | #1
> On Nov 16, 2019, at 1:40 AM, Stephan Müller <smueller@chronox.de> wrote:
> 
> The True Random Number Generator (TRNG) provides a random number
> generator with prediction resistance (SP800-90A terminology) or an NTG.1
> (AIS 31 terminology).
> 

...

> The secondary DRNGs seed from the TRNG if it is present. In addition,
> the /dev/random device accesses the TRNG.
> 
> If the TRNG is disabled, the secondary DRNGs seed from the entropy pool
> and /dev/random behaves like getrandom(2).

As mentioned before, I don’t like this API.  An application that, for some reason, needs a TRNG, should have an API by which it either gets a TRNG or an error. Similarly, an application that wants cryptographically secure random numbers efficiently should have an API that does that.  With your design, /dev/random tries to cater to both use cases, but one of the use cases fails depending on kernel config.

I think /dev/random should wait for enough entropy to initialize the system but should not block after that. A TRNG should have an entirely new API that is better than /dev/random.
Stephan Mueller Nov. 17, 2019, 11:10 a.m. UTC | #2
Am Samstag, 16. November 2019, 17:09:09 CET schrieb Andy Lutomirski:

Hi Andy,

> > On Nov 16, 2019, at 1:40 AM, Stephan Müller <smueller@chronox.de> wrote:
> > 
> > The True Random Number Generator (TRNG) provides a random number
> > generator with prediction resistance (SP800-90A terminology) or an NTG.1
> > (AIS 31 terminology).
> 
> ...
> 
> > The secondary DRNGs seed from the TRNG if it is present. In addition,
> > the /dev/random device accesses the TRNG.
> > 
> > If the TRNG is disabled, the secondary DRNGs seed from the entropy pool
> > and /dev/random behaves like getrandom(2).
> 
> As mentioned before, I don’t like this API.  An application that, for some
> reason, needs a TRNG, should have an API by which it either gets a TRNG or
> an error. Similarly, an application that wants cryptographically secure
> random numbers efficiently should have an API that does that.  With your
> design, /dev/random tries to cater to both use cases, but one of the use
> cases fails depending on kernel config.
> 
> I think /dev/random should wait for enough entropy to initialize the system
> but should not block after that. A TRNG should have an entirely new API
> that is better than /dev/random.

I apologize for the misunderstanding. I assumed we would introduce such /dev/
true_random at a later stage.

If you agree, I can certainly add /dev/true_random right now that links with 
the TRNG and make /dev/random behave as discussed, i.e. behave exactly like 
getrandom(..., 0);

As this would introduce a new device file now, is there a special process that 
I need to follow or do I need to copy? Which major/minor number should I use?

Looking into static const struct memdev devlist[] I see

         [8] = { "random", 0666, &random_fops, 0 },
         [9] = { "urandom", 0666, &urandom_fops, 0 },

Shall a true_random be added here with [10]?

Ciao
Stephan
Andy Lutomirski Nov. 19, 2019, 10:07 a.m. UTC | #3
On Sun, Nov 17, 2019 at 3:11 AM Stephan Müller <smueller@chronox.de> wrote:
>
> Am Samstag, 16. November 2019, 17:09:09 CET schrieb Andy Lutomirski:
>
> Hi Andy,
>
> > > On Nov 16, 2019, at 1:40 AM, Stephan Müller <smueller@chronox.de> wrote:
> > >
> > > The True Random Number Generator (TRNG) provides a random number
> > > generator with prediction resistance (SP800-90A terminology) or an NTG.1
> > > (AIS 31 terminology).
> >
> > ...
> >
> > > The secondary DRNGs seed from the TRNG if it is present. In addition,
> > > the /dev/random device accesses the TRNG.
> > >
> > > If the TRNG is disabled, the secondary DRNGs seed from the entropy pool
> > > and /dev/random behaves like getrandom(2).
> >
> > As mentioned before, I don’t like this API.  An application that, for some
> > reason, needs a TRNG, should have an API by which it either gets a TRNG or
> > an error. Similarly, an application that wants cryptographically secure
> > random numbers efficiently should have an API that does that.  With your
> > design, /dev/random tries to cater to both use cases, but one of the use
> > cases fails depending on kernel config.
> >
> > I think /dev/random should wait for enough entropy to initialize the system
> > but should not block after that. A TRNG should have an entirely new API
> > that is better than /dev/random.
>
> I apologize for the misunderstanding. I assumed we would introduce such /dev/
> true_random at a later stage.
>
> If you agree, I can certainly add /dev/true_random right now that links with
> the TRNG and make /dev/random behave as discussed, i.e. behave exactly like
> getrandom(..., 0);

Given that your series is already a decently large ABI change, I think
it would be polite to users to make all the anticipated changes all at
once to reduce the amount of churn everyone needs to deal with.

>
> As this would introduce a new device file now, is there a special process that
> I need to follow or do I need to copy? Which major/minor number should I use?
>
> Looking into static const struct memdev devlist[] I see
>
>          [8] = { "random", 0666, &random_fops, 0 },
>          [9] = { "urandom", 0666, &urandom_fops, 0 },
>
> Shall a true_random be added here with [10]?

I am not at all an expert on chardevs, but this sounds generally
reasonable.  gregkh is probably the real authority here.
Stephan Mueller Nov. 19, 2019, 10:46 a.m. UTC | #4
Am Dienstag, 19. November 2019, 11:07:40 CET schrieb Andy Lutomirski:

Hi Andy,

> On Sun, Nov 17, 2019 at 3:11 AM Stephan Müller <smueller@chronox.de> wrote:
> > Am Samstag, 16. November 2019, 17:09:09 CET schrieb Andy Lutomirski:
> > 
> > Hi Andy,
> > 
> > > > On Nov 16, 2019, at 1:40 AM, Stephan Müller <smueller@chronox.de>
> > > > wrote:
> > > > 
> > > > The True Random Number Generator (TRNG) provides a random number
> > > > generator with prediction resistance (SP800-90A terminology) or an
> > > > NTG.1
> > > > (AIS 31 terminology).
> > > 
> > > ...
> > > 
> > > > The secondary DRNGs seed from the TRNG if it is present. In addition,
> > > > the /dev/random device accesses the TRNG.
> > > > 
> > > > If the TRNG is disabled, the secondary DRNGs seed from the entropy
> > > > pool
> > > > and /dev/random behaves like getrandom(2).
> > > 
> > > As mentioned before, I don’t like this API.  An application that, for
> > > some
> > > reason, needs a TRNG, should have an API by which it either gets a TRNG
> > > or
> > > an error. Similarly, an application that wants cryptographically secure
> > > random numbers efficiently should have an API that does that.  With your
> > > design, /dev/random tries to cater to both use cases, but one of the use
> > > cases fails depending on kernel config.
> > > 
> > > I think /dev/random should wait for enough entropy to initialize the
> > > system
> > > but should not block after that. A TRNG should have an entirely new API
> > > that is better than /dev/random.
> > 
> > I apologize for the misunderstanding. I assumed we would introduce such
> > /dev/ true_random at a later stage.
> > 
> > If you agree, I can certainly add /dev/true_random right now that links
> > with the TRNG and make /dev/random behave as discussed, i.e. behave
> > exactly like getrandom(..., 0);
> 
> Given that your series is already a decently large ABI change, I think
> it would be polite to users to make all the anticipated changes all at
> once to reduce the amount of churn everyone needs to deal with.

I fully agree with that. This is the reason for my question to ask for how to 
approach adding such additional interface for the TRNG. Considering that there 
are use cases for the blocking interfaces, I would like to have it present 
from the start.

That said, are you planning to keep the blocking_pool considering our 
discussion?

But may I ask why you say that there are ABI changes? The LRNG set tries to be 
100% API and ABI compliant to the existing random.c interfaces.

The only change is the runtime-behavior (e.g. time when something is seeded), 
performance of the interrupt handling and the kernel/user interfaces that may 
be noticeable by users. I.e. there are timing changes, but no technical 
changes.

The LRNG though would add one optional interface for kernel internal use and 
then the discussed /dev/true_random interface.
> 
> > As this would introduce a new device file now, is there a special process
> > that I need to follow or do I need to copy? Which major/minor number
> > should I use?
> > 
> > Looking into static const struct memdev devlist[] I see
> > 
> >          [8] = { "random", 0666, &random_fops, 0 },
> >          [9] = { "urandom", 0666, &urandom_fops, 0 },
> > 
> > Shall a true_random be added here with [10]?
> 
> I am not at all an expert on chardevs, but this sounds generally
> reasonable.  gregkh is probably the real authority here.

Thank you for the hint. Then I would like to wait for Greg on this.

Ciao
Stephan
Greg KH Nov. 19, 2019, 12:41 p.m. UTC | #5
On Tue, Nov 19, 2019 at 02:07:40AM -0800, Andy Lutomirski wrote:
> > As this would introduce a new device file now, is there a special process that
> > I need to follow or do I need to copy? Which major/minor number should I use?
> >
> > Looking into static const struct memdev devlist[] I see
> >
> >          [8] = { "random", 0666, &random_fops, 0 },
> >          [9] = { "urandom", 0666, &urandom_fops, 0 },
> >
> > Shall a true_random be added here with [10]?
> 
> I am not at all an expert on chardevs, but this sounds generally
> reasonable.  gregkh is probably the real authority here.

[10] is the aio char device node, so you better not try to overlap it or
bad things will happen :(

thanks,

greg k-h
Stephan Mueller Nov. 20, 2019, 8:58 a.m. UTC | #6
Am Dienstag, 19. November 2019, 13:41:50 CET schrieb Greg Kroah-Hartman:

Hi Greg,

> On Tue, Nov 19, 2019 at 02:07:40AM -0800, Andy Lutomirski wrote:
> > > As this would introduce a new device file now, is there a special
> > > process that I need to follow or do I need to copy? Which major/minor
> > > number should I use?
> > > 
> > > Looking into static const struct memdev devlist[] I see
> > > 
> > >          [8] = { "random", 0666, &random_fops, 0 },
> > >          [9] = { "urandom", 0666, &urandom_fops, 0 },
> > > 
> > > Shall a true_random be added here with [10]?
> > 
> > I am not at all an expert on chardevs, but this sounds generally
> > reasonable.  gregkh is probably the real authority here.
> 
> [10] is the aio char device node, so you better not try to overlap it or
> bad things will happen :(

Thanks for your insights.

Which device minor number could we use?

Or another idea and apologies if I restart this conversation as there was 
already a discussion around it: what about extending the getrandom(2) call 
instead of adding a device file?

What about adding yet another flag to getrandom: GRND_TRUERANDOM and process 
it as follows:

        if (flags & ~(GRND_NONBLOCK|GRND_RANDOM|GRND_INSECURE|
GRND_TRUERANDOM))
                return -EINVAL;

        //From Andy's tree
        /*
         * Requesting insecure and blocking randomness at the same time makes
         * no sense.
         */
        if ((flags & (GRND_INSECURE|GRND_RANDOM)) == (GRND_INSECURE|
GRND_RANDOM))
                return -EINVAL;

	  /* We only allow GRND_TRUERANDOM by itself or with NONBLOCK */
	  if (! ((flags & GRND_TRUERANDOM) &&
               ((flags == GRND_TRUERANDOM) ||
                (flags == GRND_TRUERANDOM | GRND_NONBLOCK))))
		return -EINVAL;

	if (flags & GRND_TRUERANDOM) {
		... do the TRNG processing ...
		... may return -ENOPNOTSUPP if no TRNG available ...
	}

Thanks a lot.


Ciao
Stephan
Alexander Patrakov Nov. 20, 2019, 9:55 a.m. UTC | #7
20.11.2019 13:58, Stephan Müller пишет:

> Or another idea and apologies if I restart this conversation as there was
> already a discussion around it: what about extending the getrandom(2) call
> instead of adding a device file?
> 
> What about adding yet another flag to getrandom: GRND_TRUERANDOM and process
> it as follows:
> 
>          if (flags & ~(GRND_NONBLOCK|GRND_RANDOM|GRND_INSECURE|
> GRND_TRUERANDOM))
>                  return -EINVAL;
> 
>          //From Andy's tree
>          /*
>           * Requesting insecure and blocking randomness at the same time makes
>           * no sense.
>           */
>          if ((flags & (GRND_INSECURE|GRND_RANDOM)) == (GRND_INSECURE|
> GRND_RANDOM))
>                  return -EINVAL;
> 
> 	  /* We only allow GRND_TRUERANDOM by itself or with NONBLOCK */
> 	  if (! ((flags & GRND_TRUERANDOM) &&
>                 ((flags == GRND_TRUERANDOM) ||
>                  (flags == GRND_TRUERANDOM | GRND_NONBLOCK))))
> 		return -EINVAL;
> 
> 	if (flags & GRND_TRUERANDOM) {
> 		... do the TRNG processing ...
> 		... may return -ENOPNOTSUPP if no TRNG available ...
> 	}

This would totally miss the point of adding a device node: UNIX 
permissions that don't allow "others" to read and deplete "true" random 
numbers.
Greg KH Nov. 20, 2019, 1:29 p.m. UTC | #8
On Wed, Nov 20, 2019 at 09:58:35AM +0100, Stephan Müller wrote:
> Am Dienstag, 19. November 2019, 13:41:50 CET schrieb Greg Kroah-Hartman:
> 
> Hi Greg,
> 
> > On Tue, Nov 19, 2019 at 02:07:40AM -0800, Andy Lutomirski wrote:
> > > > As this would introduce a new device file now, is there a special
> > > > process that I need to follow or do I need to copy? Which major/minor
> > > > number should I use?
> > > > 
> > > > Looking into static const struct memdev devlist[] I see
> > > > 
> > > >          [8] = { "random", 0666, &random_fops, 0 },
> > > >          [9] = { "urandom", 0666, &urandom_fops, 0 },
> > > > 
> > > > Shall a true_random be added here with [10]?
> > > 
> > > I am not at all an expert on chardevs, but this sounds generally
> > > reasonable.  gregkh is probably the real authority here.
> > 
> > [10] is the aio char device node, so you better not try to overlap it or
> > bad things will happen :(
> 
> Thanks for your insights.
> 
> Which device minor number could we use?

Get your own dynamic one by using a misc device if you _REALLY_ want to
add yet-another-char-node-for-random-data.

But I would have thought that we all realize that this is not the way to
do things.  Let's not have "random", "urandom", and "true_random" be
something we want to totally confuse userspace with, that way is insane.

Please just make the existing userspace api "just work", don't add to
the mess.

thanks,

greg k-h
Stephan Mueller Nov. 20, 2019, 7:51 p.m. UTC | #9
Am Mittwoch, 20. November 2019, 14:29:18 CET schrieb Greg Kroah-Hartman:

Hi Greg,

> On Wed, Nov 20, 2019 at 09:58:35AM +0100, Stephan Müller wrote:
> > Am Dienstag, 19. November 2019, 13:41:50 CET schrieb Greg Kroah-Hartman:
> > 
> > Hi Greg,
> > 
> > > On Tue, Nov 19, 2019 at 02:07:40AM -0800, Andy Lutomirski wrote:
> > > > > As this would introduce a new device file now, is there a special
> > > > > process that I need to follow or do I need to copy? Which
> > > > > major/minor
> > > > > number should I use?
> > > > > 
> > > > > Looking into static const struct memdev devlist[] I see
> > > > > 
> > > > >          [8] = { "random", 0666, &random_fops, 0 },
> > > > >          [9] = { "urandom", 0666, &urandom_fops, 0 },
> > > > > 
> > > > > Shall a true_random be added here with [10]?
> > > > 
> > > > I am not at all an expert on chardevs, but this sounds generally
> > > > reasonable.  gregkh is probably the real authority here.
> > > 
> > > [10] is the aio char device node, so you better not try to overlap it or
> > > bad things will happen :(
> > 
> > Thanks for your insights.
> > 
> > Which device minor number could we use?
> 
> Get your own dynamic one by using a misc device if you _REALLY_ want to
> add yet-another-char-node-for-random-data.
> 
> But I would have thought that we all realize that this is not the way to
> do things.  Let's not have "random", "urandom", and "true_random" be
> something we want to totally confuse userspace with, that way is insane.
> 
> Please just make the existing userspace api "just work", don't add to
> the mess.

Thank you, I think we should follow that advise.

With that and considering Alexander's rightful remark we have a challenge. So, 
changing the syscall may not be the right way unless we find a way to restrict 
the permissions somehow (capability? LSM? None of that seems to be a good 
fit).

What about providing a /sys file? I.e. adding a file that:

a) has permissions 440 per default and maybe the ownership of root:root

b) allow user space to perform a chown/chgrp

c) only supports reading of data from user space

But then, how could we provide a common interface for the existing random.c 
and the LRNG?

Or should we use a proc file for that? If yes, I guess it should not be a 
sysctl, but a "regular" proc file that should allow a chown(2) operation. On 
the other hand, is proc the right place to provide a user space interface for 
exporting data to user?

Thanks a lot.

Ciao
Stephan
Alexander Patrakov Nov. 20, 2019, 7:57 p.m. UTC | #10
21.11.2019 00:51, Stephan Müller пишет:
> Am Mittwoch, 20. November 2019, 14:29:18 CET schrieb Greg Kroah-Hartman:
> 
> Hi Greg,
> 
>> On Wed, Nov 20, 2019 at 09:58:35AM +0100, Stephan Müller wrote:
>>> Am Dienstag, 19. November 2019, 13:41:50 CET schrieb Greg Kroah-Hartman:
>>>
>>> Hi Greg,
>>>
>>>> On Tue, Nov 19, 2019 at 02:07:40AM -0800, Andy Lutomirski wrote:
>>>>>> As this would introduce a new device file now, is there a special
>>>>>> process that I need to follow or do I need to copy? Which
>>>>>> major/minor
>>>>>> number should I use?
>>>>>>
>>>>>> Looking into static const struct memdev devlist[] I see
>>>>>>
>>>>>>           [8] = { "random", 0666, &random_fops, 0 },
>>>>>>           [9] = { "urandom", 0666, &urandom_fops, 0 },
>>>>>>
>>>>>> Shall a true_random be added here with [10]?
>>>>>
>>>>> I am not at all an expert on chardevs, but this sounds generally
>>>>> reasonable.  gregkh is probably the real authority here.
>>>>
>>>> [10] is the aio char device node, so you better not try to overlap it or
>>>> bad things will happen :(
>>>
>>> Thanks for your insights.
>>>
>>> Which device minor number could we use?
>>
>> Get your own dynamic one by using a misc device if you _REALLY_ want to
>> add yet-another-char-node-for-random-data.
>>
>> But I would have thought that we all realize that this is not the way to
>> do things.  Let's not have "random", "urandom", and "true_random" be
>> something we want to totally confuse userspace with, that way is insane.
>>
>> Please just make the existing userspace api "just work", don't add to
>> the mess.
> 
> Thank you, I think we should follow that advise.
> 
> With that and considering Alexander's rightful remark we have a challenge. So,
> changing the syscall may not be the right way unless we find a way to restrict
> the permissions somehow (capability? LSM? None of that seems to be a good
> fit).
> 
> What about providing a /sys file? I.e. adding a file that:
> 
> a) has permissions 440 per default and maybe the ownership of root:root
> 
> b) allow user space to perform a chown/chgrp
> 
> c) only supports reading of data from user space
> 
> But then, how could we provide a common interface for the existing random.c
> and the LRNG?
> 
> Or should we use a proc file for that? If yes, I guess it should not be a
> sysctl, but a "regular" proc file that should allow a chown(2) operation. On
> the other hand, is proc the right place to provide a user space interface for
> exporting data to user?
> 
> Thanks a lot.
> 
> Ciao
> Stephan
> 
> 

I'd say that a sys or proc file is worse than a device node, because the 
wanted semantics are exactly those of a device node. Besides, a chown of 
a sysfs file is something not friendly to containers. We may need 
different uids in different containers to be able to access true random 
data.
Greg KH Nov. 20, 2019, 8:32 p.m. UTC | #11
On Wed, Nov 20, 2019 at 08:51:11PM +0100, Stephan Müller wrote:
> Am Mittwoch, 20. November 2019, 14:29:18 CET schrieb Greg Kroah-Hartman:
> 
> Hi Greg,
> 
> > On Wed, Nov 20, 2019 at 09:58:35AM +0100, Stephan Müller wrote:
> > > Am Dienstag, 19. November 2019, 13:41:50 CET schrieb Greg Kroah-Hartman:
> > > 
> > > Hi Greg,
> > > 
> > > > On Tue, Nov 19, 2019 at 02:07:40AM -0800, Andy Lutomirski wrote:
> > > > > > As this would introduce a new device file now, is there a special
> > > > > > process that I need to follow or do I need to copy? Which
> > > > > > major/minor
> > > > > > number should I use?
> > > > > > 
> > > > > > Looking into static const struct memdev devlist[] I see
> > > > > > 
> > > > > >          [8] = { "random", 0666, &random_fops, 0 },
> > > > > >          [9] = { "urandom", 0666, &urandom_fops, 0 },
> > > > > > 
> > > > > > Shall a true_random be added here with [10]?
> > > > > 
> > > > > I am not at all an expert on chardevs, but this sounds generally
> > > > > reasonable.  gregkh is probably the real authority here.
> > > > 
> > > > [10] is the aio char device node, so you better not try to overlap it or
> > > > bad things will happen :(
> > > 
> > > Thanks for your insights.
> > > 
> > > Which device minor number could we use?
> > 
> > Get your own dynamic one by using a misc device if you _REALLY_ want to
> > add yet-another-char-node-for-random-data.
> > 
> > But I would have thought that we all realize that this is not the way to
> > do things.  Let's not have "random", "urandom", and "true_random" be
> > something we want to totally confuse userspace with, that way is insane.
> > 
> > Please just make the existing userspace api "just work", don't add to
> > the mess.
> 
> Thank you, I think we should follow that advise.
> 
> With that and considering Alexander's rightful remark we have a challenge. So, 
> changing the syscall may not be the right way unless we find a way to restrict 
> the permissions somehow (capability? LSM? None of that seems to be a good 
> fit).
> 
> What about providing a /sys file? I.e. adding a file that:
> 
> a) has permissions 440 per default and maybe the ownership of root:root
> 
> b) allow user space to perform a chown/chgrp
> 
> c) only supports reading of data from user space
> 
> But then, how could we provide a common interface for the existing random.c 
> and the LRNG?
> 
> Or should we use a proc file for that? If yes, I guess it should not be a 
> sysctl, but a "regular" proc file that should allow a chown(2) operation. On 
> the other hand, is proc the right place to provide a user space interface for 
> exporting data to user?

No, do not abuse sysfs or procfs for something like this.  Use a real
syscall please if you really need it.

greg k-h
Stephan Mueller Nov. 21, 2019, 1:06 p.m. UTC | #12
Am Mittwoch, 20. November 2019, 21:32:32 CET schrieb Greg Kroah-Hartman:

Hi Greg,

> No, do not abuse sysfs or procfs for something like this.  Use a real
> syscall please if you really need it.

You are right.

Ok, let us get back to the drawing board. What are our requirements? We need 
to have an interface for the TRNG that should ensure other users of entropy 
are not starved by unprivileged users.

What about the following: we use the getrandom(2) system call and add 
GRND_TRUERANDOM as already indicated. However, there is one more caveat we 
would add:

- if the caller of GRND_TRUERANDOM is !CAP_SYS_ADMIN the entropy pool can only 
be depleted to the point where at least one or two full seeding operations 
worth of entropy is left.

- if the caller of GRND_TRUERANDOM is CAP_SYS_ADMIN, the entropy can be 
depleted completely

At runtime, the LRNG would then behave like the following:

- calling getrandom(..., 0), /dev/random or /dev/urandom would deplete the 
entropy pool during reseeding operations but leaving an emergency level of 512 
bits of entropy in the pool. If equal or less are in the pool, reseeding would 
be skipped.

- calling getrandom(..., GRND_TRUERANDOM) with CAP_SYS_ADMIN allows the 
entropy pool to be fully depleted.

- calling getrandom(..., GRND_TRUERANDOM) without CAP_SYS_ADMIN allows the 
entropy pool to be depleted down to 1024 bits of entropy. If the pool has 
equal or less, the caller is blocked. This allows the DRNG feeding /dev/
random, /dev/urandom or getrandom(..., 0) with 512 bits of entropy (i.e. two 
reseed operations are possible). Only if the entropy pool has more than 1024 
bits of entropy, the getrandom call would unblock and provide data.

With that approach, I think we can honor the request from Greg to not add any 
new interface and yet honor the note from Alexander to not allow unprivileged 
user space to deplete the entropy pool to the extent that other users of 
entropy are too much affected.

If GRND_TRUERANDOM is not implemented, EOPNOTSUPP is returned.

Thank you.

Ciao
Stephan
diff mbox series

Patch

diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig
index 80fc723c67d2..122d67ee110e 100644
--- a/drivers/char/lrng/Kconfig
+++ b/drivers/char/lrng/Kconfig
@@ -91,4 +91,26 @@  config LRNG_JENT
 	  time or at runtime with the lrng_base.jitterrng configuration
 	  variable.
 
+config LRNG_TRNG_SUPPORT
+	bool "Enable True Random Number Generator support"
+	default y
+	help
+	  The true random number generator (TRNG) support, also
+	  known as DRNG with prediction resistance (SP800-90A
+	  terminology) or NTG.1 (AIS 31 terminology), generates
+	  random numbers after a successful reseed with entropy.
+	  Only when new entropy is provided for a new generation
+	  request, random data is provided with an equal amount
+	  as entropy was added. The TRNG is available via
+	  /dev/random.
+
+	  If the support is not enabled, /dev/random ensures that
+	  it received sufficient initial entropy and will produce
+	  random data without requiring a constant reseed with
+	  entropy. Yet it tries to regularly reseed itself with
+	  fresh entropy.
+
+	  With the TRNG support the /dev/random device will block
+	  if insufficient entropy is available.
+
 endif # LRNG
diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile
index a87d800c9aae..1c72bc060bce 100644
--- a/drivers/char/lrng/Makefile
+++ b/drivers/char/lrng/Makefile
@@ -14,3 +14,4 @@  obj-$(CONFIG_LRNG_DRNG_SWITCH)	+= lrng_switch.o
 obj-$(CONFIG_LRNG_DRBG)		+= lrng_drbg.o
 obj-$(CONFIG_LRNG_KCAPI)	+= lrng_kcapi.o
 obj-$(CONFIG_LRNG_JENT)		+= lrng_jent.o
+obj-$(CONFIG_LRNG_TRNG_SUPPORT)	+= lrng_trng.o
diff --git a/drivers/char/lrng/lrng_trng.c b/drivers/char/lrng/lrng_trng.c
new file mode 100644
index 000000000000..52ea33342a3f
--- /dev/null
+++ b/drivers/char/lrng/lrng_trng.c
@@ -0,0 +1,283 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * LRNG True Random Number Generator (TRNG) processing
+ *
+ * Copyright (C) 2016 - 2019, Stephan Mueller <smueller@chronox.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/lrng.h>
+
+#include "lrng_internal.h"
+
+/* TRNG state handle */
+struct lrng_trng {
+	void *trng;				/* TRNG handle */
+	void *hash;				/* Hash handle */
+	u32 trng_entropy_bits;			/* TRNG entropy level */
+	const struct lrng_crypto_cb *crypto_cb;	/* Crypto callbacks */
+	struct mutex lock;
+};
+
+/* TRNG for /dev/random and seed source for the secondary DRNG(s) */
+static struct lrng_trng lrng_trng = {
+	.trng		= &primary_chacha20,
+	.crypto_cb	= &lrng_cc20_crypto_cb,
+	.lock		= __MUTEX_INITIALIZER(lrng_trng.lock)
+};
+
+/********************************** Helper ************************************/
+
+void lrng_trng_reset(void)
+{
+	lrng_trng.trng_entropy_bits = 0;
+	pr_debug("reset TRNG\n");
+}
+
+void lrng_trng_init(void)
+{
+	mutex_lock(&lrng_trng.lock);
+	lrng_trng_reset();
+	lrng_cc20_init_state(&primary_chacha20);
+	mutex_unlock(&lrng_trng.lock);
+}
+
+/************************* Random Number Generation ***************************/
+
+/* Caller must hold lrng_trng.lock */
+static int lrng_trng_generate(u8 *outbuf, u32 outbuflen)
+{
+	struct lrng_trng *trng = &lrng_trng;
+	const struct lrng_crypto_cb *crypto_cb = trng->crypto_cb;
+	int ret;
+
+	/*
+	 * Only deliver as many bytes as the DRNG is seeded with except during
+	 * initialization to provide a first seed to the secondary DRNG.
+	 */
+	if (lrng_state_min_seeded())
+		outbuflen = min_t(u32, outbuflen, trng->trng_entropy_bits>>3);
+	else
+		outbuflen = min_t(u32, outbuflen,
+				  LRNG_MIN_SEED_ENTROPY_BITS>>3);
+	if (!outbuflen)
+		return 0;
+
+	ret = crypto_cb->lrng_drng_generate_helper_full(trng->trng, outbuf,
+							outbuflen);
+	if (ret != outbuflen) {
+		pr_warn("getting random data from TRNG failed (%d)\n",
+			ret);
+		return ret;
+	}
+
+	if (trng->trng_entropy_bits > (u32)(ret<<3))
+		trng->trng_entropy_bits -= ret<<3;
+	else
+		trng->trng_entropy_bits = 0;
+	pr_debug("obtained %d bytes of random data from TRNG\n", ret);
+	pr_debug("TRNG entropy level at %u bits\n",
+		 trng->trng_entropy_bits);
+
+	return ret;
+}
+
+/**
+ * Inject data into the TRNG with a given entropy value. The function calls
+ * the DRNG's update function. This function also generates random data if
+ * requested by caller. The caller is only returned the amount of random data
+ * that is at most equal to the amount of entropy that just seeded the DRNG.
+ *
+ * Note, this function seeds the TRNG and generates data in an atomic operation.
+ *
+ * @inbuf: buffer to inject
+ * @inbuflen: length of inbuf
+ * @entropy_bits: entropy value of the data in inbuf in bits
+ * @outbuf: buffer to fill immediately after seeding to get full entropy
+ * @outbuflen: length of outbuf
+ * @return: number of bytes written to outbuf, 0 if outbuf is not supplied,
+ *	    or < 0 in case of error
+ */
+static int lrng_trng_inject(const u8 *inbuf, u32 inbuflen, u32 entropy_bits,
+			    u8 *outbuf, u32 outbuflen)
+{
+	struct lrng_trng *trng = &lrng_trng;
+	int ret;
+
+	/* cap the maximum entropy value to the provided data length */
+	entropy_bits = min_t(u32, entropy_bits, inbuflen<<3);
+
+	mutex_lock(&trng->lock);
+	ret = trng->crypto_cb->lrng_drng_seed_helper(trng->trng, inbuf,
+						      inbuflen);
+	if (ret < 0) {
+		pr_warn("(re)seeding of TRNG failed\n");
+		goto unlock;
+	}
+	pr_debug("inject %u bytes with %u bits of entropy into TRNG\n",
+		 inbuflen, entropy_bits);
+
+	/* Adjust the fill level indicator to at most the DRNG sec strength */
+	trng->trng_entropy_bits =
+		min_t(u32, trng->trng_entropy_bits + entropy_bits,
+		      LRNG_DRNG_SECURITY_STRENGTH_BITS);
+	lrng_init_ops(trng->trng_entropy_bits);
+
+	if (outbuf && outbuflen)
+		ret = lrng_trng_generate(outbuf, outbuflen);
+
+unlock:
+	mutex_unlock(&trng->lock);
+	lrng_reader_wakeup();
+
+	return ret;
+}
+
+/**
+ * Seed the TRNG from the internal noise sources and generate random data. The
+ * seeding and the generation of random data is an atomic operation.
+ *
+ * lrng_pool_trylock() must be invoked successfully by caller.
+ */
+int lrng_trng_seed(u8 *outbuf, u32 outbuflen, bool drain)
+{
+	struct entropy_buf entropy_buf __aligned(LRNG_KCAPI_ALIGN);
+	struct lrng_trng *trng = &lrng_trng;
+	u32 total_entropy_bits;
+	int ret = 0, retrieved = 0;
+
+	/* Get available entropy in primary DRNG */
+	if (trng->trng_entropy_bits>>3) {
+		mutex_lock(&trng->lock);
+		ret = lrng_trng_generate(outbuf, outbuflen);
+		mutex_unlock(&trng->lock);
+		if (ret > 0) {
+			retrieved += ret;
+			if (ret == outbuflen)
+				goto out;
+
+			outbuf += ret;
+			outbuflen -= ret;
+		}
+		/* Disregard error code as another generate request is below. */
+	}
+
+	mutex_lock(&trng->lock);
+	total_entropy_bits = lrng_fill_seed_buffer(trng->crypto_cb, trng->hash,
+						   &entropy_buf, drain);
+	mutex_unlock(&trng->lock);
+
+	pr_debug("reseed TRNG from internal noise sources with %u bits "
+		 "of entropy\n", total_entropy_bits);
+
+	ret = lrng_trng_inject((u8 *)&entropy_buf, sizeof(entropy_buf),
+				total_entropy_bits,
+				outbuf, outbuflen);
+
+	memzero_explicit(&entropy_buf, sizeof(entropy_buf));
+
+	if (ret > 0)
+		retrieved += ret;
+
+out:
+	/* Allow the seeding operation to be called again */
+	lrng_pool_unlock();
+
+	return (ret >= 0) ? retrieved : ret;
+}
+
+/**
+ * Obtain random data from TRNG with information theoretical entropy by
+ * triggering a reseed. The TRNG will only return as many random bytes as it
+ * was seeded with.
+ *
+ * @outbuf: buffer to store the random data in
+ * @outbuflen: length of outbuf
+ * @return: < 0 on error
+ *	    >= 0 the number of bytes that were obtained
+ */
+int lrng_trng_get(u8 *outbuf, u32 outbuflen)
+{
+	int ret;
+
+	if (!outbuf || !outbuflen)
+		return 0;
+
+	lrng_drngs_init_cc20();
+
+	if (lrng_pool_trylock())
+		return -EINPROGRESS;
+	ret = lrng_trng_seed(outbuf, outbuflen, true);
+	if (ret >= 0) {
+		pr_debug("read %d bytes of full entropy data from TRNG\n", ret);
+	} else {
+		/* This is no error, but we have not generated anything */
+		if (ret == -EINPROGRESS)
+			return 0;
+		pr_debug("reading data from TRNG failed: %d\n", ret);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_LRNG_DRNG_SWITCH
+int lrng_trng_switch(const struct lrng_crypto_cb *cb)
+{
+	int ret;
+	u8 seed[LRNG_DRNG_SECURITY_STRENGTH_BYTES];
+	void *trng, *hash;
+
+	trng = cb->lrng_drng_alloc(LRNG_DRNG_SECURITY_STRENGTH_BYTES);
+	if (IS_ERR(trng))
+		return PTR_ERR(trng);
+
+	hash = cb->lrng_hash_alloc(seed, sizeof(seed));
+	if (IS_ERR(hash)) {
+		pr_warn("could not allocate new LRNG pool hash (%ld)\n",
+			PTR_ERR(hash));
+		cb->lrng_drng_dealloc(trng);
+		return PTR_ERR(hash);
+	}
+
+	/* Update primary DRNG */
+	mutex_lock(&lrng_trng.lock);
+	/* pull from existing DRNG to seed new DRNG */
+	ret = lrng_trng.crypto_cb->lrng_drng_generate_helper_full(
+					lrng_trng.trng, seed, sizeof(seed));
+	if (ret < 0) {
+		lrng_trng_reset();
+		pr_warn("getting random data from TRNG failed (%d)\n", ret);
+	} else {
+		/*
+		 * No change of the seed status as the old and new DRNG have
+		 * same security strength.
+		 */
+		ret = cb->lrng_drng_seed_helper(trng, seed, ret);
+		if (ret < 0) {
+			lrng_trng_reset();
+			pr_warn("seeding of new TRNG failed (%d)\n", ret);
+		} else {
+			pr_debug("seeded new TRNG instance from old TRNG "
+				 "instance\n");
+		}
+	}
+	memzero_explicit(seed, sizeof(seed));
+
+	if (!lrng_get_available())
+		lrng_trng_reset();
+	lrng_trng.crypto_cb->lrng_drng_dealloc(lrng_trng.trng);
+	lrng_trng.trng = trng;
+
+	lrng_trng.crypto_cb->lrng_hash_dealloc(lrng_trng.hash);
+	lrng_trng.hash = hash;
+
+	lrng_trng.crypto_cb = cb;
+
+	mutex_unlock(&lrng_trng.lock);
+
+	pr_info("TRNG allocated\n");
+
+	return ret;
+}
+#endif	/* CONFIG_LRNG_DRNG_SWITCH */