Ejemplo n.º 1
0
 def test_multiple_from_fails(self):
     # <https://bugs.launchpad.net/dkimpy/+bug/644046>
     # additional From header fields should cause verify failure
     hfrom = b'From: "Resident Evil" <*****@*****.**>\r\n'
     h, b = self.message.split(b'\n\n', 1)
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(self.message,
                             b"test",
                             b"example.net",
                             self.key,
                             signature_algorithm=b'ed25519-sha256')
             # adding an unknown header still verifies
             h1 = h + b'\r\n' + b'X-Foo: bar'
             message = b'\n\n'.join((h1, b))
             res = dkim.verify(sig + message, dnsfunc=self.dnsfunc)
             self.assertTrue(res)
             # adding extra from at end should not verify
             h1 = h + b'\r\n' + hfrom.strip()
             message = b'\n\n'.join((h1, b))
             res = dkim.verify(sig + message, dnsfunc=self.dnsfunc)
             self.assertFalse(res)
             # add extra from in front should not verify either
             h1 = hfrom + h
             message = b'\n\n'.join((h1, b))
             res = dkim.verify(sig + message, dnsfunc=self.dnsfunc)
             self.assertFalse(res)
Ejemplo n.º 2
0
    def test_dkim_mail(self):
        settings.AWS_SES_CONFIGURATION_SET = None
        # DKIM verification uses DNS to retrieve the public key when checking
        # the signature, so we need to replace the standard query response with
        # one that always returns the test key.
        try:
            import dkim
            import dns
        except ImportError:
            return

        def dns_query(qname, rdtype):
            name = dns.name.from_text(qname)
            response = dns.message.from_text(
                    'id 1\n;ANSWER\n%s 60 IN TXT "v=DKIM1; p=%s"' %\
                            (qname, DKIM_PUBLIC_KEY))
            return dns.resolver.Answer(name, rdtype, 1, response)

        dns.resolver.query = dns_query

        settings.DKIM_DOMAIN = 'example.com'
        settings.DKIM_PRIVATE_KEY = DKIM_PRIVATE_KEY
        send_mail('subject', 'body', '*****@*****.**', ['*****@*****.**'])
        message = self.outbox.pop()['raw_message']
        self.assertTrue(dkim.verify(message))
        self.assertFalse(dkim.verify(message + 'some additional text'))
        self.assertFalse(
            dkim.verify(message.replace('*****@*****.**', '*****@*****.**')))
Ejemplo n.º 3
0
    def test_dkim_mail(self):
        # DKIM verification uses DNS to retrieve the public key when checking
        # the signature, so we need to replace the standard query response with
        # one that always returns the test key.
        try:
            import dkim
            import dns
        except ImportError:
            return

        def dns_query(qname, rdtype):
            name = dns.name.from_text(qname)
            response = dns.message.from_text(
                    'id 1\n;ANSWER\n%s 60 IN TXT "v=DKIM1; p=%s"' %\
                            (qname, DKIM_PUBLIC_KEY))
            return dns.resolver.Answer(name, rdtype, 1, response)
        dns.resolver.query = dns_query

        settings.DKIM_DOMAIN = 'example.com'
        settings.DKIM_PRIVATE_KEY = DKIM_PRIVATE_KEY
        send_mail('subject', 'body', '*****@*****.**', ['*****@*****.**'])
        message = self.outbox.pop()['raw_message']
        self.assertTrue(dkim.verify(message))
        self.assertFalse(dkim.verify(message + 'some additional text'))
        self.assertFalse(dkim.verify(
                            message.replace('*****@*****.**', '*****@*****.**')))
Ejemplo n.º 4
0
    def test_sendmail_dkim(self):
        config.config.set('accounting', 'dkim_privkey', os.path.join(
            os.path.dirname(__file__), 'dkim_test.private'))
        config.config.set('accounting', 'dkim_domain', 'example.org')
        config.config.set('accounting', 'smtp_domain', 'test.example.org')
        config.config.set('accounting', 'smtp_to_filter', '.*@example')

        pubkey = open(os.path.join(
            os.path.dirname(__file__), 'dkim_test.txt'),'rb').read()

        body = u'räksmörgås'
        subject = u'Räksmörgåsar!'
        to = u'"Mr. Räksmörgås" <foo@example>'

        fromaddr, all_rcpts, message = mail.makemail(
            body, subject=subject, to=to)

        mail.sendmail(fromaddr, all_rcpts, message)
        smtp, = self.smtps
        message = smtp._sendmail[0][2]

        assert dkim.verify(message, dnsfunc=lambda *_: pubkey)
        assert b'[email protected]' in message

        fromaddr, all_rcpts, message = mail.makemail(
            body, subject=subject, to=to)

        mail.sendmail(fromaddr, all_rcpts, message, identity='foo')
        smtp = self.smtps[1]
        message = smtp._sendmail[0][2]

        assert dkim.verify(message, dnsfunc=lambda *_: pubkey)
        assert b'[email protected]' in message
