x86: Added TXT measurement tool.
This commit is contained in:
parent
c94a88d436
commit
562e3279fd
13
Makefile
13
Makefile
|
@ -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) $<
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue