x86: Added TXT measurement tool.

This commit is contained in:
Udo Steinberg 2023-06-09 23:14:29 +02:00
parent c94a88d436
commit 562e3279fd
2 changed files with 151 additions and 2 deletions

View File

@ -62,6 +62,7 @@ SRC := hypervisor.ld $(sort $(notdir $(foreach dir,$(SRC_DIR),$(wildcard $(dir)/
OBJ := $(patsubst %.ld,$(PAT_OBJ), $(patsubst %.S,$(PAT_OBJ), $(patsubst %.cpp,$(PAT_OBJ), $(SRC))))
OBJ_DEP := $(OBJ:%.o=%.d)
DIG := $(BLD_DIR)/digest
HYP := $(BLD_DIR)/$(ARCH)-nova
ELF := $(HYP).elf
BIN := $(HYP).bin
@ -165,6 +166,7 @@ Makefile.conf:
$(call message,CFG,$@)
@cp $@.example $@
$(DIG): $(MFL) | $(BLD_DIR) tool_hst_cc
$(OBJ): $(MFL) | $(BLD_DIR) tool_tgt_cc
# Zap old-fashioned suffixes
@ -174,12 +176,19 @@ $(OBJ): $(MFL) | $(BLD_DIR) tool_tgt_cc
clean:
$(call message,CLN,$@)
$(RM) $(OBJ) $(HYP) $(ELF) $(BIN) $(OBJ_DEP)
$(RM) $(DIG) $(OBJ) $(HYP) $(ELF) $(BIN) $(OBJ_DEP)
install: $(HYP)
install: $(HYP) | $(DIG)
$(call message,INS,$^ =\> $(INS_DIR))
$(INSTALL) $^ $(INS_DIR)
@$(TGT_SZ) $<
ifeq ($(ARCH),x86_64)
@echo Reference Integrity Measurements for $^
@echo $(shell $(DIG) $^ | sha1sum) "SHA1-160"
@echo $(shell $(DIG) $^ | sha256sum) "SHA2-256"
@echo $(shell $(DIG) $^ | sha384sum) "SHA2-384"
@echo $(shell $(DIG) $^ | sha512sum) "SHA2-512"
endif
run: $(ELF)
$(RUN) $<

140
cmd/digest.cpp Normal file
View File

@ -0,0 +1,140 @@
/*
* NOVA Integrity Measurement Tool for Intel TXT
*
* Copyright (C) 2019-2025 Udo Steinberg, BlueRock Security, Inc.
*
* This file is part of the NOVA microhypervisor.
*
* NOVA is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* NOVA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*/
#include <cstdint>
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
struct Mh final
{
uint64_t uuid[2];
uint32_t size, version, entry, first, mle_start, mle_end, mle_caps, cmd_start, cmd_end;
[[nodiscard]] bool valid() const
{
return uuid[0] == 0x74a7476f9082ac5a && uuid[1] == 0x42b651cba2555c0f && size == 52 && version == 0x20003;
}
};
struct Eh final
{
uint32_t ei_magic;
uint8_t ei_class, ei_data, ei_version, ei_osabi, ei_abiversion, ei_pad[7];
uint16_t type, machine;
uint32_t version;
uint64_t entry, ph_offset, sh_offset;
uint32_t flags;
uint16_t eh_size, ph_size, ph_count, sh_size, sh_count, strtab;
[[nodiscard]] bool valid() const
{
return ei_magic == 0x464c457f && ei_class == 2 && ei_data == 1 && ei_version == 1 && type == 2 && machine == 0x3e;
}
};
struct Ph final
{
uint32_t type, flags;
uint64_t f_offs, v_addr, p_addr, f_size, m_size, align;
};
int main (int argc, char **argv)
{
struct stat st;
if (argc < 2) {
std::cerr << "You must specify a file.\n";
return 1;
}
if (fstat (fileno (stdout), &st) == -1) {
perror ("fstat");
return 2;
}
if (!S_ISFIFO (st.st_mode)) {
std::cerr << "You must pipe the output through a hash program.\n";
return 3;
}
auto const fd { open (argv[1], O_RDONLY) };
if (fd == -1) {
perror ("open");
return 4;
}
if (fstat (fd, &st) == -1) {
perror ("fstat");
return 5;
}
auto const ptr { mmap (nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0) };
if (ptr == MAP_FAILED) {
perror ("mmap");
return 6;
}
close (fd);
auto const addr { reinterpret_cast<uintptr_t>(ptr) };
uint64_t size { 0 };
for (auto x { addr }; x < addr + st.st_size; x += sizeof (uint64_t)) {
auto const mh { reinterpret_cast<Mh const *>(x) };
if (mh->valid()) {
size = mh->mle_end - mh->mle_start;
break;
}
}
if (!size) {
std::cerr << "File is not an MLE.\n";
return 7;
}
auto const eh { reinterpret_cast<Eh const *>(addr) };
if (!eh->valid()) {
std::cerr << "File is not an ELF.\n";
return 8;
}
auto ph { reinterpret_cast<Ph const *>(addr + eh->ph_offset) };
for (auto c { eh->ph_count }; size && c--; ph++) {
if (ph->type != 1 || ph->f_size == 0)
continue;
auto const s { std::min (size, ph->f_size) };
if (fwrite (reinterpret_cast<void const *>(addr + ph->f_offs), s, 1, stdout) != 1) {
perror ("fwrite");
return 9;
}
size -= s;
}
return 0;
}