From dd3a5d71252a1f94e37f1a4c8841d253630b305a Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 23 Jul 2020 12:36:56 -0400 Subject: [PATCH 57/62] Add support for vendor_db built-in shim authorized list. Potential new signing strategies ( for example signing grub, fwupdate and vmlinuz with separate certificates ) require shim to support a vendor provided bundle of trusted certificates and hashes, which allows shim to trust EFI binaries matching either certificate by signature or hash in the vendor_db. Functionality is similar to vendor_dbx. This also improves the mirroring quite a bit. Upstream: pr#206 --- lib/variables.c | 55 +++-- mok.c | 502 ++++++++++++++++++++++++++++++-------------- shim.c | 27 +++ include/console.h | 3 +- include/variables.h | 9 +- shim.h | 7 +- cert.S | 13 +- Make.defaults | 3 + README.tpm | 1 + 9 files changed, 437 insertions(+), 183 deletions(-) diff --git a/lib/variables.c b/lib/variables.c index 9c2e7d0ac2d..8123ae60fc9 100644 --- a/lib/variables.c +++ b/lib/variables.c @@ -25,32 +25,59 @@ #include "shim.h" EFI_STATUS -variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner, - void **out, int *outlen) +fill_esl(const uint8_t *data, const size_t data_len, + const EFI_GUID *type, const EFI_GUID *owner, + uint8_t *out, size_t *outlen) { - *outlen = cert_len + sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID); + EFI_SIGNATURE_LIST *sl; + EFI_SIGNATURE_DATA *sd; + size_t needed = 0; - *out = AllocateZeroPool(*outlen); - if (!*out) - return EFI_OUT_OF_RESOURCES; + if (!data || !data_len || !type || !outlen) + return EFI_INVALID_PARAMETER; - EFI_SIGNATURE_LIST *sl = *out; + needed = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) + data_len; + if (!out || *outlen < needed) { + *outlen = needed; + return EFI_BUFFER_TOO_SMALL; + } + + *outlen = needed; + sl = (EFI_SIGNATURE_LIST *)out; sl->SignatureHeaderSize = 0; sl->SignatureType = *type; - sl->SignatureSize = cert_len + sizeof(EFI_GUID); - sl->SignatureListSize = *outlen; - - EFI_SIGNATURE_DATA *sd = *out + sizeof(EFI_SIGNATURE_LIST); + sl->SignatureSize = sizeof(EFI_GUID) + data_len; + sl->SignatureListSize = needed; + sd = (EFI_SIGNATURE_DATA *)(out + sizeof(EFI_SIGNATURE_LIST)); if (owner) sd->SignatureOwner = *owner; - CopyMem(sd->SignatureData, cert, cert_len); + CopyMem(sd->SignatureData, data, data_len); return EFI_SUCCESS; } +EFI_STATUS +variable_create_esl(const uint8_t *data, const size_t data_len, + const EFI_GUID *type, const EFI_GUID *owner, + uint8_t **out, size_t *outlen) +{ + EFI_STATUS efi_status; + + *outlen = 0; + efi_status = fill_esl(data, data_len, type, owner, NULL, outlen); + if (efi_status != EFI_BUFFER_TOO_SMALL) + return efi_status; + + *out = AllocateZeroPool(*outlen); + if (!*out) + return EFI_OUT_OF_RESOURCES; + + return fill_esl(data, data_len, type, owner, *out, outlen); +} + EFI_STATUS CreateTimeBasedPayload(IN OUT UINTN * DataSize, IN OUT UINT8 ** Data) { @@ -137,9 +164,9 @@ SetSecureVariable(CHAR16 *var, UINT8 *Data, UINTN len, EFI_GUID owner, return EFI_SECURITY_VIOLATION; if (createtimebased) { - int ds; + size_t ds; efi_status = variable_create_esl(Data, len, &X509_GUID, NULL, - (void **)&Cert, &ds); + (uint8_t **)&Cert, &ds); if (EFI_ERROR(efi_status)) { console_print(L"Failed to create %s certificate %d\n", var, efi_status); diff --git a/mok.c b/mok.c index 089ea6bfc9a..e69857f3c37 100644 --- a/mok.c +++ b/mok.c @@ -5,6 +5,8 @@ #include "shim.h" +#include + /* * Check if a variable exists */ @@ -47,6 +49,15 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle) return EFI_SUCCESS; } +typedef enum { + VENDOR_ADDEND_DB, + VENDOR_ADDEND_X509, + VENDOR_ADDEND_NONE, +} vendor_addend_category_t; + +struct mok_state_variable; +typedef vendor_addend_category_t (vendor_addend_categorizer_t)(struct mok_state_variable *); + /* * MoK variables that need to have their storage validated. * @@ -58,18 +69,20 @@ struct mok_state_variable { char *name8; CHAR16 *rtname; EFI_GUID *guid; + UINT8 *data; UINTN data_size; + /* - * These two are indirect pointers just to make initialization - * saner... + * These are indirect pointers just to make initialization saner... */ - UINT8 **addend_source; + vendor_addend_categorizer_t *categorize_addend; + UINT8 **addend; UINT32 *addend_size; -#if defined(ENABLE_SHIM_CERT) + UINT8 **build_cert; UINT32 *build_cert_size; -#endif /* defined(ENABLE_SHIM_CERT) */ + UINT32 yes_attr; UINT32 no_attr; UINT32 flags; @@ -77,6 +90,28 @@ struct mok_state_variable { UINT8 *state; }; +static vendor_addend_category_t +categorize_authorized(struct mok_state_variable *v) +{ + if (!(v->addend && v->addend_size && + *v->addend && *v->addend_size)) { + return VENDOR_ADDEND_NONE; + } + + return vendor_authorized_category; +} + +static vendor_addend_category_t +categorize_deauthorized(struct mok_state_variable *v) +{ + if (!(v->addend && v->addend_size && + *v->addend && *v->addend_size)) { + return VENDOR_ADDEND_NONE; + } + + return VENDOR_ADDEND_DB; +} + #define MOK_MIRROR_KEYDB 0x01 #define MOK_MIRROR_DELETE_FIRST 0x02 #define MOK_VARIABLE_MEASURE 0x04 @@ -90,8 +125,9 @@ struct mok_state_variable mok_state_variables[] = { .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, .no_attr = EFI_VARIABLE_RUNTIME_ACCESS, - .addend_source = &vendor_cert, - .addend_size = &vendor_cert_size, + .categorize_addend = categorize_authorized, + .addend = &vendor_authorized, + .addend_size = &vendor_authorized_size, #if defined(ENABLE_SHIM_CERT) .build_cert = &build_cert, .build_cert_size = &build_cert_size, @@ -107,6 +143,9 @@ struct mok_state_variable mok_state_variables[] = { .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, .no_attr = EFI_VARIABLE_RUNTIME_ACCESS, + .categorize_addend = categorize_deauthorized, + .addend = &vendor_deauthorized, + .addend_size = &vendor_deauthorized_size, .flags = MOK_MIRROR_KEYDB | MOK_VARIABLE_LOG, .pcr = 14, @@ -136,123 +175,253 @@ struct mok_state_variable mok_state_variables[] = { { NULL, } }; -static inline BOOLEAN nonnull(1) -check_vendor_cert(struct mok_state_variable *v) -{ - return (v->addend_source && v->addend_size && - *v->addend_source && *v->addend_size) ? TRUE : FALSE; -} +#define should_mirror_addend(v) (((v)->categorize_addend) && ((v)->categorize_addend(v) != VENDOR_ADDEND_NONE)) -#if defined(ENABLE_SHIM_CERT) static inline BOOLEAN nonnull(1) -check_build_cert(struct mok_state_variable *v) +should_mirror_build_cert(struct mok_state_variable *v) { return (v->build_cert && v->build_cert_size && *v->build_cert && *v->build_cert_size) ? TRUE : FALSE; } -#define check_addend(v) (check_vendor_cert(v) || check_build_cert(v)) -#else -#define check_addend(v) check_vendor_cert(v) -#endif /* defined(ENABLE_SHIM_CERT) */ + +static const uint8_t null_sha256[32] = { 0, }; static EFI_STATUS nonnull(1) mirror_one_mok_variable(struct mok_state_variable *v) { EFI_STATUS efi_status = EFI_SUCCESS; - void *FullData = NULL; - UINTN FullDataSize = 0; + uint8_t *FullData = NULL; + size_t FullDataSize = 0; + vendor_addend_category_t addend_category = VENDOR_ADDEND_NONE; uint8_t *p = NULL; - if ((v->flags & MOK_MIRROR_KEYDB) && check_addend(v)) { - EFI_SIGNATURE_LIST *CertList = NULL; - EFI_SIGNATURE_DATA *CertData = NULL; -#if defined(ENABLE_SHIM_CERT) - FullDataSize = v->data_size; - if (check_build_cert(v)) { - FullDataSize += sizeof (*CertList) - + sizeof (EFI_GUID) - + *v->build_cert_size; - } - if (check_vendor_cert(v)) { - FullDataSize += sizeof (*CertList) - + sizeof (EFI_GUID) - + *v->addend_size; - } -#else - FullDataSize = v->data_size - + sizeof (*CertList) - + sizeof (EFI_GUID) - + *v->addend_size; -#endif /* defined(ENABLE_SHIM_CERT) */ - FullData = AllocatePool(FullDataSize); - if (!FullData) { - perror(L"Failed to allocate space for MokListRT\n"); - return EFI_OUT_OF_RESOURCES; - } - p = FullData; + size_t build_cert_esl_sz = 0, addend_esl_sz = 0; - if (!EFI_ERROR(efi_status) && v->data_size > 0) { - CopyMem(p, v->data, v->data_size); - p += v->data_size; - } + if (v->categorize_addend) + addend_category = v->categorize_addend(v); -#if defined(ENABLE_SHIM_CERT) - if (check_build_cert(v) == FALSE) - goto skip_build_cert; + /* + * we're always mirroring the original data, whether this is an efi + * security database or not + */ + dprint(L"v->data_size:%lu v->data:0x%08llx\n", v->data_size, v->data); + dprint(L"FullDataSize:%lu FullData:0x%08llx\n", FullDataSize, FullData); + if (v->data_size) { + FullDataSize = v->data_size; + dprint(L"FullDataSize:%lu FullData:0x%08llx\n", + FullDataSize, FullData); + } - CertList = (EFI_SIGNATURE_LIST *)p; - p += sizeof (*CertList); - CertData = (EFI_SIGNATURE_DATA *)p; - p += sizeof (EFI_GUID); + /* + * if it is, there's more data + */ + if (v->flags & MOK_MIRROR_KEYDB) { - CertList->SignatureType = EFI_CERT_TYPE_X509_GUID; - CertList->SignatureListSize = *v->build_cert_size - + sizeof (*CertList) - + sizeof (*CertData) - -1; - CertList->SignatureHeaderSize = 0; - CertList->SignatureSize = *v->build_cert_size + - sizeof (EFI_GUID); + /* + * We're mirroring (into) an efi security database, aka an + * array of efi_signature_list_t. Its layout goes like: + * + * existing_variable_data + * existing_variable_data_size + * if flags & MOK_MIRROR_KEYDB + * if build_cert + * build_cert_esl + * build_cert_header (always sz=0) + * build_cert_esd[0] { owner, data } + * if addend==vendor_db + * for n=[1..N] + * vendor_db_esl_n + * vendor_db_header_n (always sz=0) + * vendor_db_esd_n[m] {{ owner, data }, ... } + * elif addend==vendor_cert + * vendor_cert_esl + * vendor_cert_header (always sz=0) + * vendor_cert_esd[1] { owner, data } + * + * first we determine the size of the variable, then alloc + * and add the data. + */ - CertData->SignatureOwner = SHIM_LOCK_GUID; - CopyMem(p, *v->build_cert, *v->build_cert_size); + /* + * first bit is existing data, but we added that above + */ - p += *v->build_cert_size; + /* + * then the build cert if it's there + */ + if (should_mirror_build_cert(v)) { + efi_status = fill_esl(*v->build_cert, + *v->build_cert_size, + &EFI_CERT_TYPE_X509_GUID, + &SHIM_LOCK_GUID, + NULL, &build_cert_esl_sz); + if (efi_status != EFI_BUFFER_TOO_SMALL) { + perror(L"Could not add built-in cert to %s: %r\n", + v->name, efi_status); + return efi_status; + } + FullDataSize += build_cert_esl_sz; + dprint(L"FullDataSize:%lu FullData:0x%08llx\n", + FullDataSize, FullData); + } - if (check_vendor_cert(v) == FALSE) - goto skip_vendor_cert; -skip_build_cert: -#endif /* defined(ENABLE_SHIM_CERT) */ + /* + * then the addend data + */ + switch (addend_category) { + case VENDOR_ADDEND_DB: + /* + * if it's an ESL already, we use it wholesale + */ + FullDataSize += *v->addend_size; + dprint(L"FullDataSize:%lu FullData:0x%08llx\n", + FullDataSize, FullData); + break; + case VENDOR_ADDEND_X509: + efi_status = fill_esl(*v->addend, *v->addend_size, + &EFI_CERT_TYPE_X509_GUID, + &SHIM_LOCK_GUID, + NULL, &addend_esl_sz); + if (efi_status != EFI_BUFFER_TOO_SMALL) { + perror(L"Could not add built-in cert to %s: %r\n", + v->name, efi_status); + return efi_status; + } + FullDataSize += addend_esl_sz; + dprint(L"FullDataSize:%lu FullData:0x%08llx\n", + FullDataSize, FullData); + break; + default: + case VENDOR_ADDEND_NONE: + dprint(L"FullDataSize:%lu FullData:0x%08llx\n", + FullDataSize, FullData); + break; + } + } - CertList = (EFI_SIGNATURE_LIST *)p; - p += sizeof (*CertList); - CertData = (EFI_SIGNATURE_DATA *)p; - p += sizeof (EFI_GUID); + /* + * Now we have the full size + */ + if (FullDataSize) { + /* + * allocate the buffer, or use the old one if it's just the + * existing data. + */ + if (FullDataSize != v->data_size) { + dprint(L"FullDataSize:%lu FullData:0x%08llx allocating FullData\n", + FullDataSize, FullData); + FullData = AllocatePool(FullDataSize); + if (!FullData) { + FreePool(v->data); + v->data = NULL; + v->data_size = 0; + perror(L"Failed to allocate %lu bytes for %s\n", + FullDataSize, v->name); + return EFI_OUT_OF_RESOURCES; + } + p = FullData; + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); + if (v->data && v->data_size) { + CopyMem(p, v->data, v->data_size); + p += v->data_size; + } + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); + } else { + FullData = v->data; + FullDataSize = v->data_size; + p = FullData + FullDataSize; + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); + v->data = NULL; + v->data_size = 0; + } + } + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); - CertList->SignatureType = EFI_CERT_TYPE_X509_GUID; - CertList->SignatureListSize = *v->addend_size - + sizeof (*CertList) - + sizeof (*CertData) - -1; - CertList->SignatureHeaderSize = 0; - CertList->SignatureSize = *v->addend_size + sizeof (EFI_GUID); + /* + * Now fill it. + */ + if (v->flags & MOK_MIRROR_KEYDB) { + /* + * first bit is existing data, but again, we added that above + */ - CertData->SignatureOwner = SHIM_LOCK_GUID; - CopyMem(p, *v->addend_source, *v->addend_size); + /* + * second is the build cert + */ + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); + if (should_mirror_build_cert(v)) { + efi_status = fill_esl(*v->build_cert, + *v->build_cert_size, + &EFI_CERT_TYPE_X509_GUID, + &SHIM_LOCK_GUID, + p, &build_cert_esl_sz); + if (EFI_ERROR(efi_status)) { + perror(L"Could not add built-in cert to %s: %r\n", + v->name, efi_status); + return efi_status; + } + p += build_cert_esl_sz; + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); + } -#if defined(ENABLE_SHIM_CERT) -skip_vendor_cert: -#endif /* defined(ENABLE_SHIM_CERT) */ - if (v->data && v->data_size) - FreePool(v->data); - v->data = FullData; - v->data_size = FullDataSize; - } else { - FullDataSize = v->data_size; - FullData = v->data; + switch (addend_category) { + case VENDOR_ADDEND_DB: + CopyMem(p, *v->addend, *v->addend_size); + p += *v->addend_size; + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); + break; + case VENDOR_ADDEND_X509: + efi_status = fill_esl(*v->addend, *v->addend_size, + &EFI_CERT_TYPE_X509_GUID, + &SHIM_LOCK_GUID, + p, &addend_esl_sz); + if (EFI_ERROR(efi_status)) { + perror(L"Could not add built-in cert to %s: %r\n", + v->name, efi_status); + return efi_status; + } + p += addend_esl_sz; + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); + break; + default: + case VENDOR_ADDEND_NONE: + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); + break; + } + } + /* + * We always want to create our key databases, so in this case we + * need a dummy entry + */ + if ((v->flags & MOK_MIRROR_KEYDB) && FullDataSize == 0) { + efi_status = variable_create_esl( + null_sha256, sizeof(null_sha256), + &EFI_CERT_SHA256_GUID, &SHIM_LOCK_GUID, + &FullData, &FullDataSize); + if (EFI_ERROR(efi_status)) { + perror(L"Failed to allocate %lu bytes for %s\n", + FullDataSize, v->name); + return efi_status; + } + p = FullData + FullDataSize; + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); } + dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n", + FullDataSize, FullData, p, p-(uintptr_t)FullData); if (FullDataSize) { + dprint(L"Setting %s with %lu bytes of data\n", + v->rtname, FullDataSize); efi_status = gRT->SetVariable(v->rtname, v->guid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, @@ -262,7 +431,15 @@ skip_vendor_cert: v->rtname, efi_status); } } - + if (v->data && v->data_size) { + FreePool(v->data); + v->data = NULL; + v->data_size = 0; + } + if (FullData && FullDataSize) { + FreePool(FullData); + } + dprint(L"returning %r\n", efi_status); return efi_status; } @@ -274,6 +451,8 @@ static EFI_STATUS nonnull(1) maybe_mirror_one_mok_variable(struct mok_state_variable *v, EFI_STATUS ret) { EFI_STATUS efi_status; + BOOLEAN present = FALSE; + if (v->rtname) { if (v->flags & MOK_MIRROR_DELETE_FIRST) LibDeleteVariable(v->rtname, v->guid); @@ -286,6 +465,43 @@ maybe_mirror_one_mok_variable(struct mok_state_variable *v, EFI_STATUS ret) efi_status); } } + + present = (v->data && v->data_size) ? TRUE : FALSE; + if (!present) + return ret; + + if (v->data_size == sizeof(UINT8) && v->state) { + *v->state = v->data[0]; + } + + if (v->flags & MOK_VARIABLE_MEASURE) { + /* + * Measure this into PCR 7 in the Microsoft format + */ + efi_status = tpm_measure_variable(v->name, *v->guid, + v->data_size, + v->data); + if (EFI_ERROR(efi_status)) { + if (ret != EFI_SECURITY_VIOLATION) + ret = efi_status; + } + } + + if (v->flags & MOK_VARIABLE_LOG) { + /* + * Log this variable into whichever PCR the table + * says. + */ + EFI_PHYSICAL_ADDRESS datap = + (EFI_PHYSICAL_ADDRESS)(UINTN)v->data, + efi_status = tpm_log_event(datap, v->data_size, + v->pcr, (CHAR8 *)v->name8); + if (EFI_ERROR(efi_status)) { + if (ret != EFI_SECURITY_VIOLATION) + ret = efi_status; + } + } + return ret; } @@ -311,26 +527,20 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle) user_insecure_mode = 0; ignore_db = 0; + dprint(L"importing mok state\n"); for (i = 0; mok_state_variables[i].name != NULL; i++) { struct mok_state_variable *v = &mok_state_variables[i]; UINT32 attrs = 0; - BOOLEAN delete = FALSE, present, addend; - - addend = check_addend(v); + BOOLEAN delete = FALSE; efi_status = get_variable_attr(v->name, &v->data, &v->data_size, *v->guid, &attrs); + dprint(L"maybe mirroring %s\n", v->name); if (efi_status == EFI_NOT_FOUND) { - if (addend) - ret = maybe_mirror_one_mok_variable(v, ret); - /* - * after possibly adding, we can continue, no - * further checks to be done. - */ - continue; - } - if (EFI_ERROR(efi_status)) { + v->data = NULL; + v->data_size = 0; + } else if (EFI_ERROR(efi_status)) { perror(L"Could not verify %s: %r\n", v->name, efi_status); /* @@ -339,22 +549,22 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle) */ if (ret != EFI_SECURITY_VIOLATION) ret = efi_status; - continue; - } - - if (!(attrs & v->yes_attr)) { - perror(L"Variable %s is missing attributes:\n", - v->name); - perror(L" 0x%08x should have 0x%08x set.\n", - attrs, v->yes_attr); - delete = TRUE; - } - if (attrs & v->no_attr) { - perror(L"Variable %s has incorrect attribute:\n", - v->name); - perror(L" 0x%08x should not have 0x%08x set.\n", - attrs, v->no_attr); delete = TRUE; + } else { + if (!(attrs & v->yes_attr)) { + perror(L"Variable %s is missing attributes:\n", + v->name); + perror(L" 0x%08x should have 0x%08x set.\n", + attrs, v->yes_attr); + delete = TRUE; + } + if (attrs & v->no_attr) { + perror(L"Variable %s has incorrect attribute:\n", + v->name); + perror(L" 0x%08x should not have 0x%08x set.\n", + attrs, v->no_attr); + delete = TRUE; + } } if (delete == TRUE) { perror(L"Deleting bad variable %s\n", v->name); @@ -366,45 +576,9 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle) FreePool(v->data); v->data = NULL; v->data_size = 0; - continue; } - if (v->data && v->data_size == sizeof(UINT8) && v->state) { - *v->state = v->data[0]; - } - - present = (v->data && v->data_size) ? TRUE : FALSE; - - if (v->flags & MOK_VARIABLE_MEASURE && present) { - /* - * Measure this into PCR 7 in the Microsoft format - */ - efi_status = tpm_measure_variable(v->name, *v->guid, - v->data_size, - v->data); - if (EFI_ERROR(efi_status)) { - if (ret != EFI_SECURITY_VIOLATION) - ret = efi_status; - } - } - - if (v->flags & MOK_VARIABLE_LOG && present) { - /* - * Log this variable into whichever PCR the table - * says. - */ - EFI_PHYSICAL_ADDRESS datap = - (EFI_PHYSICAL_ADDRESS)(UINTN)v->data, - efi_status = tpm_log_event(datap, v->data_size, - v->pcr, (CHAR8 *)v->name8); - if (EFI_ERROR(efi_status)) { - if (ret != EFI_SECURITY_VIOLATION) - ret = efi_status; - } - } - - if (present) - ret = maybe_mirror_one_mok_variable(v, ret); + ret = maybe_mirror_one_mok_variable(v, ret); } /* @@ -412,14 +586,16 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle) * cause MokManager to demand a machine reboot, so this is safe to * have after the entire loop. */ + dprint(L"checking mok request\n"); efi_status = check_mok_request(image_handle); + dprint(L"mok returned %r\n", efi_status); if (EFI_ERROR(efi_status)) { if (ret != EFI_SECURITY_VIOLATION) ret = efi_status; return ret; } - + dprint(L"returning %r\n", ret); return ret; } diff --git a/shim.c b/shim.c index 888ee6e8d7b..ee62248ca4e 100644 --- a/shim.c +++ b/shim.c @@ -646,6 +646,31 @@ static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert, } } +#if defined(VENDOR_DB_FILE) + EFI_SIGNATURE_LIST *db = (EFI_SIGNATURE_LIST *)vendor_db; + + if (check_db_hash_in_ram(db, vendor_db_size, + sha256hash, SHA256_DIGEST_SIZE, + EFI_CERT_SHA256_GUID, L"vendor_db", + EFI_SECURE_BOOT_DB_GUID) == DATA_FOUND) { + verification_method = VERIFIED_BY_HASH; + update_verification_method(VERIFIED_BY_HASH); + return EFI_SUCCESS; + } else { + LogError(L"check_db_hash(vendor_db, sha256hash) != DATA_FOUND\n"); + } + if (cert && + check_db_cert_in_ram(db, vendor_db_size, + cert, sha256hash, L"vendor_db", + EFI_SECURE_BOOT_DB_GUID) == DATA_FOUND) { + verification_method = VERIFIED_BY_CERT; + update_verification_method(VERIFIED_BY_CERT); + return EFI_SUCCESS; + } else { + LogError(L"check_db_cert(vendor_db, sha256hash) != DATA_FOUND\n"); + } +#endif + if (check_db_hash(L"MokList", SHIM_LOCK_GUID, sha256hash, SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID) == DATA_FOUND) { @@ -1076,6 +1101,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize, } #endif /* defined(ENABLE_SHIM_CERT) */ +#if defined(VENDOR_CERT_FILE) /* * And finally, check against shim's built-in key */ @@ -1093,6 +1119,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize, } else { LogError(L"AuthenticodeVerify(vendor_authorized) failed\n"); } +#endif /* defined(VENDOR_CERT_FILE) */ } LogError(L"Binary is not whitelisted\n"); diff --git a/include/console.h b/include/console.h index 9f259c71b72..810bf13a1f1 100644 --- a/include/console.h +++ b/include/console.h @@ -78,12 +78,13 @@ struct _EFI_CONSOLE_CONTROL_PROTOCOL { extern VOID console_fini(VOID); extern VOID setup_verbosity(VOID); extern UINT32 verbose; -#define dprint(fmt, ...) ({ \ +#define dprint_(fmt, ...) ({ \ UINTN __dprint_ret = 0; \ if (verbose) \ __dprint_ret = console_print((fmt), ##__VA_ARGS__); \ __dprint_ret; \ }) +#define dprint(fmt, ...) dprint_(L"%a:%d:%a() " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__) extern EFI_STATUS print_crypto_errors(EFI_STATUS rc, char *file, const char *func, int line); #define crypterr(rc) print_crypto_errors((rc), __FILE__, __func__, __LINE__) diff --git a/include/variables.h b/include/variables.h index 8566a1a4746..436adb46e16 100644 --- a/include/variables.h +++ b/include/variables.h @@ -57,7 +57,12 @@ EFI_STATUS variable_enroll_hash(CHAR16 *var, EFI_GUID owner, UINT8 hash[SHA256_DIGEST_SIZE]); EFI_STATUS -variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner, - void **out, int *outlen); +variable_create_esl(const uint8_t *cert, const size_t cert_len, + const EFI_GUID *type, const EFI_GUID *owner, + uint8_t **out, size_t *outlen); +EFI_STATUS +fill_esl(const uint8_t *data, const size_t data_len, + const EFI_GUID *type, const EFI_GUID *owner, + uint8_t *out, size_t *outlen); #endif /* SHIM_VARIABLES_H */ diff --git a/shim.h b/shim.h index 555498c6673..c1d7e7c7197 100644 --- a/shim.h +++ b/shim.h @@ -97,7 +97,11 @@ #define FALLBACK L"\\fb" EFI_ARCH L".efi" #define MOK_MANAGER L"\\mm" EFI_ARCH L".efi" -#if defined(VENDOR_CERT_FILE) +#if defined(VENDOR_DB_FILE) +# define vendor_authorized vendor_db +# define vendor_authorized_size vendor_db_size +# define vendor_authorized_category VENDOR_ADDEND_DB +#elif defined(VENDOR_CERT_FILE) # define vendor_authorized vendor_cert # define vendor_authorized_size vendor_cert_size # define vendor_authorized_category VENDOR_ADDEND_X509 @@ -116,6 +120,7 @@ #endif #include "include/asm.h" +#include "include/compiler.h" #include "include/configtable.h" #include "include/console.h" #include "include/crypt_blowfish.h" diff --git a/cert.S b/cert.S index 520caaef3af..e636fcbbf2d 100644 --- a/cert.S +++ b/cert.S @@ -1,5 +1,12 @@ -#if defined(VENDOR_CERT_FILE) +#if defined(VENDOR_DB_FILE) && defined(VENDOR_CERT_FILE) +# error both VENDOR_DB_FILE and VENDOR_CERT_FILE have been configured +#elif defined(VENDOR_DB_FILE) +# define vendor_authorized vendor_db +# define vendor_authorized_end vendor_db_end +# define vendor_authorized_size vendor_db_size +# define vendor_authorized_size_end vendor_db_size_end +#elif defined(VENDOR_CERT_FILE) # define vendor_authorized vendor_cert # define vendor_authorized_end vendor_cert_end # define vendor_authorized_size vendor_cert_size @@ -28,7 +35,9 @@ cert_table: .size vendor_authorized, .Lvendor_authorized_end - vendor_authorized .section .vendor_cert, "a", %progbits vendor_authorized: -#if defined(VENDOR_CERT_FILE) +#if defined(VENDOR_DB_FILE) +.incbin VENDOR_DB_FILE +#elif defined(VENDOR_CERT_FILE) .incbin VENDOR_CERT_FILE #endif .Lvendor_authorized_end: diff --git a/Make.defaults b/Make.defaults index f0bfa9fd573..2e01646a35d 100644 --- a/Make.defaults +++ b/Make.defaults @@ -125,6 +125,9 @@ BOOTCSVNAME ?= BOOT$(ARCH_SUFFIX_UPPER).CSV CFLAGS += "-DEFI_ARCH=L\"$(ARCH_SUFFIX)\"" "-DDEBUGDIR=L\"/usr/lib/debug/usr/share/shim/$(ARCH_SUFFIX)-$(VERSION)$(DASHRELEASE)/\"" +ifneq ($(origin VENDOR_DB_FILE), undefined) + CFLAGS += -DVENDOR_DB_FILE=\"$(VENDOR_DB_FILE)\" +endif ifneq ($(origin VENDOR_CERT_FILE), undefined) CFLAGS += -DVENDOR_CERT_FILE=\"$(VENDOR_CERT_FILE)\" endif diff --git a/README.tpm b/README.tpm index c060dbe22db..62308d5c71a 100644 --- a/README.tpm +++ b/README.tpm @@ -13,6 +13,7 @@ PCR7: - MokListX - the Mok blacklist, logged as "MokListX" - vendor_dbx - shim's built-in vendor blacklist, logged as "dbx" - DB - the system whitelist, logged as "db" + - vendor_db - shim's built-in vendor whitelist, logged as "db" - MokList the Mok whitelist, logged as "MokList" - vendor_cert - shim's built-in vendor whitelist, logged as "Shim" - shim_cert - shim's build-time generated whitelist, logged as "Shim" -- 2.26.2