|  | @@ -18,9 +18,13 @@
 | 
		
	
		
			
			| 18 | 18 |  
 | 
		
	
		
			
			| 19 | 19 |  FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			| 20 | 20 |  
 | 
		
	
		
			
			|  | 21 | +#include <stdlib.h>
 | 
		
	
		
			
			| 21 | 22 |  #include <ipxe/crypto.h>
 | 
		
	
		
			
			| 22 | 23 |  #include <ipxe/sha256.h>
 | 
		
	
		
			
			| 23 | 24 |  #include <ipxe/x509.h>
 | 
		
	
		
			
			|  | 25 | +#include <ipxe/settings.h>
 | 
		
	
		
			
			|  | 26 | +#include <ipxe/dhcp.h>
 | 
		
	
		
			
			|  | 27 | +#include <ipxe/init.h>
 | 
		
	
		
			
			| 24 | 28 |  #include <ipxe/rootcert.h>
 | 
		
	
		
			
			| 25 | 29 |  
 | 
		
	
		
			
			| 26 | 30 |  /** @file
 | 
		
	
	
		
			
			|  | @@ -29,6 +33,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			| 29 | 33 |   *
 | 
		
	
		
			
			| 30 | 34 |   */
 | 
		
	
		
			
			| 31 | 35 |  
 | 
		
	
		
			
			|  | 36 | +/** Length of a root certificate fingerprint */
 | 
		
	
		
			
			|  | 37 | +#define FINGERPRINT_LEN SHA256_DIGEST_SIZE
 | 
		
	
		
			
			|  | 38 | +
 | 
		
	
		
			
			| 32 | 39 |  /* Use iPXE root CA if no trusted certificates are explicitly specified */
 | 
		
	
		
			
			| 33 | 40 |  #ifndef TRUSTED
 | 
		
	
		
			
			| 34 | 41 |  #define TRUSTED								\
 | 
		
	
	
		
			
			|  | @@ -42,9 +49,65 @@ FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			| 42 | 49 |  /** Root certificate fingerprints */
 | 
		
	
		
			
			| 43 | 50 |  static const uint8_t fingerprints[] = { TRUSTED };
 | 
		
	
		
			
			| 44 | 51 |  
 | 
		
	
		
			
			|  | 52 | +/** Root certificate fingerprint setting */
 | 
		
	
		
			
			|  | 53 | +struct setting trust_setting __setting ( SETTING_CRYPTO ) = {
 | 
		
	
		
			
			|  | 54 | +	.name = "trust",
 | 
		
	
		
			
			|  | 55 | +	.description = "Trusted root certificate fingerprint",
 | 
		
	
		
			
			|  | 56 | +	.tag = DHCP_EB_TRUST,
 | 
		
	
		
			
			|  | 57 | +	.type = &setting_type_hex,
 | 
		
	
		
			
			|  | 58 | +};
 | 
		
	
		
			
			|  | 59 | +
 | 
		
	
		
			
			| 45 | 60 |  /** Root certificates */
 | 
		
	
		
			
			| 46 | 61 |  struct x509_root root_certificates = {
 | 
		
	
		
			
			| 47 | 62 |  	.digest = &sha256_algorithm,
 | 
		
	
		
			
			| 48 |  | -	.count = ( sizeof ( fingerprints ) / SHA256_DIGEST_SIZE ),
 | 
		
	
		
			
			|  | 63 | +	.count = ( sizeof ( fingerprints ) / FINGERPRINT_LEN ),
 | 
		
	
		
			
			| 49 | 64 |  	.fingerprints = fingerprints,
 | 
		
	
		
			
			| 50 | 65 |  };
 | 
		
	
		
			
			|  | 66 | +
 | 
		
	
		
			
			|  | 67 | +/**
 | 
		
	
		
			
			|  | 68 | + * Initialise root certificate
 | 
		
	
		
			
			|  | 69 | + *
 | 
		
	
		
			
			|  | 70 | + * We allow the list of trusted root certificate fingerprints to be
 | 
		
	
		
			
			|  | 71 | + * overridden using the "trust" setting, but only at the point of iPXE
 | 
		
	
		
			
			|  | 72 | + * initialisation.  This prevents untrusted sources of settings
 | 
		
	
		
			
			|  | 73 | + * (e.g. DHCP) from subverting the chain of trust, while allowing
 | 
		
	
		
			
			|  | 74 | + * trustworthy sources (e.g. VMware GuestInfo or non-volatile stored
 | 
		
	
		
			
			|  | 75 | + * options) to change the trusted root certificate without requiring a
 | 
		
	
		
			
			|  | 76 | + * rebuild.
 | 
		
	
		
			
			|  | 77 | + */
 | 
		
	
		
			
			|  | 78 | +static void rootcert_init ( void ) {
 | 
		
	
		
			
			|  | 79 | +	void *external;
 | 
		
	
		
			
			|  | 80 | +	int len;
 | 
		
	
		
			
			|  | 81 | +	int rc;
 | 
		
	
		
			
			|  | 82 | +
 | 
		
	
		
			
			|  | 83 | +	/* Fetch copy of "trust" setting, if it exists.  This memory
 | 
		
	
		
			
			|  | 84 | +	 * will never be freed.
 | 
		
	
		
			
			|  | 85 | +	 */
 | 
		
	
		
			
			|  | 86 | +	len = fetch_setting_copy ( NULL, &trust_setting, &external );
 | 
		
	
		
			
			|  | 87 | +	if ( len < 0 ) {
 | 
		
	
		
			
			|  | 88 | +		rc = len;
 | 
		
	
		
			
			|  | 89 | +		DBGC ( &root_certificates, "ROOTCERT cannot fetch trusted "
 | 
		
	
		
			
			|  | 90 | +		       "root certificate fingerprints: %s\n", strerror ( rc ) );
 | 
		
	
		
			
			|  | 91 | +		/* No way to prevent startup; fail safe by trusting no
 | 
		
	
		
			
			|  | 92 | +		 * certificates.
 | 
		
	
		
			
			|  | 93 | +		 */
 | 
		
	
		
			
			|  | 94 | +		root_certificates.count = 0;
 | 
		
	
		
			
			|  | 95 | +		return;
 | 
		
	
		
			
			|  | 96 | +	}
 | 
		
	
		
			
			|  | 97 | +
 | 
		
	
		
			
			|  | 98 | +	/* Use certificates from "trust" setting, if present */
 | 
		
	
		
			
			|  | 99 | +	if ( external ) {
 | 
		
	
		
			
			|  | 100 | +		root_certificates.fingerprints = external;
 | 
		
	
		
			
			|  | 101 | +		root_certificates.count = ( len / FINGERPRINT_LEN );
 | 
		
	
		
			
			|  | 102 | +	}
 | 
		
	
		
			
			|  | 103 | +
 | 
		
	
		
			
			|  | 104 | +	DBGC ( &root_certificates, "ROOTCERT using %d %s certificate(s):\n",
 | 
		
	
		
			
			|  | 105 | +	       root_certificates.count, ( external ? "external" : "built-in" ));
 | 
		
	
		
			
			|  | 106 | +	DBGC_HDA ( &root_certificates, 0, root_certificates.fingerprints,
 | 
		
	
		
			
			|  | 107 | +		   ( root_certificates.count * FINGERPRINT_LEN ) );
 | 
		
	
		
			
			|  | 108 | +}
 | 
		
	
		
			
			|  | 109 | +
 | 
		
	
		
			
			|  | 110 | +/** Root certificate initialiser */
 | 
		
	
		
			
			|  | 111 | +struct init_fn rootcert_init_fn __init_fn ( INIT_LATE ) = {
 | 
		
	
		
			
			|  | 112 | +	.initialise = rootcert_init,
 | 
		
	
		
			
			|  | 113 | +};
 |