[PATCH 1/3] securebootcert: add Ubuntu UEFI secure boot tests

Colin Ian King colin.king at canonical.com
Mon Mar 4 09:31:46 UTC 2013


On 04/03/13 08:29, Ivan Hu wrote:
> 1. Check the secure boot relative variables, SetupMode, SecureBoot, existence.
> 2. Check the variable db existence and the Microsoft UEFI CA certificate
> 	presence in db.
> 3. Check the variable KEK existence and Ubuntu master CA certificate
> 	presence in KEK.

Checking for the Ubuntu master CA certificate makes this test hard-wired 
to be Ubuntu only.   fwts should not really be tied to a specific 
distro, so I'm not sure if we should make that test necessarily fail (I 
see that is in patch 3), instead perhaps it should throw up a warning or 
an info message.

Colin

>
> Here check the SetupMode and SecureBoot existence and dump the attribute
> and guid info.
>
> Signed-off-by: Ivan Hu <ivan.hu at canonical.com>
> ---
>   src/Makefile.am                          |    3 +-
>   src/uefi/securebootcert/securebootcert.c |  259 ++++++++++++++++++++++++++++++
>   2 files changed, 261 insertions(+), 1 deletion(-)
>   create mode 100644 src/uefi/securebootcert/securebootcert.c
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 200f92e..a7ddce5 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -80,7 +80,8 @@ fwts_SOURCES = main.c 				\
>   	uefi/uefidump/uefidump.c 		\
>   	uefi/uefirttime/uefirttime.c		\
>   	uefi/uefirtvariable/uefirtvariable.c	\
> -	uefi/uefirtmisc/uefirtmisc.c
> +	uefi/uefirtmisc/uefirtmisc.c		\
> +	uefi/securebootcert/securebootcert.c
>
>   fwts_LDFLAGS = -ljson -lm
>
> diff --git a/src/uefi/securebootcert/securebootcert.c b/src/uefi/securebootcert/securebootcert.c
> new file mode 100644
> index 0000000..f972681
> --- /dev/null
> +++ b/src/uefi/securebootcert/securebootcert.c
> @@ -0,0 +1,259 @@
> +/*
> + * Copyright (C) 2013 Canonical
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +#include <stddef.h>
> +#include <inttypes.h>
> +
> +#include "fwts.h"
> +#include "fwts_uefi.h"
> +
> +typedef void (*securebootcert_func)(fwts_framework *fw, fwts_uefi_var *var, char *varname);
> +
> +typedef struct {
> +	char *description;		/* UEFI var */
> +	securebootcert_func	func;	/* Function to dump this variable */
> +} securebootcert_info;
> +
> +typedef struct {
> +	uint32_t	Data1;
> +	uint16_t	Data2;
> +	uint16_t	Data3;
> +	uint8_t		Data4[8];
> +} __attribute__ ((packed)) EFI_GUID;
> +
> +#define VAR_SECUREBOOT_FOUND	1
> +#define VAR_SETUPMODE_FOUND	2
> +#define VAR_DB_FOUND		4
> +#define VAR_KEK_FOUND		8
> +
> +#define EFI_GLOBAL_VARIABLE \
> +{ \
> +	0x8BE4DF61, 0x93CA, 0x11d2, { 0xAA, 0x0D, 0x00, \
> +						0xE0, 0x98, 0x03, 0x2B, 0x8C} \
> +}
> +
> +static uint8_t var_found;
> +
> +static bool compare_guid(EFI_GUID *guid1, uint8_t *guid2)
> +{
> +	bool ident = true;
> +	int i;
> +	uint32_t data1 = guid2[0] + (guid2[1] << 8) + (guid2[2] << 16) + (guid2[3] << 24);
> +	uint16_t data2 = guid2[4] + (guid2[5] << 8);
> +	uint16_t data3 = guid2[6] + (guid2[7] << 8);
> +
> +	if ((guid1->Data1 != data1) || (guid1->Data2 != data2) || (guid1->Data3 != data3))
> +		ident = false;
> +	else {
> +		for (i = 0; i < 8; i++) {
> +			if (guid1->Data4[i] != guid2[i+8])
> +				ident = false;
> +		}
> +	}
> +	return ident;
> +}
> +
> +static void securebootcert_secure_boot(fwts_framework *fw, fwts_uefi_var *var, char *varname)
> +{
> +	bool ident = false;
> +	EFI_GUID global_var_guid = EFI_GLOBAL_VARIABLE;
> +
> +	if (strcmp(varname, "SecureBoot"))
> +		return;
> +
> +	var_found |= VAR_SECUREBOOT_FOUND;
> +	ident = compare_guid(&global_var_guid, var->guid);
> +
> +	if (!ident) {
> +		fwts_failed(fw, LOG_LEVEL_HIGH, "SecureBootCertVariableGUIDInvalid",
> +			"The secure boot variable %s GUID invalid.", varname);
> +		return;
> +	}
> +	if (var->datalen != 1) {
> +		fwts_failed(fw, LOG_LEVEL_HIGH, "SecureBootCertVariableSizeInvalid",
> +			"The secure boot variable %s size invalid.", varname);
> +		return;
> +	} else {
> +		char *mode;
> +		uint8_t value = (uint8_t)var->data[0];
> +
> +		switch (value) {
> +		case 0:
> +			mode = " (Secure Boot Mode Off)";
> +			break;
> +		case 1:
> +			mode = " (Secure Boot Mode On)";
> +			break;
> +		default:
> +			fwts_failed(fw, LOG_LEVEL_HIGH, "SecureBootCertVariableDataInvalid",
> +				"The secure boot variable data invalid.");
> +			return;
> +		}
> +		fwts_log_info_verbatum(fw, "  Value: 0x%2.2x%s.", value, mode);
> +		fwts_passed(fw, "Secure boot relative variable %s check passed.", varname);
> +	}
> +}
> +
> +static void securebootcert_setup_mode(fwts_framework *fw, fwts_uefi_var *var, char *varname)
> +{
> +
> +	bool ident = false;
> +	EFI_GUID global_var_guid = EFI_GLOBAL_VARIABLE;
> +
> +	if (strcmp(varname, "SetupMode"))
> +		return;
> +
> +	var_found |= VAR_SETUPMODE_FOUND;
> +	ident = compare_guid(&global_var_guid, var->guid);
> +
> +	if (!ident) {
> +		fwts_failed(fw, LOG_LEVEL_HIGH, "SecureBootCertVariableGUIDInvalid",
> +			"The secure boot variable %s GUID invalid.", varname);
> +		return;
> +	}
> +	if (var->datalen != 1) {
> +		fwts_failed(fw, LOG_LEVEL_HIGH, "SecureBootCertVariableSizeInvalid",
> +			"The secure boot variable %s size invalid.", varname);
> +	} else {
> +		char *mode;
> +		uint8_t value = (uint8_t)var->data[0];
> +
> +		switch (value) {
> +		case 0:
> +			mode = " (User Mode)";
> +			break;
> +		case 1:
> +			mode = " (Setup Mode)";
> +			break;
> +		default:
> +			fwts_failed(fw, LOG_LEVEL_HIGH, "SecureBootCertVariableDataInvalid",
> +				"The secure boot variable %s data invalid.", varname);
> +			return;
> +		}
> +		fwts_log_info_verbatum(fw, "  Value: 0x%2.2" PRIx8 "%s.", value, mode);
> +		fwts_passed(fw, "Secure boot relative variable %s check passed.", varname);
> +	}
> +}
> +
> +static securebootcert_info securebootcert_info_table[] = {
> +	{ "SecureBoot",		securebootcert_secure_boot },
> +	{ "SetupMode",		securebootcert_setup_mode },
> +	{ NULL, NULL }
> +};
> +
> +static char *securebootcert_attribute(uint32_t attr)
> +{
> +	static char str[100];
> +
> +	*str = 0;
> +
> +	if (attr & FWTS_UEFI_VAR_NON_VOLATILE)
> +		strcat(str, "NonVolatile");
> +
> +	if (attr & FWTS_UEFI_VAR_BOOTSERVICE_ACCESS) {
> +		if (*str)
> +			strcat(str, ",");
> +		strcat(str, "BootServ");
> +	}
> +
> +	if (attr & FWTS_UEFI_VAR_RUNTIME_ACCESS) {
> +		if (*str)
> +			strcat(str, ",");
> +		strcat(str, "RunTime");
> +	}
> +
> +	return str;
> +}
> +

