]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Allow trusted root certificate to be changed without a rebuild
authorMichael Brown <mcb30@ipxe.org>
Thu, 19 Apr 2012 13:52:07 +0000 (14:52 +0100)
committerMichael Brown <mcb30@ipxe.org>
Thu, 19 Apr 2012 15:11:20 +0000 (16:11 +0100)
Changing the trusted root certificate currently requires a rebuild of
the iPXE binary, which may be inconvenient or impractical.

Allow the list of trusted root certificate fingerprints to be
overridden using the "trust" setting, but only at the point of iPXE
initialisation.  This prevents untrusted sources of settings
(e.g. DHCP) from subverting the chain of trust, while allowing
trustworthy sources to change the trusted root certificate without
requiring a rebuild.

The basic idea is that if you are able to manipulate a trustworthy
source of settings (e.g. VMware GuestInfo or non-volatile stored
options), then you would be able to replace the iPXE binary anyway,
and so no security is lost by allowing such sources to override the
list of trusted root certificates.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/crypto/rootcert.c
src/include/ipxe/dhcp.h
src/include/ipxe/settings.h

index 99ee9c87c0f1d04532a7b1aa8f7f668c701b8429..6a9e594cc8b38b69c5c771c345041bbebf8b2ebd 100644 (file)
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+#include <stdlib.h>
 #include <ipxe/crypto.h>
 #include <ipxe/sha256.h>
 #include <ipxe/x509.h>
+#include <ipxe/settings.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/init.h>
 #include <ipxe/rootcert.h>
 
 /** @file
@@ -29,6 +33,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
  *
  */
 
+/** Length of a root certificate fingerprint */
+#define FINGERPRINT_LEN SHA256_DIGEST_SIZE
+
 /* Use iPXE root CA if no trusted certificates are explicitly specified */
 #ifndef TRUSTED
 #define TRUSTED                                                                \
@@ -42,9 +49,65 @@ FILE_LICENCE ( GPL2_OR_LATER );
 /** Root certificate fingerprints */
 static const uint8_t fingerprints[] = { TRUSTED };
 
+/** Root certificate fingerprint setting */
+struct setting trust_setting __setting ( SETTING_CRYPTO ) = {
+       .name = "trust",
+       .description = "Trusted root certificate fingerprint",
+       .tag = DHCP_EB_TRUST,
+       .type = &setting_type_hex,
+};
+
 /** Root certificates */
 struct x509_root root_certificates = {
        .digest = &sha256_algorithm,
-       .count = ( sizeof ( fingerprints ) / SHA256_DIGEST_SIZE ),
+       .count = ( sizeof ( fingerprints ) / FINGERPRINT_LEN ),
        .fingerprints = fingerprints,
 };
+
+/**
+ * Initialise root certificate
+ *
+ * We allow the list of trusted root certificate fingerprints to be
+ * overridden using the "trust" setting, but only at the point of iPXE
+ * initialisation.  This prevents untrusted sources of settings
+ * (e.g. DHCP) from subverting the chain of trust, while allowing
+ * trustworthy sources (e.g. VMware GuestInfo or non-volatile stored
+ * options) to change the trusted root certificate without requiring a
+ * rebuild.
+ */
+static void rootcert_init ( void ) {
+       void *external;
+       int len;
+       int rc;
+
+       /* Fetch copy of "trust" setting, if it exists.  This memory
+        * will never be freed.
+        */
+       len = fetch_setting_copy ( NULL, &trust_setting, &external );
+       if ( len < 0 ) {
+               rc = len;
+               DBGC ( &root_certificates, "ROOTCERT cannot fetch trusted "
+                      "root certificate fingerprints: %s\n", strerror ( rc ) );
+               /* No way to prevent startup; fail safe by trusting no
+                * certificates.
+                */
+               root_certificates.count = 0;
+               return;
+       }
+
+       /* Use certificates from "trust" setting, if present */
+       if ( external ) {
+               root_certificates.fingerprints = external;
+               root_certificates.count = ( len / FINGERPRINT_LEN );
+       }
+
+       DBGC ( &root_certificates, "ROOTCERT using %d %s certificate(s):\n",
+              root_certificates.count, ( external ? "external" : "built-in" ));
+       DBGC_HDA ( &root_certificates, 0, root_certificates.fingerprints,
+                  ( root_certificates.count * FINGERPRINT_LEN ) );
+}
+
+/** Root certificate initialiser */
+struct init_fn rootcert_init_fn __init_fn ( INIT_LATE ) = {
+       .initialise = rootcert_init,
+};
index f5b3136ac3e49cd3a993cbe9a1761631f7edac78..cc594ab1e9a4eee94db12b7eb798ac51d18bce34 100644 (file)
@@ -355,6 +355,9 @@ struct dhcp_client_uuid {
 /** Encrypted syslog server */
 #define DHCP_EB_SYSLOGS_SERVER DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x55 )
 
+/** Trusted root certficate fingerprints */
+#define DHCP_EB_TRUST DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x5a )
+
 /** Skip PXE DHCP protocol extensions such as ProxyDHCP
  *
  * If set to a non-zero value, iPXE will not wait for ProxyDHCP offers
index 34c0ed477028ca91b664a43c10131f4cdb63b9b7..d0a142fad036a07611500879914ce160d4df6aae 100644 (file)
@@ -83,7 +83,8 @@ struct setting {
 #define SETTING_HOST_EXTRA     10 /**< Host identity additional settings */
 #define SETTING_AUTH           11 /**< Authentication settings */
 #define SETTING_AUTH_EXTRA     12 /**< Authentication additional settings */
-#define SETTING_MISC           13 /**< Miscellaneous settings */
+#define SETTING_CRYPTO         13 /**< Cryptography settings */
+#define SETTING_MISC           14 /**< Miscellaneous settings */
 
 /** @} */