Ejemplo n.º 1
0
    def test_cached_key(self):

        # Create cache entry
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(
            DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [
            DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data, ))
        ]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)

        # Cache valid
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(
            DKIMUtils.extractTags(dkim))
        lookup.keys = []
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)

        # Cache invalid
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(
            DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = []
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)
Ejemplo n.º 2
0
    def test_locate_public_key(self):
        """
        L{DKIMVerifier.locatePublicKey} correctly finds key matching headers.
        """

        data = (
            # Valid
            (
                """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
                [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
                True,
            ),
            # Invalid - no method
            (
                """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
                [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
                False,
            ),
            # Invalid - wrong algorithm
            (
                """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
                [DKIMUtils.extractTags("v=DKIM1; h=sha-1; p=%s" % (self.public_key_data,))],
                False,
            ),
        )

        for hdrs, keys, result in data:
            headers = [hdr.split(":", 1) for hdr in hdrs.splitlines()]
            TestPublicKeyLookup.PublicKeyLookup_Testing.keys = keys
            TestPublicKeyLookup.PublicKeyLookup_Testing.flushCache()
            verifier = DKIMVerifier(self._makeHeaders(headers), "", key_lookup=(TestPublicKeyLookup.PublicKeyLookup_Testing,))
            verifier.processDKIMHeader()
            pkey = (yield verifier.locatePublicKey())
            if result:
                self.assertTrue(pkey is not None)
            else:
                self.assertTrue(pkey is None)
Ejemplo n.º 3
0
    def test_locate_public_key(self):
        """
        L{DKIMVerifier.locatePublicKey} correctly finds key matching headers.
        """

        data = (
            # Valid
            (
                """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
                [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
                True,
            ),
            # Invalid - no method
            (
                """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
                [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
                False,
            ),
            # Invalid - wrong algorithm
            (
                """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
                [DKIMUtils.extractTags("v=DKIM1; h=sha-1; p=%s" % (self.public_key_data,))],
                False,
            ),
        )

        for hdrs, keys, result in data:
            headers = [hdr.split(":", 1) for hdr in hdrs.splitlines()]
            TestPublicKeyLookup.PublicKeyLookup_Testing.keys = keys
            TestPublicKeyLookup.PublicKeyLookup_Testing.flushCache()
            verifier = DKIMVerifier(self._makeHeaders(headers), "", key_lookup=(TestPublicKeyLookup.PublicKeyLookup_Testing,))
            verifier.processDKIMHeader()
            pkey = (yield verifier.locatePublicKey())
            if result:
                self.assertTrue(pkey is not None)
            else:
                self.assertTrue(pkey is None)
Ejemplo n.º 4
0
    def test_HTTP_URI_key(self):

        # Need to setup a fake resolver
        module = getModule(__name__)
        dataPath = module.filePath.sibling("data")
        bindPath = dataPath.child("db.example.com")
        self.patch(config.Scheduling.iSchedule, "DNSDebug", bindPath.path)
        utils.DebugResolver = None
        utils._initResolver()

        for d, s, result in (
            ("example.com", "_ischedule",
             "https://key.example.com:8443/.well-known/domainkey/example.com/_ischedule"
             ),
            ("www.example.com", "_ischedule",
             "http://key.example.com/.well-known/domainkey/www.example.com/_ischedule"
             ),
            ("example.org", "_ischedule",
             "https://example.org/.well-known/domainkey/example.org/_ischedule"
             ),
        ):
            dkim = "v=1; d=%s; s = %s; t = 1234; a=rsa-sha1; q=http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=" % (
                d,
                s,
            )
            tester = PublicKeyLookup_HTTP_WellKnown(
                DKIMUtils.extractTags(dkim))
            uri = (yield tester._getURI())
            self.assertEqual(uri, result)
Ejemplo n.º 5
0
    def test_private_exchange(self):

        keydir = self.mktemp()
        PublicKeyLookup_PrivateExchange.directory = keydir
        os.mkdir(keydir)
        keyfile = os.path.join(keydir, "example.com#dkim")
        with open(keyfile, "w") as f:
            f.write("""v=DKIM1; p=%s
""" % (self.public_key_data, ))

        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = PublicKeyLookup_PrivateExchange(DKIMUtils.extractTags(dkim))
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)

        dkim = "v=1; d=example.com; s = dkim2; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = PublicKeyLookup_PrivateExchange(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)

        with open(keyfile, "w") as f:
            f.write("""v=DKIM1; s=email; p=%s
""" % (self.public_key_data, ))

        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = PublicKeyLookup_PrivateExchange(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)

        with open(keyfile, "w") as f:
            f.write("""v=DKIM1; s=email; p=%s
v=DKIM1; s=ischedule; p=%s
""" % (
                self.public_key_data,
                self.public_key_data,
            ))

        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = PublicKeyLookup_PrivateExchange(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)
Ejemplo n.º 6
0
    def test_private_exchange(self):

        keydir = self.mktemp()
        PublicKeyLookup_PrivateExchange.directory = keydir
        os.mkdir(keydir)
        keyfile = os.path.join(keydir, "example.com#dkim")
        with open(keyfile, "w") as f:
            f.write("""v=DKIM1; p=%s
""" % (self.public_key_data,))

        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = PublicKeyLookup_PrivateExchange(DKIMUtils.extractTags(dkim))
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)

        dkim = "v=1; d=example.com; s = dkim2; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = PublicKeyLookup_PrivateExchange(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)

        with open(keyfile, "w") as f:
            f.write("""v=DKIM1; s=email; p=%s
""" % (self.public_key_data,))

        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = PublicKeyLookup_PrivateExchange(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)

        with open(keyfile, "w") as f:
            f.write("""v=DKIM1; s=email; p=%s
v=DKIM1; s=ischedule; p=%s
""" % (self.public_key_data, self.public_key_data,))

        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = PublicKeyLookup_PrivateExchange(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)
