summaryrefslogtreecommitdiffstats
path: root/src/crypto/rootcert.c
diff options
context:
space:
mode:
authorMichael Brown2012-04-19 15:52:07 +0200
committerMichael Brown2012-04-19 17:11:20 +0200
commit02f1f3066d434cf67b886a1cc482f74dee87479e (patch)
tree074f81beab63855137441d0b48e80847f1c6e199 /src/crypto/rootcert.c
parent[settings] Add fetch_setting_copy() (diff)
downloadipxe-02f1f3066d434cf67b886a1cc482f74dee87479e.tar.gz
ipxe-02f1f3066d434cf67b886a1cc482f74dee87479e.tar.xz
ipxe-02f1f3066d434cf67b886a1cc482f74dee87479e.zip
[crypto] Allow trusted root certificate to be changed without a rebuild
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>
Diffstat (limited to 'src/crypto/rootcert.c')
-rw-r--r--src/crypto/rootcert.c65
1 files changed, 64 insertions, 1 deletions
diff --git a/src/crypto/rootcert.c b/src/crypto/rootcert.c
index 99ee9c87..6a9e594c 100644
--- a/src/crypto/rootcert.c
+++ b/src/crypto/rootcert.c
@@ -18,9 +18,13 @@
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,
+};