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