diff options
author | Philipp Hörist <philipp@hoerist.com> | 2023-11-07 00:19:58 +0300 |
---|---|---|
committer | Philipp Hörist <philipp@hoerist.com> | 2023-11-07 00:19:58 +0300 |
commit | 24d5889a333503e02bf4a0614ea9d823c25bc129 (patch) | |
tree | 9fa6b5ade1dc97205828c545aa79bdbc314cdca3 | |
parent | b679ed792d9b3df7bc68521953104fffa08e7d06 (diff) |
new: Websocket: Implement channel binding
-rw-r--r-- | nbxmpp/connection.py | 16 | ||||
-rw-r--r-- | nbxmpp/tcp.py | 39 | ||||
-rw-r--r-- | nbxmpp/websocket.py | 12 |
3 files changed, 35 insertions, 32 deletions
diff --git a/nbxmpp/connection.py b/nbxmpp/connection.py index e4f1d82..5a72c22 100644 --- a/nbxmpp/connection.py +++ b/nbxmpp/connection.py @@ -59,6 +59,7 @@ class Connection(Observable): self._state = None self._state = TCPState.DISCONNECTED + self._tls_con: Optional[Gio.TlsConnection] = None self._peer_certificate = None self._peer_certificate_errors = None @@ -71,14 +72,24 @@ class Connection(Observable): return None @property - def ciphersuite(self) -> Optional[int]: + def ciphersuite(self) -> Optional[str]: return None def get_channel_binding_data( self, type_: Gio.TlsChannelBindingType # pylint: disable=unused-argument ) -> Optional[bytes]: - return None + assert self._tls_con is not None + + try: + success, data = self._tls_con.get_channel_binding_data(type_) + except Exception as error: + self._log.warning('Unable to get channel binding data: %s', error) + return None + + if not success: + return None + return data @property def local_address(self): @@ -160,3 +171,4 @@ class Connection(Observable): self._peer_certificate = None self._client_cert = None self._address = None + self._tls_con = None diff --git a/nbxmpp/tcp.py b/nbxmpp/tcp.py index 4913a32..d44c071 100644 --- a/nbxmpp/tcp.py +++ b/nbxmpp/tcp.py @@ -66,44 +66,23 @@ class TCPConnection(Connection): @property def tls_version(self) -> Optional[int]: - if self._con is None: + if self._tls_con is None: return None if not min_version('GLib', '2.69.0'): return None - tls_con = self._con.get_base_io_stream() - return tls_con.get_protocol_version() + return self._tls_con.get_protocol_version() @property def ciphersuite(self) -> Optional[str]: - if self._con is None: + if self._tls_con is None: return None if not min_version('GLib', '2.69.0'): return None - tls_con = self._con.get_base_io_stream() - return tls_con.get_ciphersuite_name() - - def get_channel_binding_data( - self, - type_: Gio.TlsChannelBindingType - ) -> Optional[bytes]: - if self._con is None: - return None - - tls_con = self._con.get_base_io_stream() - - try: - success, data = tls_con.get_channel_binding_data(type_) - except Exception as error: - self._log.warning('Unable to get channel binding data: %s', error) - return None - - if not success: - return None - return data + return self._tls_con.get_ciphersuite_name() def connect(self): self.state = TCPState.CONNECTING @@ -216,16 +195,16 @@ class TCPConnection(Connection): identity = Gio.NetworkAddress.new(self._address.domain, remote_address.props.port) - tls_client = Gio.TlsClientConnection.new(self._con, identity) + self._tls_con = Gio.TlsClientConnection.new(self._con, identity) if self._address.type == ConnectionType.DIRECT_TLS: - tls_client.set_advertised_protocols(['xmpp-client']) - tls_client.connect('accept-certificate', self._check_certificate) - tls_client.connect('notify::peer-certificate', self._on_certificate_set) + self._tls_con.set_advertised_protocols(['xmpp-client']) + self._tls_con.connect('accept-certificate', self._check_certificate) + self._tls_con.connect('notify::peer-certificate', self._on_certificate_set) # This Wraps the Gio.TlsClientConnection and the Gio.Socket together # so we get back a Gio.SocketConnection - self._con = Gio.TcpWrapperConnection.new(tls_client, + self._con = Gio.TcpWrapperConnection.new(self._tls_con, self._con.get_socket()) def _read_async(self): diff --git a/nbxmpp/websocket.py b/nbxmpp/websocket.py index a3f8d82..a8e7f62 100644 --- a/nbxmpp/websocket.py +++ b/nbxmpp/websocket.py @@ -51,9 +51,11 @@ class WebsocketConnection(Connection): self.state = TCPState.CONNECTING message = Soup.Message.new('GET', self._address.uri) + assert message is not None message.connect('accept-certificate', self._check_certificate) message.connect('notify::tls-peer-certificate', self._on_certificate_set) + message.connect('network-event', self._on_network_event) message.set_flags(Soup.MessageFlags.NO_REDIRECT) self._session.websocket_connect_async(message, None, @@ -107,6 +109,16 @@ class WebsocketConnection(Connection): self._cancellable.cancel() return False + def _on_network_event( + self, + message: Soup.Message, + event: Gio.SocketClientEvent, + connection: Gio.TlsConnection + ) -> None: + + if event == Gio.SocketClientEvent.TLS_HANDSHAKED: + self._tls_con = connection + def _on_certificate_set(self, message, _param): if self._peer_certificate is not None: return |