This looks almost identical to uefidump_attribute() in 
src/uefi/uefidump/uefidump.c, perhaps we should factor this out into the 
fwts lib in src/lib/src/fwts_uefi.csince we're now duplicating code. 
Can you do that as another set of patches?


> +static void securebootcert_var(fwts_framework *fw, fwts_uefi_var *var)
> +{
> +	char varname[512];
> +	char guid_str[37];
> +	securebootcert_info *info;
> +
> +	fwts_uefi_get_varname(varname, sizeof(varname), var);
> +
> +	for (info = securebootcert_info_table; info->description != NULL; info++) {
> +		if (strcmp(varname, info->description) == 0) {
> +			fwts_log_info_verbatum(fw, "The %s variable check.", varname);
> +			fwts_guid_buf_to_str(var->guid, guid_str, sizeof(guid_str));
> +			fwts_log_info_verbatum(fw, "  GUID: %s", guid_str);
> +			fwts_log_info_verbatum(fw, "  Attr: 0x%x (%s).", var->attributes,
> +							securebootcert_attribute(var->attributes));
> +			info->func(fw, var, varname);
> +			fwts_log_nl(fw);
> +			return;
> +		}
> +	}
> +}
> +
> +static int securebootcert_init(fwts_framework *fw)
> +{
> +	if (fwts_firmware_detect() != FWTS_FIRMWARE_UEFI) {
> +		fwts_log_info(fw, "Cannot detect any UEFI firmware. Aborted.");
> +		return FWTS_ABORTED;
> +	}
> +
> +	return FWTS_OK;
> +}
> +
> +static int securebootcert_test1(fwts_framework *fw)
> +{
> +	fwts_list name_list;
> +
> +	if (fwts_uefi_get_variable_names(&name_list) == FWTS_ERROR) {
> +		fwts_log_info(fw, "Cannot find any UEFI variables.");
> +	} else {
> +		fwts_list_link *item;
> +
> +		fwts_list_foreach(item, &name_list) {
> +			fwts_uefi_var var;
> +			char *name = fwts_list_data(char *, item);
> +
> +			if (fwts_uefi_get_variable(name, &var) == FWTS_OK) {
> +				securebootcert_var(fw, &var);
> +				fwts_uefi_free_variable(&var);
> +			}
> +		}
> +	}
> +
> +	/* check all the secure boot variables be found */
> +	if (!(var_found & VAR_SECUREBOOT_FOUND))
> +		fwts_failed(fw, LOG_LEVEL_HIGH, "SecureBootCertVariableNotFound",
> +			"The secure boot variable SecureBoot not found.");
> +	if (!(var_found & VAR_SETUPMODE_FOUND))
> +		fwts_failed(fw, LOG_LEVEL_HIGH, "SecureBootCertVariableNotFound",
> +			"The secure boot variable SetupMode not found.");
> +
> +	fwts_uefi_free_variable_names(&name_list);
> +
> +	return FWTS_OK;
> +}
> +
> +static fwts_framework_minor_test securebootcert_tests[] = {
> +	{ securebootcert_test1, "Ubuntu UEFI secure boot test." },
> +	{ NULL, NULL }
> +};
> +
> +static fwts_framework_ops securebootcert_ops = {
> +	.description = "Ubuntu UEFI secure boot test.",
> +	.init        = securebootcert_init,
> +	.minor_tests = securebootcert_tests
> +};
> +
> +FWTS_REGISTER("securebootcert", &securebootcert_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV);
>

Acked-by: Colin Ian King <colin.king at canonicalcom>



More information about the fwts-devel mailing list