iPXE
efi_cacert.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 CA certificates
30  *
31  */
32 
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36 #include <errno.h>
37 #include <ipxe/init.h>
38 #include <ipxe/x509.h>
39 #include <ipxe/rootcert.h>
40 #include <ipxe/efi/efi.h>
41 #include <ipxe/efi/efi_siglist.h>
43 
44 /** List of EFI CA certificates */
45 static struct x509_chain efi_cacerts = {
47  .links = LIST_HEAD_INIT ( efi_cacerts.links ),
48 };
49 
50 /**
51  * Retrieve EFI CA certificate
52  *
53  * @v data TlsCaCertificate variable data
54  * @v len Length of TlsCaCertificate
55  * @v offset Offset within data
56  * @v next Next offset, or negative error
57  */
58 static int efi_cacert ( const void *data, size_t len, size_t offset ) {
59  struct asn1_cursor *cursor;
60  struct x509_certificate *cert;
61  int next;
62  int rc;
63 
64  /* Extract ASN.1 object */
65  next = efisig_asn1 ( data, len, offset, &cursor );
66  if ( next < 0 ) {
67  rc = next;
68  DBGC ( &efi_cacerts, "EFICA could not parse at +%#zx: %s\n",
69  offset, strerror ( rc ) );
70  goto err_asn1;
71  }
72 
73  /* Append to list of EFI CA certificates */
74  if ( ( rc = x509_append_raw ( &efi_cacerts, cursor->data,
75  cursor->len ) ) != 0 ) {
76  DBGC ( &efi_cacerts, "EFICA could not append at +%#zx: %s\n",
77  offset, strerror ( rc ) );
78  goto err_append;
79  }
80  cert = x509_last ( &efi_cacerts );
81  DBGC ( &efi_cacerts, "EFICA found certificate %s\n",
82  x509_name ( cert ) );
83 
84  /* Mark certificate as valid (i.e. trusted) if permitted */
85  if ( allow_trust_override ) {
86  DBGC ( &efi_cacerts, "EFICA trusting certificate %s\n",
87  x509_name ( cert ) );
89  }
90 
91  /* Free ASN.1 object */
92  free ( cursor );
93 
94  return next;
95 
96  err_append:
97  free ( cursor );
98  err_asn1:
99  return rc;
100 }
101 
102 /**
103  * Retrieve all EFI CA certificates
104  *
105  * @ret rc Return status code
106  */
107 static int efi_cacert_all ( void ) {
110  static CHAR16 *wname = EFI_TLS_CA_CERTIFICATE_VARIABLE;
111  int offset = 0;
112  UINT32 attrs;
113  UINTN size;
114  void *data;
115  EFI_STATUS efirc;
116  int rc;
117 
118  /* Get variable length */
119  size = 0;
120  if ( ( efirc = rs->GetVariable ( wname, guid, &attrs, &size,
121  NULL ) ) != EFI_BUFFER_TOO_SMALL ) {
122  rc = -EEFI ( efirc );
123  DBGC ( &efi_cacerts, "EFICA could not get %ls size: %s\n",
124  wname, strerror ( rc ) );
125  goto err_len;
126  }
127 
128  /* Allocate temporary buffer */
129  data = malloc ( size );
130  if ( ! data ) {
131  rc = -ENOMEM;
132  goto err_alloc;
133  }
134 
135  /* Read variable */
136  if ( ( efirc = rs->GetVariable ( wname, guid, &attrs, &size,
137  data ) ) != 0 ) {
138  rc = -EEFI ( efirc );
139  DBGC ( &efi_cacerts, "EFICA could not read %ls: %s\n",
140  wname, strerror ( rc ) );
141  goto err_get;
142  }
143 
144  /* Parse certificates */
145  while ( ( ( size_t ) offset ) < size ) {
146  offset = efi_cacert ( data, size, offset );
147  if ( offset < 0 ) {
148  rc = offset;
149  goto err_cacert;
150  }
151  }
152 
153  /* Success */
154  rc = 0;
155 
156  err_cacert:
157  err_get:
158  free ( data );
159  err_alloc:
160  err_len:
161  return rc;
162 }
163 
164 /**
165  * Initialise EFI CA certificates
166  *
167  */
168 static void efi_cacert_init ( void ) {
169  int rc;
170 
171  /* Initialise all certificates */
172  if ( ( rc = efi_cacert_all() ) != 0 ) {
173  DBGC ( &efi_cacert, "EFICA could not initialise: %s\n",
174  strerror ( rc ) );
175  /* Nothing we can do at this point */
176  return;
177  }
178 }
179 
180 /** EFI CA certificates initialisation function */
181 struct init_fn efi_cacert_init_fn __init_fn ( INIT_LATE ) = {
182  .name = "eficacert",
183  .initialise = efi_cacert_init,
184 };
185 
186 /**
187  * Discard any EFI CA certificates
188  *
189  */
190 static void efi_cacert_shutdown ( int booting __unused ) {
191 
192  /* Drop our references to the certificates */
193  DBGC ( &efi_cacert, "EFICA discarding certificates\n" );
196 }
197 
198 /** EFI CA certificates shutdown function */
199 struct startup_fn efi_cacert_shutdown_fn __startup_fn ( STARTUP_NORMAL ) = {
200  .name = "efi_cacert",
201  .shutdown = efi_cacert_shutdown,
202 };
#define STARTUP_NORMAL
Normal startup.
Definition: init.h:65
void x509_set_valid(struct x509_certificate *cert, struct x509_certificate *issuer, struct x509_root *root)
Set X.509 certificate as validated.
Definition: x509.c:1329
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:175
const int allow_trust_override
Flag indicating if root of trust may be overridden at runtime.
Definition: rootcert.c:65
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
128 bit buffer containing a unique identifier value.
Definition: Base.h:216
struct list_head links
List of links.
Definition: x509.h:205
Error codes.
FILE_SECBOOT(PERMITTED)
int x509_append_raw(struct x509_chain *chain, const void *data, size_t len)
Append X.509 certificate to X.509 certificate chain.
Definition: x509.c:1674
uint16_t size
Buffer size.
Definition: dwmac.h:14
struct x509_root root_certificates
Root certificates.
Definition: rootcert.c:79
const void * data
Start of data.
Definition: asn1.h:23
#define DBGC(...)
Definition: compiler.h:505
unsigned int UINT32
Definition: ProcessorBind.h:99
struct init_fn efi_cacert_init_fn __init_fn(INIT_LATE)
EFI CA certificates initialisation function.
unsigned short CHAR16
void x509_truncate(struct x509_chain *chain, struct x509_link *link)
Truncate X.509 certificate chain.
Definition: x509.c:1704
#define EFI_BUFFER_TOO_SMALL
Enumeration of EFI_STATUS.
Definition: UefiBaseType.h:120
const char * name
Definition: init.h:44
PEM-encoded ASN.1 data.
size_t len
Length of data.
Definition: asn1.h:25
static void efi_cacert_shutdown(int booting __unused)
Discard any EFI CA certificates.
Definition: efi_cacert.c:190
#define list_empty(list)
Test whether a list is empty.
Definition: list.h:137
A startup/shutdown function.
Definition: init.h:43
An X.509 certificate chain.
Definition: x509.h:201
#define ENOMEM
Not enough space.
Definition: errno.h:535
static struct x509_chain efi_cacerts
List of EFI CA certificates.
Definition: efi_cacert.c:45
#define EFI_TLS_CA_CERTIFICATE_VARIABLE
An initialisation function.
Definition: init.h:15
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
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
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
ring len
Length.
Definition: dwmac.h:231
const char * name
Definition: init.h:16
EFI_GET_VARIABLE GetVariable
Definition: UefiSpec.h:1903
static int efi_cacert_all(void)
Retrieve all EFI CA certificates.
Definition: efi_cacert.c:107
struct startup_fn efi_cacert_shutdown_fn __startup_fn(STARTUP_NORMAL)
EFI CA certificates shutdown function.
EFI Runtime Services Table.
Definition: UefiSpec.h:1880
static struct x509_certificate * x509_last(struct x509_chain *chain)
Get last certificate in X.509 certificate chain.
Definition: x509.h:325
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
An X.509 certificate.
Definition: x509.h:216
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
UINT64 UINTN
Unsigned value of native width.
X.509 certificates.
This file defines TlsCaCertificate variable.
uint32_t next
Next descriptor address.
Definition: dwmac.h:22
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:621
EFI API.
uint64_t guid
GUID.
Definition: edd.h:31
const char * x509_name(struct x509_certificate *cert)
Get X.509 certificate display name.
Definition: x509.c:147
EFI_RUNTIME_SERVICES * RuntimeServices
A pointer to the EFI Runtime Services Table.
Definition: UefiSpec.h:2095
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:32
EFI_GUID efi_tls_ca_certificate_guid
TLS CA certificate variable GUID.
Definition: efi_guid.c:478
uint8_t data[48]
Additional event data.
Definition: ena.h:22
#define REF_INIT(free_fn)
Initialise a static reference counter.
Definition: refcnt.h:78
Root certificate store.
EFI_SYSTEM_TABLE * efi_systab
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
#define INIT_LATE
Late initialisation.
Definition: init.h:33
#define LIST_HEAD_INIT(list)
Initialise a static list head.
Definition: list.h:31
static int efi_cacert(const void *data, size_t len, size_t offset)
Retrieve EFI CA certificate.
Definition: efi_cacert.c:58
static void efi_cacert_init(void)
Initialise EFI CA certificates.
Definition: efi_cacert.c:168
void ref_no_free(struct refcnt *refcnt __unused)
Do not free reference-counted object.
Definition: refcnt.c:102
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
An ASN.1 object cursor.
Definition: asn1.h:21
struct refcnt refcnt
Reference count.
Definition: x509.h:203