Пример #1
0
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")
Пример #2
0
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")
Пример #3
0
 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)
Пример #4
0
 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
Пример #5
0
 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
Пример #6
0
 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)
Пример #7
0
 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))
Пример #8
0
    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")
Пример #9
0
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
Пример #10
0
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
Пример #11
0
 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)))
Пример #12
0
 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)
Пример #13
0
 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)
Пример #14
0
 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)
Пример #15
0
    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
Пример #16
0
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
Пример #17
0
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")
Пример #18
0
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()
Пример #19
0
    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))
Пример #20
0
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)
Пример #21
0
 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
Пример #22
0
#!/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()
Пример #24
0
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()
Пример #25
0
# 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")
Пример #26
0
 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)
Пример #27
0
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
Пример #28
0
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")