--- dkimpy-0.5.1.orig/debian/docs +++ dkimpy-0.5.1/debian/docs @@ -0,0 +1 @@ +README --- dkimpy-0.5.1.orig/debian/rules +++ dkimpy-0.5.1/debian/rules @@ -0,0 +1,25 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +%: + dh $@ --with python2,python3 + +override_dh_auto_build: + +override_dh_auto_install: + python $(CURDIR)/setup.py install --no-compile -O0 --install-layout=deb \ + --root $(CURDIR)/debian/python-dkim + mv debian/python-dkim/usr/bin/dkimsign.py debian/python-dkim/usr/bin/dkimsign + mv debian/python-dkim/usr/bin/dkimverify.py debian/python-dkim/usr/bin/dkimverify + python3 $(CURDIR)/setup.py install --no-compile -O0 --install-layout=deb \ + --root $(CURDIR)/debian/python3-dkim + rm -rf $(CURDIR)/debian/python3-dkim/usr/bin + rm -rf $(CURDIR)/debian/python3-dkim/usr/share/man + dh_install + +override_dh_auto_clean: + python setup.py clean -a + python3 setup.py clean -a; \ + done + find . -name \*.pyc -exec rm {} \; + dh_clean --- dkimpy-0.5.1.orig/debian/watch +++ dkimpy-0.5.1/debian/watch @@ -0,0 +1,3 @@ +version=3 +http://launchpad.net/pydkim/+download http://launchpad.net/pydkim/.*/.*/pydkim-(.*)\.tar\.gz debian uupdate + --- dkimpy-0.5.1.orig/debian/compat +++ dkimpy-0.5.1/debian/compat @@ -0,0 +1,2 @@ +7 + --- dkimpy-0.5.1.orig/debian/control +++ dkimpy-0.5.1/debian/control @@ -0,0 +1,28 @@ +Source: dkimpy +Section: python +Priority: optional +Maintainer: Scott Kitterman +Uploaders: Debian Python Modules Team +Build-Depends: debhelper (>= 7.3.16), python (>= 2.6.5-2~), python3 +X-Python-Version: >= 2.6 +X-Python3-Version: >= 3.1 +Vcs-Svn: svn://svn.debian.org/python-modules/packages/dkimpy/trunk/ +Vcs-Browser: http://svn.debian.org/viewsvn/python-modules/packages/dkimpy/trunk/ +Standards-Version: 3.9.2 +Homepage: http://launchpad.net/dkimpy + +Package: python-dkim +Architecture: all +Depends: ${python:Depends}, ${misc:Depends}, python-dns|python-dnspython +Breaks: dkimproxy (<< 1.0.1-8.1~) +Description: Python module for DKIM signing and verification + Python module that implements DKIM (DomainKeys Identified Mail) email signing + and verification. It also provides helper scripts for command line signing + and verification. + +Package: python3-dkim +Architecture: all +Depends: ${python3:Depends}, ${misc:Depends}, python3-dns +Description: Python 3 module for DKIM signing and verification + Python 3 module that implements DKIM (DomainKeys Identified Mail) email signing + and verification. --- dkimpy-0.5.1.orig/debian/changelog +++ dkimpy-0.5.1/debian/changelog @@ -0,0 +1,141 @@ +dkimpy (0.5.1-1ubuntu2) precise; urgency=low + + * Cherrypick bug fixes from upstream trunk + - Fixed hashing problem when using sha1 (rev 85) (LP: #969206) + - Added test suite coverage for bag handling of b= tag folding (rev 87) + - Fold b= tags before signing to work around validation issues at Hotmail + and Yahoo and correctly (per RFC) ignore FWS in b= tag when verifying + signatures (rev 88) + + -- Scott Kitterman Tue, 24 Apr 2012 09:36:00 -0400 + +dkimpy (0.5.1-1ubuntu1) precise; urgency=low + + * Change default header signing canonicalization from 'simple' to + 'relaxed' to avoid interoperability problems like those described in + LP 939128 + - This is a work-around, not a fix + + -- Scott Kitterman Wed, 18 Apr 2012 01:00:18 -0400 + +dkimpy (0.5.1-1) unstable; urgency=low + + * New upstream release + - Rename source to match new upstream name + - Updated debian/copyright + * Remove no longer used quilt patch system artifacts + + -- Scott Kitterman Fri, 03 Feb 2012 19:35:05 -0500 + +pydkim (0.5-1) unstable; urgency=low + + * New upstream release + - Drop debian/patches/adjust-setup.py.patch, essential parts incorporated + upstream + - Remove the no longer existing (and never very useful) dkimsend.sh from + debian/docs + + -- Scott Kitterman Wed, 26 Oct 2011 17:39:45 -0400 + +pydkim (0.4.2-1) unstable; urgency=low + + * New upstream release + - Drop debian/patches/dns-namespace.patch, incorporated upstream + + -- Scott Kitterman Fri, 17 Jun 2011 08:36:05 -0500 + +pydkim (0.4.1-1) unstable; urgency=low + + * New upstream release + - Drop debian/patches/fix-key-record-validation.patch and + relaxed-canonicalization.patch, incorporated upstream + - Update debian/patches/adjust-setup.py.patch to match upstream setup.py + versions + - Add debian/patches/dns-namespace.patch to deconflict dns (python- + dnspython) and dkim/dns.py namespaces so the package works with either + python-dns (DNS) or python-dnspython (dns) + - Drop debian/dkimsign.1 and dkimverify.1, provided in the upstream + tarball now + - Drop debian/manpages, installed using upstream setup.py + - Add depends on python-dns and use python-dnspython as an alternate + - Increase minimum python version to 2.6 (X-P-V) and add X-Python3-Version + >= 3.1 for python3 support + - Add python3-dkim to debian/control for python3 support + - Only python3-dns is available for python3, so use this + - Add python3 to build-depends + - Rework debian/rules to build for python3 + - Update debian/copyright + * Update debian/watch and debian/control Homepage: to point at the new + upstream location + * python-dkim Breaks instead of Conflicts dkimproxy + + -- Scott Kitterman Thu, 16 Jun 2011 15:01:59 -0500 + +pydkim (0.3-6) unstable; urgency=low + + * Rebuild for python transition + * Bump Standards-Version to 3.9.2 without futher change + * Drop Breaks: ${python:Breaks} since it is no longer used + + -- Scott Kitterman Wed, 20 Apr 2011 00:12:53 -0400 + +pydkim (0.3-5) unstable; urgency=low + + * Add debian/patches/relaxed-canonicalization.patch to fix body hash + verification failures due to out of sequence operations. Thanks to + Martin Pool for the patch + * Add debian/patches/fix-key-record-validation.patch to fix incorrect key + record validation failures due to invalid assumptions about public key + record requirements + * Bump standards version to 3.9.1 without further change + * Change XS-Python-Version to X-Python-Version + * Add Breaks: ${python:Breaks} + * Drop XB-Python-Version + + -- Scott Kitterman Mon, 07 Mar 2011 00:09:56 -0500 + +pydkim (0.3-4) unstable; urgency=low + + * Convert from CDBS to Debhelper 7: + - Drop cdbs from build-depends and bump required debhelper verion + - Change compat to 7 + - Change debian/rules to DH 7 tiny --with quilt + - Add quilt to build-depends + - Update README.source for quilt + - Remove autogenerated pycompat + * Convert from python-central to dh_python2 + - Drop python-central from build-depends + - Build --with python2 + - Bump python version requirement to 2.6.5-2~ + * Bump standards version to 3.8.4 without further change + * Remove DM-Upload-Allowed (no longer needed) + * Update debian/dkimsign.1 and debian/dkimverify.1 to specify their license + * Use correct © symbol in debian/copyright + * Remove pointless debian/examples file + * Fix typo in previous debian/changelog entry to make lintian happy + + -- Scott Kitterman Mon, 21 Jun 2010 23:20:36 -0400 + +pydkim (0.3-3) unstable; urgency=low + + * Adjust dkimproxy conflict to << 1.0.1-8.1 due to filename collision + (Closes: #511037) + * Add ${misc:Depends} + + -- Scott Kitterman Mon, 12 Jan 2009 23:17:26 -0500 + +pydkim (0.3-2) unstable; urgency=low + + * Conflict dkimproxy << 1.0.1-8 due to filename collision + (Closes: #509045) + + -- Scott Kitterman Fri, 19 Dec 2008 14:34:10 -0500 + +pydkim (0.3-1) unstable; urgency=low + + * Initial Debian package (Closes: #502264) + * Add adjust-setup.py.patch to correct shebang in setup.py and to + not install dkimsend.sh in /usr/bin (at best it's an example and not + suitable for actual use - will install with docs) + + -- Scott Kitterman Thu, 06 Nov 2008 23:53:21 -0500 --- dkimpy-0.5.1.orig/debian/copyright +++ dkimpy-0.5.1/debian/copyright @@ -0,0 +1,35 @@ +This package was debianized by Scott Kitterman on +Thu, 06 Nov 2008 23:12:29 -0500. + +It was downloaded from http://hewgill.com/pydkim + +Copyright Holders: +Copyright © 2008 Greg Hewgill http://hewgill.com +Copyright © 2011 William Grant +Copyright © 2011,2012 Scott Kitterman + +Every file for which the original upstream specified copyright in the original +has been modified from in this altered version of the software. + +License: + +# 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 © 2008 Greg Hewgill http://hewgill.com + +The Debian packaging is © 2008-11, Scott Kitterman and +is licensed under the same terms as pydkim, see above. --- dkimpy-0.5.1.orig/dkim/__init__.py +++ dkimpy-0.5.1/dkim/__init__.py @@ -89,11 +89,6 @@ """Validation error.""" pass -def _remove(s, t): - i = s.find(t) - assert i >= 0 - return s[:i] + s[i+len(t):] - def select_headers(headers, include_headers): """Select message header fields to be signed/verified. @@ -119,14 +114,17 @@ lastindex[h] = i return sign_headers +FWS = r'(?:\r\n\s+)?' +RE_BTAG = re.compile(r'([; ]b'+FWS+r'=)(?:'+FWS+r'[a-zA-Z0-9+/=])*(?:\r\n\Z)?') + def hash_headers(hasher, canonicalize_headers, headers, include_headers, - sigheaders, sig): + sigheader, sig): """Update hash for signed message header fields.""" sign_headers = select_headers(headers,include_headers) # The call to _remove() assumes that the signature b= only appears # once in the signature header cheaders = canonicalize_headers.canonicalize_headers( - [(sigheaders[0][0], _remove(sigheaders[0][1], sig[b'b']))]) + [(sigheader[0], RE_BTAG.sub(b'\\1',sigheader[1]))]) # the dkim sig is hashed with no trailing crlf, even if the # canonicalization algorithm would add one. for x,y in sign_headers + [(x, y.rstrip()) for x,y in cheaders]: @@ -381,7 +379,7 @@ #: @param identity: the DKIM identity value for the signature #: (default "@"+domain) #: @param canonicalize: the canonicalization algorithms to use - #: (default (Simple, Simple)) + #: (default (Relaxed, Simple)) #: @param include_headers: a list of strings indicating which headers #: are to be signed (default rfc4871 recommended headers) #: @param length: true if the l= tag should be included to indicate @@ -390,7 +388,7 @@ #: @raise DKIMException: when the message, include_headers, or key are badly #: formed. def sign(self, selector, domain, privkey, identity=None, - canonicalize=(b'simple',b'simple'), include_headers=None, length=False): + canonicalize=(b'relaxed',b'simple'), include_headers=None, length=False): try: pk = parse_pem_private_key(privkey) except UnparsableKeyError as e: @@ -435,25 +433,33 @@ (b't', str(int(time.time())).encode('ascii')), (b'h', b" : ".join(include_headers)), (b'bh', bodyhash), - (b'b', b""), + # Force b= to fold onto it's own line so that refolding after + # adding sig doesn't change whitespace for previous tags. + (b'b', b'0'*60), ] if x] include_headers = [x.lower() for x in include_headers] # record what verify should extract self.include_headers = tuple(include_headers) sig_value = fold(b"; ".join(b"=".join(x) for x in sigfields)) + sig_value = RE_BTAG.sub(b'\\1',sig_value) dkim_header = (b'DKIM-Signature', b' ' + sig_value) - h = hashlib.sha256() + h = hasher() sig = dict(sigfields) self.signed_headers = hash_headers( - h, canon_policy, headers, include_headers, [dkim_header],sig) + h, canon_policy, headers, include_headers, dkim_header,sig) self.logger.debug("sign headers: %r" % self.signed_headers) try: sig2 = RSASSA_PKCS1_v1_5_sign(h, pk) except DigestTooLargeError: raise ParameterError("digest too large for modulus") - sig_value += base64.b64encode(bytes(sig2)) + # Folding b= is explicity allowed, but yahoo and live.com are broken + #sig_value += base64.b64encode(bytes(sig2)) + # Instead of leaving unfolded (which lets an MTA fold it later and still + # breaks yahoo and live.com), we change the default signing mode to + # relaxed/simple (for broken receivers), and fold now. + sig_value = fold(sig_value + base64.b64encode(bytes(sig2))) self.domain = domain self.selector = selector @@ -480,7 +486,6 @@ except InvalidTagValueList as e: raise MessageFormatError(e) - sig = parse_tag_value(sigheaders[idx][1]) logger = self.logger logger.debug("sig: %r" % sig) @@ -540,7 +545,7 @@ include_headers.append('from') h = hasher() self.signed_headers = hash_headers( - h, canon_policy, headers, include_headers, sigheaders, sig) + h, canon_policy, headers, include_headers, sigheaders[idx], sig) try: self.signature_fields = sig signature = base64.b64decode(re.sub(br"\s+", b"", sig[b'b'])) @@ -558,7 +563,7 @@ @param domain: the DKIM domain value for the signature @param privkey: a PKCS#1 private key in base64-encoded text form @param identity: the DKIM identity value for the signature (default "@"+domain) - @param canonicalize: the canonicalization algorithms to use (default (Simple, Simple)) + @param canonicalize: the canonicalization algorithms to use (default (Relaxed, Simple)) @param include_headers: a list of strings indicating which headers are to be signed (default all headers not listed as SHOULD NOT sign) @param length: true if the l= tag should be included to indicate body length (default False) @param logger: a logger to which debug info will be written (default None) --- dkimpy-0.5.1.orig/dkim/tests/test_dkim.py +++ dkimpy-0.5.1/dkim/tests/test_dkim.py @@ -86,9 +86,12 @@ res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc) self.assertFalse(res) - def test_dkim_dignature_canonicalization(self): + def test_dkim_signature_canonicalization(self): # # Relaxed-mode header signing is wrong + # + # Simple-mode signature header verification is wrong + # (should ignore FWS anywhere in signature tag: b=) sample_msg = """\ From: mbp@canonical.com To: scottk@example.com @@ -125,8 +128,13 @@ dkim_header = dkim.sign(sample_msg, 'example', 'canonical.com', sample_privkey, canonicalize=(header_mode, dkim.Relaxed)) - signed = dkim_header + sample_msg - + # 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=lambda x: _dns_responses[x]) self.assertTrue(result)