Example #1
0
    def fail_bad_negotiation(self, reason, fields=None):
        '''sends an error and cancels everything.

if fields is None, the remote party has given us a bad cryptographic value of some kind

otherwise, list the fields we haven't implemented'''

        err = xmpp.Error(xmpp.Message(), xmpp.ERR_FEATURE_NOT_IMPLEMENTED)
        err.T.error.T.text.setData(reason)

        if fields:
            feature = xmpp.Node(xmpp.NS_FEATURE + ' feature')

            for field in fields:
                fn = xmpp.Node('field')
                fn['var'] = field
                feature.addChild(node=feature)

            err.addChild(node=feature)

        self.send(err)

        self.status = None
        self.enable_encryption = False

        # this prevents the MAC check on decryption from succeeding,
        # preventing falsified messages from going through.
        self.km_o = ''
Example #2
0
    def receive_chat_msg(self, jid, msgtxt):
        '''simulate receiving a chat message from jid'''
        msg = xmpp.Message()
        msg.setBody(msgtxt)
        msg.setType('chat')

        tim = time.localtime()
        encrypted = False
        self.sess.received(jid, msgtxt, tim, encrypted, msg)
Example #3
0
	def on_ok_button_clicked(self, widget):
		acceptance = xmpp.Message(self.jid)
		acceptance.setThread(self.session.thread_id)
		feature = acceptance.NT.feature
		feature.setNamespace(xmpp.NS_FEATURE)

		form = self.data_form_widget.data_form
		form.setAttr('type', 'submit')

		feature.addChild(node=form)

		gajim.connections[self.account].send_stanza(acceptance)

		self.window.destroy()
Example #4
0
	def on_cancel_button_clicked(self, widget):
		rejection = xmpp.Message(self.jid)
		rejection.setThread(self.session.thread_id)
		feature = rejection.NT.feature
		feature.setNamespace(xmpp.NS_FEATURE)

		x = xmpp.DataForm(typ='submit')
		x.addChild(node=xmpp.DataField('FORM_TYPE', value='urn:xmpp:ssn'))
		x.addChild(node=xmpp.DataField('accept', value='false', typ='boolean'))

		feature.addChild(node=x)

		gajim.connections[self.account].send_stanza(rejection)

		self.window.destroy()
Example #5
0
    def reject_negotiation(self, body=None):
        msg = xmpp.Message()
        feature = msg.NT.feature
        feature.setNamespace(xmpp.NS_FEATURE)

        x = xmpp.DataForm(typ='submit')
        x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
        x.addChild(node=xmpp.DataField(name='accept', value='0'))

        feature.addChild(node=x)

        if body:
            msg.setBody(body)

        self.send(msg)

        self.cancelled_negotiation()
