1 /*-
2 * Copyright (c) 2019 Stormshield.
3 * Copyright (c) 2019 Semihalf.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 #include <stand.h>
29 #include <string.h>
30
31 #include <efi.h>
32 #include <efilib.h>
33 #include <Guid/ImageAuthentication.h>
34
35 #define NEED_BRSSL_H
36 #include "../libsecureboot-priv.h"
37 #include <brssl.h>
38
39 static EFI_GUID ImageSecurityDatabaseGUID = EFI_IMAGE_SECURITY_DATABASE_GUID;
40
41 static EFI_GUID efiCertX509GUID = EFI_CERT_X509_GUID;
42 static EFI_GUID efiCertX509Sha256GUID = EFI_CERT_X509_SHA256_GUID;
43 static EFI_GUID efiCertX509Sha384GUID = EFI_CERT_X509_SHA384_GUID;
44 static EFI_GUID efiCertX509Sha5122UID = EFI_CERT_X509_SHA512_GUID;
45
46 /*
47 * Check if Secure Boot is enabled in firmware.
48 * We evaluate two variables - Secure Boot and Setup Mode.
49 * Secure Boot is enforced only if the first one equals 1 and the other 0.
50 */
51 int
efi_secure_boot_enabled(void)52 efi_secure_boot_enabled(void)
53 {
54 UINT8 SecureBoot;
55 UINT8 SetupMode;
56 size_t length;
57 EFI_STATUS status;
58
59 length = sizeof(SecureBoot);
60 status = efi_global_getenv("SecureBoot", &SecureBoot, &length);
61 if (status != EFI_SUCCESS) {
62 if (status == EFI_NOT_FOUND)
63 return (0);
64
65 printf("Failed to read \"SecureBoot\" variable\n");
66 return (-efi_status_to_errno(status));
67 }
68
69 length = sizeof(SetupMode);
70 status = efi_global_getenv("SetupMode", &SetupMode, &length);
71 if (status != EFI_SUCCESS)
72 SetupMode = 0;
73
74 printf(" SecureBoot: %d, SetupMode: %d\n", SecureBoot, SetupMode);
75
76 return (SecureBoot == 1 && SetupMode == 0);
77 }
78
79 /*
80 * Iterate through UEFI variable and extract X509 certificates from it.
81 * The EFI_* structures and related guids are defined in UEFI standard.
82 */
83 static br_x509_certificate*
efi_get_certs(const char * name,size_t * count)84 efi_get_certs(const char *name, size_t *count)
85 {
86 br_x509_certificate *certs;
87 UINT8 *database;
88 EFI_SIGNATURE_LIST *list;
89 EFI_SIGNATURE_DATA *entry;
90 size_t db_size;
91 ssize_t cert_count;
92 EFI_STATUS status;
93
94 database = NULL;
95 certs = NULL;
96 db_size = 0;
97 cert_count = 0;
98
99 /*
100 * Read variable length and allocate memory for it
101 */
102 status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
103 if (status != EFI_BUFFER_TOO_SMALL)
104 return (NULL);
105
106 database = malloc(db_size);
107 if (database == NULL)
108 return (NULL);
109
110 status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
111 if (status != EFI_SUCCESS)
112 goto fail;
113
114 for (list = (EFI_SIGNATURE_LIST*) database;
115 db_size >= list->SignatureListSize && db_size > 0;
116 db_size -= list->SignatureListSize,
117 list = (EFI_SIGNATURE_LIST*)
118 ((UINT8*)list + list->SignatureListSize)) {
119
120 /* We are only interested in entries containing X509 certs. */
121 if (memcmp(&efiCertX509GUID,
122 &list->SignatureType,
123 sizeof(EFI_GUID)) != 0) {
124 continue;
125 }
126
127 entry = (EFI_SIGNATURE_DATA*)
128 ((UINT8*)list +
129 sizeof(EFI_SIGNATURE_LIST) +
130 list->SignatureHeaderSize);
131
132 certs = realloc(certs,
133 (cert_count + 1) * sizeof(br_x509_certificate));
134 if (certs == NULL) {
135 cert_count = 0;
136 goto fail;
137 }
138
139 certs[cert_count].data_len = list->SignatureSize - sizeof(EFI_GUID);
140 certs[cert_count].data = malloc(certs[cert_count].data_len);
141 if (certs[cert_count].data == NULL)
142 goto fail;
143
144 memcpy(certs[cert_count].data,
145 entry->SignatureData,
146 certs[cert_count].data_len);
147
148 cert_count++;
149 }
150
151 *count = cert_count;
152
153 xfree(database);
154 return (certs);
155
156 fail:
157 free_certificates(certs, cert_count);
158 xfree(database);
159 return (NULL);
160
161 }
162
163 /*
164 * Extract digests from UEFI "dbx" variable.
165 * UEFI standard specifies three types of digest - sha256, sha386, sha512.
166 */
167 hash_data*
efi_get_forbidden_digests(size_t * count)168 efi_get_forbidden_digests(size_t *count)
169 {
170 UINT8 *database;
171 hash_data *digests;
172 EFI_SIGNATURE_LIST *list;
173 EFI_SIGNATURE_DATA *entry;
174 size_t db_size, header_size, hash_size;
175 int digest_count, entry_count;
176 EFI_STATUS status;
177
178 db_size = 0;
179 digest_count = 0;
180 database = NULL;
181 digests = NULL;
182
183 status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
184 if (status != EFI_BUFFER_TOO_SMALL)
185 return (NULL);
186
187 database = malloc(db_size);
188 if (database == NULL)
189 return (NULL);
190
191 status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
192 if (status != EFI_SUCCESS)
193 goto fail;
194
195
196 for (list = (EFI_SIGNATURE_LIST*) database;
197 db_size >= list->SignatureListSize && db_size > 0;
198 db_size -= list->SignatureListSize,
199 list = (EFI_SIGNATURE_LIST*)
200 ((UINT8*)list + list->SignatureListSize)) {
201
202 /* We are only interested in entries that contain digests. */
203 if (memcmp(&efiCertX509Sha256GUID, &list->SignatureType,
204 sizeof(EFI_GUID)) == 0) {
205 hash_size = br_sha256_SIZE;
206 } else if (memcmp(&efiCertX509Sha384GUID, &list->SignatureType,
207 sizeof(EFI_GUID)) == 0) {
208 hash_size = br_sha384_SIZE;
209 } else if (memcmp(&efiCertX509Sha5122UID, &list->SignatureType,
210 sizeof(EFI_GUID)) == 0) {
211 hash_size = br_sha512_SIZE;
212 } else {
213 continue;
214 }
215
216 /*
217 * A single entry can have multiple digests
218 * of the same type for some reason.
219 */
220 header_size = sizeof(EFI_SIGNATURE_LIST) + list->SignatureHeaderSize;
221
222 /* Calculate the number of entries basing on structure size */
223 entry_count = list->SignatureListSize - header_size;
224 entry_count /= list->SignatureSize;
225 entry = (EFI_SIGNATURE_DATA*)((UINT8*)list + header_size);
226 while (entry_count-- > 0) {
227 digests = realloc(digests,
228 (digest_count + 1) * sizeof(hash_data));
229 if (digests == NULL) {
230 digest_count = 0;
231 goto fail;
232 }
233
234 digests[digest_count].data = malloc(hash_size);
235 if (digests[digest_count].data == NULL)
236 goto fail;
237
238 memcpy(digests[digest_count].data,
239 entry->SignatureData,
240 hash_size);
241 digests[digest_count].hash_size = hash_size;
242
243 entry = (EFI_SIGNATURE_DATA*)(entry + list->SignatureSize);
244 digest_count++;
245 }
246 }
247 xfree(database);
248 if (count != NULL)
249 *count = digest_count;
250
251 return (digests);
252
253 fail:
254 while (digest_count--)
255 xfree(digests[digest_count].data);
256
257 xfree(database);
258 xfree(digests);
259 return (NULL);
260 }
261
262 /* Copy x509 certificates from db */
263 br_x509_certificate*
efi_get_trusted_certs(size_t * count)264 efi_get_trusted_certs(size_t *count)
265 {
266 return (efi_get_certs("db", count));
267 }
268
269 /* Copy forbidden certificates from dbx */
270 br_x509_certificate*
efi_get_forbidden_certs(size_t * count)271 efi_get_forbidden_certs(size_t *count)
272 {
273 return (efi_get_certs("dbx", count));
274 }
275