Ejemplo n.º 7
0
    def test_selector_key(self):

        for lookup, d, result in (
            (PublicKeyLookup_DNSTXT, "example.com", "dkim._domainkey.example.com"),
            (PublicKeyLookup_DNSTXT, "calendar.example.com", "dkim._domainkey.calendar.example.com"),
            (PublicKeyLookup_HTTP_WellKnown, "example.com", "https://example.com/.well-known/domainkey/example.com/dkim"),
            (PublicKeyLookup_HTTP_WellKnown, "calendar.example.com", "https://example.com/.well-known/domainkey/calendar.example.com/dkim"),
            (PublicKeyLookup_PrivateExchange, "example.com", "example.com#dkim"),
            (PublicKeyLookup_PrivateExchange, "calendar.example.com", "calendar.example.com#dkim"),
        ):
            dkim = "v=1; d=%s; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=" % (d,)
            tester = lookup(DKIMUtils.extractTags(dkim))
            self.assertEqual(tester._getSelectorKey(), result)
Ejemplo n.º 8
0
    def test_cached_key(self):

        # Create cache entry
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)

        # Cache valid
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.keys = []
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)

        # Cache invalid
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = []
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)
Ejemplo n.º 9
0
    def test_HTTP_URI_key(self):

        # Need to setup a fake resolver
        module = getModule(__name__)
        dataPath = module.filePath.sibling("data")
        bindPath = dataPath.child("db.example.com")
        self.patch(config.Scheduling.iSchedule, "DNSDebug", bindPath.path)
        utils.DebugResolver = None
        utils._initResolver()

        for d, s, result in (
            ("example.com", "_ischedule", "https://key.example.com:8443/.well-known/domainkey/example.com/_ischedule"),
            ("www.example.com", "_ischedule", "http://key.example.com/.well-known/domainkey/www.example.com/_ischedule"),
            ("example.org", "_ischedule", "https://example.org/.well-known/domainkey/example.org/_ischedule"),
        ):
            dkim = "v=1; d=%s; s = %s; t = 1234; a=rsa-sha1; q=http/well-known ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=" % (d, s,)
            tester = PublicKeyLookup_HTTP_WellKnown(DKIMUtils.extractTags(dkim))
            uri = (yield tester._getURI())
            self.assertEqual(uri, result)
Ejemplo n.º 10
0
    def test_TXT_key(self):

        # Need to setup a fake resolver
        module = getModule(__name__)
        dataPath = module.filePath.sibling("data")
        bindPath = dataPath.child("db.example.com")
        self.patch(config.Scheduling.iSchedule, "DNSDebug", bindPath.path)
        utils.DebugResolver = None
        utils._initResolver()

        for d, s, result in (
            ("example.com", "_ischedule", True),
            ("example.com", "_revoked", False),
            ("example.com", "dkim", False),
            ("calendar.example.com", "_ischedule", False),
            ("example.org", "_ischedule", False),
        ):
            dkim = "v=1; d=%s; s = %s; t = 1234; a=rsa-sha1; q=dns/txt ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=" % (d, s,)
            tester = PublicKeyLookup_DNSTXT(DKIMUtils.extractTags(dkim))
            pkey = yield tester.getPublicKey(False)
            self.assertEqual(pkey is not None, result)
