Philipp Hörist pushed to branch master at gajim / gajim
Commits:
-
3c312d13
by wurstsalat at 2022-11-26T12:09:58+00:00
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:
| ... | ... | @@ -189,7 +189,6 @@ def init(self): |
| 189 | 189 | unique_profile_paths = [
|
| 190 | 190 | # Data paths
|
| 191 | 191 | ('SECRETS_FILE', 'secrets', PathLocation.DATA, PathType.FILE),
|
| 192 | - ('MY_PEER_CERTS', 'certs', PathLocation.DATA, PathType.FOLDER),
|
|
| 193 | 192 | ('CERT_STORE', 'cert_store', PathLocation.DATA, PathType.FOLDER),
|
| 194 | 193 | ('DEBUG', 'debug', PathLocation.DATA, PathType.FOLDER),
|
| 195 | 194 | ('PLUGINS_DATA', 'plugins_data',
|
| ... | ... | @@ -200,7 +199,6 @@ def init(self): |
| 200 | 199 | ('CONFIG_FILE', 'config', PathLocation.CONFIG, PathType.FILE),
|
| 201 | 200 | ('PLUGINS_CONFIG_DIR',
|
| 202 | 201 | 'pluginsconfig', PathLocation.CONFIG, PathType.FOLDER),
|
| 203 | - ('MY_CERT', 'localcerts', PathLocation.CONFIG, PathType.FOLDER),
|
|
| 204 | 202 | ('MY_SHORTCUTS', 'shortcuts.json',
|
| 205 | 203 | PathLocation.CONFIG, PathType.FILE),
|
| 206 | 204 | ]
|
| ... | ... | @@ -903,7 +903,6 @@ def is_active(self): |
| 903 | 903 | Namespace.HASHES_BLAKE2B_512,
|
| 904 | 904 | Namespace.JINGLE,
|
| 905 | 905 | Namespace.JINGLE_FILE_TRANSFER_5,
|
| 906 | - Namespace.JINGLE_XTLS,
|
|
| 907 | 906 | Namespace.JINGLE_BYTESTREAM,
|
| 908 | 907 | Namespace.JINGLE_IBB,
|
| 909 | 908 | Namespace.AVATAR_METADATA + '+notify',
|
| ... | ... | @@ -26,10 +26,7 @@ |
| 26 | 26 | from nbxmpp.namespaces import Namespace
|
| 27 | 27 | |
| 28 | 28 | from gajim.common import app
|
| 29 | -from gajim.common import configpaths
|
|
| 30 | 29 | from gajim.common.file_props import FileProp
|
| 31 | -from gajim.common.jingle_xtls import SELF_SIGNED_CERTIFICATE
|
|
| 32 | -from gajim.common.jingle_xtls import load_cert_file
|
|
| 33 | 30 | |
| 34 | 31 | if TYPE_CHECKING:
|
| 35 | 32 | from gajim.common.jingle_transport import JingleTransport
|
| ... | ... | @@ -84,7 +81,6 @@ def __init__(self, |
| 84 | 81 | |
| 85 | 82 | # These were found by the Politie
|
| 86 | 83 | self.file_props: Optional[FileProp] = None
|
| 87 | - self.use_security: Optional[bool] = None
|
|
| 88 | 84 | |
| 89 | 85 | self.callbacks: dict[str, list[Callable[
|
| 90 | 86 | [nbxmpp.Node, nbxmpp.Node, Optional[nbxmpp.Node], str],
|
| ... | ... | @@ -267,22 +263,6 @@ def _fill_content(self, content: nbxmpp.Node) -> None: |
| 267 | 263 | desc = file_tag.setTag('desc')
|
| 268 | 264 | if self.file_props.desc:
|
| 269 | 265 | desc.setData(self.file_props.desc)
|
| 270 | - if self.use_security:
|
|
| 271 | - security = nbxmpp.simplexml.Node(
|
|
| 272 | - tag=Namespace.JINGLE_XTLS + ' security')
|
|
| 273 | - certpath = configpaths.get('MY_CERT')
|
|
| 274 | - certpath = certpath / f'{SELF_SIGNED_CERTIFICATE}.cert'
|
|
| 275 | - cert = load_cert_file(certpath)
|
|
| 276 | - if cert:
|
|
| 277 | - digest_algo = (cert.get_signature_algorithm()
|
|
| 278 | - .decode('utf-8').split('With')[0])
|
|
| 279 | - security.addChild('fingerprint').addData(cert.digest(
|
|
| 280 | - digest_algo).decode('utf-8'))
|
|
| 281 | - for m in ('x509', ): # supported authentication methods
|
|
| 282 | - method = nbxmpp.simplexml.Node(tag='method')
|
|
| 283 | - method.setAttr('name', m)
|
|
| 284 | - security.addChild(node=method)
|
|
| 285 | - content.addChild(node=security)
|
|
| 286 | 266 | content.addChild(node=description_node)
|
| 287 | 267 | |
| 288 | 268 | def destroy(self) -> None:
|
| ... | ... | @@ -33,8 +33,6 @@ |
| 33 | 33 | from nbxmpp.namespaces import Namespace
|
| 34 | 34 | |
| 35 | 35 | from gajim.common import app
|
| 36 | -from gajim.common import configpaths
|
|
| 37 | -from gajim.common import jingle_xtls
|
|
| 38 | 36 | from gajim.common import helpers
|
| 39 | 37 | from gajim.common.const import KindConstant
|
| 40 | 38 | from gajim.common.helpers import AdditionalDataDict
|
| ... | ... | @@ -80,7 +78,6 @@ def __init__(self, |
| 80 | 78 | session: JingleSession,
|
| 81 | 79 | file_props: FileProp,
|
| 82 | 80 | transport: Optional[JingleTransport] = None,
|
| 83 | - use_security: bool = False,
|
|
| 84 | 81 | senders: Optional[str] = None
|
| 85 | 82 | ) -> None:
|
| 86 | 83 | |
| ... | ... | @@ -102,8 +99,6 @@ def __init__(self, |
| 102 | 99 | self.callbacks['transport-info'] += [self.__on_transport_info]
|
| 103 | 100 | self.callbacks['iq-result'] += [self.__on_iq_result]
|
| 104 | 101 | |
| 105 | - self.use_security = use_security
|
|
| 106 | - self.x509_fingerprint: Optional[str] = None
|
|
| 107 | 102 | self.file_props = file_props
|
| 108 | 103 | self.weinitiate = self.session.weinitiate
|
| 109 | 104 | self.werequest = self.session.werequest
|
| ... | ... | @@ -139,12 +134,6 @@ def __init__(self, |
| 139 | 134 | State.CAND_SENT_AND_RECEIVED: StateCandSentAndRecv(self)
|
| 140 | 135 | }
|
| 141 | 136 | |
| 142 | - cert_name = (configpaths.get('MY_CERT') /
|
|
| 143 | - jingle_xtls.SELF_SIGNED_CERTIFICATE)
|
|
| 144 | - if not (cert_name.with_suffix('.cert').exists() and
|
|
| 145 | - cert_name.with_suffix('.pkey').exists()):
|
|
| 146 | - jingle_xtls.make_certs(cert_name, 'gajim')
|
|
| 147 | - |
|
| 148 | 137 | def __state_changed(self,
|
| 149 | 138 | nextstate: State,
|
| 150 | 139 | args: Optional[dict[str, Any]] = None
|
| ... | ... | @@ -200,13 +189,6 @@ def _raise_event(self, |
| 200 | 189 | if not content:
|
| 201 | 190 | return
|
| 202 | 191 | |
| 203 | - secu = content.getTag('security')
|
|
| 204 | - self.use_security = bool(secu)
|
|
| 205 | - if secu:
|
|
| 206 | - fingerprint = secu.getTag('fingerprint')
|
|
| 207 | - if fingerprint:
|
|
| 208 | - self.x509_fingerprint = fingerprint.getData()
|
|
| 209 | - |
|
| 210 | 192 | if not self.transport:
|
| 211 | 193 | self.transport = JingleTransportSocks5()
|
| 212 | 194 | self.transport.set_our_jid(self.session.ourjid)
|
| ... | ... | @@ -333,26 +315,6 @@ def __on_session_accept(self, |
| 333 | 315 | action: str
|
| 334 | 316 | ) -> None:
|
| 335 | 317 | log.info('__on_session_accept')
|
| 336 | - con = self.session.connection
|
|
| 337 | - security = content.getTag('security')
|
|
| 338 | - if not security: # responder can not verify our fingerprint
|
|
| 339 | - self.use_security = False
|
|
| 340 | - else:
|
|
| 341 | - fingerprint = security.getTag('fingerprint')
|
|
| 342 | - if fingerprint:
|
|
| 343 | - fingerprint = fingerprint.getData()
|
|
| 344 | - self.x509_fingerprint = fingerprint
|
|
| 345 | - if not jingle_xtls.check_cert(app.get_jid_without_resource(
|
|
| 346 | - self.session.responder), fingerprint):
|
|
| 347 | - id_ = jingle_xtls.send_cert_request(con,
|
|
| 348 | - self.session.responder)
|
|
| 349 | - jingle_xtls.key_exchange_pend(id_,
|
|
| 350 | - self.continue_session_accept,
|
|
| 351 | - [stanza])
|
|
| 352 | - raise nbxmpp.NodeProcessed
|
|
| 353 | - self.continue_session_accept(stanza)
|
|
| 354 | - |
|
| 355 | - def continue_session_accept(self, stanza: nbxmpp.Node) -> None:
|
|
| 356 | 318 | if self.state == State.TRANSPORT_REPLACE:
|
| 357 | 319 | # If we are requesting we don't have the file
|
| 358 | 320 | if self.session.werequest:
|
| ... | ... | @@ -371,16 +333,12 @@ def continue_session_accept(self, stanza: nbxmpp.Node) -> None: |
| 371 | 333 | host['initiator'] = self.session.initiator
|
| 372 | 334 | host['target'] = self.session.responder
|
| 373 | 335 | host['sid'] = self.file_props.sid
|
| 374 | - fingerprint = None
|
|
| 375 | - if self.use_security:
|
|
| 376 | - fingerprint = 'client'
|
|
| 377 | 336 | if self.transport.type_ == TransportType.SOCKS5:
|
| 378 | 337 | sid = self.file_props.transport_sid
|
| 379 | 338 | app.socks5queue.connect_to_hosts(self.session.connection.name,
|
| 380 | 339 | sid,
|
| 381 | 340 | self.on_connect,
|
| 382 | 341 | self._on_connect_error,
|
| 383 | - fingerprint=fingerprint,
|
|
| 384 | 342 | receiving=False)
|
| 385 | 343 | raise nbxmpp.NodeProcessed
|
| 386 | 344 | self.__state_changed(State.TRANSFERRING)
|
| ... | ... | @@ -550,15 +508,11 @@ def _listen_host(self) -> None: |
| 550 | 508 | receiver)
|
| 551 | 509 | self.file_props.sha_str = sha_str
|
| 552 | 510 | port = app.settings.get('file_transfers_port')
|
| 553 | - fingerprint = None
|
|
| 554 | - if self.use_security:
|
|
| 555 | - fingerprint = 'server'
|
|
| 556 | 511 | listener = app.socks5queue.start_listener(
|
| 557 | 512 | port,
|
| 558 | 513 | sha_str,
|
| 559 | 514 | self._store_socks5_sid,
|
| 560 | 515 | self.file_props,
|
| 561 | - fingerprint=fingerprint,
|
|
| 562 | 516 | typ='sender' if self.weinitiate else 'receiver')
|
| 563 | 517 | if not listener:
|
| 564 | 518 | # send error message, notify the user
|
| ... | ... | @@ -61,14 +61,11 @@ def action(self, args: Optional[dict[str, Any]] = None) -> None: |
| 61 | 61 | self.jft._listen_host()
|
| 62 | 62 | # Listen on configured port for file transfer
|
| 63 | 63 | else:
|
| 64 | - fingerprint = None
|
|
| 65 | - if self.jft.use_security:
|
|
| 66 | - fingerprint = 'client'
|
|
| 67 | 64 | # Connect to the candidate host, on success call on_connect method
|
| 68 | 65 | app.socks5queue.connect_to_hosts(
|
| 69 | 66 | self.jft.session.connection.name,
|
| 70 | 67 | self.jft.file_props.transport_sid, self.jft.on_connect,
|
| 71 | - self.jft._on_connect_error, fingerprint=fingerprint)
|
|
| 68 | + self.jft._on_connect_error)
|
|
| 72 | 69 | |
| 73 | 70 | |
| 74 | 71 | class StateCandSent(JingleFileTransferStates):
|
| ... | ... | @@ -211,13 +208,13 @@ def _start_sock5_transfer(self) -> None: |
| 211 | 208 | app.socks5queue, _sock=None,
|
| 212 | 209 | host=str(streamhost_used['host']),
|
| 213 | 210 | port=int(streamhost_used['port']),
|
| 214 | - fingerprint=None, connected=False,
|
|
| 211 | + connected=False,
|
|
| 215 | 212 | file_props=self.jft.file_props)
|
| 216 | 213 | else:
|
| 217 | 214 | sockobj = Socks5ReceiverClient(
|
| 218 | 215 | app.idlequeue, streamhost_used,
|
| 219 | 216 | transport_sid=self.jft.file_props.transport_sid,
|
| 220 | - file_props=self.jft.file_props, fingerprint=None)
|
|
| 217 | + file_props=self.jft.file_props)
|
|
| 221 | 218 | sockobj.proxy = True
|
| 222 | 219 | sockobj.streamhost = streamhost_used
|
| 223 | 220 | app.socks5queue.add_sockobj(self.jft.session.connection.name,
|
| 1 | -# This file is part of Gajim.
|
|
| 2 | -#
|
|
| 3 | -# Gajim is free software; you can redistribute it and/or modify
|
|
| 4 | -# it under the terms of the GNU General Public License as published
|
|
| 5 | -# by the Free Software Foundation; version 3 only.
|
|
| 6 | -#
|
|
| 7 | -# Gajim is distributed in the hope that it will be useful,
|
|
| 8 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| 9 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| 10 | -# GNU General Public License for more details.
|
|
| 11 | -#
|
|
| 12 | -# You should have received a copy of the GNU General Public License
|
|
| 13 | -# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
|
| 14 | - |
|
| 15 | -import logging
|
|
| 16 | -from pathlib import Path
|
|
| 17 | - |
|
| 18 | -from OpenSSL import SSL, crypto
|
|
| 19 | - |
|
| 20 | -import nbxmpp
|
|
| 21 | -from nbxmpp.namespaces import Namespace
|
|
| 22 | -from nbxmpp.util import generate_id
|
|
| 23 | -from gajim.common import app
|
|
| 24 | -from gajim.common import configpaths
|
|
| 25 | - |
|
| 26 | -log = logging.getLogger('gajim.c.jingle_xtls')
|
|
| 27 | - |
|
| 28 | -# key-exchange id -> [callback, args]
|
|
| 29 | -# accept that session once key-exchange completes
|
|
| 30 | -pending_contents = {}
|
|
| 31 | - |
|
| 32 | - |
|
| 33 | -def key_exchange_pend(id_, cb, args):
|
|
| 34 | - # args is a list
|
|
| 35 | - pending_contents[id_] = [cb, args]
|
|
| 36 | - |
|
| 37 | - |
|
| 38 | -def approve_pending_content(id_):
|
|
| 39 | - cb = pending_contents[id_][0]
|
|
| 40 | - args = pending_contents[id_][1]
|
|
| 41 | - cb(*args)
|
|
| 42 | - |
|
| 43 | - |
|
| 44 | -TYPE_RSA = crypto.TYPE_RSA
|
|
| 45 | -TYPE_DSA = crypto.TYPE_DSA
|
|
| 46 | - |
|
| 47 | -SELF_SIGNED_CERTIFICATE = 'localcert'
|
|
| 48 | -DH_PARAMS = 'dh_params.pem'
|
|
| 49 | -DEFAULT_DH_PARAMS = 'dh4096.pem'
|
|
| 50 | - |
|
| 51 | - |
|
| 52 | -def default_callback(connection, certificate, error_num, depth, return_code):
|
|
| 53 | - log.info('certificate: %s', certificate)
|
|
| 54 | - return return_code
|
|
| 55 | - |
|
| 56 | - |
|
| 57 | -def load_cert_file(cert_path, cert_store=None):
|
|
| 58 | - '''
|
|
| 59 | - This is almost identical to the one in nbxmpp.tls_nb
|
|
| 60 | - '''
|
|
| 61 | - if not cert_path.is_file():
|
|
| 62 | - return None
|
|
| 63 | - try:
|
|
| 64 | - f = open(cert_path, 'r', encoding='utf8')
|
|
| 65 | - except IOError as e:
|
|
| 66 | - log.warning('Unable to open certificate file %s: %s', cert_path,
|
|
| 67 | - str(e))
|
|
| 68 | - return None
|
|
| 69 | - lines = f.readlines()
|
|
| 70 | - i = 0
|
|
| 71 | - begin = -1
|
|
| 72 | - for line in lines:
|
|
| 73 | - if 'BEGIN CERTIFICATE' in line:
|
|
| 74 | - begin = i
|
|
| 75 | - elif 'END CERTIFICATE' in line and begin > -1:
|
|
| 76 | - cert = ''.join(lines[begin:i + 2])
|
|
| 77 | - try:
|
|
| 78 | - x509cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
|
|
| 79 | - if cert_store:
|
|
| 80 | - cert_store.add_cert(x509cert)
|
|
| 81 | - f.close()
|
|
| 82 | - return x509cert
|
|
| 83 | - except crypto.Error as exception_obj:
|
|
| 84 | - log.warning('Unable to load a certificate from file %s: %s',
|
|
| 85 | - cert_path, exception_obj.args[0][0][2])
|
|
| 86 | - except Exception:
|
|
| 87 | - log.warning('Unknown error while loading certificate from file '
|
|
| 88 | - '%s', cert_path)
|
|
| 89 | - begin = -1
|
|
| 90 | - i += 1
|
|
| 91 | - f.close()
|
|
| 92 | - |
|
| 93 | - |
|
| 94 | -def get_context(fingerprint, verify_cb=None, remote_jid=None):
|
|
| 95 | - '''
|
|
| 96 | - constructs and returns the context objects
|
|
| 97 | - '''
|
|
| 98 | - ctx = SSL.Context(SSL.SSLv23_METHOD)
|
|
| 99 | - flags = (SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3 | SSL.OP_SINGLE_DH_USE |
|
|
| 100 | - SSL.OP_NO_TICKET)
|
|
| 101 | - ctx.set_options(flags)
|
|
| 102 | - ctx.set_cipher_list(b'HIGH:!aNULL:!3DES')
|
|
| 103 | - |
|
| 104 | - if fingerprint == 'server': # for testing purposes only
|
|
| 105 | - ctx.set_verify(SSL.VERIFY_NONE | SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
|
|
| 106 | - verify_cb or default_callback)
|
|
| 107 | - elif fingerprint == 'client':
|
|
| 108 | - ctx.set_verify(SSL.VERIFY_PEER, verify_cb or default_callback)
|
|
| 109 | - |
|
| 110 | - cert_name = configpaths.get('MY_CERT') / SELF_SIGNED_CERTIFICATE
|
|
| 111 | - ctx.use_privatekey_file(str(cert_name.with_suffix('.pkey')).encode('utf-8'))
|
|
| 112 | - ctx.use_certificate_file(
|
|
| 113 | - str(cert_name.with_suffix('.cert')).encode('utf-8'))
|
|
| 114 | - |
|
| 115 | - # Try to load Diffie-Hellman parameters.
|
|
| 116 | - # First try user DH parameters, if this fails load the default DH parameters
|
|
| 117 | - dh_params_name = configpaths.get('MY_CERT') / DH_PARAMS
|
|
| 118 | - try:
|
|
| 119 | - with open(dh_params_name, 'r', encoding='utf8'):
|
|
| 120 | - ctx.load_tmp_dh(dh_params_name.encode('utf-8'))
|
|
| 121 | - except FileNotFoundError:
|
|
| 122 | - default_dh_params_name = (configpaths.get('DATA') / 'other' /
|
|
| 123 | - DEFAULT_DH_PARAMS)
|
|
| 124 | - try:
|
|
| 125 | - with open(default_dh_params_name, 'r', encoding='utf8'):
|
|
| 126 | - ctx.load_tmp_dh(str(default_dh_params_name).encode('utf-8'))
|
|
| 127 | - except FileNotFoundError as err:
|
|
| 128 | - log.error('Unable to load default DH parameter file: %s, %s',
|
|
| 129 | - default_dh_params_name, err)
|
|
| 130 | - raise
|
|
| 131 | - |
|
| 132 | - if remote_jid:
|
|
| 133 | - store = ctx.get_cert_store()
|
|
| 134 | - path = configpaths.get('MY_PEER_CERTS').expanduser()
|
|
| 135 | - path = path / f'{remote_jid}.cert'
|
|
| 136 | - if path.exists():
|
|
| 137 | - load_cert_file(path, cert_store=store)
|
|
| 138 | - log.debug('certificate file %s loaded fingerprint %s',
|
|
| 139 | - path, fingerprint)
|
|
| 140 | - return ctx
|
|
| 141 | - |
|
| 142 | - |
|
| 143 | -def read_cert(certpath):
|
|
| 144 | - certificate = ''
|
|
| 145 | - with open(certpath, 'r', encoding='utf8') as certfile:
|
|
| 146 | - for line in certfile.readlines():
|
|
| 147 | - if not line.startswith('-'):
|
|
| 148 | - certificate += line
|
|
| 149 | - return certificate
|
|
| 150 | - |
|
| 151 | - |
|
| 152 | -def send_cert(con, jid_from, sid):
|
|
| 153 | - certpath = configpaths.get('MY_CERT') / f'{SELF_SIGNED_CERTIFICATE}.cert'
|
|
| 154 | - certificate = read_cert(certpath)
|
|
| 155 | - iq = nbxmpp.Iq('result', to=jid_from)
|
|
| 156 | - iq.setAttr('id', sid)
|
|
| 157 | - |
|
| 158 | - pubkey = iq.setTag('pubkeys')
|
|
| 159 | - pubkey.setNamespace(Namespace.PUBKEY_PUBKEY)
|
|
| 160 | - |
|
| 161 | - keyinfo = pubkey.setTag('keyinfo')
|
|
| 162 | - name = keyinfo.setTag('name')
|
|
| 163 | - name.setData('CertificateHash')
|
|
| 164 | - cert = keyinfo.setTag('x509cert')
|
|
| 165 | - cert.setData(certificate)
|
|
| 166 | - |
|
| 167 | - con.send(iq)
|
|
| 168 | - |
|
| 169 | - |
|
| 170 | -def handle_new_cert(con, obj, jid_from):
|
|
| 171 | - jid = app.get_jid_without_resource(jid_from)
|
|
| 172 | - certpath = configpaths.get('MY_PEER_CERTS').expanduser() / (jid + '.cert')
|
|
| 173 | - |
|
| 174 | - id_ = obj.getAttr('id')
|
|
| 175 | - |
|
| 176 | - x509cert = obj.getTag('pubkeys').getTag('keyinfo').getTag('x509cert')
|
|
| 177 | - |
|
| 178 | - cert = x509cert.getData()
|
|
| 179 | - |
|
| 180 | - f = open(certpath, 'w', encoding='utf8')
|
|
| 181 | - f.write('-----BEGIN CERTIFICATE-----\n')
|
|
| 182 | - f.write(cert)
|
|
| 183 | - f.write('-----END CERTIFICATE-----\n')
|
|
| 184 | - f.close()
|
|
| 185 | - |
|
| 186 | - approve_pending_content(id_)
|
|
| 187 | - |
|
| 188 | - |
|
| 189 | -def check_cert(jid, fingerprint):
|
|
| 190 | - certpath = configpaths.get('MY_PEER_CERTS').expanduser() / (jid + '.cert')
|
|
| 191 | - if certpath.exists():
|
|
| 192 | - cert = load_cert_file(certpath)
|
|
| 193 | - if cert:
|
|
| 194 | - digest_algo = cert.get_signature_algorithm()
|
|
| 195 | - digest_algo = digest_algo.decode('utf-8').split('With')[0]
|
|
| 196 | - if cert.digest(digest_algo) == fingerprint:
|
|
| 197 | - return True
|
|
| 198 | - return False
|
|
| 199 | - |
|
| 200 | - |
|
| 201 | -def send_cert_request(con, to_jid):
|
|
| 202 | - iq = nbxmpp.Iq('get', to=to_jid)
|
|
| 203 | - id_ = generate_id()
|
|
| 204 | - iq.setAttr('id', id_)
|
|
| 205 | - pubkey = iq.setTag('pubkeys')
|
|
| 206 | - pubkey.setNamespace(Namespace.PUBKEY_PUBKEY)
|
|
| 207 | - con.connection.send(iq)
|
|
| 208 | - return str(id_)
|
|
| 209 | - |
|
| 210 | -# the following code is partly due to pyopenssl examples
|
|
| 211 | - |
|
| 212 | - |
|
| 213 | -def createKeyPair(type_, bits):
|
|
| 214 | - '''
|
|
| 215 | - Create a public/private key pair.
|
|
| 216 | - |
|
| 217 | - Arguments: type_ - Key type, must be one of TYPE_RSA and TYPE_DSA
|
|
| 218 | - bits - Number of bits to use in the key
|
|
| 219 | - Returns: The public/private key pair in a PKey object
|
|
| 220 | - '''
|
|
| 221 | - pkey = crypto.PKey()
|
|
| 222 | - pkey.generate_key(type_, bits)
|
|
| 223 | - return pkey
|
|
| 224 | - |
|
| 225 | - |
|
| 226 | -def createCertRequest(pkey, digest='sha256', **name):
|
|
| 227 | - '''
|
|
| 228 | - Create a certificate request.
|
|
| 229 | - |
|
| 230 | - Arguments: pkey - The key to associate with the request
|
|
| 231 | - digest - Digestion method to use for signing, default is sha256
|
|
| 232 | - **name - The name of the subject of the request, possible
|
|
| 233 | - arguments are:
|
|
| 234 | - C - Country name
|
|
| 235 | - ST - State or province name
|
|
| 236 | - L - Locality name
|
|
| 237 | - O - Organization name
|
|
| 238 | - OU - Organizational unit name
|
|
| 239 | - CN - Common name
|
|
| 240 | - emailAddress - E-mail address
|
|
| 241 | - Returns: The certificate request in an X509Req object
|
|
| 242 | - '''
|
|
| 243 | - req = crypto.X509Req()
|
|
| 244 | - subj = req.get_subject()
|
|
| 245 | - |
|
| 246 | - for (key, value) in name.items():
|
|
| 247 | - setattr(subj, key, value)
|
|
| 248 | - |
|
| 249 | - req.set_pubkey(pkey)
|
|
| 250 | - req.sign(pkey, digest)
|
|
| 251 | - return req
|
|
| 252 | - |
|
| 253 | - |
|
| 254 | -def createCertificate(req, issuerCert, issuerKey, serial, notBefore, notAfter,
|
|
| 255 | - digest='sha256'):
|
|
| 256 | - '''
|
|
| 257 | - Generate a certificate given a certificate request.
|
|
| 258 | - |
|
| 259 | - Arguments: req - Certificate request to use
|
|
| 260 | - issuerCert - The certificate of the issuer
|
|
| 261 | - issuerKey - The private key of the issuer
|
|
| 262 | - serial - Serial number for the certificate
|
|
| 263 | - notBefore - Timestamp (relative to now) when the certificate
|
|
| 264 | - starts being valid
|
|
| 265 | - notAfter - Timestamp (relative to now) when the certificate
|
|
| 266 | - stops being valid
|
|
| 267 | - digest - Digest method to use for signing, default is sha256
|
|
| 268 | - Returns: The signed certificate in an X509 object
|
|
| 269 | - '''
|
|
| 270 | - cert = crypto.X509()
|
|
| 271 | - cert.set_serial_number(serial)
|
|
| 272 | - cert.gmtime_adj_notBefore(notBefore)
|
|
| 273 | - cert.gmtime_adj_notAfter(notAfter)
|
|
| 274 | - cert.set_issuer(issuerCert.get_subject())
|
|
| 275 | - cert.set_subject(req.get_subject())
|
|
| 276 | - cert.set_pubkey(req.get_pubkey())
|
|
| 277 | - cert.sign(issuerKey, digest)
|
|
| 278 | - return cert
|
|
| 279 | - |
|
| 280 | - |
|
| 281 | -def make_certs(filepath, CN):
|
|
| 282 | - '''
|
|
| 283 | - make self signed certificates
|
|
| 284 | - filepath : absolute path of certificate file, will be appended the '.pkey'
|
|
| 285 | - and '.cert' extensions
|
|
| 286 | - CN : common name
|
|
| 287 | - '''
|
|
| 288 | - key = createKeyPair(TYPE_RSA, 4096)
|
|
| 289 | - req = createCertRequest(key, CN=CN)
|
|
| 290 | - # five years
|
|
| 291 | - cert = createCertificate(req, req, key, 0, 0, 60 * 60 * 24 * 365 * 5)
|
|
| 292 | - with open(filepath.with_suffix('.pkey'), 'wb') as f:
|
|
| 293 | - filepath.with_suffix('.pkey').chmod(0o600)
|
|
| 294 | - f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))
|
|
| 295 | - with open(filepath.with_suffix('.cert'), 'wb') as f:
|
|
| 296 | - f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
|
|
| 297 | - |
|
| 298 | - |
|
| 299 | -if __name__ == '__main__':
|
|
| 300 | - make_certs(Path('selfcert'), 'gajim') |
| ... | ... | @@ -43,7 +43,6 @@ |
| 43 | 43 | |
| 44 | 44 | from gajim.common import app
|
| 45 | 45 | from gajim.common import helpers
|
| 46 | -from gajim.common import jingle_xtls
|
|
| 47 | 46 | from gajim.common import types
|
| 48 | 47 | from gajim.common.events import FileRequestError
|
| 49 | 48 | from gajim.common.file_props import FileProp
|
| ... | ... | @@ -165,16 +164,6 @@ def send_file_approval(self, file_props: FileProp) -> None: |
| 165 | 164 | |
| 166 | 165 | if not session.accepted:
|
| 167 | 166 | content = session.get_content('file', content.name)
|
| 168 | - if content.use_security:
|
|
| 169 | - fingerprint = content.x509_fingerprint
|
|
| 170 | - if not jingle_xtls.check_cert(
|
|
| 171 | - app.get_jid_without_resource(file_props.sender),
|
|
| 172 | - fingerprint):
|
|
| 173 | - id_ = jingle_xtls.send_cert_request(
|
|
| 174 | - self._con, file_props.sender)
|
|
| 175 | - jingle_xtls.key_exchange_pend(id_,
|
|
| 176 | - content.on_cert_received, [])
|
|
| 177 | - return
|
|
| 178 | 167 | session.approve_session()
|
| 179 | 168 | |
| 180 | 169 | session.approve_content('file', content.name)
|
| ... | ... | @@ -747,7 +736,6 @@ def _on_bytestream_result(self, |
| 747 | 736 | _sock=None,
|
| 748 | 737 | host=str(proxy['host']),
|
| 749 | 738 | port=int(proxy['port']),
|
| 750 | - fingerprint=None,
|
|
| 751 | 739 | connected=False,
|
| 752 | 740 | file_props=file_props)
|
| 753 | 741 | sender.streamhost = proxy
|
| ... | ... | @@ -42,7 +42,6 @@ |
| 42 | 42 | from nbxmpp.structs import IqProperties
|
| 43 | 43 | |
| 44 | 44 | from gajim.common import helpers
|
| 45 | -from gajim.common import jingle_xtls
|
|
| 46 | 45 | from gajim.common import types
|
| 47 | 46 | from gajim.common.file_props import FileProp
|
| 48 | 47 | from gajim.common.modules.base import BaseModule
|
| ... | ... | @@ -71,14 +70,6 @@ def __init__(self, con: types.Client) -> None: |
| 71 | 70 | typ='set',
|
| 72 | 71 | ns=Namespace.JINGLE,
|
| 73 | 72 | callback=self._on_jingle_iq),
|
| 74 | - StanzaHandler(name='iq',
|
|
| 75 | - typ='get',
|
|
| 76 | - ns=Namespace.PUBKEY_PUBKEY,
|
|
| 77 | - callback=self._on_pubkey_request),
|
|
| 78 | - StanzaHandler(name='iq',
|
|
| 79 | - typ='result',
|
|
| 80 | - ns=Namespace.PUBKEY_PUBKEY,
|
|
| 81 | - callback=self._pubkey_result_received),
|
|
| 82 | 73 | ]
|
| 83 | 74 | |
| 84 | 75 | # dictionary: sessionid => JingleSession object
|
| ... | ... | @@ -100,26 +91,6 @@ def delete_jingle_session(self, sid: str) -> None: |
| 100 | 91 | self._sessions[sid].callbacks = []
|
| 101 | 92 | del self._sessions[sid]
|
| 102 | 93 | |
| 103 | - def _on_pubkey_request(self,
|
|
| 104 | - con: types.xmppClient,
|
|
| 105 | - stanza: Iq,
|
|
| 106 | - _properties: IqProperties
|
|
| 107 | - ) -> None:
|
|
| 108 | - jid_from = helpers.get_full_jid_from_iq(stanza)
|
|
| 109 | - self._log.info('Pubkey request from %s', jid_from)
|
|
| 110 | - sid = stanza.getAttr('id')
|
|
| 111 | - jingle_xtls.send_cert(con, jid_from, sid)
|
|
| 112 | - raise nbxmpp.NodeProcessed
|
|
| 113 | - |
|
| 114 | - def _pubkey_result_received(self,
|
|
| 115 | - con: types.xmppClient,
|
|
| 116 | - stanza: Iq,
|
|
| 117 | - _properties: IqProperties
|
|
| 118 | - ) -> None:
|
|
| 119 | - jid_from = helpers.get_full_jid_from_iq(stanza)
|
|
| 120 | - self._log.info('Pubkey result from %s', jid_from)
|
|
| 121 | - jingle_xtls.handle_new_cert(con, stanza, jid_from)
|
|
| 122 | - |
|
| 123 | 94 | def _on_jingle_iq(self,
|
| 124 | 95 | _con: types.xmppClient,
|
| 125 | 96 | stanza: Iq,
|
| ... | ... | @@ -236,7 +207,6 @@ def start_file_transfer(self, |
| 236 | 207 | ) -> Optional[str]:
|
| 237 | 208 | logger.info('start file transfer with file: %s', file_props)
|
| 238 | 209 | contact = self._con.get_module('Contacts').get_contact(jid)
|
| 239 | - use_security = contact.supports(Namespace.JINGLE_XTLS)
|
|
| 240 | 210 | jingle = JingleSession(self._con,
|
| 241 | 211 | weinitiate=True,
|
| 242 | 212 | jid=jid,
|
| ... | ... | @@ -261,7 +231,6 @@ def start_file_transfer(self, |
| 261 | 231 | transfer = JingleFileTransfer(jingle,
|
| 262 | 232 | transport=transport,
|
| 263 | 233 | file_props=file_props,
|
| 264 | - use_security=use_security,
|
|
| 265 | 234 | senders=senders)
|
| 266 | 235 | file_props.transport_sid = transport.sid
|
| 267 | 236 | file_props.algo = self.__hash_support(contact)
|
| ... | ... | @@ -33,11 +33,9 @@ |
| 33 | 33 | from errno import EAFNOSUPPORT
|
| 34 | 34 | |
| 35 | 35 | from nbxmpp.idlequeue import IdleObject
|
| 36 | -import OpenSSL
|
|
| 37 | 36 | |
| 38 | 37 | from gajim.common.file_props import FilesProp
|
| 39 | 38 | from gajim.common import app
|
| 40 | -from gajim.common import jingle_xtls
|
|
| 41 | 39 | |
| 42 | 40 | log = logging.getLogger('gajim.c.socks5')
|
| 43 | 41 | MAX_BUFF_LEN = 65536
|
| ... | ... | @@ -77,7 +75,7 @@ def __init__(self, idlequeue, complete_transfer_cb=None, |
| 77 | 75 | self.on_failure = {} # {id: cb}
|
| 78 | 76 | |
| 79 | 77 | def start_listener(self, port, sha_str, sha_handler, file_props,
|
| 80 | - fingerprint=None, typ='sender'):
|
|
| 78 | + typ='sender'):
|
|
| 81 | 79 | """
|
| 82 | 80 | Start waiting for incoming connections on (host, port) and do a socks5
|
| 83 | 81 | authentication using sid for generated SHA
|
| ... | ... | @@ -86,8 +84,7 @@ def start_listener(self, port, sha_str, sha_handler, file_props, |
| 86 | 84 | sid = file_props.sid
|
| 87 | 85 | self.sha_handlers[sha_str] = (sha_handler, sid)
|
| 88 | 86 | if self.listener is None or not self.listener.connections:
|
| 89 | - self.listener = Socks5Listener(self.idlequeue, port, file_props,
|
|
| 90 | - fingerprint=fingerprint)
|
|
| 87 | + self.listener = Socks5Listener(self.idlequeue, port, file_props)
|
|
| 91 | 88 | self.listener.queue = self
|
| 92 | 89 | self.listener.bind()
|
| 93 | 90 | else:
|
| ... | ... | @@ -113,7 +110,7 @@ def send_success_reply(self, file_props, streamhost): |
| 113 | 110 | return 1
|
| 114 | 111 | |
| 115 | 112 | def connect_to_hosts(self, account, transport_sid, on_success=None,
|
| 116 | - on_failure=None, fingerprint=None, receiving=True):
|
|
| 113 | + on_failure=None, receiving=True):
|
|
| 117 | 114 | self.on_success[transport_sid] = on_success
|
| 118 | 115 | self.on_failure[transport_sid] = on_failure
|
| 119 | 116 | file_props = FilesProp.getFilePropByTransportSid(account, transport_sid)
|
| ... | ... | @@ -128,10 +125,6 @@ def connect_to_hosts(self, account, transport_sid, on_success=None, |
| 128 | 125 | on_failure(file_props.transport_sid)
|
| 129 | 126 | # add streamhosts to the queue
|
| 130 | 127 | for streamhost in streamhosts_to_test:
|
| 131 | - if 'type' in streamhost and streamhost['type'] == 'proxy':
|
|
| 132 | - fp = None
|
|
| 133 | - else:
|
|
| 134 | - fp = fingerprint
|
|
| 135 | 128 | if receiving:
|
| 136 | 129 | if 'candidate_id' in streamhost:
|
| 137 | 130 | 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, |
| 141 | 134 | streamhost['jid'])
|
| 142 | 135 | file_props.type_ = 'r'
|
| 143 | 136 | socks5obj = Socks5ReceiverClient(self.idlequeue, streamhost,
|
| 144 | - transport_sid, file_props, fingerprint=fp)
|
|
| 137 | + transport_sid, file_props)
|
|
| 145 | 138 | self.add_sockobj(account, socks5obj)
|
| 146 | 139 | else:
|
| 147 | 140 | if 'candidate_id' in streamhost:
|
| ... | ... | @@ -162,7 +155,7 @@ def connect_to_hosts(self, account, transport_sid, on_success=None, |
| 162 | 155 | file_props.proxy_receiver = streamhost['initiator']
|
| 163 | 156 | socks5obj = Socks5SenderClient(self.idlequeue, idx,
|
| 164 | 157 | self, _sock=None, host=str(streamhost['host']),
|
| 165 | - port=int(streamhost['port']), fingerprint=fp,
|
|
| 158 | + port=int(streamhost['port']),
|
|
| 166 | 159 | connected=False, file_props=file_props,
|
| 167 | 160 | initiator=streamhost['initiator'],
|
| 168 | 161 | target=streamhost['target'])
|
| ... | ... | @@ -345,7 +338,7 @@ def on_connection_accepted(self, sock, listener): |
| 345 | 338 | if listener.file_props.type_ == 's' and \
|
| 346 | 339 | not self.isHashInSockObjs(self.senders, sock_hash):
|
| 347 | 340 | sockobj = Socks5SenderServer(self.idlequeue, sock_hash, self,
|
| 348 | - sock[0], sock[1][0], sock[1][1], fingerprint=None,
|
|
| 341 | + sock[0], sock[1][0], sock[1][1],
|
|
| 349 | 342 | file_props=listener.file_props)
|
| 350 | 343 | self._add(sockobj, self.senders, listener.file_props, sock_hash)
|
| 351 | 344 | # Start waiting for data
|
| ... | ... | @@ -360,7 +353,7 @@ def on_connection_accepted(self, sock, listener): |
| 360 | 353 | sh['target'] = None
|
| 361 | 354 | sockobj = Socks5ReceiverServer(idlequeue=self.idlequeue,
|
| 362 | 355 | streamhost=sh, transport_sid=None,
|
| 363 | - file_props=listener.file_props, fingerprint=None)
|
|
| 356 | + file_props=listener.file_props)
|
|
| 364 | 357 | |
| 365 | 358 | self._add(sockobj, self.readers, listener.file_props, sock_hash)
|
| 366 | 359 | sockobj.set_sock(sock[0])
|
| ... | ... | @@ -477,20 +470,12 @@ def __init__(self, idlequeue, host, port, initiator, target, sid): |
| 477 | 470 | self.file = None
|
| 478 | 471 | self.connected = False
|
| 479 | 472 | self.mode = ''
|
| 480 | - self.ssl_cert = None
|
|
| 481 | - self.ssl_errnum = 0
|
|
| 482 | 473 | |
| 483 | 474 | def _is_connected(self):
|
| 484 | 475 | if self.state < 5:
|
| 485 | 476 | return False
|
| 486 | 477 | return True
|
| 487 | 478 | |
| 488 | - def ssl_verify_cb(self, ssl_conn, cert, error_num, depth, return_code):
|
|
| 489 | - if depth == 0:
|
|
| 490 | - self.ssl_cert = cert
|
|
| 491 | - self.ssl_errnum = error_num
|
|
| 492 | - return True
|
|
| 493 | - |
|
| 494 | 479 | def connect(self):
|
| 495 | 480 | """
|
| 496 | 481 | Create the socket and plug it to the idlequeue
|
| ... | ... | @@ -500,17 +485,6 @@ def connect(self): |
| 500 | 485 | for ai in self.ais:
|
| 501 | 486 | try:
|
| 502 | 487 | self._sock = socket.socket(*ai[:3])
|
| 503 | - if self.fingerprint is not None:
|
|
| 504 | - if self.file_props.type_ == 's':
|
|
| 505 | - remote_jid = app.get_jid_without_resource(
|
|
| 506 | - self.file_props.receiver)
|
|
| 507 | - else:
|
|
| 508 | - remote_jid = app.get_jid_without_resource(
|
|
| 509 | - self.file_props.sender)
|
|
| 510 | - self._sock = OpenSSL.SSL.Connection(
|
|
| 511 | - jingle_xtls.get_context('client',
|
|
| 512 | - verify_cb=self.ssl_verify_cb, remote_jid=remote_jid),
|
|
| 513 | - self._sock)
|
|
| 514 | 488 | # this will not block the GUI
|
| 515 | 489 | self._sock.setblocking(False)
|
| 516 | 490 | self._server = ai[4]
|
| ... | ... | @@ -532,8 +506,6 @@ def do_connect(self): |
| 532 | 506 | self._sock.connect(self._server)
|
| 533 | 507 | self._send = self._sock.send
|
| 534 | 508 | self._recv = self._sock.recv
|
| 535 | - except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError):
|
|
| 536 | - pass
|
|
| 537 | 509 | except Exception as ee:
|
| 538 | 510 | errnum = ee.errno
|
| 539 | 511 | self.connect_timeout += 1
|
| ... | ... | @@ -642,10 +614,6 @@ def receive(self): |
| 642 | 614 | received = b''
|
| 643 | 615 | try:
|
| 644 | 616 | add = self._recv(64)
|
| 645 | - except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError,
|
|
| 646 | - OpenSSL.SSL.WantX509LookupError) as e:
|
|
| 647 | - log.info('SSL rehandshake request: %s', repr(e))
|
|
| 648 | - raise e
|
|
| 649 | 617 | except Exception:
|
| 650 | 618 | add = b''
|
| 651 | 619 | received += add
|
| ... | ... | @@ -659,10 +627,6 @@ def send_raw(self, raw_data): |
| 659 | 627 | """
|
| 660 | 628 | try:
|
| 661 | 629 | self._send(raw_data)
|
| 662 | - except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError,
|
|
| 663 | - OpenSSL.SSL.WantX509LookupError) as e:
|
|
| 664 | - log.info('SSL rehandshake request: %s', repr(e))
|
|
| 665 | - raise e
|
|
| 666 | 630 | except Exception:
|
| 667 | 631 | self.disconnect()
|
| 668 | 632 | return len(raw_data)
|
| ... | ... | @@ -683,13 +647,6 @@ def write_next(self): |
| 683 | 647 | lenn = 0
|
| 684 | 648 | try:
|
| 685 | 649 | lenn = self._send(buff)
|
| 686 | - except (OpenSSL.SSL.WantReadError,
|
|
| 687 | - OpenSSL.SSL.WantWriteError,
|
|
| 688 | - OpenSSL.SSL.WantX509LookupError) as err:
|
|
| 689 | - log.info('SSL rehandshake request: %s', repr(err))
|
|
| 690 | - raise err
|
|
| 691 | - except OpenSSL.SSL.SysCallError:
|
|
| 692 | - return self._on_send_exception()
|
|
| 693 | 650 | except socket.error as err:
|
| 694 | 651 | if err.errno not in (EINTR, ENOBUFS, EWOULDBLOCK):
|
| 695 | 652 | return self._on_send_exception()
|
| ... | ... | @@ -767,10 +724,6 @@ def get_file_contents(self, timeout): |
| 767 | 724 | return 0
|
| 768 | 725 | try:
|
| 769 | 726 | buff = self._recv(MAX_BUFF_LEN)
|
| 770 | - except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError,
|
|
| 771 | - OpenSSL.SSL.WantX509LookupError) as e:
|
|
| 772 | - log.info('SSL rehandshake request: %s', repr(e))
|
|
| 773 | - raise e
|
|
| 774 | 727 | except Exception:
|
| 775 | 728 | buff = b''
|
| 776 | 729 | current_time = time.time()
|
| ... | ... | @@ -825,10 +778,7 @@ def disconnect(self, *args, **kwargs): |
| 825 | 778 | if self.queue.listener.connections == []:
|
| 826 | 779 | self.queue.listener.disconnect()
|
| 827 | 780 | try:
|
| 828 | - if isinstance(self._sock, OpenSSL.SSL.Connection):
|
|
| 829 | - self._sock.shutdown()
|
|
| 830 | - else:
|
|
| 831 | - self._sock.shutdown(socket.SHUT_RDWR)
|
|
| 781 | + self._sock.shutdown(socket.SHUT_RDWR)
|
|
| 832 | 782 | self._sock.close()
|
| 833 | 783 | except Exception:
|
| 834 | 784 | # socket is already closed
|
| ... | ... | @@ -905,12 +855,7 @@ def read_connect(self): |
| 905 | 855 | """
|
| 906 | 856 | Connect response: version, auth method
|
| 907 | 857 | """
|
| 908 | - try:
|
|
| 909 | - buff = self._recv().decode('utf-8')
|
|
| 910 | - except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError,
|
|
| 911 | - OpenSSL.SSL.WantX509LookupError) as e:
|
|
| 912 | - log.info("SSL rehandshake request: %s", repr(e))
|
|
| 913 | - raise e
|
|
| 858 | + buff = self._recv().decode('utf-8')
|
|
| 914 | 859 | try:
|
| 915 | 860 | version, method = struct.unpack('!BB', buff)
|
| 916 | 861 | except Exception:
|
| ... | ... | @@ -943,21 +888,15 @@ class Socks5Sender(IdleObject): |
| 943 | 888 | Class for sending file to socket over socks5
|
| 944 | 889 | """
|
| 945 | 890 | def __init__(self, idlequeue, sock_hash, parent, _sock, host=None,
|
| 946 | - port=None, fingerprint=None, connected=True, file_props=None):
|
|
| 891 | + port=None, connected=True, file_props=None):
|
|
| 947 | 892 | IdleObject.__init__(self)
|
| 948 | - self.fingerprint = fingerprint
|
|
| 949 | 893 | self.queue_idx = sock_hash
|
| 950 | 894 | self.queue = parent
|
| 951 | 895 | self.file_props = file_props
|
| 952 | 896 | self.proxy = False
|
| 953 | 897 | self._sock = _sock
|
| 954 | 898 | if _sock is not None:
|
| 955 | - if self.fingerprint is not None and not isinstance(self._sock,
|
|
| 956 | - OpenSSL.SSL.Connection):
|
|
| 957 | - self._sock = OpenSSL.SSL.Connection(
|
|
| 958 | - jingle_xtls.get_context('server'), _sock)
|
|
| 959 | - else:
|
|
| 960 | - self._sock.setblocking(False)
|
|
| 899 | + self._sock.setblocking(False)
|
|
| 961 | 900 | self.fd = _sock.fileno()
|
| 962 | 901 | self._recv = _sock.recv
|
| 963 | 902 | self._send = _sock.send
|
| ... | ... | @@ -985,11 +924,7 @@ def start_transfer(self): |
| 985 | 924 | |
| 986 | 925 | def set_connection_sock(self, _sock):
|
| 987 | 926 | self._sock = _sock
|
| 988 | - if self.fingerprint is not None:
|
|
| 989 | - self._sock = OpenSSL.SSL.Connection(
|
|
| 990 | - jingle_xtls.get_context('client'), _sock)
|
|
| 991 | - else:
|
|
| 992 | - self._sock.setblocking(False)
|
|
| 927 | + self._sock.setblocking(False)
|
|
| 993 | 928 | self.fd = _sock.fileno()
|
| 994 | 929 | self._recv = _sock.recv
|
| 995 | 930 | self._send = _sock.send
|
| ... | ... | @@ -1023,17 +958,11 @@ def disconnect(self, cb=True): |
| 1023 | 958 | |
| 1024 | 959 | |
| 1025 | 960 | class Socks5Receiver(IdleObject):
|
| 1026 | - def __init__(self, idlequeue, streamhost, sid, file_props=None,
|
|
| 1027 | - fingerprint=None):
|
|
| 1028 | - """
|
|
| 1029 | - fingerprint: fingerprint of certificates we shall use, set to None if
|
|
| 1030 | - TLS connection not desired
|
|
| 1031 | - """
|
|
| 961 | + def __init__(self, idlequeue, streamhost, sid, file_props=None):
|
|
| 1032 | 962 | IdleObject.__init__(self)
|
| 1033 | 963 | self.queue_idx = -1
|
| 1034 | 964 | self.streamhost = streamhost
|
| 1035 | 965 | self.queue = None
|
| 1036 | - self.fingerprint = fingerprint
|
|
| 1037 | 966 | self.connect_timeout = 0
|
| 1038 | 967 | self.connected = False
|
| 1039 | 968 | self.pauses = 0
|
| ... | ... | @@ -1129,36 +1058,31 @@ def main(self): |
| 1129 | 1058 | def pollin(self):
|
| 1130 | 1059 | self.idlequeue.remove_timeout(self.fd)
|
| 1131 | 1060 | if self.connected:
|
| 1132 | - try:
|
|
| 1133 | - if self.state < 5:
|
|
| 1134 | - result = self.main()
|
|
| 1135 | - if self.state == 4:
|
|
| 1136 | - self.queue.result_sha(self.sha_msg, self.queue_idx)
|
|
| 1137 | - if result == -1:
|
|
| 1138 | - self.disconnect()
|
|
| 1139 | - elif self.state == 5:
|
|
| 1140 | - self.state = 7
|
|
| 1141 | - if self.file_props.type_ == 's':
|
|
| 1142 | - # We wait for the end of the negotiation to
|
|
| 1143 | - # send the file
|
|
| 1144 | - self.idlequeue.plug_idle(self, False, False)
|
|
| 1145 | - else:
|
|
| 1146 | - # We plug for reading
|
|
| 1147 | - self.idlequeue.plug_idle(self, False, True)
|
|
| 1148 | - return
|
|
| 1149 | - elif self.state == 7:
|
|
| 1150 | - if self.file_props.paused:
|
|
| 1151 | - self.file_props.continue_cb = \
|
|
| 1152 | - self.continue_paused_transfer
|
|
| 1153 | - self.idlequeue.plug_idle(self, False, False)
|
|
| 1154 | - return
|
|
| 1155 | - self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT)
|
|
| 1156 | - result = self.start_transfer() # send
|
|
| 1157 | - self.queue.process_result(result, self)
|
|
| 1158 | - except (OpenSSL.SSL.WantReadError,
|
|
| 1159 | - OpenSSL.SSL.WantWriteError,
|
|
| 1160 | - OpenSSL.SSL.WantX509LookupError):
|
|
| 1161 | - log.info('caught SSL exception, ignored')
|
|
| 1061 | + if self.state < 5:
|
|
| 1062 | + result = self.main()
|
|
| 1063 | + if self.state == 4:
|
|
| 1064 | + self.queue.result_sha(self.sha_msg, self.queue_idx)
|
|
| 1065 | + if result == -1:
|
|
| 1066 | + self.disconnect()
|
|
| 1067 | + elif self.state == 5:
|
|
| 1068 | + self.state = 7
|
|
| 1069 | + if self.file_props.type_ == 's':
|
|
| 1070 | + # We wait for the end of the negotiation to
|
|
| 1071 | + # send the file
|
|
| 1072 | + self.idlequeue.plug_idle(self, False, False)
|
|
| 1073 | + else:
|
|
| 1074 | + # We plug for reading
|
|
| 1075 | + self.idlequeue.plug_idle(self, False, True)
|
|
| 1076 | + return
|
|
| 1077 | + elif self.state == 7:
|
|
| 1078 | + if self.file_props.paused:
|
|
| 1079 | + self.file_props.continue_cb = \
|
|
| 1080 | + self.continue_paused_transfer
|
|
| 1081 | + self.idlequeue.plug_idle(self, False, False)
|
|
| 1082 | + return
|
|
| 1083 | + self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT)
|
|
| 1084 | + result = self.start_transfer() # send
|
|
| 1085 | + self.queue.process_result(result, self)
|
|
| 1162 | 1086 | else:
|
| 1163 | 1087 | self.disconnect()
|
| 1164 | 1088 | |
| ... | ... | @@ -1173,32 +1097,26 @@ def pollout(self): |
| 1173 | 1097 | self.disconnect()
|
| 1174 | 1098 | return
|
| 1175 | 1099 | self.idlequeue.remove_timeout(self.fd)
|
| 1176 | - try:
|
|
| 1177 | - if self.state == 2: # send reply with desired auth type
|
|
| 1178 | - self.send_raw(self._get_auth_response())
|
|
| 1179 | - elif self.state == 4: # send positive response to the 'connect'
|
|
| 1180 | - self.send_raw(self._get_request_buff(self.sha_msg, 0x00))
|
|
| 1181 | - elif self.state == 7:
|
|
| 1182 | - if self.file_props.paused:
|
|
| 1183 | - self.file_props.continue_cb = self.continue_paused_transfer
|
|
| 1184 | - self.idlequeue.plug_idle(self, False, False)
|
|
| 1185 | - return
|
|
| 1186 | - result = self.start_transfer() # send
|
|
| 1187 | - self.queue.process_result(result, self)
|
|
| 1188 | - if result is None or result <= 0:
|
|
| 1189 | - self.disconnect()
|
|
| 1190 | - return
|
|
| 1191 | - self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT)
|
|
| 1192 | - elif self.state == 8:
|
|
| 1193 | - self.disconnect()
|
|
| 1100 | + if self.state == 2: # send reply with desired auth type
|
|
| 1101 | + self.send_raw(self._get_auth_response())
|
|
| 1102 | + elif self.state == 4: # send positive response to the 'connect'
|
|
| 1103 | + self.send_raw(self._get_request_buff(self.sha_msg, 0x00))
|
|
| 1104 | + elif self.state == 7:
|
|
| 1105 | + if self.file_props.paused:
|
|
| 1106 | + self.file_props.continue_cb = self.continue_paused_transfer
|
|
| 1107 | + self.idlequeue.plug_idle(self, False, False)
|
|
| 1194 | 1108 | return
|
| 1195 | - else:
|
|
| 1109 | + result = self.start_transfer() # send
|
|
| 1110 | + self.queue.process_result(result, self)
|
|
| 1111 | + if result is None or result <= 0:
|
|
| 1196 | 1112 | self.disconnect()
|
| 1197 | - except (OpenSSL.SSL.WantReadError,
|
|
| 1198 | - OpenSSL.SSL.WantWriteError,
|
|
| 1199 | - OpenSSL.SSL.WantX509LookupError):
|
|
| 1200 | - log.info('caught SSL exception, ignored')
|
|
| 1113 | + return
|
|
| 1114 | + self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT)
|
|
| 1115 | + elif self.state == 8:
|
|
| 1116 | + self.disconnect()
|
|
| 1201 | 1117 | return
|
| 1118 | + else:
|
|
| 1119 | + self.disconnect()
|
|
| 1202 | 1120 | if self.state < 5:
|
| 1203 | 1121 | self.state += 1
|
| 1204 | 1122 | # unplug and plug this time for reading
|
| ... | ... | @@ -1286,61 +1204,41 @@ def main(self, timeout=0): |
| 1286 | 1204 | self.state += 1
|
| 1287 | 1205 | return None
|
| 1288 | 1206 | |
| 1289 | - def send_file(self):
|
|
| 1290 | - if self.ssl_errnum > 0:
|
|
| 1291 | - log.error('remote certificate does not match the announced one.'
|
|
| 1292 | - '\nSSL Error: %d\nCancelling file transfer',
|
|
| 1293 | - self.ssl_errnum)
|
|
| 1294 | - self.file_props.error = -12
|
|
| 1295 | - return -1
|
|
| 1296 | - return super(Socks5Client, self).send_file()
|
|
| 1297 | - |
|
| 1298 | 1207 | def pollin(self):
|
| 1299 | 1208 | self.idlequeue.remove_timeout(self.fd)
|
| 1300 | 1209 | if self.connected:
|
| 1301 | - try:
|
|
| 1302 | - if self.file_props.paused:
|
|
| 1303 | - self.idlequeue.plug_idle(self, False, False)
|
|
| 1304 | - return
|
|
| 1305 | - if self.state < 5:
|
|
| 1306 | - self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
|
|
| 1307 | - self.main(0)
|
|
| 1308 | - elif self.state == 5: # wait for proxy reply
|
|
| 1309 | - pass
|
|
| 1310 | - elif self.file_props.type_ == 'r':
|
|
| 1311 | - self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT)
|
|
| 1312 | - result = self.start_transfer() # receive
|
|
| 1313 | - self.queue.process_result(result, self)
|
|
| 1314 | - except (OpenSSL.SSL.WantReadError,
|
|
| 1315 | - OpenSSL.SSL.WantWriteError,
|
|
| 1316 | - OpenSSL.SSL.WantX509LookupError):
|
|
| 1317 | - log.info('caught SSL exception, ignored')
|
|
| 1210 | + if self.file_props.paused:
|
|
| 1211 | + self.idlequeue.plug_idle(self, False, False)
|
|
| 1318 | 1212 | return
|
| 1213 | + if self.state < 5:
|
|
| 1214 | + self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
|
|
| 1215 | + self.main(0)
|
|
| 1216 | + elif self.state == 5: # wait for proxy reply
|
|
| 1217 | + pass
|
|
| 1218 | + elif self.file_props.type_ == 'r':
|
|
| 1219 | + self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT)
|
|
| 1220 | + result = self.start_transfer() # receive
|
|
| 1221 | + self.queue.process_result(result, self)
|
|
| 1319 | 1222 | else:
|
| 1320 | 1223 | self.disconnect()
|
| 1321 | 1224 | |
| 1322 | 1225 | def pollout(self):
|
| 1323 | 1226 | self.idlequeue.remove_timeout(self.fd)
|
| 1324 | - try:
|
|
| 1325 | - if self.state == 0:
|
|
| 1326 | - self.do_connect()
|
|
| 1327 | - return
|
|
| 1328 | - if self.state == 1: # send initially: version and auth types
|
|
| 1329 | - self.send_raw(self._get_auth_buff())
|
|
| 1330 | - elif self.state == 3: # send 'connect' request
|
|
| 1331 | - self.send_raw(self._get_request_buff(self._get_sha1_auth()))
|
|
| 1332 | - elif self.file_props.type_ != 'r':
|
|
| 1333 | - if self.file_props.paused:
|
|
| 1334 | - self.idlequeue.plug_idle(self, False, False)
|
|
| 1335 | - return
|
|
| 1336 | - result = self.start_transfer() # send
|
|
| 1337 | - self.queue.process_result(result, self)
|
|
| 1227 | + if self.state == 0:
|
|
| 1228 | + self.do_connect()
|
|
| 1229 | + return
|
|
| 1230 | + if self.state == 1: # send initially: version and auth types
|
|
| 1231 | + self.send_raw(self._get_auth_buff())
|
|
| 1232 | + elif self.state == 3: # send 'connect' request
|
|
| 1233 | + self.send_raw(self._get_request_buff(self._get_sha1_auth()))
|
|
| 1234 | + elif self.file_props.type_ != 'r':
|
|
| 1235 | + if self.file_props.paused:
|
|
| 1236 | + self.idlequeue.plug_idle(self, False, False)
|
|
| 1338 | 1237 | return
|
| 1339 | - except (OpenSSL.SSL.WantReadError,
|
|
| 1340 | - OpenSSL.SSL.WantWriteError,
|
|
| 1341 | - OpenSSL.SSL.WantX509LookupError):
|
|
| 1342 | - log.info('caught SSL exception, ignored')
|
|
| 1238 | + result = self.start_transfer() # send
|
|
| 1239 | + self.queue.process_result(result, self)
|
|
| 1343 | 1240 | return
|
| 1241 | + |
|
| 1344 | 1242 | self.state += 1
|
| 1345 | 1243 | # unplug and plug for reading
|
| 1346 | 1244 | self.idlequeue.plug_idle(self, False, True)
|
| ... | ... | @@ -1359,55 +1257,50 @@ def pollend(self): |
| 1359 | 1257 | class Socks5SenderClient(Socks5Client, Socks5Sender):
|
| 1360 | 1258 | |
| 1361 | 1259 | def __init__(self, idlequeue, sock_hash, parent, _sock, host=None,
|
| 1362 | - port=None, fingerprint=None, connected=True, file_props=None,
|
|
| 1260 | + port=None, connected=True, file_props=None,
|
|
| 1363 | 1261 | initiator=None, target=None):
|
| 1364 | 1262 | Socks5Client.__init__(self, idlequeue, host, port, initiator, target,
|
| 1365 | 1263 | file_props.transport_sid)
|
| 1366 | 1264 | Socks5Sender.__init__(self, idlequeue, sock_hash, parent, _sock,
|
| 1367 | - host, port, fingerprint, connected, file_props)
|
|
| 1265 | + host, port, connected, file_props)
|
|
| 1368 | 1266 | |
| 1369 | 1267 | |
| 1370 | 1268 | class Socks5SenderServer(Socks5Server, Socks5Sender):
|
| 1371 | 1269 | |
| 1372 | 1270 | def __init__(self, idlequeue, sock_hash, parent, _sock, host=None,
|
| 1373 | - port=None, fingerprint=None, connected=True, file_props=None):
|
|
| 1271 | + port=None, connected=True, file_props=None):
|
|
| 1374 | 1272 | Socks5Server.__init__(self, idlequeue, host, port, None, None,
|
| 1375 | 1273 | file_props.transport_sid)
|
| 1376 | 1274 | Socks5Sender.__init__(self, idlequeue, sock_hash, parent, _sock,
|
| 1377 | - host, port, fingerprint, connected, file_props)
|
|
| 1275 | + host, port, connected, file_props)
|
|
| 1378 | 1276 | |
| 1379 | 1277 | |
| 1380 | 1278 | class Socks5ReceiverClient(Socks5Client, Socks5Receiver):
|
| 1381 | - def __init__(self, idlequeue, streamhost, transport_sid, file_props=None,
|
|
| 1382 | - fingerprint=None):
|
|
| 1279 | + def __init__(self, idlequeue, streamhost, transport_sid, file_props=None):
|
|
| 1383 | 1280 | Socks5Client.__init__(self, idlequeue, streamhost['host'],
|
| 1384 | 1281 | int(streamhost['port']), streamhost['initiator'],
|
| 1385 | 1282 | streamhost['target'], transport_sid)
|
| 1386 | 1283 | Socks5Receiver.__init__(self, idlequeue, streamhost, transport_sid,
|
| 1387 | - file_props, fingerprint)
|
|
| 1284 | + file_props)
|
|
| 1388 | 1285 | |
| 1389 | 1286 | |
| 1390 | 1287 | class Socks5ReceiverServer(Socks5Server, Socks5Receiver):
|
| 1391 | 1288 | |
| 1392 | - def __init__(self, idlequeue, streamhost, transport_sid, file_props=None,
|
|
| 1393 | - fingerprint=None):
|
|
| 1289 | + def __init__(self, idlequeue, streamhost, transport_sid, file_props=None):
|
|
| 1394 | 1290 | Socks5Server.__init__(self, idlequeue, streamhost['host'],
|
| 1395 | 1291 | int(streamhost['port']), streamhost['initiator'],
|
| 1396 | 1292 | streamhost['target'], transport_sid)
|
| 1397 | 1293 | Socks5Receiver.__init__(self, idlequeue, streamhost, transport_sid,
|
| 1398 | - file_props, fingerprint)
|
|
| 1294 | + file_props)
|
|
| 1399 | 1295 | |
| 1400 | 1296 | |
| 1401 | 1297 | class Socks5Listener(IdleObject):
|
| 1402 | - def __init__(self, idlequeue, port, fp, fingerprint=None):
|
|
| 1298 | + def __init__(self, idlequeue, port, fp):
|
|
| 1403 | 1299 | """
|
| 1404 | 1300 | Handle all incoming connections on (0.0.0.0, port)
|
| 1405 | 1301 | |
| 1406 | 1302 | This class implements IdleObject, but we will expect
|
| 1407 | 1303 | only pollin events though
|
| 1408 | - |
|
| 1409 | - fingerprint: fingerprint of certificates we shall use, set to None if
|
|
| 1410 | - TLS connection not desired
|
|
| 1411 | 1304 | """
|
| 1412 | 1305 | IdleObject.__init__(self)
|
| 1413 | 1306 | self.port = port
|
| ... | ... | @@ -1420,7 +1313,6 @@ def __init__(self, idlequeue, port, fp, fingerprint=None): |
| 1420 | 1313 | self.started = False
|
| 1421 | 1314 | self._sock = None
|
| 1422 | 1315 | self.fd = -1
|
| 1423 | - self.fingerprint = fingerprint
|
|
| 1424 | 1316 | self.file_props = fp
|
| 1425 | 1317 | self.connections = []
|
| 1426 | 1318 | |
| ... | ... | @@ -1429,9 +1321,6 @@ def bind(self): |
| 1429 | 1321 | # try the different possibilities (ipv6, ipv4, etc.)
|
| 1430 | 1322 | try:
|
| 1431 | 1323 | self._serv = socket.socket(*ai[:3])
|
| 1432 | - if self.fingerprint is not None:
|
|
| 1433 | - self._serv = OpenSSL.SSL.Connection(
|
|
| 1434 | - jingle_xtls.get_context('server'), self._serv)
|
|
| 1435 | 1324 | except socket.error as e:
|
| 1436 | 1325 | if e.errno == EAFNOSUPPORT:
|
| 1437 | 1326 | self.ai = None
|
| 1 | ------BEGIN DH PARAMETERS-----
|
|
| 2 | -MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
|
|
| 3 | -IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
|
|
| 4 | -awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
|
|
| 5 | -mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
|
|
| 6 | -fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
|
|
| 7 | -5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM
|
|
| 8 | -fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq
|
|
| 9 | -ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI
|
|
| 10 | -ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O
|
|
| 11 | -+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI
|
|
| 12 | -HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQI=
|
|
| 13 | ------END DH PARAMETERS-----
|
|
| 14 | - |
|
| 15 | -"4096-bit MODP Group" from RFC3526, Section 5.
|
|
| 16 | - |
|
| 17 | -The prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
|
|
| 18 | - |
|
| 19 | -RFC3526 specifies a generator of 2.
|
|
| 20 | - |
|
| 21 | -The generation of the group is described in RFC 2412. |