iPXE
Macros | 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.

Macros

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

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 
 EFI_REQUEST_PROTOCOL (EFI_RNG_PROTOCOL, &efirng)
 
static int efi_entropy_enable (void)
 Enable entropy gathering. More...
 
static void efi_entropy_disable (void)
 Disable entropy gathering. More...
 
static int efi_entropy_tick (void)
 Wait for a timer tick. More...
 
static int efi_get_noise_ticks (noise_sample_t *noise)
 Get noise sample from timer ticks. More...
 
static int efi_get_noise_rng (noise_sample_t *noise)
 Get noise sample from RNG protocol. More...
 
static int efi_get_noise (noise_sample_t *noise)
 Get noise sample. More...
 
 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. More...
 
static EFI_EVENT tick
 Event used to wait for timer tick. More...
 

Detailed Description

EFI entropy source.

Definition in file efi_entropy.c.

Macro Definition Documentation

◆ EFI_ENTROPY_RNG_LEN

#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.

◆ EFI_ENTROPY_TRIGGER_TIME

#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.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ EFI_REQUEST_PROTOCOL()

EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL  ,
efirng 
)

◆ efi_entropy_enable()

static int efi_entropy_enable ( void  )
static

Enable entropy gathering.

Return values
rcReturn status code

Definition at line 74 of file efi_entropy.c.