Ejemplo n.º 11
0
    def test_get_key(self):

        # Valid
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)

        # Valid with more tags
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [DKIMUtils.extractTags("v=DKIM1; k = rsa ; h=  sha1 : sha256  ; s=ischedule ; p=%s" % (self.public_key_data,))]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)

        # Invalid - key type
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [DKIMUtils.extractTags("v=DKIM1; k=dsa ; p=%s" % (self.public_key_data,))]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)

        # Invalid - hash
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [DKIMUtils.extractTags("v=DKIM1; k=rsa ; h=sha512 ; p=%s" % (self.public_key_data,))]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)

        # Invalid - service
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [DKIMUtils.extractTags("v=DKIM1; k=rsa ; s=email ; p=%s" % (self.public_key_data,))]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)

        # Invalid - revoked
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [DKIMUtils.extractTags("v=DKIM1; k=rsa ; s=email ; p=")]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)

        # Multiple valid
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [
            DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,)),
            DKIMUtils.extractTags("v=DKIM1; k = rsa ; h=  sha1 : sha256  ; s=ischedule ; p=%s" % (self.public_key_data,)),
            DKIMUtils.extractTags("v=DKIM1; k = rsa ; h=  sha1 : sha256  ; s=* ; p=%s" % (self.public_key_data,)),
        ]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)

        # Multiple - some valid, some invalid
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [
            DKIMUtils.extractTags("v=DKIM1; k=rsa ; s=email ; p="),
            DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,)),
            DKIMUtils.extractTags("v=DKIM1; k = rsa ; h=  sha1 : sha256  ; s=ischedule ; p=%s" % (self.public_key_data,)),
            DKIMUtils.extractTags("v=DKIM1; k = rsa ; h=  sha1 : sha256  ; s=* ; p=%s" % (self.public_key_data,)),
        ]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is not None)

        # Multiple - invalid
        dkim = "v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known:private-exchange ; http=UE9TVDov; c=relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="
        lookup = TestPublicKeyLookup.PublicKeyLookup_Testing(DKIMUtils.extractTags(dkim))
        lookup.flushCache()
        lookup.keys = [
            DKIMUtils.extractTags("v=DKIM1; k=rsa ; s=email ; p="),
            DKIMUtils.extractTags("v=DKIM1; k=rsa ; s=email ; p="),
        ]
        pubkey = (yield lookup.getPublicKey())
        self.assertTrue(pubkey is None)
