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 * $FreeBSD$
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <stand.h>
33 #include <string.h>
34
35 #include <efi.h>
36 #include <efilib.h>
37 #include <Guid/ImageAuthentication.h>
38
39 #define NEED_BRSSL_H
40 #include "../libsecureboot-priv.h"
41 #include <brssl.h>
42
43 static EFI_GUID ImageSecurityDatabaseGUID = EFI_IMAGE_SECURITY_DATABASE_GUID;
44
45 static EFI_GUID efiCertX509GUID = EFI_CERT_X509_GUID;
46 static EFI_GUID efiCertX509Sha256GUID = EFI_CERT_X509_SHA256_GUID;
47 static EFI_GUID efiCertX509Sha384GUID = EFI_CERT_X509_SHA384_GUID;
48 static EFI_GUID efiCertX509Sha5122UID = EFI_CERT_X509_SHA512_GUID;
49
50 /*
51 * Check if Secure Boot is enabled in firmware.
52 * We evaluate two variables - Secure Boot and Setup Mode.
53 * Secure Boot is enforced only if the first one equals 1 and the other 0.
54 */
55 int
efi_secure_boot_enabled(void)56 efi_secure_boot_enabled(void)
57 {
58 UINT8 SecureBoot;
59 UINT8 SetupMode;
60 size_t length;
61 EFI_STATUS status;
62
63 length = sizeof(SecureBoot);
64 status = efi_global_getenv("SecureBoot", &SecureBoot, &length);
65 if (status != EFI_SUCCESS) {
66 if (status == EFI_NOT_FOUND)
67 return (0);
68
69 printf("Failed to read \"SecureBoot\" variable\n");
70 return (-efi_status_to_errno(status));
71 }
72
73 length = sizeof(SetupMode);
74 status = efi_global_getenv("SetupMode", &SetupMode, &length);
75 if (status != EFI_SUCCESS)
76 SetupMode = 0;
77
78 printf(" SecureBoot: %d, SetupMode: %d\n", SecureBoot, SetupMode);
79
80 return (SecureBoot == 1 && SetupMode == 0);
81 }
82
83 /*
84 * Iterate through UEFI variable and extract X509 certificates from it.
85 * The EFI_* structures and related guids are defined in UEFI standard.
86 */
87 static br_x509_certificate*
efi_get_certs(const char * name,size_t * count)88 efi_get_certs(const char *name, size_t *count)
89 {
90 br_x509_certificate *certs;
91 UINT8 *database;
92 EFI_SIGNATURE_LIST *list;
93 EFI_SIGNATURE_DATA *entry;
94 size_t db_size;
95 ssize_t cert_count;
96 EFI_STATUS status;
97
98 database = NULL;
99 certs = NULL;
100 db_size = 0;
101 cert_count = 0;
102
103 /*
104 * Read variable length and allocate memory for it
105 */
106 status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
107 if (status != EFI_BUFFER_TOO_SMALL)
108 return (NULL);
109
110 database = malloc(db_size);
111 if (database == NULL)
112 return (NULL);
113
114 status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
115 if (status != EFI_SUCCESS)
116 goto fail;
117
118 for (list = (EFI_SIGNATURE_LIST*) database;
119 db_size >= list->SignatureListSize && db_size > 0;
120 db_size -= list->SignatureListSize,
121 list = (EFI_SIGNATURE_LIST*)
122 ((UINT8*)list + list->SignatureListSize)) {
123
124 /* We are only interested in entries containing X509 certs. */
125 if (memcmp(&efiCertX509GUID,
126 &list->SignatureType,
127 sizeof(EFI_GUID)) != 0) {
128 continue;
129 }
130
131 entry = (EFI_SIGNATURE_DATA*)
132 ((UINT8*)list +
133 sizeof(EFI_SIGNATURE_LIST) +
134 list->SignatureHeaderSize);
135
136 certs = realloc(certs,
137 (cert_count + 1) * sizeof(br_x509_certificate));
138 if (certs == NULL) {
139 cert_count = 0;
140 goto fail;
141 }
142
143 certs[cert_count].data_len = list->SignatureSize - sizeof(EFI_GUID);
144 certs[cert_count].data = malloc(certs[cert_count].data_len);
145 if (certs[cert_count].data == NULL)
146 goto fail;
147
148 memcpy(certs[cert_count].data,
149 entry->SignatureData,
150 certs[cert_count].data_len);
151
152 cert_count++;
153 }
154
155 *count = cert_count;
156
157 xfree(database);
158 return (certs);
159
160 fail:
161 free_certificates(certs, cert_count);
162 xfree(database);
163 return (NULL);
164
165 }
166
167 /*
168 * Extract digests from UEFI "dbx" variable.
169 * UEFI standard specifies three types of digest - sha256, sha386, sha512.
170 */
171 hash_data*
efi_get_forbidden_digests(size_t * count)172 efi_get_forbidden_digests(size_t *count)
173 {
174 UINT8 *database;
175 hash_data *digests;
176 EFI_SIGNATURE_LIST *list;
177 EFI_SIGNATURE_DATA *entry;
178 size_t db_size, header_size, hash_size;
179 int digest_count, entry_count;
180 EFI_STATUS status;
181
182 db_size = 0;
183 digest_count = 0;
184 database = NULL;
185 digests = NULL;
186
187 status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
188 if (status != EFI_BUFFER_TOO_SMALL)
189 return (NULL);
190
191 database = malloc(db_size);
192 if (database == NULL)
193 return (NULL);
194
195 status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
196 if (status != EFI_SUCCESS)
197 goto fail;
198
199
200 for (list = (EFI_SIGNATURE_LIST*) database;
201 db_size >= list->SignatureListSize && db_size > 0;
202 db_size -= list->SignatureListSize,
203 list = (EFI_SIGNATURE_LIST*)
204 ((UINT8*)list + list->SignatureListSize)) {
205
206 /* We are only interested in entries that contain digests. */
207 if (memcmp(&efiCertX509Sha256GUID, &list->SignatureType,
208 sizeof(EFI_GUID)) == 0) {
209 hash_size = br_sha256_SIZE;
210 } else if (memcmp(&efiCertX509Sha384GUID, &list->SignatureType,
211 sizeof(EFI_GUID)) == 0) {
212 hash_size = br_sha384_SIZE;
213 } else if (memcmp(&efiCertX509Sha5122UID, &list->SignatureType,
214 sizeof(EFI_GUID)) == 0) {
215 hash_size = br_sha512_SIZE;
216 } else {
217 continue;
218 }
219
220 /*
221 * A single entry can have multiple digests
222 * of the same type for some reason.
223 */
224 header_size = sizeof(EFI_SIGNATURE_LIST) + list->SignatureHeaderSize;
225
226 /* Calculate the number of entries basing on structure size */
227 entry_count = list->SignatureListSize - header_size;
228 entry_count /= list->SignatureSize;
229 entry = (EFI_SIGNATURE_DATA*)((UINT8*)list + header_size);
230 while (entry_count-- > 0) {
231 digests = realloc(digests,
232 (digest_count + 1) * sizeof(hash_data));
233 if (digests == NULL) {
234 digest_count = 0;
235 goto fail;
236 }
237
238 digests[digest_count].data = malloc(hash_size);
239 if (digests[digest_count].data == NULL)
240 goto fail;
241
242 memcpy(digests[digest_count].data,
243 entry->SignatureData,
244 hash_size);
245 digests[digest_count].hash_size = hash_size;
246
247 entry = (EFI_SIGNATURE_DATA*)(entry + list->SignatureSize);
248 digest_count++;
249 }
250 }
251 xfree(database);
252 if (count != NULL)
253 *count = digest_count;
254
255 return (digests);
256
257 fail:
258 while (digest_count--)
259 xfree(digests[digest_count].data);
260
261 xfree(database);
262 xfree(digests);
263 return (NULL);
264 }
265
266 /* Copy x509 certificates from db */
267 br_x509_certificate*
efi_get_trusted_certs(size_t * count)268 efi_get_trusted_certs(size_t *count)
269 {
270 return (efi_get_certs("db", count));
271 }
272
273 /* Copy forbidden certificates from dbx */
274 br_x509_certificate*
efi_get_forbidden_certs(size_t * count)275 efi_get_forbidden_certs(size_t *count)
276 {
277 return (efi_get_certs("dbx", count));
278 }
279