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 < (*lhdr)->SignatureListSize ) {
78 DBGC ( data, "EFISIG [%#zx,%#zx) truncated list at "
79 "+%#zx\n", *start, len, offset );
80 return -EINVAL;
81 }
82 remaining = (*lhdr)->SignatureListSize;
83
84 /* Get length of each signature in list */
85 dlen = (*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 (*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 ) + (*lhdr)->SignatureHeaderSize );
101 offset += skip;
102 remaining -= skip;
103
104 /* Read signatures */
105 for ( ; remaining ; offset += dlen, remaining -= dlen ) {
106
107 /* Check length */
108 if ( remaining < dlen ) {
109 DBGC ( data, "EFISIG [%#zx,%#zx) truncated "
110 "at +%#zx\n", *start, len, offset );
111 return -EINVAL;
112 }
113
114 /* Continue until we find the requested signature */
115 if ( offset < *start )
116 continue;
117
118 /* Read data header */
119 *dhdr = ( data + offset );
120 DBGC2 ( data, "EFISIG [%#zx,%#zx) %s ",
121 offset, ( offset + dlen ),
122 efi_guid_ntoa ( &(*lhdr)->SignatureType ) );
123 DBGC2 ( data, "owner %s\n",
124 efi_guid_ntoa ( &(*dhdr)->SignatureOwner ) );
125 *start = offset;
126 return 0;
127 }
128 }
129}
130
131/**
132 * Extract ASN.1 object from EFI signature list
133 *
134 * @v data EFI signature list
135 * @v len Length of EFI signature list
136 * @v offset Offset within image
137 * @v cursor ASN.1 cursor to fill in
138 * @ret next Offset to next image, or negative error
139 *
140 * The caller is responsible for eventually calling free() on the
141 * allocated ASN.1 cursor.
142 */
143int efisig_asn1 ( const void *data, size_t len, size_t offset,
144 struct asn1_cursor **cursor ) {
145 const EFI_SIGNATURE_LIST *lhdr;
146 const EFI_SIGNATURE_DATA *dhdr;
147 int ( * asn1 ) ( const void *data, size_t len, size_t offset,
148 struct asn1_cursor **cursor );
149 size_t skip = offsetof ( typeof ( *dhdr ), SignatureData );
150 int next;
151 int rc;
152
153 /* Locate signature list entry */
154 if ( ( rc = efisig_find ( data, len, &offset, &lhdr, &dhdr ) ) != 0 )
155 goto err_entry;
156 len = ( offset + lhdr->SignatureSize );
157
158 /* Parse as PEM or DER based on first character */
159 asn1 = ( ( dhdr->SignatureData[0] == ASN1_SEQUENCE ) ?
160 der_asn1 : pem_asn1 );
161 DBGC2 ( data, "EFISIG [%#zx,%#zx) extracting %s\n", offset, len,
162 ( ( asn1 == der_asn1 ) ? "DER" : "PEM" ) );
163 next = asn1 ( data, len, ( offset + skip ), cursor );
164 if ( next < 0 ) {
165 rc = next;
166 DBGC ( data, "EFISIG [%#zx,%#zx) could not extract ASN.1: "
167 "%s\n", offset, len, strerror ( rc ) );
168 goto err_asn1;
169 }
170
171 /* Check that whole entry was consumed */
172 if ( ( ( unsigned int ) next ) != len ) {
173 DBGC ( data, "EFISIG [%#zx,%#zx) malformed data\n",
174 offset, len );
175 rc = -EINVAL;
176 goto err_whole;
177 }
178
179 return len;
180
181 err_whole:
182 free ( *cursor );
183 err_asn1:
184 err_entry:
185 return rc;
186}
187
188/**
189 * Probe EFI signature list image
190 *
191 * @v image EFI signature list
192 * @ret rc Return status code
193 */
194static int efisig_image_probe ( struct image *image ) {
195 const EFI_SIGNATURE_LIST *lhdr;
196 const EFI_SIGNATURE_DATA *dhdr;
197 size_t offset = 0;
198 unsigned int count = 0;
199 int rc;
200
201 /* Check file is a well-formed signature list */
202 while ( 1 ) {
203
204 /* Find next signature list entry */
205 if ( ( rc = efisig_find ( image->data, image->len, &offset,
206 &lhdr, &dhdr ) ) != 0 ) {
207 return rc;
208 }
209
210 /* Skip this entry */
211 offset += lhdr->SignatureSize;
212 count++;
213
214 /* Check if we have reached end of the image */
215 if ( offset == image->len ) {
216 DBGC ( image, "EFISIG %s contains %d signatures\n",
217 image->name, count );
218 return 0;
219 }
220 }
221}
222
223/**
224 * Extract ASN.1 object from EFI signature list image
225 *
226 * @v image EFI signature list
227 * @v offset Offset within image
228 * @v cursor ASN.1 cursor to fill in
229 * @ret next Offset to next image, or negative error
230 *
231 * The caller is responsible for eventually calling free() on the
232 * allocated ASN.1 cursor.
233 */
234static int efisig_image_asn1 ( struct image *image, size_t offset,
235 struct asn1_cursor **cursor ) {
236 int next;
237 int rc;
238
239 /* Extract ASN.1 object */
240 if ( ( next = efisig_asn1 ( image->data, image->len, offset,
241 cursor ) ) < 0 ) {
242 rc = next;
243 DBGC ( image, "EFISIG %s could not extract ASN.1: %s\n",
244 image->name, strerror ( rc ) );
245 return rc;
246 }
247
248 return next;
249}
250
251/** EFI signature list image type */
252struct image_type efisig_image_type __image_type ( PROBE_NORMAL ) = {
253 .name = "EFISIG",
254 .probe = efisig_image_probe,
255 .asn1 = efisig_image_asn1,
256};
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:726
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:522
#define DBGC(...)
Definition compiler.h:505
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:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
Executable images.
#define PROBE_NORMAL
Normal image probe priority.
Definition image.h:156
#define __image_type(probe_order)
An executable image type.
Definition image.h:170
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 SignatureListSize
Total size of the signature list, including this header.
UINT32 SignatureSize
Size of each signature.
An ASN.1 object cursor.
Definition asn1.h:21
An executable image type.
Definition image.h:95
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:56