Ejemplo n.º 5
0
    def test_dkim_signature_canonicalization(self):
        # <https://bugs.launchpad.net/ubuntu/+source/pydkim/+bug/587783>
        # Relaxed-mode header signing is wrong
        # <https://bugs.launchpad.net/dkimpy/+bug/939128>
        # Simple-mode signature header verification is wrong
        # (should ignore FWS anywhere in signature tag: b=)
        sample_msg = b"""\
From: [email protected]
To: [email protected]
Subject: this is my
    test message
""".replace(b'\n', b'\r\n')

        sample_privkey = b"""\
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBANmBe10IgY+u7h3enWTukkqtUD5PR52Tb/mPfjC0QJTocVBq6Za/
PlzfV+Py92VaCak19F4WrbVTK5Gg5tW220MCAwEAAQJAYFUKsD+uMlcFu1D3YNaR
EGYGXjJ6w32jYGJ/P072M3yWOq2S1dvDthI3nRT8MFjZ1wHDAYHrSpfDNJ3v2fvZ
cQIhAPgRPmVYn+TGd59asiqG1SZqh+p+CRYHW7B8BsicG5t3AiEA4HYNOohlgWan
8tKgqLJgUdPFbaHZO1nDyBgvV8hvWZUCIQDDdCq6hYKuKeYUy8w3j7cgJq3ih922
2qNWwdJCfCWQbwIgTY0cBvQnNe0067WQIpj2pG7pkHZR6qqZ9SE+AjNTHX0CIQCI
Mgq55Y9MCq5wqzy141rnxrJxTwK9ABo3IAFMWEov3g==
-----END RSA PRIVATE KEY-----
"""

        sample_pubkey = """\
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANmBe10IgY+u7h3enWTukkqtUD5PR52T
b/mPfjC0QJTocVBq6Za/PlzfV+Py92VaCak19F4WrbVTK5Gg5tW220MCAwEAAQ==
-----END PUBLIC KEY-----
"""

        for header_mode in [dkim.Relaxed, dkim.Simple]:

            dkim_header = dkim.sign(sample_msg,
                                    b'example',
                                    b'canonical.com',
                                    sample_privkey,
                                    canonicalize=(header_mode, dkim.Relaxed))
            # Folding dkim_header affects b= tag only, since dkim.sign folds
            # sig_value with empty b= before hashing, and then appends the
            # signature.  So folding dkim_header again adds FWS to
            # the b= tag only.  This should be ignored even with
            # simple canonicalization.
            # http://tools.ietf.org/html/rfc4871#section-3.5
            signed = dkim.fold(dkim_header) + sample_msg
            result = dkim.verify(signed, dnsfunc=self.dnsfunc, minkey=512)
            self.assertTrue(result)
            dkim_header = dkim.fold(dkim_header)
            # use a tab for last fold to test tab in FWS bug
            pos = dkim_header.rindex(b'\r\n ')
            dkim_header = dkim_header[:pos] + b'\r\n\t' + dkim_header[pos + 3:]
            result = dkim.verify(dkim_header + sample_msg,
                                 dnsfunc=self.dnsfunc,
                                 minkey=512)
            self.assertTrue(result)
Ejemplo n.º 6
0
    def test_dkim_signature_canonicalization(self):
      # <https://bugs.launchpad.net/ubuntu/+source/pydkim/+bug/587783>
      # Relaxed-mode header signing is wrong
      # <https://bugs.launchpad.net/dkimpy/+bug/939128>
      # Simple-mode signature header verification is wrong
      # (should ignore FWS anywhere in signature tag: b=)
      sample_msg = b"""\
From: [email protected]
To: [email protected]
Subject: this is my
    test message
""".replace(b'\n', b'\r\n')

      sample_privkey = b"""\
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBANmBe10IgY+u7h3enWTukkqtUD5PR52Tb/mPfjC0QJTocVBq6Za/
PlzfV+Py92VaCak19F4WrbVTK5Gg5tW220MCAwEAAQJAYFUKsD+uMlcFu1D3YNaR
EGYGXjJ6w32jYGJ/P072M3yWOq2S1dvDthI3nRT8MFjZ1wHDAYHrSpfDNJ3v2fvZ
cQIhAPgRPmVYn+TGd59asiqG1SZqh+p+CRYHW7B8BsicG5t3AiEA4HYNOohlgWan
8tKgqLJgUdPFbaHZO1nDyBgvV8hvWZUCIQDDdCq6hYKuKeYUy8w3j7cgJq3ih922
2qNWwdJCfCWQbwIgTY0cBvQnNe0067WQIpj2pG7pkHZR6qqZ9SE+AjNTHX0CIQCI
Mgq55Y9MCq5wqzy141rnxrJxTwK9ABo3IAFMWEov3g==
-----END RSA PRIVATE KEY-----
"""

      sample_pubkey = """\
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANmBe10IgY+u7h3enWTukkqtUD5PR52T
b/mPfjC0QJTocVBq6Za/PlzfV+Py92VaCak19F4WrbVTK5Gg5tW220MCAwEAAQ==
-----END PUBLIC KEY-----
"""

      for header_mode in [dkim.Relaxed, dkim.Simple]:

        dkim_header = dkim.sign(sample_msg, b'example', b'canonical.com',
            sample_privkey, canonicalize=(header_mode, dkim.Relaxed))
        # Folding dkim_header affects b= tag only, since dkim.sign folds
        # sig_value with empty b= before hashing, and then appends the
        # signature.  So folding dkim_header again adds FWS to
        # the b= tag only.  This should be ignored even with
        # simple canonicalization.  
        # http://tools.ietf.org/html/rfc4871#section-3.5
        signed = dkim.fold(dkim_header) + sample_msg
        result = dkim.verify(signed,dnsfunc=self.dnsfunc,
                minkey=512)
        self.assertTrue(result)
        dkim_header = dkim.fold(dkim_header)
        # use a tab for last fold to test tab in FWS bug
        pos = dkim_header.rindex(b'\r\n ')
        dkim_header = dkim_header[:pos]+b'\r\n\t'+dkim_header[pos+3:]
        result = dkim.verify(dkim_header + sample_msg,
                dnsfunc=self.dnsfunc, minkey=512)
        self.assertTrue(result)
Ejemplo n.º 7
0
 def test_add_body_length(self):
     sig = dkim.sign(
         self.message, b"test", b"example.com", self.key, length=True)
     msg = email.message_from_string(self.message.decode('utf-8'))
     self.assertIn('; l=%s' % len(msg.get_payload() + '\n'), sig.decode('utf-8'))
     res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc)
     self.assertTrue(res)
Ejemplo n.º 8
0
 def test_email_signed(self):
     """Verify e-mail signature."""
     out = StringIO()
     email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**'])
     sent = get_connection(stream=out).send_messages([email])
     self.assertEqual(sent, 1)
     match = re.match('^(.*)\n-{79}\n$', out.getvalue(), flags=re.DOTALL)
     self.assertTrue(dkim.verify(bytes(match.group(1), 'utf-8'), dnsfunc=lambda x: DNS_TXT_RECORD))
