tpmstream icon indicating copy to clipboard operation
tpmstream copied to clipboard

Utility to convert swtpm logs to binary for use with tpmstream

Open HarryR opened this issue 1 year ago • 2 comments

Hi, I started writing my own tpm log parser to grok the output of https://github.com/stefanberger/swtpm debug logs, but then found yours which is very elegantly written and has saved me a load of time.

I'm ignoring the control commands as I can't find them in the TCG docs, and the '0x00C1' packet. Even though tpmstream can't parse the packet it could be skipped as the length of the packet in the header is correct, so could be skipped with a hex dump provided instead?

Unknown packet & response (first packet which occurs after command codes). When this is skipped everything else works fine:

 SWTPM_IO_Read: length 10
 00 C1 00 00 00 0A 00 00 00 F1 
 SWTPM_IO_Write: length 10
 80 01 00 00 00 0A 00 00 00 84 

Example swtpm command:

swtpm socket --tpmstate dir=`pwd`/.swtpm/ \
				 --ctrl type=unixio,path=`pwd`/.swtpm/tpm.sock \
				 --log level=40,file=`pwd`/.swtpm/log \
				 --tpm2 -d --pid file=`pwd`/.swtpm/tpm.pid

Example log file:

Ctrl Cmd: length 4
 00 00 00 10 
 Ctrl Rsp: length 4
 00 00 00 00 
 SWTPM_IO_Read: length 10
 80 01 00 00 00 0A 00 00 01 81 
 SWTPM_IO_Write: length 10
 80 01 00 00 00 0A 00 00 01 01 
 Ctrl Cmd: length 4
 00 00 00 01 
 Ctrl Rsp: length 8
 00 00 00 00 00 00 FF FF 
 Ctrl Cmd: length 4
 00 00 00 0E 
 Ctrl Rsp: length 4
 00 00 00 00 
 Ctrl Cmd: length 8
 00 00 00 11 00 00 00 00 
 Ctrl Rsp: length 16
 00 00 00 00 00 00 10 00 00 00 0A F8 00 00 10 00 
 Ctrl Cmd: length 4
 00 00 00 0E 
 Ctrl Rsp: length 4
 00 00 00 00 
 Ctrl Cmd: length 8
 00 00 00 11 00 00 10 00 
 Ctrl Rsp: length 16
 00 00 00 00 00 00 10 00 00 00 0A F8 00 00 10 00 
 Ctrl Cmd: length 8
 00 00 00 02 00 00 00 00 
 Ctrl Rsp: length 4
 00 00 00 00 
 Ctrl Cmd: length 4
 00 00 00 04 
 Ctrl Rsp: length 8
 00 00 00 00 00 00 00 00 
 Ctrl Cmd: length 8
 00 00 00 05 00 00 00 00 
 Ctrl Rsp: length 4
 00 00 00 00 
 SWTPM_IO_Read: length 10
 00 C1 00 00 00 0A 00 00 00 F1 
 SWTPM_IO_Write: length 10
 80 01 00 00 00 0A 00 00 00 84 
 SWTPM_IO_Read: length 12
 80 01 00 00 00 0C 00 00 01 44 00 00 
 SWTPM_IO_Write: length 10
 80 01 00 00 00 0A 00 00 00 00 
 SWTPM_IO_Read: length 22
 80 01 00 00 00 16 00 00 01 7A 00 00 00 05 00 00 
 00 00 00 00 00 01 
 SWTPM_IO_Write: length 43
 80 01 00 00 00 2B 00 00 00 00 00 00 00 00 05 00 
 00 00 04 00 04 03 FF FF FF 00 0B 03 FF FF FF 00 
 0C 03 FF FF FF 00 0D 03 FF FF FF 

The script:

#!/usr/bin/env python3
import sys

def parse_tpmlog(handle):
	skip = 0
	for line in handle:
		cmd, args = line.strip().split(':')
		args = args.strip(' ').split(' ')
		is_io = cmd in ('SWTPM_IO_Read', 'SWTPM_IO_Write')
		assert args[0] == 'length'
		length = int(args[1])
		toks = b''
		for line in handle:
			toks += bytes([int(_, 16) for _ in line.strip().split(' ')])
			if len(toks) >= length:
				break
		# This seems to be specific to QEMU & swtpm, it breaks tpmstream parsing
		if cmd == 'SWTPM_IO_Read' and toks[:2] == bytes([0x00, 0xc1]):
			skip = 2
		if is_io:
			if skip > 0:
				skip -= 1
			else:
				yield toks

def main(log_path, out_path):
	with open(log_path, 'r') as in_handle:
		with open(out_path, 'wb') as out_handle:
			for packet in parse_tpmlog(in_handle):
				out_handle.write(packet)
	return 0

if __name__ == "__main__":
	sys.exit(main(*sys.argv[1:]))

HarryR avatar Feb 27 '23 18:02 HarryR