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