iPXE
Defines | Functions | Variables
efi_entropy.c File Reference

EFI entropy source. More...

#include <errno.h>
#include <ipxe/entropy.h>
#include <ipxe/crc32.h>
#include <ipxe/profile.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Protocol/Rng.h>

Go to the source code of this file.

Defines

#define EFI_ENTROPY_RNG_LEN   32
 Minimum number of bytes to request from RNG.
#define EFI_ENTROPY_TRIGGER_TIME   10
 Time (in 100ns units) to delay waiting for timer tick.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 EFI_REQUEST_PROTOCOL (EFI_RNG_PROTOCOL,&efirng)
static int efi_entropy_enable (void)
 Enable entropy gathering.
static void efi_entropy_disable (void)
 Disable entropy gathering.
static int efi_entropy_tick (void)
 Wait for a timer tick.
static int efi_get_noise_ticks (noise_sample_t *noise)
 Get noise sample from timer ticks.
static int efi_get_noise_rng (noise_sample_t *noise)
 Get noise sample from RNG protocol.
static int efi_get_noise (noise_sample_t *noise)
 Get noise sample.
 PROVIDE_ENTROPY_INLINE (efi, min_entropy_per_sample)
 PROVIDE_ENTROPY (efi, entropy_enable, efi_entropy_enable)
 PROVIDE_ENTROPY (efi, entropy_disable, efi_entropy_disable)
 PROVIDE_ENTROPY (efi, get_noise, efi_get_noise)

Variables

static EFI_RNG_PROTOCOLefirng
 Random number generator protocol.
static EFI_EVENT tick
 Event used to wait for timer tick.

Detailed Description

EFI entropy source.

Definition in file efi_entropy.c.


Define Documentation

#define EFI_ENTROPY_RNG_LEN   32

Minimum number of bytes to request from RNG.

The UEFI spec states (for no apparently good reason) that "When a Deterministic Random Bit Generator (DRBG) is used on the output of a (raw) entropy source, its security level must be at least 256 bits." The EDK2 codebase (mis)interprets this to mean that the call to GetRNG() should fail if given a buffer less than 32 bytes.

Incidentally, nothing in the EFI RNG protocol provides any way to report the actual amount of entropy returned by GetRNG().

Definition at line 54 of file efi_entropy.c.

Referenced by efi_get_noise_rng().

#define EFI_ENTROPY_TRIGGER_TIME   10

Time (in 100ns units) to delay waiting for timer tick.

In theory, UEFI allows us to specify a trigger time of zero to simply wait for the next timer tick. In practice, specifying zero seems to often return immediately, which produces almost no entropy. Specify a delay of 1000ns to try to force an existent delay.

Definition at line 64 of file efi_entropy.c.

Referenced by efi_entropy_tick().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL  ,
efirng 
)
static int efi_entropy_enable ( void  ) [static]

Enable entropy gathering.

Return values:
rcReturn status code

Definition at line 74 of file efi_entropy.c.

References EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CreateEvent, DBGC, EEFI, efi_systab, EVT_TIMER, NULL, rc, EFI_BOOT_SERVICES::RestoreTPL, strerror(), tick, TPL_APPLICATION, and TPL_NOTIFY.

                                       {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        EFI_STATUS efirc;
        int rc;

        DBGC ( &tick, "ENTROPY %s RNG protocol\n",
               ( efirng ? "has" : "has no" ) );

        /* Drop to TPL_APPLICATION to allow timer tick event to take place */
        bs->RestoreTPL ( TPL_APPLICATION );

        /* Create timer tick event */
        if ( ( efirc = bs->CreateEvent ( EVT_TIMER, TPL_NOTIFY, NULL, NULL,
                                         &tick ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( &tick, "ENTROPY could not create event: %s\n",
                       strerror ( rc ) );
                return rc;
        }

        return 0;
}
static void efi_entropy_disable ( void  ) [static]

Disable entropy gathering.

Definition at line 101 of file efi_entropy.c.

References EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseEvent, efi_systab, EFI_BOOT_SERVICES::RaiseTPL, tick, and TPL_CALLBACK.

                                         {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;

        /* Close timer tick event */
        bs->CloseEvent ( tick );

        /* Return to TPL_CALLBACK */
        bs->RaiseTPL ( TPL_CALLBACK );
}
static int efi_entropy_tick ( void  ) [static]

Wait for a timer tick.

Return values:
lowCPU profiling low-order bits, or negative error

Definition at line 116 of file efi_entropy.c.

References EFI_SYSTEM_TABLE::BootServices, DBGC, EEFI, EFI_ENTROPY_TRIGGER_TIME, efi_systab, index, low, rc, EFI_BOOT_SERVICES::SetTimer, strerror(), tick, TimerRelative, and EFI_BOOT_SERVICES::WaitForEvent.

Referenced by efi_get_noise_ticks().

                                     {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        UINTN index;
        uint16_t low;
        EFI_STATUS efirc;
        int rc;

        /* Wait for next timer tick */
        if ( ( efirc = bs->SetTimer ( tick, TimerRelative,
                                      EFI_ENTROPY_TRIGGER_TIME ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( &tick, "ENTROPY could not set timer: %s\n",
                       strerror ( rc ) );
                return rc;
        }
        if ( ( efirc = bs->WaitForEvent ( 1, &tick, &index ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( &tick, "ENTROPY could not wait for timer tick: %s\n",
                       strerror ( rc ) );
                return rc;
        }

        /* Get current CPU profiling timestamp low-order bits */
        low = profile_timestamp();

        return low;
}
static int efi_get_noise_ticks ( noise_sample_t noise) [static]

Get noise sample from timer ticks.

Return values:
noiseNoise sample
rcReturn status code

Definition at line 150 of file efi_entropy.c.

References efi_entropy_tick(), and rc.

Referenced by efi_get_noise().

                                                         {
        int before;
        int after;
        int rc;

        /* Wait for a timer tick */
        before = efi_entropy_tick();
        if ( before < 0 ) {
                rc = before;
                return rc;
        }

        /* Wait for another timer tick */
        after = efi_entropy_tick();
        if ( after < 0 ) {
                rc = after;
                return rc;
        }

        /* Use TSC delta as noise sample */
        *noise = ( after - before );

        return 0;
}
static int efi_get_noise_rng ( noise_sample_t noise) [static]

Get noise sample from RNG protocol.

Return values:
noiseNoise sample
rcReturn status code

Definition at line 181 of file efi_entropy.c.

References crc32_le(), DBGC, EEFI, EFI_ENTROPY_RNG_LEN, ENOTSUP, _EFI_RNG_PROTOCOL::GetRNG, NULL, rc, strerror(), and tick.

Referenced by efi_get_noise().

                                                       {
        uint8_t buf[EFI_ENTROPY_RNG_LEN];
        EFI_STATUS efirc;
        int rc;

        /* Fail if we have no EFI RNG protocol */
        if ( ! efirng )
                return -ENOTSUP;

        /* Get the minimum allowed number of random bytes */
        if ( ( efirc = efirng->GetRNG ( efirng, NULL, EFI_ENTROPY_RNG_LEN,
                                        buf ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( &tick, "ENTROPY could not read from RNG: %s\n",
                       strerror ( rc ) );
                return rc;
        }

        /* Reduce random bytes to a single noise sample.  This seems
         * like overkill, but we have no way of knowing how much
         * entropy is actually present in the bytes returned by the
         * RNG protocol.
         */
        *noise = crc32_le ( 0, buf, sizeof ( buf ) );

        return 0;
}
static int efi_get_noise ( noise_sample_t noise) [static]

Get noise sample.

Return values:
noiseNoise sample
rcReturn status code

Definition at line 215 of file efi_entropy.c.

References efi_get_noise_rng(), efi_get_noise_ticks(), and rc.

                                                   {
        int rc;

        /* Try RNG first, falling back to timer ticks */
        if ( ( ( rc = efi_get_noise_rng ( noise ) ) != 0 ) &&
             ( ( rc = efi_get_noise_ticks ( noise ) ) != 0 ) )
                return rc;

        return 0;
}
PROVIDE_ENTROPY ( efi  ,
get_noise  ,
efi_get_noise   
)

Variable Documentation

Random number generator protocol.

Definition at line 40 of file efi_entropy.c.

EFI_EVENT tick [static]

Event used to wait for timer tick.

Definition at line 67 of file efi_entropy.c.

Referenced by efi_entropy_disable(), efi_entropy_enable(), efi_entropy_tick(), efi_get_noise_rng(), and fiber_autoneg().