Package: release.debian.org Severity: normal Tags: buster User: release.debian....@packages.debian.org Usertags: pu
This proposed update includes fixes for all user reported bugs since the last version available before buster froze. These are all issues reported by actual package users (not all on Debian). The two most imoprtant issues are: - Updating the ARC (Authenticated Receive Chain) code to match the final version of the spec. RFC 8617 is published not, so it is highly unlikely to change again during Buster's lifetime. - Ignoring unknown service types: Since 0.9.1 was released, a new DKIM service type, TLSRPT, has been defined and is starting to see use. RFC 6376 (DKIM RFC) always required unknown service types to be ignored, but since there had only ever been one, that check was never implemented. This change will prevent mis-processing of TLSRPT service signatures. Some of the fixes (like the pydns CNAME processing issue, for example) don't directly affect dkimpy as packaged in Debian, but I would prefer to use the upstream bugfix release without modification to minimize risk I make a mistake when extracting changes. I have the package ready to go. I've run the autopkgtest in a Buster chroot and it passes. All these fixes are in version 1.0.1 in Testing. Thanks. Full debian/changelog with upstream changelog entries follows: * Update debian/watch to only see 0.9 versions for stable updates * Update debian/gbp.conf to use buster branches * New upstream bugfix releases: * 0.9.6 - Follow CNAMES when looking up key records when using DNS (pydns) (LP: #1856421) - Provide specialized error message when signing or verifying ed25519 signatures and pynacl is not installed (LP: #1854475) - Catch binascii related key format errors (LP: #1854477) * 0.9.5 - Ignore unknown service types in key records (LP: #1847020) - This is required by RFC 6376 and predecessors. It becomes important now that RFC 8460, which defines a new DKIM service type exists. This change is required to avoid processing tlsrpt keys like regular email keys, which is incorrect, they have different requirements. * 0.9.4 - Add LICENSE to MANIFEST.in so it is included in the tarball (LP: #1845318) * 0.9.3 - Fix linesep setting in arcsign script (LP: #1838262) (Thanks to Gowtham Gopalakrishnan for the report and the patch) - Fix default canonicalization for DKIM signature verification to be simple/simple per RFC 6376 (LP: #1839299) (Thanks to Cyril Nicodème for the report and a suggested fix) * 0.9.2 - Fix the arcsign script so it works with the current API (Note: the new srv_id option is the authserv_id to use in the ARC signatures - Only AR fields with an authserv-id that matches srv_id will be considered for ARC signing) - Fix cv=none processing for initial signature in chain - Add additional text documenting use of srv_id for ARC signing to docstrings and man 1 arcsign (LP: #1808301) - Use same line seperator for output as input in dkimsign/arcsign (LP: #1808686) - Refactor canonicalization.py strip_trailing_lines to avoid using re for more consistent processing across python versions (Thanks to Jonathan Bastien-Filiatrault for the change) - Refactor header folding for more consistent results, including reduced stray whitespace (Also Jonathan Bastien-Filiatrault) - Don't log message headers and body unless explicitely requested. This should also reduce memory usage on large messages. (Jonathan Bastien-Filiatrault) - Clarify the crlf does not count towards line length in fold - Adjust fold maxlen to one shorter for lines after the first, since they already have a leading space (LP: #1823008) Scott K
diff -Nru dkimpy-0.9.1/ChangeLog dkimpy-0.9.6/ChangeLog --- dkimpy-0.9.1/ChangeLog 2018-12-09 14:04:26.000000000 -0500 +++ dkimpy-0.9.6/ChangeLog 2019-12-24 10:22:40.000000000 -0500 @@ -1,3 +1,50 @@ +2019-12-24 Version 0.9.6 + - Follow CNAMES when looking up key records when using DNS (pydns) + (LP: #1856421) + - Provide specialized error message when signing or verifying ed25519 + signatures and pynacl is not installed (LP: #1854475) + - Catch binascii related key format errors (LP: #1854477) + +2019-10-07 Version 0.9.5 + - Ignore unknown service types in key records (LP: #1847020) + - This is required by RFC 6376 and predecessors. It becomes important + now that RFC 8460, which defines a new DKIM service type exists. This + change is required to avoid processing tlsrpt keys like regular email + keys, which is incorrect, they have different requirements. + +2019-09-25 Verstion 0.9.4 + - Add LICENSE to MANIFEST.in so it is included in the tarball (LP: + #1845318) + +2019-08-09 Version 0.9.3 + - Fix linesep setting in arcsign script (LP: #1838262) (Thanks to Gowtham + Gopalakrishnan for the report and the patch) + - Fix default canonicalization for DKIM signature verification to be + simple/simple per RFC 6376 (LP: #1839299) (Thanks to Cyril Nicodème for + the report and a suggested fix) + +2019-04-14 Version 0.9.2 + - Fix the arcsign script so it works with the current API (Note: the new + srv_id option is the authserv_id to use in the ARC signatures - Only AR + fields with an authserv-id that matches srv_id will be considered for + ARC signing) + - Fix cv=none processing for initial signature in chain + - Add additional text documenting use of srv_id for ARC signing to + docstrings and man 1 arcsign (LP: #1808301) + - Use same line seperator for output as input in dkimsign/arcsign + (LP: #1808686) + - Refactor canonicalization.py strip_trailing_lines to avoid using re for + more consistent processing across python versions (Thanks to Jonathan + Bastien-Filiatrault for the change) + - Refactor header folding for more consistent results, including reduced + stray whitespace (Also Jonathan Bastien-Filiatrault) + - Don't log message headers and body unless explicitely requested. This + should also reduce memory usage on large messages. (Jonathan + Bastien-Filiatrault) + - Clarify the crlf does not count towards line length in fold + - Adjust fold maxlen to one shorter for lines after the first, since they + already have a leading space (LP: #1823008) + 2018-12-09 Version 0.9.1 - Fixed ARC verification to fail if h= tag is present in Arc-Seal and added tests diff -Nru dkimpy-0.9.1/debian/changelog dkimpy-0.9.6/debian/changelog --- dkimpy-0.9.1/debian/changelog 2018-12-09 15:33:28.000000000 -0500 +++ dkimpy-0.9.6/debian/changelog 2019-12-24 10:41:22.000000000 -0500 @@ -1,3 +1,53 @@ +dkimpy (0.9.6-0+deb10u1) buster; urgency=medium + + * Update debian/watch to only see 0.9 versions for stable updates + * Update debian/gbp.conf to use buster branches + * New upstream bugfix releases: + * 0.9.6 + - Follow CNAMES when looking up key records when using DNS (pydns) + (LP: #1856421) + - Provide specialized error message when signing or verifying ed25519 + signatures and pynacl is not installed (LP: #1854475) + - Catch binascii related key format errors (LP: #1854477) + * 0.9.5 + - Ignore unknown service types in key records (LP: #1847020) + - This is required by RFC 6376 and predecessors. It becomes important + now that RFC 8460, which defines a new DKIM service type exists. This + change is required to avoid processing tlsrpt keys like regular email + keys, which is incorrect, they have different requirements. + * 0.9.4 + - Add LICENSE to MANIFEST.in so it is included in the tarball (LP: + #1845318) + * 0.9.3 + - Fix linesep setting in arcsign script (LP: #1838262) (Thanks to Gowtham + Gopalakrishnan for the report and the patch) + - Fix default canonicalization for DKIM signature verification to be + simple/simple per RFC 6376 (LP: #1839299) (Thanks to Cyril Nicodème for + the report and a suggested fix) + * 0.9.2 + - Fix the arcsign script so it works with the current API (Note: the new + srv_id option is the authserv_id to use in the ARC signatures - Only AR + fields with an authserv-id that matches srv_id will be considered for + ARC signing) + - Fix cv=none processing for initial signature in chain + - Add additional text documenting use of srv_id for ARC signing to + docstrings and man 1 arcsign (LP: #1808301) + - Use same line seperator for output as input in dkimsign/arcsign + (LP: #1808686) + - Refactor canonicalization.py strip_trailing_lines to avoid using re for + more consistent processing across python versions (Thanks to Jonathan + Bastien-Filiatrault for the change) + - Refactor header folding for more consistent results, including reduced + stray whitespace (Also Jonathan Bastien-Filiatrault) + - Don't log message headers and body unless explicitely requested. This + should also reduce memory usage on large messages. (Jonathan + Bastien-Filiatrault) + - Clarify the crlf does not count towards line length in fold + - Adjust fold maxlen to one shorter for lines after the first, since they + already have a leading space (LP: #1823008) + + -- Scott Kitterman <sc...@kitterman.com> Tue, 24 Dec 2019 10:41:22 -0500 + dkimpy (0.9.1-1) unstable; urgency=medium * New upstream release diff -Nru dkimpy-0.9.1/debian/gbp.conf dkimpy-0.9.6/debian/gbp.conf --- dkimpy-0.9.1/debian/gbp.conf 2018-02-07 01:20:55.000000000 -0500 +++ dkimpy-0.9.6/debian/gbp.conf 2019-12-24 10:39:42.000000000 -0500 @@ -1,2 +1,3 @@ [DEFAULT] -debian-branch=debian/master +debian-branch=debian/buster-updates +upstream-branch=upstream-buster diff -Nru dkimpy-0.9.1/debian/watch dkimpy-0.9.6/debian/watch --- dkimpy-0.9.1/debian/watch 2018-12-09 15:28:17.000000000 -0500 +++ dkimpy-0.9.6/debian/watch 2019-12-24 10:32:40.000000000 -0500 @@ -1,4 +1,4 @@ version=3 opts="pgpsigurlmangle=s/$/.asc/" https://launchpad.net/dkimpy/+download \ -https://launchpad.net/dkimpy/.*/.*/dkimpy-(.*)\.tar\.gz +https://launchpad.net/dkimpy/.*/.*/dkimpy-(0.9.*)\.tar\.gz diff -Nru dkimpy-0.9.1/dkim/arcsign.py dkimpy-0.9.6/dkim/arcsign.py --- dkimpy-0.9.1/dkim/arcsign.py 2018-10-27 20:48:51.000000000 -0400 +++ dkimpy-0.9.6/dkim/arcsign.py 2019-11-03 12:09:47.000000000 -0500 @@ -24,6 +24,13 @@ # This has been modified from the original software. # Copyright (c) 2016 Google, Inc. # Contact: Brandon Long <bl...@google.com> +# This has been modified from the original software. +# Copyright (c) 2017, 2018, 2019 Scott Kitterman <sc...@kitterman.com> +# +# This has been modified from the original software. +# Copyright (c) 2017 Valimail Inc +# Contact: Gene Shuman <g...@valimail.com> + from __future__ import print_function @@ -37,8 +44,8 @@ def main(): - if len(sys.argv) != 4: - print("Usage: arcsign.py selector domain privatekeyfile", file=sys.stderr) + if len(sys.argv) != 5: + print("Usage: arcsign.py selector domain privatekeyfile srv_id", file=sys.stderr) sys.exit(1) if sys.version_info[0] >= 3: @@ -49,17 +56,18 @@ selector = sys.argv[1].encode('ascii') domain = sys.argv[2].encode('ascii') privatekeyfile = sys.argv[3] + srv_id = sys.argv[4].encode('ascii') message = sys.stdin.read() # Pick a cv status cv = dkim.CV_None - if re.search('arc-seal', message, re.IGNORECASE): + if re.search(b'arc-seal', message, re.IGNORECASE): cv = dkim.CV_Pass #try: sig = dkim.arc_sign(message, selector, domain, open(privatekeyfile, "rb").read(), - domain + ": none", cv) + srv_id, cv, linesep=dkim.util.get_linesep(message)) for line in sig: sys.stdout.write(line) sys.stdout.write(message) diff -Nru dkimpy-0.9.1/dkim/canonicalization.py dkimpy-0.9.6/dkim/canonicalization.py --- dkimpy-0.9.1/dkim/canonicalization.py 2018-10-29 19:42:01.000000000 -0400 +++ dkimpy-0.9.6/dkim/canonicalization.py 2019-11-03 12:09:47.000000000 -0500 @@ -41,15 +41,21 @@ def strip_trailing_lines(content): - content = re.sub(b"(\r\n)*$", b"\r\n", content) - # Yes, this is horrible, but regex processing changed in python3.7 and it - # is the least horrible solution I came up with for python2.7, python3.7, - # and python3 << 3.7 combined support. Better solution welcome. - if len(content) >= 4: - if (content[len(content)-4:] == b'\r\n\r\n'): - content = content[:len(content)-2] - return content + end = None + while content.endswith(b"\r\n", 0, end): + if end is None: + end = -2 + else: + end -= 2 + if end is None: + return content + b"\r\n" + + end += 2 + if end == 0: + return content + + return content[:end] def unfold_header_value(content): return re.sub(b"\r\n", b"", content) diff -Nru dkimpy-0.9.1/dkim/dkimsign.py dkimpy-0.9.6/dkim/dkimsign.py --- dkimpy-0.9.1/dkim/dkimsign.py 2018-10-27 20:48:51.000000000 -0400 +++ dkimpy-0.9.6/dkim/dkimsign.py 2019-11-03 12:09:47.000000000 -0500 @@ -70,8 +70,8 @@ message = sys.stdin.read() try: - d = dkim.DKIM(message,logger=logger, - signature_algorithm=args.signalg) + d = dkim.DKIM(message,logger=logger, signature_algorithm=args.signalg, + linesep=dkim.util.get_linesep(message)) sig = d.sign(args.selector, args.domain, open( args.privatekeyfile, "rb").read(), identity = args.identity, canonicalize=canonicalize, include_headers=include_headers, diff -Nru dkimpy-0.9.1/dkim/dnsplug.py dkimpy-0.9.6/dkim/dnsplug.py --- dkimpy-0.9.1/dkim/dnsplug.py 2018-10-29 21:52:26.000000000 -0400 +++ dkimpy-0.9.6/dkim/dnsplug.py 2019-12-24 10:21:38.000000000 -0500 @@ -44,7 +44,10 @@ response = DNS.DnsRequest(name, qtype='txt').req() if not response.answers: return None - return b''.join(response.answers[0]['data']) + for answer in response.answers: + if answer['typename'].lower() == 'txt': + return b''.join(answer['data']) + return None def get_txt_Milter_dns(name): diff -Nru dkimpy-0.9.1/dkim/__init__.py dkimpy-0.9.6/dkim/__init__.py --- dkimpy-0.9.1/dkim/__init__.py 2018-11-09 18:30:35.000000000 -0500 +++ dkimpy-0.9.6/dkim/__init__.py 2019-12-24 10:21:38.000000000 -0500 @@ -24,7 +24,7 @@ # Contact: Brandon Long <bl...@google.com> # # This has been modified from the original software. -# Copyright (c) 2016, 2017, 2018 Scott Kitterman <sc...@kitterman.com> +# Copyright (c) 2016, 2017, 2018, 2019 Scott Kitterman <sc...@kitterman.com> # # This has been modified from the original software. # Copyright (c) 2017 Valimail Inc @@ -37,6 +37,7 @@ import logging import re import time +import binascii # only needed for arc try: @@ -112,13 +113,15 @@ class HashThrough(object): - def __init__(self, hasher): + def __init__(self, hasher, debug=False): self.data = [] self.hasher = hasher self.name = hasher.name + self.debug = debug def update(self, data): - self.data.append(data) + if self.debug: + self.data.append(data) return self.hasher.update(data) def digest(self): @@ -175,7 +178,6 @@ """ Nacl package not installed, needed for ed25119 signatures """ pass - class UnknownKeyTypeError(DKIMException): """ Key type (k tag) is not known (rsa/ed25519) """ @@ -365,13 +367,14 @@ return s.encode('ascii') -def fold(header, namelen=0): - """Fold a header line into multiple crlf-separated lines at column 72. +def fold(header, namelen=0, linesep=b'\r\n'): + """Fold a header line into multiple crlf-separated lines of text at column + 72. The crlf does not count for line length. >>> text(fold(b'foo')) 'foo' >>> text(fold(b'foo '+b'foo'*24).splitlines()[0]) - 'foo ' + 'foo ' >>> text(fold(b'foo'*25).splitlines()[-1]) ' foo' >>> len(fold(b'foo'*25).splitlines()[0]) @@ -380,6 +383,8 @@ 'x' >>> text(fold(b'xyz'*24)) 'xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz' + >>> len(fold(b'xyz'*48)) + 150 """ # 72 is the max line length we actually want, but the header field name # has to fit in the first line too (See Debian Bug #863690). @@ -399,11 +404,12 @@ i = header[:maxleng].rfind(b" ") if i == -1: j = maxleng + pre += header[:j] + linesep + b" " else: j = i + 1 - pre += header[:j] + b"\r\n " + pre += header[:i] + linesep + b" " header = header[j:] - namelen = 0 + maxleng = 71 if len(header) > 2: return pre + header else: @@ -431,7 +437,10 @@ pass try: if pub[b'k'] == b'ed25519': - pk = nacl.signing.VerifyKey(pub[b'p'], encoder=nacl.encoding.Base64Encoder) + try: + pk = nacl.signing.VerifyKey(pub[b'p'], encoder=nacl.encoding.Base64Encoder) + except NameError: + raise NaClNotFoundError('pynacl module required for ed25519 signing, see README.md') keysize = 256 ktag = b'ed25519' except KeyError: @@ -447,6 +456,16 @@ ktag = b'rsa' if pub[b'k'] != b'rsa' and pub[b'k'] != b'ed25519': raise KeyFormatError('unknown algorithm in k= tag: {0}'.format(pub[b'k'])) + try: + # Ignore unknown service types, RFC 6376 3.6.1 + if pub[b's'] != b'*' and pub[b's'] != b'email': + pk = None + keysize = None + ktag = None + raise KeyFormatError('unknown service type in s= tag: {0}'.format(pub[b's'])) + except: + # Default is '*' - all service types, so no error if missing from key record + pass return pk, keysize, ktag @@ -459,12 +478,15 @@ #: (with either \\n or \\r\\n line endings) #: @param logger: a logger to which debug info will be written (default None) #: @param signature_algorithm: the signing algorithm to use when signing + #: @param debug_content: log headers and body after canonicalization (default False) + #: @param linesep: use this line seperator for folding the headers def __init__(self,message=None,logger=None,signature_algorithm=b'rsa-sha256', - minkey=1024): + minkey=1024, linesep=b'\r\n', debug_content=False): self.set_message(message) if logger is None: logger = get_default_logger() self.logger = logger + self.debug_content = debug_content and logger.isEnabledFor(logging.DEBUG) if signature_algorithm not in HASH_ALGORITHMS: raise ParameterError( "Unsupported signature algorithm: "+signature_algorithm) @@ -481,6 +503,9 @@ #: Minimum public key size. Shorter keys raise KeyFormatError. The #: default is 1024 self.minkey = minkey + # use this line seperator for output + self.linesep = linesep + #: Header fields to protect from additions by default. #: @@ -607,16 +632,17 @@ header_value = b"; ".join(b"=".join(x) for x in fields) if not standardize: - header_value = fold(header_value, namelen=len(header_name)) + header_value = fold(header_value, namelen=len(header_name), linesep=b'\r\n') header_value = RE_BTAG.sub(b'\\1',header_value) header = (header_name, b' ' + header_value) - h = HashThrough(self.hasher()) + h = HashThrough(self.hasher(), self.debug_content) sig = dict(fields) headers = canon_policy.canonicalize_headers(self.headers) self.signed_headers = hash_headers( h, canon_policy, headers, include_headers, header, sig) - self.logger.debug("sign %s headers: %r" % (header_name, h.hashed())) + if self.debug_content: + self.logger.debug("sign %s headers: %r" % (header_name, h.hashed())) if self.signature_algorithm == b'rsa-sha256' or self.signature_algorithm == b'rsa-sha1': try: @@ -633,10 +659,10 @@ # relaxed/simple (for broken receivers), and fold now. idx = [i for i in range(len(fields)) if fields[i][0] == b'b'][0] fields[idx] = (b'b', base64.b64encode(bytes(sig2))) - header_value = b"; ".join(b"=".join(x) for x in fields) + b"\r\n" + header_value = b"; ".join(b"=".join(x) for x in fields) + self.linesep if not standardize: - header_value = fold(header_value, namelen=len(header_name)) + header_value = fold(header_value, namelen=len(header_name), linesep=self.linesep) return header_value @@ -652,9 +678,12 @@ except KeyFormatError as e: self.logger.error("%s" % e) return False + except binascii.Error as e: + self.logger.error('KeyFormatError: {0}'.format(e)) + return False try: - canon_policy = CanonicalizationPolicy.from_c_value(sig.get(b'c', b'relaxed/relaxed')) + canon_policy = CanonicalizationPolicy.from_c_value(sig.get(b'c', b'simple/simple')) except InvalidCanonicalizationPolicyError as e: raise MessageFormatError("invalid c= value: %s" % e.args[0]) @@ -662,13 +691,14 @@ # validate body if present if b'bh' in sig: - h = HashThrough(hasher()) + h = HashThrough(hasher(), self.debug_content) body = canon_policy.canonicalize_body(self.body) if b'l' in sig: body = body[:int(sig[b'l'])] h.update(body) - self.logger.debug("body hashed: %r" % h.hashed()) + if self.debug_content: + self.logger.debug("body hashed: %r" % h.hashed()) bodyhash = h.digest() self.logger.debug("bh: %s" % base64.b64encode(bodyhash)) @@ -687,12 +717,13 @@ # generalized to check for extras of other singleton headers. if b'from' in include_headers: include_headers.append(b'from') - h = HashThrough(hasher()) + h = HashThrough(hasher(), self.debug_content) headers = canon_policy.canonicalize_headers(self.headers) self.signed_headers = hash_headers( h, canon_policy, headers, include_headers, sig_header, sig) - self.logger.debug("signed for %s: %r" % (sig_header[0], h.hashed())) + if self.debug_content: + self.logger.debug("signed for %s: %r" % (sig_header[0], h.hashed())) signature = base64.b64decode(re.sub(br"\s+", b"", sig[b'b'])) if ktag == b'rsa': try: @@ -761,7 +792,10 @@ except UnparsableKeyError as e: raise KeyFormatError(str(e)) elif self.signature_algorithm == b'ed25519-sha256': - pk = nacl.signing.SigningKey(privkey, encoder=nacl.encoding.Base64Encoder) + try: + pk = nacl.signing.SigningKey(privkey, encoder=nacl.encoding.Base64Encoder) + except NameError: + raise NaClNotFoundError('pynacl module required for ed25519 signing, see README.md') if identity is not None and not identity.endswith(domain): raise ParameterError("identity must end with domain") @@ -946,14 +980,13 @@ results_lists = [raw.replace(srv_id + b';', b'').strip() for (raw, parsed) in auth_headers] results_lists = [tags.split(b';') for tags in results_lists] results = [tag.strip() for sublist in results_lists for tag in sublist] - auth_results = srv_id + b'; ' + b';\r\n '.join(results) + auth_results = srv_id + b'; ' + (b';' + self.linesep + b' ').join(results) # extract cv parsed_auth_results = AuthenticationResultsHeader.parse('Authentication-Results: ' + auth_results.decode('utf-8')) arc_results = [res for res in parsed_auth_results.results if res.method == 'arc'] if len(arc_results) == 0: - self.logger.debug("no AR arc stamps found, chain terminated") - return [] + chain_validation_status = CV_None elif len(arc_results) != 1: self.logger.debug("multiple AR arc stamps found, failing chain") chain_validation_status = CV_Fail @@ -988,7 +1021,8 @@ if instance == 1 and chain_validation_status != CV_None: raise ParameterError("No existing chain found on message, cv should be none") elif instance != 1 and chain_validation_status == CV_None: - raise ParameterError("cv=none not allowed on instance %d" % instance) + self.logger.debug("no previous AR arc results found and instance > 1, chain terminated") + return [] new_arc_set = [] if chain_validation_status != CV_Fail: @@ -1008,9 +1042,10 @@ canon_policy = CanonicalizationPolicy.from_c_value(b'relaxed/relaxed') self.hasher = HASH_ALGORITHMS[self.signature_algorithm] - h = HashThrough(self.hasher()) + h = HashThrough(self.hasher(), self.debug_content) h.update(canon_policy.canonicalize_body(self.body)) - self.logger.debug("sign ams body hashed: %r" % h.hashed()) + if self.debug_content: + self.logger.debug("sign ams body hashed: %r" % h.hashed()) bodyhash = base64.b64encode(h.digest()) # Compute ARC-Message-Signature @@ -1173,6 +1208,9 @@ # and this can use simple canonicalization raw_ams_header = [(x, y) for (x, y) in self.headers if x.lower() == b'arc-message-signature'][0] + # Only relaxed canonicalization used by ARC + if b'c' not in sig: + sig[b'c'] = b'relaxed/relaxed' try: ams_valid = self.verify_sig(sig, include_headers, raw_ams_header, dnsfunc) except DKIMException as e: @@ -1201,6 +1239,9 @@ as_include_headers = [x[0].lower() for x in arc_headers] as_include_headers.reverse() as_header = (b'ARC-Seal', b' ' + as_value) + # Only relaxed canonicalization used by ARC + if b'c' not in sig: + sig[b'c'] = b'relaxed/relaxed' try: as_valid = self.verify_sig(sig, as_include_headers[:-1], as_header, dnsfunc) except DKIMException as e: @@ -1215,7 +1256,8 @@ def sign(message, selector, domain, privkey, identity=None, canonicalize=(b'relaxed', b'simple'), signature_algorithm=b'rsa-sha256', - include_headers=None, length=False, logger=None): + include_headers=None, length=False, logger=None, + linesep=b'\r\n'): # type: (bytes, bytes, bytes, bytes, bytes, tuple, bytes, list, bool, any) -> bytes """Sign an RFC822 message and return the DKIM-Signature header line. @param message: an RFC822 formatted message (with either \\n or \\r\\n line endings) @@ -1228,11 +1270,12 @@ @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) + @param linesep: use this line seperator for folding the headers @return: DKIM-Signature header field terminated by \\r\\n @raise DKIMException: when the message, include_headers, or key are badly formed. """ - d = DKIM(message,logger=logger,signature_algorithm=signature_algorithm) + d = DKIM(message,logger=logger,signature_algorithm=signature_algorithm,linesep=linesep) return d.sign(selector, domain, privkey, identity=identity, canonicalize=canonicalize, include_headers=include_headers, length=length) @@ -1259,23 +1302,24 @@ def arc_sign(message, selector, domain, privkey, srv_id, signature_algorithm=b'rsa-sha256', include_headers=None, timestamp=None, - logger=None, standardize=False): + logger=None, standardize=False, linesep=b'\r\n'): # type: (bytes, bytes, bytes, bytes, bytes, bytes, list, any, any, bool) -> list """Sign an RFC822 message and return the ARC set header lines for the next instance @param message: an RFC822 formatted message (with either \\n or \\r\\n line endings) @param selector: the DKIM selector value for the signature @param domain: the DKIM domain value for the signature @param privkey: a PKCS#1 private key in base64-encoded text form - @param srv_id: the authserv_id used to identify the ADMD's AR headers + @param srv_id: the authserv_id used to identify the ADMD's AR headers and to use for ARC authserv_id @param signature_algorithm: the signing algorithm to use when signing @param include_headers: a list of strings indicating which headers are to be signed (default all headers not listed as SHOULD NOT sign) @param timestamp: the time in integer seconds when the message is sealed (default is int(time.time) based on platform, can be string or int) @param logger: a logger to which debug info will be written (default None) + @param linesep: use this line seperator for folding the headers @return: A list containing the ARC set of header fields for the next instance @raise DKIMException: when the message, include_headers, or key are badly formed. """ - a = ARC(message,logger=logger,signature_algorithm=b'rsa-sha256') + a = ARC(message,logger=logger,signature_algorithm=b'rsa-sha256',linesep=linesep) if not include_headers: include_headers = a.default_sign_headers() return a.sign(selector, domain, privkey, srv_id, include_headers=include_headers, diff -Nru dkimpy-0.9.1/dkim/tests/data/rfc6376.signed.rsa.msg dkimpy-0.9.6/dkim/tests/data/rfc6376.signed.rsa.msg --- dkimpy-0.9.1/dkim/tests/data/rfc6376.signed.rsa.msg 1969-12-31 19:00:00.000000000 -0500 +++ dkimpy-0.9.6/dkim/tests/data/rfc6376.signed.rsa.msg 2019-12-15 02:33:19.000000000 -0500 @@ -0,0 +1,20 @@ +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; + d=football.example.com; i=@football.example.com; + q=dns/txt; s=test; t=1527915362; h=from : to : subject : + date : message-id : from : subject : date; + bh=4bLNXImK9drULnmePzZNEBleUanJCX5PIsDIFoH4KTQ=; + b=icKcLSEZYXJ95flvWE8FT6hl5iqd8MC/LEKYH0QjsqYy6MO/4pgVNCZH + l/RAXAuADxE/40Fg7uTlxwwD1hjN2Ple6J//cJfslBdDOq6zTVbne1dqtl + NOat7iamJ1AfRqyG+ja7a2AZsrpUuJ7VA6O+0zRYPqpwMEkEFIzI9i/Xk= +From: Joe SixPack <j...@football.example.com> +To: Suzie Q <su...@shopping.example.net> +Subject: Is dinner ready? +Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT) +Message-ID: <20030712040037.46341.5...@football.example.com> + +Hi. + +We lost the game. Are you hungry yet? + +Joe. + diff -Nru dkimpy-0.9.1/dkim/tests/test_arc.py dkimpy-0.9.6/dkim/tests/test_arc.py --- dkimpy-0.9.1/dkim/tests/test_arc.py 2018-11-09 19:56:17.000000000 -0500 +++ dkimpy-0.9.6/dkim/tests/test_arc.py 2019-12-24 10:21:38.000000000 -0500 @@ -74,8 +74,7 @@ sig_lines = dkim.arc_sign( self.message, b"test", b"example.com", self.key, b"lists.example.org", timestamp="12345") - expected_sig = [b'ARC-Seal: i=1; cv=none; a=rsa-sha256; d=example.com; s=test; t=12345; \r\n b=2DTLaiAcKznJwwNOWoOG8WBsdTq+/S92TZbURDxkgjGCmsSw8czQiisf02sC92\r\n 0nswz3JItA80l70iguM00onrj3eCe41yRDzB8lQL3kbrDyM+wUewmyhPoifRTsng\r\n t9ELTFrax4kCeHv6SdNz3uJfGYwQc+WCFEchXt3szNTRM=\r\n', b'ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; \r\n d=example.com; s=test; t=12345; h=message-id : \r\n date : from : to : subject : from; \r\n bh=wE7NXSkgnx9PGiavN4OZhJztvkqPDlemV3OGuEnLwNo=; \r\n b=a0f6qc3k9eECTSR155A0TQS+LjqPFWfI/brQBA83EUz00SNxj\r\n 1wmWykvs1hhBVeM0r1kEQc6CKbzRYaBNSiFj4q8JBpRIujLz1qL\r\n yGmPuAI6ddu/Z/1hQxgpVcp/odmI1UMV2R+d+yQ7tUp3EQxF/GY\r\n Nt22rV4rNmDmANZVqJ90=\r\n', b'ARC-Authentication-Results: i=1; lists.example.org; arc=none;\r\n spf=pass smtp.mfrom=jqd@d1.example;\r\n dkim=pass (1024-bit key) header.i=@d1.example;\r\n dmarc=pass\r\n'] - + expected_sig = [b'ARC-Seal: i=1; cv=none; a=rsa-sha256; d=example.com; s=test; t=12345;\r\n b=MBw2+L1/4PuYWJlt1tZlDtbOvyfbyH2t2N6DinFV/BIaB2LqbDKTYjXXk9HuuK1/qEkTd\r\n TxCYScIrtVO7pFbGiSawMuLatVzHNCqTURa1zBTXr2mKW1hgdmrtMMUcMVCYxr1AJpu6IYX\r\n VMIoOAn7tIDdO0VLokK6FnIXTWEAplQ=\r\n', b'ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed;\r\n d=example.com; s=test; t=12345; h=message-id : date : from : to :\r\n subject : from; bh=wE7NXSkgnx9PGiavN4OZhJztvkqPDlemV3OGuEnLwNo=;\r\n b=a0f6qc3k9eECTSR155A0TQS+LjqPFWfI/brQBA83EUz00SNxj1wmWykvs1hhBVeM0r1kE\r\n Qc6CKbzRYaBNSiFj4q8JBpRIujLz1qLyGmPuAI6ddu/Z/1hQxgpVcp/odmI1UMV2R+d+yQ7\r\n tUp3EQxF/GYNt22rV4rNmDmANZVqJ90=\r\n', b'ARC-Authentication-Results: i=1; lists.example.org; arc=none;\r\n spf=pass smtp.mfrom=jqd@d1.example;\r\n dkim=pass (1024-bit key) header.i=@d1.example;\r\n dmarc=pass\r\n'] self.assertEqual(expected_sig, sig_lines) (cv, res, reason) = dkim.arc_verify(b''.join(sig_lines) + self.message, dnsfunc=self.dnsfunc) @@ -84,7 +83,7 @@ def test_fails_h_in_as(self): # ARC 4.1.3, h= not allowed in AS self.maxDiff = None - sig_lines = [b'ARC-Seal: i=1; cv=none; a=rsa-sha256; d=example.com; s=test; t=12345; \r\n h=message-id : date : from : to : subject : from; \r\n b=mIurIuLl0/wAxWhA4DBS1wsUE15IBnmJ7o3sH15hIuesdD4smz1cCLXVhRtxQE\r\n rVtVLv4OgNCgdFsB5zbSOUao2bSSYP6y0BGyCWvr+hU4tai5axIc1Kfwbtv/0Mqg\r\n waiGJPreOAAeZOJ4vPfdaAbSXlN5MI4PHW89U82FSIBKI=\r\n', b'ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; \r\n d=example.com; s=test; t=12345; h=message-id : \r\n date : from : to : subject : from; \r\n bh=wE7NXSkgnx9PGiavN4OZhJztvkqPDlemV3OGuEnLwNo=; \r\n b=a0f6qc3k9eECTSR155A0TQS+LjqPFWfI/brQBA83EUz00SNxj\r\n 1wmWykvs1hhBVeM0r1kEQc6CKbzRYaBNSiFj4q8JBpRIujLz1qL\r\n yGmPuAI6ddu/Z/1hQxgpVcp/odmI1UMV2R+d+yQ7tUp3EQxF/GY\r\n Nt22rV4rNmDmANZVqJ90=\r\n', b'ARC-Authentication-Results: i=1; lists.example.org; arc=none;\r\n spf=pass smtp.mfrom=jqd@d1.example;\r\n dkim=pass (1024-bit key) header.i=@d1.example;\r\n dmarc=pass\r\n'] + sig_lines = [b'ARC-Seal: i=1; cv=none; a=rsa-sha256; d=example.com; s=test; t=12345;\r\n h=message-id : date : from : to : subject : from;\r\n b=mIurIuLl0/wAxWhA4DBS1wsUE15IBnmJ7o3sH15hIuesdD4smz1cCLXVhRtxQE\r\n rVtVLv4OgNCgdFsB5zbSOUao2bSSYP6y0BGyCWvr+hU4tai5axIc1Kfwbtv/0Mqg\r\n waiGJPreOAAeZOJ4vPfdaAbSXlN5MI4PHW89U82FSIBKI=\r\n', b'ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed;\r\n d=example.com; s=test; t=12345; h=message-id :\r\n date : from : to : subject : from;\r\n bh=wE7NXSkgnx9PGiavN4OZhJztvkqPDlemV3OGuEnLwNo=;\r\n b=a0f6qc3k9eECTSR155A0TQS+LjqPFWfI/brQBA83EUz00SNxj\r\n 1wmWykvs1hhBVeM0r1kEQc6CKbzRYaBNSiFj4q8JBpRIujLz1qL\r\n yGmPuAI6ddu/Z/1hQxgpVcp/odmI1UMV2R+d+yQ7tUp3EQxF/GY\r\n Nt22rV4rNmDmANZVqJ90=\r\n', b'ARC-Authentication-Results: i=1; lists.example.org; arc=none;\r\n spf=pass smtp.mfrom=jqd@d1.example;\r\n dkim=pass (1024-bit key) header.i=@d1.example;\r\n dmarc=pass\r\n'] (cv, res, reason) = dkim.arc_verify(b''.join(sig_lines) + self.message, dnsfunc=self.dnsfunc) self.assertEqual(cv, dkim.CV_Fail) diff -Nru dkimpy-0.9.1/dkim/tests/test_dkim.py dkimpy-0.9.6/dkim/tests/test_dkim.py --- dkimpy-0.9.1/dkim/tests/test_dkim.py 2018-10-27 20:48:51.000000000 -0400 +++ dkimpy-0.9.6/dkim/tests/test_dkim.py 2019-12-24 10:21:38.000000000 -0500 @@ -46,6 +46,11 @@ self.assertEqual( b"foo" * 24 + b"\r\n foo", dkim.fold(b"foo" * 25)) + def test_linesep(self): + self.assertEqual( + b"foo" * 24 + b"\n foo", dkim.fold(b"foo" * 25, linesep=b"\n")) + + class TestSignAndVerify(unittest.TestCase): """End-to-end signature and verification tests.""" @@ -54,12 +59,13 @@ self.message = read_test_data("test.message") self.message3 = read_test_data("rfc6376.msg") self.message4 = read_test_data("rfc6376.signed.msg") + self.message5 = read_test_data("rfc6376.signed.rsa.msg") self.key = read_test_data("test.private") self.rfckey = read_test_data("rfc8032_7_1.key") def dnsfunc(self, domain): sample_dns = """\ -k=rsa; \ +k=rsa; s=email;\ p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANmBe10IgY+u7h3enWTukkqtUD5PR52T\ b/mPfjC0QJTocVBq6Za/PlzfV+Py92VaCak19F4WrbVTK5Gg5tW220MCAwEAAQ==""" @@ -172,6 +178,24 @@ self.assertTrue(domain in _dns_responses,domain) return _dns_responses[domain] + def dnsfunc6(self, domain, timeout=5): + sample_dns = """\ +k=rsa; \ +p=MFwwDQYJKoZIhvNAQEBBQADSwAwSAJBANmBe10IgY+u7h3enWTukkqtUD5PR52T\ +b/mPfjC0QJTocVBq6Za/PlzfV+Py92VaCak19F4WrbVTK5Gg5tW220MCAwEAAQ==""" + + _dns_responses = { + 'test._domainkey.football.example.com.': sample_dns, + 'brisbane._domainkey.football.example.com.': """v=DKIM1; k=ed25519; \ +p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=""" + } + try: + domain = domain.decode('ascii') + except UnicodeDecodeError: + return None + self.assertTrue(domain in _dns_responses,domain) + return _dns_responses[domain] + def test_verifies(self): # A message verifies after being signed. for header_algo in (b"simple", b"relaxed"): @@ -203,6 +227,23 @@ res = d.verify(dnsfunc=self.dnsfunc5) self.assertTrue(res) + def test_catch_bad_key(self): + # Raise correct error for defective public key. + d = dkim.DKIM(self.message5) + res = d.verify(dnsfunc=self.dnsfunc6) + self.assertFalse(res) + + def test_verifies_lflinesep(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), linesep=b"\n") + res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc) + self.assertFalse(b'\r\n' in sig) + self.assertTrue(res) + def test_implicit_k(self): # A message verifies after being signed when k= tag is not provided. for header_algo in (b"simple", b"relaxed"): diff -Nru dkimpy-0.9.1/dkim/tests/test_util.py dkimpy-0.9.6/dkim/tests/test_util.py --- dkimpy-0.9.1/dkim/tests/test_util.py 2018-06-16 17:28:10.000000000 -0400 +++ dkimpy-0.9.6/dkim/tests/test_util.py 2019-11-03 12:09:47.000000000 -0500 @@ -22,6 +22,7 @@ DuplicateTag, InvalidTagSpec, parse_tag_value, + get_linesep, ) @@ -75,6 +76,30 @@ self.assertEqual(len(sig),11) +class TestGetLineSep(unittest.TestCase): + """Line seperator probing tests.""" + + def test_default(self): + self.assertEqual( + b'\r\n', + get_linesep(b'abc')) + + def test_withcrlf(self): + self.assertEqual( + b'\r\n', + get_linesep(b'abc\r\n')) + + def test_withlf(self): + self.assertEqual( + b'\n', + get_linesep(b'abc\n')) + + def test_toosmall(self): + self.assertEqual( + b'\r\n', + get_linesep(b'a')) + + def test_suite(): from unittest import TestLoader return TestLoader().loadTestsFromName(__name__) diff -Nru dkimpy-0.9.1/dkim/util.py dkimpy-0.9.6/dkim/util.py --- dkimpy-0.9.1/dkim/util.py 2018-03-11 18:42:04.000000000 -0400 +++ dkimpy-0.9.6/dkim/util.py 2019-11-03 12:09:47.000000000 -0500 @@ -33,6 +33,7 @@ 'InvalidTagSpec', 'InvalidTagValueList', 'parse_tag_value', + 'get_linesep', ] @@ -80,3 +81,8 @@ if not logger.handlers: logger.addHandler(NullHandler()) return logger + +def get_linesep(msg): + if msg[-2:] != b'\r\n' and msg[-1:] == b'\n': + return b'\n' + return b'\r\n' diff -Nru dkimpy-0.9.1/dkimpy.egg-info/entry_points.txt dkimpy-0.9.6/dkimpy.egg-info/entry_points.txt --- dkimpy-0.9.1/dkimpy.egg-info/entry_points.txt 2018-12-09 14:05:45.000000000 -0500 +++ dkimpy-0.9.6/dkimpy.egg-info/entry_points.txt 2019-12-24 10:23:26.000000000 -0500 @@ -1,7 +1,7 @@ [console_scripts] -dkimsign = dkim.dkimsign:main arcsign = dkim.arcsign:main -dknewkey = dkim.dknewkey:main -dkimverify = dkim.dkimverify:main arcverify = dkim.arcverify:main +dkimsign = dkim.dkimsign:main +dkimverify = dkim.dkimverify:main +dknewkey = dkim.dknewkey:main diff -Nru dkimpy-0.9.1/dkimpy.egg-info/PKG-INFO dkimpy-0.9.6/dkimpy.egg-info/PKG-INFO --- dkimpy-0.9.1/dkimpy.egg-info/PKG-INFO 2018-12-09 14:05:45.000000000 -0500 +++ dkimpy-0.9.6/dkimpy.egg-info/PKG-INFO 2019-12-24 10:23:26.000000000 -0500 @@ -1,6 +1,6 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: dkimpy -Version: 0.9.1 +Version: 0.9.6 Summary: DKIM (DomainKeys Identified Mail) Home-page: https://launchpad.net/dkimpy Author: Scott Kitterman @@ -22,3 +22,6 @@ Classifier: Topic :: Communications :: Email :: Filters Classifier: Topic :: Internet :: Name Service (DNS) Classifier: Topic :: Software Development :: Libraries :: Python Modules +Provides-Extra: ARC +Provides-Extra: ed25519 +Provides-Extra: testing diff -Nru dkimpy-0.9.1/dkimpy.egg-info/requires.txt dkimpy-0.9.6/dkimpy.egg-info/requires.txt --- dkimpy-0.9.1/dkimpy.egg-info/requires.txt 2018-12-09 14:05:45.000000000 -0500 +++ dkimpy-0.9.6/dkimpy.egg-info/requires.txt 2019-12-24 10:23:26.000000000 -0500 @@ -1,11 +1,11 @@ Py3DNS -[testing] +[ARC] authres -pynacl [ed25519] pynacl -[ARC] -authres \ No newline at end of file +[testing] +authres +pynacl diff -Nru dkimpy-0.9.1/dkimpy.egg-info/SOURCES.txt dkimpy-0.9.6/dkimpy.egg-info/SOURCES.txt --- dkimpy-0.9.1/dkimpy.egg-info/SOURCES.txt 2018-12-09 14:05:46.000000000 -0500 +++ dkimpy-0.9.6/dkimpy.egg-info/SOURCES.txt 2019-12-24 10:23:27.000000000 -0500 @@ -1,4 +1,5 @@ ChangeLog +LICENSE MANIFEST.in README setup.py @@ -33,6 +34,7 @@ dkim/tests/data/message.mbox dkim/tests/data/rfc6376.msg dkim/tests/data/rfc6376.signed.msg +dkim/tests/data/rfc6376.signed.rsa.msg dkim/tests/data/rfc8032_7_1.key dkim/tests/data/test.message dkim/tests/data/test.private diff -Nru dkimpy-0.9.1/LICENSE dkimpy-0.9.6/LICENSE --- dkimpy-0.9.1/LICENSE 1969-12-31 19:00:00.000000000 -0500 +++ dkimpy-0.9.6/LICENSE 2019-11-03 12:09:47.000000000 -0500 @@ -0,0 +1,19 @@ +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 +See individual files for information about modification to these files and +additional copyright information. diff -Nru dkimpy-0.9.1/man/arcsign.1 dkimpy-0.9.6/man/arcsign.1 --- dkimpy-0.9.1/man/arcsign.1 2018-03-11 18:42:04.000000000 -0400 +++ dkimpy-0.9.6/man/arcsign.1 2019-11-03 12:09:47.000000000 -0500 @@ -127,31 +127,29 @@ .rm #[ #] #H #V #F C .\" ======================================================================== .\" -.IX Title "arcsign 1" -.TH arcsign 1 "2017-01-23" +.TH arcsign 1 "2019-04-14" .SH "NAME" arcsign \- Script for ARC signing messages on stdin .SH "VERSION" -.IX Header "VERSION" -0\.6\.0 +0\.9\.2 .SH "DESCRIPTION" -.IX Header "DESCRIPTION" arcsign is a filter that reads an RFC822 message on standard input, and writes the same message on standard output with a ARC-Signature lines prepended. .SH "USAGE" -.IX Header "USAGE" The signing options are specified on the command line: -arcsign selector domain privatekeyfile +arcsign selector domain privatekeyfile srv_id + +Note: arcsign will only use authentication results header fields with an +authserv-id that matches srv_id as the input fields for the ARC chain. .SH "AUTHORS" -.IX Header "AUTHORS" This version of \fBarcsign\fR was written by Brandon Long <bl...@google.com> and is derived from \fBdkimsign\fR, written by Greg Hewgill <g...@hewgill.com>. diff -Nru dkimpy-0.9.1/man/arcverify.1 dkimpy-0.9.6/man/arcverify.1 --- dkimpy-0.9.1/man/arcverify.1 2018-03-11 18:42:04.000000000 -0400 +++ dkimpy-0.9.6/man/arcverify.1 2019-11-03 12:09:47.000000000 -0500 @@ -127,25 +127,21 @@ .rm #[ #] #H #V #F C .\" ======================================================================== .\" -.IX Title "dkimverify 1" .TH dkimverify 1 "2017-01-23" .SH "NAME" dkimverify \- Script for DKIM verifying messages on stdin .SH "VERSION" -.IX Header "VERSION" 0\.6\.0 .SH "DESCRIPTION" -.IX Header "DESCRIPTION" dkimverify reads an RFC822 message on standard input, and returns with exit code 0 if the signature verifies successfully. Otherwise, it returns with exit code 1. .SH "AUTHORS" -.IX Header "AUTHORS" This version of \fBarcverify\fR was written by Brandon Long <bl...@google.com> and is derived from \fBdkimverify\fR, written by Greg Hewgill <g...@hewgill.com>. diff -Nru dkimpy-0.9.1/man/dkimsign.1 dkimpy-0.9.6/man/dkimsign.1 --- dkimpy-0.9.1/man/dkimsign.1 2018-03-11 18:42:04.000000000 -0400 +++ dkimpy-0.9.6/man/dkimsign.1 2019-11-03 12:09:47.000000000 -0500 @@ -127,24 +127,20 @@ .rm #[ #] #H #V #F C .\" ======================================================================== .\" -.IX Title "dkimsign 1" .TH dkimsign 1 "2018-02-05" .SH "NAME" dkimsign \- Script for DKIM signing messages on stdin .SH "VERSION" -.IX Header "VERSION" 0\.7\.0 .SH "DESCRIPTION" -.IX Header "DESCRIPTION" dkimsign is a filter that reads an RFC822 message on standard input, and writes the same message on standard output with a DKIM-Signature line prepended. .SH "USAGE" -.IX Header "USAGE" usage: dkimsign.py [\-h] [\-\-hcanon {simple,relaxed}] [\-\-bcanon {simple,relaxed}] @@ -168,7 +164,6 @@ \-\-identity IDENTITY Optional value for i= tag. .SH "AUTHORS" -.IX Header "AUTHORS" The original version of \fBdkimsign\fR was written by Greg Hewgill <g...@hewgill.com>. It has been substantially rewritten by Scott Kitterman <sc...@kitterman.com>. diff -Nru dkimpy-0.9.1/man/dkimverify.1 dkimpy-0.9.6/man/dkimverify.1 --- dkimpy-0.9.1/man/dkimverify.1 2018-03-11 18:42:04.000000000 -0400 +++ dkimpy-0.9.6/man/dkimverify.1 2019-11-03 12:09:47.000000000 -0500 @@ -127,25 +127,21 @@ .rm #[ #] #H #V #F C .\" ======================================================================== .\" -.IX Title "dkimverify 1" .TH dkimverify 1 "2017-01-23" .SH "NAME" dkimverify \- Script for DKIM verifying messages on stdin .SH "VERSION" -.IX Header "VERSION" 0\.6\.0 .SH "DESCRIPTION" -.IX Header "DESCRIPTION" dkimverify reads an RFC822 message on standard input, and returns with exit code 0 if the signature verifies successfully. Otherwise, it returns with exit code 1. .SH "AUTHORS" -.IX Header "AUTHORS" This version of \fBdkimverify\fR was written by Greg Hewgill <g...@hewgill.com>. .PP This man-page was created by Scott Kitterman <sc...@kitterman.com> and is diff -Nru dkimpy-0.9.1/man/dknewkey.1 dkimpy-0.9.6/man/dknewkey.1 --- dkimpy-0.9.1/man/dknewkey.1 2018-03-28 06:49:43.000000000 -0400 +++ dkimpy-0.9.6/man/dknewkey.1 2019-11-03 12:09:47.000000000 -0500 @@ -127,18 +127,15 @@ .rm #[ #] #H #V #F C .\" ======================================================================== .\" -.IX Title "dknewkey 1" .TH dknewkey 1 "2018-02-05" .SH "NAME" dknewkey \- Generates new DKIM public/private key pairs .SH "VERSION" -.IX Header "VERSION" 0\.8\.0 .SH "DESCRIPTION" -.IX Header "DESCRIPTION" dknewykey generates new DKIM keys. @@ -153,7 +150,6 @@ 8301). .SH "USAGE" -.IX Header "USAGE" dknewkey.py [\-h] [\-\-ktype {rsa,ed25519}] key_name @@ -169,7 +165,6 @@ the executable may vary. .SH "AUTHORS" -.IX Header "AUTHORS" This version of \fBdknewkey\fR was written by Brandon Long <bl...@google.com>. It has been substantially rewritten by Scott Kitterman <sc...@kitterman.com>. .PP diff -Nru dkimpy-0.9.1/MANIFEST.in dkimpy-0.9.6/MANIFEST.in --- dkimpy-0.9.1/MANIFEST.in 2018-03-25 22:37:59.000000000 -0400 +++ dkimpy-0.9.6/MANIFEST.in 2019-12-24 10:21:38.000000000 -0500 @@ -1,8 +1,10 @@ include dkim/* include dkim/tests/* include dkim/tests/data/* +include LICENSE include README include ChangeLog include MANIFEST.in include man/* include test.py +exclude dkim/*.pyc dkim/tests/*.pyc diff -Nru dkimpy-0.9.1/PKG-INFO dkimpy-0.9.6/PKG-INFO --- dkimpy-0.9.1/PKG-INFO 2018-12-09 14:05:46.000000000 -0500 +++ dkimpy-0.9.6/PKG-INFO 2019-12-24 10:23:27.000000000 -0500 @@ -1,6 +1,6 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: dkimpy -Version: 0.9.1 +Version: 0.9.6 Summary: DKIM (DomainKeys Identified Mail) Home-page: https://launchpad.net/dkimpy Author: Scott Kitterman @@ -22,3 +22,6 @@ Classifier: Topic :: Communications :: Email :: Filters Classifier: Topic :: Internet :: Name Service (DNS) Classifier: Topic :: Software Development :: Libraries :: Python Modules +Provides-Extra: ARC +Provides-Extra: ed25519 +Provides-Extra: testing diff -Nru dkimpy-0.9.1/README dkimpy-0.9.6/README --- dkimpy-0.9.1/README 2018-10-30 11:01:24.000000000 -0400 +++ dkimpy-0.9.6/README 2019-12-24 10:21:38.000000000 -0500 @@ -11,7 +11,7 @@ VERSION -This is dkimpy 0.9.0. +This is dkimpy 0.9.6. REQUIREMENTS @@ -36,7 +36,7 @@ setuptools developers decided not being able to do this by default is a feature: -python setup.py install --single-version-externally-managed --record=/dev/null +python3 setup.py install --single-version-externally-managed --record=/dev/null DOCUMENTATION @@ -48,11 +48,11 @@ To run dkimpy's test suite: - PYTHONPATH=. python dkim + PYTHONPATH=. python3 dkim or - python test.py + python3 test.py or - PYTHONPATH=. python -m unittest dkim.tests.test_suite + PYTHONPATH=. python3 -m unittest dkim.tests.test_suite Alternatively, if you have testrepository installed: @@ -67,21 +67,13 @@ The included ARC tests are very limited. The primary testing method for ARC is using the ARC test suite: https://github.com/ValiMail/arc_test_suite -As of 0.6.0, all tests except as_fields_b_512 pass for both python2.7 and -python3.5. The test suite ships with test runners for dkimpy. After -downloading the test suite, you can run the signing and validation tests like -this: +As of 0.6.0, all tests pass for both python2.7 and python3. The test suite + ships with test runners for dkimpy. After downloading the test suite, you + can run the signing and validation tests like this: python2.7 ./testarc.py sign runners/arcsigntest.py python2.7 ./testarc.py validate runners/arcverifytest.py -The reason for the test failure is that the ARC specification (as of 20170120) -sets the minimum key size to 512 bits. This is operationally inappropriate, -so dkimpy sets the default minkey=1024, the same as is used for DKIM. This -can be overridden, but that is not recommended. The minimum key size -requirement for DKIM (and thus ARC) has recently been updated to require at -least a 1024 bit key. See RFC 8301. - USAGE The dkimpy library offers one module called dkim. The sign() function takes an @@ -124,15 +116,18 @@ https://datatracker.ietf.org/doc/draft-ietf-dcrup-dkim-crypto/ -The dkimpy 0.7 implementation matches the -08 revision of the draft, except it -uses Ed25519 vice Ed25519ph (a change to Ed25519 is planned for -09, but that -had not been published yet as of the release of dkimpy 0.7). - -draft-ietf-dcrup-dkim-crypto-09 has been released and dkimpy 0.7 and later are -aligned to its requirements. As of 0.8, ed25519 need not be considered -experimental. The dkimpy implementation has successfully interoperated with -three other implementations and the technical parameters for ed25519-sha256 -are defined and stable. +The RFC that documents ed25519 DKIM signatures, RFC 8463, has been released +and dkimpy 0.7 and later are aligned to its requirements. As of 0.8, ed25519 +need not be considered experimental. The dkimpy implementation has +successfully interoperated with three other implementations and the technical +parameters for ed25519-sha256 are defined and stable. + +To install from pypi with the required optional depenencies, use the ed25519 +option: + +```pip install -e '.[ed25519]'``` + +DKIM SCRIPTS Three helper programs are also supplied: dknewkey, dkimsign and dkimverify @@ -156,15 +151,18 @@ As of version 0.6.0, dkimpy provides experimental support for ARC (Authenticated Received Chain): -https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-18 +https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-23 This new functionality is marked experimental because the protocol is still under development. There are no guarantees about API stability or -compatibility. +compatibility. Since the draft is through IETF last call, further changes are +unlikely. In addition to arcsign and arcverify, the dkim module now provides arc_sign and arc_verify functions as well as an ARC class. +Both DKIM ed25519 and ARC are now considered stable (no longer experimantal). + FEEDBACK Bug reports may be submitted to the bug tracker for the dkimpy project on diff -Nru dkimpy-0.9.1/setup.cfg dkimpy-0.9.6/setup.cfg --- dkimpy-0.9.1/setup.cfg 2018-12-09 14:05:46.000000000 -0500 +++ dkimpy-0.9.6/setup.cfg 2019-12-24 10:23:27.000000000 -0500 @@ -1,5 +1,4 @@ [egg_info] -tag_date = 0 tag_build = -tag_svn_revision = 0 +tag_date = 0 diff -Nru dkimpy-0.9.1/setup.py dkimpy-0.9.6/setup.py --- dkimpy-0.9.1/setup.py 2018-11-09 19:56:31.000000000 -0500 +++ dkimpy-0.9.6/setup.py 2019-12-24 10:21:38.000000000 -0500 @@ -25,7 +25,7 @@ import os import sys -version = "0.9.1" +version = "0.9.6" kw = {} # Work-around for lack of 'or' requires in setuptools. try: