def main(): parser = argparse.ArgumentParser( description='Verify DKIM signature for email messages.', epilog="message to be verified follows commands on stdin") parser.add_argument( '--index', metavar='N', type=int, default=0, help='Index of DKIM signature header to verify: default=0') parser.add_argument('-v', action='store_true', help='Verbose: default=False') args = parser.parse_args() if sys.version_info[0] >= 3: # Make sys.stdin a binary stream. sys.stdin = sys.stdin.detach() message = sys.stdin.read() verbose = args.v import logging logging.basicConfig(format='%(asctime)-15s %(message)s') logger = logging.getLogger('dkimpy') logger.setLevel(logging.DEBUG) if verbose: d = dkim.DKIM(message, logger=logger, debug_content=True) logger.debug("debug level set") else: d = dkim.DKIM(message) res = d.verify(args.index) if not res: print("signature verification failed") sys.exit(1) print("signature ok")
def main(): parser = argparse.ArgumentParser( description='Verify DKIM signature for email messages.', epilog="message to be verified follows commands on stdin") parser.add_argument( '--index', metavar='N', type=int, default=0, help='Index of DKIM signature header to verify: default=0') args = parser.parse_args() if sys.version_info[0] >= 3: # Make sys.stdin a binary stream. sys.stdin = sys.stdin.detach() message = sys.stdin.read() verbose = '-v' in sys.argv if verbose: import logging d = dkim.DKIM(message, logger=logging) else: d = dkim.DKIM(message) res = d.verify(args.index) if not res: print("signature verification failed") sys.exit(1) print("signature ok")
def test_present(self): # Test DKIM.present(). d = dkim.DKIM(self.message, signature_algorithm=b'rsa-sha256') present = d.present() self.assertFalse(present) sig = d.sign(b"test", b"example.com", self.key) signed = sig + self.message d2 = dkim.DKIM(signed) present = d2.present() self.assertTrue(present)
def sign_dkim(self, txt): canon = milterconfig.get('Canonicalization') canonicalize = [] if len(canon.split('/')) == 2: canonicalize.append(canon.split('/')[0]) canonicalize.append(canon.split('/')[1]) else: canonicalize.append(canon) canonicalize.append(canon) if (milterconfig.get('Syslog') and milterconfig.get('debugLevel') >= 1): syslog.syslog('canonicalize: {0}'.format(canonicalize)) try: if privateRSA: d = dkim.DKIM(txt) h = d.sign(milterconfig.get('Selector'), self.fdomain, privateRSA, canonicalize=(canonicalize[0], canonicalize[1])) name, val = h.split(': ', 1) self.addheader(name, val.strip().replace('\r\n', '\n'), 0) if (milterconfig.get('Syslog') and (milterconfig.get('SyslogSuccess') or milterconfig.get('debugLevel') >= 1)): syslog.syslog('{0}: {1} DKIM-Signature field added (s={2} ' 'd={3})'.format(self.getsymval('i'), d.signature_fields.get(b'a'), d.signature_fields.get(b's'), d.domain)) if privateEd25519: d = dkim.DKIM(txt) h = d.sign(milterconfig.get('SelectorEd25519'), self.fdomain, privateEd25519, canonicalize=(canonicalize[0], canonicalize[1]), signature_algorithm='ed25519-sha256') name, val = h.split(': ', 1) self.addheader(name, val.strip().replace('\r\n', '\n'), 0) if (milterconfig.get('Syslog') and (milterconfig.get('SyslogSuccess') or milterconfig.get('debugLevel') >= 1)): syslog.syslog('{0}: {1} DKIM-Signature field added (s={2} ' 'd={3})'.format(self.getsymval('i'), d.signature_fields.get(b'a'), d.signature_fields.get(b's'), d.domain)) except dkim.DKIMException as x: if milterconfig.get('Syslog'): syslog.syslog('DKIM: {0}'.format(x)) except Exception as x: if milterconfig.get('Syslog'): syslog.syslog("sign_dkim: {0}".format(x)) raise
def add_fbl(self, flattened_message): sig = '' mailing = self.recipient.mailing fbl_settings = mailing.get('feedback_loop', {}) if not fbl_settings: return flattened_message dkim_settings = fbl_settings.get('dkim', None) sender_id = fbl_settings.get('sender_id', None) if dkim_settings and sender_id: campaign_id = fbl_settings.get('campaign_id', mailing.id) customer_id = fbl_settings.get('customer_id', mailing.domain_name) mail_type_id = fbl_settings.get('mail_type_id', mailing.type) fbl_header = 'Feedback-ID: %s:%s:%s:%s\n' % ( campaign_id, customer_id, mail_type_id, sender_id) flattened_message = fbl_header + flattened_message d = dkim.DKIM(flattened_message, signature_algorithm=dkim_settings.get( 'signature_algorithm', b'rsa-sha256'), logger=self.log) sig = d.sign( dkim_settings['selector'], dkim_settings['domain'], dkim_settings['privkey'], canonicalize=dkim_settings.get('canonicalize', (b'relaxed', b'simple')), include_headers=dkim_settings.get('include_headers', d.default_sign_headers()) + ['Feedback-ID'], length=dkim_settings.get('length', False), ) sig = str(sig.replace(b'\r\n', b'\n')) # sig is in unicode return sig + flattened_message
def test_degenerate_folding(self): # <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=711751> # degenerate folding is ugly but legal message = read_test_data("test2.message") dv = dkim.DKIM(message) res = dv.verify(dnsfunc=self.dnsfunc) self.assertTrue(res)
def dkim_verify(self, msg, uid): """ Verify DKIM signature(s) from a given RFC822 message Returns a result dict """ try: obj = dkim.DKIM(msg) except Exception as e: self.helper.log_info( 'dkim_verify: exception verifying msg uid %s with %s' % (uid, str(e))) else: sigheaders = [(x, y) for x, y in obj.headers if x.lower() == b"dkim-signature"] self.helper.log_debug( 'dkim_verify: msg uid %s has %d DKIM signatures' % (uid, len(sigheaders))) for i in range(0, len(sigheaders)): try: res = obj.verify(i) except Exception as e: self.helper.log_info( 'dkim_verify: exception verifying msg uid %s with %s' % (uid, str(e))) else: if res: self.helper.log_debug( 'dkim_verify: msg uid %s signature %d ok from domain %s selector %s' % (uid, i, obj.domain, obj.selector)) else: self.helper.log_debug( 'dkim_verify: msg uid %s signature %d fail from domain %s selector %s' % (uid, i, obj.domain, obj.selector))
def test_tenant_dkim_settings(self, smtp): """ test setup where tenant config differs from global settings """ with mock.patch("bluebottle.utils.email_backend.properties", new=mock.Mock([])) as properties: properties.MAIL_CONFIG = {'HOST': 'tenanthost', 'PORT': 4242} properties.DKIM_SELECTOR = "key2" properties.DKIM_DOMAIN = "testserver" properties.DKIM_PRIVATE_KEY = DKIM_PRIVATE_KEY be = TenantAwareBackend() msg = EmailMultiAlternatives(subject="test", body="test", to=["*****@*****.**"]) be.open() connection = be.connection be.send_messages([msg]) to_bytes = lambda s: force_bytes(s, 'utf-8') def _plain_key(s): return b"".join( [l for l in s.split(b'\n') if not l.startswith(b'---')]) signed_msg = connection.sendmail.call_args[0][2] dkim_message = dkim.DKIM(message=to_bytes(signed_msg)) dkim_check = dkim_message.verify(dnsfunc=lambda name: b"".join( [b"v=DKIM1; p=", _plain_key(DKIM_PUBLIC_KEY)])) self.assertTrue(signed_msg.find("d=testserver") >= 0) self.assertTrue(signed_msg.find("s=key2") >= 0) self.assertTrue(dkim_check, "Email should be signed by tenant")
def testDKIM(filename): with open(filename, 'rb') as f: rawemail = f.read() d = dkim.DKIM(rawemail) try: return d.verify() except dkim.ValidationError: return False
def generate_dkim_header(dkim_msg, dkim_para): d = dkim.DKIM(dkim_msg) dkim_header = d.sign(dkim_para["s"], dkim_para["d"], open("dkimkey", "rb").read(), canonicalize=(b'simple', b'relaxed'), include_headers=[b"from"]).strip() + b"\r\n" return dkim_header
def dkim_verify(self, msg, uid): """ Verify DKIM signature(s) from a given RFC822 message Currently only generated debug logging """ try: obj = dkim.DKIM(msg) except Exception, e: self.helper.log_info( 'dkim_verify: exception verifying msg uid %s with %s' % (uid, str(e)))
def test_extra_headers(self): # <https://bugs.launchpad.net/dkimpy/+bug/737311> # extra headers above From caused failure #message = read_test_data("test_extra.message") message = read_test_data("message.mbox") for header_algo in (b"simple", b"relaxed"): for body_algo in (b"simple", b"relaxed"): d = dkim.DKIM(message) # bug requires a repeated header to manifest d.should_not_sign.remove(b'received') sig = d.sign(b"test", b"example.com", self.key, include_headers=d.all_sign_headers(), canonicalize=(header_algo, body_algo)) dv = dkim.DKIM(sig + message) res = dv.verify(dnsfunc=self.dnsfunc) self.assertEquals(d.include_headers,dv.include_headers) s = dkim.select_headers(d.headers,d.include_headers) sv = dkim.select_headers(dv.headers,dv.include_headers) self.assertEquals(s,sv) self.assertTrue(res)
def test_rfc8032_previous_verifies(self): # A message previously signed using RFC 8032 sample keys verifies after being signed. for header_algo in (b"simple", b"relaxed"): for body_algo in (b"simple", b"relaxed"): sig = dkim.sign(self.message3, b"brisbane", b"football.example.com", self.rfckey, canonicalize=(header_algo, body_algo), signature_algorithm=b'ed25519-sha256') d = dkim.DKIM(self.message4) res = d.verify(dnsfunc=self.dnsfunc) self.assertTrue(res)
def test_double_previous_verifies(self): # A message previously signed using both rsa and ed25519 verifies after being signed. for header_algo in (b"simple", b"relaxed"): for body_algo in (b"simple", b"relaxed"): sig = dkim.sign(self.message3, b"test", b"football.example.com", self.key, canonicalize=(header_algo, body_algo), signature_algorithm=b'rsa-sha256') d = dkim.DKIM(self.message4) res = d.verify(dnsfunc=self.dnsfunc5) self.assertTrue(res)
def dkim_verify(self, email): # verify dkim dkim_obj = dkim.DKIM(email.as_string()) try: verified = dkim_obj.verify() except dkim.ValidationError as e: return False except dkim.KeyFormatError as e: return False except Exception as e: print e return False return verified
def check_dkim(msg_bytes, fromAddr, logger): """ :param msg_bytes: bytes :param fromAddr: str :param logger: logger :return: bool Validate the message (passed as a byte sequence, as that's what the dkimpy library wants). """ d = dkim.DKIM(msg_bytes, logger=logger) valid_dkim = d.verify() _, fromDomain = fromAddr.split('@') matching_from = (d.domain != None) and (d.domain.decode('utf8') == fromDomain) return valid_dkim and matching_from
def main(): if sys.version_info[0] >= 3: # Make sys.stdin a binary stream. sys.stdin = sys.stdin.detach() message = sys.stdin.read() verbose = '-v' in sys.argv if verbose: import logging d = dkim.DKIM(message, logger=logging) res = d.verify() else: res = dkim.verify(message) if not res: print("signature verification failed") sys.exit(1) print("signature ok")
def message_has_valid_dkim(sender, msg): d = dkim.DKIM(msg.as_string()) try: if not d.verify(): return False except dkim.DKIMException as x: syslog('error', 'DKIM exception when verifying bounce recipient: %s', x) return False except Exception as x: syslog('error', 'Exception when verifying bounce recipient: %s', x) return False dkim_identity = d.signature_fields.get(b'i') if dkim_identity is not None: return sender.lower() == dkim_identity.lower() else: dkim_domain = d.signature_fields.get(b'd') sender_domain = sender.split('@', 2)[1] return dkim_domain.lower() == sender_domain.lower()
def test_dkim_and_feedback_loop(self): privkey = self._get_dkim_privkey() mailing = factories.MailingFactory(dkim={'selector': 'mail', 'domain': 'unittest.cloud-mailing.net', 'privkey':privkey}, feedback_loop={'dkim': {'selector': 'mail', 'domain': 'unittest.cloud-mailing.net', 'privkey':privkey}, 'sender_id': 'CloudMailing'}) recipient = factories.RecipientFactory(mailing=mailing) message_str = self._customize(recipient) self.assertNotIn(b"\r\n", message_str) parser = email.parser.Parser() message = parser.parsestr(message_str, headersonly=False) assert (isinstance(message, email.message.Message)) self.assertTrue('Feedback-ID' in message) self.assertEqual(2, len(message.get_all('DKIM-Signature'))) d = dkim.DKIM(message_str) self.assertTrue(d.verify(0, dnsfunc=self._get_txt)) self.assertTrue(d.verify(1, dnsfunc=self._get_txt))
def main(): # Backward compatibility hack because argparse doesn't support optional # positional arguments arguments = [ '--' + arg if arg[:8] == 'identity' else arg for arg in sys.argv[1:] ] parser = argparse.ArgumentParser( description='Produce DKIM signature for email messages.', epilog="message to be signed follows commands on stdin") parser.add_argument('selector', action="store") parser.add_argument('domain', action="store") parser.add_argument('privatekeyfile', action="store") parser.add_argument( '--hcanon', choices=['simple', 'relaxed'], default='relaxed', help='Header canonicalization algorithm: default=relaxed') parser.add_argument('--bcanon', choices=['simple', 'relaxed'], default='simple', help='Body canonicalization algorithm: default=simple') parser.add_argument('--signalg', choices=['rsa-sha256', 'ed25519-sha256', 'rsa-sha1'], default='rsa-sha256', help='Signature algorithm: default=rsa-sha256') parser.add_argument('--identity', help='Optional value for i= tag.') args = parser.parse_args(arguments) include_headers = None length = None logger = None if sys.version_info[0] >= 3: args.selector = bytes(args.selector, encoding='UTF-8') args.domain = bytes(args.domain, encoding='UTF-8') if args.identity is not None: args.identity = bytes(args.identity, encoding='UTF-8') args.hcanon = bytes(args.hcanon, encoding='UTF-8') args.bcanon = bytes(args.bcanon, encoding='UTF-8') args.signalg = bytes(args.signalg, encoding='UTF-8') # Make sys.stdin and stdout binary streams. sys.stdin = sys.stdin.detach() sys.stdout = sys.stdout.detach() canonicalize = (args.hcanon, args.bcanon) message = sys.stdin.read() try: d = dkim.DKIM(message, logger=logger, signature_algorithm=args.signalg, linesep=dkim.util.get_linesep(message)) sig = d.sign(args.selector, args.domain, open(args.privatekeyfile, "rb").read(), identity=args.identity, canonicalize=canonicalize, include_headers=include_headers, length=length) sys.stdout.write(sig) sys.stdout.write(message) except Exception as e: print(e, file=sys.stderr) sys.stdout.write(message)
def check_dkim(self, txt): res = False for y in range(self.has_dkim): # Verify _ALL_ the signatures d = dkim.DKIM(txt) try: res = d.verify(idx=y) # added by saku self.dkimdomain = d.domain # ---------- if res: if d.signature_fields.get(b'a') == 'ed25519-sha256': self.dkim_comment = ('Good {0} signature'.format( d.signature_fields.get(b'a'))) else: self.dkim_comment = ( 'Good {0} bit {1} signature'.format( d.keysize, d.signature_fields.get(b'a'))) else: self.dkim_comment = ('Bad {0} bit {1} signature.'.format( d.keysize, d.signature_fields.get(b'a'))) except dkim.DKIMException as x: self.dkim_comment = str(x) if milterconfig.get('Syslog'): syslog.syslog('DKIM: {0}'.format(x)) except Exception as x: self.dkim_comment = str(x) if milterconfig.get('Syslog'): syslog.syslog("check_dkim: {0}".format(x)) self.header_i = d.signature_fields.get(b'i') self.header_d = d.signature_fields.get(b'd') self.header_a = d.signature_fields.get(b'a') if res: if (milterconfig.get('Syslog') and (milterconfig.get('SyslogSuccess') or milterconfig.get('debugLevel') >= 1)): syslog.syslog('{0}: {1} DKIM signature verified (s={2} ' 'd={3})'.format(self.getsymval('i'), d.signature_fields.get(b'a'), d.signature_fields.get(b's'), d.domain)) self.dkim_domain = d.domain else: if milterconfig.get('DiagnosticDirectory'): fd, fname = tempfile.mkstemp(".dkim") with os.fdopen(fd, "w+b") as fp: fp.write(txt) if milterconfig.get('Syslog'): syslog.syslog( 'DKIM: Fail (saved as {0})'.format(fname)) else: syslog.syslog('DKIM: Fail ({0})'.format(d.domain)) if res: self.dkimresult = 'pass' else: self.dkimresult = 'fail' res = False self.arresults.append( authres.DKIMAuthenticationResult( result=self.dkimresult, header_i=self.header_i, header_d=self.header_d, header_a=self.header_a, result_comment=self.dkim_comment)) return
#!/usr/bin/python # Copyright (C) 2014 SIDN Labs # Author: Arjen Zonneveld, Marco Davids, Jelte Jansen # Version 0.1 - 20141008 import dkim import sys try: dKI = dkim.DKIM(message=open('./test.eml').read()) if dKI.verify(): print("DKIM is ok.") sys.exit(0) else: print("DKIM klopt niet!") sys.exit(1) except dkim.ValidationError, dVE: print("Validatiefout: " + str(dVE)) sys.exit(1) except dkim.KeyFormatError, dVE: print("Sleutel-formaat fout: " + str(dVE)) sys.exit(1) except dkim.MessageFormatError, dVE: print("Bericht-formaat fout: " + str(dVE)) sys.exit(1)
def _email_header_validation_using_dkimarc_function( self, event, *args, **kwargs): """Function: Analyzes the DKIM and ARC headers for an RFC822 formatted email.""" try: # Get the function parameters: email_header_validation_target_email = kwargs.get( "email_header_validation_target_email") # text incident_id = kwargs.get('incident_id') # number attachment_id = kwargs.get('attachment_id') # number artifact_id = kwargs.get('artifact_id') # number if email_header_validation_target_email is None and incident_id is None: raise FunctionError( 'Either an RFC822 email must be provided or an incident id and attachment_id ' 'or artifact_id must be provided') log = logging.getLogger(__name__) log.info("email_header_validation_target_email: %s", email_header_validation_target_email) yield StatusMessage("Analyzing email headers") # Initialize DKIM object from string or attachment and check for DKIM header if email_header_validation_target_email: target_email = email_header_validation_target_email else: client = self.rest_client() target_email = get_content(client, incident_id, attachment_id, artifact_id) dkim_email = dkim.DKIM(target_email) dkim_header_exists = b"dkim-signature" in [ header[0].lower() for header in dkim_email.headers ] # Do header analysis dkim_results = dkim.dkim_verify(target_email) arc_results = dkim.arc_verify(target_email) if arc_results == 'success': arc_results = 'Validation successful' # Form DKIM results statement if dkim_header_exists: if dkim_results: dkim_message = 'Validation successful' else: dkim_message = 'Most recent DKIM-Message-Signature did not validate' else: dkim_message = 'Message is not DKIM signed' results = { "dkim_verify": dkim_results, "arc_verify": arc_results[0] == 'pass', "dkim_message": dkim_message, "arc_message": arc_results[2] } # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def SendMail(to, template, params={}, templateFromFile=True, dkimKeys=None, dkimSelector=None): """ sends email to @to if @templateFromFile == True message will be taken from @template _file_ and from @template as a string else. template should have header and content section (separated with mail.utils.HEADER_TAG, mail.utils.CONTENT_TAG). For example: {% load email_tags %} {% email_header %} # will be replaced with mail.utils.HEADER_TAG[0] Subject: foo To: [email protected] From: [email protected] {% email_endheader %} # mail.utils.HEADER_TAG[1] {% email_content %} # mail.utils.CONTENT_TAG[0] blahblahblah {% email_endcontent %} # mail.utils.CONTENT_TAG[1] @params are used tor rendering the template @dkimKeys is a pair (private=priv_key, public=pub_key). if None, settings.EMAIL_DKIM_KEYS will be taken. if there aren't such keys, the mail won't be signed with dkim! @dkimSelector is a selector for dkim. if None, settings.EMAIL_DKIM_SELECTOR will be taken """ if not settings.ENABLE_EMAIL: return fr = "*****@*****.**" params.update({ "to_email": to, "fr_email": fr, "hostAddr": settings.CURRENT_HOST }) if templateFromFile: rawmsg = templates.render_to_string(template, params) else: t = templates.Template(template) rawmsg = t.render(templates.Context(params)) rawmsg = rawmsg.replace("\r\n", "\n") rawheaders = _ExtractTags(rawmsg, HEADER_TAG, exactlyOne=True) if rawheaders: headers = {} for rawh in rawheaders.split("\n"): if rawh.strip() == "": continue header = rawh.split(": ") if len(header) != 2: raise MailErr("Something wrong with header: got {} tokens: {}".format(len(header), header)) headers[header[0].strip()] = header[1].strip() else: headers = {} content = _ExtractTags(rawmsg, CONTENT_TAG, exactlyOne=True) if not content: raise NoMailContent("Content is empty") msg = MIMEText(content) for hname, hval in headers.items(): msg[hname] = hval if dkimKeys: rsaKeys = dkimKeys elif settings.EMAIL_DKIM_KEYS: rsaKeys = settings.EMAIL_DKIM_KEYS else: rsaKeys = None if rsaKeys: dkimmsg = dkim.DKIM(str(msg).encode("utf-8")) if dkimSelector: dkimsel = dkimSelector else: dkimsel = settings.EMAIL_DKIM_SELECTOR dkimsel = dkimsel.encode("utf-8") dkimdomain = settings.EMAIL_DKIM_DOMAIN.encode("utf-8") dkimkey = rsaKeys.private.encode("utf-8") sig = dkimmsg.sign(dkimsel, dkimdomain, dkimkey).decode('ascii') sigh, sigc = tuple(sig.split(': ', 1)) msg[sigh] = sigc sm = smtplib.SMTP("localhost") sm.sendmail(fr, to, str(msg)) sm.quit()
# 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # # Copyright (c) 2008 Greg Hewgill http://hewgill.com # # This has been modified from the original software. # Copyright (c) 2011 William Grant <*****@*****.**> from __future__ import print_function import sys import dkim if sys.version_info[0] >= 3: # Make sys.stdin a binary stream. sys.stdin = sys.stdin.detach() message = sys.stdin.read() verbose = '-v' in sys.argv if verbose: d = dkim.DKIM(message) res = d.verify() else: res = dkim.verify(message) if not res: print("signature verification failed") sys.exit(1) print("signature ok")
def test_catch_bad_key(self): # Raise correct error for defective public key. d = dkim.DKIM(self.message5) res = d.verify(dnsfunc=self.dnsfunc6) self.assertFalse(res)
def _verifyDkimOrigin(signed_message): """Find a From or Sender address for which there's a DKIM signature. :returns: A string email address for the trusted sender, if there is one, otherwise None. :param signed_message: ISignedMessage """ log = logging.getLogger('mail-authenticate-dkim') log.setLevel(logging.DEBUG) if getFeatureFlag('mail.dkim_authentication.disabled'): log.info('dkim authentication feature disabled') return None # uncomment this for easier test debugging # log.addHandler(logging.FileHandler('/tmp/dkim.log')) dkim_log = BufferLogger() log.info( 'Attempting DKIM authentication of message id=%r from=%r sender=%r' % (signed_message['Message-ID'], signed_message['From'], signed_message['Sender'])) dkim_checker = None dkim_result = False try: dkim_checker = dkim.DKIM(signed_message.parsed_string, logger=dkim_log) dkim_result = dkim_checker.verify() except dkim.DKIMException as e: log.info('DKIM error: %r' % (e, )) except dns.exception.DNSException as e: # This can easily happen just through bad input data, eg. claiming to # be signed by a domain with no visible key of that name. It's not an # operational error. log.info('DNS exception: %r' % (e, )) except Exception as e: # DKIM leaks some errors when it gets bad input, as in bug 881237. We # don't generally want them to cause the mail to be dropped entirely # though. It probably is reasonable to treat them as potential # operational errors, at least until they're handled properly, by # making pydkim itself more defensive. log.warning( 'unexpected error in DKIM verification, treating as unsigned: %r' % (e, )) log.info('DKIM verification result: trusted=%s' % (dkim_result, )) log.debug('DKIM debug log: %s' % (dkim_log.getLogBuffer(), )) if not dkim_result: return None # in addition to the dkim signature being valid, we have to check that it # was actually signed by the user's domain. signing_domain = dkim_checker.domain if not _isDkimDomainTrusted(signing_domain): log.info("valid DKIM signature from untrusted domain %s" % (signing_domain, )) return None for origin in ['From', 'Sender']: if signed_message[origin] is None: continue name, addr = parseaddr(signed_message[origin]) try: origin_domain = addr.split('@')[1] except IndexError: log.warning("couldn't extract domain from address %r", signed_message[origin]) if signing_domain == origin_domain: log.info("DKIM signing domain %s matches %s address %r", signing_domain, origin, addr) return addr else: log.info("DKIM signing domain %s doesn't match message origin; " "disregarding signature" % (signing_domain)) return None
def dkim_vrfy(message): PYDNS_AVAILABLE = False DNSPYTHON_AVAILABLE = False # check dns libraries try: import dns DNSPYTHON_AVAILABLE = True except ImportError: pass try: import DNS PYDNS_AVAILABLE = True except ImportError: pass try: from dkim import DKIM, verify, DKIMException if not (PYDNS_AVAILABLE or DNSPYTHON_AVAILABLE): raise Exception("no supported dns library available") except: pass try: import dkim if True: d = dkim.DKIM(message) #print 'dir:',dir(d) #print 'sel:',d.selector #print 'dom:',d.domain #print 'h:',d.headers #print 'sh:',d.signed_headers #print 'sa:',d.signature_algorithm #print 'sf:',d.signature_fields #print 'ks:',d.keysize r = d.verify() fpr('Signature details') fpr('_' * (tc - 4)) print fpr(' selector (s): %s' % d.selector) fpr(' domain (d): %s' % d.domain) fpr(' headers : %s' % d.headers) fpr(' signed heads: %s' % d.signed_headers) fpr(' key algo (a): %s' % d.signature_algorithm) fpr(' key size : %s' % d.keysize) print fpr(' DKIM-Signature: %s' % d.signature_fields) fpr('_' * (tc - 4)) print else: r = dkim.verify(message) if r: fpr.ok("DKIM signature verification successful") else: fpr.fail("DKIM signature verification failed") except DKIMException, e: fpr("Verification result:") print fpr('%s' % e) print fpr.fail("DKIM signature verification failed")