[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