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