xref: /freebsd/lib/libsecureboot/efi/efi_variables.c (revision b9f654b163bce26de79705e77b872427c9f2afa1)
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 }
279