joholl / tpmstream

A tool to help you understand TPM commands and responses.
https://joholl.github.io/tpmstream-web
BSD 2-Clause "Simplified" License
27 stars 1 forks source link

Utility to convert swtpm logs to binary for use with tpmstream #7

Open HarryR opened 1 year ago

HarryR commented 1 year ago

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:]))
joholl commented 1 year ago

I'm ignoring the control commands as I can't find them in the TCG docs, and the '0x00C1' packet.

Naturally. They are not standardized, but swtpm-proprietary.

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?

Maybe support for these command could be added to tpmstream. That depends mainly if the format for swtpm (and perhaps also ibmtpm/mssim) is compatible with how tpmstream works under the hood. However, that format might change and break things.

Also, a switch --input-format is conceivable (or auto-recognizing it) where tpmstream supports "swtpm log format" alltogether. I'm cautious here, though. These types of logs are not intended to be parsed. This would break in the future, for sure.

A better option would be to add support for dumping raw TPM commands/responses in swtpm. Contrary to log files, that format is actually specified and stable. Then you could plug swtpm and tpmstream simply together using a pipe.

joholl commented 1 year ago

@HarryR Also, I forgot to mention that tpmstream can parse pcap. That is, you can export your traffic (or pipe it somehow) fromn wireshark as pcap and then have tpmstream parse it. Just use --in=pcapng or --in=auto.

berrange commented 2 weeks ago

FYI, in pull request #23 I implemented support for directly detecting & parsing swtpm's debug logs as a new data input format. I just skip over the swtpm control commands since they're not especially relevant.