Example #6
0
    def terminate(self):
        # only send termination message if we've sent a message and think they
        # have XEP-0201 support
        if self.last_send > 0 and \
        (self.received_thread_id or self.last_receive == 0):
            msg = xmpp.Message()
            feature = msg.NT.feature
            feature.setNamespace(xmpp.NS_FEATURE)

            x = xmpp.DataForm(typ='submit')
            x.addChild(
                node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
            x.addChild(node=xmpp.DataField(name='terminate', value='1'))

            feature.addChild(node=x)

            self.send(msg)

        self.status = None
Example #7
0
    def accept_e2e_bob(self, form):
        response = xmpp.Message()

        init = response.NT.init
        init.setNamespace(xmpp.NS_ESESSION_INIT)

        x = xmpp.DataForm(typ='result')

        for field in ('nonce', 'dhkeys', 'rshashes', 'identity', 'mac'):
            assert field in form.asDict(), "alice's form didn't have a %s field" \
             % field

        # 4.5.1 generating provisory session keys
        e = crypto.decode_mpi(base64.b64decode(form['dhkeys']))
        p = dh.primes[self.modp]

        if crypto.sha256(crypto.encode_mpi(e)) != self.negotiated['He']:
            raise exceptions.NegotiationError, 'SHA256(e) != He'

        k = self.get_shared_secret(e, self.y, p)

        self.kc_o, self.km_o, self.ks_o = self.generate_initiator_keys(k)

        # 4.5.2 verifying alice's identity

        self.verify_identity(form, e, False, 'a')

        # 4.5.4 generating bob's final session keys

        srs = ''

        srses = secrets.secrets().retained_secrets(self.conn.name,
                                                   self.jid.getStripped())
        rshashes = [
            base64.b64decode(rshash)
            for rshash in form.getField('rshashes').getValues()
        ]

        for (secret, verified) in srses:
            if self.hmac(self.n_o, secret) in rshashes:
                srs = secret
                break

        # other shared secret
        # (we're not using one)
        oss = ''

        k = crypto.sha256(k + srs + oss)

        self.kc_s, self.km_s, self.ks_s = self.generate_responder_keys(k)
        self.kc_o, self.km_o, self.ks_o = self.generate_initiator_keys(k)

        # 4.5.5
        if srs:
            srshash = self.hmac(srs, 'Shared Retained Secret')
        else:
            srshash = crypto.random_bytes(32)

        x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
        x.addChild(node=xmpp.DataField(name='nonce',
                                       value=base64.b64encode(self.n_o)))
        x.addChild(node=xmpp.DataField(name='srshash',
                                       value=base64.b64encode(srshash)))

        for datafield in self.make_identity(x, self.d):
            x.addChild(node=datafield)

        init.addChild(node=x)

        self.send(response)

        self.do_retained_secret(k, srs)

        if self.negotiated['logging'] == 'mustnot':
            self.loggable = False

        self.status = 'active'
        self.enable_encryption = True

        if self.control:
            self.control.print_esession_details()
Example #8
0
    def accept_e2e_alice(self, form, negotiated):
        self.encryptable_stanzas = ['message']
        self.sas_algs = 'sas28x5'
        self.cipher = AES
        self.hash_alg = SHA256
        self.compression = None

        self.negotiated = negotiated

        accept = xmpp.Message()
        feature = accept.NT.feature
        feature.setNamespace(xmpp.NS_FEATURE)

        result = xmpp.DataForm(typ='result')

        self.c_s = crypto.decode_mpi(base64.b64decode(form['counter']))
        self.c_o = self.c_s ^ (2**(self.n - 1))

        self.n_o = base64.b64decode(form['my_nonce'])

        mod_p = int(form['modp'])
        p = dh.primes[mod_p]
        x = self.xes[mod_p]
        e = self.es[mod_p]

        self.d = crypto.decode_mpi(base64.b64decode(form['dhkeys']))

        self.k = self.get_shared_secret(self.d, x, p)

        result.addChild(
            node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
        result.addChild(node=xmpp.DataField(name='accept', value='1'))
        result.addChild(node=xmpp.DataField(name='nonce',
                                            value=base64.b64encode(self.n_o)))

        self.kc_s, self.km_s, self.ks_s = self.generate_initiator_keys(self.k)

        if self.sigmai:
            self.kc_o, self.km_o, self.ks_o = self.generate_responder_keys(
                self.k)
            self.verify_identity(form, self.d, True, 'b')
        else:
            srses = secrets.secrets().retained_secrets(self.conn.name,
                                                       self.jid.getStripped())
            rshashes = [self.hmac(self.n_s, rs) for (rs, v) in srses]

            if not rshashes:
                # we've never spoken before, but we'll pretend we have
                rshash_size = self.hash_alg.digest_size
                rshashes.append(crypto.random_bytes(rshash_size))

            rshashes = [base64.b64encode(rshash) for rshash in rshashes]
            result.addChild(
                node=xmpp.DataField(name='rshashes', value=rshashes))
            result.addChild(node=xmpp.DataField(
                name='dhkeys', value=base64.b64encode(crypto.encode_mpi(e))))

            self.form_o = ''.join(
                map(lambda el: xmpp.c14n.c14n(el), form.getChildren()))

        # MUST securely destroy K unless it will be used later to generate the
        # final shared secret

        for datafield in self.make_identity(result, e):
            result.addChild(node=datafield)

        feature.addChild(node=result)
        self.send(accept)

        if self.sigmai:
            self.status = 'active'
            self.enable_encryption = True
        else:
            self.status = 'identified-alice'
Example #9
0
    def respond_e2e_bob(self, form, negotiated, not_acceptable):
        response = xmpp.Message()
        feature = response.NT.feature
        feature.setNamespace(xmpp.NS_FEATURE)

        x = xmpp.DataForm(typ='submit')

        x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
        x.addChild(node=xmpp.DataField(name='accept', value='true'))

        for name in negotiated:
            # some fields are internal and should not be sent
            if not name in ('send_pubkey', 'recv_pubkey'):
                x.addChild(
                    node=xmpp.DataField(name=name, value=negotiated[name]))

        self.negotiated = negotiated

        # the offset of the group we chose (need it to match up with the dhhash)
        group_order = 0
        self.modp = int(form.getField('modp').getOptions()[group_order][1])
        x.addChild(node=xmpp.DataField(name='modp', value=self.modp))

        g = dh.generators[self.modp]
        p = dh.primes[self.modp]

        self.n_o = base64.b64decode(form['my_nonce'])

        dhhashes = form.getField('dhhashes').getValues()
        self.negotiated['He'] = base64.b64decode(
            dhhashes[group_order].encode('utf8'))

        bytes = int(self.n / 8)

        self.n_s = crypto.generate_nonce()

        # n-bit random number
        self.c_o = crypto.decode_mpi(crypto.random_bytes(bytes))
        self.c_s = self.c_o ^ (2**(self.n - 1))

        self.y = crypto.srand(2**(2 * self.n - 1), p - 1)
        self.d = crypto.powmod(g, self.y, p)

        to_add = {
            'my_nonce': self.n_s,
            'dhkeys': crypto.encode_mpi(self.d),
            'counter': crypto.encode_mpi(self.c_o),
            'nonce': self.n_o
        }

        for name in to_add:
            b64ed = base64.b64encode(to_add[name])
            x.addChild(node=xmpp.DataField(name=name, value=b64ed))

        self.form_o = ''.join(
            map(lambda el: xmpp.c14n.c14n(el), form.getChildren()))
        self.form_s = ''.join(
            map(lambda el: xmpp.c14n.c14n(el), x.getChildren()))

        self.status = 'responded-e2e'

        feature.addChild(node=x)

        if not_acceptable:
            response = xmpp.Error(response, xmpp.ERR_NOT_ACCEPTABLE)

            feature = xmpp.Node(xmpp.NS_FEATURE + ' feature')

            for f in not_acceptable:
                n = xmpp.Node('field')
                n['var'] = f
                feature.addChild(node=n)

            response.T.error.addChild(node=feature)

        self.send(response)
Example #10
0
    def negotiate_e2e(self, sigmai):
        self.negotiated = {}

        request = xmpp.Message()
        feature = request.NT.feature
        feature.setNamespace(xmpp.NS_FEATURE)

        x = xmpp.DataForm(typ='form')

        x.addChild(node=xmpp.DataField(
            name='FORM_TYPE', value='urn:xmpp:ssn', typ='hidden'))
        x.addChild(node=xmpp.DataField(
            name='accept', value='1', typ='boolean', required=True))

        # this field is incorrectly called 'otr' in XEPs 0116 and 0217
        x.addChild(node=xmpp.DataField(name='logging',
                                       typ='list-single',
                                       options=self.logging_preference(),
                                       required=True))

        # unsupported options: 'disabled', 'enabled'
        x.addChild(node=xmpp.DataField(name='disclosure',
                                       typ='list-single',
                                       options=['never'],
                                       required=True))
        x.addChild(node=xmpp.DataField(
            name='security', typ='list-single', options=['e2e'
                                                         ], required=True))
        x.addChild(node=xmpp.DataField(
            name='crypt_algs', value='aes128-ctr', typ='hidden'))
        x.addChild(node=xmpp.DataField(
            name='hash_algs', value='sha256', typ='hidden'))
        x.addChild(
            node=xmpp.DataField(name='compress', value='none', typ='hidden'))

        # unsupported options: 'iq', 'presence'
        x.addChild(node=xmpp.DataField(
            name='stanzas', typ='list-multi', options=['message']))

        x.addChild(node=xmpp.DataField(name='init_pubkey',
                                       options=['none', 'key', 'hash'],
                                       typ='list-single'))

        # XXX store key, use hash
        x.addChild(node=xmpp.DataField(
            name='resp_pubkey', options=['none', 'key'], typ='list-single'))

        x.addChild(node=xmpp.DataField(name='ver', value='1.0', typ='hidden'))

        x.addChild(node=xmpp.DataField(
            name='rekey_freq', value='4294967295', typ='hidden'))

        x.addChild(node=xmpp.DataField(
            name='sas_algs', value='sas28x5', typ='hidden'))
        x.addChild(node=xmpp.DataField(
            name='sign_algs',
            value='http://www.w3.org/2000/09/xmldsig#rsa-sha256',
            typ='hidden'))

        self.n_s = crypto.generate_nonce()

        x.addChild(node=xmpp.DataField(
            name='my_nonce', value=base64.b64encode(self.n_s), typ='hidden'))

        modp_options = [
            int(g) for g in gajim.config.get('esession_modp').split(',')
        ]

        x.addChild(node=xmpp.DataField(name='modp',
                                       typ='list-single',
                                       options=map(lambda x: [None, x],
                                                   modp_options)))

        x.addChild(node=self.make_dhfield(modp_options, sigmai))
        self.sigmai = sigmai

        self.form_s = ''.join(
            map(lambda el: xmpp.c14n.c14n(el), x.getChildren()))

        feature.addChild(node=x)

        self.status = 'requested-e2e'

        self.send(request)