109 lines
2.9 KiB
C
109 lines
2.9 KiB
C
|
// SPDX-License-Identifier: GPL-2.0+
|
||
|
/* EFI signature/key/certificate list parser
|
||
|
*
|
||
|
* Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved.
|
||
|
* Written by David Howells (dhowells@redhat.com)
|
||
|
*/
|
||
|
|
||
|
#define pr_fmt(fmt) "EFI: "fmt
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/printk.h>
|
||
|
#include <linux/err.h>
|
||
|
#include <linux/efi.h>
|
||
|
|
||
|
/**
|
||
|
* parse_efi_signature_list - Parse an EFI signature list for certificates
|
||
|
* @source: The source of the key
|
||
|
* @data: The data blob to parse
|
||
|
* @size: The size of the data blob
|
||
|
* @get_handler_for_guid: Get the handler func for the sig type (or NULL)
|
||
|
*
|
||
|
* Parse an EFI signature list looking for elements of interest. A list is
|
||
|
* made up of a series of sublists, where all the elements in a sublist are of
|
||
|
* the same type, but sublists can be of different types.
|
||
|
*
|
||
|
* For each sublist encountered, the @get_handler_for_guid function is called
|
||
|
* with the type specifier GUID and returns either a pointer to a function to
|
||
|
* handle elements of that type or NULL if the type is not of interest.
|
||
|
*
|
||
|
* If the sublist is of interest, each element is passed to the handler
|
||
|
* function in turn.
|
||
|
*
|
||
|
* Error EBADMSG is returned if the list doesn't parse correctly and 0 is
|
||
|
* returned if the list was parsed correctly. No error can be returned from
|
||
|
* the @get_handler_for_guid function or the element handler function it
|
||
|
* returns.
|
||
|
*/
|
||
|
int __init parse_efi_signature_list(
|
||
|
const char *source,
|
||
|
const void *data, size_t size,
|
||
|
efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *))
|
||
|
{
|
||
|
efi_element_handler_t handler;
|
||
|
unsigned int offs = 0;
|
||
|
|
||
|
pr_devel("-->%s(,%zu)\n", __func__, size);
|
||
|
|
||
|
while (size > 0) {
|
||
|
const efi_signature_data_t *elem;
|
||
|
efi_signature_list_t list;
|
||
|
size_t lsize, esize, hsize, elsize;
|
||
|
|
||
|
if (size < sizeof(list))
|
||
|
return -EBADMSG;
|
||
|
|
||
|
memcpy(&list, data, sizeof(list));
|
||
|
pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n",
|
||
|
offs,
|
||
|
&list.signature_type, list.signature_list_size,
|
||
|
list.signature_header_size, list.signature_size);
|
||
|
|
||
|
lsize = list.signature_list_size;
|
||
|
hsize = list.signature_header_size;
|
||
|
esize = list.signature_size;
|
||
|
elsize = lsize - sizeof(list) - hsize;
|
||
|
|
||
|
if (lsize > size) {
|
||
|
pr_devel("<--%s() = -EBADMSG [overrun @%x]\n",
|
||
|
__func__, offs);
|
||
|
return -EBADMSG;
|
||
|
}
|
||
|
|
||
|
if (lsize < sizeof(list) ||
|
||
|
lsize - sizeof(list) < hsize ||
|
||
|
esize < sizeof(*elem) ||
|
||
|
elsize < esize ||
|
||
|
elsize % esize != 0) {
|
||
|
pr_devel("- bad size combo @%x\n", offs);
|
||
|
return -EBADMSG;
|
||
|
}
|
||
|
|
||
|
handler = get_handler_for_guid(&list.signature_type);
|
||
|
if (!handler) {
|
||
|
data += lsize;
|
||
|
size -= lsize;
|
||
|
offs += lsize;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
data += sizeof(list) + hsize;
|
||
|
size -= sizeof(list) + hsize;
|
||
|
offs += sizeof(list) + hsize;
|
||
|
|
||
|
for (; elsize > 0; elsize -= esize) {
|
||
|
elem = data;
|
||
|
|
||
|
pr_devel("ELEM[%04x]\n", offs);
|
||
|
handler(source,
|
||
|
&elem->signature_data,
|
||
|
esize - sizeof(*elem));
|
||
|
|
||
|
data += esize;
|
||
|
size -= esize;
|
||
|
offs += esize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|