74  {
76  EFI_STATUS efirc;
77  int rc;
78 
79  DBGC ( &tick, "ENTROPY %s RNG protocol\n",
80  ( efirng ? "has" : "has no" ) );
81 
82  /* Drop to external TPL to allow timer tick event to take place */
84 
85  /* Create timer tick event */
86  if ( ( efirc = bs->CreateEvent ( EVT_TIMER, TPL_NOTIFY, NULL, NULL,
87  &tick ) ) != 0 ) {
88  rc = -EEFI ( efirc );
89  DBGC ( &tick, "ENTROPY could not create event: %s\n",
90  strerror ( rc ) );
91  return rc;
92  }
93 
94  return 0;
95 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2000
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:162
static EFI_EVENT tick
Event used to wait for timer tick.
Definition: efi_entropy.c:67
static EFI_RNG_PROTOCOL * efirng
Random number generator protocol.
Definition: efi_entropy.c:40
#define DBGC(...)
Definition: compiler.h:505
#define TPL_NOTIFY
Definition: UefiSpec.h:592
EFI_CREATE_EVENT CreateEvent
Definition: UefiSpec.h:1860
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
EFI Boot Services Table.
Definition: UefiSpec.h:1836
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:35
EFI_SYSTEM_TABLE * efi_systab
EFI_RESTORE_TPL RestoreTPL
Definition: UefiSpec.h:1846
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
#define EVT_TIMER
Definition: UefiSpec.h:391
EFI_TPL efi_external_tpl
External task priority level.
Definition: efi_init.c:54

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

◆ efi_entropy_disable()

static void efi_entropy_disable ( void  )
static

Disable entropy gathering.

Definition at line 101 of file efi_entropy.c.

101  {
103 
104  /* Close timer tick event */
105  bs->CloseEvent ( tick );
106 
107  /* Return to internal TPL */
108  bs->RaiseTPL ( efi_internal_tpl );
109 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2000
EFI_RAISE_TPL RaiseTPL
Definition: UefiSpec.h:1845
static EFI_EVENT tick
Event used to wait for timer tick.
Definition: efi_entropy.c:67
EFI_CLOSE_EVENT CloseEvent
Definition: UefiSpec.h:1864
EFI_TPL efi_internal_tpl
Internal task priority level.
Definition: efi_init.c:51
EFI Boot Services Table.
Definition: UefiSpec.h:1836
EFI_SYSTEM_TABLE * efi_systab

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

◆ efi_entropy_tick()

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.

116  {
118  UINTN index;
119  uint16_t low;
120  EFI_STATUS efirc;
121  int rc;
122 
123  /* Wait for next timer tick */
124  if ( ( efirc = bs->SetTimer ( tick, TimerRelative,
125  EFI_ENTROPY_TRIGGER_TIME ) ) != 0 ) {
126  rc = -EEFI ( efirc );
127  DBGC ( &tick, "ENTROPY could not set timer: %s\n",
128  strerror ( rc ) );
129  return rc;
130  }
131  if ( ( efirc = bs->WaitForEvent ( 1, &tick, &index ) ) != 0 ) {
132  rc = -EEFI ( efirc );
133  DBGC ( &tick, "ENTROPY could not wait for timer tick: %s\n",
134  strerror ( rc ) );
135  return rc;
136  }
137 
138  /* Get current CPU profiling timestamp low-order bits */
139  low = profile_timestamp();
140 
141  return low;
142 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2000
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned short uint16_t
Definition: stdint.h:11
uint32_t low
Low 16 bits of address.
Definition: myson.h:19
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:162
An event is to be signaled once at a specified interval from the current time.
Definition: UefiSpec.h:493
static EFI_EVENT tick
Event used to wait for timer tick.
Definition: efi_entropy.c:67
#define DBGC(...)
Definition: compiler.h:505
EFI_SET_TIMER SetTimer
Definition: UefiSpec.h:1861
#define EFI_ENTROPY_TRIGGER_TIME
Time (in 100ns units) to delay waiting for timer tick.
Definition: efi_entropy.c:64
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
EFI Boot Services Table.
Definition: UefiSpec.h:1836
UINT64 UINTN
Unsigned value of native width.
Definition: ProcessorBind.h:71
EFI_WAIT_FOR_EVENT WaitForEvent
Definition: UefiSpec.h:1862
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:35
EFI_SYSTEM_TABLE * efi_systab
uint64_t index
Index of the first segment within the content.
Definition: pccrc.h:21

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_get_noise_ticks()

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.

150  {
151  int before;
152  int after;
153  int rc;
154 
155  /* Wait for a timer tick */
156  before = efi_entropy_tick();
157  if ( before < 0 ) {
158  rc = before;
159  return rc;
160  }
161 
162  /* Wait for another timer tick */
163  after = efi_entropy_tick();
164  if ( after < 0 ) {
165  rc = after;
166  return rc;
167  }
168 
169  /* Use TSC delta as noise sample */
170  *noise = ( after - before );
171 
172  return 0;
173 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
static int efi_entropy_tick(void)
Wait for a timer tick.
Definition: efi_entropy.c:116

References efi_entropy_tick(), and rc.

Referenced by efi_get_noise().

◆ efi_get_noise_rng()

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.

181  {
182  static uint8_t prev[EFI_ENTROPY_RNG_LEN];
184  EFI_STATUS efirc;
185  int rc;
186 
187  /* Fail if we have no EFI RNG protocol */
188  if ( ! efirng )
189  return -ENOTSUP;
190 
191  /* Get the minimum allowed number of random bytes */
192  if ( ( efirc = efirng->GetRNG ( efirng, NULL, EFI_ENTROPY_RNG_LEN,
193  buf ) ) != 0 ) {
194  rc = -EEFI ( efirc );
195  DBGC ( &tick, "ENTROPY could not read from RNG: %s\n",
196  strerror ( rc ) );
197  return rc;
198  }
199 
200  /* Fail (and permanently disable the EFI RNG) if we get
201  * consecutive identical results.
202  */
203  if ( memcmp ( buf, prev, sizeof ( buf ) ) == 0 ) {
204  DBGC ( &tick, "ENTROPY detected broken EFI RNG:\n" );
205  DBGC_HDA ( &tick, 0, buf, sizeof ( buf ) );
206  efirng = NULL;
207  return -EIO;
208  }
209  memcpy ( prev, buf, sizeof ( prev ) );
210 
211  /* Reduce random bytes to a single noise sample. This seems
212  * like overkill, but we have no way of knowing how much
213  * entropy is actually present in the bytes returned by the
214  * RNG protocol.
215  */
216  *noise = crc32_le ( 0, buf, sizeof ( buf ) );
217 
218  return 0;
219 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:162
static EFI_EVENT tick
Event used to wait for timer tick.
Definition: efi_entropy.c:67
static EFI_RNG_PROTOCOL * efirng
Random number generator protocol.
Definition: efi_entropy.c:40
#define DBGC(...)
Definition: compiler.h:505
#define EFI_ENTROPY_RNG_LEN
Minimum number of bytes to request from RNG.
Definition: efi_entropy.c:54
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
u32 crc32_le(u32 seed, const void *data, size_t len)
Calculate 32-bit little-endian CRC checksum.
Definition: crc32.c:39
void * memcpy(void *dest, const void *src, size_t len) __nonnull
#define DBGC_HDA(...)
Definition: compiler.h:506
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
unsigned char uint8_t
Definition: stdint.h:10
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:35
#define EIO
Input/output error.
Definition: errno.h:433
EFI_RNG_GET_RNG GetRNG
Definition: Rng.h:147
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:114
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362

References crc32_le(), DBGC, DBGC_HDA, EEFI, EFI_ENTROPY_RNG_LEN, efirng, EIO, ENOTSUP, _EFI_RNG_PROTOCOL::GetRNG, memcmp(), memcpy(), NULL, rc, strerror(), and tick.

Referenced by efi_get_noise().

◆ efi_get_noise()

static int efi_get_noise ( noise_sample_t noise)
static

Get noise sample.

Return values
noiseNoise sample
rcReturn status code

Definition at line 227 of file efi_entropy.c.

227  {
228  int rc;
229 
230  /* Try RNG first, falling back to timer ticks */
231  if ( ( ( rc = efi_get_noise_rng ( noise ) ) != 0 ) &&
232  ( ( rc = efi_get_noise_ticks ( noise ) ) != 0 ) )
233  return rc;
234 
235  return 0;
236 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
static int efi_get_noise_rng(noise_sample_t *noise)
Get noise sample from RNG protocol.
Definition: efi_entropy.c:181
static int efi_get_noise_ticks(noise_sample_t *noise)
Get noise sample from timer ticks.
Definition: efi_entropy.c:150

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

◆ PROVIDE_ENTROPY_INLINE()

PROVIDE_ENTROPY_INLINE ( efi  ,
min_entropy_per_sample   
)

◆ PROVIDE_ENTROPY() [1/3]

PROVIDE_ENTROPY ( efi  ,
entropy_enable  ,
efi_entropy_enable   
)

◆ PROVIDE_ENTROPY() [2/3]

PROVIDE_ENTROPY ( efi  ,
entropy_disable  ,
efi_entropy_disable   
)

◆ PROVIDE_ENTROPY() [3/3]

PROVIDE_ENTROPY ( efi  ,
get_noise  ,
efi_get_noise   
)

Variable Documentation

◆ efirng

EFI_RNG_PROTOCOL* efirng
static

Random number generator protocol.

Definition at line 40 of file efi_entropy.c.

Referenced by efi_entropy_enable(), and efi_get_noise_rng().

◆ tick

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().