mirror of
https://git.proxmox.com/git/efi-boot-shim
synced 2025-06-14 11:10:31 +00:00
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
This commit is contained in:
parent
7d542805ba
commit
dd3a5d7125
@ -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
|
||||
|
@ -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"
|
||||
|
13
cert.S
13
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:
|
||||
|
@ -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__)
|
||||
|
@ -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 */
|
||||
|
@ -25,30 +25,57 @@
|
||||
#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;
|
||||
|
||||
if (!data || !data_len || !type || !outlen)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
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 = 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, 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;
|
||||
|
||||
EFI_SIGNATURE_LIST *sl = *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);
|
||||
|
||||
if (owner)
|
||||
sd->SignatureOwner = *owner;
|
||||
|
||||
CopyMem(sd->SignatureData, cert, cert_len);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
return fill_esl(data, data_len, type, owner, *out, outlen);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
@ -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);
|
||||
|
522
mok.c
522
mok.c
@ -5,6 +5,8 @@
|
||||
|
||||
#include "shim.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* 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)
|
||||
size_t build_cert_esl_sz = 0, addend_esl_sz = 0;
|
||||
|
||||
if (v->categorize_addend)
|
||||
addend_category = v->categorize_addend(v);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
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;
|
||||
|
||||
if (!EFI_ERROR(efi_status) && v->data_size > 0) {
|
||||
CopyMem(p, v->data, v->data_size);
|
||||
p += v->data_size;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_SHIM_CERT)
|
||||
if (check_build_cert(v) == FALSE)
|
||||
goto skip_build_cert;
|
||||
|
||||
CertList = (EFI_SIGNATURE_LIST *)p;
|
||||
p += sizeof (*CertList);
|
||||
CertData = (EFI_SIGNATURE_DATA *)p;
|
||||
p += sizeof (EFI_GUID);
|
||||
|
||||
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);
|
||||
|
||||
CertData->SignatureOwner = SHIM_LOCK_GUID;
|
||||
CopyMem(p, *v->build_cert, *v->build_cert_size);
|
||||
|
||||
p += *v->build_cert_size;
|
||||
|
||||
if (check_vendor_cert(v) == FALSE)
|
||||
goto skip_vendor_cert;
|
||||
skip_build_cert:
|
||||
#endif /* defined(ENABLE_SHIM_CERT) */
|
||||
|
||||
CertList = (EFI_SIGNATURE_LIST *)p;
|
||||
p += sizeof (*CertList);
|
||||
CertData = (EFI_SIGNATURE_DATA *)p;
|
||||
p += sizeof (EFI_GUID);
|
||||
|
||||
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);
|
||||
|
||||
CertData->SignatureOwner = SHIM_LOCK_GUID;
|
||||
CopyMem(p, *v->addend_source, *v->addend_size);
|
||||
|
||||
#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;
|
||||
dprint(L"FullDataSize:%lu FullData:0x%08llx\n",
|
||||
FullDataSize, FullData);
|
||||
}
|
||||
|
||||
/*
|
||||
* if it is, there's more data
|
||||
*/
|
||||
if (v->flags & MOK_MIRROR_KEYDB) {
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* first bit is existing data, but we added that above
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Now fill it.
|
||||
*/
|
||||
if (v->flags & MOK_MIRROR_KEYDB) {
|
||||
/*
|
||||
* first bit is existing data, but again, we added that above
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
27
shim.c
27
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");
|
||||
|
7
shim.h
7
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"
|
||||
|
Loading…
Reference in New Issue
Block a user