Ejemplo n.º 9
0
    def test_dkim_signature_canonicalization(self):
        # <https://bugs.launchpad.net/ubuntu/+source/pydkim/+bug/587783>
        # Relaxed-mode header signing is wrong
        # <https://bugs.launchpad.net/dkimpy/+bug/939128>
        # Simple-mode signature header verification is wrong
        # (should ignore FWS anywhere in signature tag: b=)
        sample_msg = b"""\
From: [email protected]
To: [email protected]
Subject: this is my
    test message
""".replace(b'\n', b'\r\n')

        sample_privkey = b"""\
fL+5V9EquCZAovKik3pA6Lk9zwCzoEtjIuIqK9ZXHHA=\
"""

        sample_pubkey = """\
yi50DjK5O9pqbFpNHklsv9lqaS0ArSYu02qp1S0DW1Y=\
"""

        for header_mode in [dkim.Relaxed, dkim.Simple]:

            dkim_header = dkim.sign(sample_msg,
                                    b'example',
                                    b'canonical.com',
                                    sample_privkey,
                                    canonicalize=(header_mode, dkim.Relaxed),
                                    signature_algorithm=b'ed25519-sha256')
            # Folding dkim_header affects b= tag only, since dkim.sign folds
            # sig_value with empty b= before hashing, and then appends the
            # signature.  So folding dkim_header again adds FWS to
            # the b= tag only.  This should be ignored even with
            # simple canonicalization.
            # http://tools.ietf.org/html/rfc4871#section-3.5
            signed = dkim.fold(dkim_header) + sample_msg
            result = dkim.verify(signed, dnsfunc=self.dnsfunc)
            self.assertTrue(result)
            dkim_header = dkim.fold(dkim_header)
            # use a tab for last fold to test tab in FWS bug
            pos = dkim_header.rindex(b'\r\n ')
            dkim_header = dkim_header[:pos] + b'\r\n\t' + dkim_header[pos + 3:]
            result = dkim.verify(dkim_header + sample_msg,
                                 dnsfunc=self.dnsfunc)
            self.assertTrue(result)
Ejemplo n.º 10
0
 def test_verifies(self):
     # A message verifies after being signed.
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(
                 self.message, b"test", b"example.com", self.key,
                 canonicalize=(header_algo, body_algo))
             res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc)
             self.assertTrue(res)
Ejemplo n.º 11
0
 def test_altered_body_fails(self):
     # An altered body fails verification.
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(self.message, b"test", b"example.com",
                             self.key)
             res = dkim.verify(sig + self.message + b"foo",
                               dnsfunc=self.dnsfunc)
             self.assertFalse(res)
Ejemplo n.º 12
0
 def test_badly_encoded_domain_fails(self):
     # Domains should be ASCII. Bad ASCII causes verification to fail.
     sig = dkim.sign(self.message,
                     b"test",
                     b"example.net\xe9",
                     self.key,
                     signature_algorithm=b'ed25519-sha256')
     res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc)
     self.assertFalse(res)
Ejemplo n.º 13
0
def main():
    msg = sys.stdin.read()
    res = None
    res = dkim.verify(msg)

    print('[' + os.path.basename(__file__) + '] isDkimValid = ' + str(res))
    if not res:
        # Invalid signature, exit with code 11.
        sys.exit(11)
Ejemplo n.º 14
0
 def test_verifies(self):
     # A message verifies after being signed.
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(
                 self.message, b"test", b"example.com", self.key,
                 canonicalize=(header_algo, body_algo))
             res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc)
             self.assertTrue(res)
Ejemplo n.º 15
0
def main():
    msg = sys.stdin.read()
    res = None
    res = dkim.verify(msg)

    print('[' + os.path.basename(__file__) + '] isDkimValid = ' + str(res))
    if not res:
        # Invalid signature, exit with code 11.
        sys.exit(11)
Ejemplo n.º 16
0
 def test_altered_body_fails(self):
     # An altered body fails verification.
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(
                 self.message, b"test", b"example.com", self.key)
             res = dkim.verify(
                 sig + self.message + b"foo", dnsfunc=self.dnsfunc)
             self.assertFalse(res)
Ejemplo n.º 17
0
 def test_simple_signature(self):
     # A message verifies after being signed with SHOULD headers
     for header_algo in (b"simple", b"relaxed"):
          for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(
                 self.message, b"test", b"example.com", self.key,
                 canonicalize=(header_algo, body_algo),
                 include_headers=(b'from',) + dkim.DKIM.SHOULD)
             res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc)
             self.assertTrue(res)
Ejemplo n.º 18
0
def verify_dkim_sig(crypto_message):
    ''' Verify DKIM signature if option selected and header exists. '''

    verified_sig = False
    if crypto_message.get_email_message().get_header(
            'DKIM-Signature') is not None:
        log_message('trying to verify DKIM signature')
        try:
            global _log

            crypto_message.set_dkim_signed(True)

            charset, __ = get_charset(crypto_message.get_email_message())
            log_message('dkim message char set: {}'.format(charset))

            message = crypto_message.get_email_message().to_string().encode()
            if DEBUGGING:
                log_message('headers before DKIM verification:\n{}'.format(
                    crypto_message.get_email_message().get_header_lines()))
                log_message('message:\n{}'.format(message))

            if DKIM_VERIFICATION_ACTIVE:
                verified_sig = dkim.verify(message, logger=_log)
                log_message('DKIM signature verified: {}'.format(verified_sig))

                if verified_sig:
                    crypto_message.get_email_message().delete_header(
                        'DKIM-Signature')
                    crypto_message.set_dkim_sig_verified(True)
                elif options.dkim_delivery_policy() == DKIM_WARN_POLICY:
                    crypto_message.get_email_message().delete_header(
                        'DKIM-Signature')
                    log_message('dkim policy is to warn and accept message')
                else:
                    raise DKIMException(
                        "Unable to verify message originated on sender's mail server."
                    )
            else:
                verified_sig = True  # !!!!! fix dkim in python3
                log_message('unable to verify dkim sig with python3')
        except dkim.DKIMException as dkim_exception:
            if options.dkim_delivery_policy() == DKIM_WARN_POLICY:
                crypto_message.get_email_message().delete_header(
                    'DKIM-Signature')
                log_message(
                    'dkim policy is to warn; {}'.format(dkim_exception))
            else:
                raise dkim.DKIMException(str(dkim_exception))
        except:
            log_message('EXCEPTION - see syr.exception.log for details')
            record_exception()
    else:
        verified_sig = False

    return crypto_message, verified_sig
