From patchwork Mon Mar 4 08:29:28 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Hu X-Patchwork-Id: 224635 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id 620C72C0309 for ; Mon, 4 Mar 2013 19:29:29 +1100 (EST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1UCQlz-0005Lw-6r; Mon, 04 Mar 2013 08:29:27 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1UCQlw-0005Lm-Rq for fwts-devel@lists.ubuntu.com; Mon, 04 Mar 2013 08:29:24 +0000 Received: from [175.41.48.77] (helo=canonical.com) by youngberry.canonical.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1UCQlv-0006t4-T5; Mon, 04 Mar 2013 08:29:24 +0000 From: Ivan Hu To: fwts-devel@lists.ubuntu.com Subject: [PATCH 1/3] securebootcert: add Ubuntu UEFI secure boot tests Date: Mon, 4 Mar 2013 16:29:28 +0800 Message-Id: <1362385768-19178-1-git-send-email-ivan.hu@canonical.com> X-Mailer: git-send-email 1.7.10.4 X-BeenThere: fwts-devel@lists.ubuntu.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: Firmware Test Suite Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: fwts-devel-bounces@lists.ubuntu.com Sender: fwts-devel-bounces@lists.ubuntu.com 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. Here check the SetupMode and SecureBoot existence and dump the attribute and guid info. Signed-off-by: Ivan Hu Acked-by: Colin Ian King Acked-by: Keng-Yu Lin --- 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 +#include + +#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; +} + +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);