xref: /freebsd/lib/libsecureboot/efi/efi_variables.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
1*13ea0450SMarcin Wojtas /*-
2*13ea0450SMarcin Wojtas  * Copyright (c) 2019 Stormshield.
3*13ea0450SMarcin Wojtas  * Copyright (c) 2019 Semihalf.
4*13ea0450SMarcin Wojtas  *
5*13ea0450SMarcin Wojtas  * Redistribution and use in source and binary forms, with or without
6*13ea0450SMarcin Wojtas  * modification, are permitted provided that the following conditions
7*13ea0450SMarcin Wojtas  * are met:
8*13ea0450SMarcin Wojtas  * 1. Redistributions of source code must retain the above copyright
9*13ea0450SMarcin Wojtas  *    notice, this list of conditions and the following disclaimer.
10*13ea0450SMarcin Wojtas  * 2. Redistributions in binary form must reproduce the above copyright
11*13ea0450SMarcin Wojtas  *    notice, this list of conditions and the following disclaimer in the
12*13ea0450SMarcin Wojtas  *    documentation and/or other materials provided with the distribution.
13*13ea0450SMarcin Wojtas  *
14*13ea0450SMarcin Wojtas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*13ea0450SMarcin Wojtas  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16*13ea0450SMarcin Wojtas  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17*13ea0450SMarcin Wojtas  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18*13ea0450SMarcin Wojtas  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19*13ea0450SMarcin Wojtas  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20*13ea0450SMarcin Wojtas  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*13ea0450SMarcin Wojtas  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22*13ea0450SMarcin Wojtas  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23*13ea0450SMarcin Wojtas  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24*13ea0450SMarcin Wojtas  * POSSIBILITY OF SUCH DAMAGE.
25*13ea0450SMarcin Wojtas  */
26*13ea0450SMarcin Wojtas 
27*13ea0450SMarcin Wojtas #include <sys/cdefs.h>
28*13ea0450SMarcin Wojtas #include <stand.h>
29*13ea0450SMarcin Wojtas #include <string.h>
30*13ea0450SMarcin Wojtas 
31*13ea0450SMarcin Wojtas #include <efi.h>
32*13ea0450SMarcin Wojtas #include <efilib.h>
33*13ea0450SMarcin Wojtas #include <Guid/ImageAuthentication.h>
34*13ea0450SMarcin Wojtas 
35*13ea0450SMarcin Wojtas #define NEED_BRSSL_H
36*13ea0450SMarcin Wojtas #include "../libsecureboot-priv.h"
37*13ea0450SMarcin Wojtas #include <brssl.h>
38*13ea0450SMarcin Wojtas 
39*13ea0450SMarcin Wojtas static EFI_GUID ImageSecurityDatabaseGUID = EFI_IMAGE_SECURITY_DATABASE_GUID;
40*13ea0450SMarcin Wojtas 
41*13ea0450SMarcin Wojtas static EFI_GUID efiCertX509GUID = EFI_CERT_X509_GUID;
42*13ea0450SMarcin Wojtas static EFI_GUID efiCertX509Sha256GUID = EFI_CERT_X509_SHA256_GUID;
43*13ea0450SMarcin Wojtas static EFI_GUID efiCertX509Sha384GUID = EFI_CERT_X509_SHA384_GUID;
44*13ea0450SMarcin Wojtas static EFI_GUID efiCertX509Sha5122UID = EFI_CERT_X509_SHA512_GUID;
45*13ea0450SMarcin Wojtas 
46*13ea0450SMarcin Wojtas /*
47*13ea0450SMarcin Wojtas  * Check if Secure Boot is enabled in firmware.
48*13ea0450SMarcin Wojtas  * We evaluate two variables - Secure Boot and Setup Mode.
49*13ea0450SMarcin Wojtas  * Secure Boot is enforced only if the first one equals 1 and the other 0.
50*13ea0450SMarcin Wojtas  */
51*13ea0450SMarcin Wojtas int
efi_secure_boot_enabled(void)52*13ea0450SMarcin Wojtas efi_secure_boot_enabled(void)
53*13ea0450SMarcin Wojtas {
54*13ea0450SMarcin Wojtas 	UINT8 SecureBoot;
55*13ea0450SMarcin Wojtas 	UINT8 SetupMode;
56*13ea0450SMarcin Wojtas 	size_t length;
57*13ea0450SMarcin Wojtas 	EFI_STATUS status;
58*13ea0450SMarcin Wojtas 
59*13ea0450SMarcin Wojtas 	length = sizeof(SecureBoot);
60*13ea0450SMarcin Wojtas 	status = efi_global_getenv("SecureBoot", &SecureBoot, &length);
61*13ea0450SMarcin Wojtas 	if (status != EFI_SUCCESS) {
62*13ea0450SMarcin Wojtas 		if (status == EFI_NOT_FOUND)
63*13ea0450SMarcin Wojtas 			return (0);
64*13ea0450SMarcin Wojtas 
65*13ea0450SMarcin Wojtas 		printf("Failed to read \"SecureBoot\" variable\n");
66*13ea0450SMarcin Wojtas 		return (-efi_status_to_errno(status));
67*13ea0450SMarcin Wojtas 	}
68*13ea0450SMarcin Wojtas 
69*13ea0450SMarcin Wojtas 	length = sizeof(SetupMode);
70*13ea0450SMarcin Wojtas 	status = efi_global_getenv("SetupMode", &SetupMode, &length);
71*13ea0450SMarcin Wojtas 	if (status != EFI_SUCCESS)
72*13ea0450SMarcin Wojtas 		SetupMode = 0;
73*13ea0450SMarcin Wojtas 
74*13ea0450SMarcin Wojtas 	printf("   SecureBoot: %d, SetupMode: %d\n", SecureBoot, SetupMode);
75*13ea0450SMarcin Wojtas 
76*13ea0450SMarcin Wojtas 	return (SecureBoot == 1 && SetupMode == 0);
77*13ea0450SMarcin Wojtas }
78*13ea0450SMarcin Wojtas 
79*13ea0450SMarcin Wojtas /*
80*13ea0450SMarcin Wojtas  * Iterate through UEFI variable and extract X509 certificates from it.
81*13ea0450SMarcin Wojtas  * The EFI_* structures and related guids are defined in UEFI standard.
82*13ea0450SMarcin Wojtas  */
83*13ea0450SMarcin Wojtas static br_x509_certificate*
efi_get_certs(const char * name,size_t * count)84*13ea0450SMarcin Wojtas efi_get_certs(const char *name, size_t *count)
85*13ea0450SMarcin Wojtas {
86*13ea0450SMarcin Wojtas 	br_x509_certificate *certs;
87*13ea0450SMarcin Wojtas 	UINT8 *database;
88*13ea0450SMarcin Wojtas 	EFI_SIGNATURE_LIST *list;
89*13ea0450SMarcin Wojtas 	EFI_SIGNATURE_DATA *entry;
90*13ea0450SMarcin Wojtas 	size_t db_size;
91*13ea0450SMarcin Wojtas 	ssize_t cert_count;
92*13ea0450SMarcin Wojtas 	EFI_STATUS status;
93*13ea0450SMarcin Wojtas 
94*13ea0450SMarcin Wojtas 	database = NULL;
95*13ea0450SMarcin Wojtas 	certs = NULL;
96*13ea0450SMarcin Wojtas 	db_size = 0;
97*13ea0450SMarcin Wojtas 	cert_count = 0;
98*13ea0450SMarcin Wojtas 
99*13ea0450SMarcin Wojtas 	/*
100*13ea0450SMarcin Wojtas 	 * Read variable length and allocate memory for it
101*13ea0450SMarcin Wojtas 	 */
102*13ea0450SMarcin Wojtas 	status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
103*13ea0450SMarcin Wojtas 	if (status != EFI_BUFFER_TOO_SMALL)
104*13ea0450SMarcin Wojtas 		return (NULL);
105*13ea0450SMarcin Wojtas 
106*13ea0450SMarcin Wojtas 	database = malloc(db_size);
107*13ea0450SMarcin Wojtas 	if (database == NULL)
108*13ea0450SMarcin Wojtas 		return (NULL);
109*13ea0450SMarcin Wojtas 
110*13ea0450SMarcin Wojtas 	status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
111*13ea0450SMarcin Wojtas 	if (status != EFI_SUCCESS)
112*13ea0450SMarcin Wojtas 		goto fail;
113*13ea0450SMarcin Wojtas 
114*13ea0450SMarcin Wojtas 	for (list = (EFI_SIGNATURE_LIST*) database;
115*13ea0450SMarcin Wojtas 	    db_size >= list->SignatureListSize && db_size > 0;
116*13ea0450SMarcin Wojtas 	    db_size -= list->SignatureListSize,
117*13ea0450SMarcin Wojtas 	    list = (EFI_SIGNATURE_LIST*)
118*13ea0450SMarcin Wojtas 	    ((UINT8*)list + list->SignatureListSize)) {
119*13ea0450SMarcin Wojtas 
120*13ea0450SMarcin Wojtas 		/* We are only interested in entries containing X509 certs. */
121*13ea0450SMarcin Wojtas 		if (memcmp(&efiCertX509GUID,
122*13ea0450SMarcin Wojtas 		    &list->SignatureType,
123*13ea0450SMarcin Wojtas 		    sizeof(EFI_GUID)) != 0) {
124*13ea0450SMarcin Wojtas 			continue;
125*13ea0450SMarcin Wojtas 		}
126*13ea0450SMarcin Wojtas 
127*13ea0450SMarcin Wojtas 		entry = (EFI_SIGNATURE_DATA*)
128*13ea0450SMarcin Wojtas 		    ((UINT8*)list +
129*13ea0450SMarcin Wojtas 		    sizeof(EFI_SIGNATURE_LIST) +
130*13ea0450SMarcin Wojtas 		    list->SignatureHeaderSize);
131*13ea0450SMarcin Wojtas 
132*13ea0450SMarcin Wojtas 		certs = realloc(certs,
133*13ea0450SMarcin Wojtas 		    (cert_count + 1) * sizeof(br_x509_certificate));
134*13ea0450SMarcin Wojtas 		if (certs == NULL) {
135*13ea0450SMarcin Wojtas 			cert_count = 0;
136*13ea0450SMarcin Wojtas 			goto fail;
137*13ea0450SMarcin Wojtas 		}
138*13ea0450SMarcin Wojtas 
139*13ea0450SMarcin Wojtas 		certs[cert_count].data_len = list->SignatureSize - sizeof(EFI_GUID);
140*13ea0450SMarcin Wojtas 		certs[cert_count].data = malloc(certs[cert_count].data_len);
141*13ea0450SMarcin Wojtas 		if (certs[cert_count].data == NULL)
142*13ea0450SMarcin Wojtas 			goto fail;
143*13ea0450SMarcin Wojtas 
144*13ea0450SMarcin Wojtas 		memcpy(certs[cert_count].data,
145*13ea0450SMarcin Wojtas 		    entry->SignatureData,
146*13ea0450SMarcin Wojtas 		    certs[cert_count].data_len);
147*13ea0450SMarcin Wojtas 
148*13ea0450SMarcin Wojtas 		cert_count++;
149*13ea0450SMarcin Wojtas 	}
150*13ea0450SMarcin Wojtas 
151*13ea0450SMarcin Wojtas 	*count = cert_count;
152*13ea0450SMarcin Wojtas 
153*13ea0450SMarcin Wojtas 	xfree(database);
154*13ea0450SMarcin Wojtas 	return (certs);
155*13ea0450SMarcin Wojtas 
156*13ea0450SMarcin Wojtas fail:
157*13ea0450SMarcin Wojtas 	free_certificates(certs, cert_count);
158*13ea0450SMarcin Wojtas 	xfree(database);
159*13ea0450SMarcin Wojtas 	return (NULL);
160*13ea0450SMarcin Wojtas 
161*13ea0450SMarcin Wojtas }
162*13ea0450SMarcin Wojtas 
163*13ea0450SMarcin Wojtas /*
164*13ea0450SMarcin Wojtas  * Extract digests from UEFI "dbx" variable.
165*13ea0450SMarcin Wojtas  * UEFI standard specifies three types of digest - sha256, sha386, sha512.
166*13ea0450SMarcin Wojtas  */
167*13ea0450SMarcin Wojtas hash_data*
efi_get_forbidden_digests(size_t * count)168*13ea0450SMarcin Wojtas efi_get_forbidden_digests(size_t *count)
169*13ea0450SMarcin Wojtas {
170*13ea0450SMarcin Wojtas 	UINT8 *database;
171*13ea0450SMarcin Wojtas 	hash_data *digests;
172*13ea0450SMarcin Wojtas 	EFI_SIGNATURE_LIST *list;
173*13ea0450SMarcin Wojtas 	EFI_SIGNATURE_DATA *entry;
174*13ea0450SMarcin Wojtas 	size_t db_size, header_size, hash_size;
175*13ea0450SMarcin Wojtas 	int digest_count, entry_count;
176*13ea0450SMarcin Wojtas 	EFI_STATUS status;
177*13ea0450SMarcin Wojtas 
178*13ea0450SMarcin Wojtas 	db_size = 0;
179*13ea0450SMarcin Wojtas 	digest_count = 0;
180*13ea0450SMarcin Wojtas 	database = NULL;
181*13ea0450SMarcin Wojtas 	digests = NULL;
182*13ea0450SMarcin Wojtas 
183*13ea0450SMarcin Wojtas 	status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
184*13ea0450SMarcin Wojtas 	if (status != EFI_BUFFER_TOO_SMALL)
185*13ea0450SMarcin Wojtas 		return (NULL);
186*13ea0450SMarcin Wojtas 
187*13ea0450SMarcin Wojtas 	database = malloc(db_size);
188*13ea0450SMarcin Wojtas 	if (database == NULL)
189*13ea0450SMarcin Wojtas 		return (NULL);
190*13ea0450SMarcin Wojtas 
191*13ea0450SMarcin Wojtas 	status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
192*13ea0450SMarcin Wojtas 	if (status != EFI_SUCCESS)
193*13ea0450SMarcin Wojtas 		goto fail;
194*13ea0450SMarcin Wojtas 
195*13ea0450SMarcin Wojtas 
196*13ea0450SMarcin Wojtas 	for (list = (EFI_SIGNATURE_LIST*) database;
197*13ea0450SMarcin Wojtas 	    db_size >= list->SignatureListSize && db_size > 0;
198*13ea0450SMarcin Wojtas 	    db_size -= list->SignatureListSize,
199*13ea0450SMarcin Wojtas 	    list = (EFI_SIGNATURE_LIST*)
200*13ea0450SMarcin Wojtas 	    ((UINT8*)list + list->SignatureListSize)) {
201*13ea0450SMarcin Wojtas 
202*13ea0450SMarcin Wojtas 		/* We are only interested in entries that contain digests. */
203*13ea0450SMarcin Wojtas 		if (memcmp(&efiCertX509Sha256GUID, &list->SignatureType,
204*13ea0450SMarcin Wojtas 		    sizeof(EFI_GUID)) == 0) {
205*13ea0450SMarcin Wojtas 			hash_size = br_sha256_SIZE;
206*13ea0450SMarcin Wojtas 		} else if (memcmp(&efiCertX509Sha384GUID, &list->SignatureType,
207*13ea0450SMarcin Wojtas 		    sizeof(EFI_GUID)) == 0) {
208*13ea0450SMarcin Wojtas 			hash_size = br_sha384_SIZE;
209*13ea0450SMarcin Wojtas 		} else if (memcmp(&efiCertX509Sha5122UID, &list->SignatureType,
210*13ea0450SMarcin Wojtas 		    sizeof(EFI_GUID)) == 0) {
211*13ea0450SMarcin Wojtas 			hash_size = br_sha512_SIZE;
212*13ea0450SMarcin Wojtas 		} else {
213*13ea0450SMarcin Wojtas 			continue;
214*13ea0450SMarcin Wojtas 		}
215*13ea0450SMarcin Wojtas 
216*13ea0450SMarcin Wojtas 		/*
217*13ea0450SMarcin Wojtas 		 * A single entry can have multiple digests
218*13ea0450SMarcin Wojtas 		 * of the same type for some reason.
219*13ea0450SMarcin Wojtas 		 */
220*13ea0450SMarcin Wojtas 		header_size = sizeof(EFI_SIGNATURE_LIST) + list->SignatureHeaderSize;
221*13ea0450SMarcin Wojtas 
222*13ea0450SMarcin Wojtas 		/* Calculate the number of entries basing on structure size */
223*13ea0450SMarcin Wojtas 		entry_count = list->SignatureListSize - header_size;
224*13ea0450SMarcin Wojtas 		entry_count /= list->SignatureSize;
225*13ea0450SMarcin Wojtas 		entry = (EFI_SIGNATURE_DATA*)((UINT8*)list + header_size);
226*13ea0450SMarcin Wojtas 		while (entry_count-- > 0) {
227*13ea0450SMarcin Wojtas 			digests = realloc(digests,
228*13ea0450SMarcin Wojtas 			    (digest_count + 1) * sizeof(hash_data));
229*13ea0450SMarcin Wojtas 			if (digests == NULL) {
230*13ea0450SMarcin Wojtas 				digest_count = 0;
231*13ea0450SMarcin Wojtas 				goto fail;
232*13ea0450SMarcin Wojtas 			}
233*13ea0450SMarcin Wojtas 
234*13ea0450SMarcin Wojtas 			digests[digest_count].data = malloc(hash_size);
235*13ea0450SMarcin Wojtas 			if (digests[digest_count].data == NULL)
236*13ea0450SMarcin Wojtas 				goto fail;
237*13ea0450SMarcin Wojtas 
238*13ea0450SMarcin Wojtas 			memcpy(digests[digest_count].data,
239*13ea0450SMarcin Wojtas 			    entry->SignatureData,
240*13ea0450SMarcin Wojtas 			    hash_size);
241*13ea0450SMarcin Wojtas 			digests[digest_count].hash_size = hash_size;
242*13ea0450SMarcin Wojtas 
243*13ea0450SMarcin Wojtas 			entry = (EFI_SIGNATURE_DATA*)(entry + list->SignatureSize);
244*13ea0450SMarcin Wojtas 			digest_count++;
245*13ea0450SMarcin Wojtas 		}
246*13ea0450SMarcin Wojtas 	}
247*13ea0450SMarcin Wojtas 	xfree(database);
248*13ea0450SMarcin Wojtas 	if (count != NULL)
249*13ea0450SMarcin Wojtas 		*count = digest_count;
250*13ea0450SMarcin Wojtas 
251*13ea0450SMarcin Wojtas 	return (digests);
252*13ea0450SMarcin Wojtas 
253*13ea0450SMarcin Wojtas fail:
254*13ea0450SMarcin Wojtas 	while (digest_count--)
255*13ea0450SMarcin Wojtas 		xfree(digests[digest_count].data);
256*13ea0450SMarcin Wojtas 
257*13ea0450SMarcin Wojtas 	xfree(database);
258*13ea0450SMarcin Wojtas 	xfree(digests);
259*13ea0450SMarcin Wojtas 	return (NULL);
260*13ea0450SMarcin Wojtas }
261*13ea0450SMarcin Wojtas 
262*13ea0450SMarcin Wojtas /* Copy x509 certificates from db */
263*13ea0450SMarcin Wojtas br_x509_certificate*
efi_get_trusted_certs(size_t * count)264*13ea0450SMarcin Wojtas efi_get_trusted_certs(size_t *count)
265*13ea0450SMarcin Wojtas {
266*13ea0450SMarcin Wojtas 	return (efi_get_certs("db", count));
267*13ea0450SMarcin Wojtas }
268*13ea0450SMarcin Wojtas 
269*13ea0450SMarcin Wojtas /* Copy forbidden certificates from dbx */
270*13ea0450SMarcin Wojtas br_x509_certificate*
efi_get_forbidden_certs(size_t * count)271*13ea0450SMarcin Wojtas efi_get_forbidden_certs(size_t *count)
272*13ea0450SMarcin Wojtas {
273*13ea0450SMarcin Wojtas 	return (efi_get_certs("dbx", count));
274*13ea0450SMarcin Wojtas }
275