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