]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libsecureboot/efi/efi_variables.c
Merge OpenSSL 1.1.1i.
[FreeBSD/FreeBSD.git] / lib / libsecureboot / efi / efi_variables.c
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
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*
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*
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*
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*
275 efi_get_forbidden_certs(size_t *count)
276 {
277         return (efi_get_certs("dbx", count));
278 }