Philipp Hörist pushed to branch master at gajim / gajim
Commits: 3c312d13 by wurstsalat at 2022-11-26T12:09:58+00:00 change: Jingle: Remove XTLS support
XTLS has never been standardized, see https://datatracker.ietf.org/doc/html/draft-meyer-xmpp-e2e-encryption Gajim used this for file transfers, but there probably was no other client supporting this now obsolete feature. Today, using XEP-0396: Jingle Encrypted Transports - OMEMO would be the preferred solution.
Part of #11160
- - - - -
10 changed files:
- gajim/common/configpaths.py - gajim/common/const.py - gajim/common/jingle_content.py - gajim/common/jingle_ft.py - gajim/common/jingle_ftstates.py - − gajim/common/jingle_xtls.py - gajim/common/modules/bytestream.py - gajim/common/modules/jingle.py - gajim/common/socks5.py - − gajim/data/other/dh4096.pem
Changes:
===================================== gajim/common/configpaths.py ===================================== @@ -189,7 +189,6 @@ def init(self): unique_profile_paths = [ # Data paths ('SECRETS_FILE', 'secrets', PathLocation.DATA, PathType.FILE), - ('MY_PEER_CERTS', 'certs', PathLocation.DATA, PathType.FOLDER), ('CERT_STORE', 'cert_store', PathLocation.DATA, PathType.FOLDER), ('DEBUG', 'debug', PathLocation.DATA, PathType.FOLDER), ('PLUGINS_DATA', 'plugins_data', @@ -200,7 +199,6 @@ def init(self): ('CONFIG_FILE', 'config', PathLocation.CONFIG, PathType.FILE), ('PLUGINS_CONFIG_DIR', 'pluginsconfig', PathLocation.CONFIG, PathType.FOLDER), - ('MY_CERT', 'localcerts', PathLocation.CONFIG, PathType.FOLDER), ('MY_SHORTCUTS', 'shortcuts.json', PathLocation.CONFIG, PathType.FILE), ]
===================================== gajim/common/const.py ===================================== @@ -903,7 +903,6 @@ def is_active(self): Namespace.HASHES_BLAKE2B_512, Namespace.JINGLE, Namespace.JINGLE_FILE_TRANSFER_5, - Namespace.JINGLE_XTLS, Namespace.JINGLE_BYTESTREAM, Namespace.JINGLE_IBB, Namespace.AVATAR_METADATA + '+notify',
===================================== gajim/common/jingle_content.py ===================================== @@ -26,10 +26,7 @@ from nbxmpp.namespaces import Namespace
from gajim.common import app -from gajim.common import configpaths from gajim.common.file_props import FileProp -from gajim.common.jingle_xtls import SELF_SIGNED_CERTIFICATE -from gajim.common.jingle_xtls import load_cert_file
if TYPE_CHECKING: from gajim.common.jingle_transport import JingleTransport @@ -84,7 +81,6 @@ def __init__(self,
# These were found by the Politie self.file_props: Optional[FileProp] = None - self.use_security: Optional[bool] = None
self.callbacks: dict[str, list[Callable[ [nbxmpp.Node, nbxmpp.Node, Optional[nbxmpp.Node], str], @@ -267,22 +263,6 @@ def _fill_content(self, content: nbxmpp.Node) -> None: desc = file_tag.setTag('desc') if self.file_props.desc: desc.setData(self.file_props.desc) - if self.use_security: - security = nbxmpp.simplexml.Node( - tag=Namespace.JINGLE_XTLS + ' security') - certpath = configpaths.get('MY_CERT') - certpath = certpath / f'{SELF_SIGNED_CERTIFICATE}.cert' - cert = load_cert_file(certpath) - if cert: - digest_algo = (cert.get_signature_algorithm() - .decode('utf-8').split('With')[0]) - security.addChild('fingerprint').addData(cert.digest( - digest_algo).decode('utf-8')) - for m in ('x509', ): # supported authentication methods - method = nbxmpp.simplexml.Node(tag='method') - method.setAttr('name', m) - security.addChild(node=method) - content.addChild(node=security) content.addChild(node=description_node)
def destroy(self) -> None:
===================================== gajim/common/jingle_ft.py ===================================== @@ -33,8 +33,6 @@ from nbxmpp.namespaces import Namespace
from gajim.common import app -from gajim.common import configpaths -from gajim.common import jingle_xtls from gajim.common import helpers from gajim.common.const import KindConstant from gajim.common.helpers import AdditionalDataDict @@ -80,7 +78,6 @@ def __init__(self, session: JingleSession, file_props: FileProp, transport: Optional[JingleTransport] = None, - use_security: bool = False, senders: Optional[str] = None ) -> None:
@@ -102,8 +99,6 @@ def __init__(self, self.callbacks['transport-info'] += [self.__on_transport_info] self.callbacks['iq-result'] += [self.__on_iq_result]
- self.use_security = use_security - self.x509_fingerprint: Optional[str] = None self.file_props = file_props self.weinitiate = self.session.weinitiate self.werequest = self.session.werequest @@ -139,12 +134,6 @@ def __init__(self, State.CAND_SENT_AND_RECEIVED: StateCandSentAndRecv(self) }
- cert_name = (configpaths.get('MY_CERT') / - jingle_xtls.SELF_SIGNED_CERTIFICATE) - if not (cert_name.with_suffix('.cert').exists() and - cert_name.with_suffix('.pkey').exists()): - jingle_xtls.make_certs(cert_name, 'gajim') - def __state_changed(self, nextstate: State, args: Optional[dict[str, Any]] = None @@ -200,13 +189,6 @@ def _raise_event(self, if not content: return
- secu = content.getTag('security') - self.use_security = bool(secu) - if secu: - fingerprint = secu.getTag('fingerprint') - if fingerprint: - self.x509_fingerprint = fingerprint.getData() - if not self.transport: self.transport = JingleTransportSocks5() self.transport.set_our_jid(self.session.ourjid) @@ -333,26 +315,6 @@ def __on_session_accept(self, action: str ) -> None: log.info('__on_session_accept') - con = self.session.connection - security = content.getTag('security') - if not security: # responder can not verify our fingerprint - self.use_security = False - else: - fingerprint = security.getTag('fingerprint') - if fingerprint: - fingerprint = fingerprint.getData() - self.x509_fingerprint = fingerprint - if not jingle_xtls.check_cert(app.get_jid_without_resource( - self.session.responder), fingerprint): - id_ = jingle_xtls.send_cert_request(con, - self.session.responder) - jingle_xtls.key_exchange_pend(id_, - self.continue_session_accept, - [stanza]) - raise nbxmpp.NodeProcessed - self.continue_session_accept(stanza) - - def continue_session_accept(self, stanza: nbxmpp.Node) -> None: if self.state == State.TRANSPORT_REPLACE: # If we are requesting we don't have the file if self.session.werequest: @@ -371,16 +333,12 @@ def continue_session_accept(self, stanza: nbxmpp.Node) -> None: host['initiator'] = self.session.initiator host['target'] = self.session.responder host['sid'] = self.file_props.sid - fingerprint = None - if self.use_security: - fingerprint = 'client' if self.transport.type_ == TransportType.SOCKS5: sid = self.file_props.transport_sid app.socks5queue.connect_to_hosts(self.session.connection.name, sid, self.on_connect, self._on_connect_error, - fingerprint=fingerprint, receiving=False) raise nbxmpp.NodeProcessed self.__state_changed(State.TRANSFERRING) @@ -550,15 +508,11 @@ def _listen_host(self) -> None: receiver) self.file_props.sha_str = sha_str port = app.settings.get('file_transfers_port') - fingerprint = None - if self.use_security: - fingerprint = 'server' listener = app.socks5queue.start_listener( port, sha_str, self._store_socks5_sid, self.file_props, - fingerprint=fingerprint, typ='sender' if self.weinitiate else 'receiver') if not listener: # send error message, notify the user
===================================== gajim/common/jingle_ftstates.py ===================================== @@ -61,14 +61,11 @@ def action(self, args: Optional[dict[str, Any]] = None) -> None: self.jft._listen_host() # Listen on configured port for file transfer else: - fingerprint = None - if self.jft.use_security: - fingerprint = 'client' # Connect to the candidate host, on success call on_connect method app.socks5queue.connect_to_hosts( self.jft.session.connection.name, self.jft.file_props.transport_sid, self.jft.on_connect, - self.jft._on_connect_error, fingerprint=fingerprint) + self.jft._on_connect_error)
class StateCandSent(JingleFileTransferStates): @@ -211,13 +208,13 @@ def _start_sock5_transfer(self) -> None: app.socks5queue, _sock=None, host=str(streamhost_used['host']), port=int(streamhost_used['port']), - fingerprint=None, connected=False, + connected=False, file_props=self.jft.file_props) else: sockobj = Socks5ReceiverClient( app.idlequeue, streamhost_used, transport_sid=self.jft.file_props.transport_sid, - file_props=self.jft.file_props, fingerprint=None) + file_props=self.jft.file_props) sockobj.proxy = True sockobj.streamhost = streamhost_used app.socks5queue.add_sockobj(self.jft.session.connection.name,
===================================== gajim/common/jingle_xtls.py deleted ===================================== @@ -1,300 +0,0 @@ -# This file is part of Gajim. -# -# Gajim is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published -# by the Free Software Foundation; version 3 only. -# -# Gajim is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Gajim. If not, see http://www.gnu.org/licenses/. - -import logging -from pathlib import Path - -from OpenSSL import SSL, crypto - -import nbxmpp -from nbxmpp.namespaces import Namespace -from nbxmpp.util import generate_id -from gajim.common import app -from gajim.common import configpaths - -log = logging.getLogger('gajim.c.jingle_xtls') - -# key-exchange id -> [callback, args] -# accept that session once key-exchange completes -pending_contents = {} - - -def key_exchange_pend(id_, cb, args): - # args is a list - pending_contents[id_] = [cb, args] - - -def approve_pending_content(id_): - cb = pending_contents[id_][0] - args = pending_contents[id_][1] - cb(*args) - - -TYPE_RSA = crypto.TYPE_RSA -TYPE_DSA = crypto.TYPE_DSA - -SELF_SIGNED_CERTIFICATE = 'localcert' -DH_PARAMS = 'dh_params.pem' -DEFAULT_DH_PARAMS = 'dh4096.pem' - - -def default_callback(connection, certificate, error_num, depth, return_code): - log.info('certificate: %s', certificate) - return return_code - - -def load_cert_file(cert_path, cert_store=None): - ''' - This is almost identical to the one in nbxmpp.tls_nb - ''' - if not cert_path.is_file(): - return None - try: - f = open(cert_path, 'r', encoding='utf8') - except IOError as e: - log.warning('Unable to open certificate file %s: %s', cert_path, - str(e)) - return None - lines = f.readlines() - i = 0 - begin = -1 - for line in lines: - if 'BEGIN CERTIFICATE' in line: - begin = i - elif 'END CERTIFICATE' in line and begin > -1: - cert = ''.join(lines[begin:i + 2]) - try: - x509cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert) - if cert_store: - cert_store.add_cert(x509cert) - f.close() - return x509cert - except crypto.Error as exception_obj: - log.warning('Unable to load a certificate from file %s: %s', - cert_path, exception_obj.args[0][0][2]) - except Exception: - log.warning('Unknown error while loading certificate from file ' - '%s', cert_path) - begin = -1 - i += 1 - f.close() - - -def get_context(fingerprint, verify_cb=None, remote_jid=None): - ''' - constructs and returns the context objects - ''' - ctx = SSL.Context(SSL.SSLv23_METHOD) - flags = (SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3 | SSL.OP_SINGLE_DH_USE | - SSL.OP_NO_TICKET) - ctx.set_options(flags) - ctx.set_cipher_list(b'HIGH:!aNULL:!3DES') - - if fingerprint == 'server': # for testing purposes only - ctx.set_verify(SSL.VERIFY_NONE | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, - verify_cb or default_callback) - elif fingerprint == 'client': - ctx.set_verify(SSL.VERIFY_PEER, verify_cb or default_callback) - - cert_name = configpaths.get('MY_CERT') / SELF_SIGNED_CERTIFICATE - ctx.use_privatekey_file(str(cert_name.with_suffix('.pkey')).encode('utf-8')) - ctx.use_certificate_file( - str(cert_name.with_suffix('.cert')).encode('utf-8')) - - # Try to load Diffie-Hellman parameters. - # First try user DH parameters, if this fails load the default DH parameters - dh_params_name = configpaths.get('MY_CERT') / DH_PARAMS - try: - with open(dh_params_name, 'r', encoding='utf8'): - ctx.load_tmp_dh(dh_params_name.encode('utf-8')) - except FileNotFoundError: - default_dh_params_name = (configpaths.get('DATA') / 'other' / - DEFAULT_DH_PARAMS) - try: - with open(default_dh_params_name, 'r', encoding='utf8'): - ctx.load_tmp_dh(str(default_dh_params_name).encode('utf-8')) - except FileNotFoundError as err: - log.error('Unable to load default DH parameter file: %s, %s', - default_dh_params_name, err) - raise - - if remote_jid: - store = ctx.get_cert_store() - path = configpaths.get('MY_PEER_CERTS').expanduser() - path = path / f'{remote_jid}.cert' - if path.exists(): - load_cert_file(path, cert_store=store) - log.debug('certificate file %s loaded fingerprint %s', - path, fingerprint) - return ctx - - -def read_cert(certpath): - certificate = '' - with open(certpath, 'r', encoding='utf8') as certfile: - for line in certfile.readlines(): - if not line.startswith('-'): - certificate += line - return certificate - - -def send_cert(con, jid_from, sid): - certpath = configpaths.get('MY_CERT') / f'{SELF_SIGNED_CERTIFICATE}.cert' - certificate = read_cert(certpath) - iq = nbxmpp.Iq('result', to=jid_from) - iq.setAttr('id', sid) - - pubkey = iq.setTag('pubkeys') - pubkey.setNamespace(Namespace.PUBKEY_PUBKEY) - - keyinfo = pubkey.setTag('keyinfo') - name = keyinfo.setTag('name') - name.setData('CertificateHash') - cert = keyinfo.setTag('x509cert') - cert.setData(certificate) - - con.send(iq) - - -def handle_new_cert(con, obj, jid_from): - jid = app.get_jid_without_resource(jid_from) - certpath = configpaths.get('MY_PEER_CERTS').expanduser() / (jid + '.cert') - - id_ = obj.getAttr('id') - - x509cert = obj.getTag('pubkeys').getTag('keyinfo').getTag('x509cert') - - cert = x509cert.getData() - - f = open(certpath, 'w', encoding='utf8') - f.write('-----BEGIN CERTIFICATE-----\n') - f.write(cert) - f.write('-----END CERTIFICATE-----\n') - f.close() - - approve_pending_content(id_) - - -def check_cert(jid, fingerprint): - certpath = configpaths.get('MY_PEER_CERTS').expanduser() / (jid + '.cert') - if certpath.exists(): - cert = load_cert_file(certpath) - if cert: - digest_algo = cert.get_signature_algorithm() - digest_algo = digest_algo.decode('utf-8').split('With')[0] - if cert.digest(digest_algo) == fingerprint: - return True - return False - - -def send_cert_request(con, to_jid): - iq = nbxmpp.Iq('get', to=to_jid) - id_ = generate_id() - iq.setAttr('id', id_) - pubkey = iq.setTag('pubkeys') - pubkey.setNamespace(Namespace.PUBKEY_PUBKEY) - con.connection.send(iq) - return str(id_) - -# the following code is partly due to pyopenssl examples - - -def createKeyPair(type_, bits): - ''' - Create a public/private key pair. - - Arguments: type_ - Key type, must be one of TYPE_RSA and TYPE_DSA - bits - Number of bits to use in the key - Returns: The public/private key pair in a PKey object - ''' - pkey = crypto.PKey() - pkey.generate_key(type_, bits) - return pkey - - -def createCertRequest(pkey, digest='sha256', **name): - ''' - Create a certificate request. - - Arguments: pkey - The key to associate with the request - digest - Digestion method to use for signing, default is sha256 - **name - The name of the subject of the request, possible - arguments are: - C - Country name - ST - State or province name - L - Locality name - O - Organization name - OU - Organizational unit name - CN - Common name - emailAddress - E-mail address - Returns: The certificate request in an X509Req object - ''' - req = crypto.X509Req() - subj = req.get_subject() - - for (key, value) in name.items(): - setattr(subj, key, value) - - req.set_pubkey(pkey) - req.sign(pkey, digest) - return req - - -def createCertificate(req, issuerCert, issuerKey, serial, notBefore, notAfter, - digest='sha256'): - ''' - Generate a certificate given a certificate request. - - Arguments: req - Certificate request to use - issuerCert - The certificate of the issuer - issuerKey - The private key of the issuer - serial - Serial number for the certificate - notBefore - Timestamp (relative to now) when the certificate - starts being valid - notAfter - Timestamp (relative to now) when the certificate - stops being valid - digest - Digest method to use for signing, default is sha256 - Returns: The signed certificate in an X509 object - ''' - cert = crypto.X509() - cert.set_serial_number(serial) - cert.gmtime_adj_notBefore(notBefore) - cert.gmtime_adj_notAfter(notAfter) - cert.set_issuer(issuerCert.get_subject()) - cert.set_subject(req.get_subject()) - cert.set_pubkey(req.get_pubkey()) - cert.sign(issuerKey, digest) - return cert - - -def make_certs(filepath, CN): - ''' - make self signed certificates - filepath : absolute path of certificate file, will be appended the '.pkey' - and '.cert' extensions - CN : common name - ''' - key = createKeyPair(TYPE_RSA, 4096) - req = createCertRequest(key, CN=CN) - # five years - cert = createCertificate(req, req, key, 0, 0, 60 * 60 * 24 * 365 * 5) - with open(filepath.with_suffix('.pkey'), 'wb') as f: - filepath.with_suffix('.pkey').chmod(0o600) - f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key)) - with open(filepath.with_suffix('.cert'), 'wb') as f: - f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) - - -if __name__ == '__main__': - make_certs(Path('selfcert'), 'gajim')
===================================== gajim/common/modules/bytestream.py ===================================== @@ -43,7 +43,6 @@
from gajim.common import app from gajim.common import helpers -from gajim.common import jingle_xtls from gajim.common import types from gajim.common.events import FileRequestError from gajim.common.file_props import FileProp @@ -165,16 +164,6 @@ def send_file_approval(self, file_props: FileProp) -> None:
if not session.accepted: content = session.get_content('file', content.name) - if content.use_security: - fingerprint = content.x509_fingerprint - if not jingle_xtls.check_cert( - app.get_jid_without_resource(file_props.sender), - fingerprint): - id_ = jingle_xtls.send_cert_request( - self._con, file_props.sender) - jingle_xtls.key_exchange_pend(id_, - content.on_cert_received, []) - return session.approve_session()
session.approve_content('file', content.name) @@ -747,7 +736,6 @@ def _on_bytestream_result(self, _sock=None, host=str(proxy['host']), port=int(proxy['port']), - fingerprint=None, connected=False, file_props=file_props) sender.streamhost = proxy
===================================== gajim/common/modules/jingle.py ===================================== @@ -42,7 +42,6 @@ from nbxmpp.structs import IqProperties
from gajim.common import helpers -from gajim.common import jingle_xtls from gajim.common import types from gajim.common.file_props import FileProp from gajim.common.modules.base import BaseModule @@ -71,14 +70,6 @@ def __init__(self, con: types.Client) -> None: typ='set', ns=Namespace.JINGLE, callback=self._on_jingle_iq), - StanzaHandler(name='iq', - typ='get', - ns=Namespace.PUBKEY_PUBKEY, - callback=self._on_pubkey_request), - StanzaHandler(name='iq', - typ='result', - ns=Namespace.PUBKEY_PUBKEY, - callback=self._pubkey_result_received), ]
# dictionary: sessionid => JingleSession object @@ -100,26 +91,6 @@ def delete_jingle_session(self, sid: str) -> None: self._sessions[sid].callbacks = [] del self._sessions[sid]
- def _on_pubkey_request(self, - con: types.xmppClient, - stanza: Iq, - _properties: IqProperties - ) -> None: - jid_from = helpers.get_full_jid_from_iq(stanza) - self._log.info('Pubkey request from %s', jid_from) - sid = stanza.getAttr('id') - jingle_xtls.send_cert(con, jid_from, sid) - raise nbxmpp.NodeProcessed - - def _pubkey_result_received(self, - con: types.xmppClient, - stanza: Iq, - _properties: IqProperties - ) -> None: - jid_from = helpers.get_full_jid_from_iq(stanza) - self._log.info('Pubkey result from %s', jid_from) - jingle_xtls.handle_new_cert(con, stanza, jid_from) - def _on_jingle_iq(self, _con: types.xmppClient, stanza: Iq, @@ -236,7 +207,6 @@ def start_file_transfer(self, ) -> Optional[str]: logger.info('start file transfer with file: %s', file_props) contact = self._con.get_module('Contacts').get_contact(jid) - use_security = contact.supports(Namespace.JINGLE_XTLS) jingle = JingleSession(self._con, weinitiate=True, jid=jid, @@ -261,7 +231,6 @@ def start_file_transfer(self, transfer = JingleFileTransfer(jingle, transport=transport, file_props=file_props, - use_security=use_security, senders=senders) file_props.transport_sid = transport.sid file_props.algo = self.__hash_support(contact)
===================================== gajim/common/socks5.py ===================================== @@ -33,11 +33,9 @@ from errno import EAFNOSUPPORT
from nbxmpp.idlequeue import IdleObject -import OpenSSL
from gajim.common.file_props import FilesProp from gajim.common import app -from gajim.common import jingle_xtls
log = logging.getLogger('gajim.c.socks5') MAX_BUFF_LEN = 65536 @@ -77,7 +75,7 @@ def __init__(self, idlequeue, complete_transfer_cb=None, self.on_failure = {} # {id: cb}
def start_listener(self, port, sha_str, sha_handler, file_props, - fingerprint=None, typ='sender'): + typ='sender'): """ Start waiting for incoming connections on (host, port) and do a socks5 authentication using sid for generated SHA @@ -86,8 +84,7 @@ def start_listener(self, port, sha_str, sha_handler, file_props, sid = file_props.sid self.sha_handlers[sha_str] = (sha_handler, sid) if self.listener is None or not self.listener.connections: - self.listener = Socks5Listener(self.idlequeue, port, file_props, - fingerprint=fingerprint) + self.listener = Socks5Listener(self.idlequeue, port, file_props) self.listener.queue = self self.listener.bind() else: @@ -113,7 +110,7 @@ def send_success_reply(self, file_props, streamhost): return 1
def connect_to_hosts(self, account, transport_sid, on_success=None, - on_failure=None, fingerprint=None, receiving=True): + on_failure=None, receiving=True): self.on_success[transport_sid] = on_success self.on_failure[transport_sid] = on_failure file_props = FilesProp.getFilePropByTransportSid(account, transport_sid) @@ -128,10 +125,6 @@ def connect_to_hosts(self, account, transport_sid, on_success=None, on_failure(file_props.transport_sid) # add streamhosts to the queue for streamhost in streamhosts_to_test: - if 'type' in streamhost and streamhost['type'] == 'proxy': - fp = None - else: - fp = fingerprint if receiving: if 'candidate_id' in streamhost: log.debug('Trying to connect as receiver to cid %s', @@ -141,7 +134,7 @@ def connect_to_hosts(self, account, transport_sid, on_success=None, streamhost['jid']) file_props.type_ = 'r' socks5obj = Socks5ReceiverClient(self.idlequeue, streamhost, - transport_sid, file_props, fingerprint=fp) + transport_sid, file_props) self.add_sockobj(account, socks5obj) else: if 'candidate_id' in streamhost: @@ -162,7 +155,7 @@ def connect_to_hosts(self, account, transport_sid, on_success=None, file_props.proxy_receiver = streamhost['initiator'] socks5obj = Socks5SenderClient(self.idlequeue, idx, self, _sock=None, host=str(streamhost['host']), - port=int(streamhost['port']), fingerprint=fp, + port=int(streamhost['port']), connected=False, file_props=file_props, initiator=streamhost['initiator'], target=streamhost['target']) @@ -345,7 +338,7 @@ def on_connection_accepted(self, sock, listener): if listener.file_props.type_ == 's' and \ not self.isHashInSockObjs(self.senders, sock_hash): sockobj = Socks5SenderServer(self.idlequeue, sock_hash, self, - sock[0], sock[1][0], sock[1][1], fingerprint=None, + sock[0], sock[1][0], sock[1][1], file_props=listener.file_props) self._add(sockobj, self.senders, listener.file_props, sock_hash) # Start waiting for data @@ -360,7 +353,7 @@ def on_connection_accepted(self, sock, listener): sh['target'] = None sockobj = Socks5ReceiverServer(idlequeue=self.idlequeue, streamhost=sh, transport_sid=None, - file_props=listener.file_props, fingerprint=None) + file_props=listener.file_props)
self._add(sockobj, self.readers, listener.file_props, sock_hash) sockobj.set_sock(sock[0]) @@ -477,20 +470,12 @@ def __init__(self, idlequeue, host, port, initiator, target, sid): self.file = None self.connected = False self.mode = '' - self.ssl_cert = None - self.ssl_errnum = 0
def _is_connected(self): if self.state < 5: return False return True
- def ssl_verify_cb(self, ssl_conn, cert, error_num, depth, return_code): - if depth == 0: - self.ssl_cert = cert - self.ssl_errnum = error_num - return True - def connect(self): """ Create the socket and plug it to the idlequeue @@ -500,17 +485,6 @@ def connect(self): for ai in self.ais: try: self._sock = socket.socket(*ai[:3]) - if self.fingerprint is not None: - if self.file_props.type_ == 's': - remote_jid = app.get_jid_without_resource( - self.file_props.receiver) - else: - remote_jid = app.get_jid_without_resource( - self.file_props.sender) - self._sock = OpenSSL.SSL.Connection( - jingle_xtls.get_context('client', - verify_cb=self.ssl_verify_cb, remote_jid=remote_jid), - self._sock) # this will not block the GUI self._sock.setblocking(False) self._server = ai[4] @@ -532,8 +506,6 @@ def do_connect(self): self._sock.connect(self._server) self._send = self._sock.send self._recv = self._sock.recv - except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError): - pass except Exception as ee: errnum = ee.errno self.connect_timeout += 1 @@ -642,10 +614,6 @@ def receive(self): received = b'' try: add = self._recv(64) - except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError, - OpenSSL.SSL.WantX509LookupError) as e: - log.info('SSL rehandshake request: %s', repr(e)) - raise e except Exception: add = b'' received += add @@ -659,10 +627,6 @@ def send_raw(self, raw_data): """ try: self._send(raw_data) - except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError, - OpenSSL.SSL.WantX509LookupError) as e: - log.info('SSL rehandshake request: %s', repr(e)) - raise e except Exception: self.disconnect() return len(raw_data) @@ -683,13 +647,6 @@ def write_next(self): lenn = 0 try: lenn = self._send(buff) - except (OpenSSL.SSL.WantReadError, - OpenSSL.SSL.WantWriteError, - OpenSSL.SSL.WantX509LookupError) as err: - log.info('SSL rehandshake request: %s', repr(err)) - raise err - except OpenSSL.SSL.SysCallError: - return self._on_send_exception() except socket.error as err: if err.errno not in (EINTR, ENOBUFS, EWOULDBLOCK): return self._on_send_exception() @@ -767,10 +724,6 @@ def get_file_contents(self, timeout): return 0 try: buff = self._recv(MAX_BUFF_LEN) - except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError, - OpenSSL.SSL.WantX509LookupError) as e: - log.info('SSL rehandshake request: %s', repr(e)) - raise e except Exception: buff = b'' current_time = time.time() @@ -825,10 +778,7 @@ def disconnect(self, *args, **kwargs): if self.queue.listener.connections == []: self.queue.listener.disconnect() try: - if isinstance(self._sock, OpenSSL.SSL.Connection): - self._sock.shutdown() - else: - self._sock.shutdown(socket.SHUT_RDWR) + self._sock.shutdown(socket.SHUT_RDWR) self._sock.close() except Exception: # socket is already closed @@ -905,12 +855,7 @@ def read_connect(self): """ Connect response: version, auth method """ - try: - buff = self._recv().decode('utf-8') - except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError, - OpenSSL.SSL.WantX509LookupError) as e: - log.info("SSL rehandshake request: %s", repr(e)) - raise e + buff = self._recv().decode('utf-8') try: version, method = struct.unpack('!BB', buff) except Exception: @@ -943,21 +888,15 @@ class Socks5Sender(IdleObject): Class for sending file to socket over socks5 """ def __init__(self, idlequeue, sock_hash, parent, _sock, host=None, - port=None, fingerprint=None, connected=True, file_props=None): + port=None, connected=True, file_props=None): IdleObject.__init__(self) - self.fingerprint = fingerprint self.queue_idx = sock_hash self.queue = parent self.file_props = file_props self.proxy = False self._sock = _sock if _sock is not None: - if self.fingerprint is not None and not isinstance(self._sock, - OpenSSL.SSL.Connection): - self._sock = OpenSSL.SSL.Connection( - jingle_xtls.get_context('server'), _sock) - else: - self._sock.setblocking(False) + self._sock.setblocking(False) self.fd = _sock.fileno() self._recv = _sock.recv self._send = _sock.send @@ -985,11 +924,7 @@ def start_transfer(self):
def set_connection_sock(self, _sock): self._sock = _sock - if self.fingerprint is not None: - self._sock = OpenSSL.SSL.Connection( - jingle_xtls.get_context('client'), _sock) - else: - self._sock.setblocking(False) + self._sock.setblocking(False) self.fd = _sock.fileno() self._recv = _sock.recv self._send = _sock.send @@ -1023,17 +958,11 @@ def disconnect(self, cb=True):
class Socks5Receiver(IdleObject): - def __init__(self, idlequeue, streamhost, sid, file_props=None, - fingerprint=None): - """ - fingerprint: fingerprint of certificates we shall use, set to None if - TLS connection not desired - """ + def __init__(self, idlequeue, streamhost, sid, file_props=None): IdleObject.__init__(self) self.queue_idx = -1 self.streamhost = streamhost self.queue = None - self.fingerprint = fingerprint self.connect_timeout = 0 self.connected = False self.pauses = 0 @@ -1129,36 +1058,31 @@ def main(self): def pollin(self): self.idlequeue.remove_timeout(self.fd) if self.connected: - try: - if self.state < 5: - result = self.main() - if self.state == 4: - self.queue.result_sha(self.sha_msg, self.queue_idx) - if result == -1: - self.disconnect() - elif self.state == 5: - self.state = 7 - if self.file_props.type_ == 's': - # We wait for the end of the negotiation to - # send the file - self.idlequeue.plug_idle(self, False, False) - else: - # We plug for reading - self.idlequeue.plug_idle(self, False, True) - return - elif self.state == 7: - if self.file_props.paused: - self.file_props.continue_cb = \ - self.continue_paused_transfer - self.idlequeue.plug_idle(self, False, False) - return - self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) - result = self.start_transfer() # send - self.queue.process_result(result, self) - except (OpenSSL.SSL.WantReadError, - OpenSSL.SSL.WantWriteError, - OpenSSL.SSL.WantX509LookupError): - log.info('caught SSL exception, ignored') + if self.state < 5: + result = self.main() + if self.state == 4: + self.queue.result_sha(self.sha_msg, self.queue_idx) + if result == -1: + self.disconnect() + elif self.state == 5: + self.state = 7 + if self.file_props.type_ == 's': + # We wait for the end of the negotiation to + # send the file + self.idlequeue.plug_idle(self, False, False) + else: + # We plug for reading + self.idlequeue.plug_idle(self, False, True) + return + elif self.state == 7: + if self.file_props.paused: + self.file_props.continue_cb = \ + self.continue_paused_transfer + self.idlequeue.plug_idle(self, False, False) + return + self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) + result = self.start_transfer() # send + self.queue.process_result(result, self) else: self.disconnect()
@@ -1173,32 +1097,26 @@ def pollout(self): self.disconnect() return self.idlequeue.remove_timeout(self.fd) - try: - if self.state == 2: # send reply with desired auth type - self.send_raw(self._get_auth_response()) - elif self.state == 4: # send positive response to the 'connect' - self.send_raw(self._get_request_buff(self.sha_msg, 0x00)) - elif self.state == 7: - if self.file_props.paused: - self.file_props.continue_cb = self.continue_paused_transfer - self.idlequeue.plug_idle(self, False, False) - return - result = self.start_transfer() # send - self.queue.process_result(result, self) - if result is None or result <= 0: - self.disconnect() - return - self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) - elif self.state == 8: - self.disconnect() + if self.state == 2: # send reply with desired auth type + self.send_raw(self._get_auth_response()) + elif self.state == 4: # send positive response to the 'connect' + self.send_raw(self._get_request_buff(self.sha_msg, 0x00)) + elif self.state == 7: + if self.file_props.paused: + self.file_props.continue_cb = self.continue_paused_transfer + self.idlequeue.plug_idle(self, False, False) return - else: + result = self.start_transfer() # send + self.queue.process_result(result, self) + if result is None or result <= 0: self.disconnect() - except (OpenSSL.SSL.WantReadError, - OpenSSL.SSL.WantWriteError, - OpenSSL.SSL.WantX509LookupError): - log.info('caught SSL exception, ignored') + return + self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) + elif self.state == 8: + self.disconnect() return + else: + self.disconnect() if self.state < 5: self.state += 1 # unplug and plug this time for reading @@ -1286,61 +1204,41 @@ def main(self, timeout=0): self.state += 1 return None
- def send_file(self): - if self.ssl_errnum > 0: - log.error('remote certificate does not match the announced one.' - '\nSSL Error: %d\nCancelling file transfer', - self.ssl_errnum) - self.file_props.error = -12 - return -1 - return super(Socks5Client, self).send_file() - def pollin(self): self.idlequeue.remove_timeout(self.fd) if self.connected: - try: - if self.file_props.paused: - self.idlequeue.plug_idle(self, False, False) - return - if self.state < 5: - self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) - self.main(0) - elif self.state == 5: # wait for proxy reply - pass - elif self.file_props.type_ == 'r': - self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) - result = self.start_transfer() # receive - self.queue.process_result(result, self) - except (OpenSSL.SSL.WantReadError, - OpenSSL.SSL.WantWriteError, - OpenSSL.SSL.WantX509LookupError): - log.info('caught SSL exception, ignored') + if self.file_props.paused: + self.idlequeue.plug_idle(self, False, False) return + if self.state < 5: + self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) + self.main(0) + elif self.state == 5: # wait for proxy reply + pass + elif self.file_props.type_ == 'r': + self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) + result = self.start_transfer() # receive + self.queue.process_result(result, self) else: self.disconnect()
def pollout(self): self.idlequeue.remove_timeout(self.fd) - try: - if self.state == 0: - self.do_connect() - return - if self.state == 1: # send initially: version and auth types - self.send_raw(self._get_auth_buff()) - elif self.state == 3: # send 'connect' request - self.send_raw(self._get_request_buff(self._get_sha1_auth())) - elif self.file_props.type_ != 'r': - if self.file_props.paused: - self.idlequeue.plug_idle(self, False, False) - return - result = self.start_transfer() # send - self.queue.process_result(result, self) + if self.state == 0: + self.do_connect() + return + if self.state == 1: # send initially: version and auth types + self.send_raw(self._get_auth_buff()) + elif self.state == 3: # send 'connect' request + self.send_raw(self._get_request_buff(self._get_sha1_auth())) + elif self.file_props.type_ != 'r': + if self.file_props.paused: + self.idlequeue.plug_idle(self, False, False) return - except (OpenSSL.SSL.WantReadError, - OpenSSL.SSL.WantWriteError, - OpenSSL.SSL.WantX509LookupError): - log.info('caught SSL exception, ignored') + result = self.start_transfer() # send + self.queue.process_result(result, self) return + self.state += 1 # unplug and plug for reading self.idlequeue.plug_idle(self, False, True) @@ -1359,55 +1257,50 @@ def pollend(self): class Socks5SenderClient(Socks5Client, Socks5Sender):
def __init__(self, idlequeue, sock_hash, parent, _sock, host=None, - port=None, fingerprint=None, connected=True, file_props=None, + port=None, connected=True, file_props=None, initiator=None, target=None): Socks5Client.__init__(self, idlequeue, host, port, initiator, target, file_props.transport_sid) Socks5Sender.__init__(self, idlequeue, sock_hash, parent, _sock, - host, port, fingerprint, connected, file_props) + host, port, connected, file_props)
class Socks5SenderServer(Socks5Server, Socks5Sender):
def __init__(self, idlequeue, sock_hash, parent, _sock, host=None, - port=None, fingerprint=None, connected=True, file_props=None): + port=None, connected=True, file_props=None): Socks5Server.__init__(self, idlequeue, host, port, None, None, file_props.transport_sid) Socks5Sender.__init__(self, idlequeue, sock_hash, parent, _sock, - host, port, fingerprint, connected, file_props) + host, port, connected, file_props)
class Socks5ReceiverClient(Socks5Client, Socks5Receiver): - def __init__(self, idlequeue, streamhost, transport_sid, file_props=None, - fingerprint=None): + def __init__(self, idlequeue, streamhost, transport_sid, file_props=None): Socks5Client.__init__(self, idlequeue, streamhost['host'], int(streamhost['port']), streamhost['initiator'], streamhost['target'], transport_sid) Socks5Receiver.__init__(self, idlequeue, streamhost, transport_sid, - file_props, fingerprint) + file_props)
class Socks5ReceiverServer(Socks5Server, Socks5Receiver):
- def __init__(self, idlequeue, streamhost, transport_sid, file_props=None, - fingerprint=None): + def __init__(self, idlequeue, streamhost, transport_sid, file_props=None): Socks5Server.__init__(self, idlequeue, streamhost['host'], int(streamhost['port']), streamhost['initiator'], streamhost['target'], transport_sid) Socks5Receiver.__init__(self, idlequeue, streamhost, transport_sid, - file_props, fingerprint) + file_props)
class Socks5Listener(IdleObject): - def __init__(self, idlequeue, port, fp, fingerprint=None): + def __init__(self, idlequeue, port, fp): """ Handle all incoming connections on (0.0.0.0, port)
This class implements IdleObject, but we will expect only pollin events though - - fingerprint: fingerprint of certificates we shall use, set to None if - TLS connection not desired """ IdleObject.__init__(self) self.port = port @@ -1420,7 +1313,6 @@ def __init__(self, idlequeue, port, fp, fingerprint=None): self.started = False self._sock = None self.fd = -1 - self.fingerprint = fingerprint self.file_props = fp self.connections = []
@@ -1429,9 +1321,6 @@ def bind(self): # try the different possibilities (ipv6, ipv4, etc.) try: self._serv = socket.socket(*ai[:3]) - if self.fingerprint is not None: - self._serv = OpenSSL.SSL.Connection( - jingle_xtls.get_context('server'), self._serv) except socket.error as e: if e.errno == EAFNOSUPPORT: self.ai = None
===================================== gajim/data/other/dh4096.pem deleted ===================================== @@ -1,21 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb -IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft -awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT -mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh -fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq -5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM -fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq -ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI -ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O -+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI -HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQI= ------END DH PARAMETERS----- - -"4096-bit MODP Group" from RFC3526, Section 5. - -The prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } - -RFC3526 specifies a generator of 2. - -The generation of the group is described in RFC 2412.
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/3c312d1334e8fdb1f09dddce144d0cbdb...