summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/pcrlock/meson.build1
-rw-r--r--src/pcrlock/pcrlock.c2
-rw-r--r--src/pcrlock/pehash.c264
-rw-r--r--src/pcrlock/pehash.h11
-rw-r--r--src/shared/openssl-util.h1
-rw-r--r--src/shared/pe-binary.c268
-rw-r--r--src/shared/pe-binary.h7
7 files changed, 276 insertions, 278 deletions
diff --git a/src/pcrlock/meson.build b/src/pcrlock/meson.build
index a31b30bb15..8c8728a3a0 100644
--- a/src/pcrlock/meson.build
+++ b/src/pcrlock/meson.build
@@ -10,7 +10,6 @@ executables += [
'sources' : files(
'pcrlock.c',
'pcrlock-firmware.c',
- 'pehash.c',
),
'dependencies' : [
libm,
diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c
index c1915761ee..d824914ae7 100644
--- a/src/pcrlock/pcrlock.c
+++ b/src/pcrlock/pcrlock.c
@@ -40,7 +40,7 @@
#include "path-util.h"
#include "pcrextend-util.h"
#include "pcrlock-firmware.h"
-#include "pehash.h"
+#include "pe-binary.h"
#include "pretty-print.h"
#include "proc-cmdline.h"
#include "random-util.h"
diff --git a/src/pcrlock/pehash.c b/src/pcrlock/pehash.c
deleted file mode 100644
index 39ed61cc2e..0000000000
--- a/src/pcrlock/pehash.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "hexdecoct.h"
-#include "pe-binary.h"
-#include "pehash.h"
-#include "sort-util.h"
-#include "stat-util.h"
-#include "string-table.h"
-
-/* Implements:
- *
- * https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/authenticode_pe.docx
- * → Section "Calculating the PE Image Hash"
- */
-
-#define IMAGE_DATA_DIRECTORY_INDEX_CERTIFICATION_TABLE 4U
-
-static int hash_file(int fd, EVP_MD_CTX *md_ctx, uint64_t offset, uint64_t size) {
- uint8_t buffer[64*1024];
-
- log_debug("Hashing %" PRIu64 " @ %" PRIu64 " → %" PRIu64, size, offset, offset + size);
-
- while (size > 0) {
- size_t m = MIN(size, sizeof(buffer));
- ssize_t n;
-
- n = pread(fd, buffer, m, offset);
- if (n < 0)
- return log_debug_errno(errno, "Failed to read file for hashing: %m");
- if ((size_t) n != m)
- return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Short read while hashing.");
-
- if (EVP_DigestUpdate(md_ctx, buffer, m) != 1)
- return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
-
- offset += m;
- size -= m;
- }
-
- return 0;
-}
-
-static int section_offset_cmp(const IMAGE_SECTION_HEADER *a, const IMAGE_SECTION_HEADER *b) {
- return CMP(ASSERT_PTR(a)->PointerToRawData, ASSERT_PTR(b)->PointerToRawData);
-}
-
-int pe_hash(int fd,
- const EVP_MD *md,
- void **ret_hash,
- size_t *ret_hash_size) {
-
- _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *mdctx = NULL;
- _cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
- _cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
- _cleanup_free_ PeHeader *pe_header = NULL;
- const IMAGE_DATA_DIRECTORY *certificate_table;
- struct stat st;
- uint64_t p, q;
- int r;
-
- assert(fd >= 0);
- assert(md);
- assert(ret_hash_size);
- assert(ret_hash);
-
- if (fstat(fd, &st) < 0)
- return log_debug_errno(errno, "Failed to stat file: %m");
- r = stat_verify_regular(&st);
- if (r < 0)
- return log_debug_errno(r, "Not a regular file: %m");
-
- r = pe_load_headers(fd, &dos_header, &pe_header);
- if (r < 0)
- return r;
-
- r = pe_load_sections(fd, dos_header, pe_header, &sections);
- if (r < 0)
- return r;
-
- certificate_table = pe_header_get_data_directory(pe_header, IMAGE_DATA_DIRECTORY_INDEX_CERTIFICATION_TABLE);
- if (!certificate_table)
- return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "File lacks certificate table.");
-
- mdctx = EVP_MD_CTX_new();
- if (!mdctx)
- return log_oom_debug();
-
- if (EVP_DigestInit_ex(mdctx, md, NULL) != 1)
- return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to allocate message digest.");
-
- /* Everything from beginning of file to CheckSum field in PE header */
- p = (uint64_t) dos_header->e_lfanew +
- offsetof(PeHeader, optional.CheckSum);
- r = hash_file(fd, mdctx, 0, p);
- if (r < 0)
- return r;
- p += sizeof(le32_t);
-
- /* Everything between the CheckSum field and the Image Data Directory Entry for the Certification Table */
- q = (uint64_t) dos_header->e_lfanew +
- PE_HEADER_OPTIONAL_FIELD_OFFSET(pe_header, DataDirectory[IMAGE_DATA_DIRECTORY_INDEX_CERTIFICATION_TABLE]);
- r = hash_file(fd, mdctx, p, q - p);
- if (r < 0)
- return r;
- q += sizeof(IMAGE_DATA_DIRECTORY);
-
- /* The rest of the header + the section table */
- p = pe_header->optional.SizeOfHeaders;
- if (p < q)
- return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "SizeOfHeaders too short.");
- r = hash_file(fd, mdctx, q, p - q);
- if (r < 0)
- return r;
-
- /* Sort by location in file */
- typesafe_qsort(sections, pe_header->pe.NumberOfSections, section_offset_cmp);
-
- FOREACH_ARRAY(section, sections, pe_header->pe.NumberOfSections) {
- r = hash_file(fd, mdctx, section->PointerToRawData, section->SizeOfRawData);
- if (r < 0)
- return r;
-
- p += section->SizeOfRawData;
- }
-
- if ((uint64_t) st.st_size > p) {
-
- if (st.st_size - p < certificate_table->Size)
- return log_debug_errno(errno, "No space for certificate table, refusing.");
-
- r = hash_file(fd, mdctx, p, st.st_size - p - certificate_table->Size);
- if (r < 0)
- return r;
-
- /* If the file size is not a multiple of 8 bytes, pad the hash with zero bytes. */
- if (st.st_size % 8 != 0 && EVP_DigestUpdate(mdctx, (const uint8_t[8]) {}, 8 - (st.st_size % 8)) != 1)
- return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
- }
-
- int hsz = EVP_MD_CTX_size(mdctx);
- if (hsz < 0)
- return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get hash size.");
-
- unsigned hash_size = (unsigned) hsz;
- _cleanup_free_ void *hash = malloc(hsz);
- if (!hash)
- return log_oom_debug();
-
- if (EVP_DigestFinal_ex(mdctx, hash, &hash_size) != 1)
- return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to finalize hash function.");
-
- assert(hash_size == (unsigned) hsz);
-
- *ret_hash = TAKE_PTR(hash);
- *ret_hash_size = hash_size;
-
- return 0;
-}
-
-typedef void* SectionHashArray[_UNIFIED_SECTION_MAX];
-
-static void section_hash_array_done(SectionHashArray *array) {
- assert(array);
-
- for (size_t i = 0; i < _UNIFIED_SECTION_MAX; i++)
- free((*array)[i]);
-}
-
-int uki_hash(int fd,
- const EVP_MD *md,
- void* ret_hashes[static _UNIFIED_SECTION_MAX],
- size_t *ret_hash_size) {
-
- _cleanup_(section_hash_array_done) SectionHashArray hashes = {};
- _cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
- _cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
- _cleanup_free_ PeHeader *pe_header = NULL;
- int r;
-
- assert(fd >= 0);
- assert(ret_hashes);
- assert(ret_hash_size);
-
- r = pe_load_headers(fd, &dos_header, &pe_header);
- if (r < 0)
- return r;
-
- r = pe_load_sections(fd, dos_header, pe_header, &sections);
- if (r < 0)
- return r;
-
- int hsz = EVP_MD_size(md);
- if (hsz < 0)
- return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get hash size.");
-
- FOREACH_ARRAY(section, sections, pe_header->pe.NumberOfSections) {
- _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *mdctx = NULL;
- _cleanup_free_ char *n = NULL;
- ssize_t i;
-
- n = memdup_suffix0(section->Name, sizeof(section->Name));
- if (!n)
- return log_oom_debug();
-
- i = string_table_lookup(unified_sections, _UNIFIED_SECTION_MAX, n);
- if (i < 0)
- continue;
-
- if (hashes[i])
- return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Duplicate section");
-
- mdctx = EVP_MD_CTX_new();
- if (!mdctx)
- return log_oom_debug();
-
- if (EVP_DigestInit_ex(mdctx, md, NULL) != 1)
- return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to allocate message digest.");
-
- r = hash_file(fd, mdctx, section->PointerToRawData, MIN(section->VirtualSize, section->SizeOfRawData));
- if (r < 0)
- return r;
-
- if (section->SizeOfRawData < section->VirtualSize) {
- uint8_t zeroes[1024] = {};
- size_t remaining = section->VirtualSize - section->SizeOfRawData;
-
- while (remaining > 0) {
- size_t sz = MIN(sizeof(zeroes), remaining);
-
- if (EVP_DigestUpdate(mdctx, zeroes, sz) != 1)
- return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
-
- remaining -= sz;
- }
- }
-
- hashes[i] = malloc(hsz);
- if (!hashes[i])
- return log_oom_debug();
-
- unsigned hash_size = (unsigned) hsz;
- if (EVP_DigestFinal_ex(mdctx, hashes[i], &hash_size) != 1)
- return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to finalize hash function.");
-
- assert(hash_size == (unsigned) hsz);
-
- if (DEBUG_LOGGING) {
- _cleanup_free_ char *hs = NULL;
-
- hs = hexmem(hashes[i], hsz);
- log_debug("Section %s with %s is %s.", n, EVP_MD_name(md), strna(hs));
- }
- }
-
- memcpy(ret_hashes, hashes, sizeof(hashes));
- zero(hashes);
- *ret_hash_size = (unsigned) hsz;
-
- return 0;
-}
diff --git a/src/pcrlock/pehash.h b/src/pcrlock/pehash.h
deleted file mode 100644
index 26f2fb1e7b..0000000000
--- a/src/pcrlock/pehash.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <sys/types.h>
-
-#include "openssl-util.h"
-#include "uki.h"
-
-int pe_hash(int fd, const EVP_MD *md, void **ret_hash, size_t *ret_hash_size);
-
-int uki_hash(int fd, const EVP_MD *md, void *ret_hashes[static _UNIFIED_SECTION_MAX], size_t *ret_hash_size);
diff --git a/src/shared/openssl-util.h b/src/shared/openssl-util.h
index c9acd40f22..f70de86a09 100644
--- a/src/shared/openssl-util.h
+++ b/src/shared/openssl-util.h
@@ -140,6 +140,7 @@ int openssl_load_key_from_token(KeySourceType private_key_source_type, const cha
typedef struct X509 X509;
typedef struct EVP_PKEY EVP_PKEY;
+typedef struct EVP_MD EVP_MD;
typedef struct UI_METHOD UI_METHOD;
static inline void *X509_free(X509 *p) {
diff --git a/src/shared/pe-binary.c b/src/shared/pe-binary.c
index 3893ffaf97..60d0886d22 100644
--- a/src/shared/pe-binary.c
+++ b/src/shared/pe-binary.c
@@ -1,12 +1,18 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include <sys/stat.h>
#include <unistd.h>
#include "alloc-util.h"
+#include "hexdecoct.h"
#include "log.h"
#include "pe-binary.h"
+#include "sort-util.h"
+#include "stat-util.h"
+#include "string-table.h"
#include "string-util.h"
-#include "uki.h"
+
+#define IMAGE_DATA_DIRECTORY_INDEX_CERTIFICATION_TABLE 4U
bool pe_header_is_64bit(const PeHeader *h) {
assert(h);
@@ -284,3 +290,263 @@ bool pe_is_native(const PeHeader *pe_header) {
return false;
#endif
}
+
+/* Implements:
+ *
+ * https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/authenticode_pe.docx
+ * → Section "Calculating the PE Image Hash"
+ */
+
+#if HAVE_OPENSSL
+static int hash_file(int fd, EVP_MD_CTX *md_ctx, uint64_t offset, uint64_t size) {
+ uint8_t buffer[64*1024];
+
+ log_debug("Hashing %" PRIu64 " @ %" PRIu64 " → %" PRIu64, size, offset, offset + size);
+
+ while (size > 0) {
+ size_t m = MIN(size, sizeof(buffer));
+ ssize_t n;
+
+ n = pread(fd, buffer, m, offset);
+ if (n < 0)
+ return log_debug_errno(errno, "Failed to read file for hashing: %m");
+ if ((size_t) n != m)
+ return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Short read while hashing.");
+
+ if (EVP_DigestUpdate(md_ctx, buffer, m) != 1)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
+
+ offset += m;
+ size -= m;
+ }
+
+ return 0;
+}
+
+static int section_offset_cmp(const IMAGE_SECTION_HEADER *a, const IMAGE_SECTION_HEADER *b) {
+ return CMP(ASSERT_PTR(a)->PointerToRawData, ASSERT_PTR(b)->PointerToRawData);
+}
+#endif
+
+int pe_hash(int fd,
+ const EVP_MD *md,
+ void **ret_hash,
+ size_t *ret_hash_size) {
+#if HAVE_OPENSSL
+ _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *mdctx = NULL;
+ _cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
+ _cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
+ _cleanup_free_ PeHeader *pe_header = NULL;
+ const IMAGE_DATA_DIRECTORY *certificate_table;
+ struct stat st;
+ uint64_t p, q;
+ int r;
+
+ assert(fd >= 0);
+ assert(md);
+ assert(ret_hash_size);
+ assert(ret_hash);
+
+ if (fstat(fd, &st) < 0)
+ return log_debug_errno(errno, "Failed to stat file: %m");
+ r = stat_verify_regular(&st);
+ if (r < 0)
+ return log_debug_errno(r, "Not a regular file: %m");
+
+ r = pe_load_headers(fd, &dos_header, &pe_header);
+ if (r < 0)
+ return r;
+
+ r = pe_load_sections(fd, dos_header, pe_header, &sections);
+ if (r < 0)
+ return r;
+
+ certificate_table = pe_header_get_data_directory(pe_header, IMAGE_DATA_DIRECTORY_INDEX_CERTIFICATION_TABLE);
+ if (!certificate_table)
+ return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "File lacks certificate table.");
+
+ mdctx = EVP_MD_CTX_new();
+ if (!mdctx)
+ return log_oom_debug();
+
+ if (EVP_DigestInit_ex(mdctx, md, NULL) != 1)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to allocate message digest.");
+
+ /* Everything from beginning of file to CheckSum field in PE header */
+ p = (uint64_t) dos_header->e_lfanew +
+ offsetof(PeHeader, optional.CheckSum);
+ r = hash_file(fd, mdctx, 0, p);
+ if (r < 0)
+ return r;
+ p += sizeof(le32_t);
+
+ /* Everything between the CheckSum field and the Image Data Directory Entry for the Certification Table */
+ q = (uint64_t) dos_header->e_lfanew +
+ PE_HEADER_OPTIONAL_FIELD_OFFSET(pe_header, DataDirectory[IMAGE_DATA_DIRECTORY_INDEX_CERTIFICATION_TABLE]);
+ r = hash_file(fd, mdctx, p, q - p);
+ if (r < 0)
+ return r;
+ q += sizeof(IMAGE_DATA_DIRECTORY);
+
+ /* The rest of the header + the section table */
+ p = pe_header->optional.SizeOfHeaders;
+ if (p < q)
+ return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "SizeOfHeaders too short.");
+ r = hash_file(fd, mdctx, q, p - q);
+ if (r < 0)
+ return r;
+
+ /* Sort by location in file */
+ typesafe_qsort(sections, pe_header->pe.NumberOfSections, section_offset_cmp);
+
+ FOREACH_ARRAY(section, sections, pe_header->pe.NumberOfSections) {
+ r = hash_file(fd, mdctx, section->PointerToRawData, section->SizeOfRawData);
+ if (r < 0)
+ return r;
+
+ p += section->SizeOfRawData;
+ }
+
+ if ((uint64_t) st.st_size > p) {
+
+ if (st.st_size - p < certificate_table->Size)
+ return log_debug_errno(errno, "No space for certificate table, refusing.");
+
+ r = hash_file(fd, mdctx, p, st.st_size - p - certificate_table->Size);
+ if (r < 0)
+ return r;
+
+ /* If the file size is not a multiple of 8 bytes, pad the hash with zero bytes. */
+ if (st.st_size % 8 != 0 && EVP_DigestUpdate(mdctx, (const uint8_t[8]) {}, 8 - (st.st_size % 8)) != 1)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
+ }
+
+ int hsz = EVP_MD_CTX_size(mdctx);
+ if (hsz < 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get hash size.");
+
+ unsigned hash_size = (unsigned) hsz;
+ _cleanup_free_ void *hash = malloc(hsz);
+ if (!hash)
+ return log_oom_debug();
+
+ if (EVP_DigestFinal_ex(mdctx, hash, &hash_size) != 1)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to finalize hash function.");
+
+ assert(hash_size == (unsigned) hsz);
+
+ *ret_hash = TAKE_PTR(hash);
+ *ret_hash_size = hash_size;
+
+ return 0;
+#else
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot calculate PE hash.");
+#endif
+}
+
+#if HAVE_OPENSSL
+typedef void* SectionHashArray[_UNIFIED_SECTION_MAX];
+
+static void section_hash_array_done(SectionHashArray *array) {
+ assert(array);
+
+ for (size_t i = 0; i < _UNIFIED_SECTION_MAX; i++)
+ free((*array)[i]);
+}
+#endif
+
+int uki_hash(int fd,
+ const EVP_MD *md,
+ void* ret_hashes[static _UNIFIED_SECTION_MAX],
+ size_t *ret_hash_size) {
+#if HAVE_OPENSSL
+ _cleanup_(section_hash_array_done) SectionHashArray hashes = {};
+ _cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
+ _cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
+ _cleanup_free_ PeHeader *pe_header = NULL;
+ int r;
+
+ assert(fd >= 0);
+ assert(ret_hashes);
+ assert(ret_hash_size);
+
+ r = pe_load_headers(fd, &dos_header, &pe_header);
+ if (r < 0)
+ return r;
+
+ r = pe_load_sections(fd, dos_header, pe_header, &sections);
+ if (r < 0)
+ return r;
+
+ int hsz = EVP_MD_size(md);
+ if (hsz < 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get hash size.");
+
+ FOREACH_ARRAY(section, sections, pe_header->pe.NumberOfSections) {
+ _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *mdctx = NULL;
+ _cleanup_free_ char *n = NULL;
+ ssize_t i;
+
+ n = memdup_suffix0(section->Name, sizeof(section->Name));
+ if (!n)
+ return log_oom_debug();
+
+ i = string_table_lookup(unified_sections, _UNIFIED_SECTION_MAX, n);
+ if (i < 0)
+ continue;
+
+ if (hashes[i])
+ return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Duplicate section");
+
+ mdctx = EVP_MD_CTX_new();
+ if (!mdctx)
+ return log_oom_debug();
+
+ if (EVP_DigestInit_ex(mdctx, md, NULL) != 1)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to allocate message digest.");
+
+ r = hash_file(fd, mdctx, section->PointerToRawData, MIN(section->VirtualSize, section->SizeOfRawData));
+ if (r < 0)
+ return r;
+
+ if (section->SizeOfRawData < section->VirtualSize) {
+ uint8_t zeroes[1024] = {};
+ size_t remaining = section->VirtualSize - section->SizeOfRawData;
+
+ while (remaining > 0) {
+ size_t sz = MIN(sizeof(zeroes), remaining);
+
+ if (EVP_DigestUpdate(mdctx, zeroes, sz) != 1)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
+
+ remaining -= sz;
+ }
+ }
+
+ hashes[i] = malloc(hsz);
+ if (!hashes[i])
+ return log_oom_debug();
+
+ unsigned hash_size = (unsigned) hsz;
+ if (EVP_DigestFinal_ex(mdctx, hashes[i], &hash_size) != 1)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to finalize hash function.");
+
+ assert(hash_size == (unsigned) hsz);
+
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *hs = NULL;
+
+ hs = hexmem(hashes[i], hsz);
+ log_debug("Section %s with %s is %s.", n, EVP_MD_name(md), strna(hs));
+ }
+ }
+
+ memcpy(ret_hashes, hashes, sizeof(hashes));
+ zero(hashes);
+ *ret_hash_size = (unsigned) hsz;
+
+ return 0;
+#else
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot calculate UKI hash.");
+#endif
+}
diff --git a/src/shared/pe-binary.h b/src/shared/pe-binary.h
index f508989185..1b86b93c03 100644
--- a/src/shared/pe-binary.h
+++ b/src/shared/pe-binary.h
@@ -3,7 +3,10 @@
#include <sys/types.h>
+#include "openssl-util.h"
+#include "macro-fundamental.h"
#include "sparse-endian.h"
+#include "uki.h"
/* When naming things we try to stay close to the official Windows APIs as per:
* → https://learn.microsoft.com/en-us/windows/win32/debug/pe-format */
@@ -147,3 +150,7 @@ bool pe_is_uki(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections);
bool pe_is_addon(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections);
bool pe_is_native(const PeHeader *pe_header);
+
+int pe_hash(int fd, const EVP_MD *md, void **ret_hash, size_t *ret_hash_size);
+
+int uki_hash(int fd, const EVP_MD *md, void *ret_hashes[static _UNIFIED_SECTION_MAX], size_t *ret_hash_size);