--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock
Please unblock package dkimpy
This upload fixes two grave upstream issues (one of which has
securtyy implicaitions).
unblock dkimpy/0.5.2-1
diff -Nru dkimpy-0.5.2/ChangeLog dkimpy-0.5.3/ChangeLog
--- dkimpy-0.5.2/ChangeLog 2012-06-13 06:27:37.000000000 +0200
+++ dkimpy-0.5.3/ChangeLog 2012-07-21 07:41:31.000000000 +0200
@@ -1,4 +1,8 @@
-2012-06-13 Verion 0.5.2
+UNRELEASED Version 0.5.3
+ - Make key parsing error messages more specific to help troubleshooting
+ (Based on user feedback)
+
+2012-06-13 Version 0.5.2
- Change canonicalization defaults to work around issues with different
verification implementations <https://launchpad.net/bugs/939128>
- Fully fold DKIM-Signature on sign, and ignore FWS in b= value on verify
diff -Nru dkimpy-0.5.2/debian/changelog dkimpy-0.5.3/debian/changelog
--- dkimpy-0.5.2/debian/changelog 2012-10-28 10:48:11.000000000 +0100
+++ dkimpy-0.5.3/debian/changelog 2012-10-28 10:48:12.000000000 +0100
@@ -1,3 +1,15 @@
+dkimpy (0.5.3-1) unstable; urgency=medium
+
+ * Urgency medium for multiple RC bug fixes
+ * New upstream release:
+ * Fix header unfolding and body hash calculation errors that cause
+ correct DKIM signatures to fail to verify in many cases
+ (Closes: #691663)
+ * Add minimum key length requirement to prevent validation of signatures
+ generated with insecure keys (Closes: #691662)
+
+ -- Scott Kitterman <sc...@kitterman.com> Sun, 28 Oct 2012 10:32:13 +0100
+
dkimpy (0.5.2-1) unstable; urgency=low
* New upstream release
Binary files /tmp/vhfFWHbNtB/dkimpy-0.5.2/dkim/.asn1.py.swp and /tmp/4HMA0c1mG7/dkimpy-0.5.3/dkim/.asn1.py.swp differ
diff -Nru dkimpy-0.5.2/dkim/crypto.py dkimpy-0.5.3/dkim/crypto.py
--- dkimpy-0.5.2/dkim/crypto.py 2012-06-13 06:21:56.000000000 +0200
+++ dkimpy-0.5.3/dkim/crypto.py 2012-07-21 07:39:51.000000000 +0200
@@ -112,7 +112,7 @@
x = asn1_parse(ASN1_Object, data)
pkd = asn1_parse(ASN1_RSAPublicKey, x[0][1][1:])
except ASN1FormatError as e:
- raise UnparsableKeyError(str(e))
+ raise UnparsableKeyError('Unparsable public key: ' + str(e))
pk = {
'modulus': pkd[0][0],
'publicExponent': pkd[0][1],
@@ -129,7 +129,7 @@
try:
pka = asn1_parse(ASN1_RSAPrivateKey, data)
except ASN1FormatError as e:
- raise UnparsableKeyError(str(e))
+ raise UnparsableKeyError('Unparsable private key: ' + str(e))
pk = {
'version': pka[0][0],
'modulus': pka[0][1],
diff -Nru dkimpy-0.5.2/dkim/__init__.py dkimpy-0.5.3/dkim/__init__.py
--- dkimpy-0.5.2/dkim/__init__.py 2012-06-13 06:21:56.000000000 +0200
+++ dkimpy-0.5.3/dkim/__init__.py 2012-10-27 18:17:59.000000000 +0200
@@ -65,6 +65,10 @@
Relaxed = b'relaxed' # for clients passing dkim.Relaxed
Simple = b'simple' # for clients passing dkim.Simple
+def bitsize(x):
+ """Return size of long in bits."""
+ return len(bin(x)) - 2
+
class DKIMException(Exception):
"""Base class for DKIM errors."""
pass
@@ -114,8 +118,8 @@
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)?')
+FWS = r'(?:\r?\n\s+)?'
+RE_BTAG = re.compile(r'([;\s]b'+FWS+r'=)(?:'+FWS+r'[a-zA-Z0-9+/=])*(?:\r?\n\Z)?')
def hash_headers(hasher, canonicalize_headers, headers, include_headers,
sigheader, sig):
@@ -284,7 +288,8 @@
#: (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
- def __init__(self,message=None,logger=None,signature_algorithm=b'rsa-sha256'):
+ def __init__(self,message=None,logger=None,signature_algorithm=b'rsa-sha256',
+ minkey=1024):
self.set_message(message)
if logger is None:
logger = get_default_logger()
@@ -302,6 +307,9 @@
self.should_not_sign = set(DKIM.SHOULD_NOT)
#: Header fields to sign an extra time to prevent additions.
self.frozen_sign = set(DKIM.FROZEN)
+ #: Minimum public key size. Shorter keys raise KeyFormatError. The
+ #: default is 1024
+ self.minkey = minkey
def add_frozen(self,s):
""" Add headers not in should_not_sign to frozen_sign.
@@ -337,6 +345,8 @@
#: is a name,value tuple. FIXME: The headers are canonicalized.
#: This could be more useful as original headers.
self.signed_headers = []
+ #: The public key size last verified.
+ self.keysize = 0
def default_sign_headers(self):
"""Return the default list of headers to sign: those in should_sign or
@@ -493,6 +503,8 @@
logger.debug("sig: %r" % sig)
validate_signature_fields(sig)
+ self.domain = sig[b'd']
+ self.selector = sig[b's']
try:
canon_policy = CanonicalizationPolicy.from_c_value(sig.get(b'c'))
@@ -506,8 +518,6 @@
except KeyError as e:
raise MessageFormatError("unknown signature algorithm: %s" % e.args[0])
- self.domain = sig[b'd']
- self.selector = sig[b's']
if b'l' in sig:
body = body[:int(sig[b'l'])]
@@ -534,6 +544,7 @@
raise KeyFormatError(e)
try:
pk = parse_public_key(base64.b64decode(pub[b'p']))
+ self.keysize = bitsize(pk['modulus'])
except KeyError:
raise KeyFormatError("incomplete public key: %s" % s)
except (TypeError,UnparsableKeyError) as e:
@@ -551,7 +562,10 @@
h, canon_policy, headers, include_headers, sigheaders[idx], sig)
try:
signature = base64.b64decode(re.sub(br"\s+", b"", sig[b'b']))
- return RSASSA_PKCS1_v1_5_verify(h, signature, pk)
+ res = RSASSA_PKCS1_v1_5_verify(h, signature, pk)
+ if res and self.keysize < self.minkey:
+ raise KeyFormatError("public key too small: %d" % self.keysize)
+ return res
except (TypeError,DigestTooLargeError) as e:
raise KeyFormatError("digest too large for modulus: %s"%e)
@@ -578,13 +592,13 @@
include_headers = d.all_sign_headers()
return d.sign(selector, domain, privkey, identity=identity, canonicalize=canonicalize, include_headers=include_headers, length=length)
-def verify(message, logger=None, dnsfunc=get_txt):
+def verify(message, logger=None, dnsfunc=get_txt, minkey=1024):
"""Verify the first (topmost) DKIM signature on an RFC822 formatted message.
@param message: an RFC822 formatted message (with either \\n or \\r\\n line endings)
@param logger: a logger to which debug info will be written (default None)
@return: True if signature verifies or False otherwise
"""
- d = DKIM(message,logger=logger)
+ d = DKIM(message,logger=logger,minkey=minkey)
try:
return d.verify(dnsfunc=dnsfunc)
except DKIMException as x:
diff -Nru dkimpy-0.5.2/dkim/tests/test_dkim.py dkimpy-0.5.3/dkim/tests/test_dkim.py
--- dkimpy-0.5.2/dkim/tests/test_dkim.py 2012-06-13 06:21:56.000000000 +0200
+++ dkimpy-0.5.3/dkim/tests/test_dkim.py 2012-10-27 18:17:59.000000000 +0200
@@ -135,7 +135,15 @@
# 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])
+ result = dkim.verify(signed,dnsfunc=lambda x: _dns_responses[x],
+ minkey=512)
+ self.assertTrue(result)
+ dkim_header = dkim.fold(dkim_header)
+ # use a tab for last fold to test tab in FWS bug
+ pos = dkim_header.rindex(b'\r\n ')
+ dkim_header = dkim_header[:pos]+b'\r\n\t'+dkim_header[pos+3:]
+ result = dkim.verify(dkim_header + sample_msg,
+ dnsfunc=lambda x: _dns_responses[x], minkey=512)
self.assertTrue(result)
def test_extra_headers(self):
diff -Nru dkimpy-0.5.2/PKG-INFO dkimpy-0.5.3/PKG-INFO
--- dkimpy-0.5.2/PKG-INFO 2012-06-13 06:59:38.000000000 +0200
+++ dkimpy-0.5.3/PKG-INFO 2012-10-27 18:21:31.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: dkimpy
-Version: 0.5.2
+Version: 0.5.3
Summary: DKIM (DomainKeys Identified Mail)
Home-page: https://launchpad.net/dkimpy
Author: Scott Kitterman
diff -Nru dkimpy-0.5.2/README dkimpy-0.5.3/README
--- dkimpy-0.5.2/README 2012-06-13 06:23:07.000000000 +0200
+++ dkimpy-0.5.3/README 2012-07-21 07:43:06.000000000 +0200
@@ -11,7 +11,7 @@
VERSION
-This is dkimpy 0.5.2.
+This is dkimpy 0.5.3.
REQUIREMENTS
diff -Nru dkimpy-0.5.2/setup.py dkimpy-0.5.3/setup.py
--- dkimpy-0.5.2/setup.py 2012-06-13 06:58:48.000000000 +0200
+++ dkimpy-0.5.3/setup.py 2012-07-21 07:41:46.000000000 +0200
@@ -24,7 +24,7 @@
from distutils.core import setup
import os
-version = "0.5.2"
+version = "0.5.3"
setup(
name = "dkimpy",
--- End Message ---