Skip to content

Commit 5fd8094

Browse files
committed
x86_fsp: add helper script to compute TPM PCR reg
1 parent 5331244 commit 5fd8094

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

tools/x86_fsp/compute_pcr.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"""
2+
Parse IFWI Image to compute initial PCR0 value as obtained by Intel Boot Guard
3+
"""
4+
import struct
5+
import argparse
6+
import hashlib
7+
import os
8+
import re
9+
import subprocess
10+
11+
FLASH_SIZE_IN_MB = 64
12+
13+
def off_to_addr(off: int, image_size : int = FLASH_SIZE_IN_MB*1024*1024) -> int:
14+
"""
15+
convert offset in the image to address in memory
16+
"""
17+
return (4 * 1024 * 1024 * 1024) - (image_size - off)
18+
19+
def addr_to_off(addr:int, image_size : int = FLASH_SIZE_IN_MB*1024*1024) -> int:
20+
"""
21+
convert address in memory to offset in the image
22+
"""
23+
return image_size - ((4 * 1024 * 1024 * 1024) - addr)
24+
25+
def get_sha256_hash(data: bytearray) -> bytearray:
26+
"""
27+
return the sha256 of data
28+
"""
29+
h = hashlib.sha256()
30+
h.update(data)
31+
return h.digest()
32+
33+
def get_config_value(config: str, name):
34+
"""
35+
Parse config to find line of type NAME=value, return value
36+
"""
37+
38+
pattern = rf'^{re.escape(name)}=(.*)$'
39+
matches = re.findall(pattern, config, re.MULTILINE)
40+
if matches:
41+
return matches[0].strip()
42+
return None
43+
44+
def get_sha256_hash_of_wolfboot_image(file_path: str):
45+
"""
46+
Get sha256 hash of wolfboot image at file_path
47+
"""
48+
HDR_OFF = 8
49+
WOLFBOOT_SHA_HDR = 0x03
50+
with open(file_path, 'rb') as f:
51+
data = f.read()
52+
data = data[HDR_OFF:]
53+
while True:
54+
if data[0] == 0xff:
55+
data = data[1:]
56+
continue
57+
t, l = struct.unpack('<HH', data[:4])
58+
if l == 0:
59+
return None
60+
if t == WOLFBOOT_SHA_HDR:
61+
return data[4:4+l]
62+
data = data[4+l:]
63+
64+
def get_keystore_sym_addr() -> int:
65+
"""
66+
get the address of symbol keystore from ELF file image
67+
"""
68+
symbols = subprocess.check_output(['nm', 'stage1/loader_stage1.elf']).split(b'\n')
69+
_start_keystore = int(list(filter(lambda x: b'_start_keystore' in x, symbols))[0].split(b' ')[0], 16)
70+
return _start_keystore
71+
72+
def pcr_extend(pcr: bytearray, data: bytearray) -> bytearray:
73+
"""
74+
get value of extend operation on pcr with data
75+
"""
76+
return get_sha256_hash(pcr + data)
77+
78+
if __name__ == '__main__':
79+
if os.path.exists('.config'):
80+
with open('.config', 'r', encoding='utf-8') as f:
81+
config = f.read()
82+
else:
83+
print("The file .config does not exist.")
84+
85+
parser = argparse.ArgumentParser()
86+
parser.add_argument('image_file', type=str, help='Path to the image file')
87+
parser.add_argument('--target', type=str, choices=['IBG', 'qemu'],
88+
default='IBG', help='Target platform')
89+
90+
args = parser.parse_args()
91+
image = bytes()
92+
93+
with open(args.image_file, 'rb') as f:
94+
image = bytearray(f.read())
95+
96+
pcr0 = bytearray(b'\x00'*32)
97+
if args.target == 'qemu':
98+
keystore_addr = get_keystore_sym_addr()
99+
keystore_off = addr_to_off(keystore_addr, image_size = len(image))
100+
ibb = image[keystore_off:]
101+
h = hashlib.sha256()
102+
h.update(ibb)
103+
pcr0_data_hash = h.digest()
104+
pcr0 = pcr_extend(b'\x00'*32, pcr0_data_hash)
105+
106+
print(f"Initial PCR0: {pcr0.hex()}")
107+
108+
is_stage1_auth_enabled = get_config_value(config, 'STAGE1_AUTH') == '1'
109+
print(f"stage1 auth is {'enabled' if is_stage1_auth_enabled else 'disabled'}")
110+
111+
if is_stage1_auth_enabled:
112+
fsp_s_hash = get_sha256_hash_of_wolfboot_image("src/x86/fsp_s_v1_signed.bin")
113+
pcr0 = pcr_extend(pcr0, fsp_s_hash)
114+
print(f"PCR0 after FSP_S: {pcr0.hex()}")
115+
116+
wb_hash = get_sha256_hash_of_wolfboot_image('stage1/wolfboot_raw_v1_signed.bin')
117+
pcr0 = pcr_extend(pcr0, wb_hash)
118+
print(f"PCR0 after wolfboot: {pcr0.hex()}")
119+
120+
# the pcrdigest needed by policy_sign tool is the hash of the concatenation of all PCRs involved in the policy.
121+
# we have only one PCR here
122+
pcr_digest = get_sha256_hash(pcr0)
123+
124+
print("PCR Policy (use with tpm/policy_sign with -pcrdigest arg)")
125+
print(pcr_digest.hex())

0 commit comments

Comments
 (0)