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