Ejemplo n.º 19
0
 def test_unknown_k(self):
     # A error is detected if an unknown algorithm is in the k= tag.
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(self.message,
                             b"test",
                             b"example.com",
                             self.key,
                             canonicalize=(header_algo, body_algo))
             res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc4)
             self.assertFalse(res)
Ejemplo n.º 20
0
 def test_bad_version(self):
     # A error is detected if a bad version is used.
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(self.message,
                             b"test",
                             b"example.com",
                             self.key,
                             canonicalize=(header_algo, body_algo))
             res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc3)
             self.assertFalse(res)
Ejemplo n.º 21
0
 def test_ignores_tlsrptsvc(self):
     # A non-tlsrpt signed with a key record with s=tlsrpt shouldn't verify.
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(self.message,
                             b"test",
                             b"example.com",
                             self.key,
                             canonicalize=(header_algo, body_algo))
             res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc6)
             self.assertFalse(res)
Ejemplo n.º 22
0
def verify_dkim(path):
    '''
    Verify DKIM signature of an e-mail file.

    :param path: Path to the e-mail file.
    :returns: Whether DKIM signature is valid or not.
    '''
    with open(path, 'rb') as message_file:
        message_bytes = message_file.read()

    return dkim.verify(message_bytes)
Ejemplo n.º 23
0
 def test_double_verifies(self):
     # A message also containing a ed25519 signature verifies after being signed with rsa.
     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')
             res = dkim.verify(sig + self.message3, dnsfunc=self.dnsfunc5)
             self.assertTrue(res)
Ejemplo n.º 24
0
 def test_rfc8032_verifies(self):
     # A message 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')
             res = dkim.verify(sig + self.message3, dnsfunc=self.dnsfunc)
             self.assertTrue(res)
Ejemplo n.º 25
0
 def test_string_include(self):
     # A message can be signed when the include_headers is string
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(self.message,
                             b"test",
                             b"example.com",
                             self.key,
                             canonicalize=(header_algo, body_algo),
                             include_headers=('from', ))
             res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc)
             self.assertTrue(res)
Ejemplo n.º 26
0
 def test_l_verify(self):
     # Sign with l=, add text, should verify
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(self.message,
                             b"test",
                             b"example.com",
                             self.key,
                             canonicalize=(header_algo, body_algo),
                             length=True)
             self.message += b'added more text\n'
             res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc)
             self.assertTrue(res)
Ejemplo n.º 27
0
 def test_tlsrpt_with_no_tlsrptsvc(self):
     # A tlsrpt signed with a key record without s=tlsrpt and tlsrpt=True should verify.
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(self.message,
                             b"test",
                             b"example.com",
                             self.key,
                             canonicalize=(header_algo, body_algo))
             res = dkim.verify(sig + self.message,
                               dnsfunc=self.dnsfunc,
                               tlsrpt=True)
             self.assertTrue(res)
Ejemplo n.º 28
0
    def test_email_signed(self, mock_smtp):
        """Test sending signed email over SMTP."""

        email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**'])
        sent = get_connection().send_messages([email])
        self.assertEqual(sent, 1)

        instance = mock_smtp.return_value
        self.assertEqual(instance.sendmail.call_count, 1)
        args, kwargs = instance.sendmail.call_args
        self.assertEqual(args[0], '*****@*****.**')
        self.assertEqual(args[1], ['*****@*****.**'])
        self.assertTrue(dkim.verify(args[2], dnsfunc=lambda x: DNS_TXT_RECORD))
Ejemplo n.º 29
0
def _test_email_with_dkim(include_headers):
    from yagmail import SMTP
    from yagmail.dkim import DKIM

    private_key_path = Path(__file__).parent / "privkey.pem"

    private_key = private_key_path.read_bytes()

    dkim_obj = DKIM(
        domain=b"a.com",
        selector=b"selector",
        private_key=private_key,
        include_headers=include_headers,
    )

    yag = SMTP(
        user="******",
        host="smtp.blabla.com",
        port=25,
        dkim=dkim_obj,
    )

    yag.login = Mock()

    to = "*****@*****.**"

    recipients, msg_bytes = yag.send(to=to,
                                     subject="hello from tests",
                                     contents="important message",
                                     preview_only=True)

    msg_string = msg_bytes.decode("utf8")

    assert recipients == [to]
    assert "Subject: hello from tests" in msg_string
    text_b64 = base64.b64encode(b"important message").decode("utf8")
    assert text_b64 in msg_string

    dkim_string1 = "DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=a.com; [email protected];\n " \
                   "q=dns/txt; s=selector; t="
    assert dkim_string1 in msg_string

    l = logging.getLogger()
    l.setLevel(level=logging.DEBUG)
    logging.basicConfig(level=logging.DEBUG)

    assert dkim.verify(message=msg_string.encode("utf8"),
                       logger=l,
                       dnsfunc=get_txt_from_test_file)

    return msg_string
Ejemplo n.º 30
0
 def test_tlsrpt_ignore_l_sign(self):
     # For a tlsrpt, don't add l= when signing tlsrpt
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(self.message,
                             b"test",
                             b"example.com",
                             self.key,
                             canonicalize=(header_algo, body_algo),
                             length=True,
                             tlsrpt=True)
             self.message += b'added more text'
             res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc)
             self.assertFalse(res)
Ejemplo n.º 31
0
def verify_dkim(path):
    """
    Verify DKIM signature of an e-mail file.

    :param path: Path to the e-mail file.
    :returns: Whether DKIM signature is valid or not.
    """
    with open(path, 'rb') as message_file:
        message_bytes = message_file.read()

    try:
        return dkim.verify(message_bytes)
    except (dns.exception.DNSException, dkim.DKIMException) as exception:
        raise DKIMVerifyError(str(exception)) from exception
