4040from .utils .cipherfactory import createAESCCM , createAESCCM_8 , \
4141 createAESGCM , createCHACHA20
4242from .utils .compression import choose_compression_send_algo
43+ from .sslkeylogging import SSLKeyLogger
4344
4445class TLSConnection (TLSRecordLayer ):
4546 """
@@ -76,14 +77,20 @@ class TLSConnection(TLSRecordLayer):
7677 compression wasn't used then it is set to None.
7778 """
7879
79- def __init__ (self , sock ):
80+ def __init__ (self , sock , ssl_key_log_file = None ):
8081 """Create a new TLSConnection instance.
8182
8283 :param sock: The socket data will be transmitted on. The
8384 socket should already be connected. It may be in blocking or
8485 non-blocking mode.
8586
8687 :type sock: socket.socket
88+
89+ :param ssl_key_log_file: override location for logging session secrets.
90+ If not provided the filepath pointed to by the SSLKEYLOGFILE env
91+ variable will be used.
92+
93+ :type ssl_key_log_file: str
8794 """
8895 TLSRecordLayer .__init__ (self , sock )
8996 self .serverSigAlg = None
@@ -101,6 +108,7 @@ def __init__(self, sock):
101108 self ._pha_supported = False
102109 self .client_cert_compression_algo = None
103110 self .server_cert_compression_algo = None
111+ self .ssl_key_logger = SSLKeyLogger (ssl_key_log_file )
104112
105113 def keyingMaterialExporter (self , label , length = 20 ):
106114 """Return keying material as described in RFC 5705
@@ -414,7 +422,6 @@ def _handshakeClientAsync(self, srpParams=(), certParams=(), anonParams=(),
414422 session = None , settings = None , checker = None ,
415423 nextProtos = None , serverName = None , reqTack = True ,
416424 alpn = None ):
417-
418425 handshaker = self ._handshakeClientAsyncHelper (srpParams = srpParams ,
419426 certParams = certParams ,
420427 anonParams = anonParams ,
@@ -427,6 +434,12 @@ def _handshakeClientAsync(self, srpParams=(), certParams=(), anonParams=(),
427434 for result in self ._handshakeWrapperAsync (handshaker , checker ):
428435 yield result
429436
437+ # Log client random and master secret for version < TLS1.3
438+ if self .version < (3 , 4 ):
439+ self .ssl_key_logger .log_session_keys ([(
440+ 'CLIENT_RANDOM' , self ._clientRandom , self .session .masterSecret
441+ )])
442+
430443
431444 def _handshakeClientAsyncHelper (self , srpParams , certParams , anonParams ,
432445 session , settings , serverName , nextProtos ,
@@ -1323,6 +1336,14 @@ def _clientTLS13Handshake(self, settings, session, clientHello,
13231336 self ._handshake_hash ,
13241337 prfName )
13251338
1339+ # TLS1.3 log Client and Server traffic secrets for SSLKEYLOGFILE
1340+ self .ssl_key_logger .log_session_keys ([
1341+ ('CLIENT_HANDSHAKE_TRAFFIC_SECRET' ,
1342+ clientHello .random , cl_handshake_traffic_secret ),
1343+ ('SERVER_HANDSHAKE_TRAFFIC_SECRET' ,
1344+ clientHello .random , sr_handshake_traffic_secret )
1345+ ])
1346+
13261347 # prepare for reading encrypted messages
13271348 self ._recordLayer .calcTLS1_3PendingState (
13281349 serverHello .cipher_suite ,
@@ -1613,6 +1634,15 @@ def _clientTLS13Handshake(self, settings, session, clientHello,
16131634 bytearray (b'exp master' ),
16141635 self ._handshake_hash , prfName )
16151636
1637+
1638+ # Now that we have all the TLS1.3 secrets during the handshake,
1639+ # log them if necessary
1640+ self .ssl_key_logger .log_session_keys ([
1641+ ('EXPORTER_SECRET' , clientHello .random , exporter_master_secret ),
1642+ ('CLIENT_TRAFFIC_SECRET_0' , clientHello .random , cl_app_traffic ),
1643+ ('SERVER_TRAFFIC_SECRET_0' , clientHello .random , sr_app_traffic )
1644+ ])
1645+
16161646 self ._recordLayer .calcTLS1_3PendingState (
16171647 serverHello .cipher_suite ,
16181648 cl_app_traffic ,
@@ -1708,7 +1738,9 @@ def _clientTLS13Handshake(self, settings, session, clientHello,
17081738 exporterMasterSecret = exporter_master_secret ,
17091739 resumptionMasterSecret = resumption_master_secret ,
17101740 # NOTE it must be a reference, not a copy!
1711- tickets = self .tickets )
1741+ tickets = self .tickets ,
1742+ cl_hs_traffic_secret = cl_handshake_traffic_secret ,
1743+ sr_hs_traffic_secret = sr_handshake_traffic_secret )
17121744
17131745 yield "finished" if not resuming else "resumed_and_finished"
17141746
@@ -2250,6 +2282,12 @@ def handshakeServerAsync(self, verifierDB=None,
22502282 for result in self ._handshakeWrapperAsync (handshaker , checker ):
22512283 yield result
22522284
2285+ # Log client random and master secret for version < TLS1.3
2286+ if self .version < (3 , 4 ):
2287+ self .ssl_key_logger .log_session_keys ([(
2288+ 'CLIENT_RANDOM' , self ._clientRandom , self .session .masterSecret
2289+ )])
2290+
22532291
22542292 def _handshakeServerAsyncHelper (self , verifierDB ,
22552293 cert_chain , privateKey , reqCert ,
@@ -2956,6 +2994,15 @@ def _serverTLS13Handshake(self, settings, clientHello, cipherSuite,
29562994 bytearray (b'c hs traffic' ),
29572995 self ._handshake_hash ,
29582996 prf_name )
2997+
2998+ # TLS1.3 log Client and Server traffic secrets for SSLKEYLOGFILE
2999+ self .ssl_key_logger .log_session_keys ([
3000+ ('CLIENT_HANDSHAKE_TRAFFIC_SECRET' ,
3001+ clientHello .random , cl_handshake_traffic_secret ),
3002+ ('SERVER_HANDSHAKE_TRAFFIC_SECRET' ,
3003+ clientHello .random , sr_handshake_traffic_secret )
3004+ ])
3005+
29593006 self .version = version
29603007 self ._recordLayer .calcTLS1_3PendingState (
29613008 cipherSuite ,
@@ -3222,6 +3269,19 @@ def _serverTLS13Handshake(self, settings, clientHello, cipherSuite,
32223269 self ._handshake_hash ,
32233270 prf_name )
32243271
3272+
3273+ # Now that we have all the TLS1.3 secrets during the handshake,
3274+ # log them if necessary
3275+ self .ssl_key_logger .log_session_keys ([
3276+ ('EXPORTER_SECRET' ,
3277+ clientHello .random , exporter_master_secret ),
3278+ ('CLIENT_TRAFFIC_SECRET_0' ,
3279+ clientHello .random , cl_app_traffic ),
3280+ ('SERVER_TRAFFIC_SECRET_0' ,
3281+ clientHello .random , sr_app_traffic )
3282+ ])
3283+
3284+
32253285 # verify Finished of client
32263286 cl_finished_key = HKDF_expand_label (cl_handshake_traffic_secret ,
32273287 b"finished" , b'' ,
0 commit comments