From df2c20d4b35013819a4eafd179d372efcbcbd0c4 Mon Sep 17 00:00:00 2001 From: William Grant Date: Wed, 9 Mar 2011 18:07:27 +1100 Subject: [PATCH 1/9] Turn dkim into a package. --- dkim.py => dkim/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dkim.py => dkim/__init__.py (100%) diff --git a/dkim.py b/dkim/__init__.py similarity index 100% rename from dkim.py rename to dkim/__init__.py From 508ad7ceec8d83c6d211f26f9d4d3c3cebfdbf1f Mon Sep 17 00:00:00 2001 From: William Grant Date: Wed, 9 Mar 2011 18:47:11 +1100 Subject: [PATCH 2/9] Add a couple of tests for fold(). One disabled, because the function is broken. --- dkim/tests/__init__.py | 0 dkim/tests/test_dkim.py | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 dkim/tests/__init__.py create mode 100644 dkim/tests/test_dkim.py diff --git a/dkim/tests/__init__.py b/dkim/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dkim/tests/test_dkim.py b/dkim/tests/test_dkim.py new file mode 100644 index 0000000..c7b271e --- /dev/null +++ b/dkim/tests/test_dkim.py @@ -0,0 +1,20 @@ +import unittest + +import dkim + + +class TestFold(unittest.TestCase): + + def test_short_line(self): + self.assertEqual( + "foo", dkim.fold("foo")) + + def DISABLED_test_long_line(self): + # The function is terribly broken, not passing even this simple + # test. + self.assertEqual( + "foo"*24 + "\r\n foo", dkim.fold("foo" * 25)) + + +if __name__ == '__main__': + unittest.main() From 3fa5c5263a21286df9a39dd81e3af0ae8b12e704 Mon Sep 17 00:00:00 2001 From: William Grant Date: Wed, 9 Mar 2011 18:47:27 +1100 Subject: [PATCH 3/9] Add testrepository config. --- .bzrignore | 1 + .testr.conf | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 .bzrignore create mode 100644 .testr.conf diff --git a/.bzrignore b/.bzrignore new file mode 100644 index 0000000..a9b310f --- /dev/null +++ b/.bzrignore @@ -0,0 +1 @@ +.testrepository diff --git a/.testr.conf b/.testr.conf new file mode 100644 index 0000000..3f13aff --- /dev/null +++ b/.testr.conf @@ -0,0 +1,4 @@ +[DEFAULT] +test_command=PYTHONPATH=. python -m subunit.run $LISTOPT $IDOPTION dkim.tests.test_dkim +test_id_option=--load-list $IDFILE +test_list_option=--list From 97ec4a65a41eb27301abd4ff4a7c05244f1a5da6 Mon Sep 17 00:00:00 2001 From: William Grant Date: Wed, 9 Mar 2011 18:49:18 +1100 Subject: [PATCH 4/9] Add TESTING section to README. --- README | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README b/README index d638456..cebb3e1 100644 --- a/README +++ b/README @@ -21,6 +21,17 @@ To build and install pydkim: python setup.py install +TESTING + +To run pydkim's test suite: + + PYTHONPATH=. python dkim/tests/test_dkim.py + +Alternatively, if you have testrepository installed: + + testr init + testr run + USAGE The pydkim library offers one module called dkim. The sign() function takes an From fbe24a00015fb9d54405ff85cc5f18b4463ea7af Mon Sep 17 00:00:00 2001 From: William Grant Date: Wed, 9 Mar 2011 20:10:04 +1100 Subject: [PATCH 5/9] Allow callers to override the DNS function used by verify(). --- dkim/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dkim/__init__.py b/dkim/__init__.py index 23618bd..f8e06c4 100644 --- a/dkim/__init__.py +++ b/dkim/__init__.py @@ -396,7 +396,7 @@ def sign(message, selector, domain, privkey, identity=None, canonicalize=(Simple return sig + "\r\n" -def verify(message, debuglog=None): +def verify(message, debuglog=None, dnsfunc=dnstxt): """Verify a DKIM signature on an RFC822 formatted message. @param message: an RFC822 formatted message (with either \\n or \\r\\n line endings) @@ -548,7 +548,7 @@ def verify(message, debuglog=None): print >>debuglog, "body hash mismatch (got %s, expected %s)" % (base64.b64encode(bodyhash), sig['bh']) return False - s = dnstxt(sig['s']+"._domainkey."+sig['d']+".") + s = dnsfunc(sig['s']+"._domainkey."+sig['d']+".") if not s: return False a = re.split(r"\s*;\s*", s) From 58525fbbd709bfc400d9e9acfea479fea027b939 Mon Sep 17 00:00:00 2001 From: William Grant Date: Wed, 9 Mar 2011 20:10:18 +1100 Subject: [PATCH 6/9] Add basic end-to-end signing and verification tests. --- dkim/tests/data/test.message | 8 ++++++++ dkim/tests/data/test.private | 15 +++++++++++++++ dkim/tests/data/test.txt | 1 + dkim/tests/test_dkim.py | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 dkim/tests/data/test.message create mode 100644 dkim/tests/data/test.private create mode 100644 dkim/tests/data/test.txt diff --git a/dkim/tests/data/test.message b/dkim/tests/data/test.message new file mode 100644 index 0000000..8a7254e --- /dev/null +++ b/dkim/tests/data/test.message @@ -0,0 +1,8 @@ +Received: from localhost +Message-ID: +Date: Mon, 01 Jan 2011 01:02:03 +0400 +From: Test User +To: somebody@example.com +Subject: Testing + +This is a test message. diff --git a/dkim/tests/data/test.private b/dkim/tests/data/test.private new file mode 100644 index 0000000..3800be0 --- /dev/null +++ b/dkim/tests/data/test.private @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- diff --git a/dkim/tests/data/test.txt b/dkim/tests/data/test.txt new file mode 100644 index 0000000..5976ea7 --- /dev/null +++ b/dkim/tests/data/test.txt @@ -0,0 +1 @@ +v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB diff --git a/dkim/tests/test_dkim.py b/dkim/tests/test_dkim.py index c7b271e..1baff54 100644 --- a/dkim/tests/test_dkim.py +++ b/dkim/tests/test_dkim.py @@ -1,8 +1,18 @@ +import os.path import unittest import dkim +def read_test_data(filename): + """Get the content of the given test data file. + + The files live in dkim/tests/data. + """ + path = os.path.join(os.path.dirname(__file__), 'data', filename) + return open(path).read() + + class TestFold(unittest.TestCase): def test_short_line(self): @@ -16,5 +26,29 @@ class TestFold(unittest.TestCase): "foo"*24 + "\r\n foo", dkim.fold("foo" * 25)) +class TestSignAndVerify(unittest.TestCase): + """End-to-end signature and verification tests.""" + + def setUp(self): + self.message = read_test_data("test.message") + self.key = read_test_data("test.private") + + def dnsfunc(self, domain): + self.assertEqual('test._domainkey.example.com.', domain) + return read_test_data("test.txt") + + def test_verifies(self): + # A message verifies after being signed. + sig = dkim.sign(self.message, "test", "example.com", self.key) + res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc) + self.assertTrue(res) + + def test_altered_body_fails(self): + # An altered body fails verification. + sig = dkim.sign(self.message, "test", "example.com", self.key) + res = dkim.verify(sig + self.message + "foo", dnsfunc=self.dnsfunc) + self.assertFalse(res) + + if __name__ == '__main__': unittest.main() From b165714c52e159dcc4d842378d0c12749d904cb3 Mon Sep 17 00:00:00 2001 From: William Grant Date: Wed, 9 Mar 2011 20:16:53 +1100 Subject: [PATCH 7/9] Remove old test which was specific to the original upstrea. --- dkim/__init__.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dkim/__init__.py b/dkim/__init__.py index f8e06c4..b694a07 100644 --- a/dkim/__init__.py +++ b/dkim/__init__.py @@ -629,11 +629,3 @@ def verify(message, debuglog=None, dnsfunc=dnstxt): assert len(v) == len(sig2) # Byte-by-byte compare of signatures return not [1 for x in zip(v, sig2) if x[0] != x[1]] - -if __name__ == "__main__": - message = """From: greg@hewgill.com\r\nSubject: test\r\n message\r\n\r\nHi.\r\n\r\nWe lost the game. Are you hungry yet?\r\n\r\nJoe.\r\n""" - print rfc822_parse(message) - sig = sign(message, "greg", "hewgill.com", open("/home/greg/.domainkeys/rsa.private").read()) - print sig - print verify(sig+message) - #print sign(open("/home/greg/tmp/message").read(), "greg", "hewgill.com", open("/home/greg/.domainkeys/rsa.private").read()) From f9c2c2dcd93ce4ab1cc57a055cc96576e7efb03e Mon Sep 17 00:00:00 2001 From: William Grant Date: Thu, 10 Mar 2011 09:32:15 +1100 Subject: [PATCH 8/9] Add license header to test_dkim. --- dkim/tests/test_dkim.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dkim/tests/test_dkim.py b/dkim/tests/test_dkim.py index 1baff54..aecc326 100644 --- a/dkim/tests/test_dkim.py +++ b/dkim/tests/test_dkim.py @@ -1,3 +1,21 @@ +# 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) 2011 William Grant + import os.path import unittest From 44cb4c357df52009a32ee8fdccf77cc2074d3933 Mon Sep 17 00:00:00 2001 From: William Grant Date: Sat, 12 Mar 2011 11:20:30 +1100 Subject: [PATCH 9/9] Only exclude .testrepository at the root. --- .bzrignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzrignore b/.bzrignore index a9b310f..6a691e0 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1 +1 @@ -.testrepository +/.testrepository