xiaoxiang781216 edited a comment on pull request #2488:
URL: https://github.com/apache/incubator-nuttx/pull/2488#issuecomment-740693509


   > It is good it failed to compile. That allows programmer to notice, that 
maybe something is different for NuttX. Users should not expect that Linux man 
pages describe NuttX APIs. This is especially important for security code. I 
have seen at least one TLS implementation that resorts back to using rand() if 
getrandom() fails. It is very good that that kind of insecure code fails to 
compile for NuttX!
   > 
   
   But now you directly ignore the error at all, could you tell me how can the 
caller handle these error case securely?
   
   1. nxsem_wait_uninterruptible return fail
   2. user call getrandom too early and then no enough entropy is collected yet
   
   > It is unfortunate the NuttX function is called getrandom(). I originally 
wanted it to have a distinctive name, but it was changed to getrandom() by 
other people.
   > 
   > This commit just introduces more confusion to system as it adds things 
that do not work or are contradicting existing code, like this piece in 
comments:
   > 
   > `GRND_NONBLOCK Don't block and return EAGAIN instead`
   > 
   
   If some flags don't make sense, we can remove it, but the prototype should 
keep consistently with the practice.
   
   > NuttX getrandom() cannot return EGAIN and it cannot block (for an 
indefinite time at least, as the semaphore there can not really cause 
starvation). Comment is incorrect, because it hints that getrandom() blocks by 
default. On Linux it does, which is just another design failure of the Linux 
version. Why should we ever block for random numbers, or even have a blocking 
API, since we already have the ability to generate nearly infinite sequences of 
them without blocking?
   > 
   
   No, from the spec:
   ```
   GRND_NONBLOCK
                 By default, when reading from the random source, getrandom()
                 blocks if no random bytes are available, and when reading from
                 the urandom source, it blocks if the entropy pool has not yet
                 been initialized.  If the GRND_NONBLOCK flag is set, then
                 getrandom() does not block in these cases, but instead
                 immediately returns -1 with errno set to EAGAIN.
   ```
   If the entropy isn't collected enough, we should block and wait the enough 
entropy by default, or return -1 with errno set to EAGAIN if user pass 
GRND_NONBLOCK. But your implementation just log a warning:
   ```
   static void rng_buf_internal(FAR void *bytes, size_t nbytes)
   {
     if (!g_rng.output_initialized)
       {
         if (g_rng.rd_newentr < MIN_SEED_NEW_ENTROPY_WORDS)
           {
             cryptwarn("Entropy pool RNG initialized with very low entropy. "
                       " Consider implementing CONFIG_BOARD_INITRNGSEED!\n");
           }
         rng_reseed();
       }
     else if (g_rng.rd_newentr >= MAX_SEED_NEW_ENTROPY_WORDS)
       {
         /* Initial entropy is low. Reseed when we have accumulated more. */
         rng_reseed();
       }
     else if (g_rng.blake2xs.out_node_offset == UINT32_MAX)
       {
         /* Maximum BLAKE2Xs output reached (2^32-1 output blocks, maximum 128
          * GiB bytes), reseed.
          */
         rng_reseed();
       }
   ```
   So, getrandom implement GRND_NONBLOCK semantic only. The secure 
implementation is return -1 and set errno to EAGAIN if entropy is low. Instead 
return the weak random number without any indication.
   
   > > getrandom is designed to can be implemented by the hardware crypto 
accelerator, nobody can make 100% guarantee that the hardware will always work 
as expect(especially some accelerator connect to CPU through SPI, SDIO, USB 
bus). Now we have no way to report the error with your prototype?
   > 
   > getrandom() is not designed specifically for hardware crypto accelerators. 
We use it in real products with MCUs that lack hardware RNG. It only needs 
enough initial entropy for one cryptographical key (unless generate huge 
amounts, several Gb, of output, then it must re-key itself) and it can get that 
from sensors, interrupt timings, factory production line etc.
   > 
   
   But how you tell caller if there isn't enough entropy has been collected 
yet? or the external hardware RNG can't access because I2C/SPI/USB bus is 
broken.
   
   > To better understand these issues, please try this exercise: 1) implement 
Linux getrandom() using OpenBSD's arc4random_buf() function 2) implement 
arc4random_buf() using Linux's getrandom(). Part 1) is trivial, but for 2) one 
has an insurmountable problem, what to do if getrandom() fails (for any reason)?
   
   It's arc4random_buf design problem: it doesn't return the error code. We 
should avoid to use this function, but it is wrong to drop getrandom return 
value. If you look at how NuttX implementation now, there are many places the 
random generatation isn't really random:
   ```
   void getrandom(FAR void *bytes, size_t nbytes)
   {
     int ret;
   
     ret = nxsem_wait_uninterruptible(&g_rng.rd_sem);
     if (ret >= 0)
       {
         rng_buf_internal(bytes, nbytes);
         nxsem_post(&g_rng.rd_sem);
       }
   }
   
   static void rng_buf_internal(FAR void *bytes, size_t nbytes)
   {
     if (!g_rng.output_initialized)
       {
         if (g_rng.rd_newentr < MIN_SEED_NEW_ENTROPY_WORDS)
           {
             cryptwarn("Entropy pool RNG initialized with very low entropy. "
                       " Consider implementing CONFIG_BOARD_INITRNGSEED!\n");
           }
         rng_reseed();
       }
     else if (g_rng.rd_newentr >= MAX_SEED_NEW_ENTROPY_WORDS)
       {
         /* Initial entropy is low. Reseed when we have accumulated more. */
         rng_reseed();
       }
     else if (g_rng.blake2xs.out_node_offset == UINT32_MAX)
       {
         /* Maximum BLAKE2Xs output reached (2^32-1 output blocks, maximum 128
          * GiB bytes), reseed.
          */
         rng_reseed();
       }
   ```
   Do you think it's more secure to blindly ignore the error?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to