113ea0450SMarcin Wojtas /*-
213ea0450SMarcin Wojtas  * Copyright (c) 2019 Stormshield.
313ea0450SMarcin Wojtas  * Copyright (c) 2019 Semihalf.
413ea0450SMarcin Wojtas  *
513ea0450SMarcin Wojtas  * Redistribution and use in source and binary forms, with or without
613ea0450SMarcin Wojtas  * modification, are permitted provided that the following conditions
713ea0450SMarcin Wojtas  * are met:
813ea0450SMarcin Wojtas  * 1. Redistributions of source code must retain the above copyright
913ea0450SMarcin Wojtas  *    notice, this list of conditions and the following disclaimer.
1013ea0450SMarcin Wojtas  * 2. Redistributions in binary form must reproduce the above copyright
1113ea0450SMarcin Wojtas  *    notice, this list of conditions and the following disclaimer in the
1213ea0450SMarcin Wojtas  *    documentation and/or other materials provided with the distribution.
1313ea0450SMarcin Wojtas  *
1413ea0450SMarcin Wojtas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1513ea0450SMarcin Wojtas  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1613ea0450SMarcin Wojtas  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1713ea0450SMarcin Wojtas  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
1813ea0450SMarcin Wojtas  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1913ea0450SMarcin Wojtas  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2013ea0450SMarcin Wojtas  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2113ea0450SMarcin Wojtas  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2213ea0450SMarcin Wojtas  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2313ea0450SMarcin Wojtas  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2413ea0450SMarcin Wojtas  * POSSIBILITY OF SUCH DAMAGE.
2513ea0450SMarcin Wojtas  */
2613ea0450SMarcin Wojtas 
2713ea0450SMarcin Wojtas #include <sys/cdefs.h>
2813ea0450SMarcin Wojtas #include <stand.h>
2913ea0450SMarcin Wojtas #include <string.h>
3013ea0450SMarcin Wojtas 
3113ea0450SMarcin Wojtas #include <efi.h>
3213ea0450SMarcin Wojtas #include <efilib.h>
3313ea0450SMarcin Wojtas #include <Guid/ImageAuthentication.h>
3413ea0450SMarcin Wojtas 
3513ea0450SMarcin Wojtas #define NEED_BRSSL_H
3613ea0450SMarcin Wojtas #include "../libsecureboot-priv.h"
3713ea0450SMarcin Wojtas #include <brssl.h>
3813ea0450SMarcin Wojtas 
3913ea0450SMarcin Wojtas static EFI_GUID ImageSecurityDatabaseGUID = EFI_IMAGE_SECURITY_DATABASE_GUID;
4013ea0450SMarcin Wojtas 
4113ea0450SMarcin Wojtas static EFI_GUID efiCertX509GUID = EFI_CERT_X509_GUID;
4213ea0450SMarcin Wojtas static EFI_GUID efiCertX509Sha256GUID = EFI_CERT_X509_SHA256_GUID;
4313ea0450SMarcin Wojtas static EFI_GUID efiCertX509Sha384GUID = EFI_CERT_X509_SHA384_GUID;
4413ea0450SMarcin Wojtas static EFI_GUID efiCertX509Sha5122UID = EFI_CERT_X509_SHA512_GUID;
4513ea0450SMarcin Wojtas 
4613ea0450SMarcin Wojtas /*
4713ea0450SMarcin Wojtas  * Check if Secure Boot is enabled in firmware.
4813ea0450SMarcin Wojtas  * We evaluate two variables - Secure Boot and Setup Mode.
4913ea0450SMarcin Wojtas  * Secure Boot is enforced only if the first one equals 1 and the other 0.
5013ea0450SMarcin Wojtas  */
5113ea0450SMarcin Wojtas int
efi_secure_boot_enabled(void)5213ea0450SMarcin Wojtas efi_secure_boot_enabled(void)
5313ea0450SMarcin Wojtas {
5413ea0450SMarcin Wojtas 	UINT8 SecureBoot;
5513ea0450SMarcin Wojtas 	UINT8 SetupMode;
5613ea0450SMarcin Wojtas 	size_t length;
5713ea0450SMarcin Wojtas 	EFI_STATUS status;
5813ea0450SMarcin Wojtas 
5913ea0450SMarcin Wojtas 	length = sizeof(SecureBoot);
6013ea0450SMarcin Wojtas 	status = efi_global_getenv("SecureBoot", &SecureBoot, &length);
6113ea0450SMarcin Wojtas 	if (status != EFI_SUCCESS) {
6213ea0450SMarcin Wojtas 		if (status == EFI_NOT_FOUND)
6313ea0450SMarcin Wojtas 			return (0);
6413ea0450SMarcin Wojtas 
6513ea0450SMarcin Wojtas 		printf("Failed to read \"SecureBoot\" variable\n");
6613ea0450SMarcin Wojtas 		return (-efi_status_to_errno(status));
6713ea0450SMarcin Wojtas 	}
6813ea0450SMarcin Wojtas 
6913ea0450SMarcin Wojtas 	length = sizeof(SetupMode);
7013ea0450SMarcin Wojtas 	status = efi_global_getenv("SetupMode", &SetupMode, &length);
7113ea0450SMarcin Wojtas 	if (status != EFI_SUCCESS)
7213ea0450SMarcin Wojtas 		SetupMode = 0;
7313ea0450SMarcin Wojtas 
7413ea0450SMarcin Wojtas 	printf("   SecureBoot: %d, SetupMode: %d\n", SecureBoot, SetupMode);
7513ea0450SMarcin Wojtas 
7613ea0450SMarcin Wojtas 	return (SecureBoot == 1 && SetupMode == 0);
7713ea0450SMarcin Wojtas }
7813ea0450SMarcin Wojtas 
7913ea0450SMarcin Wojtas /*
8013ea0450SMarcin Wojtas  * Iterate through UEFI variable and extract X509 certificates from it.
8113ea0450SMarcin Wojtas  * The EFI_* structures and related guids are defined in UEFI standard.
8213ea0450SMarcin Wojtas  */
8313ea0450SMarcin Wojtas static br_x509_certificate*
efi_get_certs(const char * name,size_t * count)8413ea0450SMarcin Wojtas efi_get_certs(const char *name, size_t *count)
8513ea0450SMarcin Wojtas {
8613ea0450SMarcin Wojtas 	br_x509_certificate *certs;
8713ea0450SMarcin Wojtas 	UINT8 *database;
8813ea0450SMarcin Wojtas 	EFI_SIGNATURE_LIST *list;
8913ea0450SMarcin Wojtas 	EFI_SIGNATURE_DATA *entry;
9013ea0450SMarcin Wojtas 	size_t db_size;
9113ea0450SMarcin Wojtas 	ssize_t cert_count;
9213ea0450SMarcin Wojtas 	EFI_STATUS status;
9313ea0450SMarcin Wojtas 
9413ea0450SMarcin Wojtas 	database = NULL;
9513ea0450SMarcin Wojtas 	certs = NULL;
9613ea0450SMarcin Wojtas 	db_size = 0;
9713ea0450SMarcin Wojtas 	cert_count = 0;
9813ea0450SMarcin Wojtas 
9913ea0450SMarcin Wojtas 	/*
10013ea0450SMarcin Wojtas 	 * Read variable length and allocate memory for it
10113ea0450SMarcin Wojtas 	 */
10213ea0450SMarcin Wojtas 	status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
10313ea0450SMarcin Wojtas 	if (status != EFI_BUFFER_TOO_SMALL)
10413ea0450SMarcin Wojtas 		return (NULL);
10513ea0450SMarcin Wojtas 
10613ea0450SMarcin Wojtas 	database = malloc(db_size);
10713ea0450SMarcin Wojtas 	if (database == NULL)
10813ea0450SMarcin Wojtas 		return (NULL);
10913ea0450SMarcin Wojtas 
11013ea0450SMarcin Wojtas 	status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
11113ea0450SMarcin Wojtas 	if (status != EFI_SUCCESS)
11213ea0450SMarcin Wojtas 		goto fail;
11313ea0450SMarcin Wojtas 
11413ea0450SMarcin Wojtas 	for (list = (EFI_SIGNATURE_LIST*) database;
11513ea0450SMarcin Wojtas 	    db_size >= list->SignatureListSize && db_size > 0;
11613ea0450SMarcin Wojtas 	    db_size -= list->SignatureListSize,
11713ea0450SMarcin Wojtas 	    list = (EFI_SIGNATURE_LIST*)
11813ea0450SMarcin Wojtas 	    ((UINT8*)list + list->SignatureListSize)) {
11913ea0450SMarcin Wojtas 
12013ea0450SMarcin Wojtas 		/* We are only interested in entries containing X509 certs. */
12113ea0450SMarcin Wojtas 		if (memcmp(&efiCertX509GUID,
12213ea0450SMarcin Wojtas 		    &list->SignatureType,
12313ea0450SMarcin Wojtas 		    sizeof(EFI_GUID)) != 0) {
12413ea0450SMarcin Wojtas 			continue;
12513ea0450SMarcin Wojtas 		}
12613ea0450SMarcin Wojtas 
12713ea0450SMarcin Wojtas 		entry = (EFI_SIGNATURE_DATA*)
12813ea0450SMarcin Wojtas 		    ((UINT8*)list +
12913ea0450SMarcin Wojtas 		    sizeof(EFI_SIGNATURE_LIST) +
13013ea0450SMarcin Wojtas 		    list->SignatureHeaderSize);
13113ea0450SMarcin Wojtas 
13213ea0450SMarcin Wojtas 		certs = realloc(certs,
13313ea0450SMarcin Wojtas 		    (cert_count + 1) * sizeof(br_x509_certificate));
13413ea0450SMarcin Wojtas 		if (certs == NULL) {
13513ea0450SMarcin Wojtas 			cert_count = 0;
13613ea0450SMarcin Wojtas 			goto fail;
13713ea0450SMarcin Wojtas 		}
13813ea0450SMarcin Wojtas 
13913ea0450SMarcin Wojtas 		certs[cert_count].data_len = list->SignatureSize - sizeof(EFI_GUID);
14013ea0450SMarcin Wojtas 		certs[cert_count].data = malloc(certs[cert_count].data_len);
14113ea0450SMarcin Wojtas 		if (certs[cert_count].data == NULL)
14213ea0450SMarcin Wojtas 			goto fail;
14313ea0450SMarcin Wojtas 
14413ea0450SMarcin Wojtas 		memcpy(certs[cert_count].data,
14513ea0450SMarcin Wojtas 		    entry->SignatureData,
14613ea0450SMarcin Wojtas 		    certs[cert_count].data_len);
14713ea0450SMarcin Wojtas 
14813ea0450SMarcin Wojtas 		cert_count++;
14913ea0450SMarcin Wojtas 	}
15013ea0450SMarcin Wojtas 
15113ea0450SMarcin Wojtas 	*count = cert_count;
15213ea0450SMarcin Wojtas 
15313ea0450SMarcin Wojtas 	xfree(database);
15413ea0450SMarcin Wojtas 	return (certs);
15513ea0450SMarcin Wojtas 
15613ea0450SMarcin Wojtas fail:
15713ea0450SMarcin Wojtas 	free_certificates(certs, cert_count);
15813ea0450SMarcin Wojtas 	xfree(database);
15913ea0450SMarcin Wojtas 	return (NULL);
16013ea0450SMarcin Wojtas 
16113ea0450SMarcin Wojtas }
16213ea0450SMarcin Wojtas 
16313ea0450SMarcin Wojtas /*
16413ea0450SMarcin Wojtas  * Extract digests from UEFI "dbx" variable.
16513ea0450SMarcin Wojtas  * UEFI standard specifies three types of digest - sha256, sha386, sha512.
16613ea0450SMarcin Wojtas  */
16713ea0450SMarcin Wojtas hash_data*
efi_get_forbidden_digests(size_t * count)16813ea0450SMarcin Wojtas efi_get_forbidden_digests(size_t *count)
16913ea0450SMarcin Wojtas {
17013ea0450SMarcin Wojtas 	UINT8 *database;
17113ea0450SMarcin Wojtas 	hash_data *digests;
17213ea0450SMarcin Wojtas 	EFI_SIGNATURE_LIST *list;
17313ea0450SMarcin Wojtas 	EFI_SIGNATURE_DATA *entry;
17413ea0450SMarcin Wojtas 	size_t db_size, header_size, hash_size;
17513ea0450SMarcin Wojtas 	int digest_count, entry_count;
17613ea0450SMarcin Wojtas 	EFI_STATUS status;
17713ea0450SMarcin Wojtas 
17813ea0450SMarcin Wojtas 	db_size = 0;
17913ea0450SMarcin Wojtas 	digest_count = 0;
18013ea0450SMarcin Wojtas 	database = NULL;
18113ea0450SMarcin Wojtas 	digests = NULL;
18213ea0450SMarcin Wojtas 
18313ea0450SMarcin Wojtas 	status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
18413ea0450SMarcin Wojtas 	if (status != EFI_BUFFER_TOO_SMALL)
18513ea0450SMarcin Wojtas 		return (NULL);
18613ea0450SMarcin Wojtas 
18713ea0450SMarcin Wojtas 	database = malloc(db_size);
18813ea0450SMarcin Wojtas 	if (database == NULL)
18913ea0450SMarcin Wojtas 		return (NULL);
19013ea0450SMarcin Wojtas 
19113ea0450SMarcin Wojtas 	status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
19213ea0450SMarcin Wojtas 	if (status != EFI_SUCCESS)
19313ea0450SMarcin Wojtas 		goto fail;
19413ea0450SMarcin Wojtas 
19513ea0450SMarcin Wojtas 
19613ea0450SMarcin Wojtas 	for (list = (EFI_SIGNATURE_LIST*) database;
19713ea0450SMarcin Wojtas 	    db_size >= list->SignatureListSize && db_size > 0;
19813ea0450SMarcin Wojtas 	    db_size -= list->SignatureListSize,
19913ea0450SMarcin Wojtas 	    list = (EFI_SIGNATURE_LIST*)
20013ea0450SMarcin Wojtas 	    ((UINT8*)list + list->SignatureListSize)) {
20113ea0450SMarcin Wojtas 
20213ea0450SMarcin Wojtas 		/* We are only interested in entries that contain digests. */
20313ea0450SMarcin Wojtas 		if (memcmp(&efiCertX509Sha256GUID, &list->SignatureType,
20413ea0450SMarcin Wojtas 		    sizeof(EFI_GUID)) == 0) {
20513ea0450SMarcin Wojtas 			hash_size = br_sha256_SIZE;
20613ea0450SMarcin Wojtas 		} else if (memcmp(&efiCertX509Sha384GUID, &list->SignatureType,
20713ea0450SMarcin Wojtas 		    sizeof(EFI_GUID)) == 0) {
20813ea0450SMarcin Wojtas 			hash_size = br_sha384_SIZE;
20913ea0450SMarcin Wojtas 		} else if (memcmp(&efiCertX509Sha5122UID, &list->SignatureType,
21013ea0450SMarcin Wojtas 		    sizeof(EFI_GUID)) == 0) {
21113ea0450SMarcin Wojtas 			hash_size = br_sha512_SIZE;
21213ea0450SMarcin Wojtas 		} else {
21313ea0450SMarcin Wojtas 			continue;
21413ea0450SMarcin Wojtas 		}
21513ea0450SMarcin Wojtas 
21613ea0450SMarcin Wojtas 		/*
21713ea0450SMarcin Wojtas 		 * A single entry can have multiple digests
21813ea0450SMarcin Wojtas 		 * of the same type for some reason.
21913ea0450SMarcin Wojtas 		 */
22013ea0450SMarcin Wojtas 		header_size = sizeof(EFI_SIGNATURE_LIST) + list->SignatureHeaderSize;
22113ea0450SMarcin Wojtas 
22213ea0450SMarcin Wojtas 		/* Calculate the number of entries basing on structure size */
22313ea0450SMarcin Wojtas 		entry_count = list->SignatureListSize - header_size;
22413ea0450SMarcin Wojtas 		entry_count /= list->SignatureSize;
22513ea0450SMarcin Wojtas 		entry = (EFI_SIGNATURE_DATA*)((UINT8*)list + header_size);
22613ea0450SMarcin Wojtas 		while (entry_count-- > 0) {
22713ea0450SMarcin Wojtas 			digests = realloc(digests,
22813ea0450SMarcin Wojtas 			    (digest_count + 1) * sizeof(hash_data));
22913ea0450SMarcin Wojtas 			if (digests == NULL) {
23013ea0450SMarcin Wojtas 				digest_count = 0;
23113ea0450SMarcin Wojtas 				goto fail;
23213ea0450SMarcin Wojtas 			}
23313ea0450SMarcin Wojtas 
23413ea0450SMarcin Wojtas 			digests[digest_count].data = malloc(hash_size);
23513ea0450SMarcin Wojtas 			if (digests[digest_count].data == NULL)
23613ea0450SMarcin Wojtas 				goto fail;
23713ea0450SMarcin Wojtas 
23813ea0450SMarcin Wojtas 			memcpy(digests[digest_count].data,
23913ea0450SMarcin Wojtas 			    entry->SignatureData,
24013ea0450SMarcin Wojtas 			    hash_size);
24113ea0450SMarcin Wojtas 			digests[digest_count].hash_size = hash_size;
24213ea0450SMarcin Wojtas 
24313ea0450SMarcin Wojtas 			entry = (EFI_SIGNATURE_DATA*)(entry + list->SignatureSize);
24413ea0450SMarcin Wojtas 			digest_count++;
24513ea0450SMarcin Wojtas 		}
24613ea0450SMarcin Wojtas 	}
24713ea0450SMarcin Wojtas 	xfree(database);
24813ea0450SMarcin Wojtas 	if (count != NULL)
24913ea0450SMarcin Wojtas 		*count = digest_count;
25013ea0450SMarcin Wojtas 
25113ea0450SMarcin Wojtas 	return (digests);
25213ea0450SMarcin Wojtas 
25313ea0450SMarcin Wojtas fail:
25413ea0450SMarcin Wojtas 	while (digest_count--)
25513ea0450SMarcin Wojtas 		xfree(digests[digest_count].data);
25613ea0450SMarcin Wojtas 
25713ea0450SMarcin Wojtas 	xfree(database);
25813ea0450SMarcin Wojtas 	xfree(digests);
25913ea0450SMarcin Wojtas 	return (NULL);
26013ea0450SMarcin Wojtas }
26113ea0450SMarcin Wojtas 
26213ea0450SMarcin Wojtas /* Copy x509 certificates from db */
26313ea0450SMarcin Wojtas br_x509_certificate*
efi_get_trusted_certs(size_t * count)26413ea0450SMarcin Wojtas efi_get_trusted_certs(size_t *count)
26513ea0450SMarcin Wojtas {
26613ea0450SMarcin Wojtas 	return (efi_get_certs("db", count));
26713ea0450SMarcin Wojtas }
26813ea0450SMarcin Wojtas 
26913ea0450SMarcin Wojtas /* Copy forbidden certificates from dbx */
27013ea0450SMarcin Wojtas br_x509_certificate*
efi_get_forbidden_certs(size_t * count)27113ea0450SMarcin Wojtas efi_get_forbidden_certs(size_t *count)
27213ea0450SMarcin Wojtas {
27313ea0450SMarcin Wojtas 	return (efi_get_certs("dbx", count));
27413ea0450SMarcin Wojtas }
275