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 |
> 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.
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
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.
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
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
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
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.
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
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
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.
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
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 --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 */