iPXE
efi_siglist.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27/** @file
28 *
29 * EFI signature lists
30 *
31 */
32
33#include <stdlib.h>
34#include <string.h>
35#include <errno.h>
36#include <ipxe/asn1.h>
37#include <ipxe/der.h>
38#include <ipxe/pem.h>
39#include <ipxe/image.h>
40#include <ipxe/efi/efi.h>
43
44/**
45 * Find EFI signature list entry
46 *
47 * @v data EFI signature list
48 * @v len Length of EFI signature list
49 * @v start Starting offset to update
50 * @v lhdr Signature list header to fill in
51 * @v dhdr Signature data header to fill in
52 * @ret rc Return status code
53 */
54static int efisig_find ( const void *data, size_t len, size_t *start,
55 const EFI_SIGNATURE_LIST **lhdr,
56 const EFI_SIGNATURE_DATA **dhdr ) {
57 size_t offset;
58 size_t remaining;
59 size_t skip;
60 size_t dlen;
61
62 /* Scan through signature list */
63 offset = 0;
64 while ( 1 ) {
65
66 /* Read list header */
67 assert ( offset <= len );
68 remaining = ( len - offset );
69 if ( remaining < sizeof ( **lhdr ) ) {
70 DBGC ( data, "EFISIG [%#zx,%#zx) truncated header "
71 "at +%#zx\n", *start, len, offset );
72 return -EINVAL;
73 }
74 *lhdr = ( data + offset );
75
76 /* Get length of this signature list */
77 if ( remaining < le32_to_cpu ( (*lhdr)->SignatureListSize ) ) {
78 DBGC ( data, "EFISIG [%#zx,%#zx) truncated list at "
79 "+%#zx\n", *start, len, offset );
80 return -EINVAL;
81 }
82 remaining = le32_to_cpu ( (*lhdr)->SignatureListSize );
83
84 /* Get length of each signature in list */
85 dlen = le32_to_cpu ( (*lhdr)->SignatureSize );
86 if ( dlen < sizeof ( **dhdr ) ) {
87 DBGC ( data, "EFISIG [%#zx,%#zx) underlength "
88 "signatures at +%#zx\n", *start, len, offset );
89 return -EINVAL;
90 }
91
92 /* Strip list header (including variable portion) */
93 if ( ( remaining < sizeof ( **lhdr ) ) ||
94 ( ( remaining - sizeof ( **lhdr ) ) <
95 le32_to_cpu ( (*lhdr)->SignatureHeaderSize ) ) ) {
96 DBGC ( data, "EFISIG [%#zx,%#zx) malformed header at "
97 "+%#zx\n", *start, len, offset );
98 return -EINVAL;
99 }
100 skip = ( sizeof ( **lhdr ) +
101 le32_to_cpu ( (*lhdr)->SignatureHeaderSize ) );
102 offset += skip;
103 remaining -= skip;
104
105 /* Read signatures */
106 for ( ; remaining ; offset += dlen, remaining -= dlen ) {
107
108 /* Check length */
109 if ( remaining < dlen ) {
110 DBGC ( data, "EFISIG [%#zx,%#zx) truncated "
111 "at +%#zx\n", *start, len, offset );
112 return -EINVAL;
113 }
114
115 /* Continue until we find the requested signature */
116 if ( offset < *start )
117 continue;
118
119 /* Read data header */
120 *dhdr = ( data + offset );
121 DBGC2 ( data, "EFISIG [%#zx,%#zx) %s ",
122 offset, ( offset + dlen ),
123 efi_guid_ntoa ( &(*lhdr)->SignatureType ) );
124 DBGC2 ( data, "owner %s\n",
125 efi_guid_ntoa ( &(*dhdr)->SignatureOwner ) );
126 *start = offset;
127 return 0;
128 }
129 }
130}
131
132/**
133 * Extract ASN.1 object from EFI signature list
134 *
135 * @v data EFI signature list
136 * @v len Length of EFI signature list
137 * @v offset Offset within image
138 * @v cursor ASN.1 cursor to fill in
139 * @ret next Offset to next image, or negative error
140 *
141 * The caller is responsible for eventually calling free() on the
142 * allocated ASN.1 cursor.
143 */
144int efisig_asn1 ( const void *data, size_t len, size_t offset,
145 struct asn1_cursor **cursor ) {
146 const EFI_SIGNATURE_LIST *lhdr;
147 const EFI_SIGNATURE_DATA *dhdr;
148 int ( * asn1 ) ( const void *data, size_t len, size_t offset,
149 struct asn1_cursor **cursor );
150 size_t skip = offsetof ( typeof ( *dhdr ), SignatureData );
151 int next;
152 int rc;
153
154 /* Locate signature list entry */
155 if ( ( rc = efisig_find ( data, len, &offset, &lhdr, &dhdr ) ) != 0 )
156 goto err_entry;
157 len = ( offset + le32_to_cpu ( lhdr->SignatureSize ) );
158
159 /* Parse as PEM or DER based on first character */
160 asn1 = ( ( dhdr->SignatureData[0] == ASN1_SEQUENCE ) ?
161 der_asn1 : pem_asn1 );
162 DBGC2 ( data, "EFISIG [%#zx,%#zx) extracting %s\n", offset, len,
163 ( ( asn1 == der_asn1 ) ? "DER" : "PEM" ) );
164 next = asn1 ( data, len, ( offset + skip ), cursor );
165 if ( next < 0 ) {
166 rc = next;
167 DBGC ( data, "EFISIG [%#zx,%#zx) could not extract ASN.1: "
168 "%s\n", offset, len, strerror ( rc ) );
169 goto err_asn1;
170 }
171
172 /* Check that whole entry was consumed */
173 if ( ( ( unsigned int ) next ) != len ) {
174 DBGC ( data, "EFISIG [%#zx,%#zx) malformed data\n",
175 offset, len );
176 rc = -EINVAL;
177 goto err_whole;
178 }
179
180 return len;
181
182 err_whole:
183 free ( *cursor );
184 err_asn1:
185 err_entry:
186 return rc;
187}
188
189/**
190 * Probe EFI signature list image
191 *
192 * @v image EFI signature list
193 * @ret rc Return status code
194 */
195static int efisig_image_probe ( struct image *image ) {
196 const EFI_SIGNATURE_LIST *lhdr;
197 const EFI_SIGNATURE_DATA *dhdr;
198 size_t offset = 0;
199 unsigned int count = 0;
200 int rc;
201
202 /* Check file is a well-formed signature list */
203 while ( 1 ) {
204
205 /* Find next signature list entry */
206 if ( ( rc = efisig_find ( image->data, image->len, &offset,
207 &lhdr, &dhdr ) ) != 0 ) {
208 return rc;
209 }
210
211 /* Skip this entry */
212 offset += le32_to_cpu ( lhdr->SignatureSize );
213 count++;
214
215 /* Check if we have reached end of the image */
216 if ( offset == image->len ) {
217 DBGC ( image, "EFISIG %s contains %d signatures\n",
218 image->name, count );
219 return 0;
220 }
221 }
222}
223
224/**
225 * Extract ASN.1 object from EFI signature list image
226 *
227 * @v image EFI signature list
228 * @v offset Offset within image
229 * @v cursor ASN.1 cursor to fill in
230 * @ret next Offset to next image, or negative error
231 *
232 * The caller is responsible for eventually calling free() on the
233 * allocated ASN.1 cursor.
234 */
235static int efisig_image_asn1 ( struct image *image, size_t offset,
236 struct asn1_cursor **cursor ) {
237 int next;
238 int rc;
239
240 /* Extract ASN.1 object */
241 if ( ( next = efisig_asn1 ( image->data, image->len, offset,
242 cursor ) ) < 0 ) {
243 rc = next;
244 DBGC ( image, "EFISIG %s could not extract ASN.1: %s\n",
245 image->name, strerror ( rc ) );
246 return rc;
247 }
248
249 return next;
250}
251
252/** EFI signature list image type */
253struct image_type efisig_image_type __image_type ( PROBE_NORMAL ) = {
254 .name = "EFISIG",
255 .probe = efisig_image_probe,
256 .asn1 = efisig_image_asn1,
257};
Image signature database are defined for the signed image validation.
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
ASN.1 encoding.
#define ASN1_SEQUENCE
ASN.1 sequence.
Definition asn1.h:90
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
uint16_t offset
Offset to command line.
Definition bzimage.h:3
int der_asn1(const void *data, size_t len, size_t offset, struct asn1_cursor **cursor)
Extract ASN.1 object from DER data.
Definition der.c:53
DER image format.
uint32_t next
Next descriptor address.
Definition dwmac.h:11
ring len
Length.
Definition dwmac.h:226
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition efi_guid.c:733
int efisig_asn1(const void *data, size_t len, size_t offset, struct asn1_cursor **cursor)
Extract ASN.1 object from EFI signature list.
static int efisig_image_asn1(struct image *image, size_t offset, struct asn1_cursor **cursor)
Extract ASN.1 object from EFI signature list image.
static int efisig_image_probe(struct image *image)
Probe EFI signature list image.
static int efisig_find(const void *data, size_t len, size_t *start, const EFI_SIGNATURE_LIST **lhdr, const EFI_SIGNATURE_DATA **dhdr)
Find EFI signature list entry.
Definition efi_siglist.c:54
PEM-encoded ASN.1 data.
uint8_t data[48]
Additional event data.
Definition ena.h:11
Error codes.
#define DBGC2(...)
Definition compiler.h:547
#define DBGC(...)
Definition compiler.h:530
uint32_t start
Starting offset.
Definition netvsc.h:1
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:921
#define EINVAL
Invalid argument.
Definition errno.h:429
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:951
Executable images.
#define PROBE_NORMAL
Normal image probe priority.
Definition image.h:163
#define __image_type(probe_order)
An executable image type.
Definition image.h:177
#define le32_to_cpu(value)
Definition byteswap.h:114
EFI API.
String functions.
int pem_asn1(const void *data, size_t len, size_t offset, struct asn1_cursor **cursor)
Extract ASN.1 object from PEM data.
Definition pem.c:104
PEM-encoded ASN.1 data.
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
The format of a signature database.
UINT8 SignatureData[1]
The format of the signature is defined by the SignatureType.
UINT32 SignatureSize
Size of each signature.
An ASN.1 object cursor.
Definition asn1.h:21
An executable image type.
Definition image.h:102
An executable image.
Definition image.h:24
const void * data
Read-only data.
Definition image.h:51
char * name
Name.
Definition image.h:38
size_t len
Length of raw file image.
Definition image.h:63