diff --git a/scapy/layers/tls/session.py b/scapy/layers/tls/session.py index de9f342bb46..3b00023dab2 100644 --- a/scapy/layers/tls/session.py +++ b/scapy/layers/tls/session.py @@ -30,51 +30,58 @@ from typing import Dict -def load_nss_keys(filename): +def parse_nss_keys(content): # type: (str) -> Dict[str, bytes] """ - Parses a NSS Keys log and returns unpacked keys in a dictionary. + Parses the content of a NSS Keys log and returns unpacked keys in a + dictionary. """ # http://udn.realityripple.com/docs/Mozilla/Projects/NSS/Key_Log_Format keys = collections.defaultdict(dict) + for line in content.splitlines(): + if line.startswith("#"): + continue + data = line.strip().split(" ") + if len(data) != 3 or data[0] != data[0].upper(): + warning("Invalid NSS Key Log Entry: %s", line.strip()) + return {} + + try: + client_random = binascii.unhexlify(data[1]) + except ValueError: + warning("Invalid ClientRandom: %s", data[1]) + return {} + + try: + secret = binascii.unhexlify(data[2]) + except ValueError: + warning("Invalid Secret: %s", data[2]) + return {} + + # Warn that a duplicated entry was detected. The latest one + # will be kept in the resulting dictionary. + if client_random in keys[data[0]]: + warning("Duplicated entry for %s !", data[0]) + + keys[data[0]][client_random] = secret + return keys + + +def load_nss_keys(filename): + # type: (str) -> Dict[str, bytes] + """ + Parses a NSS Keys log file and returns unpacked keys in a dictionary. + """ try: - fd = open(filename) - fd.close() + with open(filename) as fd: + content = fd.read() except FileNotFoundError: warning("Cannot open NSS Key Log: %s", filename) return {} - try: - with open(filename) as fd: - for line in fd: - if line.startswith("#"): - continue - data = line.strip().split(" ") - if len(data) != 3 or data[0] != data[0].upper(): - warning("Invalid NSS Key Log Entry: %s", line.strip()) - return {} - - try: - client_random = binascii.unhexlify(data[1]) - except ValueError: - warning("Invalid ClientRandom: %s", data[1]) - return {} - - try: - secret = binascii.unhexlify(data[2]) - except ValueError: - warning("Invalid Secret: %s", data[2]) - return {} - - # Warn that a duplicated entry was detected. The latest one - # will be kept in the resulting dictionary. - if client_random in keys[data[0]]: - warning("Duplicated entry for %s !", data[0]) - - keys[data[0]][client_random] = secret - return keys except UnicodeDecodeError as ex: warning("Cannot read NSS Key Log: %s %s", filename, str(ex)) return {} + return parse_nss_keys(content) # Note the following import may happen inside connState.__init__() diff --git a/scapy/utils.py b/scapy/utils.py index bed6049fe7c..45f1161e1bf 100644 --- a/scapy/utils.py +++ b/scapy/utils.py @@ -2003,15 +2003,12 @@ def _read_block_dsb(self, block, size): "the TLS layer is not loaded! Scapy won't be able " "to decrypt the packets.") else: - from scapy.layers.tls.session import load_nss_keys + from scapy.layers.tls.session import parse_nss_keys - # Write Key Log to a file and parse it - filename = get_temp_file() - with open(filename, "wb") as fd: - fd.write(secrets_data) - fd.close() - - keys = load_nss_keys(filename) + try: + keys = parse_nss_keys(secrets_data.decode()) + except UnicodeDecodeError: + keys = {} if not keys: warning("PcapNg: invalid TLS Key Log in DSB!") else: