def test_protect(): #> From foo msg='''Content-Type: multipart/mixed; boundary="------------030608090900090202040409" This is a multi-part message in MIME format. --------------030608090900090202040409 Content-Type: text/plain; charset=ISO-8859-15 Content-Transfer-Encoding: quoted-printable body line2 --------------030608090900090202040409 Content-Type: text/plain; charset=UTF-8; name="attach.txt" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="attach.txt" attachment line2 --------------030608090900090202040409-- ''' prot = protect_mail(msg,linesep='\n',sevenbit=True) assert prot.as_string() == msg prot = protect_mail(msg,linesep='\r\n',sevenbit=True) assert prot.as_string() == fix_lines(msg,'\r\n') msg = create_mail(sender,receiver,'subject','body\nmessage') prot = protect_mail(msg,linesep='\n') assert msg.get_payload() == prot.get_payload() prot = protect_mail(msg,linesep='\r\n') assert fix_lines(msg.get_payload(),'\r\n') == prot.get_payload()
def test_sign(gpgsender, inline, attach, asstr, protect): # protect = use protected CRLF message import copy if inline and attach: return if attach: # with attachment nmsg, pmsg = protect_mail(msgatt, linesep='\n'), protatt inmsg = protatt if protect else nmsg else: inmsg = prot if protect else msg nmsg, pmsg = msg, prot if asstr: inmsg, nmsg, pmsg = inmsg.as_string(), nmsg.as_string( ), pmsg.as_string() omsg = copy.deepcopy(inmsg) sgn, result = gpgsender.sign(inmsg, inline=inline, verify=True) assert sgn compare_mail(omsg, inmsg) # unmodified if inline: assert not sgn.is_multipart() body = gpgsender.without_signature(sgn.get_payload()) if not asstr: assert body == pmsg.get_payload() if asstr: sgn = sgn.as_string() if protect: sgn = protect_mail(sgn, linesep='\r\n') osgn = copy.deepcopy(sgn) assert gpgsender.verify(sgn, strict=True)[0] compare_mail(osgn, sgn) # unmodified msg2, signed, results = gpgsender.decrypt(sgn, strict=True) assert signed and msg2 compare_mail(osgn, sgn) # unmodified if asstr: msg2 = msg2.as_string() compare_mail(pmsg, msg2) assert gpgsender.verify(sgn, strict=False)[0] compare_mail(osgn, sgn) # unmodified msg2, signed, results = gpgsender.decrypt(sgn, strict=False) assert signed and msg2 compare_mail(osgn, sgn) # unmodified if asstr: msg2 = msg2.as_string() compare_mail(pmsg, msg2) nsgn = protect_mail(sgn, linesep='\n') # use LF message as input if asstr: nsgn = nsgn.as_string() compare_mail(osgn, sgn) # unmodified onsgn = copy.deepcopy(nsgn) msg2, signed, results = gpgsender.decrypt(nsgn, strict=True) assert signed == bool( inline) and msg2 # sgn was modified, should fail for detached compare_mail(onsgn, nsgn) # unmodified if asstr: msg2 = msg2.as_string() compare_mail(nmsg, msg2) msg2, signed, results = gpgsender.decrypt(nsgn, strict=False) assert signed and msg2 compare_mail(onsgn, nsgn) if asstr: msg2 = msg2.as_string() if inline: compare_mail(nmsg, msg2) else: compare_mail(pmsg, msg2)
def test_sign(gpgsender,inline,attach,asstr,protect): # protect = use protected CRLF message import copy if inline and attach: return if attach: # with attachment nmsg, pmsg = protect_mail(msgatt,linesep='\n'), protatt inmsg = protatt if protect else nmsg else: inmsg = prot if protect else msg nmsg, pmsg = msg, prot if asstr: inmsg, nmsg, pmsg = inmsg.as_string(), nmsg.as_string(), pmsg.as_string() omsg = copy.deepcopy(inmsg) sgn, result = gpgsender.sign(inmsg,inline=inline,verify=True) assert sgn compare_mail(omsg,inmsg) # unmodified if inline: assert not sgn.is_multipart() body = gpgsender.without_signature(sgn.get_payload()) if not asstr: assert body==pmsg.get_payload() if asstr: sgn = sgn.as_string() if protect: sgn = protect_mail(sgn,linesep='\r\n') osgn = copy.deepcopy(sgn) assert gpgsender.verify(sgn,strict=True)[0] compare_mail(osgn,sgn) # unmodified msg2, signed, results = gpgsender.decrypt(sgn,strict=True) assert signed and msg2 compare_mail(osgn,sgn) # unmodified if asstr: msg2 = msg2.as_string() compare_mail(pmsg,msg2) assert gpgsender.verify(sgn,strict=False)[0] compare_mail(osgn,sgn) # unmodified msg2, signed, results = gpgsender.decrypt(sgn,strict=False) assert signed and msg2 compare_mail(osgn,sgn) # unmodified if asstr: msg2 = msg2.as_string() compare_mail(pmsg,msg2) nsgn = protect_mail(sgn,linesep='\n') # use LF message as input if asstr: nsgn = nsgn.as_string() compare_mail(osgn,sgn) # unmodified onsgn = copy.deepcopy(nsgn) msg2, signed, results = gpgsender.decrypt(nsgn,strict=True) assert signed==bool(inline) and msg2 # sgn was modified, should fail for detached compare_mail(onsgn,nsgn) # unmodified if asstr: msg2 = msg2.as_string() compare_mail(nmsg,msg2) msg2, signed, results = gpgsender.decrypt(nsgn,strict=False) assert signed and msg2 compare_mail(onsgn,nsgn) if asstr: msg2 = msg2.as_string() if inline: compare_mail(nmsg,msg2) else: compare_mail(pmsg,msg2)
def __iter__(self): from kryptomime.mail import protect_mail filter = "(OR UNSEEN FLAGGED)" if self.filter else 'ALL' status, response = self.imap.uid('search', None, filter) if not status == 'OK': return email_ids = response[0].split() for e_id in email_ids: status, response = self.imap.uid('fetch', e_id, '(FLAGS)') flags = '' for flag in imaplib.ParseFlags(response[0]): if 'Flagged' in flag: flags += 'F' elif 'Seen' in flag: flags += 'S' elif 'Deleted' in flag: flags += 'D' if 'D' in flags: continue # mark for processing status, response = self.imap.uid('store', e_id, '+FLAGS', r'(\Flagged)') status, response = self.imap.uid('fetch', e_id, '(RFC822)') raw = response[0][1] yield protect_mail(raw), flags if self.keep: status, response = self.imap.uid('store', e_id, '-FLAGS', r'(\Flagged)') else: status, response = self.imap.uid('store', e_id, '+FLAGS', r'(\Deleted)')
def store_mail(mail,identity=None,decrypt=False,notify=None): from six import iteritems from kryptomime.mail import protect_mail mail = protect_mail(mail,sevenbit=False) ids = settings.EMAIL_IDS def find_identity(recv): for id,opts in iteritems(ids): idemail = opts.get('email',id) if idemail in recv: return id, opts, idemail return None, None, None if identity: opts = ids[identity] idemail = opts.get('email',identity) else: import email.utils recv = mail.get_all('to', []) + mail.get_all('cc', []) recv = [to[1] for to in email.utils.getaddresses(recv)] identity, opts, idemail = find_identity(recv) if not identity: log.error('unknown receiver') return False indep_crypto = getattr(settings, 'EMAIL_INDEP_CRYPT', False) if indep_crypto and not decrypt: gpg, crypto, skey = None, None, None else: from kryptomime.pgp import GPGMIME gpg = gnupg_init() if not 'key' in opts: skey = None else: skey = get_full_key(GPGMIME(gpg),opts,identity) crypto = GPGMIME(gpg,default_key=skey) return save_mail(mail, identity, idemail, crypto, gpg, skey, notify)
def test_encrypt(gpgsender, asstr, protect): import copy inmsg = protect_mail(msgrev,linesep='\r\n') if protect else msgrev if asstr: inmsg = inmsg.as_string() omsg = copy.deepcopy(inmsg) enc, results = gpgsender.encrypt(inmsg,toself=False,sign=False) # we only know sender keys assert enc compare_mail(omsg,inmsg) if protect: enc = protect_mail(enc,linesep='\r\n') if asstr: enc = enc.as_string() oenc = copy.deepcopy(enc) msg2, signed, results = gpgsender.decrypt(enc,strict=True) assert not signed and msg2 compare_mail(oenc,enc) if asstr: msg2 = msg2.as_string() compare_mail(inmsg,msg2)
def test_encrypt(gpgsender, asstr, protect): import copy inmsg = protect_mail(msgrev, linesep='\r\n') if protect else msgrev if asstr: inmsg = inmsg.as_string() omsg = copy.deepcopy(inmsg) enc, results = gpgsender.encrypt(inmsg, toself=False, sign=False) # we only know sender keys assert enc compare_mail(omsg, inmsg) if protect: enc = protect_mail(enc, linesep='\r\n') if asstr: enc = enc.as_string() oenc = copy.deepcopy(enc) msg2, signed, results = gpgsender.decrypt(enc, strict=True) assert not signed and msg2 compare_mail(oenc, enc) if asstr: msg2 = msg2.as_string() compare_mail(inmsg, msg2)
def test_attach(): attachment = create_mime('some\nattachment') msg = create_mail(sender,receiver,'subject','body\nmessage',attach=[attachment]) # boundary is generated randomly by as_string - hardcode here msg.set_boundary('===============1808028167789866750==') prot = _protected(msg) assert prot.as_string() == msg.as_string() prot = protect_mail(msg,linesep='\n',sevenbit=True) assert prot.as_string() == msg.as_string()
def test_sender_signed_nl(self,unilateral,gpgreceiver): # good self sign id1, id2, sgn = unilateral['id'], gpgreceiver, unilateral['sgn'] sgn = protect_mail(sgn,linesep='\n') raw, verified, result1 = id1.decrypt(sgn,strict=False) verified2, result2 = id1.verify(sgn,strict=False) assert raw and result1 and result2 assert not result1['encrypted'] and verified and result1['signed'] and result2['signed'] and result1['fingerprints'] assert result1['fingerprints']==result2['fingerprints']
def test_sender_signed_nl(self, unilateral, gpgreceiver): # good self sign id1, id2, sgn = unilateral['id'], gpgreceiver, unilateral['sgn'] sgn = protect_mail(sgn, linesep='\n') raw, verified, result1 = id1.decrypt(sgn, strict=False) verified2, result2 = id1.verify(sgn, strict=False) assert raw and result1 and result2 assert not result1['encrypted'] and verified and result1[ 'signed'] and result2['signed'] and result1['fingerprints'] assert result1['fingerprints'] == result2['fingerprints']
def sign(self,ids,msg,inline): id1, id2 = ids['id1'], ids['id2'] prot = protect_mail(msg,linesep='\r\n') sgn,_ = id1.sign(msg,inline=inline) assert sgn and id2.analyze(sgn) == (False,True) mail, verified, result1 = id2.decrypt(sgn) verified2, result2 = id2.verify(sgn) rawmail, signed = id2.strip_signature(sgn) assert mail and verified==verified2 compare_mail(mail,rawmail) assert result1 and result2 assert not result1['encrypted'] and verified and result1['signed'] and result2['signed'] assert result1['fingerprints']==result2['fingerprints'] compare_mail(rawmail,prot)
def sign(self, ids, msg, inline): id1, id2 = ids['id1'], ids['id2'] prot = protect_mail(msg, linesep='\r\n') sgn, _ = id1.sign(msg, inline=inline) assert sgn and id2.analyze(sgn) == (False, True) mail, verified, result1 = id2.decrypt(sgn) verified2, result2 = id2.verify(sgn) rawmail, signed = id2.strip_signature(sgn) assert mail and verified == verified2 compare_mail(mail, rawmail) assert result1 and result2 assert not result1['encrypted'] and verified and result1[ 'signed'] and result2['signed'] assert result1['fingerprints'] == result2['fingerprints'] compare_mail(rawmail, prot)
def bad_sign(self,ids,receiver,msg,encrypt): # id1 signs, but id2 doesn't know id1 id1, id2 = ids['id1'], receiver prot = protect_mail(msg,linesep='\r\n') if encrypt: out,_ = id1.encrypt(msg,sign=True) else: out,_ = id1.sign(msg) assert out if encrypt: assert id2.analyze(out) == (True,None) else: assert id2.analyze(out) == (False,True) mail, verified, result1 = id2.decrypt(out) verified2, result2 = id2.verify(out) assert mail and result1 and result2 assert result1['encrypted']==encrypt and not verified and not verified2 assert result1['signed'] and result2['signed'] assert not result1['fingerprints'] and not result2['fingerprints']
def bad_sign(self, ids, receiver, msg, encrypt): # id1 signs, but id2 doesn't know id1 id1, id2 = ids['id1'], receiver prot = protect_mail(msg, linesep='\r\n') if encrypt: out, _ = id1.encrypt(msg, sign=True) else: out, _ = id1.sign(msg) assert out if encrypt: assert id2.analyze(out) == (True, None) else: assert id2.analyze(out) == (False, True) mail, verified, result1 = id2.decrypt(out) verified2, result2 = id2.verify(out) assert mail and result1 and result2 assert result1[ 'encrypted'] == encrypt and not verified and not verified2 assert result1['signed'] and result2['signed'] assert not result1['fingerprints'] and not result2['fingerprints']
def encode_mail(sender, receiver, data): "data must be validated by check_mail" from kryptomime.mail import create_mail, create_mime, check_charset, protect_mail from time import time as epochtime import email.utils from email.mime.text import MIMEText from six import iteritems from idapi.models import Message subject = data['subject'] time = data.get('date') if not time: time = epochtime() parts = data.get('parts',None) if parts: # multi-part mail = None for i,part in enumerate(parts): ctype = part.get('content-type','text/plain').lower().split('/') encoding = part.get('content-encoding') content = part['content'] content, charset = check_charset(content,part.get('content-charset')) if not i: msg = create_mail(sender,receiver,subject,content,time=time,subtype=ctype[1], charset=charset,encoding=encoding,attach=[]) else: msg = create_mime(content,*ctype,charset=charset,encoding=encoding) filename= part.get('filename') filename = dict(filename=filename) if filename else {} msg.add_header('Content-Disposition', 'attachment', **filename) params = part.get('content-params',{}) if params: for k,v in iteritems(params): msg.set_param(k,v) if i: mail.attach(msg) else: mail = msg else: # single part ctype = data.get('content-type','text/plain').lower().split('/') encoding = data.get('content-encoding') body, charset = check_charset(data['content'],data.get('content-charset')) mail = create_mail(sender,receiver,subject,body,time=time,subtype=ctype[1], charset=charset,encoding=encoding) params = data.get('content-params',{}) if params: for k,v in iteritems(params): mail.set_param(k,v) return protect_mail(mail)
def __iter__(self): from mailbox import Maildir from kryptomime.mail import protect_mail haveflags = isinstance(self.mailbox,Maildir) for key, mail in list(self.mailbox.items()): if haveflags: flags = mail.get_flags() if self.filter and 'S' in flags and not 'F' in flags: continue if not self.readonly: mail.set_subdir('cur') mail.add_flag('F') else: flags = '' if not self.readonly: self.mailbox[key] = mail yield protect_mail(mail,sevenbit=False),flags if self.readonly: continue if self.keep: if haveflags: mail.remove_flag('F') mail.add_flag('S') self.mailbox[key] = mail else: self.mailbox.remove(key)
def __iter__(self): from mailbox import Maildir from kryptomime.mail import protect_mail haveflags = isinstance(self.mailbox,Maildir) for key, mail in list(self.mailbox.items()): if haveflags: flags = mail.get_flags() if self.filter and 'S' in flags and not 'F' in flags: continue if not self.readonly: mail.set_subdir('cur') mail.add_flag('F') else: flags = '' if not self.readonly: self.mailbox[key] = mail yield protect_mail(mail,sevenbit=False),flags if self.readonly: continue if self.keep: if haveflags: mail.remove_flag('F') mail.add_flag('S') self.mailbox[key] = mail else: self.mailbox.remove(key)
def __iter__(self): from kryptomime.mail import protect_mail filter = "(OR UNSEEN FLAGGED)" if self.filter else 'ALL' status, response = self.imap.uid('search', None, filter) if not status=='OK': return email_ids= response[0].split() for e_id in email_ids: status, response = self.imap.uid('fetch',e_id, '(FLAGS)') flags = '' for flag in imaplib.ParseFlags(response[0]): if 'Flagged' in flag: flags += 'F' elif 'Seen' in flag: flags += 'S' elif 'Deleted' in flag: flags += 'D' if 'D' in flags: continue # mark for processing status, response = self.imap.uid('store',e_id, '+FLAGS', r'(\Flagged)') status, response = self.imap.uid('fetch',e_id, '(RFC822)') raw = response[0][1] yield protect_mail(raw,sevenbit=False), flags if self.keep: status,response = self.imap.uid('store',e_id, '-FLAGS', r'(\Flagged)') else: status,response = self.imap.uid('store',e_id, '+FLAGS', r'(\Deleted)')
from kryptomime.mail import create_mail, protect_mail from kryptomime.smime import OpenSMIME, Certificate, PrivateKey, MemoryKeyStore, OpenSSL, OpenSSL_CA import email.mime.text from conftest import sender, receiver from test_openssl import x509keys, openssl passphrase='mysecret' attachment = email.mime.text.MIMEText('some\nattachment') msg = create_mail(sender,receiver,'subject','body\nmessage') msg.epilogue='' msgatt = create_mail(sender,receiver,'subject','body\nmessage',attach=[attachment]) msgrev = create_mail(receiver,sender,'subject','body\nmessage') msgself = create_mail(sender,sender,'subject','body\nmessage') prot = protect_mail(msg,linesep='\r\n') protatt = protect_mail(msgatt,linesep='\r\n') def compare_mail(a,b): if type(a)==str: return a==b assert a.is_multipart() == b.is_multipart() #from kryptomime.mail import ProtectedMessage #assert isinstance(a,ProtectedMessage)==isinstance(b,ProtectedMessage) # todo headers if a.is_multipart(): for i in range(len(a.get_payload())): ap = a.get_payload(i) bp = b.get_payload(i) assert ap.as_string() == bp.as_string() else: assert a.get_payload() == b.get_payload()
def test_8bit(attachments): expect=b'''Content-Type: multipart/mixed; boundary="===============6661726347990728450==" MIME-Version: 1.0 From: Foo <foo@localhost> To: Bar <bar@localhost> Subject: subject Date: Mon, 02 Feb 2015 12:00:00 +0100 --===============6661726347990728450== MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 w7xiZXIKMQoy --===============6661726347990728450== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit uber --===============6661726347990728450== MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 w7xiZXIKMQoy --===============6661726347990728450== MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 w7xiZXIKMQoy --===============6661726347990728450== MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable =C3=BCber 1 2 --===============6661726347990728450== MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit \xc3\xbcber 1 2 --===============6661726347990728450== Content-Type: text/plain; charset="iso8859-1" MIME-Version: 1.0 Content-Transfer-Encoding: base64 /GJlcgoxCjI= --===============6661726347990728450== Content-Type: text/plain; charset="iso8859-1" MIME-Version: 1.0 Content-Transfer-Encoding: base64 /GJlcgoxCjI= --===============6661726347990728450== Content-Type: text/plain; charset="iso8859-1" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable =FCber 1 2 --===============6661726347990728450== Content-Type: text/plain; charset="iso8859-1" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit \xfcber 1 2 --===============6661726347990728450==-- ''' s = u'über\n1\n2' msg = create_mail(sender,receiver,'subject',s,attach=attachments,time='Mon, 02 Feb 2015 12:00:00 +0100') msg.set_boundary('===============6661726347990728450==') out = mail_binary(msg) assert out==expect prot = protect_mail(out,linesep='\n',sevenbit=False) att = prot.get_payload() out2 = mail_binary(prot) assert out==out2 compare_mail(msg,prot)
TODO: 'multipart/encrypted' but single-part, text/plain but encrypted, 'multipart/mixed' but signed """ from conftest import sender, receiver, compare_mail passphrase = 'mysecret' attachment = email.mime.text.MIMEText('some\nattachment') msg = create_mail(sender, receiver, 'subject', 'body\nmessage') msg.epilogue = '' msgatt = create_mail(sender, receiver, 'subject', 'body\nmessage', attach=[attachment]) msgrev = create_mail(receiver, sender, 'subject', 'body\nmessage') msgself = create_mail(sender, sender, 'subject', 'body\nmessage') prot = protect_mail(msg, linesep='\r\n') protatt = protect_mail(msgatt, linesep='\r\n') bools = [False, True] @fixture(scope='module') def keys(request): import os generate = request.config.getoption('generate') verbose = request.config.getoption('gpglog') if verbose: gnupg._logger.create_logger(10) keyrings = [tmpfname() for i in range(2)] secrings = [tmpfname() for i in range(2)] home = os.path.dirname(os.path.abspath(__file__)) fpubkey = [os.path.join(home, 'pubkey%i.asc' % (i + 1)) for i in range(2)] fseckey = [os.path.join(home, 'seckey%i.asc' % (i + 1)) for i in range(2)]