From 6b9d166e1cfe6c71a1f55d86e144a17fc3e73581 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 12 Nov 2011 02:48:13 +0100 Subject: Gpg module: send signed presences, and verify the signature in received presences. --- plugins/gpg/__init__.py | 70 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) (limited to 'plugins/gpg') diff --git a/plugins/gpg/__init__.py b/plugins/gpg/__init__.py index 88259acf..2c6d9981 100644 --- a/plugins/gpg/__init__.py +++ b/plugins/gpg/__init__.py @@ -1,8 +1,76 @@ from gpg import gnupg +from xml.etree import cElementTree as ET +import xml.sax.saxutils from plugin import BasePlugin +import logging +log = logging.getLogger(__name__) + +NS_SIGNED = "jabber:x:signed" +NS_ENCRYPTED = "jabber:x:encrypted" + class Plugin(BasePlugin): def init(self): - pass + self.contacts = {} + # a dict of {full-JID: 'signed'/'valid'/'invalid'} + # Whenever we receive a signed presence from a JID, we add it to this + # dict, this way we know if we can encrypt the messages we will send to + # this JID. + # If that resource sends a non-signed presence, then we remove it + # from that dict and stop encrypting our messages. + self.gpg = gnupg.GPG() + self.keyid = self.config.get('keyid', '') or None + self.passphrase = self.config.get('passphrase', '') or None + if not self.keyid: + self.core.information('No GPG keyid provided in the configuration', 'Warning') + + self.add_event_handler('send_normal_presence', self.sign_presence) + self.add_event_handler('normal_presence', self.on_normal_presence) + + def cleanup(self): + self.send_unsigned_presence() + + def sign_presence(self, presence): + """ + Sign every normal presence we send + """ + signed_element = ET.Element('{%s}x' % (NS_SIGNED)) + t = self.gpg.sign(presence['status'], keyid=self.keyid, passphrase=self.passphrase) + if not t: + self.core.information('Could not sign presence. Disabling GPG module', 'Info') + self.core.plugin_manager.unload('gpg') + return + signed_element.text = xml.sax.saxutils.escape(str(t)) + presence.append(signed_element) + + def send_unsigned_presence(self): + """ + Send our current presence, to everyone, but unsigned, to indicate + that we cannot/do not want to encrypt/unencrypt messages. + """ + current_presence = self.core.get_status() + self.core.command_status('%s %s' % (current_presence.show or 'available', current_presence.message,)) + def on_normal_presence(self, presence, resource): + """ + Check if it’s signed, if it is and we can verify the signature, + add 'valid' or 'invalid' into the dict. If it cannot be verified, just add + 'signed'. Otherwise, do nothing. + """ + signed = presence.find('{%s}x' % (NS_SIGNED,)) + bare = presence['from'].bare + full = presence['from'].full + if signed is None: + log.debug('Not signed') + if bare in self.contacts.keys(): + del self.contacts[bare] + return + if self.config.has_section('keys') and bare in self.config.options('keys'): + verify = self.gpg.verify(signed.text) + if verify: + self.contacts[full] = 'valid' + else: + self.contacts[full] = 'invalid' + else: + self.contacts[full] = 'signed' -- cgit v1.2.3