Ejemplo n.º 12
0
class TestDKIMVerifier (TestDKIMBase):
    """
    L{DKIMVerifier} support tests.
    """

    class StubRequest(object):

        def __init__(self, method, uri, headers, body):
            self.method = method
            self.uri = uri
            self.headers = Headers()
            for name, value in headers:
                self.headers.addRawHeader(name, value)
            self.stream = MemoryStream(body)


    def _makeHeaders(self, headers_pairs):
        headers = Headers()
        for name, value in headers_pairs:
            headers.addRawHeader(name, value)
        return headers


    def test_valid_dkim_headers(self):
        """
        L{DKIMVerifier.processDKIMHeader} correctly validates DKIM-Signature headers.
        """

        data = (
            # Bogus
            ((("DKIM-Signature", "v=1"),), False,),

            # More than one
            ((
                ("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),
                ("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha256; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),
            ), False,),

            # Valid
            ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),), True,),
            ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def"),), True,),
            ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; x=%d; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() + 30),)),), True,),

            # Invalid
            ((("DKIM-Signature", "v=2; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),), False,),
            ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha512; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),), False,),
            ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; c=ischedule-relaxed/relaxed; h=Originator:Recipient; bh=abc; b=def"),), False,),
            ((("DKIM-Signature", "v=1; d=example.com; t=1234; a=rsa-sha1; q=dns/txt:http/well-known; c=ischedule-relaxed/simple; h=Originator:Recipient; bh=abc; b=def"),), False,),
            ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; x=%d; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() - 30),)),), False,),
            ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; x=%d; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() - 30),)),), False,),
            ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; x=%d; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() - 30),)),), False,),
            ((("DKIM-Signature", "v=1; d=example.com; s=dkim; t=1234; x=%d; a=rsa-sha256; q=dns/txt; c=ischedule-relaxed; h=Originator:Recipient; bh=abc; b=def" % (int(time.time() - 30),)),), False,),
        )

        for headers, result in data:
            verifier = DKIMVerifier(self._makeHeaders(headers), "")
            if result:
                verifier.processDKIMHeader()
            else:
                self.assertRaises(DKIMVerificationError, verifier.processDKIMHeader)


    def test_canonicalize_header(self):
        """
        L{DKIMVerifier.canonicalizeHeader} correctly canonicalizes headers.
        """

        data = (
            ("Content-Type", " text/calendar  ; charset =  \"utf-8\"  ", "content-type:text/calendar ; charset = \"utf-8\"\r\n"),
            ("Originator", "  mailto:[email protected]  ", "originator:mailto:[email protected]\r\n"),
            ("Recipient", "  mailto:[email protected]  ,\t mailto:[email protected]\t\t  ", "recipient:mailto:[email protected],mailto:[email protected]\r\n"),
            ("iSchedule-Version", " 1.0 ", "ischedule-version:1.0\r\n"),
            (
                "DKIM-Signature",
                "  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=a b  c; b=d ef",
                "dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; c=ischedule-relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=a b c; b=",
            ),
            (
                "DKIM-Signature",
                "  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; b= def ; c=ischedule-relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=a\t bc",
                "dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; b= ; c=ischedule-relaxed/simple; h=Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=a bc",
            ),
        )

        for name, value, result in data:
            verifier = DKIMVerifier(self._makeHeaders(((name, value,),)), "")
            if name == "DKIM-Signature":
                verifier.processDKIMHeader()
            canonicalized = DKIMUtils.canonicalizeHeader(name, value, verifier.dkim_tags if name == "DKIM-Signature" else None)
            self.assertEqual(canonicalized, result)


    def test_extract_headers(self):
        """
        L{DKIMVerifier.extractSignedHeaders} correctly extracts canonicalizes headers.
        """

        data = (
            # Count on Recipient
            ("""Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
iSchedule-Version: 1.0
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
            """content-type:text/calendar ; charset = "utf-8"
originator:mailto:[email protected]
recipient:mailto:[email protected],mailto:[email protected]
ischedule-version:1.0
dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="""
            ),
            # Exact count on Recipient
            ("""Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
Recipient:\t\t  mailto:[email protected]
iSchedule-Version: 1.0
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
            """content-type:text/calendar ; charset = "utf-8"
originator:mailto:[email protected]
recipient:mailto:[email protected],mailto:[email protected],mailto:[email protected]
ischedule-version:1.0
dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="""
            ),
            # Re-ordered Content-Type
            ("""Host:example.com
iSchedule-Version: 1.0
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Content-Type: text/calendar  ; charset =  "utf-8"
Cache-Control:no-cache
Connection:close
""",
            """content-type:text/calendar ; charset = "utf-8"
originator:mailto:[email protected]
recipient:mailto:[email protected],mailto:[email protected]
ischedule-version:1.0
dkim-signature:v=1; d=example.com; s = dkim; t = 1234; a=rsa-sha1; q=dns/txt:http/well-known ; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b="""
            ),
        )

        for hdrs, result in data:
            headers = [hdr.split(":", 1) for hdr in hdrs.splitlines()]
            verifier = DKIMVerifier(self._makeHeaders(headers), "")
            verifier.processDKIMHeader()
            extracted = verifier.extractSignedHeaders()
            self.assertEqual(extracted, result.replace("\n", "\r\n"))


    def test_locate_public_key(self):
        """
        L{DKIMVerifier.locatePublicKey} correctly finds key matching headers.
        """

        data = (
            # Valid
            ("""Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
            [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
            True,
            ),
            # Invalid - no method
            ("""Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
            [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
            False,
            ),
            # Invalid - wrong algorithm
            ("""Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
DKIM-Signature:  v=1;\t\t d=example.com; s = dkim; t\t=\t1234; a=rsa-sha1; \t\tq=dns/txt:http/well-known\t\t; c=ischedule-relaxed/simple; h=Content-Type:Originator:Recipient:Recipient:iSchedule-Version:iSchedule-Message-ID; bh=abc; b=def
Cache-Control:no-cache
Connection:close
""",
            [DKIMUtils.extractTags("v=DKIM1; h=sha-1; p=%s" % (self.public_key_data,))],
            False,
            ),
        )

        for hdrs, keys, result in data:
            headers = [hdr.split(":", 1) for hdr in hdrs.splitlines()]
            TestPublicKeyLookup.PublicKeyLookup_Testing.keys = keys
            verifier = DKIMVerifier(self._makeHeaders(headers), "", key_lookup=(TestPublicKeyLookup.PublicKeyLookup_Testing,))
            verifier.processDKIMHeader()
            pkey = (yield verifier.locatePublicKey())
            if result:
                self.assertNotEqual(pkey, None)
            else:
                self.assertEqual(pkey, None)


    @inlineCallbacks
    def test_verify(self):
        """
        L{DKIMVerifier.verify} correctly finds key matching headers.
        """

        @inlineCallbacks
        def _verify(hdrs, body, keys, result, sign_headers=("Originator", "Recipient", "Content-Type",), manipulate_request=None):
            for algorithm in ("rsa-sha1", "rsa-sha256",):
                # Create signature
                stream = MemoryStream(body)
                headers = Headers()
                for name, value in [hdr.split(":", 1) for hdr in hdrs.splitlines()]:
                    headers.addRawHeader(name, value)
                request = DKIMRequest("POST", "/", headers, stream, "example.com", "dkim", self.private_keyfile, algorithm, sign_headers, True, True, True, 3600)
                yield request.sign()

                # Possibly munge the request after the signature is done
                if manipulate_request is not None:
                    manipulate_request(request)

                # Verify signature
                TestPublicKeyLookup.PublicKeyLookup_Testing.keys = keys
                data = (yield allDataFromStream(request.stream))
                verifier = DKIMVerifier(request.headers, data, key_lookup=(TestPublicKeyLookup.PublicKeyLookup_Testing,))
                TestPublicKeyLookup.PublicKeyLookup_Testing({}).flushCache()
                try:
                    yield verifier.verify()
                except Exception, e:
                    if result:
                        self.fail("DKIMVerifier:verify failed: %s" % (e,))
                else:
                    if not result:
                        self.fail("DKIMVerifier:verify did not fail")

        # Valid
        yield _verify(
            """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
Cache-Control:no-cache
Connection:close
""",
            """BEGIN:DATA
END:DATA
""",
            [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
            True,
        )

        # Invalid - key revoked
        yield _verify(
            """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
Cache-Control:no-cache
Connection:close
""",
            """BEGIN:DATA
END:DATA
""",
            [DKIMUtils.extractTags("v=DKIM1; p=")],
            False,
        )

        # Invalid - missing header
        yield _verify(
            """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
Cache-Control:no-cache
Connection:close
""",
            """BEGIN:DATA
END:DATA
""",
            [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
            False,
            manipulate_request=lambda request: request.headers.removeHeader("Originator")
        )

        # Invalid - changed header
        yield _verify(
            """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
Cache-Control:no-cache
Connection:close
""",
            """BEGIN:DATA
END:DATA
""",
            [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
            False,
            manipulate_request=lambda request: request.headers.setRawHeaders("Originator", ("mailto:[email protected]",))
        )

        # Invalid - changed body
        yield _verify(
            """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
Cache-Control:no-cache
Connection:close
""",
            """BEGIN:DATA
END:DATA
""",
            [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
            False,
            manipulate_request=lambda request: setattr(request, "stream", MemoryStream("BEGIN:DATA\n")),
        )

        # Invalid - extra header
        yield _verify(
            """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
Cache-Control:no-cache
Connection:close
""",
            """BEGIN:DATA
END:DATA
""",
            [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
            False,
            manipulate_request=lambda request: request.headers.getRawHeaders("Recipient").insert(0, "mailto:[email protected]"),
        )

        # Valid - header
        yield _verify(
            """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
Cache-Control:no-cache
Connection:close
""",
            """BEGIN:DATA
END:DATA
""",
            [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
            True,
            sign_headers=("Originator", "Recipient", "Content-Type",),
        )

        # Invalid - over sign header extra header
        yield _verify(
            """Host:example.com
Content-Type: text/calendar  ; charset =  "utf-8"
Originator:  mailto:[email protected]
Recipient:  mailto:[email protected]  ,\t mailto:[email protected]\t\t
Cache-Control:no-cache
Connection:close
""",
            """BEGIN:DATA
END:DATA
""",
            [DKIMUtils.extractTags("v=DKIM1; p=%s" % (self.public_key_data,))],
            False,
            sign_headers=("Originator", "Recipient", "Content-Type",),
            manipulate_request=lambda request: request.headers.addRawHeader("Recipient", ("mailto:[email protected]",))
        )