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 FILE_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>
42 #include <ipxe/efi/efi_siglist.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  */
54 static 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  */
143 int 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  */
194 static 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  */
234 static 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 */
252 struct image_type efisig_image_type __image_type ( PROBE_NORMAL ) = {
253  .name = "EFISIG",
254  .probe = efisig_image_probe,
255  .asn1 = efisig_image_asn1,
256 };
#define EINVAL
Invalid argument.
Definition: errno.h:429
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:104
UINT32 SignatureSize
Size of each signature.
Error codes.
const void * data
Read-only data.
Definition: image.h:51
FILE_SECBOOT(PERMITTED)
#define DBGC(...)
Definition: compiler.h:505
An executable image type.
Definition: image.h:95
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:234
#define PROBE_NORMAL
Normal image probe priority.
Definition: image.h:156
An executable image.
Definition: image.h:24
#define offsetof(type, field)
Get offset of a field within a structure.
Definition: stddef.h:25
char * name
Name of this image type.
Definition: image.h:97
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:143
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:133
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:54
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
size_t len
Length of raw file image.
Definition: image.h:56
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:726
#define ASN1_SEQUENCE
ASN.1 sequence.
Definition: asn1.h:90
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:194
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:53
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:48
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
char * name
Name.
Definition: image.h:38
String functions.
An ASN.1 object cursor.
Definition: asn1.h:21