1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /* EFI signature/key/certificate list parser
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved.
5*4882a593Smuzhiyun * Written by David Howells (dhowells@redhat.com)
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #define pr_fmt(fmt) "EFI: "fmt
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/printk.h>
11*4882a593Smuzhiyun #include <linux/err.h>
12*4882a593Smuzhiyun #include <linux/efi.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun /**
15*4882a593Smuzhiyun * parse_efi_signature_list - Parse an EFI signature list for certificates
16*4882a593Smuzhiyun * @source: The source of the key
17*4882a593Smuzhiyun * @data: The data blob to parse
18*4882a593Smuzhiyun * @size: The size of the data blob
19*4882a593Smuzhiyun * @get_handler_for_guid: Get the handler func for the sig type (or NULL)
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun * Parse an EFI signature list looking for elements of interest. A list is
22*4882a593Smuzhiyun * made up of a series of sublists, where all the elements in a sublist are of
23*4882a593Smuzhiyun * the same type, but sublists can be of different types.
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * For each sublist encountered, the @get_handler_for_guid function is called
26*4882a593Smuzhiyun * with the type specifier GUID and returns either a pointer to a function to
27*4882a593Smuzhiyun * handle elements of that type or NULL if the type is not of interest.
28*4882a593Smuzhiyun *
29*4882a593Smuzhiyun * If the sublist is of interest, each element is passed to the handler
30*4882a593Smuzhiyun * function in turn.
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun * Error EBADMSG is returned if the list doesn't parse correctly and 0 is
33*4882a593Smuzhiyun * returned if the list was parsed correctly. No error can be returned from
34*4882a593Smuzhiyun * the @get_handler_for_guid function or the element handler function it
35*4882a593Smuzhiyun * returns.
36*4882a593Smuzhiyun */
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 *))37*4882a593Smuzhiyun int __init parse_efi_signature_list(
38*4882a593Smuzhiyun const char *source,
39*4882a593Smuzhiyun const void *data, size_t size,
40*4882a593Smuzhiyun efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *))
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun efi_element_handler_t handler;
43*4882a593Smuzhiyun unsigned int offs = 0;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun pr_devel("-->%s(,%zu)\n", __func__, size);
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun while (size > 0) {
48*4882a593Smuzhiyun const efi_signature_data_t *elem;
49*4882a593Smuzhiyun efi_signature_list_t list;
50*4882a593Smuzhiyun size_t lsize, esize, hsize, elsize;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun if (size < sizeof(list))
53*4882a593Smuzhiyun return -EBADMSG;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun memcpy(&list, data, sizeof(list));
56*4882a593Smuzhiyun pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n",
57*4882a593Smuzhiyun offs,
58*4882a593Smuzhiyun list.signature_type.b, list.signature_list_size,
59*4882a593Smuzhiyun list.signature_header_size, list.signature_size);
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun lsize = list.signature_list_size;
62*4882a593Smuzhiyun hsize = list.signature_header_size;
63*4882a593Smuzhiyun esize = list.signature_size;
64*4882a593Smuzhiyun elsize = lsize - sizeof(list) - hsize;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun if (lsize > size) {
67*4882a593Smuzhiyun pr_devel("<--%s() = -EBADMSG [overrun @%x]\n",
68*4882a593Smuzhiyun __func__, offs);
69*4882a593Smuzhiyun return -EBADMSG;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if (lsize < sizeof(list) ||
73*4882a593Smuzhiyun lsize - sizeof(list) < hsize ||
74*4882a593Smuzhiyun esize < sizeof(*elem) ||
75*4882a593Smuzhiyun elsize < esize ||
76*4882a593Smuzhiyun elsize % esize != 0) {
77*4882a593Smuzhiyun pr_devel("- bad size combo @%x\n", offs);
78*4882a593Smuzhiyun return -EBADMSG;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun handler = get_handler_for_guid(&list.signature_type);
82*4882a593Smuzhiyun if (!handler) {
83*4882a593Smuzhiyun data += lsize;
84*4882a593Smuzhiyun size -= lsize;
85*4882a593Smuzhiyun offs += lsize;
86*4882a593Smuzhiyun continue;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun data += sizeof(list) + hsize;
90*4882a593Smuzhiyun size -= sizeof(list) + hsize;
91*4882a593Smuzhiyun offs += sizeof(list) + hsize;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun for (; elsize > 0; elsize -= esize) {
94*4882a593Smuzhiyun elem = data;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun pr_devel("ELEM[%04x]\n", offs);
97*4882a593Smuzhiyun handler(source,
98*4882a593Smuzhiyun &elem->signature_data,
99*4882a593Smuzhiyun esize - sizeof(*elem));
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun data += esize;
102*4882a593Smuzhiyun size -= esize;
103*4882a593Smuzhiyun offs += esize;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun return 0;
108*4882a593Smuzhiyun }
109