Ejemplo n.º 32
0
 def test_multiple_from_fails(self):
     # <https://bugs.launchpad.net/dkimpy/+bug/644046>
     # additional From header fields should cause verify failure
     hfrom = b'From: "Resident Evil" <*****@*****.**>\r\n'
     h,b = self.message.split(b'\n\n',1)
     for header_algo in (b"simple", b"relaxed"):
         for body_algo in (b"simple", b"relaxed"):
             sig = dkim.sign(
                 self.message, b"test", b"example.com", self.key)
             # adding an unknown header still verifies
             h1 = h+b'\r\n'+b'X-Foo: bar'
             message = b'\n\n'.join((h1,b))
             res = dkim.verify(sig+message, dnsfunc=self.dnsfunc)
             self.assertTrue(res)
             # adding extra from at end should not verify
             h1 = h+b'\r\n'+hfrom.strip()
             message = b'\n\n'.join((h1,b))
             res = dkim.verify(sig+message, dnsfunc=self.dnsfunc)
             self.assertFalse(res)
             # add extra from in front should not verify either
             h1 = hfrom+h
             message = b'\n\n'.join((h1,b))
             res = dkim.verify(sig+message, dnsfunc=self.dnsfunc)
             self.assertFalse(res)
Ejemplo n.º 33
0
def verify_dkim_sig(crypto_message):
    ''' Verify DKIM signature if option selected and header exists. '''

    verified_sig = False
    if crypto_message.get_email_message().get_header('DKIM-Signature') is not None:
        log_message('trying to verify DKIM signature')
        try:
            global _log

            crypto_message.set_dkim_signed(True)

            charset, __ = get_charset(crypto_message.get_email_message())
            log_message('dkim message char set: {}'.format(charset))

            message = crypto_message.get_email_message().to_string().encode()
            if DEBUGGING:
                log_message('headers before DKIM verification:\n{}'.format(
                   crypto_message.get_email_message().get_header_lines()))
                log_message('message:\n{}'.format(message))

            if DKIM_VERIFICATION_ACTIVE:
                verified_sig = dkim.verify(message, logger=_log)
                log_message('DKIM signature verified: {}'.format(verified_sig))

                if verified_sig:
                    crypto_message.get_email_message().delete_header('DKIM-Signature')
                    crypto_message.set_dkim_sig_verified(True)
                elif options.dkim_delivery_policy() == DKIM_WARN_POLICY:
                    crypto_message.get_email_message().delete_header('DKIM-Signature')
                    log_message('dkim policy is to warn and accept message')
                else:
                    raise DKIMException("Unable to verify message originated on sender's mail server.")
            else:
                verified_sig = True # !!!!! fix dkim in python3
                log_message('unable to verify dkim sig with python3')
        except dkim.DKIMException as dkim_exception:
            if options.dkim_delivery_policy() == DKIM_WARN_POLICY:
                crypto_message.get_email_message().delete_header('DKIM-Signature')
                log_message('dkim policy is to warn; {}'.format(dkim_exception))
            else:
                raise dkim.DKIMException(str(dkim_exception))
        except:
            log_message('EXCEPTION - see syr.exception.log for details')
            record_exception()
    else:
        verified_sig = False

    return crypto_message, verified_sig
Ejemplo n.º 34
0
    def test_dkim(self):
        privkey = self._get_dkim_privkey()
        mailing = factories.MailingFactory(dkim={'selector': 'mail', 'domain': 'unittest.cloud-mailing.net', 'privkey':privkey})
        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('DKIM-Signature' in message)
        # print message['DKIM-Signature']

        self.assertTrue(dkim.verify(message_str, dnsfunc=self._get_txt))
Ejemplo n.º 35
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")
Ejemplo n.º 36
0
 def dkim_verify(self, msg_str, norm_addr):
     # DKIM verification. Simply check that the server has verified the
     # message's signature
     if self.dkim:
         log.msg("Checking DKIM signature.", system="email parser")
         # Note: msg.as_string() changes the message to conver it to
         # string, so DKIM will fail. Use the original string instead
         if dkim.verify(msg_str):
             log.msg("Valid DKIM signature.", system="email parser")
             return True
         else:
             log.msg("Invalid DKIM signature.", system="email parser")
             username, domain = norm_addr.split("@")
             raise DkimError("DKIM failed for {} at {}".format(
                 hid.hexdigest(), domain))
     # Is this even useful like this?
     else:
         return True
Ejemplo n.º 37
0
    async def handle_DATA(self, server: SMTP, session: Session,
                          envelope: Envelope):

        valid_dkim = dkim.verify(envelope.content)
        envelope.dkim = valid_dkim
        log.info("DKIM: %s", test_results[valid_dkim])

        message: Message = email.message_from_bytes(envelope.content)

        log.info('From: %s', message['From'])
        log.info('To: %s', message['To'])
        log.info('Subject: %s', message['Subject'])
        log.info('Message data:\n%s', message_to_display(message))

        if self.verify_dkim and not valid_dkim:
            return '550 DKIM validation failed'

        return '250 Message accepted for delivery'
    def verify_dkim(self, body, options, output):
        """
        Purpose: Verify DKIM Signature
        Returns: Status, Message
        """
        match = re.search('d=[^;]+; s=(\d{14});', body)
        if not match:
            # Enable the next line, if no dkim signature should only be a warning.
            # return RETURN_WARNING, "No dkim signature found"
            return RETURN_CRITICAL, "No dkim signature found"
        selector = match.group(1)
        if dkim.verify(body): #, debuglog=output):
            if (datetime.now() - datetime.strptime(selector, '%Y%m%d%H%M%S')) > timedelta(days=KEY_MAX_AGE):
                return RETURN_CRITICAL, 'DKIM key (%s) older than %s days' % (selector, KEY_MAX_AGE)

            return RETURN_OK, 'DKIM verification successful, selector is %s' % selector
        else:
            return RETURN_CRITICAL, 'DKIM verification failed'
