]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Start up RBG on demand if needed 1411/head
authorMichael Brown <mcb30@ipxe.org>
Tue, 18 Feb 2025 15:28:55 +0000 (15:28 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 18 Feb 2025 15:38:54 +0000 (15:38 +0000)
The ANS X9.82 specification implicitly assumes that the RBG_Startup
function will be called before it is needed, and includes checks to
make sure that Generate_function fails if this has not happened.
However, there is no well-defined point at which the RBG_Startup
function is to be called: it's just assumed that this happens as part
of system startup.

We currently call RBG_Startup to instantiate the DRBG as an iPXE
startup function, with the corresponding shutdown function
uninstantiating the DRBG.  This works for most use cases, and avoids
an otherwise unexpected user-visible delay when a caller first
attempts to use the DRBG (e.g. by attempting an HTTPS download).

The download of autoexec.ipxe for UEFI is triggered by the EFI root
bus probe in efi_probe().  Both the root bus probe and the RBG startup
function run at STARTUP_NORMAL, so there is no defined ordering
between them.  If the base URI for autoexec.ipxe uses HTTPS, then this
may cause random bits to be requested before the RBG has been started.

Extend the logic in rbg_generate() to automatically start up the RBG
if startup has not already been attempted.  If startup fails
(e.g. because the entropy source is broken), then do not automatically
retry since this could result in extremely long delays waiting for
entropy that will never arrive.

Reported-by: Michael Niehaus <niehaus@live.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/crypto/rbg.c
src/include/ipxe/rbg.h

index 4b45b34745933155f2b9e4469f7a6ca795060951..5e1c25f530e34650229847dd7e1ab070cf7678ca 100644 (file)
@@ -75,6 +75,9 @@ static int rbg_startup ( void ) {
        int len;
        int rc;
 
+       /* Record that startup has been attempted (even if unsuccessful) */
+       rbg.started = 1;
+
        /* Try to obtain system UUID for use as personalisation
         * string, in accordance with ANS X9.82 Part 3-2007 Section
         * 8.5.2.  If no UUID is available, proceed without a
@@ -97,6 +100,33 @@ static int rbg_startup ( void ) {
        return 0;
 }
 
+/**
+ * Generate bits using RBG
+ *
+ * @v additional       Additional input
+ * @v additional_len   Length of additional input
+ * @v prediction_resist        Prediction resistance is required
+ * @v data             Output buffer
+ * @v len              Length of output buffer
+ * @ret rc             Return status code
+ *
+ * This is the RBG_Generate function defined in ANS X9.82 Part 4
+ * (April 2011 Draft) Section 9.1.2.2.
+ */
+int rbg_generate ( const void *additional, size_t additional_len,
+                  int prediction_resist, void *data, size_t len ) {
+
+       /* Attempt startup, if not already attempted */
+       if ( ! rbg.started )
+               rbg_startup();
+
+       /* Generate bits.  The DRBG will itself return an error if it
+        * is not valid (e.g. due to an instantiation failure).
+        */
+       return drbg_generate ( &rbg.state, additional, additional_len,
+                              prediction_resist, data, len );
+}
+
 /**
  * Shut down RBG
  *
@@ -105,16 +135,21 @@ static void rbg_shutdown ( void ) {
 
        /* Uninstantiate DRBG */
        drbg_uninstantiate ( &rbg.state );
+
+       /* Clear startup attempted flag */
+       rbg.started = 0;
 }
 
 /** RBG startup function */
 static void rbg_startup_fn ( void ) {
 
-       /* Start up RBG.  There is no way to report an error at this
-        * stage, but a failed startup will result in an invalid DRBG
-        * that refuses to generate bits.
+       /* Start up RBG (if not already started on demand).  There is
+        * no way to report an error at this stage, but a failed
+        * startup will result in an invalid DRBG that refuses to
+        * generate bits.
         */
-       rbg_startup();
+       if ( ! rbg.started )
+               rbg_startup();
 }
 
 /** RBG shutdown function */
index 758238a656882f906d96f5026f3a1a60d8e88eb1..4bf3055d100f87356467f68ad8912585cc860fa6 100644 (file)
@@ -16,28 +16,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 struct random_bit_generator {
        /** DRBG state */
        struct drbg_state state;
+       /** Startup has been attempted */
+       int started;
 };
 
 extern struct random_bit_generator rbg;
 
-/**
- * Generate bits using RBG
- *
- * @v additional       Additional input
- * @v additional_len   Length of additional input
- * @v prediction_resist        Prediction resistance is required
- * @v data             Output buffer
- * @v len              Length of output buffer
- * @ret rc             Return status code
- *
- * This is the RBG_Generate function defined in ANS X9.82 Part 4
- * (April 2011 Draft) Section 9.1.2.2.
- */
-static inline int rbg_generate ( const void *additional, size_t additional_len,
-                                int prediction_resist, void *data,
-                                size_t len ) {
-       return drbg_generate ( &rbg.state, additional, additional_len,
-                              prediction_resist, data, len );
-}
+extern int rbg_generate ( const void *additional, size_t additional_len,
+                         int prediction_resist, void *data, size_t len );
 
 #endif /* _IPXE_RBG_H */