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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 /** @file
27  *
28  * EFI signature lists
29  *
30  */
31 
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <ipxe/asn1.h>
36 #include <ipxe/der.h>
37 #include <ipxe/pem.h>
38 #include <ipxe/image.h>
39 #include <ipxe/efi/efi.h>
41 #include <ipxe/efi/efi_siglist.h>
42 
43 /**
44  * Find EFI signature list entry
45  *
46  * @v data EFI signature list
47  * @v len Length of EFI signature list
48  * @v start Starting offset to update
49  * @v lhdr Signature list header to fill in
50  * @v dhdr Signature data header to fill in
51  * @ret rc Return status code
52  */
53 static int efisig_find ( const void *data, size_t len, size_t *start,
54  const EFI_SIGNATURE_LIST **lhdr,
55  const EFI_SIGNATURE_DATA **dhdr ) {
56  size_t offset;
57  size_t remaining;
58  size_t skip;
59  size_t dlen;
60 
61  /* Scan through signature list */
62  offset = 0;
63  while ( 1 ) {
64 
65  /* Read list header */
66  assert ( offset <= len );
67  remaining = ( len - offset );
68  if ( remaining < sizeof ( **lhdr ) ) {
69  DBGC ( data, "EFISIG [%#zx,%#zx) truncated header "
70  "at +%#zx\n", *start, len, offset );
71  return -EINVAL;
72  }
73  *lhdr = ( data + offset );
74 
75  /* Get length of this signature list */
76  if ( remaining < (*lhdr)->SignatureListSize ) {
77  DBGC ( data, "EFISIG [%#zx,%#zx) truncated list at "
78  "+%#zx\n", *start, len, offset );
79  return -EINVAL;
80  }
81  remaining = (*lhdr)->SignatureListSize;
82 
83  /* Get length of each signature in list */
84  dlen = (*lhdr)->SignatureSize;
85  if ( dlen < sizeof ( **dhdr ) ) {
86  DBGC ( data, "EFISIG [%#zx,%#zx) underlength "
87  "signatures at +%#zx\n", *start, len, offset );
88  return -EINVAL;
89  }
90 
91  /* Strip list header (including variable portion) */
92  if ( ( remaining < sizeof ( **lhdr ) ) ||
93  ( ( remaining - sizeof ( **lhdr ) ) <
94  (*lhdr)->SignatureHeaderSize ) ) {
95  DBGC ( data, "EFISIG [%#zx,%#zx) malformed header at "
96  "+%#zx\n", *start, len, offset );
97  return -EINVAL;
98  }
99  skip = ( sizeof ( **lhdr ) + (*lhdr)->SignatureHeaderSize );
100  offset += skip;
101  remaining -= skip;
102 
103  /* Read signatures */
104  for ( ; remaining ; offset += dlen, remaining -= dlen ) {
105 
106  /* Check length */
107  if ( remaining < dlen ) {
108  DBGC ( data, "EFISIG [%#zx,%#zx) truncated "
109  "at +%#zx\n", *start, len, offset );
110  return -EINVAL;
111  }
112 
113  /* Continue until we find the requested signature */
114  if ( offset < *start )
115  continue;
116 
117  /* Read data header */
118  *dhdr = ( data + offset );
119  DBGC2 ( data, "EFISIG [%#zx,%#zx) %s ",
120  offset, ( offset + dlen ),
121  efi_guid_ntoa ( &(*lhdr)->SignatureType ) );
122  DBGC2 ( data, "owner %s\n",
123  efi_guid_ntoa ( &(*dhdr)->SignatureOwner ) );
124  *start = offset;
125  return 0;
126  }
127  }
128 }
129 
130 /**
131  * Extract ASN.1 object from EFI signature list
132  *
133  * @v data EFI signature list
134  * @v len Length of EFI signature list
135  * @v offset Offset within image
136  * @v cursor ASN.1 cursor to fill in
137  * @ret next Offset to next image, or negative error
138  *
139  * The caller is responsible for eventually calling free() on the
140  * allocated ASN.1 cursor.
141  */
142 int efisig_asn1 ( const void *data, size_t len, size_t offset,
143  struct asn1_cursor **cursor ) {
144  const EFI_SIGNATURE_LIST *lhdr;
145  const EFI_SIGNATURE_DATA *dhdr;
146  int ( * asn1 ) ( const void *data, size_t len, size_t offset,
147  struct asn1_cursor **cursor );
148  size_t skip = offsetof ( typeof ( *dhdr ), SignatureData );
149  int next;
150  int rc;
151 
152  /* Locate signature list entry */
153  if ( ( rc = efisig_find ( data, len, &offset, &lhdr, &dhdr ) ) != 0 )
154  goto err_entry;
155  len = ( offset + lhdr->SignatureSize );
156 
157  /* Parse as PEM or DER based on first character */
158  asn1 = ( ( dhdr->SignatureData[0] == ASN1_SEQUENCE ) ?
159  der_asn1 : pem_asn1 );
160  DBGC2 ( data, "EFISIG [%#zx,%#zx) extracting %s\n", offset, len,
161  ( ( asn1 == der_asn1 ) ? "DER" : "PEM" ) );
162  next = asn1 ( data, len, ( offset + skip ), cursor );
163  if ( next < 0 ) {
164  rc = next;
165  DBGC ( data, "EFISIG [%#zx,%#zx) could not extract ASN.1: "
166  "%s\n", offset, len, strerror ( rc ) );
167  goto err_asn1;
168  }
169 
170  /* Check that whole entry was consumed */
171  if ( ( ( unsigned int ) next ) != len ) {
172  DBGC ( data, "EFISIG [%#zx,%#zx) malformed data\n",
173  offset, len );
174  rc = -EINVAL;
175  goto err_whole;
176  }
177 
178  return len;
179 
180  err_whole:
181  free ( *cursor );
182  err_asn1:
183  err_entry:
184  return rc;
185 }
186 
187 /**
188  * Probe EFI signature list image
189  *
190  * @v image EFI signature list
191  * @ret rc Return status code
192  */
193 static int efisig_image_probe ( struct image *image ) {
194  const EFI_SIGNATURE_LIST *lhdr;
195  const EFI_SIGNATURE_DATA *dhdr;
196  size_t offset = 0;
197  unsigned int count = 0;
198  int rc;
199 
200  /* Check file is a well-formed signature list */
201  while ( 1 ) {
202 
203  /* Find next signature list entry */
204  if ( ( rc = efisig_find ( image->data, image->len, &offset,
205  &lhdr, &dhdr ) ) != 0 ) {
206  return rc;
207  }
208 
209  /* Skip this entry */
210  offset += lhdr->SignatureSize;
211  count++;
212 
213  /* Check if we have reached end of the image */
214  if ( offset == image->len ) {
215  DBGC ( image, "EFISIG %s contains %d signatures\n",
216  image->name, count );
217  return 0;
218  }
219  }
220 }
221 
222 /**
223  * Extract ASN.1 object from EFI signature list image
224  *
225  * @v image EFI signature list
226  * @v offset Offset within image
227  * @v cursor ASN.1 cursor to fill in
228  * @ret next Offset to next image, or negative error
229  *
230  * The caller is responsible for eventually calling free() on the
231  * allocated ASN.1 cursor.
232  */
233 static int efisig_image_asn1 ( struct image *image, size_t offset,
234  struct asn1_cursor **cursor ) {
235  int next;
236  int rc;
237 
238  /* Extract ASN.1 object */
239  if ( ( next = efisig_asn1 ( image->data, image->len, offset,
240  cursor ) ) < 0 ) {
241  rc = next;
242  DBGC ( image, "EFISIG %s could not extract ASN.1: %s\n",
243  image->name, strerror ( rc ) );
244  return rc;
245  }
246 
247  return next;
248 }
249 
250 /** EFI signature list image type */
251 struct image_type efisig_image_type __image_type ( PROBE_NORMAL ) = {
252  .name = "EFISIG",
253  .probe = efisig_image_probe,
254  .asn1 = efisig_image_asn1,
255 };
#define EINVAL
Invalid argument.
Definition: errno.h:428
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
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:103
UINT32 SignatureSize
Size of each signature.
Error codes.
const void * data
Read-only data.
Definition: image.h:50
#define DBGC(...)
Definition: compiler.h:505
An executable image type.
Definition: image.h:94
static int efisig_image_asn1(struct image *image, size_t offset, struct asn1_cursor **cursor)
Extract ASN.1 object from EFI signature list image.
Definition: efi_siglist.c:233
#define PROBE_NORMAL
Normal image probe priority.
Definition: image.h:155
An executable image.
Definition: image.h:23
#define offsetof(type, field)
Get offset of a field within a structure.
Definition: stddef.h:24
char * name
Name of this image type.
Definition: image.h:96
PEM-encoded ASN.1 data.
uint32_t start
Starting offset.
Definition: netvsc.h:12
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
Executable images.
UINT8 SignatureData[1]
The format of the signature is defined by the SignatureType.
ASN.1 encoding.
int efisig_asn1(const void *data, size_t len, size_t offset, struct asn1_cursor **cursor)
Extract ASN.1 object from EFI signature list.
Definition: efi_siglist.c:142
PEM-encoded ASN.1 data.
ring len
Length.
Definition: dwmac.h:231
int(* asn1)(struct image *image, size_t offset, struct asn1_cursor **cursor)
Extract ASN.1 object from image.
Definition: image.h:132
static unsigned int count
Number of entries.
Definition: dwmac.h:225
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
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:53
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
size_t len
Length of raw file image.
Definition: image.h:55
struct image_type efisig_image_type __image_type(PROBE_NORMAL)
EFI signature list image type.
DER image format.
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition: efi_guid.c:725
#define ASN1_SEQUENCE
ASN.1 sequence.
Definition: asn1.h:89
uint32_t next
Next descriptor address.
Definition: dwmac.h:22
EFI API.
static int efisig_image_probe(struct image *image)
Probe EFI signature list image.
Definition: efi_siglist.c:193
The format of a signature database.
#define DBGC2(...)
Definition: compiler.h:522
Image signature database are defined for the signed image validation.
uint8_t data[48]
Additional event data.
Definition: ena.h:22
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:52
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:47
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
char * name
Name.
Definition: image.h:37
String functions.
An ASN.1 object cursor.
Definition: asn1.h:20