Ejemplo n.º 39
0
def isSenderVerified(message):
	# check 1: DKIM
	email_message = message.original
	_, sender_addr = parseaddr(message['From'].lower())
	_, to_addr = parseaddr(message['To'].lower())
	verified = dkim.verify(email_message)

	# import spf
	# check 2: SPF - TODO: SPF not implemented - need to find incoming mail server IP address
	# if not verified:
	# 	spf_i = ""
	# 	spf_h = ""
	# 	spf_s = sender_addr
	# 	result = spf.check(spf_i, spf_s, spf_h)
	# 	if result[0] == "pass":
	# 		verified = True

	if not verified:
		# check if UserProfile has a hash, if not generate one and send it to them
		try:
			user = UserProfile.objects.get(email=sender_addr)
		except UserProfile.DoesNotExist:
			user = None
		if user:
			# TODO: create new user here if it doesn't exist or otherwise handle posts from non-users
			# for now just mark as un-verified if DKIM and SPF fail
			if not user.hash:
				salt = hashlib.sha1(str(random.random())+str(time.time())).hexdigest()[:5]
				new_hash = hashlib.sha1(sender_addr+to_addr+salt).hexdigest()[:20]
				user.hash = new_hash
				user.save()
				#mail = MurmurMailResponse(From = NO_REPLY, Subject = "Please use your secret code in future emails")
				#mail.Body = "In future, to ensure your message is delivered, please include the code %s within the address of your emails, before the '@' symbol and after a '+' symbol. E.g. if you are emailing testgroup@%s, you should now email testgroup+%s@%s to ensure your email is verified as coming directly from you, and thus delivered correctly." % (new_hash, HOST, new_hash, HOST)
				#relay.deliver(mail, To = sender_addr)
			hash_group = re.search(r'\+(.{20,40}?)\@', to_addr)
			if hash_group:
				sender_hash = hash_group.group(1)
				if sender_hash == user.hash:
					verified = True
	return verified
Ejemplo n.º 40
0
    f.write( query + str(testid) + str(unixtime) + "\n")
    f.write( str(test) + "\n")
    if (len(test) >= 1) and int(test[0][0]) == 1:
      timestamp=test[0][1]
      parent = testid
      query = "INSERT INTO queue (domain, email, test_id, parent, start_time, ip, extra, slow) VALUES(%s, %s, nextval('test_id_seq'), %s, %s, %s, 'd:StandardAddresses', true) RETURNING test_id, EXTRACT(EPOCH FROM start_time)::integer AS start_time"
      test=db.fetch(query, ( domain, email, testid, timestamp, db_ip ))
      testid = test[0][0]

      f.write(str(test)+"\n")
    else:
      exit(str("No matching test"))
  f.write(str(output)+"\n"+str(query)+"\n")


if len(extra_tests) >= 1:
  for extra in extra_tests:
    if extra == 'DKIM' and incoming == False:
      dkim=dkim.verify(output)
      if dkim == True:
        message='DKIM test successful'
        goldstar='1'
        status='1'
      else:
        message='DKIM-test failed'
        goldstar='0'
        status='2'
      save_result(testid, message, status, 'adv', 'DKIM', 'Incoming', '0', goldstar, int())
      save_result(testid, message, status, 'adv', 'DKIM', 'Incoming', '1', goldstar, int())
Ejemplo n.º 41
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")
Ejemplo n.º 42
0
        from_address = re.search("<(.+)>", from_address).group(1)

      #Get Domain from email address
      from_address = str(from_address.lower())
      (user, domain) = from_address.split("@")

      # Get spf result from email
      spf_result = re.search('spf=(\S+)', msg).group(1)

      # Get DKIM result
      dkim_present = re.search('^DKIM-Signature', msg, re.MULTILINE)

      # If we have a DKIM signature, verify it. If not, DKIM = none
      if dkim_present:
        try:
          dkim_result = dkim.verify(msg)
        except DKIMException as x:
          print('DKIM Exception: ' + str(x))
      else:
        dkim_result = 'none'

      # Evaluate results according to our rules

      # DKIM valid, SPF pass
      if dkim_result == True and spf_result == 'pass':
        results['dkim_valid_spf_pass'] += 1
      # DKIM valid, SPF none
      elif dkim_result == True and (spf_result == 'neutral' or spf_result == 'none'):
        results['dkim_valid_spf_none'] += 1
      # DKIM valid, SPF fail
      elif dkim_result == True and (spf_result == 'fail' or spf_result == 'softfail' or spf_result == 'temperror' or spf_result == 'permerror'):
Ejemplo n.º 43
0
#!/usr/local/bin/python2.5

# This software is provided 'as-is', without any express or implied
# warranty.  In no event will the author be held liable for any damages
# arising from the use of this software.
# 
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
# 
# 1. The origin of this software must not be misrepresented; you must not
#    claim that you wrote the original software. If you use this software
#    in a product, an acknowledgment in the product documentation would be
#    appreciated but is not required.
# 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

import sys

import dkim

message = sys.stdin.read()
if not dkim.verify(message):
    print "signature verification failed"
    sys.exit(1)
print "signature ok"
Ejemplo n.º 44
0
def checkMail (mailbox, outputFileHandle):	


	htmlDMARCBox = ""
	htmlDKIMBox = ""
	htmlSPFBox = ""


	#Read the message from the inbox
	mailBoxFileHandle = open(mailbox,'r+')
	message = mailBoxFileHandle.read()
	headers = Parser().parsestr(message)



	receivedHeader =  headers['Received']
	#print headers.items()

	pattern = re.compile(r'\[.*]')
	result = re.search(pattern, receivedHeader).group(0)

	pattern = re.compile(r'from .*? ')
	result2 = re.search(pattern, receivedHeader).group(0)


	subject = headers['subject']

	#Variables needed for spf check
	fromHeader = headers['from']
	ipaddr = result[1:-1]
	host = result2[5:-1]




	# Perfom SPF and DKIM checks
	spfResult = spf.check(i=ipaddr,s=fromHeader,h=host)
	dkimResult = dkim.verify(message ,None)


	#Create HTML conentent according to the results of the test
	if (spfResult[0] == 'pass'):
		htmlSPFBox = """<tr class="success">
					<td>SPF check passed <br><strong>↳</strong>""" + spfResult[2] + """</td>
				</tr>"""
	else:
		htmlSPFBox = """<tr class="danger">
					<td>SPF check failed <br><strong>↳</strong>""" + spfResult[2] + """</td>	
				</tr>"""
		
	if (dkimResult == True):
		htmlDKIMBox = """<tr class="success">
					<td>DKIM check passed</td>
				</tr>"""
	else:
		htmlDKIMBox = """<tr class="danger">
					<td>DKIM check failed</td>
				</tr>"""
		
	if (spfResult[0] == 'pass' or dkimResult == True):
		htmlDMARCBox = """<tr class="success">
					<td>DMARC check passed</td>
				</tr>"""
	else:
		htmlDMARCBox = """<tr class="danger">
					<td>DMARC check failed</td>
				</tr>"""		
	
		
	html = """
	<div class="well well-lg">
		<h4><p class="text-center"><strong>DMARC test</strong></p></h4>
		<table class="table table-condensed">
			<thead>
				<tr>
					<th>Result</th>
				</tr>
				<tr></tr>
			</thead>
			<tbody>
				<tr>
					<td>Subject: """ + subject + """</td>
				</tr>
				<tr><td></td></tr>
				""" + htmlDKIMBox + htmlSPFBox + """<tr><td></td></tr>""" + htmlDMARCBox + """
			</tbody>

		</table>
	</div>
	"""

	outputFileHandle.write(html)
	outputFileHandle.close()

	# Empty the mail box for the the next test, remove this line if 
	# you whish to keep the email. 
	# (Hackish way of emtying the file contents)
	open(mailbox, 'w').close()
