#include <sys/cdefs.h>
#include <stand.h>
#include <string.h>
#include <efi.h>
#include <efilib.h>
#include <Uefi.h>
#include <Guid/ImageAuthentication.h>
#define NEED_BRSSL_H
#include "../libsecureboot-priv.h"
#include <brssl.h>
static EFI_GUID ImageSecurityDatabaseGUID = EFI_IMAGE_SECURITY_DATABASE_GUID;
static EFI_GUID efiCertX509GUID = EFI_CERT_X509_GUID;
static EFI_GUID efiCertX509Sha256GUID = EFI_CERT_X509_SHA256_GUID;
static EFI_GUID efiCertX509Sha384GUID = EFI_CERT_X509_SHA384_GUID;
static EFI_GUID efiCertX509Sha5122UID = EFI_CERT_X509_SHA512_GUID;
int
efi_secure_boot_enabled(void)
{
UINT8 SecureBoot;
UINT8 SetupMode;
size_t length;
EFI_STATUS status;
length = sizeof(SecureBoot);
status = efi_global_getenv("SecureBoot", &SecureBoot, &length);
if (status != EFI_SUCCESS) {
if (status == EFI_NOT_FOUND)
return (0);
printf("Failed to read \"SecureBoot\" variable\n");
return (-efi_status_to_errno(status));
}
length = sizeof(SetupMode);
status = efi_global_getenv("SetupMode", &SetupMode, &length);
if (status != EFI_SUCCESS)
SetupMode = 0;
printf(" SecureBoot: %d, SetupMode: %d\n", SecureBoot, SetupMode);
return (SecureBoot == 1 && SetupMode == 0);
}
static br_x509_certificate*
efi_get_certs(const char *name, size_t *count)
{
br_x509_certificate *certs;
UINT8 *database;
EFI_SIGNATURE_LIST *list;
EFI_SIGNATURE_DATA *entry;
size_t db_size;
ssize_t cert_count;
EFI_STATUS status;
database = NULL;
certs = NULL;
db_size = 0;
cert_count = 0;
status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
if (status != EFI_BUFFER_TOO_SMALL)
return (NULL);
database = malloc(db_size);
if (database == NULL)
return (NULL);
status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
if (status != EFI_SUCCESS)
goto fail;
for (list = (EFI_SIGNATURE_LIST*) database;
db_size >= list->SignatureListSize && db_size > 0;
db_size -= list->SignatureListSize,
list = (EFI_SIGNATURE_LIST*)
((UINT8*)list + list->SignatureListSize)) {
if (memcmp(&efiCertX509GUID,
&list->SignatureType,
sizeof(EFI_GUID)) != 0) {
continue;
}
entry = (EFI_SIGNATURE_DATA*)
((UINT8*)list +
sizeof(EFI_SIGNATURE_LIST) +
list->SignatureHeaderSize);
certs = realloc(certs,
(cert_count + 1) * sizeof(br_x509_certificate));
if (certs == NULL) {
cert_count = 0;
goto fail;
}
certs[cert_count].data_len = list->SignatureSize - sizeof(EFI_GUID);
certs[cert_count].data = malloc(certs[cert_count].data_len);
if (certs[cert_count].data == NULL)
goto fail;
memcpy(certs[cert_count].data,
entry->SignatureData,
certs[cert_count].data_len);
cert_count++;
}
*count = cert_count;
xfree(database);
return (certs);
fail:
free_certificates(certs, cert_count);
xfree(database);
return (NULL);
}
hash_data*
efi_get_forbidden_digests(size_t *count)
{
UINT8 *database;
hash_data *digests;
EFI_SIGNATURE_LIST *list;
EFI_SIGNATURE_DATA *entry;
size_t db_size, header_size, hash_size;
int digest_count, entry_count;
EFI_STATUS status;
db_size = 0;
digest_count = 0;
database = NULL;
digests = NULL;
status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
if (status != EFI_BUFFER_TOO_SMALL)
return (NULL);
database = malloc(db_size);
if (database == NULL)
return (NULL);
status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
if (status != EFI_SUCCESS)
goto fail;
for (list = (EFI_SIGNATURE_LIST*) database;
db_size >= list->SignatureListSize && db_size > 0;
db_size -= list->SignatureListSize,
list = (EFI_SIGNATURE_LIST*)
((UINT8*)list + list->SignatureListSize)) {
if (memcmp(&efiCertX509Sha256GUID, &list->SignatureType,
sizeof(EFI_GUID)) == 0) {
hash_size = br_sha256_SIZE;
} else if (memcmp(&efiCertX509Sha384GUID, &list->SignatureType,
sizeof(EFI_GUID)) == 0) {
hash_size = br_sha384_SIZE;
} else if (memcmp(&efiCertX509Sha5122UID, &list->SignatureType,
sizeof(EFI_GUID)) == 0) {
hash_size = br_sha512_SIZE;
} else {
continue;
}
header_size = sizeof(EFI_SIGNATURE_LIST) + list->SignatureHeaderSize;
entry_count = list->SignatureListSize - header_size;
entry_count /= list->SignatureSize;
entry = (EFI_SIGNATURE_DATA*)((UINT8*)list + header_size);
while (entry_count-- > 0) {
digests = realloc(digests,
(digest_count + 1) * sizeof(hash_data));
if (digests == NULL) {
digest_count = 0;
goto fail;
}
digests[digest_count].data = malloc(hash_size);
if (digests[digest_count].data == NULL)
goto fail;
memcpy(digests[digest_count].data,
entry->SignatureData,
hash_size);
digests[digest_count].hash_size = hash_size;
entry = (EFI_SIGNATURE_DATA*)(entry + list->SignatureSize);
digest_count++;
}
}
xfree(database);
if (count != NULL)
*count = digest_count;
return (digests);
fail:
while (digest_count--)
xfree(digests[digest_count].data);
xfree(database);
xfree(digests);
return (NULL);
}
br_x509_certificate*
efi_get_trusted_certs(size_t *count)
{
return (efi_get_certs("db", count));
}
br_x509_certificate*
efi_get_forbidden_certs(size_t *count)
{
return (efi_get_certs("dbx", count));
}