diff --git a/tests/tlstest.py b/tests/tlstest.py index f88f3f26..657de6bd 100755 --- a/tests/tlstest.py +++ b/tests/tlstest.py @@ -2917,12 +2917,17 @@ def connect(): testConnServer(connection) connection.close() finally: - try: - os.remove(db_name) - except FileNotFoundError: - # dbm module may create files with different names depending on - # platform - os.remove(db_name + ".dat") + def quiet_remove(db_name): + try: + os.remove(db_name) + except OSError: + pass + + # dbm module may create files with different names depending on + # platform + candidates = [db_name, db_name + ".dat", db_name + ".db"] + for candidate in candidates: + quiet_remove(candidate) test_no += 1 diff --git a/tlslite/session.py b/tlslite/session.py index ede744ed..e137e981 100644 --- a/tlslite/session.py +++ b/tlslite/session.py @@ -112,7 +112,9 @@ def create(self, masterSecret, sessionID, cipherSuite, sr_app_secret=bytearray(0), exporterMasterSecret=bytearray(0), resumptionMasterSecret=bytearray(0), tickets=None, tls_1_0_tickets=None, ec_point_format=None, - delegated_credential=None): + delegated_credential=None, + cl_hs_traffic_secret=bytearray(0), + sr_hs_traffic_secret=bytearray(0)): self.masterSecret = masterSecret self.sessionID = sessionID self.cipherSuite = cipherSuite @@ -130,6 +132,8 @@ def create(self, masterSecret, sessionID, cipherSuite, self.sr_app_secret = sr_app_secret self.exporterMasterSecret = exporterMasterSecret self.resumptionMasterSecret = resumptionMasterSecret + self.cl_handshake_traffic_secret = cl_hs_traffic_secret + self.sr_handshake_traffic_secret = sr_hs_traffic_secret # NOTE we need a reference copy not a copy of object here! self.tickets = tickets self.tls_1_0_tickets = tls_1_0_tickets diff --git a/tlslite/sslkeylogging.py b/tlslite/sslkeylogging.py new file mode 100644 index 00000000..b65bd63b --- /dev/null +++ b/tlslite/sslkeylogging.py @@ -0,0 +1,76 @@ +import os +import sys +import threading +from .utils.compat import b2a_hex + + +def posix_lock_write(file_path, lines): + import fcntl + with open(file_path, 'a') as f: + fcntl.flock(f, fcntl.LOCK_EX) + try: + f.writelines(lines) + f.flush() + finally: + fcntl.flock(f, fcntl.LOCK_UN) + + +def unsafe_write(file_path, lines): + with open(file_path, 'a') as f: + f.writelines(lines) + f.flush() + + +class SSLKeyLogger: + """ + Write session secrets to the file pointed to by the SSLKEYLOGFILE + environment variable. Implemented to be thread-safe at the class level and + uses OS level file-locking. The file-locking implementation is a function + assigned to self.lock_write and determined by the value of sys.platform. + + Currently, POSIX is supported for thread and process safety. If enabled for + other systems, safety is not guaranteed. + + :param logfile_override: specify the filepath for logging + :type logfile_override: str + """ + _lock = threading.Lock() + + def __init__(self, logfile_override=None): + self.ssl_key_logfile = os.environ.get('SSLKEYLOGFILE') + if logfile_override: + self.ssl_key_logfile = logfile_override + self.platform = sys.platform + if self.platform in ['darwin', 'linux']: + self.lock_write = posix_lock_write + else: + self.lock_write = unsafe_write + + def log_session_keys(self, keys): + """ + Log session keys to the SSL key log file, if configured. + + Write session keys in the `SSLKEYLOGFILE` format, allowing tools like + Wireshark to decrypt captured traffic. Each entry is written as a line + with the format: ``