coding standards

This commit is contained in:
Yann Leboulanger 2008-09-17 19:04:17 +00:00
parent c876e8f65e
commit 6df6e9ddf1
1 changed files with 128 additions and 80 deletions

View File

@ -73,10 +73,12 @@ class StanzaSession(object):
def remove_events(self, types): def remove_events(self, types):
any_removed = False any_removed = False
for event in gajim.events.get_events(self.conn.name, self.jid, types=types): for event in gajim.events.get_events(self.conn.name, self.jid,
types=types):
# the event wasn't in this session # the event wasn't in this session
if (event.type_ == 'chat' and event.parameters[8] != self) or \ if (event.type_ == 'chat' and event.parameters[8] != self) or \
(event.type_ == 'printed_chat' and event.parameters[0].session != self): (event.type_ == 'printed_chat' and event.parameters[0].session != \
self):
continue continue
# events.remove_events returns True when there were no events # events.remove_events returns True when there were no events
@ -89,7 +91,8 @@ class StanzaSession(object):
return any_removed return any_removed
def generate_thread_id(self): def generate_thread_id(self):
return "".join([random.choice(string.ascii_letters) for x in xrange(0,32)]) return ''.join([random.choice(string.ascii_letters) for x in xrange(0,
32)])
def send(self, msg): def send(self, msg):
if self.thread_id: if self.thread_id:
@ -120,7 +123,8 @@ class StanzaSession(object):
self.cancelled_negotiation() self.cancelled_negotiation()
def cancelled_negotiation(self): def cancelled_negotiation(self):
'''A negotiation has been cancelled, so reset this session to its default state.''' '''A negotiation has been cancelled, so reset this session to its default
state.'''
if self.control: if self.control:
self.control.on_cancel_session_negotiation() self.control.on_cancel_session_negotiation()
@ -336,7 +340,8 @@ class EncryptedStanzaSession(StanzaSession):
try: try:
parsed = xmpp.Node(node='<node>' + plaintext + '</node>') parsed = xmpp.Node(node='<node>' + plaintext + '</node>')
except: except:
raise exceptions.DecryptionError, 'decrypted <data/> not parseable as XML' raise exceptions.DecryptionError,
'decrypted <data/> not parseable as XML'
for child in parsed.getChildren(): for child in parsed.getChildren():
stanza.addChild(node=child) stanza.addChild(node=child)
@ -348,13 +353,13 @@ class EncryptedStanzaSession(StanzaSession):
def logging_preference(self): def logging_preference(self):
if gajim.config.get('log_encrypted_sessions'): if gajim.config.get('log_encrypted_sessions'):
return ["may", "mustnot"] return ['may', 'mustnot']
else: else:
return ["mustnot", "may"] return ['mustnot', 'may']
def get_shared_secret(self, e, y, p): def get_shared_secret(self, e, y, p):
if (not 1 < e < (p - 1)): if (not 1 < e < (p - 1)):
raise exceptions.NegotiationError, "invalid DH value" raise exceptions.NegotiationError, 'invalid DH value'
return crypto.sha256(crypto.encode_mpi(crypto.powmod(e, y, p))) return crypto.sha256(crypto.encode_mpi(crypto.powmod(e, y, p)))
@ -370,7 +375,8 @@ class EncryptedStanzaSession(StanzaSession):
m_o_calculated = self.hmac(self.km_o, crypto.encode_mpi(self.c_o) + id_o) m_o_calculated = self.hmac(self.km_o, crypto.encode_mpi(self.c_o) + id_o)
if m_o_calculated != m_o: if m_o_calculated != m_o:
raise exceptions.NegotiationError, 'calculated m_%s differs from received m_%s' % (i_o, i_o) raise exceptions.NegotiationError,
'calculated m_%s differs from received m_%s' % (i_o, i_o)
if i_o == 'a' and self.sas_algs == 'sas28x5': if i_o == 'a' and self.sas_algs == 'sas28x5':
# we don't need to calculate this if there's a verified retained secret # we don't need to calculate this if there's a verified retained secret
@ -423,10 +429,12 @@ class EncryptedStanzaSession(StanzaSession):
hash = crypto.sha256(mac_o_calculated) hash = crypto.sha256(mac_o_calculated)
if not eir_pubkey.verify(hash, signature): if not eir_pubkey.verify(hash, signature):
raise exceptions.NegotiationError, 'public key signature verification failed!' raise exceptions.NegotiationError,
'public key signature verification failed!'
elif mac_o_calculated != mac_o: elif mac_o_calculated != mac_o:
raise exceptions.NegotiationError, 'calculated mac_%s differs from received mac_%s' % (i_o, i_o) raise exceptions.NegotiationError,
'calculated mac_%s differs from received mac_%s' % (i_o, i_o)
def make_identity(self, form, dh_i): def make_identity(self, form, dh_i):
if self.negotiated['send_pubkey']: if self.negotiated['send_pubkey']:
@ -434,23 +442,28 @@ class EncryptedStanzaSession(StanzaSession):
pubkey = secrets.secrets().my_pubkey(self.conn.name) pubkey = secrets.secrets().my_pubkey(self.conn.name)
fields = (pubkey.n, pubkey.e) fields = (pubkey.n, pubkey.e)
cb_fields = map(lambda f: base64.b64encode(crypto.encode_mpi(f)), fields) cb_fields = map(lambda f: base64.b64encode(crypto.encode_mpi(f)),
fields)
pubkey_s = '<RSAKeyValue xmlns="http://www.w3.org/2000/09/xmldsig#"><Modulus>%s</Modulus><Exponent>%s</Exponent></RSAKeyValue>' % tuple(cb_fields) pubkey_s = '<RSAKeyValue xmlns="http://www.w3.org/2000/09/xmldsig#"'
'><Modulus>%s</Modulus><Exponent>%s</Exponent></RSAKeyValue>' % \
tuple(cb_fields)
else: else:
pubkey_s = '' pubkey_s = ''
form_s2 = ''.join(map(lambda el: xmpp.c14n.c14n(el), form.getChildren())) form_s2 = ''.join(map(lambda el: xmpp.c14n.c14n(el), form.getChildren()))
old_c_s = self.c_s old_c_s = self.c_s
content = self.n_o + self.n_s + crypto.encode_mpi(dh_i) + pubkey_s + self.form_s + form_s2 content = self.n_o + self.n_s + crypto.encode_mpi(dh_i) + pubkey_s + \
self.form_s + form_s2
mac_s = self.hmac(self.ks_s, content) mac_s = self.hmac(self.ks_s, content)
if self.negotiated['send_pubkey']: if self.negotiated['send_pubkey']:
signature = self.sign(mac_s) signature = self.sign(mac_s)
sign_s = '<SignatureValue xmlns="http://www.w3.org/2000/09/xmldsig#">%s</SignatureValue>' % base64.b64encode(signature) sign_s = '<SignatureValue xmlns="http://www.w3.org/2000/09/xmldsig#">'
'%s</SignatureValue>' % base64.b64encode(signature)
if self.negotiated['send_pubkey'] == 'hash': if self.negotiated['send_pubkey'] == 'hash':
b64ed = base64.b64encode(self.hash(pubkey_s)) b64ed = base64.b64encode(self.hash(pubkey_s))
@ -471,7 +484,7 @@ class EncryptedStanzaSession(StanzaSession):
# XXX save retained secret? # XXX save retained secret?
self.check_identity(lambda : ()) self.check_identity(lambda : ())
return (xmpp.DataField(name='identity', value=base64.b64encode(id_s)), \ return (xmpp.DataField(name='identity', value=base64.b64encode(id_s)),
xmpp.DataField(name='mac', value=base64.b64encode(m_s))) xmpp.DataField(name='mac', value=base64.b64encode(m_s)))
def negotiate_e2e(self, sigmai): def negotiate_e2e(self, sigmai):
@ -483,41 +496,58 @@ class EncryptedStanzaSession(StanzaSession):
x = xmpp.DataForm(typ='form') 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='FORM_TYPE', value='urn:xmpp:ssn',
x.addChild(node=xmpp.DataField(name='accept', value='1', typ='boolean', required=True)) 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 # 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)) x.addChild(node=xmpp.DataField(name='logging', typ='list-single',
options=self.logging_preference(), required=True))
# unsupported options: 'disabled', 'enabled' # unsupported options: 'disabled', 'enabled'
x.addChild(node=xmpp.DataField(name='disclosure', typ='list-single', options=['never'], required=True)) x.addChild(node=xmpp.DataField(name='disclosure', typ='list-single',
x.addChild(node=xmpp.DataField(name='security', typ='list-single', options=['e2e'], required=True)) options=['never'], required=True))
x.addChild(node=xmpp.DataField(name='crypt_algs', value='aes128-ctr', typ='hidden')) x.addChild(node=xmpp.DataField(name='security', typ='list-single',
x.addChild(node=xmpp.DataField(name='hash_algs', value='sha256', typ='hidden')) options=['e2e'], required=True))
x.addChild(node=xmpp.DataField(name='compress', value='none', typ='hidden')) 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' # unsupported options: 'iq', 'presence'
x.addChild(node=xmpp.DataField(name='stanzas', typ='list-multi', options=['message'])) 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')) x.addChild(node=xmpp.DataField(name='init_pubkey', options=['none', 'key',
'hash'], typ='list-single'))
# XXX store key, use hash # 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='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='ver', value='1.0', typ='hidden'))
x.addChild(node=xmpp.DataField(name='rekey_freq', value='4294967295', 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='sas_algs', value='sas28x5',
x.addChild(node=xmpp.DataField(name='sign_algs', value='http://www.w3.org/2000/09/xmldsig#rsa-sha256', typ='hidden')) 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() self.n_s = crypto.generate_nonce()
x.addChild(node=xmpp.DataField(name='my_nonce', value=base64.b64encode(self.n_s), typ='hidden')) 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(',') ] 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=xmpp.DataField(name='modp', typ='list-single',
options=map(lambda x: [ None, x ], modp_options)))
x.addChild(node=self.make_dhfield(modp_options, sigmai)) x.addChild(node=self.make_dhfield(modp_options, sigmai))
self.sigmai = sigmai self.sigmai = sigmai
@ -536,16 +566,10 @@ class EncryptedStanzaSession(StanzaSession):
not_acceptable = [] not_acceptable = []
ask_user = {} ask_user = {}
fixed = { 'disclosure': 'never', fixed = { 'disclosure': 'never', 'security': 'e2e',
'security': 'e2e', 'crypt_algs': 'aes128-ctr', 'hash_algs': 'sha256', 'compress': 'none',
'crypt_algs': 'aes128-ctr', 'stanzas': 'message', 'init_pubkey': 'none', 'resp_pubkey': 'none',
'hash_algs': 'sha256', 'ver': '1.0', 'sas_algs': 'sas28x5' }
'compress': 'none',
'stanzas': 'message',
'init_pubkey': 'none',
'resp_pubkey': 'none',
'ver': '1.0',
'sas_algs': 'sas28x5' }
self.encryptable_stanzas = ['message'] self.encryptable_stanzas = ['message']
@ -554,7 +578,8 @@ class EncryptedStanzaSession(StanzaSession):
self.hash_alg = SHA256 self.hash_alg = SHA256
self.compression = None self.compression = None
for name, field in map(lambda name: (name, form.getField(name)), form.asDict().keys()): for name, field in map(lambda name: (name, form.getField(name)),
form.asDict().keys()):
options = map(lambda x: x[1], field.getOptions()) options = map(lambda x: x[1], field.getOptions())
values = field.getValues() values = field.getValues()
@ -598,7 +623,8 @@ class EncryptedStanzaSession(StanzaSession):
if (XmlDsig + 'rsa-sha256') in options: if (XmlDsig + 'rsa-sha256') in options:
negotiated['sign_algs'] = XmlDsig + 'rsa-sha256' negotiated['sign_algs'] = XmlDsig + 'rsa-sha256'
else: else:
# XXX some things are handled elsewhere, some things are not-implemented # XXX some things are handled elsewhere, some things are
# not-implemented
pass pass
return (negotiated, not_acceptable, ask_user) return (negotiated, not_acceptable, ask_user)
@ -632,13 +658,15 @@ class EncryptedStanzaSession(StanzaSession):
self.n_o = base64.b64decode(form['my_nonce']) self.n_o = base64.b64decode(form['my_nonce'])
dhhashes = form.getField('dhhashes').getValues() dhhashes = form.getField('dhhashes').getValues()
self.negotiated['He'] = base64.b64decode(dhhashes[group_order].encode("utf8")) self.negotiated['He'] = base64.b64decode(dhhashes[group_order].encode(
'utf8'))
bytes = int(self.n / 8) bytes = int(self.n / 8)
self.n_s = crypto.generate_nonce() self.n_s = crypto.generate_nonce()
self.c_o = crypto.decode_mpi(crypto.random_bytes(bytes)) # n-bit random number # 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.c_s = self.c_o ^ (2 ** (self.n - 1))
self.y = crypto.srand(2 ** (2 * self.n - 1), p - 1) self.y = crypto.srand(2 ** (2 * self.n - 1), p - 1)
@ -653,7 +681,8 @@ class EncryptedStanzaSession(StanzaSession):
b64ed = base64.b64encode(to_add[name]) b64ed = base64.b64encode(to_add[name])
x.addChild(node=xmpp.DataField(name=name, value=b64ed)) x.addChild(node=xmpp.DataField(name=name, value=b64ed))
self.form_o = ''.join(map(lambda el: xmpp.c14n.c14n(el), form.getChildren())) 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.form_s = ''.join(map(lambda el: xmpp.c14n.c14n(el), x.getChildren()))
self.status = 'responded-e2e' self.status = 'responded-e2e'
@ -687,7 +716,8 @@ class EncryptedStanzaSession(StanzaSession):
else: else:
negotiated['logging'] = self.logging_preference()[0] negotiated['logging'] = self.logging_preference()[0]
for r,a in (('recv_pubkey', 'resp_pubkey'), ('send_pubkey', 'init_pubkey')): for r,a in (('recv_pubkey', 'resp_pubkey'), ('send_pubkey',
'init_pubkey')):
negotiated[r] = None negotiated[r] = None
if a in form.asDict() and form[a] in ('key', 'hash'): if a in form.asDict() and form[a] in ('key', 'hash'):
@ -731,9 +761,11 @@ class EncryptedStanzaSession(StanzaSession):
self.k = self.get_shared_secret(self.d, x, p) 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='FORM_TYPE',
value='urn:xmpp:ssn'))
result.addChild(node=xmpp.DataField(name='accept', value='1')) result.addChild(node=xmpp.DataField(name='accept', value='1'))
result.addChild(node=xmpp.DataField(name='nonce', value=base64.b64encode(self.n_o))) 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) self.kc_s, self.km_s, self.ks_s = self.generate_initiator_keys(self.k)
@ -741,7 +773,8 @@ class EncryptedStanzaSession(StanzaSession):
self.kc_o, self.km_o, self.ks_o = self.generate_responder_keys(self.k) self.kc_o, self.km_o, self.ks_o = self.generate_responder_keys(self.k)
self.verify_identity(form, self.d, True, 'b') self.verify_identity(form, self.d, True, 'b')
else: else:
srses = secrets.secrets().retained_secrets(self.conn.name, self.jid.getStripped()) srses = secrets.secrets().retained_secrets(self.conn.name,
self.jid.getStripped())
rshashes = [self.hmac(self.n_s, rs) for (rs,v) in srses] rshashes = [self.hmac(self.n_s, rs) for (rs,v) in srses]
if not rshashes: if not rshashes:
@ -751,11 +784,14 @@ class EncryptedStanzaSession(StanzaSession):
rshashes = [base64.b64encode(rshash) for rshash in rshashes] rshashes = [base64.b64encode(rshash) for rshash in rshashes]
result.addChild(node=xmpp.DataField(name='rshashes', value=rshashes)) result.addChild(node=xmpp.DataField(name='rshashes', value=rshashes))
result.addChild(node=xmpp.DataField(name='dhkeys', value=base64.b64encode(crypto.encode_mpi(e)))) 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())) 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 # MUST securely destroy K unless it will be used later to generate the
# final shared secret
for datafield in self.make_identity(result, e): for datafield in self.make_identity(result, e):
result.addChild(node=datafield) result.addChild(node=datafield)
@ -779,7 +815,8 @@ class EncryptedStanzaSession(StanzaSession):
x = xmpp.DataForm(typ='result') x = xmpp.DataForm(typ='result')
for field in ('nonce', 'dhkeys', 'rshashes', 'identity', 'mac'): for field in ('nonce', 'dhkeys', 'rshashes', 'identity', 'mac'):
assert field in form.asDict(), "alice's form didn't have a %s field" % field assert field in form.asDict(), "alice's form didn't have a %s field" \
% field
# 4.5.1 generating provisory session keys # 4.5.1 generating provisory session keys
e = crypto.decode_mpi(base64.b64decode(form['dhkeys'])) e = crypto.decode_mpi(base64.b64decode(form['dhkeys']))
@ -800,8 +837,10 @@ class EncryptedStanzaSession(StanzaSession):
srs = '' srs = ''
srses = secrets.secrets().retained_secrets(self.conn.name, self.jid.getStripped()) srses = secrets.secrets().retained_secrets(self.conn.name,
rshashes = [base64.b64decode(rshash) for rshash in form.getField('rshashes').getValues()] self.jid.getStripped())
rshashes = [base64.b64decode(rshash) for rshash in form.getField(
'rshashes').getValues()]
for (secret, verified) in srses: for (secret, verified) in srses:
if self.hmac(self.n_o, secret) in rshashes: if self.hmac(self.n_o, secret) in rshashes:
@ -824,8 +863,10 @@ class EncryptedStanzaSession(StanzaSession):
srshash = crypto.random_bytes(32) srshash = crypto.random_bytes(32)
x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn')) 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='nonce', value=base64.b64encode(
x.addChild(node=xmpp.DataField(name='srshash', value=base64.b64encode(srshash))) self.n_o)))
x.addChild(node=xmpp.DataField(name='srshash', value=base64.b64encode(
srshash)))
for datafield in self.make_identity(x, self.d): for datafield in self.make_identity(x, self.d):
x.addChild(node=datafield) x.addChild(node=datafield)
@ -847,7 +888,8 @@ class EncryptedStanzaSession(StanzaSession):
def final_steps_alice(self, form): def final_steps_alice(self, form):
srs = '' srs = ''
srses = secrets.secrets().retained_secrets(self.conn.name, self.jid.getStripped()) srses = secrets.secrets().retained_secrets(self.conn.name,
self.jid.getStripped())
srshash = base64.b64decode(form['srshash']) srshash = base64.b64decode(form['srshash'])
@ -869,7 +911,8 @@ class EncryptedStanzaSession(StanzaSession):
# 4.6.2 Verifying Bob's Identity # 4.6.2 Verifying Bob's Identity
self.verify_identity(form, self.d, False, 'b') self.verify_identity(form, self.d, False, 'b')
# Note: If Alice discovers an error then she SHOULD ignore any encrypted content she received in the stanza. # Note: If Alice discovers an error then she SHOULD ignore any encrypted
# content she received in the stanza.
if self.negotiated['logging'] == 'mustnot': if self.negotiated['logging'] == 'mustnot':
self.loggable = False self.loggable = False
@ -881,7 +924,9 @@ class EncryptedStanzaSession(StanzaSession):
self.control.print_esession_details() self.control.print_esession_details()
def do_retained_secret(self, k, old_srs): def do_retained_secret(self, k, old_srs):
'''calculate the new retained secret. determine if the user needs to check the remote party's identity. set up callbacks for when the identity has been verified.''' '''calculate the new retained secret. determine if the user needs to check
the remote party's identity. set up callbacks for when the identity has
been verified.'''
new_srs = self.hmac(k, 'New Retained Secret') new_srs = self.hmac(k, 'New Retained Secret')
self.srs = new_srs self.srs = new_srs
@ -899,16 +944,19 @@ class EncryptedStanzaSession(StanzaSession):
self.verified_identity = True self.verified_identity = True
else: else:
# had a secret, but it wasn't verified. # had a secret, but it wasn't verified.
secrets.secrets().replace_srs(account, bjid, old_srs, new_srs, False) secrets.secrets().replace_srs(account, bjid, old_srs, new_srs,
False)
else: else:
# we don't even have an SRS # we don't even have an SRS
secrets.secrets().save_new_srs(account, bjid, new_srs, False) secrets.secrets().save_new_srs(account, bjid, new_srs, False)
def _verified_srs_cb(self): def _verified_srs_cb(self):
secrets.secrets().replace_srs(self.conn.name, self.jid.getStripped(), self.srs, self.srs, True) secrets.secrets().replace_srs(self.conn.name, self.jid.getStripped(),
self.srs, self.srs, True)
def _unverified_srs_cb(self): def _unverified_srs_cb(self):
secrets.secrets().replace_srs(self.conn.name, self.jid.getStripped(), self.srs, self.srs, False) secrets.secrets().replace_srs(self.conn.name, self.jid.getStripped(),
self.srs, self.srs, False)
def make_dhfield(self, modp_options, sigmai): def make_dhfield(self, modp_options, sigmai):
dhs = [] dhs = []