Files
Gilles Peskine dd683324d8 Fix spurious match of data in DUMP_CHUNK_RE
If the data from `MBEDTLS_SSL_DEBUG_BUF` that's listed in text form after
the hex digits starts with two bytes that happen to be hex digits, this
could be interpreted as an extra pair of hex digits. Fix this.

Signed-off-by: Gilles Peskine <[email protected]>
2026-04-01 09:45:50 +02:00

94 lines
3.4 KiB
Python

"""Parse logs from ssl_client2 and ssl_server2."""
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
import re
from typing import Dict, Iterator, List, Pattern, Tuple
class Info:
"""Information gathered from a log of ssl_client2 or ssl_server2."""
PREFIX_RE_S = (r'(?P<filename>\S+):(?P<lineno>[0-9]+): +' +
r'\|(?P<level>[0-9]+)\|(?: (?P<address>\w+):)? +')
DUMPING_RE = re.compile(
PREFIX_RE_S +
r'dumping \'(?P<what>.*?)\' \((?P<length>[0-9]+) bytes\)')
DUMP_CHUNK_RE = re.compile(
PREFIX_RE_S +
r'[0-9a-f]+: *(?P<data>(?: [0-9a-f]{2}){1,16})')
VALUE_OF_RE = re.compile(
PREFIX_RE_S +
r'value of \'(?P<what>.*?)\' \((?P<length>[0-9]+) bits\)')
VALUE_CHUNK_RE = re.compile(
PREFIX_RE_S +
r'(?P<data>(?:[0-9a-f]{2}(?:$| )){1,16})')
def __init__(self) -> None:
"""Create an empty log info object."""
self.dumps = {} #type: Dict[str, List[str]]
def add_dump(self, name: str, hex_data: str) -> None:
"""Add a hex dump."""
self.dumps.setdefault(name, []).append(hex_data)
@staticmethod
def read_dump(filename: str,
lines: Iterator[Tuple[int, str]],
length: int, chunk_re: Pattern) -> str:
"""Read a hex dump. Return the hex data.
This method consumes the data dump lines from lines.
"""
acc = ''
remaining = length
while remaining > 0:
lineno, line = next(lines)
m = chunk_re.match(line)
if not m:
raise Exception(f'{filename}:{lineno}: not a dump chunk as expected')
acc += m.group('data')
remaining -= 16
plain = acc.replace(' ', '')
if len(plain) != length * 2:
raise Exception(f'{filename}:{lineno}: '
f'found {len(plain)} hex digits but expected {length * 2}')
return plain
def read_file_contents(self,
filename: str,
lines: Iterator[Tuple[int, str]]) -> None:
"""Read lines from a log file and store the information we find.
The iterator lines delivers a stream of lines with their line numbers.
"""
for _lineno, line in lines:
m = self.DUMPING_RE.match(line)
if m:
what = m.group('what')
hex_data = self.read_dump(filename, lines,
int(m.group('length')),
self.DUMP_CHUNK_RE)
self.add_dump(what, hex_data)
m = self.VALUE_OF_RE.match(line)
if m:
what = m.group('what')
n_bits = int(m.group('length'))
n_bytes = (n_bits + 7) // 8
hex_data = self.read_dump(filename, lines,
n_bytes, self.VALUE_CHUNK_RE)
self.add_dump(what, hex_data)
def read_file(self, filename: str) -> None:
"""Read a log file and store the information we find."""
with open(filename) as input_:
self.read_file_contents(filename, enumerate(input_, 1))
def parse_log_file(filename: str) -> Info:
"""Parse a log of ssl_client2 or ssl_server2."""
info = Info()
info.read_file(filename)
return info