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
39static EFI_GUID ImageSecurityDatabaseGUID = EFI_IMAGE_SECURITY_DATABASE_GUID;
40
41static EFI_GUID efiCertX509GUID = EFI_CERT_X509_GUID;
42static EFI_GUID efiCertX509Sha256GUID = EFI_CERT_X509_SHA256_GUID;
43static EFI_GUID efiCertX509Sha384GUID = EFI_CERT_X509_SHA384_GUID;
44static 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 */
51int
52efi_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 */
83static br_x509_certificate*
84efi_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
156fail:
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 */
167hash_data*
168efi_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
253fail:
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 */
263br_x509_certificate*
264efi_get_trusted_certs(size_t *count)
265{
266	return (efi_get_certs("db", count));
267}
268
269/* Copy forbidden certificates from dbx */
270br_x509_certificate*
271efi_get_forbidden_certs(size_t *count)
272{
273	return (efi_get_certs("dbx", count));
274}
275