diff --git a/src/crypto/rootcert.c b/src/crypto/rootcert.c index 99ee9c87c..6a9e594cc 100644 --- a/src/crypto/rootcert.c +++ b/src/crypto/rootcert.c @@ -18,9 +18,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include #include #include #include +#include +#include +#include #include /** @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, +}; diff --git a/src/include/ipxe/dhcp.h b/src/include/ipxe/dhcp.h index f5b3136ac..cc594ab1e 100644 --- a/src/include/ipxe/dhcp.h +++ b/src/include/ipxe/dhcp.h @@ -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 diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 34c0ed477..d0a142fad 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -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 */ /** @} */