refactored and corrected identity testing, prompt user when a session is initiated by an unsubscribed jid

This commit is contained in:
Brendan Taylor 2007-07-12 06:25:05 +00:00
parent d32e8352d5
commit 8af883e852
3 changed files with 88 additions and 70 deletions

View File

@ -45,8 +45,16 @@ class SessionBusNotPresent(Exception):
def __str__(self):
return _('Session bus is not available.\nTry reading http://trac.gajim.org/wiki/GajimDBus')
class NegotiationError(Exception):
'''A session negotiation failed'''
pass
class DecryptionError(Exception):
'''A message couldn't be decrypted into usable XML'''
pass
class GajimGeneralException(Exception):
'''This exception ir our general exception'''
'''This exception is our general exception'''
def __init__(self, text=''):
Exception.__init__(self)
self.text = text

View File

@ -2,6 +2,7 @@ import gajim
from common import xmpp
from common import helpers
from common import exceptions
import random
import string
@ -47,13 +48,14 @@ class StanzaSession(object):
return "".join([random.choice(string.letters) for x in xrange(0,32)])
def send(self, msg):
if self.thread_id:
if self.thread_id and isinstance(msg, xmpp.Message):
msg.setThread(self.thread_id)
msg.setAttr('to', self.jid)
self.conn.send_stanza(msg)
self.last_send = time.time()
if isinstance(msg, xmpp.Message):
self.last_send = time.time()
def reject_negotiation(self, body = None):
msg = xmpp.Message()
@ -291,7 +293,7 @@ class EncryptedStanzaSession(StanzaSession):
try:
parsed = xmpp.Node(node='<node>' + plaintext + '</node>')
except:
raise DecryptionError
raise exceptions.DecryptionError
for child in parsed.getChildren():
stanza.addChild(node=child)
@ -446,7 +448,7 @@ class EncryptedStanzaSession(StanzaSession):
self.n_o = base64.b64decode(form['my_nonce'])
dhhashes = form.getField('dhhashes').getValues()
self.He = dhhashes[group_order].encode("utf8")
self.He = base64.b64decode(dhhashes[group_order].encode("utf8"))
bytes = int(self.n / 8)
@ -586,13 +588,8 @@ class EncryptedStanzaSession(StanzaSession):
e = self.decode_mpi(base64.b64decode(form['dhkeys']))
p = dh.primes[self.modp]
if (not self.sha256(self.encode_mpi(e)) == self.He): or \
(not e > 1 and e < (p - 1)):
err = xmpp.Error(response, xmpp.ERR_FEATURE_NOT_IMPLEMENTED)
err.T.error.T.text.setData("invalid DH value 'e'")
self.send(err)
self.status = None
return
if (self.sha256(self.encode_mpi(e)) != self.He) or (not 1 < e < (p - 1)):
raise exceptions.NegotiationError, "invalid DH value 'e'"
k = self.sha256(self.encode_mpi(self.powmod(e, self.y, p)))
@ -605,11 +602,7 @@ class EncryptedStanzaSession(StanzaSession):
m_a_calculated = self.hmac(self.km_o, self.encode_mpi(self.c_o) + id_a)
if m_a_calculated != m_a:
err = xmpp.Error(response, xmpp.ERR_FEATURE_NOT_IMPLEMENTED)
err.T.error.T.text.setData('calculated m_a differs from received m_a')
self.send(err)
self.status = None
return
raise exceptions.NegotiationError, 'calculated m_a differs from received m_a'
mac_a = self.decrypt(id_a)
@ -619,11 +612,7 @@ class EncryptedStanzaSession(StanzaSession):
mac_a_calculated = self.hmac(self.ks_o, self.n_s + self.n_o + self.encode_mpi(e) + self.form_a + form_a2)
if mac_a_calculated != mac_a:
err = xmpp.Error(response, xmpp.ERR_FEATURE_NOT_IMPLEMENTED)
err.T.error.T.text.setData('calculated mac_a differs from received mac_a')
self.send(err)
self.status = None
return
raise exceptions.NegotiationError, 'calculated mac_a differs from received mac_a'
# 4.5.4 generating bob's final session keys
self.srs = ''
@ -653,7 +642,8 @@ class EncryptedStanzaSession(StanzaSession):
form_b2 = ''.join(map(lambda el: xmpp.c14n.c14n(el), x.getChildren()))
old_c_s = self.c_s
mac_b = self.hmac(self.n_o + self.n_s + self.encode_mpi(self.d) + self.form_b + form_b2, self.ks_s)
mac_b = self.hmac(self.ks_s, self.n_o + self.n_s + self.encode_mpi(self.d) + self.form_b + form_b2)
id_b = self.encrypt(mac_b)
m_b = self.hmac(self.km_s, self.encode_mpi(old_c_s) + id_b)
@ -703,27 +693,20 @@ class EncryptedStanzaSession(StanzaSession):
m_b = base64.b64decode(form['mac'])
id_b = base64.b64decode(form['identity'])
m_b_calculated = self.hmac(self.encode_mpi(self.c_o) + id_b, self.km_o)
m_b_calculated = self.hmac(self.km_o, self.encode_mpi(self.c_o) + id_b)
if m_b_calculated != m_b:
err = xmpp.Error(response, xmpp.ERR_FEATURE_NOT_IMPLEMENTED)
err.T.error.T.text.setData('calculated m_b differs from received m_b')
self.send(err)
self.status = None
return
raise exceptions.NegotiationError, 'calculated m_b differs from received m_b'
mac_b = self.decrypt(id_b)
form_b2 = ''.join(map(lambda el: xmpp.c14n.c14n(el), form.getChildren()))
macable_children = filter(lambda x: x.getVar() not in ('mac', 'identity'), form.getChildren())
form_b2 = ''.join(map(lambda el: xmpp.c14n.c14n(el), macable_children))
mac_b_calculated = self.hmac(self.n_s + self.n_o + self.encode_mpi(self.d) + self.form_b + form_b2, self.ks_o)
mac_b_calculated = self.hmac(self.ks_o, self.n_s + self.n_o + self.encode_mpi(self.d) + self.form_b + form_b2)
if mac_b_calculated != mac_b:
err = xmpp.Error(response, xmpp.ERR_FEATURE_NOT_IMPLEMENTED)
err.T.error.T.text.setData('calculated mac_b differs from received mac_b')
self.send(err)
self.status = None
return
raise exceptions.NegotiationError, 'calculated mac_b differs from received mac_b'
# Note: If Alice discovers an error then she SHOULD ignore any encrypted content she received in the stanza.
@ -782,6 +765,13 @@ class EncryptedStanzaSession(StanzaSession):
self.enable_encryption = False
def fail_bad_negotiation(self, reason):
'''they've tried to feed us a bogus value, send an error and cancel everything.'''
err = xmpp.Error(xmpp.Message(), xmpp.ERR_FEATURE_NOT_IMPLEMENTED)
err.T.error.T.text.setData(reason)
self.send(err)
self.status = None
def is_loggable(self):
name = self.conn.name
no_log_for = gajim.config.get_per('accounts', name, 'no_log_for')

View File

@ -1669,38 +1669,50 @@ class Interface:
# bob responds
if form.getType() == 'form' and u'e2e' in \
map(lambda x: x[1], form.getField('security').getOptions()):
contact = gajim.contacts.get_contact(account, jid.getStripped(), jid.getResource())
def continue_with_negotiation(*args):
if len(args):
self.dialog.destroy()
if gajim.SHOW_LIST[gajim.connections[account].connected] == 'invisible' or \
contact.sub not in ('from', 'both'):
negotiated, not_acceptable, ask_user = session.verify_options_bob(form)
if ask_user:
def accept_nondefault_options(widget):
self.dialog.destroy()
negotiated.update(ask_user)
session.respond_e2e_bob(form, negotiated, not_acceptable)
def reject_nondefault_options(widget):
self.dialog.destroy()
for key in ask_user.keys():
not_acceptable.append(key)
session.respond_e2e_bob(form, negotiated, not_acceptable)
self.dialog = dialogs.YesNoDialog(_('Confirm these session options'),
_('''The remote client wants to negotiate an session with these features:
%s
Are these options acceptable?''') % (negotiation.describe_features(ask_user)),
on_response_yes = accept_nondefault_options,
on_response_no = reject_nondefault_options)
else:
session.respond_e2e_bob(form, negotiated, not_acceptable)
def ignore_negotiation(widget):
self.dialog.destroy()
return
negotiated, not_acceptable, ask_user = session.verify_options_bob(form)
if ask_user:
def accept_nondefault_options(widget):
negotiated.update(ask_user)
session.respond_e2e_bob(form, negotiated, not_acceptable)
dialog.destroy()
def reject_nondefault_options(widget):
for key in ask_user.keys():
not_acceptable.append(key)
session.respond_e2e_bob(form, negotiated, not_acceptable)
dialog.destroy()
dialog = dialogs.YesNoDialog(_('Confirm these session options'),
_('''The remote client wants to negotiate an session with these features:
%s
Are these options acceptable?''') % (negotiation.describe_features(ask_user)),
on_response_yes = accept_nondefault_options,
on_response_no = reject_nondefault_options)
contact = gajim.contacts.get_contact_with_highest_priority(account, str(jid))
if gajim.SHOW_LIST[gajim.connections[account].connected] == 'invisible' or not contact or\
contact.sub not in ('from', 'both'):
self.dialog = dialogs.YesNoDialog(_('Start session?'),
_('''%s would like to start a session with you. Should I respond?''') % jid,
on_response_yes = continue_with_negotiation,
on_response_no = ignore_negotiation,
)
else:
session.respond_e2e_bob(form, negotiated, not_acceptable)
continue_with_negotiation()
return
@ -1727,16 +1739,24 @@ Are these options acceptable?''') % (negotiation.describe_features(ask_user)),
on_response_no = reject_nondefault_options)
else:
session.accept_e2e_alice(form, negotiated)
negotiation.show_sas_dialog(jid, session.sas)
return
elif session.status == 'responded-e2e' and form.getType() == 'result':
session.accept_e2e_bob(form)
negotiation.show_sas_dialog(jid, session.sas)
try:
session.accept_e2e_bob(form)
except exceptions.NegotiationError, details:
session.fail_bad_negotiation(details)
else:
negotiation.show_sas_dialog(jid, session.sas)
return
elif session.status == 'identified-alice' and form.getType() == 'result':
session.final_steps_alice(form)
try:
session.final_steps_alice(form)
except exceptions.NegotiationError, details:
session.fail_bad_negotiation(details)
return
if form.getField('terminate'):