Ejemplo n.º 45
0
def __validate_mail(message):

    # First things first (and this is critical), 
    # validate the DKIM signature
    if not dkim.verify(message):
        raise ValidateMailException("DKIM signature verification failed\n")

    # Parse the email
    (headers, body) = dkim.rfc822_parse(message)

    # Get the one and only DKIM-Signature header and from address
    from_addr = __get_raw_email_addr(__get_required_header(headers, "From"))
    dkim_sig  = __get_required_header(headers, "DKIM-Signature")

    # Check that the from address and the Return-Path address are consistent
    return_paths = __get_headers_by_name(headers, "Return-Path")
    if len(return_paths) == 0:
        raise ValidateMailException("No return paths specified\n")
    for rp in return_paths:
        if __get_raw_email_addr(rp) != from_addr:
            raise ValidateMailException("'Return-Path: " + str(rp) + "' does not match from address.\n")

    # Check a few things in the DKIM header
    dkim_fields = parse_dkim_sig(dkim_sig)

    if 'bh' not in dkim_fields:
        raise ValidateMailException("Missing the DKIM body hash.\n")

    if 'h' not in dkim_fields:
        raise ValidateMailException("Missing DKIM headers key (h=).\n")

    if 'd' not in dkim_fields:
        raise ValidateMailException("Missing DKIM domain field.\n")

    if dkim_fields['d'] != "gmail.com":
        raise ValidateMailException("Not from gmail.com\n")

    signed_headers = [fld.lower().strip() for fld in dkim_fields['h'].split(":")]
    if 'from' not in signed_headers:
        raise ValidateMailException("From address is not included in signed headers!\n")

    # Some other magic stuff
    # NOTE: It is legal for there to be numerous Authentication-Results headers, 
    #       but, we won't handle that yet. Instead, just fail if there is more than one.
    auth_results = __get_required_header(headers, "Authentication-Results").strip()
    if not re.match(r"^mx\.google\.com;", auth_results):
        raise ValidateMailException("Authentication-Results header not from mx.google.com\n")
 
    # check various features    
    auth_results = " " + re.sub(r"\s+", " ", auth_results).lower().strip() + " "

    if " dkim=pass " not in auth_results:
        raise ValidateMailException("Authentication-Results failure: No 'dkim=pass'\n")

    if " dmarc=pass " not in auth_results:
        raise ValidateMailException("Authentication-Results failure: No 'dmarc=pass'\n")

    if " spf=pass " not in auth_results:
        raise ValidateMailException("Authentication-Results failure: No 'spf=pass'\n")

    # Try to get the smtp.mailfrom header
    if not re.match(r"^.*spf=pass [^;]+? smtp.mailfrom=" + re.escape(from_addr) + "(;.*)?$", auth_results):
        raise ValidateMailException("Authentication-Results failure: invalid or missing smtp.mailfrom address\n")

    return from_addr
Ejemplo n.º 46
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 = cStringIO()
    log.info(
        'Attempting DKIM authentication of message id=%r from=%r sender=%r'
        % (signed_message['Message-ID'],
           signed_message['From'],
           signed_message['Sender']))
    signing_details = []
    dkim_result = False
    try:
        dkim_result = dkim.verify(
            signed_message.parsed_string, dkim_log, details=signing_details)
    except dkim.DKIMException as e:
        log.warning('DKIM error: %r' % (e,))
    except dns.resolver.NXDOMAIN as e:
        # This can easily happen just through bad input data, ie 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 dns.exception.DNSException as e:
        # many of them have lame messages, thus %r
        log.warning('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.getvalue(),))
    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.
    if len(signing_details) != 1:
        log.info(
            'expected exactly one DKIM details record: %r'
            % (signing_details,))
        return None
    signing_domain = signing_details[0]['d']
    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
Ejemplo n.º 47
0
def scan(fileobj, dkimrule = 0, returnpath = None):
  
  try:
    import asnn_config
    # Declaring the 'import' where the CLI is starting is not getting it
    # into the namespace properly and it's faulting in this function.
  
    fileobj.seek(0)       # to the top of the file
    domains = []          # 'Return-Path' and 'From' domains
    
    # create a parsing object that reads the email from the file object
    msgobj = email.message_from_file(fileobj)
    
    if returnpath == '<>':  # the message is a bounce, maybe force DKIM to make
      # sure that it's not a spam masquarading as a bounce
      if asnn_config.DKIM_FORCE_ON_BOUNCE:
        ############# THIS FUNCTIONALITY HAS NOT BEEN TESTED ##################
        dkimrule = 2
    elif returnpath:
      domain = returnpath.split('@')[1]
      if debug > 5:
        print >> sys.stderr, logid() + "DKIM: 'Return-Path' domain: " + domain
      dobj = asnn_whois_domain.getbasedomain(domain, retobject=True, retupper=True)
      # (By 'returning upper', adding a subdomain to a domain that should be
      # checked will get checked.  Domains that don't exist in the DB will
      # end up returning a TLD, but no TLD should have a DKIM rule.)
      if dobj:   # don't look unless we found a result
        for line in dobj.whoisdecode.splitlines():
          if line == 'rpskipdkim':
            if debug > 4:
              print >> sys.stderr, logid() + \
              "DKIM: check bypassed per return-path domain: " + dobj.domain
            return '200 DKIM check bypassed'
          if line == 'forcedkim':
            dkimrule = 2
            if debug > 4:
              print >> sys.stderr, logid() + "DKIM: forced check per RP domain: " + dobj.domain
            break
          if line == 'checkdkim' and dkimrule < 2:
            dkimrule = 1
            if debug > 4:
              print >> sys.stderr, logid() + "DKIM: check per RP domain: " + dobj.domain
            break

    if ('from' in msgobj) and ('@' in msgobj['From']):
      if '<' in msgobj['From']:
        domain = msgobj['From'].split('<')[1].split('@')[1].split('>')[0]
      else:
        domain = msgobj['From'].split('@')[1]
      dobj = asnn_whois_domain.getbasedomain(domain, retobject=True, retupper=True)
      if debug > 5:
        print >> sys.stderr, logid() + "DKIM: 'From' domain: " + domain
      if dobj:   # don't look unless we found a result
        for line in dobj.whoisdecode.splitlines():
          if line == 'forcedkim':
            dkimrule = 2
            if debug > 4:
              print >> sys.stderr, logid() + "DKIM: forced check per PRA domain: " + dobj.domain
            break
          if line == 'checkdkim' and dkimrule < 2:
            dkimrule = 1
            if debug > 4:
              print >> sys.stderr, logid() + "DKIM: check per PRA domain: " + dobj.domain
            break
    else:
      if debug > 3:
        print >> sys.stderr, logid() + "DKIM: bad or missing 'From'"
    
    if not dkimrule:
      if debug > 4:
        print >> sys.stderr, logid() + "DKIM: no DKIM check required"
      return '200 no DKIM check required'
    
    import dkim
    
    if 'DKIM-Signature' not in msgobj:
      if debug > 4:
        print >> sys.stderr, logid() + "DKIM: no DKIM header found"
      if dkimrule == 2:
        return asnn_config.REJECT_DKIM
      return '200 no DKIM header found'  # i.e. dkimrule == 1
    
    fileobj.seek(0)       # to the top of the file
    dkimresult = dkim.verify(fileobj.read())
    
    if not dkimresult:
      if debug > 4:
        print >> sys.stderr, logid() + "DKIM: reject per result"
      return asnn_config.REJECT_DKIM
    
    if debug > 4:
      print >> sys.stderr, logid() + "DKIM: result okay"
    return '200 DKIM check okay'
  
  except Exception as msg:
    if debug > 0:
      print >> sys.stderr, logid() + "DKIM: exception during check: " + str(msg)
    if debug > 4:
      import traceback
      print >> sys.stderr, traceback.print_exc()
    
    return asnn_config.SOFTFAIL_DKIM
Ejemplo n.º 48
0
 def auth(self, message_data=None, peer_ip=None, message=None):
     return dkim.verify(message_data)
Ejemplo n.º 49
0
 def test_badly_encoded_domain_fails(self):
     # Domains should be ASCII. Bad ASCII causes verification to fail.
     sig = dkim.sign(self.message, b"test", b"example.com\xe9", self.key)
     res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc)
     self.assertFalse(res)
Ejemplo n.º 50
0
def checkMail (message):	

    outputFileHandle = None

    try:
        outputFileHandle = open('dmarcCheck.html', 'w')
    except:
        print "file error"
        sys.exit()


    htmlDMARCBox = ""
    htmlDKIMBox = ""
    htmlSPFBox = ""
    receivedHeader = ""
    fromHeader = ""	

    #Read the message from the inbox
    headers = email.parser.Parser().parsestr(message)


    for field in headers.items():
	    if field[0] == "Received" and "[" in field[1] and "]" in field[1]:
		    receivedHeader = field[1]

    pattern = re.compile(r'\[.*]')
    result = re.search(pattern, receivedHeader).group(0)

    pattern = re.compile(r'from .*? ')
    result2 = re.search(pattern, receivedHeader).group(0)

    subject = headers['subject']

    #Variables needed for spf check

    #We need only the email address
    if "<" in headers['from'] and ">" in headers['from']:
	    pattern = re.compile(r'\<.*>')
	    fromHeader = re.search(pattern, headers['from']).group(0)
	    fromHeader = fromHeader[1:-1]
    else:
	    fromHeader = headers['from']


    ipaddr = result[1:-1]
    host = result2[5:-1]


    # Perfom SPF and DKIM checks
    spfResult = spf.check(i=ipaddr,s=fromHeader,h=host)
    dkimResult = dkim.verify(message ,None)


    #Create HTML conentent according to the results of the test
    if (spfResult[0] == 'pass'):
	    htmlSPFBox = """<tr class="success">
				    <td>SPF check passed <br><strong>↳</strong>""" + spfResult[2] + """</td>
			    </tr>"""
    else:
	    htmlSPFBox = """<tr class="danger">
				    <td>SPF check failed <br><strong>↳</strong>""" + spfResult[2] + """</td>	
			    </tr>"""
	
    if (dkimResult == True):
	    htmlDKIMBox = """<tr class="success">
				    <td>DKIM check passed</td>
			    </tr>"""
    else:
	    htmlDKIMBox = """<tr class="danger">
				    <td>DKIM check failed</td>
			    </tr>"""
	
    if (spfResult[0] == 'pass' or dkimResult == True):
	    htmlDMARCBox = """<tr class="success">
				    <td>DMARC check passed</td>
			    </tr>"""
    else:
	    htmlDMARCBox = """<tr class="danger">
				    <td>DMARC check failed</td>
			    </tr>"""		

	
    html = """
    <div class="well well-lg">
        <h4><p class="text-center"><strong>DMARC test</strong></p></h4>
        <table class="table table-condensed">
	        <thead>
		        <tr>
			        <th>Result</th>
		        </tr>
		        <tr></tr>
	        </thead>
	        <tbody>
		        <tr>
			        <td>Subject: """ + subject + """</td>
		        </tr>
		        <tr><td></td></tr>
		        """ + htmlDKIMBox + htmlSPFBox + """<tr><td></td></tr>""" + htmlDMARCBox + """
	        </tbody>

        </table>
    </div>
    """
    outputFileHandle.write(html)
    outputFileHandle.close()